diff --git a/src/core_landice/Registry.xml b/src/core_landice/Registry.xml
index 1e31339959..b60bb79814 100644
--- a/src/core_landice/Registry.xml
+++ b/src/core_landice/Registry.xml
@@ -39,6 +39,9 @@
+
@@ -70,7 +73,7 @@
possible_values="'from_vertex_barycentric', 'from_vertex_barycentric_kiteareas', 'from_normal_slope'"
/>
-
+
+
+
@@ -107,18 +122,29 @@
possible_values=".true. or .false."
/>
-->
+
+
+
+
+
-
@@ -130,6 +156,14 @@
description="Value of eigencalving parameter if taken as a scalar by option config_calving_eigencalving_parameter_source. (Default value is 1.0e9 m a converted to units used here.)"
possible_values="any positive real number"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -157,8 +247,8 @@
description="Selection of the method for initializing the ice temperature (as described further below)."
possible_values="'sfc_air_temperature', 'linear', 'file'"
/>
-
+
+
+
+
+
+
+
+
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
@@ -454,7 +636,7 @@
-
+
+
+
+
+
+
+
+
+
+
+
@@ -491,6 +683,16 @@
+
+
+
+
+
+
+
+
+
+
-
+
+
@@ -554,6 +766,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -756,6 +981,9 @@ is the value of that variable from the *previous* time level!
+
@@ -844,8 +1072,14 @@ is the value of that variable from the *previous* time level!
+
+
@@ -855,6 +1089,12 @@ is the value of that variable from the *previous* time level!
+
+
@@ -862,13 +1102,63 @@ is the value of that variable from the *previous* time level!
description="proportionality constant K2+- used in eigencalving formulation"
/>
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
-
+
+
-
+
+
@@ -892,7 +1193,62 @@ is the value of that variable from the *previous* time level!
/>
+
+
+
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+ />
+
+
+
@@ -932,34 +1288,80 @@ is the value of that variable from the *previous* time level!
+
+
+
+
+
+
+
-
-
+
-
+
+
+
+
+
+
+
+
-
@@ -991,17 +1387,17 @@ is the value of that variable from the *previous* time level!
description="X-component of observed surface velocity" />
-
-
-
-
-
@@ -1012,7 +1408,7 @@ is the value of that variable from the *previous* time level!
-
+
-
+
-
@@ -94,7 +102,7 @@
description="width of sheet beneath/around channel that contributes to melt within the channel"
possible_values="positive real number"
/>
-
@@ -152,7 +160,7 @@
-
@@ -184,6 +192,8 @@
description="hydropotential without water thickness contribution on vertices. Only used for some choices of config_SGH_tangent_slope_calculation." />
+
+
+
+
diff --git a/src/core_landice/analysis_members/Registry_regional_stats.xml b/src/core_landice/analysis_members/Registry_regional_stats.xml
index e33203221d..fbea7c7989 100644
--- a/src/core_landice/analysis_members/Registry_regional_stats.xml
+++ b/src/core_landice/analysis_members/Registry_regional_stats.xml
@@ -60,6 +60,12 @@
+
+
@@ -84,6 +90,9 @@
+
@@ -104,7 +113,7 @@
clobber_mode="truncate"
runtime_format="single_file">
-
-
+
+
diff --git a/src/core_landice/analysis_members/mpas_li_global_stats.F b/src/core_landice/analysis_members/mpas_li_global_stats.F
index d8e8a20d1a..41ddc9aebd 100644
--- a/src/core_landice/analysis_members/mpas_li_global_stats.F
+++ b/src/core_landice/analysis_members/mpas_li_global_stats.F
@@ -71,7 +71,7 @@ module li_global_stats
!
!-----------------------------------------------------------------------
- subroutine li_init_global_stats(domain, memberName, err)!{{{
+ subroutine li_init_global_stats(domain, memberName, err)
!-----------------------------------------------------------------
!
@@ -105,7 +105,7 @@ subroutine li_init_global_stats(domain, memberName, err)!{{{
err = 0
- end subroutine li_init_global_stats!}}}
+ end subroutine li_init_global_stats
!***********************************************************************
!
@@ -120,7 +120,7 @@ end subroutine li_init_global_stats!}}}
!
!-----------------------------------------------------------------------
- subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
+ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)
!-----------------------------------------------------------------
!
@@ -165,27 +165,24 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
type (mpas_pool_type), pointer :: velocityPool
! arrays, vars needed from other pools for calculations here
- real (kind=RKIND), pointer :: config_ice_density
real (kind=RKIND), pointer :: deltat
real (kind=RKIND), dimension(:), pointer :: areaCell
real (kind=RKIND), dimension(:), pointer :: dvEdge
real (kind=RKIND), dimension(:), pointer :: thickness
real (kind=RKIND), dimension(:), pointer :: bedTopography
- real (kind=RKIND), dimension(:), pointer :: sfcMassBal
+ real (kind=RKIND), dimension(:), pointer :: sfcMassBalApplied
+ real (kind=RKIND), dimension(:), pointer :: groundedSfcMassBalApplied
real (kind=RKIND), dimension(:), pointer :: basalMassBal
real (kind=RKIND), dimension(:), pointer :: groundedBasalMassBal
real (kind=RKIND), dimension(:), pointer :: floatingBasalMassBal
real (kind=RKIND), dimension(:), pointer :: calvingThickness
real (kind=RKIND), dimension(:), pointer :: surfaceSpeed
real (kind=RKIND), dimension(:), pointer :: basalSpeed
- real (kind=RKIND), dimension(:,:), pointer :: layerNormalVelocity
- real (kind=RKIND), dimension(:,:), pointer :: layerThicknessEdge
+ real (kind=RKIND), dimension(:), pointer :: fluxAcrossGroundingLine
+ real (kind=RKIND), dimension(:), pointer :: groundedToFloatingThickness
integer, dimension(:), pointer :: cellMask
- integer, dimension(:), pointer :: edgeMask
- integer, dimension(:,:), pointer :: cellsOnEdge
integer, pointer :: nCellsSolve
integer, pointer :: nEdgesSolve
- integer, pointer :: nVertLevels
! config options needed
real (kind=RKIND), pointer :: config_sea_level
@@ -194,7 +191,6 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
! Local counters
integer :: k, iCell, iEdge
- integer :: iCell1, iCell2
! scalars to be calculated here from global reductions
real (kind=RKIND), pointer :: totalIceArea, totalIceVolume
@@ -203,12 +199,14 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
real (kind=RKIND), pointer :: floatingIceArea, floatingIceVolume
real (kind=RKIND), pointer :: iceThicknessMax, iceThicknessMin, iceThicknessMean
real (kind=RKIND), pointer :: totalSfcMassBal, totalBasalMassBal
+ real (kind=RKIND), pointer :: totalGroundedSfcMassBal, totalFloatingSfcMassBal
real (kind=RKIND), pointer :: totalGroundedBasalMassBal, totalFloatingBasalMassBal
real (kind=RKIND), pointer :: avgNetAccumulation
real (kind=RKIND), pointer :: avgGroundedBasalMelt
real (kind=RKIND), pointer :: avgSubshelfMelt
real (kind=RKIND), pointer :: totalCalvingFlux
real (kind=RKIND), pointer :: groundingLineFlux
+ real (kind=RKIND), pointer :: groundingLineMigrationFlux
real (kind=RKIND), pointer :: surfaceSpeedMax
real (kind=RKIND), pointer :: basalSpeedMax
@@ -219,17 +217,18 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
real (kind=RKIND) :: blockSumFloatingIceArea, blockSumFloatingIceVolume
real (kind=RKIND) :: blockThickMin, blockThickMax
real (kind=RKIND) :: blockSumSfcMassBal, blockSumBasalMassBal
+ real (kind=RKIND) :: blockSumGroundedSfcMassBal, blockSumFloatingSfcMassBal
real (kind=RKIND) :: blockSumGroundedBasalMassBal, blockSumFloatingBasalMassBal
real (kind=RKIND) :: blockSumCalvingFlux
real (kind=RKIND) :: blockMaxSurfaceSpeed
real (kind=RKIND) :: blockMaxBasalSpeed
real (kind=RKIND) :: blockGLflux
+ real (kind=RKIND) :: blockGLMigrationFlux
! Local variables for calculations
- real (kind=RKIND) :: fluxSign
! variables for processing stats
- integer, parameter :: kMaxVariables = 16 ! Increase if number of stats increase
+ integer, parameter :: kMaxVariables = 24 ! Increase if number of stats increase
integer :: nVars
real (kind=RKIND), dimension(kMaxVariables) :: reductions, sums, mins, maxes
@@ -246,11 +245,14 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
blockSumFloatingIceArea = 0.0_RKIND
blockSumFloatingIceVolume = 0.0_RKIND
blockSumSfcMassBal = 0.0_RKIND
+ blockSumGroundedSfcMassBal = 0.0_RKIND
+ blockSumFloatingSfcMassBal = 0.0_RKIND
blockSumBasalMassBal = 0.0_RKIND
blockSumGroundedBasalMassBal = 0.0_RKIND
blockSumFloatingBasalMassBal = 0.0_RKIND
blockSumCalvingFlux = 0.0_RKIND
blockGLflux = 0.0_RKIND
+ blockGLMigrationFlux = 0.0_RKIND
! initialize max to 0, min to large number
blockThickMin = 100000.0_RKIND
@@ -274,27 +276,24 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
! get values and arrays from standard pools
- call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density)
call mpas_pool_get_dimension(block % dimensions, 'nCellsSolve', nCellsSolve)
call mpas_pool_get_dimension(block % dimensions, 'nEdgesSolve', nEdgesSolve)
- call mpas_pool_get_dimension(block % dimensions, 'nVertLevels', nVertLevels)
call mpas_pool_get_array(meshPool, 'deltat', deltat)
call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge)
- call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge)
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
- call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
- call mpas_pool_get_array(geometryPool, 'sfcMassBal', sfcMassBal)
+ call mpas_pool_get_array(geometryPool, 'sfcMassBalApplied', sfcMassBalApplied)
+ call mpas_pool_get_array(geometryPool, 'groundedSfcMassBalApplied', groundedSfcMassBalApplied)
call mpas_pool_get_array(geometryPool, 'basalMassBal', basalMassBal)
call mpas_pool_get_array(geometryPool, 'groundedBasalMassBal', groundedBasalMassBal)
call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
- call mpas_pool_get_array(geometryPool, 'layerThicknessEdge', layerThicknessEdge)
+ call mpas_pool_get_array(geometryPool, 'groundedToFloatingThickness', groundedToFloatingThickness)
call mpas_pool_get_array(velocityPool, 'surfaceSpeed', surfaceSpeed)
call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed)
- call mpas_pool_get_array(velocityPool, 'layerNormalVelocity', layerNormalVelocity)
+ call mpas_pool_get_array(velocityPool, 'fluxAcrossGroundingLine', fluxAcrossGroundingLine)
! loop over cells
do iCell = 1,nCellsSolve
@@ -306,7 +305,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
* areaCell(iCell) * thickness(iCell)
blockSumVAF = blockSumVAF + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) * areaCell(iCell) * &
- ( thickness(iCell) + (rhow / rhoi) * min(0.0_RKIND, (bedTopography(iCell) - config_sea_level)) )
+ ( thickness(iCell) + (rhow / rhoi) * min(0.0_RKIND, (bedTopography(iCell) - config_sea_level)) )
blockSumGroundedIceArea = blockSumGroundedIceArea + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) &
* areaCell(iCell)
@@ -326,20 +325,22 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
blockThickMin = thickness(iCell)
endif
- ! sfc and basal mass balance (kg yr^{-1})
- !SFP: These calculations need to be tested still
- blockSumSfcMassBal = blockSumSfcMassBal + real(li_mask_is_ice_int(cellMask(iCell)),RKIND) &
- * areaCell(iCell) * sfcMassBal(iCell) * scyr
+ ! SMB (kg yr^{-1})
+ blockSumSfcMassBal = blockSumSfcMassBal + areaCell(iCell) * sfcMassBalApplied(iCell) * scyr
+ blockSumGroundedSfcMassBal = blockSumGroundedSfcMassBal + areaCell(iCell) * groundedSfcMassBalApplied(iCell) * scyr
+ blockSumFloatingSfcMassBal = blockSumFloatingSfcMassBal + &
+ (sfcMassBalApplied(iCell) - groundedSfcMassBalApplied(iCell)) * areaCell(iCell) * scyr
+ ! BMB (kg yr-1)
blockSumBasalMassBal = blockSumBasalMassBal + real(li_mask_is_ice_int(cellMask(iCell)),RKIND) &
* areaCell(iCell) * basalMassBal(iCell) * scyr
- blockSumGroundedBasalMassBal = blockSumGroundedBasalMassBal + real(li_mask_is_ice_int(cellMask(iCell)),RKIND) &
+ blockSumGroundedBasalMassBal = blockSumGroundedBasalMassBal + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND)&
* areaCell(iCell) * groundedBasalMassBal(iCell) * scyr
- blockSumFloatingBasalMassBal = blockSumFloatingBasalMassBal + real(li_mask_is_floating_ice_int(cellMask(iCell)),RKIND) &
+ blockSumFloatingBasalMassBal = blockSumFloatingBasalMassBal + real(li_mask_is_floating_ice_int(cellMask(iCell)),RKIND)&
* areaCell(iCell) * floatingBasalMassBal(iCell) * scyr
! mass lass due do calving (kg yr^{-1})
blockSumCalvingFlux = blockSumCalvingFlux + calvingThickness(iCell) * &
- areaCell(iCell) * config_ice_density / ( deltat / scyr )
+ areaCell(iCell) * rhoi / ( deltat / scyr )
! max surface speed
if (surfaceSpeed(iCell) > blockMaxSurfaceSpeed) then
@@ -351,29 +352,17 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
blockMaxBasalSpeed = basalSpeed(iCell)
endif
+ ! GL migration flux
+ blockGLMigrationFlux = blockGLMigrationFlux + groundedToFloatingThickness(iCell) * areaCell(iCell) &
+ * rhoi / (deltat / scyr) ! convert from m to kg/yr
+
end do ! end loop over cells
! Loop over edges
do iEdge = 1, nEdgesSolve
- if (li_mask_is_grounding_line(edgeMask(iEdge))) then
- ! Determine sign of this edge relative to GL
- ! (+=grounded to floating, -=floating to grounded)
- iCell1 = cellsOnEdge(1,iEdge)
- iCell2 = cellsOnEdge(2,iEdge)
- if (li_mask_is_grounded_ice(cellMask(iCell1))) then
- fluxSign = 1.0_RKIND
- else
- fluxSign = -1.0_RKIND
- endif
-
- ! Loop over levels
- do k = 1, nVertLevels
- ! Flux across GL, units = kg/yr
- blockGLflux = blockGLflux + fluxSign * layerNormalVelocity(k, iEdge) * dvEdge(iEdge) * layerThicknessEdge(k, iEdge) &
- * scyr * config_ice_density ! convert from m^3/s to kg/yr
- end do ! end loop over levels
- end if ! if GL
-
+ ! Flux across GL, units = kg/yr
+ blockGLflux = blockGLflux + fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) &
+ * scyr * rhoi ! convert from m^2/s to kg/yr
end do ! end loop over edges
block => block % next
@@ -412,13 +401,17 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
sums(5) = blockSumFloatingIceArea
sums(6) = blockSumFloatingIceVolume
sums(7) = blockSumSfcMassBal
- sums(8) = blockSumBasalMassBal
- sums(9) = blockSumGroundedBasalMassBal
- sums(10) = blockSumFloatingBasalMassBal
- sums(11) = blockSumCalvingFlux
- sums(12) = blockSumVAF
- sums(13) = blockGLflux
- nVars = 13
+ sums(8) = blockSumGroundedSfcMassBal
+ sums(9) = blockSumFloatingSfcMassBal
+
+ sums(10) = blockSumBasalMassBal
+ sums(11) = blockSumGroundedBasalMassBal
+ sums(12) = blockSumFloatingBasalMassBal
+ sums(13) = blockSumCalvingFlux
+ sums(14) = blockSumVAF
+ sums(15) = blockGLflux
+ sums(16) = blockGLMigrationflux
+ nVars = 16
call mpas_dmpar_sum_real_array(dminfo, nVars, sums(1:nVars), reductions(1:nVars))
@@ -435,6 +428,8 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
call mpas_pool_get_array(globalStatsAMPool, 'groundedIceVolume', groundedIceVolume)
call mpas_pool_get_array(globalStatsAMPool, 'iceThicknessMean', iceThicknessMean)
call mpas_pool_get_array(globalStatsAMPool, 'totalSfcMassBal', totalSfcMassBal)
+ call mpas_pool_get_array(globalStatsAMPool, 'totalGroundedSfcMassBal', totalGroundedSfcMassBal)
+ call mpas_pool_get_array(globalStatsAMPool, 'totalFloatingSfcMassBal', totalFloatingSfcMassBal)
call mpas_pool_get_array(globalStatsAMPool, 'avgNetAccumulation', avgNetAccumulation)
call mpas_pool_get_array(globalStatsAMPool, 'totalBasalMassBal', totalBasalMassBal)
call mpas_pool_get_array(globalStatsAMPool, 'totalGroundedBasalMassBal', totalGroundedBasalMassBal)
@@ -443,6 +438,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
call mpas_pool_get_array(globalStatsAMPool, 'avgSubshelfMelt', avgSubshelfMelt)
call mpas_pool_get_array(globalStatsAMPool, 'totalCalvingFlux', totalCalvingFlux)
call mpas_pool_get_array(globalStatsAMPool, 'groundingLineFlux', groundingLineFlux)
+ call mpas_pool_get_array(globalStatsAMPool, 'groundingLineMigrationFlux', groundingLineMigrationFlux)
totalIceArea = reductions(1)
totalIceVolume = reductions(2)
@@ -451,17 +447,33 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
floatingIceArea = reductions(5)
floatingIceVolume = reductions(6)
totalSfcMassBal = reductions(7)
- totalBasalMassBal = reductions(8)
- totalGroundedBasalMassBal = reductions(9)
- totalFloatingBasalMassBal = reductions(10)
- totalCalvingFlux = reductions(11)
- volumeAboveFloatation = reductions(12)
- groundingLineFlux = reductions(13)
-
- iceThicknessMean = totalIceVolume / totalIceArea
- avgNetAccumulation = totalSfcMassBal / totalIceArea / rhoi
- avgGroundedBasalMelt = -1.0_RKIND * totalGroundedBasalMassBal / groundedIceArea / rhoi
- avgSubshelfMelt = -1.0_RKIND * totalFloatingBasalMassBal / floatingIceArea / rhoi
+ totalGroundedSfcMassBal = reductions(8)
+ totalFloatingSfcMassBal = reductions(9)
+ totalBasalMassBal = reductions(10)
+ totalGroundedBasalMassBal = reductions(11)
+ totalFloatingBasalMassBal = reductions(12)
+ totalCalvingFlux = reductions(13)
+ volumeAboveFloatation = reductions(14)
+ groundingLineFlux = reductions(15)
+ groundingLineMigrationFlux = reductions(16)
+
+ if (totalIceArea > 0.0_RKIND) then
+ iceThicknessMean = totalIceVolume / totalIceArea
+ avgNetAccumulation = totalSfcMassBal / totalIceArea / rhoi
+ else
+ iceThicknessMean = 0.0_RKIND
+ avgNetAccumulation = 0.0_RKIND
+ endif
+ if (groundedIceArea > 0.0_RKIND) then
+ avgGroundedBasalMelt = -1.0_RKIND * totalGroundedBasalMassBal / groundedIceArea / rhoi
+ else
+ avgGroundedBasalMelt = 0.0_RKIND
+ endif
+ if (floatingIceArea > 0.0_RKIND) then
+ avgSubshelfMelt = -1.0_RKIND * totalFloatingBasalMassBal / floatingIceArea / rhoi
+ else
+ avgSubshelfMelt = 0.0_RKIND
+ endif
block => block % next
end do
@@ -514,7 +526,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err)!{{{
- end subroutine li_compute_global_stats!}}}
+ end subroutine li_compute_global_stats
!***********************************************************************
!
@@ -529,7 +541,7 @@ end subroutine li_compute_global_stats!}}}
!
!-----------------------------------------------------------------------
- subroutine li_restart_global_stats(domain, memberName, err)!{{{
+ subroutine li_restart_global_stats(domain, memberName, err)
!-----------------------------------------------------------------
!
@@ -563,7 +575,7 @@ subroutine li_restart_global_stats(domain, memberName, err)!{{{
err = 0
- end subroutine li_restart_global_stats!}}}
+ end subroutine li_restart_global_stats
!***********************************************************************
!
@@ -578,7 +590,7 @@ end subroutine li_restart_global_stats!}}}
!
!-----------------------------------------------------------------------
- subroutine li_finalize_global_stats(domain, memberName, err)!{{{
+ subroutine li_finalize_global_stats(domain, memberName, err)
!-----------------------------------------------------------------
!
@@ -612,7 +624,7 @@ subroutine li_finalize_global_stats(domain, memberName, err)!{{{
err = 0
- end subroutine li_finalize_global_stats!}}}
+ end subroutine li_finalize_global_stats
end module li_global_stats
diff --git a/src/core_landice/analysis_members/mpas_li_regional_stats.F b/src/core_landice/analysis_members/mpas_li_regional_stats.F
index f83bddd3de..0e0543df57 100644
--- a/src/core_landice/analysis_members/mpas_li_regional_stats.F
+++ b/src/core_landice/analysis_members/mpas_li_regional_stats.F
@@ -71,7 +71,7 @@ module li_regional_stats
!
!-----------------------------------------------------------------------
- subroutine li_init_regional_stats(domain, memberName, err)!{{{
+ subroutine li_init_regional_stats(domain, memberName, err)
!-----------------------------------------------------------------
!
@@ -105,7 +105,7 @@ subroutine li_init_regional_stats(domain, memberName, err)!{{{
err = 0
- end subroutine li_init_regional_stats!}}}
+ end subroutine li_init_regional_stats
!***********************************************************************
!
@@ -120,7 +120,7 @@ end subroutine li_init_regional_stats!}}}
!
!-----------------------------------------------------------------------
- subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
+ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)
!-----------------------------------------------------------------
!
@@ -169,18 +169,20 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
real (kind=RKIND), pointer :: config_ice_density
real (kind=RKIND), pointer :: deltat
real (kind=RKIND), dimension(:), pointer :: areaCell
- real (kind=RKIND), dimension(:), pointer :: dvEdge
+ real (kind=RKIND), dimension(:), pointer :: dvEdge
real (kind=RKIND), dimension(:), pointer :: thickness
real (kind=RKIND), dimension(:), pointer :: bedTopography
- real (kind=RKIND), dimension(:), pointer :: sfcMassBal
+ real (kind=RKIND), dimension(:), pointer :: sfcMassBalApplied
+ real (kind=RKIND), dimension(:), pointer :: groundedSfcMassBalApplied
real (kind=RKIND), dimension(:), pointer :: basalMassBal
real (kind=RKIND), dimension(:), pointer :: groundedBasalMassBal
real (kind=RKIND), dimension(:), pointer :: floatingBasalMassBal
real (kind=RKIND), dimension(:), pointer :: calvingThickness
- real (kind=RKIND), dimension(:), pointer :: surfaceSpeed
+ real (kind=RKIND), dimension(:), pointer :: surfaceSpeed
real (kind=RKIND), dimension(:), pointer :: basalSpeed
- real (kind=RKIND), dimension(:,:), pointer :: layerNormalVelocity
- real (kind=RKIND), dimension(:,:), pointer :: layerThicknessEdge
+ real (kind=RKIND), dimension(:), pointer :: fluxAcrossGroundingLine
+ real (kind=RKIND), dimension(:), pointer :: groundedToFloatingThickness
+ real (kind=RKIND), dimension(:,:), pointer :: normalVelocity
! config options needed
real (kind=RKIND), pointer :: config_sea_level
@@ -193,7 +195,8 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
integer, dimension(:,:), pointer :: cellsOnEdge
integer, pointer :: nRegions, nRegionGroups !, maxRegionsInGroup !! maxRegionsInGroup not needed / used yet
integer, pointer :: nCellsSolve, nEdgesSolve, nVertLevels
- integer :: k, iCell, iCell1, iCell2, iEdge
+ integer :: k, iCell, iEdge
+ integer :: upwindCell
integer :: iRegion, iGroup
! scalars to be calculated here from regional sums
@@ -203,14 +206,16 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
real (kind=RKIND), dimension(:), pointer :: regionalFloatingIceArea, regionalFloatingIceVolume
real (kind=RKIND), dimension(:), pointer :: regionalIceThicknessMin, regionalIceThicknessMax, regionalIceThicknessMean
real (kind=RKIND), dimension(:), pointer :: regionalSumSfcMassBal, regionalSumBasalMassBal
+ real (kind=RKIND), dimension(:), pointer :: regionalSumGroundedSfcMassBal, regionalSumFloatingSfcMassBal
real (kind=RKIND), dimension(:), pointer :: regionalSumGroundedBasalMassBal, regionalSumFloatingBasalMassBal
real (kind=RKIND), dimension(:), pointer :: regionalSumCalvingFlux
real (kind=RKIND), dimension(:), pointer :: regionalSumGroundingLineFlux
+ real (kind=RKIND), dimension(:), pointer :: regionalSumGroundingLineMigrationFlux
real (kind=RKIND), dimension(:), pointer :: regionalAvgNetAccumulation
real (kind=RKIND), dimension(:), pointer :: regionalAvgGroundedBasalMelt
real (kind=RKIND), dimension(:), pointer :: regionalAvgSubshelfMelt
real (kind=RKIND), dimension(:), pointer :: regionalSurfaceSpeedMax
- real (kind=RKIND), dimension(:), pointer :: regionalBasalSpeedMax
+ real (kind=RKIND), dimension(:), pointer :: regionalBasalSpeedMax
! storage for sums over blocks
real (kind=RKIND), dimension(:), allocatable :: blockSumRegionIceArea, blockSumRegionIceVolume
@@ -219,9 +224,11 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
real (kind=RKIND), dimension(:), allocatable :: blockSumRegionFloatingIceArea, blockSumRegionFloatingIceVolume
real (kind=RKIND), dimension(:), allocatable :: blockRegionThickMin, blockRegionThickMax
real (kind=RKIND), dimension(:), allocatable :: blockSumRegionSfcMassBal, blockSumRegionBasalMassBal
+ real (kind=RKIND), dimension(:), allocatable :: blockSumRegionGroundedSfcMassBal, blockSumRegionFloatingSfcMassBal
real (kind=RKIND), dimension(:), allocatable :: blockSumRegionGroundedBasalMassBal, blockSumRegionFloatingBasalMassBal
real (kind=RKIND), dimension(:), allocatable :: blockSumRegionCalvingFlux
real (kind=RKIND), dimension(:), allocatable :: blockSumRegionGLflux
+ real (kind=RKIND), dimension(:), allocatable :: blockRegionGLMigrationFlux
real (kind=RKIND), dimension(:), allocatable :: blockRegionMaxSurfaceSpeed
real (kind=RKIND), dimension(:), allocatable :: blockRegionMaxBasalSpeed
@@ -229,7 +236,7 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
real (kind=RKIND) :: fluxSign
! variables for processing stats
- integer, parameter :: kMaxVariables = 16 ! Increase if number of stats increase
+ integer, parameter :: kMaxVariables = 32 ! Increase if number of stats increase
integer :: nVars
real (kind=RKIND), dimension(kMaxVariables) :: reductions, sums, mins, maxes
@@ -270,15 +277,17 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
- call mpas_pool_get_array(geometryPool, 'sfcMassBal', sfcMassBal)
+ call mpas_pool_get_array(geometryPool, 'sfcMassBalApplied', sfcMassBalApplied)
+ call mpas_pool_get_array(geometryPool, 'groundedSfcMassBalApplied', groundedSfcMassBalApplied)
call mpas_pool_get_array(geometryPool, 'basalMassBal', basalMassBal)
call mpas_pool_get_array(geometryPool, 'groundedBasalMassBal', groundedBasalMassBal)
call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
- call mpas_pool_get_array(geometryPool, 'layerThicknessEdge', layerThicknessEdge)
+ call mpas_pool_get_array(geometryPool, 'groundedToFloatingThickness', groundedToFloatingThickness)
call mpas_pool_get_array(velocityPool, 'surfaceSpeed', surfaceSpeed)
call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed)
- call mpas_pool_get_array(velocityPool, 'layerNormalVelocity', layerNormalVelocity)
+ call mpas_pool_get_array(velocityPool, 'fluxAcrossGroundingLine', fluxAcrossGroundingLine)
+ call mpas_pool_get_array(velocityPool, 'normalVelocity', normalVelocity)
! get region cell masks from regionMasks.nc input file
call mpas_pool_get_array(regionsPool, 'regionCellMasks', regionCellMasks)
@@ -292,7 +301,10 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
allocate(blockRegionMaxBasalSpeed(nRegions)); allocate(blockRegionMaxSurfaceSpeed(nRegions))
allocate(blockSumRegionSfcMassBal(nRegions)); allocate(blockSumRegionBasalMassBal(nRegions))
allocate(blockSumRegionGroundedBasalMassBal(nRegions)); allocate(blockSumRegionFloatingBasalMassBal(nRegions))
- allocate(blockSumRegionCalvingFlux(nRegions)); allocate(blockSumRegionGLflux(nRegions))
+ allocate(blockSumRegionGroundedSfcMassBal(nRegions)); allocate(blockSumRegionFloatingSfcMassBal(nRegions))
+ allocate(blockSumRegionCalvingFlux(nRegions))
+ allocate(blockSumRegionGLflux(nRegions))
+ allocate(blockRegionGLMigrationFlux(nRegions))
blockSumRegionIceArea = 0.0_RKIND; blockSumRegionIceVolume = 0.0_RKIND
blockSumRegionVAF = 0.0_RKIND
@@ -301,8 +313,11 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
blockRegionThickMin = 10000.0_RKIND; blockRegionThickMax = 0.0_RKIND
blockRegionMaxBasalSpeed = 0.0_RKIND; blockRegionMaxSurfaceSpeed = 0.0_RKIND
blockSumRegionSfcMassBal = 0.0_RKIND; blockSumRegionBasalMassBal = 0.0_RKIND
+ blockSumRegionGroundedSfcMassBal = 0.0_RKIND; blockSumRegionFloatingSfcMassBal = 0.0_RKIND
blockSumRegionGroundedBasalMassBal = 0.0_RKIND; blockSumRegionFloatingBasalMassBal = 0.0_RKIND
- blockSumRegionCalvingFlux = 0.0_RKIND; blockSumRegionGLflux = 0.0_RKIND
+ blockSumRegionCalvingFlux = 0.0_RKIND
+ blockSumRegionGLflux = 0.0_RKIND
+ blockRegionGLMigrationFlux = 0.0_RKIND
do iCell = 1,nCellsSolve ! loop over cells
! do iGroup = 1,nRegionGroups ! loop over groups
@@ -341,23 +356,33 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
( real(regionCellMasks(iRegion,iCell),RKIND) * areaCell(iCell) &
* thickness(iCell) * real(li_mask_is_floating_ice_int(cellMask(iCell)),RKIND) )
- ! regional sum of sfc mass balance (kg yr^{-1})
+ ! regional sum of sfc mass balance (kg yr^{-1})
blockSumRegionSfcMassBal(iRegion) = blockSumRegionSfcMassBal(iRegion) + ( real(regionCellMasks(iRegion,iCell),RKIND) &
- * real(li_mask_is_ice_int(cellMask(iCell)),RKIND) * areaCell(iCell) * sfcMassBal(iCell) * scyr )
+ * areaCell(iCell) * sfcMassBalApplied(iCell) * scyr )
+
+ ! regional sum of sfc mass balance on grounded ice (kg yr^{-1})
+ blockSumRegionGroundedSfcMassBal(iRegion) = blockSumRegionGroundedSfcMassBal(iRegion) + &
+ ( real(regionCellMasks(iRegion,iCell),RKIND) &
+ * areaCell(iCell) * groundedSfcMassBalApplied(iCell) * scyr)
+
+ ! regional sum of sfc mass balance on floatingice (kg yr^{-1})
+ blockSumRegionFloatingSfcMassBal(iRegion) = blockSumRegionFloatingSfcMassBal(iRegion) + &
+ ( real(regionCellMasks(iRegion,iCell),RKIND) &
+ * areaCell(iCell) * (sfcMassBalApplied(iCell) - groundedSfcMassBalApplied(iCell)) * scyr)
! regional sum of basal mass balance (kg yr^{-1})
blockSumRegionBasalMassBal(iRegion) = blockSumRegionBasalMassBal(iRegion) + &
( real(regionCellMasks(iRegion,iCell),RKIND) * real(li_mask_is_ice_int(cellMask(iCell)),RKIND) &
* areaCell(iCell) * basalMassBal(iCell) * scyr )
- ! regional sum of grounded basal mass balance (kg yr^{-1})
+ ! regional sum of floating basal mass balance (kg yr^{-1})
blockSumRegionFloatingBasalMassBal(iRegion) = blockSumRegionFloatingBasalMassBal(iRegion) + &
( real(regionCellMasks(iRegion,iCell),RKIND) * real(li_mask_is_floating_ice_int(cellMask(iCell)),RKIND) &
* areaCell(iCell) * floatingBasalMassBal(iCell) * scyr )
- ! regional sum of floating basal mass balance (kg yr^{-1})
+ ! regional sum of grounded basal mass balance (kg yr^{-1})
blockSumRegionGroundedBasalMassBal(iRegion) = blockSumRegionGroundedBasalMassBal(iRegion) + &
- ( real(regionCellMasks(iRegion,iCell),RKIND) * real(li_mask_is_ice_int(cellMask(iCell)),RKIND) &
+ ( real(regionCellMasks(iRegion,iCell),RKIND) * real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) &
* areaCell(iCell) * groundedBasalMassBal(iCell) * scyr )
! regional sum of mass lass due do calving (kg yr^{-1})
@@ -387,44 +412,35 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
blockRegionMaxBasalSpeed(iRegion) = basalSpeed(iCell)
endif
+ ! GL migration flux
+ blockRegionGLMigrationFlux(iRegion) = blockRegionGLMigrationFlux(iRegion) + &
+ groundedToFloatingThickness(iCell) * areaCell(iCell) * rhoi / (deltat / scyr)
+
end do ! end loop over regions
! end do ! end loop over groups
end do ! end loop over cells
- do iEdge = 1,nEdgesSolve ! loop over edges
- ! do iGroup = 1,nRegionGroups ! loop over groups
- do iRegion = 1,nRegions ! loop over regions
+ do iEdge = 1,nEdgesSolve ! loop over edges
if (li_mask_is_grounding_line(edgeMask(iEdge))) then
- ! Determine sign of this edge relative to GL
- ! (+=grounded to floating, -=floating to grounded)
- iCell1 = cellsOnEdge(1,iEdge)
- iCell2 = cellsOnEdge(2,iEdge)
- if (li_mask_is_grounded_ice(cellMask(iCell1))) then
- fluxSign = 1.0_RKIND
+ ! Determine upwind cell - we are choosing to assign edge quantities to the region of the upwind cell
+ if (normalVelocity(1,iEdge) > 0.0_RKIND) then ! using surface velo to determine upwind cell
+ ! upwind cell is cell 1 on this edge
+ upwindCell = cellsOnEdge(1,iEdge)
else
- fluxSign = -1.0_RKIND
+ ! upwind cell is cell 2 on this edge
+ upwindCell = cellsOnEdge(2,iEdge)
endif
- ! first need to determine if the edge flux is being calc. on is part of the region of interest
- ! Use cellsOnEdge indices from above to index relevant regionCellMasks values and sum
- if(regionCellMasks(iRegion,iCell1) + regionCellMasks(iRegion,iCell2) > 0) then
-
- ! Loop over levels
- do k = 1, nVertLevels
- ! Flux across GL, units = kg/yr
- blockSumRegionGLflux(iRegion) = blockSumRegionGLflux(iRegion) + fluxSign * layerNormalVelocity(k, iEdge) * &
- dvEdge(iEdge) * layerThicknessEdge(k, iEdge) &
- * scyr * config_ice_density ! convert from m^3/s to kg/yr
- end do ! end loop over levels
-
- end if ! if edge is on cell in region of interest
-
+ do iRegion = 1,nRegions ! find this edge's region(s)
+ if(regionCellMasks(iRegion, upwindCell) == 1) then
+ ! assign the GL flux from this edge to the stat
+ blockSumRegionGLflux(iRegion) = blockSumRegionGLflux(iRegion) + &
+ fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) * scyr * config_ice_density ! convert from m^3/s to kg/yr
+ end if ! if edge is on cell in region of interest
+ end do ! end loop over regions
end if ! if GL
-
- end do ! end loop over regions
- ! end do ! end loop over groups
end do ! end loop over edges
block => block % next
@@ -451,7 +467,7 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
sums = 0.0_RKIND
reductions = 0.0_RKIND
-
+
sums(1) = blockSumRegionIceArea(iRegion)
sums(2) = blockSumRegionIceVolume(iRegion)
sums(3) = blockSumRegionGroundedIceArea(iRegion)
@@ -459,13 +475,16 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
sums(5) = blockSumRegionFloatingIceArea(iRegion)
sums(6) = blockSumRegionFloatingIceVolume(iRegion)
sums(7) = blockSumRegionSfcMassBal(iRegion)
- sums(8) = blockSumRegionBasalMassBal(iRegion)
- sums(9) = blockSumRegionGroundedBasalMassBal(iRegion)
- sums(10) = blockSumRegionFloatingBasalMassBal(iRegion)
- sums(11) = blockSumRegionCalvingFlux(iRegion)
- sums(12) = blockSumRegionVAF(iRegion)
- sums(13) = blockSumRegionGLflux(iRegion)
- nVars = 13
+ sums(8) = blockSumRegionGroundedSfcMassBal(iRegion)
+ sums(9) = blockSumRegionFloatingSfcMassBal(iRegion)
+ sums(10) = blockSumRegionBasalMassBal(iRegion)
+ sums(11) = blockSumRegionGroundedBasalMassBal(iRegion)
+ sums(12) = blockSumRegionFloatingBasalMassBal(iRegion)
+ sums(13) = blockSumRegionCalvingFlux(iRegion)
+ sums(14) = blockSumRegionVAF(iRegion)
+ sums(15) = blockSumRegionGLflux(iRegion)
+ sums(16) = blockRegionGLMigrationFlux(iRegion)
+ nVars = 16
call mpas_dmpar_sum_real_array(dminfo, nVars, sums(1:nVars), reductions(1:nVars))
@@ -473,7 +492,7 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
do while (associated(block))
call mpas_pool_get_subpool(block % structs, 'regionalStatsAM', regionalStatsAMPool)
-
+
! get values from regional stats pool
call mpas_pool_get_array(regionalStatsAMPool, 'regionalIceArea', regionalIceArea)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalIceVolume', regionalIceVolume)
@@ -485,6 +504,8 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
call mpas_pool_get_array(regionalStatsAMPool, 'regionalIceThicknessMean', regionalIceThicknessMean)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumSfcMassBal', regionalSumSfcMassBal)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalAvgNetAccumulation', regionalAvgNetAccumulation)
+ call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumGroundedSfcMassBal', regionalSumGroundedSfcMassBal)
+ call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumFloatingSfcMassBal', regionalSumFloatingSfcMassBal)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumBasalMassBal', regionalSumBasalMassBal)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumGroundedBasalMassBal', regionalSumGroundedBasalMassBal)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalAvgGroundedBasalMelt', regionalAvgGroundedBasalMelt)
@@ -492,7 +513,9 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
call mpas_pool_get_array(regionalStatsAMPool, 'regionalAvgSubshelfMelt', regionalAvgSubshelfMelt)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumCalvingFlux', regionalSumCalvingFlux)
call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumGroundingLineFlux', regionalSumGroundingLineFlux)
-
+ call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumGroundingLineMigrationFlux', &
+ regionalSumGroundingLineMigrationFlux)
+
regionalIceArea(iRegion) = reductions(1)
regionalIceVolume(iRegion) = reductions(2)
regionalGroundedIceArea(iRegion) = reductions(3)
@@ -500,19 +523,35 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
regionalFloatingIceArea(iRegion) = reductions(5)
regionalFloatingIceVolume(iRegion) = reductions(6)
regionalSumSfcMassBal(iRegion) = reductions(7)
- regionalSumBasalMassBal(iRegion) = reductions(8)
- regionalSumGroundedBasalMassBal(iRegion) = reductions(9)
- regionalSumFloatingBasalMassBal(iRegion) = reductions(10)
- regionalSumCalvingFlux(iRegion) = reductions(11)
- regionalVolumeAboveFloatation(iRegion) = reductions(12)
- regionalSumGroundingLineFlux(iRegion) = reductions(13)
-
- regionalIceThicknessMean(iRegion) = regionalIceVolume(iRegion) / regionalIceArea(iRegion)
- regionalAvgNetAccumulation(iRegion) = regionalSumSfcMassBal(iRegion) / regionalIceArea(iRegion) / rhoi
- regionalAvgGroundedBasalMelt(iRegion) = -1.0_RKIND * regionalSumGroundedBasalMassBal(iRegion) / &
- regionalGroundedIceArea(iRegion) / rhoi
- regionalAvgSubshelfMelt(iRegion) = -1.0_RKIND * regionalSumFloatingBasalMassBal(iRegion) / &
- regionalFloatingIceArea(iRegion) / rhoi
+ regionalSumGroundedSfcMassBal(iRegion) = reductions(8)
+ regionalSumFloatingSfcMassBal(iRegion) = reductions(9)
+ regionalSumBasalMassBal(iRegion) = reductions(10)
+ regionalSumGroundedBasalMassBal(iRegion) = reductions(11)
+ regionalSumFloatingBasalMassBal(iRegion) = reductions(12)
+ regionalSumCalvingFlux(iRegion) = reductions(13)
+ regionalVolumeAboveFloatation(iRegion) = reductions(14)
+ regionalSumGroundingLineFlux(iRegion) = reductions(15)
+ regionalSumGroundingLineMigrationFlux(iRegion) = reductions(16)
+
+ if (regionalIceArea(iRegion) > 0.0_RKIND) then
+ regionalIceThicknessMean(iRegion) = regionalIceVolume(iRegion) / regionalIceArea(iRegion)
+ regionalAvgNetAccumulation(iRegion) = regionalSumSfcMassBal(iRegion) / regionalIceArea(iRegion) / rhoi
+ else
+ regionalIceThicknessMean(iRegion) = 0.0_RKIND
+ regionalAvgNetAccumulation(iRegion) = 0.0_RKIND
+ endif
+ if (regionalGroundedIceArea(iRegion) > 0.0_RKIND) then
+ regionalAvgGroundedBasalMelt(iRegion) = -1.0_RKIND * regionalSumGroundedBasalMassBal(iRegion) / &
+ regionalGroundedIceArea(iRegion) / rhoi
+ else
+ regionalAvgGroundedBasalMelt(iRegion) = 0.0_RKIND
+ endif
+ if (regionalFloatingIceArea(iRegion) > 0.0_RKIND) then
+ regionalAvgSubshelfMelt(iRegion) = -1.0_RKIND * regionalSumFloatingBasalMassBal(iRegion) / &
+ regionalFloatingIceArea(iRegion) / rhoi
+ else
+ regionalAvgSubshelfMelt(iRegion) = 0.0_RKIND
+ endif
block => block % next
end do
@@ -556,7 +595,7 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
regionalBasalSpeedMax(iRegion) = reductions(3)
block => block % next
end do
-
+
end do ! loop over regions
! deallocate storage for sums over blocks
@@ -567,10 +606,13 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err)!{{{
deallocate(blockRegionThickMin); deallocate(blockRegionThickMax)
deallocate(blockRegionMaxBasalSpeed); deallocate(blockRegionMaxSurfaceSpeed)
deallocate(blockSumRegionSfcMassBal); deallocate(blockSumRegionBasalMassBal)
+ deallocate(blockSumRegionGroundedSfcMassBal); deallocate(blockSumRegionFloatingSfcMassBal)
deallocate(blockSumRegionGroundedBasalMassBal); deallocate(blockSumRegionFloatingBasalMassBal)
- deallocate(blockSumRegionCalvingFlux); deallocate(blockSumRegionGLflux)
+ deallocate(blockSumRegionCalvingFlux)
+ deallocate(blockSumRegionGLflux)
+ deallocate(blockRegionGLMigrationflux)
- end subroutine li_compute_regional_stats!}}}
+ end subroutine li_compute_regional_stats
!***********************************************************************
!
@@ -585,7 +627,7 @@ end subroutine li_compute_regional_stats!}}}
!
!-----------------------------------------------------------------------
- subroutine li_restart_regional_stats(domain, memberName, err)!{{{
+ subroutine li_restart_regional_stats(domain, memberName, err)
!-----------------------------------------------------------------
!
@@ -619,7 +661,7 @@ subroutine li_restart_regional_stats(domain, memberName, err)!{{{
err = 0
- end subroutine li_restart_regional_stats!}}}
+ end subroutine li_restart_regional_stats
!***********************************************************************
!
@@ -634,7 +676,7 @@ end subroutine li_restart_regional_stats!}}}
!
!-----------------------------------------------------------------------
- subroutine li_finalize_regional_stats(domain, memberName, err)!{{{
+ subroutine li_finalize_regional_stats(domain, memberName, err)
!-----------------------------------------------------------------
!
@@ -668,7 +710,7 @@ subroutine li_finalize_regional_stats(domain, memberName, err)!{{{
err = 0
- end subroutine li_finalize_regional_stats!}}}
+ end subroutine li_finalize_regional_stats
end module li_regional_stats
diff --git a/src/core_landice/external_albany_version b/src/core_landice/external_albany_version
index 4f00bb26c2..66846f145a 100644
--- a/src/core_landice/external_albany_version
+++ b/src/core_landice/external_albany_version
@@ -1 +1 @@
-d3968fc9e9b4f825f87d31564ea67d3e4fab656b
+b745455e8ec7358d8be887a986c3509cec97cbfb
diff --git a/src/core_landice/external_trilinos_version b/src/core_landice/external_trilinos_version
index a7fd78f3de..6449871951 100644
--- a/src/core_landice/external_trilinos_version
+++ b/src/core_landice/external_trilinos_version
@@ -1 +1 @@
-9630bc5b179a0c5e1537923e3450ff79bb3ae78d
+c29bb03b7743745f341efad5d82c8fc2dc93b274
diff --git a/src/core_landice/landice.cmake b/src/core_landice/landice.cmake
index 0d580d7800..3b550fd340 100644
--- a/src/core_landice/landice.cmake
+++ b/src/core_landice/landice.cmake
@@ -69,6 +69,7 @@ list(APPEND RAW_SOURCES
core_landice/mode_forward/mpas_li_velocity_simple.F
core_landice/mode_forward/mpas_li_velocity_external.F
core_landice/mode_forward/mpas_li_subglacial_hydro.F
+ core_landice/mode_forward/mpas_li_bedtopo.F
)
if (CPPDEFS MATCHES ".*MPAS_LI_BUILD_INTERFACE.*")
diff --git a/src/core_landice/mode_forward/Interface_velocity_solver.cpp b/src/core_landice/mode_forward/Interface_velocity_solver.cpp
index 505268788b..3971076ba9 100644
--- a/src/core_landice/mode_forward/Interface_velocity_solver.cpp
+++ b/src/core_landice/mode_forward/Interface_velocity_solver.cpp
@@ -14,32 +14,30 @@ distributed with this code, or at http://mpas-dev.github.com/license.html
#include
#include
#include
+#include
+#include
#include "Interface_velocity_solver.hpp"
-//#include
-//#include
-//#include
// ===================================================
//! Namespaces
// ===================================================
-//typedef std::list exchangeList_Type;
+#define changeTrianglesOwnership
+
// ice_problem pointer
int Ordering = 0; //ordering ==0 means that the mesh is extruded layerwise, whereas ordering==1 means that the mesh is extruded columnwise.
MPI_Comm comm, reducedComm;
bool isDomainEmpty = true;
-bool initialize_velocity = true;
bool first_time_step = true;
int nCells_F, nEdges_F, nVertices_F;
int nCellsSolve_F, nEdgesSolve_F, nVerticesSolve_F;
-int nVertices, nEdges, nTriangles, nGlobalVertices, nGlobalEdges,
- nGlobalTriangles;
+int nVertices, nEdges, nTriangles, globalVertexStride, globalEdgeStride,globalTriangleStride;
int maxNEdgesOnCell_F;
int const *cellsOnEdge_F, *cellsOnVertex_F, *verticesOnCell_F,
- *verticesOnEdge_F, *edgesOnCell_F, *indexToCellID_F, *nEdgesOnCells_F,
- *verticesMask_F, *cellsMask_F, *dirichletCellsMask_F, *floatingEdgesMask_F;
+ *verticesOnEdge_F, *edgesOnCell_F, *indexToCellID_F, *indexToEdgeID_F, *indexToVertexID_F, *nEdgesOnCells_F,
+ *verticesMask_F, *cellsMask_F, *dirichletCellsMask_F;
std::vector layersRatio, levelsNormalizedThickness;
int nLayers;
double const *xCell_F, *yCell_F, *zCell_F, *xVertex_F, *yVertex_F, *zVertex_F, *areaTriangle_F;
@@ -48,6 +46,7 @@ const double unit_length = 1000;
const double T0 = 273.15;
const double secondsInAYear = 31536000.0; // This may vary slightly in MPAS, but this should be close enough for how this is used.
double minThickness = 1e-3; //[km]
+double thermal_thickness_limit; //[km]
const double minBeta = 1e-5;
double rho_ice;
double rho_ocean;
@@ -63,13 +62,13 @@ int original_stderr; // the location of stderr before we captured it
int Interface_stdout; // the location of stdout as we use it here
//void *phgGrid = 0;
-std::vector edgesToReceive, fCellsToReceive, indexToTriangleID,
- verticesOnTria, trianglesOnEdge, trianglesPositionsOnEdge, verticesOnEdge,
- trianglesProcIds, reduced_ranks;
-std::vector indexToVertexID, vertexToFCell, triangleToFVertex, indexToEdgeID, edgeToFEdge,
- mask, fVertexToTriangleID, fCellToVertex, floatingEdgesIds, dirichletNodesIDs;
-std::vector temperatureOnTetra, dissipationHeatOnTetra, velocityOnVertices, velocityOnCells,
- elevationData, thicknessData, betaData, bedTopographyData, temperatureData, smbData, thicknessOnCells;
+std::vector indexToTriangleID,
+ verticesOnTria, trianglesOnEdge, verticesOnEdge,
+ trianglesProcIds, reduced_ranks;
+std::vector indexToVertexID, vertexToFCell, vertexProcIDs, triangleToFVertex, indexToEdgeID, edgeToFEdge,
+ fVertexToTriangleID, fCellToVertex, iceMarginEdgesLIds, dirichletNodesIDs;
+std::vector dissipationHeatOnPrisms, velocityOnVertices, velocityOnCells,
+ elevationData, thicknessData, betaData, bedTopographyData, stiffnessFactorData, effecPressData, muFrictionData, temperatureDataOnPrisms, smbData, thicknessOnCells, bodyForceOnBasalCell;
std::vector isVertexBoundary, isBoundaryEdge;
// only needed for creating ASCII mesh
@@ -78,6 +77,7 @@ std::vector smbUncertaintyData;
std::vector bmbData, bmbUncertaintyData;
std::vector observedVeloXData, observedVeloYData, observedVeloUncertaintyData;
std::vector observedDHDtData, observedDHDtUncertaintyData;
+std::vector surfaceAirTemperatureData, basalHeatFluxData;
std::vector indexToCellIDData;
int numBoundaryEdges;
@@ -86,8 +86,8 @@ double radius;
exchangeList_Type const *sendCellsList_F = 0, *recvCellsList_F = 0;
exchangeList_Type const *sendEdgesList_F = 0, *recvEdgesList_F = 0;
exchangeList_Type const *sendVerticesList_F = 0, *recvVerticesList_F = 0;
-exchangeList_Type sendCellsListReversed, recvCellsListReversed,
- sendEdgesListReversed, recvEdgesListReversed;
+exchangeList_Type sendVerticesListReversed, recvVerticesListReversed,
+ sendCellsListReversed, recvCellsListReversed;
exchange::exchange(int _procID, int const* vec_first, int const* vec_last,
int fieldDim) :
@@ -106,24 +106,25 @@ int velocity_solver_init_mpi(int* fComm) {
// get MPI_Comm from Fortran
comm = MPI_Comm_f2c(*fComm);
reducedComm = MPI_COMM_NULL; // initialize to null so we can check if set
-
- return 0;
+ return velocity_solver_init_mpi__(comm);
}
void velocity_solver_set_parameters(double const* gravity_F, double const* ice_density_F, double const* ocean_density_F,
double const* sea_level_F, double const* flowParamA_F,
- double const* enhancementFactor_F, double const* flowLawExponent_F, double const* dynamic_thickness_F,
+ double const* flowLawExponent_F, double const* dynamic_thickness_F,
double const* clausius_clapeyron_coeff,
+ double const* thermal_thickness_limit_F,
int const* li_mask_ValueDynamicIce, int const* li_mask_ValueIce,
bool const* use_GLP_F) {
// This function sets parameter values used by MPAS on the C/C++ side
rho_ice = *ice_density_F;
rho_ocean = *ocean_density_F;
+ thermal_thickness_limit = *thermal_thickness_limit_F / unit_length; // Import with Albany scaling
dynamic_ice_bit_value = *li_mask_ValueDynamicIce;
ice_present_bit_value = *li_mask_ValueIce;
velocity_solver_set_physical_parameters__(*gravity_F, rho_ice, *ocean_density_F, *sea_level_F/unit_length, *flowParamA_F*std::pow(unit_length,4)*secondsInAYear,
- *enhancementFactor_F, *flowLawExponent_F, *dynamic_thickness_F/unit_length, *use_GLP_F, *clausius_clapeyron_coeff);
+ *flowLawExponent_F, *dynamic_thickness_F/unit_length, *use_GLP_F, *clausius_clapeyron_coeff);
}
@@ -132,11 +133,6 @@ void velocity_solver_export_2d_data(double const* lowerSurface_F,
double const* thickness_F, double const* beta_F) {
if (isDomainEmpty)
return;
-#ifdef LIFEV
- import2DFields(lowerSurface_F, thickness_F, beta_F, minThickneess);
- velocity_solver_export_2d_data__(reducedComm, elevationData, thicknessData,
- betaData, indexToVertexID);
-#endif
}
void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
@@ -147,6 +143,8 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
int const* _verticesOnCell_F, int const* _verticesOnEdge_F,
int const* _edgesOnCell_F, int const* _nEdgesOnCells_F,
int const* _indexToCellID_F,
+ int const* _indexToEdgeID_F,
+ int const* _indexToVertexID_F,
double const* _xCell_F, double const* _yCell_F, double const* _zCell_F,
double const* _xVertex_F, double const* _yVertex_F, double const* _zVertex_F,
double const* _areaTriangle_F,
@@ -169,7 +167,9 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
verticesOnEdge_F = _verticesOnEdge_F;
edgesOnCell_F = _edgesOnCell_F;
nEdgesOnCells_F = _nEdgesOnCells_F;
+ indexToEdgeID_F = _indexToEdgeID_F;
indexToCellID_F = _indexToCellID_F;
+ indexToVertexID_F = _indexToVertexID_F;
xCell_F = _xCell_F;
yCell_F = _yCell_F;
zCell_F = _zCell_F;
@@ -177,7 +177,6 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
yVertex_F = _yVertex_F;
zVertex_F = _zVertex_F;
areaTriangle_F = _areaTriangle_F;
- mask.resize(nVertices_F);
thicknessOnCells.resize(nCellsSolve_F);
@@ -190,9 +189,6 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
recvVerticesList_F = new exchangeList_Type(
unpackMpiArray(recvVerticesArray_F));
- trianglesProcIds.resize(nVertices_F);
- getProcIds(trianglesProcIds, recvVerticesList_F);
-
if (radius > 10) {
xCellProjected.resize(nCells_F);
yCellProjected.resize(nCells_F);
@@ -211,23 +207,6 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
}
void velocity_solver_init_l1l2(double const* levelsRatio_F) {
-#ifdef LIFEV
- velocityOnVertices.resize(2 * nVertices * (nLayers + 1), 0.);
- velocityOnCells.resize(2 * nCells_F * (nLayers + 1), 0.);
-
- if (isDomainEmpty)
- return;
-
- layersRatio.resize(nLayers);
- // !!Indexing of layers is reversed
- for (int i = 0; i < nLayers; i++)
- layersRatio[i] = levelsRatio_F[nLayers - 1 - i];
- //std::copy(levelsRatio_F, levelsRatio_F+nLayers, layersRatio.begin());
- mapCellsToVertices(velocityOnCells, velocityOnVertices, 2, nLayers, Ordering);
-
- velocity_solver_init_l1l2__(layersRatio, velocityOnVertices, initialize_velocity);
- initialize_velocity = false;
-#endif
}
@@ -237,82 +216,9 @@ void velocity_solver_solve_l1l2(double const* lowerSurface_F,
double const* thickness_F, double const* beta_F, double const* temperature_F,
double* const dirichletVelocityXValue, double* const dirichletVelocitYValue,
double* u_normal_F, double* xVelocityOnCell, double* yVelocityOnCell) {
-
-#ifdef LIFEV
-
- std::fill(u_normal_F, u_normal_F + nEdges_F * (nLayers+1), 0.);
-
- double localSum(0), sum(0);
-
- for (int i = 0; i < nCellsSolve_F; i++) {
- localSum = std::max(localSum,
- std::fabs(thickness_F[i] - thicknessOnCells[i]));
- }
-
- MPI_Allreduce(&localSum, &sum, 1, MPI_DOUBLE, MPI_MAX, comm);
-
- std::cout << "Thickness change: " << sum << std::endl;
- std::copy(thickness_F, thickness_F + nCellsSolve_F, &thicknessOnCells[0]);
-
- if (!isDomainEmpty) {
- std::vector temperatureData(nLayers * nVertices);
-
- import2DFields(lowerSurface_F, thickness_F, beta_F, minThickness);
-
- for (int index = 0; index < nVertices; index++) {
- int iCell = vertexToFCell[index];
- for (int il = 0; il < nLayers; il++) {
- temperatureData[index + il * nVertices] = temperature_F[iCell * nLayers
- + (nLayers - il - 1)];
- }
- }
-
-
- velocity_solver_solve_l1l2__(elevationData, thicknessData, betaData,
- temperatureData, indexToVertexID, velocityOnVertices);
- }
-
-
- mapVerticesToCells (velocityOnVertices, &velocityOnCells[0], 2, nLayers, Ordering);
-
- //computing x, yVelocityOnCell
- int sizeVelOnCell = nCells_F * (nLayers + 1);
- for(int iCell=0; iCell regulThk(thicknessData);
- for (int index = 0; index < nVertices; index++)
- regulThk[index] = std::max(1e-4, thicknessData[index]);
-
- std::vector mpasIndexToVertexID(nVertices);
- for (int i = 0; i < nVertices; i++) {
- mpasIndexToVertexID[i] = indexToCellID_F[vertexToFCell[i]];
- }
-#ifdef LIFEV
- velocity_solver_export_l1l2_velocity__(layersRatio, elevationData, regulThk, mpasIndexToVertexID, reducedComm);
-#endif
-}
+void velocity_solver_export_l1l2_velocity() {}
void velocity_solver_init_fo(double const *levelsRatio_F) {
@@ -326,23 +232,16 @@ void velocity_solver_init_fo(double const *levelsRatio_F) {
// !!Indexing of layers is reversed
for (int i = 0; i < nLayers; i++)
layersRatio[i] = levelsRatio_F[nLayers - 1 - i];
- //std::copy(levelsRatio_F, levelsRatio_F+nLayers, layersRatio.begin());
-
mapCellsToVertices(velocityOnCells, velocityOnVertices, 2, nLayers, Ordering);
-
-#ifdef LIFEV
- velocity_solver_init_fo__(layersRatio, velocityOnVertices, indexToVertexID, initialize_velocity);
-#endif
- // iceProblemPtr->initializeSolverFO(layersRatio, velocityOnVertices, thicknessData, elevationData, indexToVertexID, initialize_velocity);
- initialize_velocity = false;
}
void velocity_solver_solve_fo(double const* bedTopography_F, double const* lowerSurface_F,
- double const* thickness_F, double const* beta_F,
- double const* smb_F, double const* temperature_F,
+ double const* thickness_F, double * beta_F,
+ double const* smb_F, double const* temperature_F, double const* stiffnessFactor_F,
+ double const* effecPress_F, double const* muFriction_F,
double* const dirichletVelocityXValue, double* const dirichletVelocitYValue,
- double* u_normal_F, double* dissipation_heat_F,
+ double* u_normal_F, double* bodyForce_F, double* dissipation_heat_F,
double* xVelocityOnCell, double* yVelocityOnCell, double const* deltat,
int *error) {
@@ -368,52 +267,36 @@ void velocity_solver_solve_fo(double const* bedTopography_F, double const* lower
if (!isDomainEmpty) {
-#ifdef LIFEV
- double localSum(0), sum(0);
-
- for (int i = 0; i < nCellsSolve_F; i++) {
- localSum = std::max(localSum,
- std::fabs(thickness_F[i] - thicknessOnCells[i]));
- }
-
- MPI_Allreduce(&localSum, &sum, 1, MPI_DOUBLE, MPI_MAX, comm);
-
- std::cout << "Thickness change: " << sum << std::endl;
- std::copy(thickness_F, thickness_F + nCellsSolve_F, &thicknessOnCells[0]);
-#endif
-
-
-
- std::map bdExtensionMap;
- import2DFields(bdExtensionMap, bedTopography_F, lowerSurface_F, thickness_F, beta_F, temperature_F, smb_F, minThickness);
+ std::vector > marineBdyExtensionMap;
+ importFields(marineBdyExtensionMap, bedTopography_F, lowerSurface_F, thickness_F, beta_F, stiffnessFactor_F, effecPress_F, muFriction_F, temperature_F, smb_F, minThickness);
std::vector regulThk(thicknessData);
for (int index = 0; index < nVertices; index++)
regulThk[index] = std::max(1e-4, thicknessData[index]);
- importP0Temperature();
-
- dissipationHeatOnTetra.resize(3 * nLayers * indexToTriangleID.size());
+ dissipationHeatOnPrisms.resize(nLayers * indexToTriangleID.size());
+ bodyForceOnBasalCell.resize(indexToTriangleID.size());
std::cout << "\n\nTimeStep: "<< *deltat << "\n\n"<< std::endl;
double dt = (*deltat)/secondsInAYear;
int albany_error;
- velocity_solver_solve_fo__(nLayers, nGlobalVertices, nGlobalTriangles,
+ velocity_solver_solve_fo__(nLayers, globalVertexStride, globalTriangleStride,
Ordering, first_time_step, indexToVertexID, indexToTriangleID, minBeta,
regulThk, levelsNormalizedThickness, elevationData, thicknessData,
betaData, bedTopographyData, smbData,
- temperatureOnTetra, dissipationHeatOnTetra, velocityOnVertices,
+ stiffnessFactorData, effecPressData, muFrictionData,
+ temperatureDataOnPrisms, bodyForceOnBasalCell, dissipationHeatOnPrisms, velocityOnVertices,
albany_error, dt);
*error=albany_error;
}
-
+
exportDissipationHeat(dissipation_heat_F);
- std::vector mpasIndexToVertexID(nVertices);
- for (int i = 0; i < nVertices; i++) {
- mpasIndexToVertexID[i] = indexToCellID_F[vertexToFCell[i]];
+ if (bodyForce_F!=nullptr) {
+ exportBodyForce(bodyForce_F);
}
+ exportBeta(beta_F);
mapVerticesToCells(velocityOnVertices, &velocityOnCells[0], 2, nLayers,
Ordering);
@@ -427,81 +310,15 @@ void velocity_solver_solve_fo(double const* bedTopography_F, double const* lower
xVelocityOnCell[indexReversed] = velocityOnCells[index];
yVelocityOnCell[indexReversed] = velocityOnCells[index+sizeVelOnCell];
}
-
- if (!isDomainEmpty)
get_prism_velocity_on_FEdges(u_normal_F, velocityOnCells, edgeToFEdge);
-
+ allToAll(u_normal_F, sendEdgesList_F, recvEdgesList_F, nLayers+1);
std::vector velOnEdges(nEdges * (nLayers+1));
for (int i = 0; i < nEdges; i++) {
for (int il = 0; il < nLayers+1; il++) {
velOnEdges[i * (nLayers+1) + il] = u_normal_F[edgeToFEdge[i] * (nLayers+1) + il];
}
}
-
- allToAll(u_normal_F, &sendEdgesListReversed, &recvEdgesListReversed, nLayers+1);
-
- allToAll(u_normal_F, sendEdgesList_F, recvEdgesList_F, nLayers+1);
-
first_time_step = false;
-
-#ifdef LIFEV
-
- std::vector edgesProcId(nEdges_F), trianglesProcIds(nVertices_F);
- getProcIds(edgesProcId, recvEdgesList_F);
- getProcIds(trianglesProcIds, recvVerticesList_F);
-
- int localSumInt(0), sumInt(0);
-
- for (int i = 0; i < nEdges; i++) {
- for (int il = 0; il < 1; il++) {
- if (std::fabs(
- velOnEdges[i * (nLayers+1) + il]
- - u_normal_F[edgeToFEdge[i] * nLayers + il]) > 1e-9)
- // if(edgeToFEdge[i]>nEdgesSolve_F)
- {
- localSumInt++;
- int edge = edgeToFEdge[i];
- int gEdge = indexToEdgeID[i];
- ID fVertex0 = verticesOnEdge_F[2 * edge] - 1;
- ID fVertex1 = verticesOnEdge_F[2 * edge + 1] - 1;
- ID triaId0 = fVertexToTriangleID[fVertex0];
- ID triaId1 = fVertexToTriangleID[fVertex1];
- ID procTria0 = trianglesProcIds[fVertex0];
- ID procTria1 = trianglesProcIds[fVertex1];
- std::cout << "vs( " << velOnEdges[i * (nLayers+1) + il] << ", "
- << u_normal_F[edgeToFEdge[i] * nLayers + il] << ") ";
- std::cout << "edge: " << edge << ", gEdge: " << gEdge << ", on proc: "
- << edgesProcId[edgeToFEdge[i]];
- if (triaId0 != NotAnId) {
- std::cout << ". first tria0: " << triaId0 << " on proc: "
- << procTria0;
- }
- if (triaId1 != NotAnId) {
- std::cout << ".. second tria0:" << std::endl;
- }
- if ((triaId0 == NotAnId) || (triaId1 == NotAnId)) {
- std::cout << ". and to Tria: " << triaId1 << " on proc: " << procTria1
- << std::endl;
- }
-
- }
-
- //localSum = std::max(localSum, std::fabs(velOnEdges[i*nLayers+il] - u_normal_F[edgeToFEdge[i]*nLayers+il]));
- }
- }
-
- MPI_Allreduce(&localSumInt, &sumInt, 1, MPI_INT, MPI_SUM, comm);
-
- int localNum(sendEdgesListReversed.size()), num(0);
-
- MPI_Allreduce(&localNum, &num, 1, MPI_INT, MPI_SUM, comm);
-
- std::cout << "Edges change: " << sumInt << " " << num << std::endl;
-
-#endif
-
-
-
}
@@ -525,7 +342,7 @@ void velocity_solver_finalize() {
/*duality:
*
- * mpas(F) | lifev
+ * mpas(F) | Albany LandIce (C++)
* ---------|---------
* cell | vertex
* vertex | triangle
@@ -533,14 +350,12 @@ void velocity_solver_finalize() {
*
*/
-void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cellsMask_F, int const* _dirichletCellsMask_F, int const* _floatingEdgesMask_F) {
+void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cellsMask_F, int const* _dirichletCellsMask_F) {
int numProcs, me;
-
verticesMask_F = _verticesMask_F;
cellsMask_F = _cellsMask_F;
verticesMask_F = _verticesMask_F;
dirichletCellsMask_F = _dirichletCellsMask_F;
- floatingEdgesMask_F = _floatingEdgesMask_F;
MPI_Comm_size(comm, &numProcs);
MPI_Comm_rank(comm, &me);
@@ -548,88 +363,156 @@ void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cel
numProcs + 1), globalOffsetVertices(numProcs + 1), globalOffsetEdge(
numProcs + 1);
+
+ // First, we compute the FE triangles belonging to this processor.
+ // If changeTrianglesOwnership is not define, the triangles belonging to this
+ // processor will be the subset of the triangles (MPAS vertices) owned by this proc
+ // that contain dynamic ice.
+ // If changeTrianglesOwnership is define, we rearrange the ownership of the triangles
+ // to improve the quality of the FE mesh and avoid corner cases (see below).
+
triangleToFVertex.clear();
triangleToFVertex.reserve(nVertices_F);
std::vector fVertexToTriangle(nVertices_F, NotAnId);
- bool changed = false;
- for (int i(0); i < nVerticesSolve_F; i++) {
- if ((verticesMask_F[i] & dynamic_ice_bit_value) && !isGhostTriangle(i)) {
- fVertexToTriangle[i] = triangleToFVertex.size();
- triangleToFVertex.push_back(i);
- }
- changed = changed || (verticesMask_F[i] != mask[i]);
- }
- for (int i(0); i < nVertices_F; i++)
- mask[i] = verticesMask_F[i];
+ //vector containing proc ranks for owned and shared FE triangles
+ trianglesProcIds.assign(nVertices_F,NotAnId);
+
+ //vector containing proc ranks for owned and shared MPAS cells
+ std::vector fCellsProcIds(nCells_F);
+ getProcIds(fCellsProcIds, recvCellsList_F);
+#ifdef changeTrianglesOwnership
+ std::vector fVerticesProcIds(nVertices_F);
+ getProcIds(fVerticesProcIds, recvVerticesList_F);
+ for (int i(0); i < nVertices_F; i++) {
+ int cellWithMinID=nCellsSolve_F;
+ if ((verticesMask_F[i] & dynamic_ice_bit_value)) {
+ int minCellId = std::numeric_limits::max();
+ int minCellIdProc(0);
+
+ int cellProc[3];
+ bool invalidCell=false;
+ for (int j = 0; j < 3; j++) {
+ int iCell = cellsOnVertex_F[3 * i + j] - 1;
+ if(iCell >= nCells_F) {
+ invalidCell = true;
+ break;
+ }
+ int cellID = indexToCellID_F[iCell];
+ cellProc[j] = fCellsProcIds[iCell];
+ if(cellID < minCellId) {
+ minCellId = cellID;
+ cellWithMinID = iCell;
+ minCellIdProc = cellProc[j];
+ }
+ }
+
+ if(invalidCell) continue;
+
+ // the proc that owns at least 2 nodes of the triangle i. If all nodes belong to different procs, procOwns2Nodes is set to -1
+ int procOwns2Nodes = ((cellProc[0] == cellProc[1]) || (cellProc[0] == cellProc[2])) ? cellProc[0] :
+ (cellProc[1] == cellProc[2]) ? cellProc[1] : -1;
+
+ int vertexProc = fVerticesProcIds[i];
+ bool triangleOwnsANode = (cellProc[0] == vertexProc) || (cellProc[1] == vertexProc) || (cellProc[2] == vertexProc);
- if (changed)
- std::cout << "mask changed!!" << std::endl;
+ //A triangle will be owned by a proc if:
+ // 1. the proc owns at least 2 nodes of the triangle associated to that vertex, OR
+ // 2. all the nodes of the triangle belong to three different procs, and the proc owns the fortran vertex and a node OR
+ // 3. the three nodes of the triangle and the fortran vertex belong to four different procs, and the proc owns the node with the minimum ID
- if ((me == 0) && (triangleToFVertex.size() == 0))
- for (int i(0); i < nVerticesSolve_F; i++) {
- if (!isGhostTriangle(i)) {
+ trianglesProcIds[i] = (procOwns2Nodes != -1) ? procOwns2Nodes :
+ triangleOwnsANode ? vertexProc :
+ minCellIdProc;
+
+ if (trianglesProcIds[i] == me) {
fVertexToTriangle[i] = triangleToFVertex.size();
triangleToFVertex.push_back(i);
- break;
- }
+ }
}
+ }
+#else
+ //in this case we just set the proc ranks for owned and shared FE triangles to the be the same as MPAS owned and shared vertices
+ getProcIds(trianglesProcIds, recvVerticesList_F);
+ for (int i(0); i < nVerticesSolve_F; i++) {
+ if (verticesMask_F[i] & dynamic_ice_bit_value) {
+ fVertexToTriangle[i] = triangleToFVertex.size();
+ triangleToFVertex.push_back(i);
+ }
+ }
+#endif
nTriangles = triangleToFVertex.size();
+ //Initialize the ice sheet problem with the number of FE triangles on this prov
initialize_iceProblem(nTriangles);
- //Compute the global number of triangles, and the localOffset on the local processor, such that a globalID = localOffset + index
- int localOffset(0);
- nGlobalTriangles = 0;
- computeLocalOffset(nTriangles, localOffset, nGlobalTriangles);
-
- //Communicate the globalIDs, computed locally, to the other processors.
- indexToTriangleID.resize(nTriangles);
-
- //To make local, not used
+ //Create a list of global IDs for FE triangles, using MPAS vertices IDs
fVertexToTriangleID.assign(nVertices_F, NotAnId);
- // std::vector fVertexToTriangleID(nVertices_F, NotAnId);
- for (int index(0); index < nTriangles; index++)
- fVertexToTriangleID[triangleToFVertex[index]] = index + localOffset;
-
+ for (int index(0); index < nTriangles; index++) {
+ fVertexToTriangleID[triangleToFVertex[index]] = indexToVertexID_F[triangleToFVertex[index]];
+ }
+
+#ifdef changeTrianglesOwnership
+ // because we change the ownership of some triangles, we need to first communicate back to the processors that used to own those triangles
+ // the data of the newly owned triangles. We do this by defining "reversed" send and receive lists, communicate back using those lists, and
+ // then communicate "forward" using the usual send and receive lists.
+ // We could join these two step in one communication, but for the moment we do that separately
+ createReverseExchangeLists(sendVerticesListReversed, recvVerticesListReversed, trianglesProcIds, indexToVertexID_F, recvVerticesList_F);
+ allToAll(fVertexToTriangleID, &sendVerticesListReversed, &recvVerticesListReversed);
+ allToAll(fVertexToTriangle, &sendVerticesListReversed, &recvVerticesListReversed);
+ allToAll(trianglesProcIds, sendVerticesList_F, recvVerticesList_F);
+#endif
allToAll(fVertexToTriangleID, sendVerticesList_F, recvVerticesList_F);
+ allToAll(fVertexToTriangle, sendVerticesList_F, recvVerticesList_F);
- for (int index(0); index < nTriangles; index++)
+ //we define the vector of global triangles Ids and compute the stride between the largest and the smallest Id globally
+ //This will be needed by the velocity solver to create the 3D FE mesh.
+ indexToTriangleID.resize(nTriangles);
+ int maxTriangleID=std::numeric_limits::min(), minTriangleID=std::numeric_limits::max(), maxGlobalTriangleID, minGlobalTriangleID;
+ for (int index(0); index < nTriangles; index++) {
indexToTriangleID[index] = fVertexToTriangleID[triangleToFVertex[index]];
+ maxTriangleID = (indexToTriangleID[index] > maxTriangleID) ? indexToTriangleID[index] : maxTriangleID;
+ minTriangleID = (indexToTriangleID[index] < minTriangleID) ? indexToTriangleID[index] : minTriangleID;
+ }
- //Compute triangle edges
- std::vector fEdgeToEdge(nEdges_F), edgesToSend, trianglesProcIds(
- nVertices_F);
- getProcIds(trianglesProcIds, recvVerticesList_F);
+ MPI_Allreduce(&maxTriangleID, &maxGlobalTriangleID, 1, MPI_INT, MPI_MAX, comm);
+ MPI_Allreduce(&minTriangleID, &minGlobalTriangleID, 1, MPI_INT, MPI_MIN, comm);
+ globalTriangleStride = maxGlobalTriangleID - minGlobalTriangleID +1;
- int interfaceSize(0);
+ // Second, we compute the FE edges belonging to the FE triangles owned by this processor.
+ // We first compute boundary edges, and then all the other edges.
+ std::vector fEdgeToEdge(nEdges_F);
std::vector fEdgeToEdgeID(nEdges_F, NotAnId);
- edgesToReceive.clear();
edgeToFEdge.clear();
isBoundaryEdge.clear();
trianglesOnEdge.clear();
- edgesToReceive.reserve(nEdges_F - nEdgesSolve_F);
edgeToFEdge.reserve(nEdges_F);
trianglesOnEdge.reserve(nEdges_F * 2);
- edgesToSend.reserve(nEdgesSolve_F);
isBoundaryEdge.reserve(nEdges_F);
- //first, we compute boundary edges (boundary edges must be the first edges)
+ //we compute boundary edges (boundary edges must be the first edges)
for (int i = 0; i < nEdges_F; i++) {
ID fVertex1(verticesOnEdge_F[2 * i] - 1), fVertex2(
verticesOnEdge_F[2 * i + 1] - 1);
+
+ // skip the (shared) edge when the associated MPAS vertices are not valid
+ if((fVertex1>=nVertices_F) || (fVertex2>=nVertices_F))
+ continue;
+
ID triaId_1 = fVertexToTriangleID[fVertex1];
ID triaId_2 = fVertexToTriangleID[fVertex2];
bool isboundary = (triaId_1 == NotAnId) || (triaId_2 == NotAnId);
ID iTria1 = fVertexToTriangle[fVertex1];
ID iTria2 = fVertexToTriangle[fVertex2];
- if (iTria1 == NotAnId)
+ if (trianglesProcIds[fVertex1] != me) {
+ std::swap(fVertex1, fVertex2);
std::swap(iTria1, iTria2);
- bool belongsToLocalTriangle = (iTria1 != NotAnId) || (iTria2 != NotAnId);
+ }
+ bool belongsToLocalTriangle = (trianglesProcIds[fVertex1] == me);
if (belongsToLocalTriangle) {
if (isboundary) {
@@ -638,36 +521,36 @@ void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cel
trianglesOnEdge.push_back(iTria1);
trianglesOnEdge.push_back(iTria2);
isBoundaryEdge.push_back(true);
- } else
- interfaceSize += (iTria2 == NotAnId);
+ }
}
}
numBoundaryEdges = edgeToFEdge.size();
- //procOnInterfaceEdge contains the pairs .
- std::vector < std::pair > procOnInterfaceEdge;
- procOnInterfaceEdge.reserve(interfaceSize);
-
//then, we compute the other edges
for (int i = 0; i < nEdges_F; i++) {
ID fVertex1(verticesOnEdge_F[2 * i] - 1), fVertex2(
verticesOnEdge_F[2 * i + 1] - 1);
+
+ // skip the (shared) edge when the associated MPAS vertices are not valid
+ if((fVertex1>=nVertices_F) || (fVertex2>=nVertices_F))
+ continue;
+
ID iTria1 = fVertexToTriangle[fVertex1];
ID iTria2 = fVertexToTriangle[fVertex2];
ID triaId_1 = fVertexToTriangleID[fVertex1]; //global Triangle
ID triaId_2 = fVertexToTriangleID[fVertex2]; //global Triangle
- if (iTria1 == NotAnId) {
- std::swap(iTria1, iTria2);
+ if (trianglesProcIds[fVertex1] != me) {
std::swap(fVertex1, fVertex2);
+ std::swap(iTria1, iTria2);
}
bool belongsToAnyTriangle = (triaId_1 != NotAnId) || (triaId_2 != NotAnId);
bool isboundary = (triaId_1 == NotAnId) || (triaId_2 == NotAnId);
- bool belongsToLocalTriangle = (iTria1 != NotAnId);
+ bool belongsToLocalTriangle = (trianglesProcIds[fVertex1] == me);
bool isMine = i < nEdgesSolve_F;
if (belongsToLocalTriangle && !isboundary) {
@@ -676,42 +559,42 @@ void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cel
trianglesOnEdge.push_back(iTria1);
trianglesOnEdge.push_back(iTria2);
isBoundaryEdge.push_back(false);
- if (iTria2 == NotAnId)
- procOnInterfaceEdge.push_back(
- std::make_pair(fEdgeToEdge[i], trianglesProcIds[fVertex2]));
- }
-
- if (belongsToAnyTriangle && isMine) {
- edgesToSend.push_back(i);
- if (!belongsToLocalTriangle)
- edgesToReceive.push_back(i);
}
-
}
- //Compute the global number of edges, and the localOffset on the local processor, such that a globalID = localOffset + index
- computeLocalOffset(edgesToSend.size(), localOffset, nGlobalEdges);
-
- //Communicate the globalIDs, computed locally, to the other processors.
- for (ID index = 0; index < edgesToSend.size(); index++)
- fEdgeToEdgeID[edgesToSend[index]] = index + localOffset;
-
- allToAll(fEdgeToEdgeID, sendEdgesList_F, recvEdgesList_F);
+ for (int fEdge = 0; fEdge < nEdges_F; fEdge++)
+ fEdgeToEdgeID[fEdge] = indexToEdgeID_F[fEdge];
nEdges = edgeToFEdge.size();
indexToEdgeID.resize(nEdges);
- floatingEdgesIds.clear();
- floatingEdgesIds.reserve(nEdges);
+ iceMarginEdgesLIds.clear();
+ iceMarginEdgesLIds.reserve(numBoundaryEdges);
+ int maxEdgeID=std::numeric_limits::min(), minEdgeID=std::numeric_limits::max(), maxGlobalEdgeID, minGlobalEdgeID;
for (int index = 0; index < nEdges; index++) {
int fEdge = edgeToFEdge[index];
indexToEdgeID[index] = fEdgeToEdgeID[fEdge];
- if((floatingEdgesMask_F[fEdge]!=0)&&(index maxEdgeID) ? indexToEdgeID[index] : maxEdgeID;
+ minEdgeID = (indexToEdgeID[index] < minEdgeID) ? indexToEdgeID[index] : minEdgeID;
+
+ if(index fCellsToSend;
- fCellsToSend.reserve(nCellsSolve_F);
+ MPI_Allreduce(&maxEdgeID, &maxGlobalEdgeID, 1, MPI_INT, MPI_MAX, comm);
+ MPI_Allreduce(&minEdgeID, &minGlobalEdgeID, 1, MPI_INT, MPI_MIN, comm);
+ globalEdgeStride = maxGlobalEdgeID - minGlobalEdgeID + 1;
+
+ // Third, we compute the FE vertices belonging to the FE triangles owned by this processor.
+ // We need to make sure that an FE vertex is owned by a proc that owns a FE triangle that contain that vertex
+ // Otherwise we might end up with weird situation where a vertex could belong to a process with no associated triangle.
vertexToFCell.clear();
vertexToFCell.reserve(nCells_F);
@@ -719,70 +602,97 @@ void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cel
fCellToVertex.assign(nCells_F, NotAnId);
std::vector fCellToVertexID(nCells_F, NotAnId);
- fCellsToReceive.clear();
+ vertexProcIDs.clear();
+
+ std::vector verticesProcIds(nCells_F, NotAnId);
- // if(! isDomainEmpty)
- // {
- fCellsToReceive.reserve(nCells_F - nCellsSolve_F);
+ vertexProcIDs.reserve(nCells_F);
for (int i = 0; i < nCells_F; i++) {
bool isMine = i < nCellsSolve_F;
bool belongsToLocalTriangle = false;
bool belongsToAnyTriangle = false;
int nEdg = nEdgesOnCells_F[i];
+ bool invalidVertex = false;
+ int minTriangleProcId = std::numeric_limits::max();
+ bool nodeOwnedByATriaProc = false;
for (int j = 0; j < nEdg; j++) {
ID fVertex(verticesOnCell_F[maxNEdgesOnCell_F * i + j] - 1);
- ID iTria = fVertexToTriangle[fVertex];
+ if(fVertex >= nVertices_F) {
+ invalidVertex = true;
+ break;
+ }
+
ID triaId = fVertexToTriangleID[fVertex];
- belongsToLocalTriangle = belongsToLocalTriangle || (iTria != NotAnId);
+ belongsToLocalTriangle = belongsToLocalTriangle || (trianglesProcIds[fVertex] == me);
belongsToAnyTriangle = belongsToAnyTriangle || (triaId != NotAnId);
- }
- if (belongsToAnyTriangle && isMine) {
- fCellsToSend.push_back(i);
- if (!belongsToLocalTriangle)
- fCellsToReceive.push_back(i);
+ if(triaId != NotAnId) {
+ nodeOwnedByATriaProc = nodeOwnedByATriaProc || (trianglesProcIds[fVertex] == fCellsProcIds[i]);
+ minTriangleProcId = (trianglesProcIds[fVertex] < minTriangleProcId) ? trianglesProcIds[fVertex] : minTriangleProcId;
+ }
}
+ if(invalidVertex) continue;
+
+ if(belongsToAnyTriangle)
+ verticesProcIds[i] = nodeOwnedByATriaProc ? fCellsProcIds[i] : minTriangleProcId;
+
if (belongsToLocalTriangle) {
fCellToVertex[i] = vertexToFCell.size();
vertexToFCell.push_back(i);
+ vertexProcIDs.push_back(reduced_ranks[verticesProcIds[i]]);
}
}
- // }
-
- //Compute the global number of vertices, and the localOffset on the local processor, such that a globalID = localOffset + index
- computeLocalOffset(fCellsToSend.size(), localOffset, nGlobalVertices);
-
- //Communicate the globalIDs, computed locally, to the other processors.
- for (int index = 0; index < int(fCellsToSend.size()); index++)
- fCellToVertexID[fCellsToSend[index]] = index + localOffset;
+ nVertices = vertexToFCell.size();
- allToAll(fCellToVertexID, sendCellsList_F, recvCellsList_F);
+ for (int fcell = 0; fcell < nCells_F; fcell++)
+ fCellToVertexID[fcell] = indexToCellID_F[fcell];
- nVertices = vertexToFCell.size();
- int vertexColumnShift = (Ordering == 1) ? 1 : nGlobalVertices;
- int vertexLayerShift = (Ordering == 0) ? 1 : nLayers + 1;
+ int maxVertexID=std::numeric_limits::min(), minVertexID=std::numeric_limits::max(), maxGlobalVertexID, minGlobalVertexID;
+ indexToVertexID.resize(nVertices);
+ for (int index = 0; index < nVertices; index++) {
+ int fCell = vertexToFCell[index];
+ indexToVertexID[index] = fCellToVertexID[fCell];
+ maxVertexID = (indexToVertexID[index] > maxVertexID) ? indexToVertexID[index] : maxVertexID;
+ minVertexID = (indexToVertexID[index] < minVertexID) ? indexToVertexID[index] : minVertexID;
+ }
+ MPI_Allreduce(&maxVertexID, &maxGlobalVertexID, 1, MPI_INT, MPI_MAX, comm);
+ MPI_Allreduce(&minVertexID, &minGlobalVertexID, 1, MPI_INT, MPI_MIN, comm);
+ globalVertexStride = maxGlobalVertexID - minGlobalVertexID + 1;
- std::cout << "\n nvertices: " << nVertices << " " << nGlobalVertices << "\n"
- << std::endl;
- indexToVertexID.resize(nVertices);
+ int vertexColumnShift = (Ordering == 1) ? 1 : globalVertexStride;
+ int vertexLayerShift = (Ordering == 0) ? 1 : nLayers + 1;
dirichletNodesIDs.clear();
dirichletNodesIDs.reserve(nVertices); //need to improve storage efficiency
+ isVertexBoundary.assign(nVertices, false);
for (int index = 0; index < nVertices; index++) {
int fCell = vertexToFCell[index];
- indexToVertexID[index] = fCellToVertexID[fCell];
for(int il=0; il< nLayers+1; ++il)
{
int imask_F = il+(nLayers+1)*fCell;
if(dirichletCellsMask_F[imask_F]!=0)
dirichletNodesIDs.push_back((nLayers-il)*vertexColumnShift+indexToVertexID[index]*vertexLayerShift);
}
+
+ int nEdg = nEdgesOnCells_F[fCell];
+ int j = 0;
+ bool isBoundary;
+ do {
+ int fVertex = verticesOnCell_F[maxNEdgesOnCell_F * fCell + j++] - 1;
+ isBoundary = !(verticesMask_F[fVertex] & dynamic_ice_bit_value);
+ } while ((j < nEdg) && (!isBoundary));
+ isVertexBoundary[index] = isBoundary;
}
- createReverseCellsExchangeLists(sendCellsListReversed, recvCellsListReversed,
- fVertexToTriangleID, fCellToVertexID);
+ // because we change the ownership of some vertices, we need to first communicate back to the processors that used to own those vertices
+ // the data of the newly owned vertices. We do this by defining "reversed" send and receive lists, communicate back using that list, and
+ // then communicate forward with the usual send and receive lists.
+ // We could join these two step in one communication, but for the moment we do that separately.
+ // We need to communicate info about the vertices when we get the ice velocity on vertices form the velocity solver/
+
+ createReverseExchangeLists(sendCellsListReversed, recvCellsListReversed, verticesProcIds, indexToCellID_F, recvCellsList_F);
//construct the local vector vertices on triangles making sure the area is positive
verticesOnTria.resize(nTriangles * 3);
@@ -801,132 +711,24 @@ void velocity_solver_compute_2d_grid(int const* _verticesMask_F, int const* _cel
std::swap(verticesOnTria[3 * index + 1], verticesOnTria[3 * index + 2]);
}
- //construct the local vector vertices on edges
- trianglesPositionsOnEdge.resize(2 * nEdges);
- isVertexBoundary.assign(nVertices, false);
-
verticesOnEdge.resize(2 * nEdges);
-
- //contains the local id of a triangle and the global id of the edges of the triangle.
- //dataForGhostTria[4*i] contains the triangle id
- //dataForGhostTria[4*i+1+k] contains the global id of the edge (at position k = 0,1,2) of the triangle.
- //Possible Optimization: for our purposes it would be enough to store two of the three edges of a triangle.
- std::vector dataForGhostTria(nVertices_F * 4, NotAnId);
-
- //*
- for (int iV = 0; iV < nVertices; iV++) {
- int fCell = vertexToFCell[iV];
- int nEdg = nEdgesOnCells_F[fCell];
- int j = 0;
- bool isBoundary;
- do {
- int fVertex = verticesOnCell_F[maxNEdgesOnCell_F * fCell + j++] - 1;
- isBoundary = !(verticesMask_F[fVertex] & dynamic_ice_bit_value);
- } while ((j < nEdg) && (!isBoundary));
- isVertexBoundary[iV] = isBoundary;
- }
- /*/
- for(int index=0; index verticesCoords(3 * nVertices);
-
- for (int index = 0; index < nVertices; index++) {
- int iCell = vertexToFCell[index];
- verticesCoords[index * 3] = xCell_F[iCell] / unit_length;
- verticesCoords[index * 3 + 1] = yCell_F[iCell] / unit_length;
- verticesCoords[index * 3 + 2] = zCell_F[iCell] / unit_length;
- }
-
- velocity_solver_compute_2d_grid__(nGlobalTriangles,
- nGlobalVertices, nGlobalEdges, indexToVertexID, verticesCoords,
- isVertexBoundary, verticesOnTria,isBoundaryEdge, trianglesOnEdge,
- trianglesPositionsOnEdge, verticesOnEdge, indexToEdgeID,
- indexToTriangleID, procOnInterfaceEdge );
-#else
- velocity_solver_compute_2d_grid__(reducedComm);
-#endif
-
- /*
-
- //initialize the mesh
- iceProblemPtr->mesh2DPtr.reset (new RegionMesh() );
-
- //construct the mesh nodes
- constructNodes ( * (iceProblemPtr->mesh2DPtr), indexToVertexID, verticesCoords, isVertexBoundary, nGlobalVertices, 3);
-
- //construct the mesh elements
- constructElements ( * (iceProblemPtr->mesh2DPtr), indexToTriangleID, verticesOnTria, nGlobalTriangles);
-
- //construct the mesh facets
- constructFacets ( * (iceProblemPtr->mesh2DPtr), isBoundaryEdge, trianglesOnEdge, trianglesPositionsOnEdge, verticesOnEdge, indexToEdgeID, procOnInterfaceEdge, nGlobalEdges, 3);
-
- Switch sw;
- std::vector elSign;
- checkVolumes ( * (iceProblemPtr->mesh2DPtr), elSign, sw );
- */
+ velocity_solver_compute_2d_grid__(reducedComm);
}
-void velocity_solver_extrude_3d_grid(double const* levelsRatio_F,
- double const* lowerSurface_F, double const* thickness_F) {
+void velocity_solver_extrude_3d_grid(double const* levelsRatio_F) {
if (isDomainEmpty)
return;
@@ -935,7 +737,6 @@ void velocity_solver_extrude_3d_grid(double const* levelsRatio_F,
// !!Indexing of layers is reversed
for (int i = 0; i < nLayers; i++)
layersRatio[i] = levelsRatio_F[nLayers - 1 - i];
- //std::copy(levelsRatio_F, levelsRatio_F+nLayers, layersRatio.begin());
levelsNormalizedThickness.resize(nLayers + 1);
@@ -944,10 +745,6 @@ void velocity_solver_extrude_3d_grid(double const* levelsRatio_F,
levelsNormalizedThickness[i + 1] = levelsNormalizedThickness[i]
+ layersRatio[i];
- std::vector mpasIndexToVertexID(nVertices);
- for (int i = 0; i < nVertices; i++)
- mpasIndexToVertexID[i] = indexToCellID_F[vertexToFCell[i]];
-
//construct the local vector of coordinates
std::vector verticesCoords(3 * nVertices);
@@ -958,13 +755,22 @@ void velocity_solver_extrude_3d_grid(double const* levelsRatio_F,
verticesCoords[index * 3 + 2] = zCell_F[iCell] / unit_length;
}
- velocity_solver_extrude_3d_grid__(nLayers, nGlobalTriangles, nGlobalVertices,
- nGlobalEdges, Ordering, reducedComm, indexToVertexID, mpasIndexToVertexID,
- verticesCoords, isVertexBoundary, verticesOnTria, isBoundaryEdge,
- trianglesOnEdge, trianglesPositionsOnEdge, verticesOnEdge, indexToEdgeID,
- indexToTriangleID, dirichletNodesIDs, floatingEdgesIds);
+ std::vector> procsSharingVertices(nVertices);
+ for(int i=0; i< nVertices; i++)
+ procsSharingVertex(i, procsSharingVertices[i]);
+
+
+ std::vector iceMarginEdgesGIds(iceMarginEdgesLIds.size());
+ for (int i=0; i< iceMarginEdgesGIds.size(); ++i) {
+ iceMarginEdgesGIds[i] = indexToEdgeID[iceMarginEdgesLIds[i]];
}
+ velocity_solver_extrude_3d_grid__(nLayers, globalTriangleStride, globalVertexStride,
+ globalEdgeStride, Ordering, reducedComm, indexToVertexID, vertexProcIDs,
+ verticesCoords, verticesOnTria, procsSharingVertices, isBoundaryEdge,
+ trianglesOnEdge, verticesOnEdge, indexToEdgeID,
+ indexToTriangleID, dirichletNodesIDs, iceMarginEdgesGIds);
+ }
// Function to set up how the MPAS log file will be used by Albany
void interface_init_log(){
@@ -1003,11 +809,7 @@ void interface_init_log(){
}
strcat(oformat, ".out");
- if (me == 0) {
- sprintf(albany_log_filename, oformat, me);
- } else {
- strcpy(albany_log_filename, "/dev/null");
- }
+ sprintf(albany_log_filename, oformat, me);
Interface_stdout = open(albany_log_filename, O_CREAT|O_WRONLY|O_TRUNC,0644);
if(Interface_stdout >= 0) {
@@ -1069,14 +871,9 @@ void get_prism_velocity_on_FEdges(double * uNormal,
UInt nPoints3D = nCells_F * (nLayers + 1);
- // Loop over all edges of the triangulation - MPAS will decide which edges it should use.
- for (int i = 0; i < nEdges; i++) {
-
- //identifying vertices on the edge
- ID lId0 = verticesOnEdge[2 * i];
- ID lId1 = verticesOnEdge[2 * i + 1];
- int iCell0 = vertexToFCell[lId0];
- int iCell1 = vertexToFCell[lId1];
+ for (int iEdge = 0; iEdge < nEdgesSolve_F; iEdge++) {
+ int iCell0 = cellsOnEdge_F[2 * iEdge] - 1;
+ int iCell1 = cellsOnEdge_F[2 * iEdge + 1] - 1;
//computing normal to the cell edge (dual of triangular edge)
double nx = xCell_F[iCell1] - xCell_F[iCell0];
@@ -1086,9 +883,14 @@ void get_prism_velocity_on_FEdges(double * uNormal,
ny /= n;
//identifying triangles that shares the edge
- ID iEdge = edgeToFEdge[i];
ID fVertex0 = verticesOnEdge_F[2 * iEdge] - 1;
ID fVertex1 = verticesOnEdge_F[2 * iEdge + 1] - 1;
+
+
+ int iTria0 = fVertexToTriangleID[fVertex0];
+ int iTria1 = fVertexToTriangleID[fVertex1];
+ if((iTria0 == NotAnId) && (iTria1 == NotAnId)) continue;
+
double t0[2*3], t1[2*3]; //t0[0] contains the x-coords of vertices of triangle 0 and t0[1] its y-coords.
for (int j = 0; j < 3; j++) {
int iCell = cellsOnVertex_F[3 * fVertex0 + j] - 1;
@@ -1119,11 +921,11 @@ void get_prism_velocity_on_FEdges(double * uNormal,
for (int j = 0; j < 3; j++)
iCells[j] = cellsOnVertex_F[3 * fVertex1 + j] - 1;
}
- else if(i& velocityOnVertices,
}
}
-void createReverseCellsExchangeLists(exchangeList_Type& sendListReverse_F,
- exchangeList_Type& receiveListReverse_F,
- const std::vector& fVertexToTriangleID,
- const std::vector& fCellToVertexID) {
- sendListReverse_F.clear();
- receiveListReverse_F.clear();
- //std::map > sendMap;
- std::map > sendMap, receiveMap;
- std::vector cellsProcId(nCells_F), trianglesProcIds(nVertices_F);
- getProcIds(cellsProcId, recvCellsList_F);
- getProcIds(trianglesProcIds, recvVerticesList_F);
-
- //std::cout << "SendList " ;
- for (int i = 0; i < nVertices; i++) {
- int iCell = vertexToFCell[i];
- if (iCell < nCellsSolve_F)
- continue;
- bool belongToTriaOnSameProc = false;
- int j(0);
- int nEdg = nEdgesOnCells_F[iCell];
- do {
- ID fVertex(verticesOnCell_F[maxNEdgesOnCell_F * iCell + j] - 1);
- ID triaId = fVertexToTriangleID[fVertex];
- belongToTriaOnSameProc = (triaId != NotAnId)
- && (trianglesProcIds[fVertex] == cellsProcId[iCell]);
- } while ((belongToTriaOnSameProc == false) && (++j < nEdg));
- if (!belongToTriaOnSameProc) {
- sendMap[cellsProcId[iCell]].insert(
- std::make_pair(fCellToVertexID[iCell], iCell));
- // std::cout<< "(" << cellsProcId[iCell] << "," << iCell << ") ";
- }
-
- }
- //std::cout < >::const_iterator it = sendMap.begin();
- it != sendMap.end(); it++) {
- std::vector sendVec(it->second.size());
- int i = 0;
- for (std::map::const_iterator iter = it->second.begin();
- iter != it->second.end(); iter++)
- sendVec[i++] = iter->second;
- sendListReverse_F.push_back(
- exchange(it->first, &sendVec[0], &sendVec[0] + sendVec.size()));
- }
-
- //std::cout << "ReceiveList " ;
- for (UInt i = 0; i < fCellsToReceive.size(); i++) {
- int iCell = fCellsToReceive[i];
- int nEdg = nEdgesOnCells_F[iCell];
- for (int j = 0; j < nEdg; j++) {
- ID fVertex(verticesOnCell_F[maxNEdgesOnCell_F * iCell + j] - 1);
- ID triaId = fVertexToTriangleID[fVertex];
- if (triaId != NotAnId) {
- receiveMap[trianglesProcIds[fVertex]].insert(
- std::make_pair(fCellToVertexID[iCell], iCell));
- // std::cout<< "(" << trianglesProcIds[fVertex] << "," << iCell << ") ";
- }
- }
- }
- //std::cout < >::const_iterator it =
- receiveMap.begin(); it != receiveMap.end(); it++) {
- std::vector receiveVec(it->second.size());
- int i = 0;
- for (std::map::const_iterator iter = it->second.begin();
- iter != it->second.end(); iter++)
- receiveVec[i++] = iter->second;
- receiveListReverse_F.push_back(
- exchange(it->first, &receiveVec[0],
- &receiveVec[0] + receiveVec.size()));
- }
-}
-
-void createReverseEdgesExchangeLists(exchangeList_Type& sendListReverse_F,
+void createReverseExchangeLists(exchangeList_Type& sendListReverse_F,
exchangeList_Type& receiveListReverse_F,
- const std::vector& fVertexToTriangleID,
- const std::vector& fEdgeToEdgeID) {
+ const std::vector& newProcIds, const int* indexToID_F, exchangeList_Type const * recvList_F) {
sendListReverse_F.clear();
receiveListReverse_F.clear();
- //std::map > sendMap;
std::map > sendMap, receiveMap;
- std::vector edgesProcId(nEdges_F), trianglesProcIds(nVertices_F);
- getProcIds(edgesProcId, recvEdgesList_F);
- getProcIds(trianglesProcIds, recvVerticesList_F);
-
- //std::cout << "EdgesSendList " ;
- for (int i = 0; i < nEdges; i++) {
- int iEdge = edgeToFEdge[i];
- if (iEdge < nEdgesSolve_F)
- continue;
- bool belongToTriaOnSameProc = false;
- int j(0);
- do {
- ID fVertex(verticesOnEdge_F[2 * iEdge + j] - 1);
- ID triaId = fVertexToTriangleID[fVertex];
- belongToTriaOnSameProc = (triaId != NotAnId)
- && (trianglesProcIds[fVertex] == edgesProcId[iEdge]);
- } while ((belongToTriaOnSameProc == false) && (++j < 2));
- if (!belongToTriaOnSameProc) {
- sendMap[edgesProcId[iEdge]].insert(
- std::make_pair(fEdgeToEdgeID[iEdge], iEdge));
- //std::cout<< "(" << edgesProcId[iEdge] << "," << iEdge << ") ";
+ int nFEntities = newProcIds.size();
+ std::vector procIds(nFEntities);
+ getProcIds(procIds, recvList_F);
+ int me;
+ MPI_Comm_rank(comm, &me);
+ for (int fEntity = 0; fEntity < nFEntities; fEntity++) {
+ if ((procIds[fEntity] != me) && (newProcIds[fEntity] == me)) {
+ sendMap[procIds[fEntity]].insert(
+ std::make_pair(indexToID_F[fEntity], fEntity));
}
}
- //std::cout < >::const_iterator it = sendMap.begin();
it != sendMap.end(); it++) {
@@ -1328,20 +1040,12 @@ void createReverseEdgesExchangeLists(exchangeList_Type& sendListReverse_F,
exchange(it->first, &sendVec[0], &sendVec[0] + sendVec.size()));
}
- //std::cout << "EdgesReceiveList " ;
- for (UInt i = 0; i < edgesToReceive.size(); i++) {
- int iEdge = edgesToReceive[i];
- for (int j = 0; j < 2; j++) {
- ID fVertex(verticesOnEdge_F[2 * iEdge + j] - 1);
- ID triaId = fVertexToTriangleID[fVertex];
- if (triaId != NotAnId) {
- receiveMap[trianglesProcIds[fVertex]].insert(
- std::make_pair(fEdgeToEdgeID[iEdge], iEdge));
- // std::cout<< "(" << trianglesProcIds[fVertex] << "," << iEdge << ") ";
- }
+ for (int fEntity = 0; fEntity < nFEntities; fEntity++) {
+ if((procIds[fEntity] == me) && (newProcIds[fEntity] != NotAnId) && (newProcIds[fEntity] != me)) {
+ receiveMap[newProcIds[fEntity]].insert(
+ std::make_pair(indexToID_F[fEntity], fEntity));
}
}
- // std::cout < >::const_iterator it =
receiveMap.begin(); it != receiveMap.end(); it++) {
@@ -1380,19 +1084,6 @@ void mapCellsToVertices(const std::vector& velocityOnCells,
}
}
-bool isGhostTriangle(int i, double relTol) {
- double x[3], y[3], area;
-
- for (int j = 0; j < 3; j++) {
- int iCell = cellsOnVertex_F[3 * i + j] - 1;
- x[j] = xCell_F[iCell];
- y[j] = yCell_F[iCell];
- }
-
- area = std::fabs(signedTriangleArea(x, y));
- return false; //(std::fabs(areaTriangle_F[i]-area)/areaTriangle_F[i] > relTol);
-}
-
double signedTriangleArea(const double* x, const double* y) {
double u[2] = { x[1] - x[0], y[1] - y[0] };
double v[2] = { x[2] - x[0], y[2] - y[0] };
@@ -1416,36 +1107,25 @@ double signedTriangleAreaOnSphere(const double* x, const double* y,
> 0) ? area : -area;
}
-//TO BE FIXED, Access To verticesOnCell_F is not correct
-void extendMaskByOneLayer(int const* verticesMask_F,
- std::vector& extendedFVerticesMask) {
- extendedFVerticesMask.resize(nVertices_F);
- extendedFVerticesMask.assign(&verticesMask_F[0],
- &verticesMask_F[0] + nVertices_F);
- for (int i = 0; i < nCells_F; i++) {
- bool belongsToMarkedTriangle = false;
- int nEdg = nEdgesOnCells_F[i];
- for (UInt k = 0; k < nEdg && !belongsToMarkedTriangle; k++)
- belongsToMarkedTriangle = belongsToMarkedTriangle
- || verticesMask_F[verticesOnCell_F[maxNEdgesOnCell_F * i + k] - 1];
- if (belongsToMarkedTriangle)
- for (UInt k = 0; k < nEdg; k++) {
- ID fVertex(verticesOnCell_F[maxNEdgesOnCell_F * i + k] - 1);
- extendedFVerticesMask[fVertex] = !isGhostTriangle(fVertex);
- }
- }
-}
-void import2DFields(std::map bdExtensionMap, double const* bedTopography_F, double const * lowerSurface_F, double const * thickness_F,
- double const * beta_F, double const * temperature_F, double const * smb_F, double eps) {
-
+void importFields(std::vector >& marineBdyExtensionMap, double const* bedTopography_F, double const * lowerSurface_F, double const * thickness_F,
+ double const * beta_F, double const* stiffnessFactor_F, double const* effecPress_F, double const* muFriction_F,
+ double const * temperature_F, double const * smb_F, double eps) {
+
+ int vertexLayerShift = (Ordering == 0) ? 1 : nLayers + 1;
elevationData.assign(nVertices, 1e10);
thicknessData.assign(nVertices, 1e10);
bedTopographyData.assign(nVertices, 1e10);
if (beta_F != 0)
betaData.assign(nVertices, 1e10);
+ if (stiffnessFactor_F != 0)
+ stiffnessFactorData.assign(nVertices, 1.0);
+ if (effecPress_F != 0)
+ effecPressData.assign(nVertices, 1e10);
+ if (muFriction_F!= 0)
+ muFrictionData.assign(nVertices, 1e10);
if(temperature_F != 0)
- temperatureData.assign(nLayers * nTriangles, 1e10);
+ temperatureDataOnPrisms.assign(nLayers * nTriangles, 1e10);
if (smb_F != 0)
smbData.assign(nVertices, 1e10);
@@ -1459,9 +1139,17 @@ void import2DFields(std::map bdExtensionMap, double const* bedTopograp
if (beta_F != 0)
betaData[index] = beta_F[iCell] / unit_length;
if (smb_F != 0)
- smbData[index] = smb_F[iCell] / unit_length * secondsInAYear/rho_ice;
+ smbData[index] = smb_F[iCell] * secondsInAYear/rho_ice;
+ if (stiffnessFactor_F != 0)
+ stiffnessFactorData[index] = stiffnessFactor_F[iCell];
+ if (effecPress_F != 0)
+ effecPressData[index] = effecPress_F[iCell] / unit_length;
+ if (muFriction_F != 0)
+ muFrictionData[index] = muFriction_F[iCell];
}
+ int lElemColumnShift = (Ordering == 1) ? 1 : nTriangles;
+ int elemLayerShift = (Ordering == 0) ? 1 : nLayers;
if(temperature_F != 0) {
for (int index = 0; index < nTriangles; index++) {
for (int il = 0; il < nLayers; il++) {
@@ -1471,112 +1159,115 @@ void import2DFields(std::map bdExtensionMap, double const* bedTopograp
for (int iVertex = 0; iVertex < 3; iVertex++) {
int v = verticesOnTria[iVertex + 3 * index];
int iCell = vertexToFCell[v];
- //compute temperature by averaging tmeperature values of triangles vertices where ice is present
- if (cellsMask_F[iCell] & ice_present_bit_value) {
+ //compute temperature by averaging temperature values of triangles vertices where ice is present
+ // Note that thermal_thickness_limit was imported in Albany units (km) but thickness_F is still in
+ // MPAS units (m), so thermal_thickness_limit is being scaled back to MPAS units for this comparison.
+ if (thickness_F[iCell] > thermal_thickness_limit * unit_length) {
temperature += temperature_F[iCell * nLayers + ilReversed];
nPoints++;
}
}
if (nPoints == 0) //if triangle is in an ice-free area, set the temperature to T0
- temperatureData[index+il*nTriangles] = T0;
+ temperatureDataOnPrisms[index*elemLayerShift + il*lElemColumnShift] = T0;
else
- temperatureData[index+il*nTriangles] = temperature / nPoints;
+ temperatureDataOnPrisms[index*elemLayerShift + il*lElemColumnShift] = temperature / nPoints;
}
}
}
-
- //extend thickness elevation and basal friction data to the border for floating vertices
- std::set::const_iterator iter;
+ //extend thickness and elevation data to the border for marine vertices
+ marineBdyExtensionMap.clear();
+ marineBdyExtensionMap.reserve(nVertices);
for (int iV = 0; iV < nVertices; iV++) {
int fCell = vertexToFCell[iV];
- if (isVertexBoundary[iV] && !(cellsMask_F[fCell] & dynamic_ice_bit_value)) {
- int c;
- int nEdg = nEdgesOnCells_F[fCell];
- bool isFloating = false;
- for (int j = 0; (j < nEdg)&&(!isFloating); j++) {
- int fEdge = edgesOnCell_F[maxNEdgesOnCell_F * fCell + j] - 1;
- isFloating = (floatingEdgesMask_F[fEdge] != 0);
- }
- if(isFloating) {
-
- // -- floating margin --
- // Identify the lowest elevation neighboring cell with ice
- // Scalar values will be mapped from that location to here.
- double elevTemp =1e10;
- bool foundNeighbor = false;
- for (int j = 0; j < nEdg; j++) {
- int fEdge = edgesOnCell_F[maxNEdgesOnCell_F * fCell + j] - 1;
- //bool keep = (mask[verticesOnEdge_F[2 * fEdge] - 1] & dynamic_ice_bit_value)
- // && (mask[verticesOnEdge_F[2 * fEdge + 1] - 1] & dynamic_ice_bit_value);
- //if (!keep)
- // continue;
-
- int c0 = cellsOnEdge_F[2 * fEdge] - 1;
- int c1 = cellsOnEdge_F[2 * fEdge + 1] - 1;
- c = (fCellToVertex[c0] == iV) ? c1 : c0;
- //if(!(cellsMask_F[c] & ice_present_bit_value)) continue;
- if((cellsMask_F[c] & dynamic_ice_bit_value)) {
- double elev = thickness_F[c] + lowerSurface_F[c]; // - 1e-8*std::sqrt(pow(xCell_F[c0],2)+std::pow(yCell_F[c0],2));
- std::cout << " elev="< v2;
-
- for (int iTetra = 0; iTetra < 3; iTetra++)
- for (int iVertex = 0; iVertex < 4; iVertex++)
- {
- tetrasIdsOnPrism[iTetra][iVertex] = prismVertexGIds[tetraOfPrism[prismType][iTetra][iVertex]];
- }
-
- // return;
-
- int reorderedPrismLIds[6];
-
- for (int ii = 0; ii < 6; ii++)
- {
- reorderedPrismLIds[ii] = prismVertexGIds[PrismVerticesMap[minIndex][ii]];
- }
-
- for (int iTetra = 0; iTetra < 3; iTetra++)
- for (int iVertex = 0; iVertex < 4; iVertex++)
- {
- tetrasIdsOnPrism[iTetra][iVertex] = reorderedPrismLIds[tetraOfPrism[prismType][iTetra][iVertex]];
- }
- }
-
-
-
-
- void setBdFacesOnPrism (const std::vector > >& prismStruct, const std::vector& prismFaceIds, std::vector& tetraPos, std::vector& facePos)
- {
- int numTriaFaces = prismFaceIds.size() - 2;
- tetraPos.assign(numTriaFaces,-1);
- facePos.assign(numTriaFaces,-1);
-
-
- for (int iTetra (0), k (0); (iTetra < 3 && k < numTriaFaces); iTetra++)
- {
- bool found;
- for (int jFaceLocalId = 0; jFaceLocalId < 4; jFaceLocalId++ )
- {
- found = true;
- for (int ip (0); ip < 3 && found; ip++)
- {
- int localId = prismStruct[iTetra][jFaceLocalId][ip];
- int j = 0;
- found = false;
- while ( (j < prismFaceIds.size()) && !found )
- {
- found = (localId == prismFaceIds[j]);
- j++;
- }
- }
- if (found)
- {
- tetraPos[k] = iTetra;
- facePos[k] = jFaceLocalId;
- k += found;
- break;
- }
- }
- }
- }
-
void procsSharingVertex(const int vertex, std::vector& procIds) {
int fCell = vertexToFCell[vertex];
procIds.clear();
int nEdg = nEdgesOnCells_F[fCell];
int me;
MPI_Comm_rank(comm, &me);
- procIds.reserve(nEdg);
for(int i=0; i regulThk(thicknessData);
-// for (int index = 0; index < nVertices; index++)
-// regulThk[index] = std::max(1e-4, thicknessData[index]); //TODO Make limit a parameter
-//
-// importP0Temperature(temperature_F);
-//
-// std::cout << "\n\nTimeStep: "<< *deltat << "\n\n"<< std::endl;
-//
-// std::vector mpasIndexToVertexID(nVertices);
-// for (int i = 0; i < nVertices; i++) {
-// mpasIndexToVertexID[i] = indexToCellID_F[vertexToFCell[i]];
-// }
-//
-// mapVerticesToCells(velocityOnVertices, &velocityOnCells[0], 2, nLayers,
-// Ordering);
-
-
// Write out ASCII format
std::cout << "Writing mesh to albany.msh." << std::endl;
// msh file
std::ofstream outfile;
- outfile.open ("albany.msh", std::ios::out | std::ios::trunc);
+ outfile.precision(15);
+ std::stringstream name;
+ int me;
+ MPI_Comm_rank(comm, &me);
+ name << "albany.msh." << me;
+ outfile.open (name.str(), std::ios::out | std::ios::trunc);
if (outfile.is_open()) {
- int nVerticesBoundaryEdge = 0;
- for (int index = 0; index < nVertices; index++) {
- if (isBoundaryEdge[index]) nVerticesBoundaryEdge += 1;
- }
- std::vector verticesOnBoundaryEdge;
- verticesOnBoundaryEdge.resize(2 * nVerticesBoundaryEdge);
- int iVerticesBoundaryEdge = 0;
- for (int index = 0; index < nVertices; index++) {
- if (isBoundaryEdge[index]) {
- verticesOnBoundaryEdge[0 + 2 * iVerticesBoundaryEdge] = verticesOnEdge[0 + 2 * index];
- verticesOnBoundaryEdge[1 + 2 * iVerticesBoundaryEdge] = verticesOnEdge[1 + 2 * index];
- iVerticesBoundaryEdge += 1;
- }
+ //creating set from vector so that we can find elements in the set in log time
+ //boundary edges labels: 2 if ice margin, 1 otherwise
+ std::vector bdEdgesLabels(numBoundaryEdges,1);
+ for (int i = 0; i < iceMarginEdgesLIds.size(); i++)
+ bdEdgesLabels[iceMarginEdgesLIds[i]] = 2;
+
+ std::vector boundaryEdges; //list of edge vertices and edge label
+ boundaryEdges.resize(3 * numBoundaryEdges);
+ for (int index = 0; index < numBoundaryEdges; index++) {
+ boundaryEdges[0 + 3 * index] = verticesOnEdge[0 + 2 * index];
+ boundaryEdges[1 + 3 * index] = verticesOnEdge[1 + 2 * index];
+ boundaryEdges[2 + 3 * index] = bdEdgesLabels[index];
}
- //std::cout<<"final count: "< sortingIndex;
+ computeSortingIndices(sortingIndex, indexToTriangleID, nTriangles);
+
+ for (int iTria = 0; iTria < nTriangles; iTria++) {//triangles lines
+ int index = sortingIndex[iTria];
+ outfile << indexToTriangleID[index] << " " << verticesOnTria[0 + 3 * index] + 1 << " " << verticesOnTria[1 + 3 * index] + 1 << " " << verticesOnTria[2 + 3 * index] + 1 << " " << 1 << "\n"; // last digit can be used to specify a 'material'. Not used by Albany LandIce, so giving dummy value
}
- for (int index = 0; index < nTriangles; index++) //triangles lines
- outfile << verticesOnTria[0 + 3 * index] + 1 << " " << verticesOnTria[1 + 3 * index] + 1 << " " << verticesOnTria[2 + 3 * index] + 1 << " " << 1 << "\n"; // last digit can be used to specify a 'material'. Not used by FELIX, so giving dummy value
+ // sort edges IDs (needed by Albany)
+ computeSortingIndices(sortingIndex, indexToEdgeID, numBoundaryEdges);
- for (int index = 0; index < nVerticesBoundaryEdge; index++) // boundary edges lines
- outfile << verticesOnBoundaryEdge[0 + 2 * index] + 1 << " " << verticesOnBoundaryEdge[1 + 2 * index] + 1 << " " << 1 << "\n"; //last digit can be used to tell whether it's floating or not.. but let's worry about this later.
+ for (int iEdge = 0; iEdge < numBoundaryEdges; iEdge++) { // boundary edges lines
+ int index = sortingIndex[iEdge];
+ outfile << indexToEdgeID[index] << " " << boundaryEdges[0 + 3 * index] + 1 << " " << boundaryEdges[1 + 3 * index] + 1 << " " << boundaryEdges[2 + 3 * index] << "\n"; //last digit can be used to tell whether it's floating or not.. but let's worry about this later.
+ }
outfile.close();
}
@@ -2178,18 +1699,31 @@ int prismType(long long int const* prismVertexMpasIds, int& minIndex)
// individual field values
// Call needed functions to process MPAS fields to Albany units/format
-
- std::map bdExtensionMap; // local map to be created by import2DFields
- import2DFields(bdExtensionMap, bedTopography_F, lowerSurface_F, thickness_F, beta_F, temperature_F, smb_F, minThickness);
- import2DFieldsObservations(bdExtensionMap,
+ std::vector > marineBdyExtensionMap; // local map to be created by importFields
+ importFields(marineBdyExtensionMap, bedTopography_F, lowerSurface_F, thickness_F, beta_F,
+ stiffnessFactor_F, effecPress_F, muFriction_F, temperature_F, smb_F, minThickness);
+
+ import2DFieldsObservations(marineBdyExtensionMap,
thicknessUncertainty_F,
smbUncertainty_F,
bmb_F, bmbUncertainty_F,
observedSurfaceVelocityX_F, observedSurfaceVelocityY_F, observedSurfaceVelocityUncertainty_F,
observedThicknessTendency_F, observedThicknessTendencyUncertainty_F,
+ surfaceAirTemperature_F, basalHeatFlux_F,
indexToCellID_F);
+ // apparent mass balance
+ std::vector appMbData(smbData.size()),
+ appMbUncertaintyData(smbData.size());
+
+ for (int i=0; i sortingIndex;
+ computeSortingIndices(sortingIndex,indexToTriangleID,nTriangles);
+
+ int lElemColumnShift = (Ordering == 1) ? 1 : nTriangles;
+ int elemLayerShift = (Ordering == 0) ? 1 : nLayers;
+ for(int il = 0; il& sortingIndices, const std::vector& vectorToSort, int numIndices) {
+ // sort triangle IDs (needed by Albany)
+ sortingIndices.resize(numIndices);
+
+ // sortingIndices = [0,1,2,..,nTriangles-1];
+ for (int i = 0; i < numIndices; i++)
+ sortingIndices[i] = i;
+
+ //compute sortingIndices that makes indexToTriangleID sorted
+ std::sort(sortingIndices.begin(), sortingIndices.end(), [&](int il, int ir) {
+ return (vectorToSort[il] < vectorToSort[ir]);
+ });
+ }
+
+
void write_ascii_mesh_field(std::vector fieldData, std::string filenamebase) {
std::string filename = filenamebase+".ascii";
std::cout << "Writing " << filename << std::endl;
std::ofstream outfile;
+ outfile.precision(15);
outfile.open (filename.c_str(), std::ios::out | std::ios::trunc);
if (outfile.is_open()) {
outfile << nVertices << "\n"; //number of vertices on first line
@@ -2287,4 +1878,4 @@ int prismType(long long int const* prismVertexMpasIds, int& minIndex)
std::cout << "Error: Failed to open "+filename << std::endl;
}
}
-
+
diff --git a/src/core_landice/mode_forward/Interface_velocity_solver.hpp b/src/core_landice/mode_forward/Interface_velocity_solver.hpp
index 574a87a285..c99cdd3cc8 100644
--- a/src/core_landice/mode_forward/Interface_velocity_solver.hpp
+++ b/src/core_landice/mode_forward/Interface_velocity_solver.hpp
@@ -10,7 +10,6 @@ distributed with this code, or at http://mpas-dev.github.com/license.html
// ===================================================
//! Includes
// ===================================================
-//#include
#include
#include
#include
@@ -45,11 +44,6 @@ distributed with this code, or at http://mpas-dev.github.com/license.html
#define write_ascii_mesh write_ascii_mesh_
#endif
-//#include
-//#include
-
-//#include
-
struct exchange {
const int procID;
const std::vector vec;
@@ -78,8 +72,9 @@ void velocity_solver_finalize();
void velocity_solver_set_parameters(double const* gravity_F, double const* ice_density_F, double const* ocean_density_F,
double const* sea_level_F, double const* flowParamA_F,
- double const* enhancementFactor_F, double const* flowLawExponent_F, double const* dynamic_thickness_F,
+ double const* flowLawExponent_F, double const* dynamic_thickness_F,
double const* clausius_clapeyron_coeff,
+ double const* thermal_thickness_limit_F,
int const* li_mask_ValueDynamicIce, int const* li_mask_ValueIce,
bool const* use_GLP_F);
@@ -94,14 +89,15 @@ void velocity_solver_solve_l1l2(double const* lowerSurface_F,
double* xVelocityOnCell = 0, double* yVelocityOnCell = 0);
void velocity_solver_solve_fo(double const* bedTopography_F, double const* lowerSurface_F,
- double const* thickness_F, double const* beta_F, double const* smb_F, double const* temperature_F,
+ double const* thickness_F, double * beta_F, double const* smb_F, double const* temperature_F, double const* stiffnessFactor_F,
+ double const* effecPress_F, double const* muFriction_F,
double* const dirichletVelocityXValue = 0, double* const dirichletVelocitYValue = 0,
- double* u_normal_F = 0, double* dissipation_heat_F = 0,
+ double* u_normal_F = 0, double* bodyForce_F = 0, double* dissipation_heat_F = 0,
double* xVelocityOnCell = 0, double* yVelocityOnCell = 0, double const * deltat = 0,
int *error = 0 );
-void velocity_solver_compute_2d_grid(int const* verticesMask_F, int const* _cellsMask_F, int const* dirichletNodesMask_F, int const* floatingEdgeMask_F);
+void velocity_solver_compute_2d_grid(int const* verticesMask_F, int const* _cellsMask_F, int const* dirichletNodesMask_F);
void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
int const* _nVertices_F, int const* _nLayers, int const* _nCellsSolve_F,
@@ -111,6 +107,8 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
int const* _verticesOnCell_F, int const* _verticesOnEdge_F,
int const* _edgesOnCell_F, int const* _nEdgesOnCells_F,
int const* _indexToCellID_F,
+ int const* _indexToEdgeID_F,
+ int const* _indexToVertexID_F,
double const* _xCell_F, double const* _yCell_F, double const* _zCell_F,
double const* _xVertex_F, double const* _yVertex_F, double const* _zVertex_F,
double const* _areaTriangle_F,
@@ -118,15 +116,12 @@ void velocity_solver_set_grid_data(int const* _nCells_F, int const* _nEdges_F,
int const* sendEdgesArray_F, int const* recvEdgesArray_F,
int const* sendVerticesArray_F, int const* recvVerticesArray_F);
-void velocity_solver_extrude_3d_grid(double const* levelsRatio_F,
- double const* lowerSurface_F, double const* thickness_F);
+void velocity_solver_extrude_3d_grid(double const* levelsRatio_F);
void velocity_solver_export_l1l2_velocity();
void velocity_solver_export_fo_velocity();
-//void velocity_solver_estimate_SS_SMB (const double* u_normal_F, double* sfcMassBal);
-
void interface_init_log();
void interface_redirect_stdout(int const* iTimestep);
@@ -136,6 +131,9 @@ void interface_reset_stdout();
void write_ascii_mesh(int const* indexToCellID_F,
double const* bedTopography_F, double const* lowerSurface_F,
double const* beta_F, double const* temperature_F,
+ double const* surfaceAirTemperature_F, double const* basalHeatFlux_F,
+ double const* stiffnessFactor_F,
+ double const* effecPress_F, double const* muFriction_F,
double const* thickness_F, double const* thicknessUncertainty_F,
double const* smb_F, double const* smbUncertainty_F,
double const* bmb_F, double const* bmbUncertainty_F,
@@ -145,25 +143,11 @@ void write_ascii_mesh(int const* indexToCellID_F,
} // extern "C"
+extern int velocity_solver_init_mpi__(MPI_Comm comm);
extern void velocity_solver_finalize__();
-#ifdef LIFEV
-extern void velocity_solver_init_l1l2__(const std::vector& layersRatio, const std::vector& velocityOnVertices, bool initialize_velocity);
-
-extern void velocity_solver_solve_l1l2__(const std::vector& elevationData,
- const std::vector& thicknessData, const std::vector& betaData,
- const std::vector& temperatureData, const std::vector& indexToVertexID,
- std::vector& velocityOnVertices);
-
-extern void velocity_solver_init_fo__(const std::vector& layersRatio, const std::vector& velocityOnVertices, const std::vector& indexToVertexID, bool initialize_velocity);
-
-extern void velocity_solver_export_l1l2_velocity__(const std::vector& layersRatio, const std::vector& elevationData, const std::vector& regulThk,
- const std::vector& mpasIndexToVertexID, MPI_Comm reducedComm);
-
-#endif
-
extern void velocity_solver_set_physical_parameters__(double const& gravity, double const& ice_density, double const& ocean_density, double const& sea_level, double const& flowParamA,
- double const& enhancementFactor, double const& flowLawExponent, double const& dynamic_thickness, bool const& useGLP, double const& clausiusClapeyronCoeff);
+ double const& flowLawExponent, double const& dynamic_thickness, bool const& useGLP, double const& clausiusClapeyronCoeff);
extern void velocity_solver_solve_fo__(int nLayers, int nGlobalVertices,
int nGlobalTriangles, bool ordering, bool first_time_step,
@@ -173,34 +157,20 @@ extern void velocity_solver_solve_fo__(int nLayers, int nGlobalVertices,
const std::vector& levelsNormalizedThickness,
const std::vector& elevationData,
const std::vector& thicknessData,
- const std::vector& betaData,
+ std::vector& betaData,
const std::vector& bedTopographyData,
const std::vector& smbData,
- const std::vector& temperatureOnTetra,
- std::vector& dissipationHeatOnTetra,
+ const std::vector& stiffnessFactorData,
+ const std::vector& effecPressData,
+ const std::vector& muFrictionData,
+ const std::vector& temperatureDataOnPrisms,
+ std::vector& bodyForceOnBasalCell,
+ std::vector& dissipationHeatOnPrisms,
std::vector& velocityOnVertices,
int& error,
const double& deltat = 0.0);
-
-#ifdef LIFEV
-extern void velocity_solver_compute_2d_grid__(int nGlobalTriangles,
- int nGlobalVertices, int nGlobalEdges,
- const std::vector& indexToVertexID,
- const std::vector& verticesCoords,
- const std::vector& isVertexBoundary,
- const std::vector& verticesOnTria,
- const std::vector& isBoundaryEdge,
- const std::vector& trianglesOnEdge,
- const std::vector& trianglesPositionsOnEdge,
- const std::vector& verticesOnEdge,
- const std::vector& indexToEdgeID,
- const std::vector& indexToTriangleID,
- const std::vector < std::pair >& procOnInterfaceEdge);
-
-#else
extern void velocity_solver_compute_2d_grid__(MPI_Comm);
-#endif
extern void velocity_solver_export_2d_data__(MPI_Comm reducedComm,
@@ -209,47 +179,37 @@ extern void velocity_solver_export_2d_data__(MPI_Comm reducedComm,
const std::vector& betaData,
const std::vector& indexToVertexID);
-extern void velocity_solver_extrude_3d_grid__(int nLayers, int nGlobalTriangles,
- int nGlobalVertices, int nGlobalEdges, int Ordering, MPI_Comm reducedComm,
+extern void velocity_solver_extrude_3d_grid__(
+ int nLayers, int globalTriangleStride, int globalVertexStride, int globalEdgeStride,
+ int Ordering, MPI_Comm reducedComm,
const std::vector& indexToVertexID,
- const std::vector& mpasIndexToVertexID,
+ const std::vector& vertexProcIDs,
const std::vector& verticesCoords,
- const std::vector& isVertexBoundary,
const std::vector& verticesOnTria,
+ const std::vector> procsSharingVertices,
const std::vector& isBoundaryEdge,
const std::vector& trianglesOnEdge,
- const std::vector& trianglesPositionsOnEdge,
const std::vector& verticesOnEdge,
const std::vector& indexToEdgeID,
const std::vector& indexToTriangleID,
const std::vector& dirichletNodes,
- const std::vector&floatingEdges);
-
-//extern void velocity_solver_export_l1l2_velocity__();
+ const std::vector& iceMarginEdgesID);
extern void velocity_solver_export_fo_velocity__(MPI_Comm reducedComm);
-
-#ifdef LIFEV
-extern int velocity_solver_initialize_iceProblem__(bool keep_proc, MPI_Comm reducedComm);
-#endif
-
-//extern void velocity_solver_estimate_SS_SMB__ (const double* u_normal_F, double* sfcMassBal);
-
exchangeList_Type unpackMpiArray(int const* array);
-bool isGhostTriangle(int i, double relTol = 1e-1);
-
double signedTriangleArea(const double* x, const double* y);
double signedTriangleArea(const double* x, const double* y, const double* z);
void createReducedMPI(int nLocalEntities, MPI_Comm& reduced_comm_id);
-void import2DFields(std::map bdExtensionMap, double const* bedTopography_F, double const* lowerSurface_F, double const* thickness_F,
- double const* beta_F = 0, double const* temperature_F = 0, double const* smb_F = 0, double eps = 0);
+void importFields(std::vector >& marineBdyExtensionMap,
+ double const* bedTopography_F, double const* lowerSurface_F, double const* thickness_F,
+ double const* beta_F = 0, double const* stiffnessFactor_F = 0, double const* effecPress_F = 0, double const* muFriction_F = 0, double const* temperature_F = 0, double const* smb_F = 0, double eps = 0);
-void import2DFieldsObservations(std::map bdExtensionMap,
+void import2DFieldsObservations(std::vector >& marineBdyExtensionMap,
double const * lowerSurface_F,
double const * thickness_F, double const * thicknessUncertainty_F,
double const * smbUncertainty_F,
@@ -257,20 +217,20 @@ void import2DFieldsObservations(std::map bdExtensionMap,
double const * observedSurfaceVelocityX_F, double const * observedSurfaceVelocityY_F,
double const * observedSurfaceVelocityUncertainty_F,
double const * observedThicknessTendency_F, double const * observedThicknessTendencyUncertainty_F,
+ double const* surfaceAirTemperature_F, double const* basalHeatFlux_F,
int const * indexToCellID_F);
-
+
+void computeSortingIndices(std::vector& sortingIndices, const std::vector& vectorToSort, int numIndices);
+
void write_ascii_mesh_field(std::vector fieldData, std::string filenamebase);
void write_ascii_mesh_field_int(std::vector fieldData, std::string filenamebase);
std::vector extendMaskByOneLayer(int const* verticesMask_F);
-void extendMaskByOneLayer(int const* verticesMask_F,
- std::vector& extendedFVerticesMask);
-
-void importP0Temperature();
-
void exportDissipationHeat(double * dissipationHeat_F);
+void exportBodyForce(double * bodyForce_F);
+void exportBeta(double * beta_F);
void get_prism_velocity_on_FEdges(double* uNormal,
const std::vector& velocityOnCells,
@@ -278,15 +238,9 @@ void get_prism_velocity_on_FEdges(double* uNormal,
int initialize_iceProblem(int nTriangles);
-void createReverseCellsExchangeLists(exchangeList_Type& sendListReverse_F,
- exchangeList_Type& receiveListReverse_F,
- const std::vector& fVertexToTriangleID,
- const std::vector& fCellToVertexID);
-
-void createReverseEdgesExchangeLists(exchangeList_Type& sendListReverse_F,
+void createReverseExchangeLists(exchangeList_Type& sendListReverse_F,
exchangeList_Type& receiveListReverse_F,
- const std::vector& fVertexToTriangleID,
- const std::vector& fEdgeToEdgeID);
+ const std::vector& newProcIds, const int* indexToID_F, exchangeList_Type const * recvList_F);
void mapCellsToVertices(const std::vector& velocityOnCells,
std::vector& velocityOnVertices, int fieldDim, int numLayers,
@@ -295,9 +249,6 @@ void mapCellsToVertices(const std::vector& velocityOnCells,
void mapVerticesToCells(const std::vector& velocityOnVertices,
double* velocityOnCells, int fieldDim, int numLayers, int ordering);
-void computeLocalOffset(int nLocalEntities, int& localOffset,
- int& nGlobalEntities);
-
void getProcIds(std::vector& field, int const* recvArray);
void getProcIds(std::vector& field, exchangeList_Type const* recvList);
@@ -311,12 +262,6 @@ void allToAll(std::vector& field, exchangeList_Type const* sendList,
void allToAll(double* field, exchangeList_Type const* sendList,
exchangeList_Type const* recvList, int fieldDim = 1);
-int prismType(long long int const* prismVertexMpasIds, int& minIndex);
-void tetrasFromPrismStructured (long long int const* prismVertexMpasIds, long long int const* prismVertexGIds, long long int tetrasIdsOnPrism[][4]);
-void computeMap();
-
-void setBdFacesOnPrism (const std::vector > >& prismStruct, const std::vector& prismFaceIds, std::vector& tetraPos, std::vector& facePos);
-void tetrasFromPrismStructured (int const* prismVertexMpasIds, int const* prismVertexGIds, int tetrasIdsOnPrism[][4]);
void procsSharingVertex(const int vertex, std::vector& procIds);
bool belongToTria(double const* x, double const* t, double bcoords[3], double eps = 1e-3);
diff --git a/src/core_landice/mode_forward/Makefile b/src/core_landice/mode_forward/Makefile
index 5543e557dd..d635b54016 100644
--- a/src/core_landice/mode_forward/Makefile
+++ b/src/core_landice/mode_forward/Makefile
@@ -11,10 +11,12 @@ OBJS = mpas_li_core.o \
mpas_li_statistics.o \
mpas_li_velocity.o \
mpas_li_thermal.o \
+ mpas_li_iceshelf_melt.o \
mpas_li_sia.o \
mpas_li_velocity_simple.o \
mpas_li_velocity_external.o \
- mpas_li_subglacial_hydro.o
+ mpas_li_subglacial_hydro.o \
+ mpas_li_bedtopo.o
ifneq (, $(findstring MPAS_LI_BUILD_INTERFACE,$(CPPFLAGS)))
OBJS += Interface_velocity_solver.o
@@ -35,9 +37,11 @@ mpas_li_time_integration.o: mpas_li_time_integration_fe.o
mpas_li_time_integration_fe.o: mpas_li_advection.o \
mpas_li_calving.o \
mpas_li_thermal.o \
+ mpas_li_iceshelf_melt.o \
mpas_li_diagnostic_vars.o \
mpas_li_velocity.o \
- mpas_li_subglacial_hydro.o
+ mpas_li_subglacial_hydro.o \
+ mpas_li_bedtopo.o
mpas_li_advection.o: mpas_li_thermal.o \
mpas_li_diagnostic_vars.o
@@ -47,12 +51,15 @@ mpas_li_calving.o: mpas_li_thermal.o \
mpas_li_thermal.o:
+mpas_li_iceshelf_melt.o: mpas_li_calving.o
+
mpas_li_diagnostic_vars.o: mpas_li_thermal.o
mpas_li_velocity.o: mpas_li_sia.o \
mpas_li_velocity_simple.o \
mpas_li_velocity_external.o \
- mpas_li_advection.o
+ mpas_li_advection.o \
+ mpas_li_thermal.o
mpas_li_sia.o: mpas_li_diagnostic_vars.o
@@ -64,6 +71,8 @@ mpas_li_statistics.o: mpas_li_diagnostic_vars.o
mpas_li_velocity_external.o: Interface_velocity_solver.o
+mpas_li_bedtopo.o: mpas_li_advection.o
+
Interface_velocity_solver.o:
clean:
diff --git a/src/core_landice/mode_forward/mpas_li_advection.F b/src/core_landice/mode_forward/mpas_li_advection.F
index f2d0ed0229..2da5503955 100644
--- a/src/core_landice/mode_forward/mpas_li_advection.F
+++ b/src/core_landice/mode_forward/mpas_li_advection.F
@@ -138,15 +138,19 @@ subroutine li_advection_thickness_tracers(&
real (kind=RKIND), dimension(:), pointer :: &
thickness, & ! ice thickness (updated in this subroutine)
bedTopography, & ! bed topography
- sfcMassBal, & ! surface mass balance
+ sfcMassBal, & ! surface mass balance (potential forcing)
+ sfcMassBalApplied, & ! surface mass balance (actually applied)
+ groundedSfcMassBalApplied, & ! surface mass balance on grounded locations (actually applied)
basalMassBal, & ! basal mass balance
groundedBasalMassBal, & ! basal mass balance for grounded ice
floatingBasalMassBal, & ! basal mass balance for floating ice
- dynamicThickening ! dynamic thickening rate
+ dynamicThickening, & ! dynamic thickening rate
+ groundedToFloatingThickness, & ! thickness changing from grounded to floating or vice versa
+ fluxAcrossGroundingLine ! magnitude of flux across GL
real (kind=RKIND), dimension(:,:), pointer :: &
temperature, & ! interior ice temperature
- waterfrac, & ! interior water fraction
+ waterFrac, & ! interior water fraction
enthalpy ! interior ice enthalpy
real (kind=RKIND), dimension(:,:), pointer :: &
@@ -174,8 +178,16 @@ subroutine li_advection_thickness_tracers(&
surfaceTracersField, & ! scratch field containing values of surface tracers
basalTracersField ! scratch field containing values of basal tracers
+ type (field1DInteger), pointer :: &
+ cellMaskTemporaryField ! scratch field containing old values of cellMask
+
integer, dimension(:), pointer :: &
- cellMask ! integer bitmask for cells
+ cellMask, & ! integer bitmask for cells
+ edgeMask ! integer bitmask for edges
+
+ integer, dimension(:,:), pointer :: cellsOnEdge
+
+ real (kind=RKIND), dimension(:), pointer :: dvEdge
character (len=StrKIND), pointer :: &
config_thickness_advection ! method for advecting thickness and tracers
@@ -185,15 +197,20 @@ subroutine li_advection_thickness_tracers(&
real (kind=RKIND), pointer :: &
config_ice_density, & ! rhoi
+ config_ocean_density, & ! rhoo
config_sea_level ! sea level relative to z = 0
logical :: advectTracers ! if true, then advect tracers as well as thickness
+ integer :: iCell1
+
+ real(kind=RKIND) :: GLfluxSign, thicknessFluxEdge
+
integer :: err_tmp
!WHL - debug
integer, dimension(:), pointer :: indexToCellID, indexToEdgeID
- integer, pointer :: nCells
+ integer, pointer :: nCells, nEdges
integer, pointer :: config_stats_cell_ID
integer :: iEdge, iEdgeOnCell
integer, dimension(:), pointer :: nEdgesOnCell
@@ -233,35 +250,44 @@ subroutine li_advection_thickness_tracers(&
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
call mpas_pool_get_array(geometryPool, 'sfcMassBal', sfcMassBal)
+ call mpas_pool_get_array(geometryPool, 'sfcMassBalApplied', sfcMassBalApplied)
+ call mpas_pool_get_array(geometryPool, 'groundedSfcMassBalApplied', groundedSfcMassBalApplied)
call mpas_pool_get_array(geometryPool, 'basalMassBal', basalMassBal)
call mpas_pool_get_array(geometryPool, 'groundedBasalMassBal', groundedBasalMassBal)
call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
call mpas_pool_get_array(geometryPool, 'layerThickness', layerThickness)
call mpas_pool_get_array(geometryPool, 'layerThicknessEdge', layerThicknessEdge)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
call mpas_pool_get_array(geometryPool, 'dynamicThickening', dynamicThickening)
+ call mpas_pool_get_array(geometryPool, 'groundedToFloatingThickness', groundedToFloatingThickness)
! get arrays from the velocity pool
call mpas_pool_get_array(velocityPool, 'layerNormalVelocity', layerNormalVelocity)
+ call mpas_pool_get_array(velocityPool, 'fluxAcrossGroundingLine', fluxAcrossGroundingLine)
! get arrays from the thermal pool
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
- call mpas_pool_get_array(thermalPool, 'waterfrac', waterfrac)
+ call mpas_pool_get_array(thermalPool, 'waterFrac', waterFrac)
call mpas_pool_get_array(thermalPool, 'enthalpy', enthalpy)
! get config variables
call mpas_pool_get_config(liConfigs, 'config_thickness_advection', config_thickness_advection)
call mpas_pool_get_config(liConfigs, 'config_print_thickness_advection_info', config_print_thickness_advection_info)
call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density)
+ call mpas_pool_get_config(liConfigs, 'config_ocean_density', config_ocean_density)
call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
!WHL - debug
call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_dimension(meshPool, 'nEdges', nEdges)
call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
call mpas_pool_get_array(meshPool, 'indexToCellID', indexToCellID)
call mpas_pool_get_array(meshPool, 'indexToEdgeID', indexToEdgeID)
call mpas_pool_get_config(liConfigs, 'config_stats_cell_ID', config_stats_cell_ID)
+ call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge)
+ call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge)
! get fields from the scratch pool
! Note: The advectedTracers field is a scratch field containing only the tracers that need to be advected.
@@ -287,9 +313,20 @@ subroutine li_advection_thickness_tracers(&
call mpas_allocate_scratch_field(basalTracersField, .true.)
basalTracers => basalTracersField % array
+ call mpas_pool_get_field(geometryPool, 'cellMaskTemporary', cellMaskTemporaryField)
+ call mpas_allocate_scratch_field(cellMaskTemporaryField, .true.)
+
+
! given the old thickness, compute the thickness in each layer
call li_calculate_layerThickness(meshPool, thickness, layerThickness)
+ ! update masks
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ ! save old copycellMask for determining cells changing from grounded to floating and vice versa
+ cellMaskTemporaryField % array(:) = cellMask(:)
+
!-----------------------------------------------------------------
! Horizontal transport of thickness and tracers
!-----------------------------------------------------------------
@@ -331,7 +368,7 @@ subroutine li_advection_thickness_tracers(&
endif
! Transport thickness and tracers using a first-order upwind scheme
- ! Note: For the enthalpy scheme, temperature and waterfrac are the primary prognostic
+ ! Note: For the enthalpy scheme, temperature and waterFrac are the primary prognostic
! variables to be updated, but enthalpy is the advected tracer (for reasons of
! energy conservation).
@@ -339,7 +376,7 @@ subroutine li_advection_thickness_tracers(&
do iCell = 1, nCells
if (indexToCellID(iCell) == config_stats_cell_ID) then
- call mpas_log_write('Before thickness advection, iCell (local=$i, global=$i), thickness=$r, layer 1 tracer:=$r', &
+ call mpas_log_write('Before thickness advection, iCell (local=$i, global=$i), thickness=$r, layer 1 tracer:=$r',&
intArgs=(/iCell, indexToCellID(iCell)/), realArgs=(/thickness(iCell), advectedTracers(1,1,iCell)/))
do iEdgeOnCell = 1, nEdgesOnCell(iCell)
iEdge = edgesOnCell(iEdgeOnCell,iCell)
@@ -362,8 +399,11 @@ subroutine li_advection_thickness_tracers(&
layerThicknessEdge, &
layerThicknessOld, &
advectedTracersOld, &
+ cellMask, &
+ edgeMask, &
layerThickness, &
advectedTracers, &
+ fluxAcrossGroundingLine, &
err)
if (config_print_thickness_advection_info) then
@@ -379,27 +419,22 @@ subroutine li_advection_thickness_tracers(&
enddo
endif
+
! Calculate dynamicThickening (layerThickness is updated by advection at this point, while thickness is still old)
dynamicThickening = (sum(layerThickness, 1) - thickness) / dt * scyr ! units of m/yr
+
! Update the thickness and cellMask before applying the mass balance.
! The update is needed because the SMB and BMB depend on whether ice is present.
-
thickness = sum(layerThickness, 1)
call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+
+
!-----------------------------------------------------------------
! Add the surface and basal mass balance to the layer thickness
!-----------------------------------------------------------------
- ! Zero out any positive surface mass balance for ice-free ocean cells
-
- where ( sfcMassBal > 0.0_RKIND .and. bedTopography < config_sea_level .and. .not.(li_mask_is_ice(cellMask) ) )
-
- sfcMassBal = 0.0_RKIND
-
- end where
-
! Combine various basal mass balance fields based on mask.
! Grounded and floating basal mass balance should come from the thermal solver.
@@ -425,7 +460,11 @@ subroutine li_advection_thickness_tracers(&
call apply_mass_balance(&
dt, &
config_ice_density, &
+ cellMask, &
+ bedTopography, &
sfcMassBal, &
+ sfcMassBalApplied, &
+ groundedSfcMassBalApplied, &
basalMassBal, &
surfaceTracers, &
basalTracers, &
@@ -444,17 +483,43 @@ subroutine li_advection_thickness_tracers(&
do iCell = 1, nCells
if (indexToCellID(iCell) == config_stats_cell_ID) then
call mpas_log_write(' ')
- call mpas_log_write('After apply_mass_balance, iCell=$i, thickness=$r', intArgs=(/iCell/), realArgs=(/thickness(iCell)/) )
+ call mpas_log_write('After apply_mass_balance, iCell=$i, thickness=$r', intArgs=(/iCell/), &
+ realArgs=(/thickness(iCell)/) )
call mpas_log_write('cellMask=$i, is ice=$l, is grounded=$l, is floating=$l', &
- intArgs=(/cellMask(iCell)/), logicArgs=(/li_mask_is_ice(cellMask(iCell)), li_mask_is_grounded_ice(cellMask(iCell)), &
- li_mask_is_floating_ice(cellMask(iCell)) /) )
- call mpas_log_write('basalMassBal=$r, grounded=$r, floating=$r', realArgs=(/ basalMassBal(iCell)*31536000./917., &
+ intArgs=(/cellMask(iCell)/), logicArgs=(/li_mask_is_ice(cellMask(iCell)), &
+ li_mask_is_grounded_ice(cellMask(iCell)), li_mask_is_floating_ice(cellMask(iCell)) /) )
+ call mpas_log_write('basalMassBal=$r, grounded=$r, floating=$r', realArgs=(/ basalMassBal(iCell)*31536000./917.,&
groundedBasalMassBal(iCell)*31536000./917., floatingBasalMassBal(iCell)*31536000./917. /) )
endif
enddo
endif
call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ ! Calculate volume converted from grounded to floating
+ ! This needs to be determined after SMB/BMB are applied because those can change floating/grounded state
+ call grounded_to_floating(cellMaskTemporaryField % array, cellMask, thickness, groundedToFloatingThickness, nCells)
+
+ ! Calculate flux across grounding line
+ ! Do this after new thickness & mask have been calculated, including SMB/BMB
+ fluxAcrossGroundingLine(:) = 0.0_RKIND
+ do iEdge = 1, nEdges
+ if (li_mask_is_grounding_line(edgeMask(iEdge))) then
+ iCell1 = cellsOnEdge(1,iEdge)
+ !iCell2 = cellsOnEdge(2,iEdge)
+ if (li_mask_is_grounded_ice(cellMask(iCell1))) then
+ GLfluxSign = 1.0_RKIND ! edge sign convention is positive from iCell1 to iCell2 on an edge
+ else
+ GLfluxSign = -1.0_RKIND
+ endif
+ do k = 1, nVertLevels
+ thicknessFluxEdge = layerNormalVelocity(k,iEdge) * dvEdge(iEdge) * layerThicknessEdge(k,iEdge)
+ fluxAcrossGroundingLine(iEdge) = fluxAcrossGroundingLine(iEdge) + GLfluxSign * thicknessFluxEdge / dvEdge(iEdge)
+ enddo
+ endif
+ enddo ! edges
+
! Remap tracers to the standard vertical sigma coordinate
! Note: If tracers are not being advected, then this subroutine simply restores the
@@ -469,7 +534,8 @@ subroutine li_advection_thickness_tracers(&
call mpas_log_write(' ')
call mpas_log_write('After vertical remap, iCell, new layer thickness, tracer 1:')
do k = 1, nVertLevels
- call mpas_log_write("$i $r $r", intArgs=(/iCell/), realArgs=(/layerThickness(k,iCell), advectedTracers(1,k,iCell)/))
+ call mpas_log_write("$i $r $r", intArgs=(/iCell/), realArgs=(/layerThickness(k,iCell), &
+ advectedTracers(1,k,iCell)/))
enddo
endif
enddo
@@ -478,7 +544,7 @@ subroutine li_advection_thickness_tracers(&
if (advectTracers) then
! Copy the advectedTracersNew values into the thermal tracer arrays
- ! (temperature, waterfrac, enthalpy)
+ ! (temperature, waterFrac, enthalpy)
call tracer_finish(&
meshPool, &
@@ -494,7 +560,8 @@ subroutine li_advection_thickness_tracers(&
case default
- call mpas_log_write(trim(config_thickness_advection) // ' is not a valid option for thickness/tracer advection.', MPAS_LOG_ERR)
+ call mpas_log_write(trim(config_thickness_advection) // ' is not a valid option for thickness/tracer advection.', &
+ MPAS_LOG_ERR)
err_tmp = 1
end select
@@ -507,6 +574,7 @@ subroutine li_advection_thickness_tracers(&
call mpas_deallocate_scratch_field(layerThicknessOldField, .true.)
call mpas_deallocate_scratch_field(basalTracersField, .true.)
call mpas_deallocate_scratch_field(surfaceTracersField, .true.)
+ call mpas_deallocate_scratch_field(cellMaskTemporaryField, .true.)
! === error check
if (err > 0) then
@@ -516,7 +584,7 @@ subroutine li_advection_thickness_tracers(&
!--------------------------------------------------------------------
end subroutine li_advection_thickness_tracers
-
+
!***********************************************************************
!
! subroutine li_update_geometry
@@ -569,7 +637,7 @@ subroutine li_update_geometry(geometryPool)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
- ! Lower surface is based on floatation for floating ice.
+ ! Lower surface is based on floatation for floating ice.
! For grounded ice (and non-ice areas) it is the bed.
where ( li_mask_is_floating_ice(cellMask) )
lowerSurface = config_sea_level - thickness * (config_ice_density / config_ocean_density)
@@ -586,7 +654,7 @@ subroutine li_update_geometry(geometryPool)
! Upper surface is the lower surface plus the thickness
upperSurface(:) = lowerSurface(:) + thickness(:)
-
+
!--------------------------------------------------------------------
end subroutine li_update_geometry
@@ -612,7 +680,11 @@ end subroutine li_update_geometry
subroutine apply_mass_balance(&
dt, &
rhoi, &
+ cellMask, &
+ bedTopography, &
sfcMassBal, &
+ sfcMassBalApplied, &
+ groundedSfcMassBalApplied, &
basalMassBal, &
surfaceTracers, &
basalTracers, &
@@ -620,16 +692,17 @@ subroutine apply_mass_balance(&
advectedTracers)
!-----------------------------------------------------------------
- !
! input variables
- !
!-----------------------------------------------------------------
real (kind=RKIND), intent(in) :: &
dt, & !< Input: time step (s)
rhoi !< Input: ice density (kg/m^3)
+ integer, dimension(:), intent(in) :: cellMask !< Input: mask on cells
+
real (kind=RKIND), dimension(:), intent(in) :: &
+ bedTopography, & !< Input: bed elevation (m)
sfcMassBal, & !< Input: surface mass balance (kg/m^2/s)
basalMassBal !< Input: basal mass balance (kg/m^2/s)
@@ -638,16 +711,25 @@ subroutine apply_mass_balance(&
basalTracers !< Input: tracer values of new ice at lower surface
!-----------------------------------------------------------------
- !
! input/output variables
- !
!-----------------------------------------------------------------
real(kind=RKIND), dimension(:,:), intent(inout) :: &
- layerThickness ! ice thickness in each layer (m)
+ layerThickness !< Input/Output: ice thickness in each layer (m)
real(kind=RKIND), dimension(:,:,:), intent(inout) :: &
- advectedTracers ! tracer values in each layer
+ advectedTracers !< Input/Output: tracer values in each layer
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ sfcMassBalApplied !< Output: surface mass balance actually applied on this time step (kg/m^2/s)
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ groundedSfcMassBalApplied !< Output: surface mass balance actually applied to grounded ice on this time step (kg/m^2/s)
+
! local variables
@@ -661,6 +743,7 @@ subroutine apply_mass_balance(&
integer :: nCells ! number of cells
integer :: nLayers ! number of layers
integer :: nTracers ! number of tracers
+ real (kind=RKIND), pointer :: config_sea_level ! sea level relative to z = 0
integer :: iCell, iLayer, iTracer
@@ -670,10 +753,15 @@ subroutine apply_mass_balance(&
allocate(thckTracerProducts(nTracers))
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+
! apply surface mass balance
! If positive, then add the SMB to the top layer, conserving mass*tracer products
! If negative, then melt from the top down until the melting term is used up or the ice is gone
+ ! Initialize applied SMB field
+ sfcMassBalApplied(:) = sfcMassBal(:)
+
do iCell = 1, nCells
! initialize accumulation/ablation terms
@@ -685,12 +773,18 @@ subroutine apply_mass_balance(&
! apply surface mass balance
- if (sfcMassBal(iCell) > 0.0_RKIND) then
+ ! Zero out any positive surface mass balance for ice-free ocean cells
+ if (sfcMassBalApplied(iCell) > 0.0_RKIND .and. &
+ bedTopography(iCell) < config_sea_level .and. .not.(li_mask_is_ice(cellMask(iCell)) ) ) then
+ sfcMassBalApplied(iCell) = 0.0_RKIND
+ end if
+
+ ! surface accumulation
+ if (sfcMassBalApplied(iCell) > 0.0_RKIND) then
- ! surface accumulation
! modify tracers conservatively in top layer
- sfcAccum = sfcMassBal(iCell) * dt / rhoi
+ sfcAccum = sfcMassBalApplied(iCell) * dt / rhoi
! compute mass-tracer products in top layer
thckTracerProducts(:) = layerThickness(1,iCell)*advectedTracers(:,1,iCell) &
@@ -702,11 +796,10 @@ subroutine apply_mass_balance(&
! new tracers in top layer
advectedTracers(:,1,iCell) = thckTracerProducts(:) / layerThickness(1,iCell)
- elseif (sfcMassBal(iCell) < 0.0_RKIND) then
-
- ! surface ablation from the top down
+ ! surface ablation
+ elseif (sfcMassBalApplied(iCell) < 0.0_RKIND) then
- sfcAblat = -sfcMassBal(iCell) * dt /rhoi ! positive for melting
+ sfcAblat = -1.0_RKIND * sfcMassBalApplied(iCell) * dt /rhoi ! positive for melting
do iLayer = 1, nLayers
if (sfcAblat > layerThickness(iLayer,iCell)) then ! melt the entire layer
@@ -720,10 +813,20 @@ subroutine apply_mass_balance(&
endif
enddo
- !TODO - If remaining sfcAblat > 0, then keep track of it to conserve energy
+ ! Adjust applied SMB to only be the amount actually applied above (this will include ice-free cells)
+ if (sfcAblat > 0.0_RKIND) then
+ sfcMassBalApplied(iCell) = sfcMassBalApplied(iCell) + sfcAblat * rhoi / dt
+ !TODO - If remaining sfcAblat > 0, then keep track of it to conserve energy (?)
+ endif
+
endif ! sfcMassBal > 0
+ groundedSfcMassBalApplied(:) = 0.0_RKIND
+ where (li_mask_is_grounded_ice(cellMask) .or. bedTopography > config_sea_level)
+ groundedSfcMassBalApplied = sfcMassBalApplied
+ end where
+
! apply basal mass balance
if (basalMassBal(iCell) > 0.0_RKIND) then
@@ -793,7 +896,7 @@ subroutine tracer_setup(&
surfaceTracers, &
basalTracers)
- use li_thermal, only: li_temperature_to_enthalpy
+ use li_thermal, only: li_temperature_to_enthalpy_kelvin
!-----------------------------------------------------------------
!
@@ -835,11 +938,11 @@ subroutine tracer_setup(&
config_thermal_solver
integer, pointer :: &
- nCellsSolve ! number of locally owned cells
+ nCells ! number of cells
real (kind=RKIND), dimension(:,:), pointer :: &
temperature, & ! interior ice temperature
- waterfrac, & ! interior water fraction
+ waterFrac, & ! interior water fraction
enthalpy ! interior ice enthalpy
real (kind=RKIND), dimension(:), pointer :: &
@@ -858,7 +961,7 @@ subroutine tracer_setup(&
integer :: iCell, iTracer
! get dimensions
- call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
! get arrays from mesh pool
call mpas_pool_get_array(meshPool, 'layerCenterSigma', layerCenterSigma)
@@ -868,7 +971,7 @@ subroutine tracer_setup(&
! get arrays from thermal pool
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
- call mpas_pool_get_array(thermalPool, 'waterfrac', waterfrac)
+ call mpas_pool_get_array(thermalPool, 'waterFrac', waterFrac)
call mpas_pool_get_array(thermalPool, 'enthalpy', enthalpy)
call mpas_pool_get_array(thermalPool, 'surfaceAirTemperature', surfaceAirTemperature)
call mpas_pool_get_array(thermalPool, 'basalTemperature', basalTemperature)
@@ -882,8 +985,8 @@ subroutine tracer_setup(&
! Notes:
! (1) For the enthalpy solver, it is necessary to transport enthalpy (rather than
- ! temperature and waterfrac separately) in order to conserve energy.
- ! (2) Temperature and waterfrac must be up to date (including halo cells)
+ ! temperature and waterFrac separately) in order to conserve energy.
+ ! (2) Temperature and waterFrac must be up to date (including halo cells)
! before calling this subroutine.
! (3) Surface and basal temperature (or enthalpy) are not transported, but their
! values are applied to new accumulation at either surface.
@@ -896,15 +999,15 @@ subroutine tracer_setup(&
if (trim(config_thermal_solver) == 'enthalpy') then ! advect enthalpy
- ! Rather than assume that enthalpy is up to date, recompute it from temperature and waterfrac
+ ! Rather than assume that enthalpy is up to date, recompute it from temperature and waterFrac
- do iCell = 1, nCellsSolve
+ do iCell = 1, nCells
- call li_temperature_to_enthalpy(&
+ call li_temperature_to_enthalpy_kelvin(&
layerCenterSigma, &
thickness(iCell), &
temperature(:,iCell), &
- waterfrac(:,iCell), &
+ waterFrac(:,iCell), &
enthalpy(:,iCell))
enddo
@@ -916,7 +1019,7 @@ subroutine tracer_setup(&
advectedTracers(iTracer,:,:) = enthalpy(:,:)
! set enthalpy of new ice at upper and lower surfaces
- ! convert temperature to enthalpy assuming waterfrac = 0 for new ice
+ ! convert temperature to enthalpy assuming waterFrac = 0 for new ice
surfaceTracers(iTracer,:) = min(surfaceAirTemperature(:), kelvin_to_celsius) * config_ice_density*cp_ice
basalTracers(iTracer,:) = basalTemperature(:) * config_ice_density*cp_ice
@@ -958,7 +1061,7 @@ subroutine tracer_finish(&
thermalPool, &
advectedTracers)
- use li_thermal, only: li_enthalpy_to_temperature
+ use li_thermal, only: li_enthalpy_to_temperature_kelvin
!-----------------------------------------------------------------
!
@@ -1005,7 +1108,7 @@ subroutine tracer_finish(&
real (kind=RKIND), dimension(:,:), pointer :: &
temperature, & ! interior ice temperature
- waterfrac, & ! water fraction
+ waterFrac, & ! water fraction
enthalpy ! interior ice enthalpy
integer :: iCell, iTracer
@@ -1021,7 +1124,7 @@ subroutine tracer_finish(&
! get arrays from thermal pool
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
- call mpas_pool_get_array(thermalPool, 'waterfrac', waterfrac)
+ call mpas_pool_get_array(thermalPool, 'waterFrac', waterFrac)
call mpas_pool_get_array(thermalPool, 'enthalpy', enthalpy)
! get config variables
@@ -1038,12 +1141,12 @@ subroutine tracer_finish(&
do iCell = 1, nCellsSolve
- call li_enthalpy_to_temperature(&
+ call li_enthalpy_to_temperature_kelvin(&
layerCenterSigma, &
thickness(iCell), &
enthalpy(:,iCell), &
temperature(:,iCell), &
- waterfrac(:,iCell))
+ waterFrac(:,iCell))
enddo
@@ -1080,8 +1183,11 @@ subroutine advect_thickness_tracers_upwind(&
layerThicknessEdge, &
layerThicknessOld, &
tracersOld, &
+ cellMask, &
+ edgeMask, &
layerThicknessNew, &
tracersNew, &
+ fluxAcrossGroundingLine, &
err, &
advectTracersIn)
@@ -1111,6 +1217,12 @@ subroutine advect_thickness_tracers_upwind(&
real (kind=RKIND), dimension(:,:,:), intent(in) :: &
tracersOld !< Input: tracer values
+ integer, dimension(:), intent(in) :: &
+ cellMask !< Input: mask on cells
+
+ integer, dimension(:), intent(in) :: &
+ edgeMask !< Input: mask on edges
+
!-----------------------------------------------------------------
!
! input/output variables
@@ -1129,6 +1241,9 @@ subroutine advect_thickness_tracers_upwind(&
real (kind=RKIND), dimension(:,:,:), intent(out) :: &
tracersNew !< Output: tracer values
+ real (kind=RKIND), dimension(:), intent(out) :: &
+ fluxAcrossGroundingLine !< Output: ice flux at grounding lines
+
integer, intent(out) :: &
err !< Output: error flag
@@ -1140,7 +1255,8 @@ subroutine advect_thickness_tracers_upwind(&
integer, pointer :: &
nCellsSolve, & ! number of locally owned cells
- nVertLevels ! number of vertical layers
+ nVertLevels, & ! number of vertical layers
+ nEdges ! number of edges
integer, dimension(:), pointer :: &
nEdgesOnCell ! number of edges on each cell
@@ -1186,6 +1302,7 @@ subroutine advect_thickness_tracers_upwind(&
! This is ~300 million years in seconds, but it is small enough not to overflow
real(kind=RKIND) :: velSign ! = 1.0_RKIND or -1.0_RKIND depending on sign of velocity
+ real(kind=RKIND) :: GLfluxSign
integer :: err_tmp
@@ -1215,6 +1332,7 @@ subroutine advect_thickness_tracers_upwind(&
! get dimensions
call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_dimension(meshPool, 'nEdges', nEdges)
call mpas_pool_get_dimension(meshPool, 'nVertLevels', nVertLevels)
! get mesh arrays
@@ -1244,6 +1362,7 @@ subroutine advect_thickness_tracers_upwind(&
endif
+
! Note: This loop structure (nCells loop outside nEdgesOnCell loop) results in double calculation of fluxes
! across each edge. But upwind advection is cheap, so the extra cost is minimal.
@@ -1253,7 +1372,8 @@ subroutine advect_thickness_tracers_upwind(&
invAreaCell = 1.0_RKIND / areaCell(iCell)
if (indexToCellID(iCell) == config_stats_cell_ID .and. config_print_thickness_advection_info) then
- call mpas_log_write('In advect_thickness_tracer, iCell (local=$i, global=$i) =', intArgs=(/iCell, indexToCellID(iCell)/))
+ call mpas_log_write('In advect_thickness_tracer, iCell (local=$i, global=$i) =', &
+ intArgs=(/iCell, indexToCellID(iCell)/))
call mpas_log_write('k, iEdgeOnCell, layerNormalVelocity, layerThicknessEdge, ' // &
'thicknessFluxEdge, thicknessTendency, thicknessTracerTendency:')
endif
@@ -1295,7 +1415,8 @@ subroutine advect_thickness_tracers_upwind(&
!WHL - debug
if (indexToCellID(iCell) == config_stats_cell_ID .and. k==1 .and. config_print_thickness_advection_info) then
- call mpas_log_write("$i $i $r $r $r $r $r", intArgs=(/k, iEdgeOnCell/), realArgs=(/layerNormalVelocity(k,iEdge), &
+ call mpas_log_write("$i $i $r $r $r $r $r", &
+ intArgs=(/k, iEdgeOnCell/), realArgs=(/layerNormalVelocity(k,iEdge), &
layerThicknessEdge(k,iEdge), thicknessFluxEdge, thicknessTendency, thicknessTracerTendency(1)/) )
endif
@@ -1397,6 +1518,7 @@ end subroutine advect_thickness_tracers_upwind
subroutine li_layer_normal_velocity(&
meshPool, &
normalVelocity, &
+ edgeMask, &
layerNormalVelocity, &
minOfMaxAllowableDt, &
err)
@@ -1413,6 +1535,9 @@ subroutine li_layer_normal_velocity(&
real (kind=RKIND), dimension(:,:), intent(in) :: &
normalVelocity !< Input: normal velocity on cell edges
+ integer, dimension(:), intent(in) :: &
+ edgeMask !< Input: normal velocity on cell edges
+
!-----------------------------------------------------------------
!
! output variables
@@ -1474,6 +1599,8 @@ subroutine li_layer_normal_velocity(&
! loop over local edges
do iEdge = 1, nEdgesSolve
+ if (li_mask_is_dynamic_ice(edgeMask(iEdge))) then
+
! loop over layers
do k = 1, nVertLevels
@@ -1491,6 +1618,10 @@ subroutine li_layer_normal_velocity(&
enddo ! k
+ else
+ layerNormalVelocity(:,iEdge) = 0.0_RKIND
+ endif
+
enddo ! iEdge
! === error check
@@ -1655,7 +1786,8 @@ subroutine vertical_remap(thickness, cellMask, meshPool, layerThickness, tracers
difference = abs(finalEnergySum - initEnergySum)
if (initEnergySum > eps11) then
if (difference/initEnergySum > eps11) then
- call mpas_log_write('vertical_remap, mass*tracer conservation error, iCell = $i', MPAS_LOG_WARN, intArgs=(/iCell/))
+ call mpas_log_write('vertical_remap, mass*tracer conservation error, iCell = $i', &
+ MPAS_LOG_WARN, intArgs=(/iCell/))
call mpas_log_write('init energy, final energy, difference: $r $r $r', &
realArgs=(/initEnergySum, finalEnergySum, finalEnergySum - initEnergySum/))
endif
@@ -1670,6 +1802,52 @@ subroutine vertical_remap(thickness, cellMask, meshPool, layerThickness, tracers
end subroutine vertical_remap
+ subroutine grounded_to_floating(cellMaskOrig, cellMaskNew, thicknessNew, groundedToFloatingThickness, nCells)
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ integer, dimension(:), intent(in) :: &
+ cellMaskOrig !< Input: mask for cells before advection
+
+ integer, dimension(:), intent(in) :: &
+ cellMaskNew !< Input: mask for cells after advection
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ thicknessNew !< Input: ice thickness after advection
+
+ integer, pointer, intent(in) :: &
+ nCells
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ groundedToFloatingThickness !< Input: ice thickness
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ integer :: iCell
+
+ groundedToFloatingThickness(:) = 0.0_RKIND
+
+ do iCell = 1, nCells
+ ! find locations that had grounded ice before but now have floating ice
+ if (li_mask_is_grounded_ice(cellMaskOrig(iCell)) .and. &
+ li_mask_is_floating_ice(cellMaskNew(iCell)) ) then
+ groundedToFloatingThickness(iCell) = thicknessNew(iCell)
+ ! find locations that had floating ice before but now have grounded ice
+ else if (li_mask_is_floating_ice(cellMaskOrig(iCell)) .and. &
+ li_mask_is_grounded_ice(cellMaskNew(iCell)) ) then
+ groundedToFloatingThickness(iCell) = -1.0_RKIND * thicknessNew(iCell)
+ endif
+ enddo
+
+ end subroutine grounded_to_floating
+
!***********************************************************************
end module li_advection
diff --git a/src/core_landice/mode_forward/mpas_li_bedtopo.F b/src/core_landice/mode_forward/mpas_li_bedtopo.F
new file mode 100644
index 0000000000..851e535b34
--- /dev/null
+++ b/src/core_landice/mode_forward/mpas_li_bedtopo.F
@@ -0,0 +1,286 @@
+! Copyright (c) 2013-2018, Los Alamos National Security, LLC (LANS)
+! and the University Corporation for Atmospheric Research (UCAR).
+!
+! Unless noted otherwise source code is licensed under the BSD license.
+! Additional copyright and license information can be found in the LICENSE file
+! distributed with this code, or at http://mpas-dev.github.com/license.html
+!
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! li_bedtopo
+!
+!> \MPAS land-ice bedtopo driver
+!> \author Matt Hoffman
+!> \date 20 June 2019
+!> \details
+!> This module contains the routines for bed topography for solid earth changes
+!>
+!
+!-----------------------------------------------------------------------
+
+module li_bedtopo
+
+ use mpas_derived_types
+ use mpas_pool_routines
+ use mpas_dmpar
+ use mpas_log
+ use li_mask
+ use li_setup
+
+ implicit none
+ private
+
+ !--------------------------------------------------------------------
+ ! Public parameters
+ !--------------------------------------------------------------------
+
+ !--------------------------------------------------------------------
+ ! Public member functions
+ !--------------------------------------------------------------------
+ public :: li_bedtopo_init, &
+ li_bedtopo_finalize, &
+ li_bedtopo_block_init, &
+ li_bedtopo_solve
+
+ !--------------------------------------------------------------------
+ ! Private module variables
+ !--------------------------------------------------------------------
+
+
+
+!***********************************************************************
+
+contains
+
+!***********************************************************************
+!
+! routine li_bedtopo_init
+!
+!> \brief Initializes bedtopo solver
+!> \author Matt Hoffman
+!> \date 20 June 2019
+!> \details
+!> This routine initializes the bedtopo solver.
+!
+!-----------------------------------------------------------------------
+
+ subroutine li_bedtopo_init(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ type (domain_type), intent(inout) :: domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+
+ ! No init is needed.
+ err = 0
+
+ !--------------------------------------------------------------------
+
+ end subroutine li_bedtopo_init
+
+
+
+!***********************************************************************
+!
+! routine li_bedtopo_block_init
+!
+!> \brief Initializes blocks for bedtopo solver
+!> \author Matt Hoffman
+!> \date 20 June 2019
+!> \details
+!> This routine initializes each block of the bedtopo solver.
+!
+!-----------------------------------------------------------------------
+
+ subroutine li_bedtopo_block_init(block, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (block_type), intent(inout) :: &
+ block !< Input/Output: block object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ ! No block init needed.
+ err = 0
+
+ !--------------------------------------------------------------------
+ end subroutine li_bedtopo_block_init
+
+
+
+!***********************************************************************
+!
+! subroutine li_bedtopo_solve
+!
+!> \brief Updates bed topography
+!> \author Matt Hoffman
+!> \date 20 June 2019
+!> \details
+!> This routine updates the bed topography. Currently the only option
+!> is a data field passed in as input.
+!
+!-----------------------------------------------------------------------
+subroutine li_bedtopo_solve(domain, err)
+
+ use li_mask
+ use li_advection
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ type (domain_type), intent(inout) :: domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ type (block_type), pointer :: block
+ character (len=StrKIND), pointer :: config_uplift_method
+ type (mpas_pool_type), pointer :: meshPool !< mesh information
+ type (mpas_pool_type), pointer :: geometryPool !< geometry information
+ type (mpas_pool_type), pointer :: velocityPool !< velocity information
+
+ real (kind=RKIND), dimension(:), pointer :: bedTopography, upliftRate
+ real (kind=RKIND), pointer :: deltat
+ integer :: err_tmp
+
+ err = 0
+ err_tmp = 0
+
+ ! Set needed variables and pointers
+ call mpas_pool_get_config(liConfigs, 'config_uplift_method', config_uplift_method)
+ if (trim(config_uplift_method)=='none') then
+ ! do nothing
+ elseif (trim(config_uplift_method)=='data') then
+
+ block => domain % blocklist
+ do while (associated(block))
+
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+
+ call mpas_pool_get_array(meshPool, 'deltat', deltat)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'upliftRate', upliftRate)
+
+ bedTopography(:) = bedTopography(:) + upliftRate(:) * deltat
+
+ call li_update_geometry(geometryPool)
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+
+ block => block % next
+ end do
+
+ else
+ call mpas_log_write("Unknown option selected for 'config_uplift_method'", MPAS_LOG_ERR)
+ endif
+
+
+
+
+
+ ! === error check
+ if (err > 0) then
+ call mpas_log_write("An error has occurred in li_bedtopo_solve.", MPAS_LOG_ERR)
+ endif
+
+ !--------------------------------------------------------------------
+
+ end subroutine li_bedtopo_solve
+
+
+
+
+!***********************************************************************
+!
+! routine li_bedtopo_finalize
+!
+!> \brief finalizes bedtopo solver
+!> \author Matt Hoffman
+!> \date 20 June 2019
+!> \details
+!> This routine finalizes the bedtopo solver.
+!
+!-----------------------------------------------------------------------
+
+ subroutine li_bedtopo_finalize(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ type (domain_type), intent(inout) :: domain
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ err = 0
+
+ !--------------------------------------------------------------------
+ end subroutine li_bedtopo_finalize
+
+
+
+ ! private subroutines
+
+
+
+
+!***********************************************************************
+
+end module li_bedtopo
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
diff --git a/src/core_landice/mode_forward/mpas_li_calving.F b/src/core_landice/mode_forward/mpas_li_calving.F
index 7970ea1f67..51ade4220d 100644
--- a/src/core_landice/mode_forward/mpas_li_calving.F
+++ b/src/core_landice/mode_forward/mpas_li_calving.F
@@ -1,4 +1,3 @@
-! Copyright (c) 2013-2018, Los Alamos National Security, LLC (LANS)
! and the University Corporation for Atmospheric Research (UCAR).
!
! Unless noted otherwise source code is licensed under the BSD license.
@@ -30,7 +29,6 @@ module li_calving
use li_mask
use li_constants
-
implicit none
private
@@ -46,7 +44,8 @@ module li_calving
!
!--------------------------------------------------------------------
- public :: li_calve_ice, li_restore_calving_front
+ public :: li_calve_ice, li_restore_calving_front, li_apply_front_ablation_velocity, &
+ li_calculate_damage, li_finalize_damage_after_advection
!--------------------------------------------------------------------
!
@@ -193,8 +192,6 @@ subroutine li_calve_ice(domain, err)
endif
! compute calvingThickness based on the calving_config option
- ! the calvingThickness field gets applied to the thickness state field
- ! after this if-construct
if (trim(config_calving) == 'thickness_threshold') then
call thickness_calving(domain, calvingFraction, err_tmp)
@@ -215,6 +212,26 @@ subroutine li_calve_ice(domain, err)
call eigencalving(domain, err_tmp)
err = ior(err, err_tmp)
+ elseif (trim(config_calving) == 'damagecalving') then
+
+ call damage_calving(domain, err_tmp)
+ err = ior(err, err_tmp)
+
+ elseif (trim(config_calving) == 'mask') then
+
+ call mask_calving(domain, err_tmp)
+ err = ior(err, err_tmp)
+
+ elseif (trim(config_calving) == 'von_Mises_stress') then
+
+ call von_Mises_calving(domain, err_tmp)
+ err = ior(err, err_tmp)
+
+ elseif (trim(config_calving) == 'specified_calving_velocity') then
+
+ call specified_calving_velocity(domain, err_tmp)
+ err = ior(err, err_tmp)
+
else
call mpas_log_write("Invalid option for config_calving specified: " // trim(config_calving), MPAS_LOG_ERR)
@@ -222,6 +239,8 @@ subroutine li_calve_ice(domain, err)
endif
+ ! now also remove any icebergs
+ call remove_icebergs(domain)
! Final operations after calving has been applied.
block => domain % blocklist
@@ -249,7 +268,8 @@ subroutine li_calve_ice(domain, err)
call mpas_log_write('Global cell ID, bedTopography, calvingThickness:')
do iCell = 1, nCells
if (calvingThickness(iCell) > 0.0_RKIND) then
- call mpas_log_write("$i $r $r", intArgs=(/indexToCellID(iCell)/), realArgs=(/bedTopography(iCell), calvingThickness(iCell)/))
+ call mpas_log_write("$i $r $r", intArgs=(/indexToCellID(iCell)/), &
+ realArgs=(/bedTopography(iCell), calvingThickness(iCell)/))
endif
enddo
endif ! config_print_calving_info
@@ -353,7 +373,7 @@ subroutine li_restore_calving_front(domain, err)
! These are needed to initialize the temperature profile in restored columns.
real (kind=RKIND), dimension(:,:), pointer :: &
temperature, & ! interior ice temperature
- waterfrac ! interior water fraction
+ waterFrac ! interior water fraction
real (kind=RKIND), dimension(:), pointer :: &
surfaceAirTemperature, & ! surface air temperature
@@ -369,6 +389,10 @@ subroutine li_restore_calving_front(domain, err)
integer :: i, iRow
integer :: k
+
+ ! first remove any icebergs - do it first so restore-calving can put back thin ice in those places
+ call remove_icebergs(domain)
+
! block loop
block => domain % blocklist
do while (associated(block))
@@ -396,7 +420,7 @@ subroutine li_restore_calving_front(domain, err)
! get required fields from the thermal pool
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
- call mpas_pool_get_array(thermalPool, 'waterfrac', waterfrac)
+ call mpas_pool_get_array(thermalPool, 'waterFrac', waterFrac)
call mpas_pool_get_array(thermalPool, 'surfaceAirTemperature', surfaceAirTemperature)
call mpas_pool_get_array(thermalPool, 'surfaceTemperature', surfaceTemperature)
call mpas_pool_get_array(thermalPool, 'basalTemperature', basalTemperature)
@@ -475,7 +499,7 @@ subroutine li_restore_calving_front(domain, err)
thickness(iCell), &
surfaceAirTemperature(iCell), &
temperature(:,iCell), &
- waterfrac(:,iCell), &
+ waterFrac(:,iCell), &
surfaceTemperature(iCell), &
basalTemperature(iCell))
@@ -799,6 +823,8 @@ subroutine thickness_calving(domain, calvingFraction, err)
! === apply calving ===
thickness(:) = thickness(:) - calvingThickness(:)
+ call remove_small_islands(meshPool, geometryPool)
+
block => block % next
enddo
@@ -817,7 +843,7 @@ end subroutine thickness_calving
!> \brief Calve any ice that is floating
!> \author William Lipscomb, moved to separate subroutine by Matt Hoffman Feb. 2018
!> \date September 2015
-!> \details
+!> \details
!-----------------------------------------------------------------------
subroutine floating_calving(domain, calvingFraction, err)
@@ -842,6 +868,7 @@ subroutine floating_calving(domain, calvingFraction, err)
!-----------------------------------------------------------------
type (block_type), pointer :: block
type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: meshPool
real (kind=RKIND), dimension(:), pointer :: calvingThickness ! thickness of ice that calves (computed in this subroutine)
real (kind=RKIND), dimension(:), pointer :: thickness
integer, dimension(:), pointer :: cellMask
@@ -854,6 +881,7 @@ subroutine floating_calving(domain, calvingFraction, err)
! get pools
call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
@@ -868,11 +896,104 @@ subroutine floating_calving(domain, calvingFraction, err)
! === apply calving ===
thickness(:) = thickness(:) - calvingThickness(:)
+ call remove_small_islands(meshPool, geometryPool)
+
block => block % next
enddo
end subroutine floating_calving
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine remove_small_islands
+!
+!> \brief Remove very small islands that lead to velocity solver problems
+!> \author Matthew Hoffman
+!> \date Summer 2018
+!> \details This routine finds and eliminates very small islands that lead to
+!> unrealistic velocities in the Albany velocity solver. Specifically, this
+!> finds one- and two-cell masses of ice that are surrounded by open ocean
+!> and eliminates them by sending them to the calving flux.
+!-----------------------------------------------------------------------
+
+ subroutine remove_small_islands(meshPool, geometryPool)
+ type (mpas_pool_type), pointer, intent(in) :: meshPool !< Input: Mesh pool
+ type (mpas_pool_type), pointer, intent(inout) :: geometryPool !< Input: Geometry pool
+
+ logical, pointer :: config_remove_small_islands
+ real(kind=RKIND), pointer :: config_sea_level
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness ! thickness of ice that calves (computed in this subroutine)
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: bedTopography
+ integer, dimension(:), pointer :: cellMask
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ integer, pointer :: nCellsSolve
+ integer :: iCell, jCell, n, nIceNeighbors, nIceNeighbors2, neighborWithIce
+ integer :: nOpenOceanNeighbors, nOpenOceanNeighbors2
+
+ call mpas_pool_get_config(liConfigs, 'config_remove_small_islands', config_remove_small_islands)
+ if (.not. config_remove_small_islands) then
+ return ! skip this entire routine if disabled
+ endif
+
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+
+ do iCell = 1, nCellsSolve
+ if (li_mask_is_ice(cellMask(iCell))) then ! might as well do for both grounded or floating
+ ! (1 or 2 cell floating masses are icebergs)
+ nIceNeighbors = 0
+ nOpenOceanNeighbors = 0
+ do n = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(n, iCell)
+ if (li_mask_is_ice(cellMask(jCell))) then
+ nIceNeighbors = nIceNeighbors + 1
+ neighborWithIce = jCell
+ endif
+ if (.not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level) then
+ nOpenOceanNeighbors = nOpenOceanNeighbors + 1
+ endif
+ enddo
+ if ((nIceNeighbors == 0) .and. (nOpenOceanNeighbors == nEdgesOnCell(iCell))) then
+ ! If this is a single cell of ice surrounded by open ocean, kill this location
+ calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell)
+ thickness(iCell) = 0.0_RKIND
+ elseif (nIceNeighbors == 1) then
+ ! check if this neighbor has any additional neighbors with ice
+ nIceNeighbors2 = 0
+ nOpenOceanNeighbors = 0
+ do n = 1, nEdgesOnCell(neighborWithIce)
+ jCell = cellsOnCell(n, neighborWithIce)
+ if (li_mask_is_ice(cellMask(jCell))) then
+ nIceNeighbors2 = nIceNeighbors2 + 1
+ endif
+ if (.not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level) then
+ nOpenOceanNeighbors2 = nOpenOceanNeighbors2 + 1
+ endif
+ enddo
+ if ((nIceNeighbors2 == 1) .and. (nOpenOceanNeighbors2 == nEdgesOnCell(iCell)-1)) then
+ ! <- only neighbor with ice must have been iCell
+ ! kill both cells
+ calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell)
+ thickness(iCell) = 0.0_RKIND
+ calvingThickness(neighborWithIce) = calvingThickness(neighborWithIce) + thickness(neighborWithIce)
+ thickness(neighborWithIce) = 0.0_RKIND
+ endif
+
+ endif ! check on nIceNeighbors
+
+ endif ! check if iCell has ice
+ end do ! loop over cells
+
+ end subroutine remove_small_islands
+
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
@@ -905,7 +1026,7 @@ subroutine topographic_calving(domain, calvingFraction, err)
! local variables
!-----------------------------------------------------------------
type (block_type), pointer :: block
- type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: geometryPool, meshPool
real (kind=RKIND), dimension(:), pointer :: calvingThickness ! thickness of ice that calves (computed in this subroutine)
real(kind=RKIND), pointer :: config_calving_topography
real(kind=RKIND), pointer :: config_sea_level
@@ -929,6 +1050,7 @@ subroutine topographic_calving(domain, calvingFraction, err)
! get pools
call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
@@ -943,6 +1065,8 @@ subroutine topographic_calving(domain, calvingFraction, err)
! === apply calving ===
thickness(:) = thickness(:) - calvingThickness(:)
+ call remove_small_islands(meshPool, geometryPool)
+
block => block % next
enddo
@@ -991,36 +1115,39 @@ subroutine eigencalving(domain, err)
real(kind=RKIND), pointer :: config_calving_eigencalving_parameter_scalar_value
character (len=StrKIND), pointer :: config_calving_eigencalving_parameter_source
logical, pointer :: config_print_calving_info
- real (kind=RKIND), pointer :: config_sea_level
real(kind=RKIND), pointer :: config_calving_thickness
- real (kind=RKIND), dimension(:), pointer :: thickness
- real (kind=RKIND), dimension(:), pointer :: bedTopography
real (kind=RKIND), dimension(:), pointer :: eigencalvingParameter
- real (kind=RKIND), dimension(:), pointer :: calvingThickness
- real (kind=RKIND), dimension(:), pointer :: requiredCalvingVolumeRate
real (kind=RKIND), dimension(:), pointer :: calvingVelocity
real (kind=RKIND), dimension(:), pointer :: eMax, eMin
+ real (kind=RKIND), dimension(:), pointer :: angleEdge
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
integer, dimension(:), pointer :: cellMask
- type (field1dInteger), pointer :: calvingFrontMaskField
integer, dimension(:), pointer :: calvingFrontMask
real (kind=RKIND), pointer :: deltat !< time step (s)
- integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
- integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
- integer, dimension(:,:), pointer :: edgesOnCell
real (kind=RKIND), dimension(:), pointer :: dvEdge
+ real (kind=RKIND), dimension(:), pointer :: areaCell
integer, pointer :: nCells
integer :: iCell, jCell, iNeighbor
- real(kind=RKIND) :: cellCalvingFrontLength, cellCalvingFrontHeight
logical :: dynamicNeighbor
+ real(kind=RKIND) :: calvingSubtotal
integer :: err_tmp
+ logical :: applyToGrounded, applyToFloating, applyToGroundingLine
err = 0
+ ! Logical arrays needed for apply_ablation_velocity
+ applyToGrounded = .true.
+ applyToFloating = .true.
+ applyToGroundingLine = .false.
+
call mpas_pool_get_config(liConfigs, 'config_print_calving_info', config_print_calving_info)
call mpas_pool_get_config(liConfigs, 'config_calving_eigencalving_parameter_scalar_value', &
config_calving_eigencalving_parameter_scalar_value)
- call mpas_pool_get_config(liConfigs, 'config_calving_eigencalving_parameter_source', config_calving_eigencalving_parameter_source)
- call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ call mpas_pool_get_config(liConfigs, 'config_calving_eigencalving_parameter_source', &
+ config_calving_eigencalving_parameter_source)
call mpas_pool_get_config(liConfigs, 'config_calving_thickness', config_calving_thickness)
! block loop
@@ -1033,26 +1160,24 @@ subroutine eigencalving(domain, err)
call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
- ! get fields
+ ! get dimensions
call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+
+ ! get fields
call mpas_pool_get_array(meshPool, 'deltat', deltat)
- call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
- call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
- call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
- call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge)
- call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(meshPool, 'angleEdge', angleEdge)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
- call mpas_pool_get_array(geometryPool, 'thickness', thickness)
- call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'calvingFrontMask', calvingFrontMask)
call mpas_pool_get_array(geometryPool, 'eigencalvingParameter', eigencalvingParameter)
- call mpas_pool_get_array(geometryPool, 'requiredCalvingVolumeRate', requiredCalvingVolumeRate)
call mpas_pool_get_array(geometryPool, 'calvingVelocity', calvingVelocity)
call mpas_pool_get_array(velocityPool, 'eMax', eMax)
call mpas_pool_get_array(velocityPool, 'eMin', eMin)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
- call mpas_pool_get_field(scratchPool, 'iceCellMask2', calvingFrontMaskField)
- call mpas_allocate_scratch_field(calvingFrontMaskField, .true.)
- calvingFrontMask => calvingFrontMaskField % array
! get parameter value
if (trim(config_calving_eigencalving_parameter_source) == 'scalar') then
@@ -1070,38 +1195,28 @@ subroutine eigencalving(domain, err)
realArgs=(/minval(eigencalvingParameter), maxval(eigencalvingParameter)/))
endif
- ! make mask for effective calving front.
- ! This is last dynamic cell, but also make sure it has a neighbor that is open ocean or thin floating ice.
- call calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask)
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
calvingVelocity(:) = 0.0_RKIND
- requiredCalvingVolumeRate(:) = 0.0_RKIND
! First calculate the front retreat rate (Levermann eq. 1)
- calvingVelocity(:) = eigencalvingParameter(:) * max(0.0_RKIND, eMax(:)) * max(0.0_RKIND, eMin(:)) & ! m/s
- * real(li_mask_is_floating_ice_int(cellMask(:)), kind=RKIND) ! calculate only for floating ice - map of "potential" calving rate
- do iCell = 1, nCells
- if (calvingFrontMask(iCell) == 1) then
-
- ! convert to a volume flux per cell masking some assumptions
- ! get front length from edge lengths abutting ocean or thin ice
- ! get front height from max thickness of neighbors (since thickness near the edge could be screwy)
- cellCalvingFrontLength = 0.0_RKIND
- cellCalvingFrontHeight = 0.0_RKIND
- do iNeighbor = 1, nEdgesOnCell(iCell)
- jCell = cellsOnCell(iNeighbor, iCell)
- if ( (li_mask_is_floating_ice(cellMask(jCell)) .and. .not. li_mask_is_dynamic_ice(cellMask(jCell))) .or. & ! thin ice
- (.not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level) ) then ! open ocean
- cellCalvingFrontLength = cellCalvingFrontLength + dvEdge(edgesOnCell(iNeighbor, iCell))
- endif
- cellCalvingFrontHeight = max(cellCalvingFrontHeight, thickness(jCell))
- enddo
-
- requiredCalvingVolumeRate(iCell) = calvingVelocity(iCell) * cellCalvingFrontLength * cellCalvingFrontHeight ! m^3/s
- endif
- enddo
-
- call distribute_calving_flux(meshPool, geometryPool, scratchPool, calvingFrontMask, err_tmp)
- err = ior(err, err_tmp)
+ calvingVelocity(:) = eigencalvingParameter(:) * max(0.0_RKIND, eMax(:)) * max(0.0_RKIND, eMin(:)) ! m/s
+
+ call mpas_log_write("calling li_apply_front_ablation_velocity from eigencalving")
+ ! Convert calvingVelocity to calvingThickness
+ call li_apply_front_ablation_velocity(meshPool, geometryPool, velocityPool, &
+ calvingThickness, calvingVelocity, applyToGrounded, &
+ applyToFloating, applyToGroundingLine, domain, err)
+ ! Update halos on calvingThickness or faceMeltingThickness before
+ ! applying it.
+ ! Testing seemed to indicate this is not necessary, but I don't
+ ! understand
+ ! why not, so leaving it.
+ ! NOTE: THIS WILL NOT WORK ON MULTIPLE BLOCKS PER PROCESSOR
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'calvingThickness')
+ call mpas_timer_stop("halo updates")
! === apply calving ===
thickness(:) = thickness(:) - calvingThickness(:)
@@ -1109,12 +1224,11 @@ subroutine eigencalving(domain, err)
! update mask
call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
err = ior(err, err_tmp)
- call calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask)
-
! Now also remove thin floating, dynamic ice (based on chosen thickness threshold) after mask is updated.
- !where ((li_mask_is_floating_ice(cellMask) .and. li_mask_is_dynamic_ice(cellMask) .and. thickness block % next
enddo
@@ -1160,31 +1280,26 @@ end subroutine eigencalving
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
-! routine distribute_calving_flux
+! routine specified_calving_velocity
!
-!> \brief Apply a specified calving flux along the calving front
+!> \brief use a specified calving velocity given by input data
!> \author Matthew Hoffman
!> \date Feb. 2018
-!> \details Applies a specified calving flux along the calving front.
-!> The calving volume needs to be distributed in three ways:
-!> 1. We need to first remove any "thin" ice in front of this cell
-!> 2. Then we remove ice from this cell
-!> 3. If there is still additional ice to be removed, we have to recursively
-!> remove ice "inland" of this cell until the total required mass is removed
+!> \details we can specify the calving velocity by i) a constant value
+!> given by config_calving_velocity_const in namelist and ii) source data
+!> specified by calvingVelocityData
!-----------------------------------------------------------------------
- subroutine distribute_calving_flux(meshPool, geometryPool, scratchPool, calvingFrontMask, err)
+ subroutine specified_calving_velocity(domain, err)
!-----------------------------------------------------------------
! input variables
!-----------------------------------------------------------------
- type (mpas_pool_type), pointer, intent(in) :: meshPool !< Input: Mesh pool
- type (mpas_pool_type), pointer, intent(in) :: scratchPool !< Input: scratch pool
- integer, dimension(:), intent(in) :: calvingFrontMask
!-----------------------------------------------------------------
! input/output variables
!-----------------------------------------------------------------
- type (mpas_pool_type), pointer, intent(inout) :: geometryPool !< Input: geometry pool
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
!-----------------------------------------------------------------
! output variables
@@ -1194,164 +1309,1879 @@ subroutine distribute_calving_flux(meshPool, geometryPool, scratchPool, calvingF
!-----------------------------------------------------------------
! local variables
!-----------------------------------------------------------------
-! logical, pointer :: config_print_calving_info
- real (kind=RKIND), dimension(:), pointer :: requiredCalvingVolumeRate !< Input: the specified calving flux at calving front margin cells
- real (kind=RKIND), dimension(:), pointer :: calvingThickness !< Output: the applied calving rate as a thickness
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: velocityPool
+ type (mpas_pool_type), pointer :: scratchPool
+ logical, pointer :: config_print_calving_info
+ real(kind=RKIND), pointer :: config_calving_thickness
+ real(kind=RKIND), pointer :: config_calving_velocity_const
+ character (len=StrKIND), pointer :: config_calving_specified_source
+ real (kind=RKIND), dimension(:), pointer :: calvingVelocity
+ real (kind=RKIND), dimension(:), pointer :: calvingVelocityData
+ real (kind=RKIND), dimension(:), pointer :: angleEdge
real (kind=RKIND), dimension(:), pointer :: thickness
- real (kind=RKIND), dimension(:), pointer :: areaCell
- integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness
integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
integer, dimension(:), pointer :: cellMask
+ integer, dimension(:), pointer :: calvingFrontMask
real (kind=RKIND), pointer :: deltat !< time step (s)
+ real (kind=RKIND), dimension(:), pointer :: dvEdge
+ real (kind=RKIND), dimension(:), pointer :: areaCell
integer, pointer :: nCells
- integer :: iCell, iNeighbor, jCell
- real(kind=RKIND) :: volumeLeft
- real(kind=RKIND) :: removeVolumeHere
- type (field1dReal), pointer :: cellVolumeField
- real(kind=RKIND), dimension(:), pointer :: cellVolume
- real(kind=RKIND), dimension(:), pointer :: uncalvedVolume
- integer :: inwardNeighbors
- integer :: uncalvedCount
- real(kind=RKIND) :: uncalvedTotal
+ integer :: iCell, jCell, iNeighbor
+ logical :: dynamicNeighbor
+ real(kind=RKIND) :: calvingSubtotal
+ integer :: err_tmp
err = 0
- ! get fields
- call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
- call mpas_pool_get_array(meshPool, 'deltat', deltat)
- call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
- call mpas_pool_get_array(geometryPool, 'thickness', thickness)
- call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
- call mpas_pool_get_array(geometryPool, 'requiredCalvingVolumeRate', requiredCalvingVolumeRate)
- call mpas_pool_get_array(geometryPool, 'uncalvedVolume', uncalvedVolume)
- call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
- call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
- call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_config(liConfigs, 'config_print_calving_info', config_print_calving_info)
+ call mpas_pool_get_config(liConfigs, 'config_calving_thickness', config_calving_thickness)
+ call mpas_pool_get_config(liConfigs, 'config_calving_velocity_const', config_calving_velocity_const)
+ call mpas_pool_get_config(liConfigs, 'config_calving_specified_source', config_calving_specified_source)
- call mpas_pool_get_field(scratchPool, 'workCell', cellVolumeField)
- call mpas_allocate_scratch_field(cellVolumeField, .true.)
- cellVolume => cellVolumeField % array
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
- calvingThickness(:) = 0.0_RKIND
- uncalvedVolume(:) = 0.0_RKIND
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
- cellVolume(:) = areaCell(:) * thickness(:)
+ ! get dimensions
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
- ! The calving volume needs to be distributed in three ways:
- ! 1. We need to first remove any "thin" ice in front of this cell
- ! 2. Then we remove ice from this cell
- ! 3. If there is still additional ice to be removed, we have to recursively
- ! remove ice "inland" of this cell until the total required mass is removed
- do iCell = 1, nCells
- if (calvingFrontMask(iCell) == 1) then
- volumeLeft = requiredCalvingVolumeRate(iCell) * deltat ! units m^3
+ ! get fields
+ call mpas_pool_get_array(meshPool, 'deltat', deltat)
+ call mpas_pool_get_array(meshPool, 'angleEdge', angleEdge)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'calvingFrontMask', calvingFrontMask)
+ call mpas_pool_get_array(geometryPool, 'calvingVelocity', calvingVelocity)
+ call mpas_pool_get_array(geometryPool, 'calvingVelocityData', calvingVelocityData)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
- ! First remove ice from "thin" neighbors
- do iNeighbor = 1, nEdgesOnCell(iCell)
- jCell = cellsOnCell(iNeighbor, iCell)
- if (li_mask_is_floating_ice(cellMask(jCell)) .and. .not. li_mask_is_dynamic_ice(cellMask(jCell))) then
- ! this is a thin neighbor - remove as much ice from here as we can TODO: could distribute this evenly amongst neighbors
- removeVolumeHere = min(volumeLeft, cellVolume(jCell)) ! how much we want to remove here
- calvingThickness(jCell) = calvingThickness(jCell) + removeVolumeHere / areaCell(jCell) ! apply to the field that will be used, in thickness units
- cellVolume(jCell) = cellVolume(jCell) - removeVolumeHere ! update accounting on cell volume
- volumeLeft = volumeLeft - removeVolumeHere ! update accounting on how much left to distribute from current iCell
- endif
- enddo
- if (volumeLeft > 0.0_RKIND) then
- ! Now remove ice from iCell
- removeVolumeHere = min(volumeLeft, cellVolume(iCell))
- calvingThickness(iCell) = calvingThickness(iCell) + removeVolumeHere / areaCell(iCell) ! apply to the field that will be used in thickness units
- cellVolume(iCell) = cellVolume(iCell) - removeVolumeHere ! update accounting on cell volume
- volumeLeft = volumeLeft - removeVolumeHere ! update accounting on how much left to distribute from current iCell
- endif
+ ! get parameter value
+ if (trim(config_calving_specified_source) == 'const') then
+ calvingVelocity = config_calving_velocity_const
+ elseif (trim(config_calving_specified_source) == 'data') then
+ calvingVelocity = calvingVelocityData
+ else
+ err = ior(err, 1)
+ call mpas_log_write("Invalid value specified for option config_calving_specified_source" // &
+ config_calving_specified_source, MPAS_LOG_ERR)
+ endif
- if (volumeLeft > 0.0_RKIND) then
- ! Now remove ice from neighbors inward on shelf
- ! first count up how many there are
- inwardNeighbors = 0
- do iNeighbor = 1, nEdgesOnCell(iCell)
- jCell = cellsOnCell(iNeighbor, iCell)
- if (li_mask_is_floating_ice(cellMask(jCell)) .and. li_mask_is_dynamic_ice(cellMask(jCell)) &
- .and. (.not. li_mask_is_dynamic_margin(jCell))) then
- inwardNeighbors = inwardNeighbors + 1
- endif
- enddo
- ! Now distribute the flux evenly amongst the neighbors
- do iNeighbor = 1, nEdgesOnCell(iCell)
- jCell = cellsOnCell(iNeighbor, iCell)
- if (li_mask_is_floating_ice(cellMask(jCell)) .and. li_mask_is_dynamic_ice(cellMask(jCell)) &
- .and. (.not. li_mask_is_dynamic_margin(jCell))) then
- ! this is thick neighbor that is not itself a margin - remove as much ice from here as we can
- removeVolumeHere = min(volumeLeft / real(inwardNeighbors, kind=RKIND), cellVolume(jCell)) ! how much we want to remove here
- calvingThickness(jCell) = calvingThickness(jCell) + removeVolumeHere / areaCell(jCell) ! apply to the field that will be used in thickness units
- cellVolume(jCell) = cellVolume(jCell) - removeVolumeHere ! update accounting on cell volume
- volumeLeft = volumeLeft - removeVolumeHere ! update accounting on how much left to distribute from current iCell
- endif
- enddo
- !TODO: need to recursively distribute across neighbors until fully depleted :(
- endif
+ if (config_print_calving_info) then
+ call mpas_log_write("calvingVelocity(m s) value range on this processor: Min=$r, Max=$r", &
+ realArgs=(/minval(calvingVelocity), maxval(calvingVelocity)/))
+ endif
- ! If we didn't calve enough ice, record that to allow assessment of how bad that is.
- if (volumeLeft > 0.0_RKIND) then
- uncalvedVolume(iCell) = 0.0_RKIND
- endif
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
- endif ! if cell is calving margin
- enddo ! cell loop
+ ! Convert calvingVelocity to calvingThickness
+ call li_apply_front_ablation_velocity(meshPool, geometryPool, velocityPool, calvingThickness, calvingVelocity, &
+ applyToGrounded=.true., applyToFloating=.true., applyToGroundingLine=.false., &
+ domain=domain, err=err_tmp)
+ err = ior(err, err_tmp)
- if (maxval(uncalvedVolume) > 0.0_RKIND) then
+ ! === apply calving ===
+ thickness(:) = thickness(:) - calvingThickness(:)
+
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
- uncalvedTotal = sum(uncalvedVolume)
- uncalvedCount = count(uncalvedVolume > 0.0_RKIND)
+ ! Now also remove thin floating, dynamic ice (based on chosen thickness threshold) after mask is updated.
- call mpas_log_write("distribute_calving_flux failed to distribute all required ice - ice was left after depleting all neighbors." &
- // " Search needs to be expanded to neighbors' neighbors.")
- call mpas_log_write(" On this processor: $i cells contain uncalved ice, for a total uncalved volume of $r m^3 ($r%).", &
- MPAS_LOG_WARN, intArgs=(/uncalvedCount/), &
- realArgs=(/uncalvedTotal, 100.0_RKIND * uncalvedTotal/(requiredCalvingVolumeRate(iCell) * deltat)/))
- endif
+ !where ((li_mask_is_floating_ice(cellMask) .and. li_mask_is_dynamic_ice(cellMask) .and. &
+ ! thickness block % next
+ enddo
- end subroutine distribute_calving_flux
+ end subroutine specified_calving_velocity
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
-! routine calculate_calving_front_mask
+! routine von_Mises_calving
!
-!> \brief Calculate mask indicating position of effective calving front
-!> \author Matthew Hoffman
-!> \date Feb. 2018
-!> \details Mmake mask for effective calving front.
-!> This is last dynamic floating cell, but also make sure it has a neighbor that is open ocean or thin floating ice.
+!> \brief Apply calving law based on von Mises stress to grounded marine margins
+!> \author Trevor Hillebrand
+!> \date April 2020
+!> \details Uses the calving law described by Morlighem et al. (2016):
+!> "Modeling of Store Gletscher’s calving dynamics, West Greenland, in response
+!> to ocean thermal forcing" to calculate calvingVelocity at grounded tidewater
+!glacier margins
!-----------------------------------------------------------------------
- subroutine calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask)
+ subroutine von_Mises_calving(domain, err)
+
+ use li_diagnostic_vars
!-----------------------------------------------------------------
! input variables
!-----------------------------------------------------------------
- type (mpas_pool_type), intent(in) :: meshPool !< Input: Mesh pool
- type (mpas_pool_type), intent(in) :: geometryPool !< Input: geometry pool
!-----------------------------------------------------------------
! input/output variables
!-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
!-----------------------------------------------------------------
! output variables
!-----------------------------------------------------------------
- integer, dimension(:) :: calvingFrontMask !< Output: calving front mask
+ integer, intent(out) :: err !< Output: error flag
!-----------------------------------------------------------------
! local variables
!-----------------------------------------------------------------
+ integer :: iCell, jCell, iNeighbor, nGroundedNeighbors, err_tmp
+ integer, dimension(:), pointer :: nEdgesOnCell
+ integer, dimension(:,:), pointer :: cellsOnCell
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool, meshPool, &
+ velocityPool, scratchPool, thermalPool
+ real (kind=RKIND), pointer :: config_grounded_von_Mises_threshold_stress, &
+ config_floating_von_Mises_threshold_stress, &
+ config_flowLawExponent
+ logical, pointer :: config_use_Albany_flowA_eqn_for_vM
+ real (kind=RKIND), dimension(:), pointer :: eMax, eMin, &
+ calvingVelocity, thickness, &
+ xvelmean, yvelmean, calvingThickness
+ real (kind=RKIND), dimension(:,:), pointer :: flowParamA, &
+ temperature, layerThickness
+ real (kind=RKIND), pointer :: config_default_flowParamA
integer, pointer :: nCells
- integer :: iCell, iNeighbor, jCell, jNeighbor, kCell
- logical :: oceanNeighbor
- integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ integer, dimension(:), pointer :: cellMask
+ real (kind=RKIND), dimension(:), pointer :: vonMisesStress
+ logical :: applyToGrounded, applyToFloating, applyToGroundingLine
+
+ err = 0
+
+ ! Logical arrays needed for li_apply_front_ablation_velocity
+ applyToGrounded = .true.
+ applyToFloating = .true.
+ applyToGroundingLine = .false.
+
+ call mpas_pool_get_config(liConfigs, 'config_grounded_von_Mises_threshold_stress', &
+ config_grounded_von_Mises_threshold_stress)
+ call mpas_pool_get_config(liConfigs, 'config_floating_von_Mises_threshold_stress', &
+ config_floating_von_Mises_threshold_stress)
+
+ if ( config_grounded_von_Mises_threshold_stress <= 0.0_RKIND ) then
+ call mpas_log_write("config_grounded_von_Mises_threshold_stress must be >0.0", MPAS_LOG_ERR)
+ err = 1
+ endif
+ !call mpas_pool_get_config(liConfigs, 'config_default_flowParamA',
+ !config_default_flowParamA) ! REMOVE THIS ONCE YOU CAN GET A FROM
+ !ALBANY!!!!!
+ call mpas_pool_get_config(liConfigs, 'config_flowLawExponent', config_flowLawExponent)
+ call mpas_pool_get_config(liConfigs, 'config_use_Albany_flowA_eqn_for_vM', config_use_Albany_flowA_eqn_for_vM)
+
+ block => domain % blocklist
+
+ do while (associated(block))
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
+ call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
+ ! get fields
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'layerThickness', layerThickness)
+ call mpas_pool_get_array(velocityPool, 'eMax', eMax)
+ call mpas_pool_get_array(velocityPool, 'eMin', eMin)
+ call mpas_pool_get_array(velocityPool, 'vonMisesStress', vonMisesStress)
+ call mpas_pool_get_array(velocityPool, 'flowParamA', flowParamA)
+ call mpas_pool_get_array(velocityPool, 'xvelmean', xvelmean)
+ call mpas_pool_get_array(velocityPool, 'yvelmean', yvelmean)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'calvingVelocity', calvingVelocity)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(thermalPool, 'temperature', temperature)
+
+ vonMisesStress(:) = 0.0_RKIND
+
+ ! get flowParamA from MPAS or use Albany-like equation
+ if ( config_use_Albany_flowA_eqn_for_vM ) then
+ !calculate Albany-type flowParamA
+ call mpas_log_write("config_use_Albany_flowA_eqn_for_vM not yet supported", MPAS_LOG_ERR)
+ err = 1
+ else
+ call li_calculate_flowParamA(meshPool, temperature, thickness,flowParamA,err) ! Get MPAS flowParamA
+ endif
+
+ !Using a depth-averaged ice viscosity parameter B_depthAvg
+ !=sum(layerThickness(:,iCell) *
+ !flowParamA(:,iCell)**(-1.0_RKIND/config_flowLawExponent), dim=1) /
+ !thickness(iCell)
+ ! Calculate effective von Mises stress.
+ calvingVelocity(:) = 0.0_RKIND
+
+ do iCell = 1,nCells
+ if ( thickness(iCell) > 0.0_RKIND ) then
+ vonMisesStress(iCell) = sqrt(3.0_RKIND) * sum(layerThickness(:,iCell) * &
+ flowParamA(:,iCell)**(-1.0_RKIND/config_flowLawExponent),dim=1) / &
+ thickness(iCell) * ( 0.5_RKIND * ( (max(0.0_RKIND, eMax(iCell)))**2.0_RKIND + &
+ (max(0.0_RKIND, eMin(iCell)))**2.0_RKIND) )**(1.0_RKIND / (2.0_RKIND * config_flowLawExponent))
+ endif
+
+ ! Calculate calving velocity for grounded cells at marine margin
+ if ( .not. li_mask_is_floating_ice(cellMask(iCell)) ) then
+ calvingVelocity(iCell) = sqrt(xvelmean(iCell)**2.0_RKIND + yvelmean(iCell)**2.0_RKIND) * &
+ vonMisesStress(iCell) / config_grounded_von_Mises_threshold_stress
+ ! If config_floating_von_Mises_threshold_stress is not 0.0, calculate
+ ! calvingVelocity. If config_floating_von_Mises_threshold_stress is
+ ! 0.0, remove floating ice in loop below.
+ elseif (li_mask_is_floating_ice(cellMask(iCell)) .and. config_floating_von_Mises_threshold_stress .ne. 0.0_RKIND) then
+ calvingVelocity(iCell) = sqrt(xvelmean(iCell)**2 + yvelmean(iCell)**2) * &
+ vonMisesStress(iCell) / config_floating_von_Mises_threshold_stress
+ endif
+ enddo
+
+ call mpas_log_write("calling li_apply_front_ablation_velocity from von Mises stress calving routine")
+ ! Convert calvingVelocity to calvingThickness
+ call li_apply_front_ablation_velocity(meshPool, geometryPool,velocityPool, &
+ calvingThickness, calvingVelocity, applyToGrounded, &
+ applyToFloating, applyToGroundingLine, domain, err)
+ ! Update halos on calvingThickness or faceMeltingThickness before
+ ! applying it.
+ ! Testing seemed to indicate this is not necessary, but I don't
+ ! understand
+ ! why not, so leaving it.
+ ! NOTE: THIS WILL NOT WORK ON MULTIPLE BLOCKS PER PROCESSOR
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'calvingThickness')
+ call mpas_timer_stop("halo updates")
+
+ ! If floating VM threshold is zero, remove floating ice. Remove
+ ! non-dynamic cells adjacent to floating ice, but leave
+ ! non-dynamic cells adjacent to grounded ice.
+ ! TODO: Make an exception for the case of floating ice surrounded by grounded ice
+ ! (i.e., floating on a subglacial lake) using a flood fill routine
+ if ( config_floating_von_Mises_threshold_stress .eq. 0.0_RKIND ) then
+ do iCell = 1,nCells
+ if ( li_mask_is_floating_ice(cellMask(iCell)) .and. &
+ li_mask_is_dynamic_ice(cellMask(iCell)) ) then
+ calvingThickness(iCell) = thickness(iCell)
+ elseif ( li_mask_is_floating_ice(cellMask(icell)) .and. &
+ (.not. li_mask_is_dynamic_ice(cellMask(iCell))) ) then
+ nGroundedNeighbors = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if ( li_mask_is_grounded_ice(cellMask(jCell)) ) then
+ nGroundedNeighbors = nGroundedNeighbors + 1
+ endif
+ enddo
+ if ( nGroundedNeighbors == 0 ) then
+ calvingThickness(iCell) = thickness(iCell)
+ endif
+ endif
+ enddo
+ endif
+
+
+ ! === apply calving ===
+ thickness(:) = thickness(:) - calvingThickness(:)
+
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ call remove_small_islands(meshPool, geometryPool)
+
+ block => block % next
+
+ enddo ! associated(block)
+
+ end subroutine von_Mises_calving
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine li_apply_front_ablation_velocity
+!
+!> \brief Convert a calving or melting velocity to an ice thickness removal
+!> \author Matthew Hoffman and Trevor Hillebrand
+!> \date March 2020
+!> \details This routine takes a calving or front melting velocity and converts it to a
+!> thickness removal. The basic idea is to multiply the calving velocity
+!> by the edge length and height to get a volume flux. However, the details
+!> are complicated by the unstructured Voronoi mesh and the use of partially-filled
+!> non-dynamic floating grid cells.
+!> The algorithm calculates the required calving volume flux based on edges, and then
+!> applies the volume removal to grid cells, converting that to a thickness removal using areaCell.
+!> This process occurs in phases.
+!>
+!> The first phase handles non-dynamic floating cells. This is done by calculating the required calving flux
+!> at the edges between those non-dynamic floating cells and the open ocean.
+!> The calving velocity and ice thickness are copied from the upstream dynamic
+!> floating cells, because these quantities do not have valid values on the non-dynamic cells.
+!> After calculating the calving flux determined at each of these edges, the non-dyamic floating cells
+!> are looped over, and volume is marked for removal based on the calving flux on the edges of each cell.
+!>
+!> The final phase handles dynamic floating cells that are eligible for calving.
+!> There are two ways this can happen - either they are adjacent to the open ocean (no buffer of
+!> non-dynamic cells present), or they are adjacent to non-dynamic floating cells that had their
+!> entire volume removed by calving, but there still is calving demand remaining.
+!> The first case is handled easily by calculating calving flux on edges between dynamic floating cells
+!> and open ocean using the calving velocity and ice thickness of the dynamic cell itself.
+!> In the second case, "leftover" required calving flux is distributed from a non-dynamic cell that
+!> has been completely "drained" to any edges between that non-dynamic cell and dynamic cells upstream.
+!> This is done by weighting the flux to be distrbuted by the length of each such edge in the direction
+!> perpendicular to the calving flux.
+!>
+!> The location at which ablation is controlled by applyToGrounded, applyToFloating, and applyToGroundingLine,
+!> which are set by the calling routine.
+!> If applyToGrounded = .true., ablation is applied to grounded marine margin cells, which do not have dynamic ice shelf neighbors
+!> If applyToGroundingLine = .true., ablation is applied to grounding line, regardless of whether there is an ice shelf or not.
+!> If there in dynamic floating ice, ablation is applied to the floating cell adjacent to grounding line;
+!> otherwise it is applied to the last grounded cell.
+!> If applyToFloating = .true., ablation is applied to dynamic floating margin cells
+!> The output of this routine is calvingThickness or faceMeltingThickness, which then needs to be applied to thickness
+!> by the calling routine. The calling routine should perform a halo update
+!> after the call and before applying ablation.
+!-----------------------------------------------------------------------
+
+ subroutine li_apply_front_ablation_velocity(meshPool, geometryPool, velocityPool, ablationThickness, ablationVelocity, &
+ applyToGrounded, applyToFloating, applyToGroundingLine, domain, err)
+
+ use ieee_arithmetic, only : ieee_is_nan
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), pointer, intent(in) :: meshPool !< Input: Mesh pool
+ type (mpas_pool_type), pointer, intent(in) :: velocityPool !< Input: velocity pool
+ logical, intent(in) :: applyToFloating, applyToGrounded, &
+ applyToGroundingLine
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: domain !< Input: domain object
+ type (mpas_pool_type), pointer, intent(inout) :: geometryPool !< Input: geometry pool
+ real (kind=RKIND), dimension(:), intent(inout) :: ablationVelocity
+ real (kind=RKIND), dimension(:), intent(out) :: ablationThickness
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ integer, pointer :: nEdges, nCells, nCellsSolve, maxEdges
+ integer :: iEdge, iCell, jCell, kCell, iNeighbor, jNeighbor
+ integer :: nEmptyNeighbors, nGroundedNeighbors, counter, nTwoCellsBack, nOneCellBack
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: bedTopography
+ real (kind=RKIND), dimension(:), pointer :: lowerSurface
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:,:), pointer :: edgesOnCell
+ integer, dimension(:), pointer :: cellMask, edgeMask
+ integer, dimension(:), pointer :: frontAblationMask
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness, faceMeltingThickness
+ real (kind=RKIND), pointer :: config_sea_level
+ real (kind=RKIND), dimension(:), pointer :: dvEdge
+ real (kind=RKIND), dimension(:), pointer :: angleEdge
+ real (kind=RKIND), dimension(:), pointer :: calvingVelocity, faceMeltSpeed
+ real (kind=RKIND), dimension(:), pointer :: areaCell
+ real (kind=RKIND), dimension(:,:), pointer :: uReconstructX
+ real (kind=RKIND), dimension(:,:), pointer :: uReconstructY
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ real (kind=RKIND), pointer :: deltat !< time step (s)
+ real (kind=RKIND), dimension(:), allocatable :: thicknessForAblation
+ real (kind=RKIND), dimension(:), allocatable :: uvelForAblation, vvelForAblation
+ integer, dimension(:), allocatable :: oneCellBackList, twoCellsBackList
+ real (kind=RKIND), dimension(:), pointer :: requiredAblationVolumeNonDynEdge, requiredAblationVolumeNonDynCell
+ real (kind=RKIND), dimension(:), pointer :: requiredAblationVolumeDynEdge, requiredAblationVolumeDynCell
+ real (kind=RKIND), dimension(:), pointer :: ablatedVolumeNonDynCell, ablatedVolumeDynCell
+ real (kind=RKIND), dimension(:), pointer :: unablatedVolumeNonDynCell, unablatedVolumeDynCell
+ real (kind=RKIND), dimension(:), allocatable :: cellVolume
+ real(kind=RKIND) :: ablationSubtotal1, ablationSubtotal2, ablationSubtotal3
+ real(kind=RKIND) :: thkSum, ablationVelSum, uvelSum, vvelSum
+ integer :: thkCount
+ real(kind=RKIND) :: removeVolumeHere
+ real(kind=RKIND) :: volumeAvailableToPass !< a temp. var. for accounting purposes that indicates how much volume
+ !< to be calved is 'leftover' after trying to calve non-dynamic cells and can be transferred to
+ !< neighboring dynamic cells
+ real(kind=RKIND) :: ablateLengthCell, ablateLengthEdge
+ real(kind=RKIND), dimension(6) :: localInfo, globalInfo
+ real(kind=RKIND) :: edgeLengthScaling
+ real(kind=RKIND), parameter :: ablationSmallThk = 1.0e-8_RKIND ! in meters, a small thickness threshold
+ integer :: err_tmp
+
+ err = 0
+ err_tmp = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
+ call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge)
+ call mpas_pool_get_array(meshPool, 'angleEdge', angleEdge)
+ call mpas_pool_get_dimension(meshPool, 'nEdges', nEdges)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_dimension(meshPool, 'maxEdges', maxEdges)
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_array(velocityPool, 'uReconstructX', uReconstructX)
+ call mpas_pool_get_array(velocityPool, 'uReconstructY', uReconstructY)
+ call mpas_pool_get_array(geometryPool, 'calvingVelocity', calvingVelocity)
+ call mpas_pool_get_array(geometryPool, 'faceMeltSpeed', faceMeltSpeed)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'faceMeltingThickness', faceMeltingThickness)
+ call mpas_pool_get_array(geometryPool, 'unablatedVolumeNonDynCell', unablatedVolumeNonDynCell)
+ call mpas_pool_get_array(geometryPool, 'unablatedVolumeDynCell', unablatedVolumeDynCell)
+ call mpas_pool_get_array(geometryPool, 'ablatedVolumeNonDynCell', ablatedVolumeNonDynCell)
+ call mpas_pool_get_array(geometryPool, 'ablatedVolumeDynCell', ablatedVolumeDynCell)
+ call mpas_pool_get_array(geometryPool, 'frontAblationMask', frontAblationMask)
+ call mpas_pool_get_array(geometryPool, 'requiredAblationVolumeNonDynEdge', requiredAblationVolumeNonDynEdge)
+ call mpas_pool_get_array(geometryPool, 'requiredAblationVolumeDynEdge', requiredAblationVolumeDynEdge)
+ call mpas_pool_get_array(geometryPool, 'requiredAblationVolumeNonDynCell', requiredAblationVolumeNonDynCell)
+ call mpas_pool_get_array(geometryPool, 'requiredAblationVolumeDynCell', requiredAblationVolumeDynCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_array(meshPool, 'deltat', deltat)
+
+
+ ! Step 0: Define the frontAblationMask that will be used to determine where ablation should be applied.
+ ! This mask can be for 1. a floating calving front, 2. a grounded marine margin (no dynamic floating ice shelf attached),
+ ! 3. along the grounding line (whether or not there is floating ice adjacent), or any combination of the three.
+ ! The mask includes both the dynamic AND non-dynamic cells along the prescribed interface type(s).
+ frontAblationMask(:) = 0
+
+ ! First identify the dynamic cells for each mask type.
+
+ if ( applyToGrounded .or. applyToGroundingLine ) then
+ do iCell = 1, nCells
+ ! If applyToGrounded: Define marine marginal cells as those that are (1) at the ice
+ ! margin, (2) have at least one neighboring cell without ice, (3) contain
+ ! grounded ice, and (4) have bed topography below sea level.
+ ! OR is adjacent to an inactive floating margin cell
+ if (li_mask_is_grounding_line(cellMask(iCell)) &
+ !< GL here means cell is grounded but has a neighbor that is floating or ocean
+ .and. bedTopography(iCell) < config_sea_level &
+ .and. li_mask_is_dynamic_ice(cellMask(iCell)) ) then
+
+ ! Check if neighboring cells contain ice and have bed topo below sea level
+ nEmptyNeighbors = 0
+ do iEdge = 1, nEdgesOnCell(iCell)
+ iNeighbor = cellsOnCell(iEdge, iCell)
+ if ( (((thickness(iNeighbor) == 0.0_RKIND) .and. bedTopography(iNeighbor) < config_sea_level)) &
+ !< these previous conditions are open ocean
+ .or. &
+ !> these following conditions are inactive floating margin cells
+ ((li_mask_is_floating_ice(cellMask(iNeighbor)) &
+ .and. li_mask_is_margin(cellMask(iNeighbor)) &
+ .and. (.not. li_mask_is_dynamic_ice(cellMask(iNeighbor)))))) then
+ nEmptyNeighbors = nEmptyNeighbors + 1
+ endif
+ enddo
+ if (nEmptyNeighbors > 0) then
+ frontAblationMask(iCell) = 1
+ endif ! nEmptyNeighbors
+ endif ! cell is GL etc.
+ enddo ! nCells loop
+ endif ! applyToGrounded
+
+ if ( applyToGroundingLine ) then
+ ! If applyToGroundingLine: Define marine marginal cells as those that
+ ! are at the margin (defined by li_mask_is_grounding_line) if no
+ ! floating ice or are the first floating cell if there is floating ice.
+ ! The case of no floating ice was handled above already, so only looking for
+ ! GL locations with floating ice here.
+ do iCell = 1,nCells
+ if ( li_mask_is_grounding_line(cellMask(iCell)) ) then
+ do iEdge = 1, nEdgesOnCell(iCell)
+ iNeighbor = cellsOnCell(iEdge, iCell)
+ if (li_mask_is_floating_ice(cellMask(iNeighbor)) .and. li_mask_is_dynamic_ice(cellMask(iNeighbor))) then
+ frontAblationMask(iNeighbor) = 1
+ endif
+ enddo
+ endif
+ enddo
+ endif
+
+ if ( applyToFloating ) then
+ do iCell = 1,nCells
+ ! If applyToFloating: marine marginal cells are dynamic floating margin cells
+ if ( li_mask_is_floating_ice(cellMask(iCell)) .and. &
+ li_mask_is_dynamic_margin(cellMask(iCell)) ) then
+ frontAblationMask(iCell) = 1
+ endif
+ enddo
+ endif
+
+ ! Now extend the mask forward to include non-dynamic floating neighbors (appropriate for any of the mask types)
+ ! Use value 2 to indicate the non-dynamic cells
+ do iCell = 1,nCells
+ if (frontAblationMask(iCell) == 1) then
+ do iEdge = 1, nEdgesOnCell(iCell)
+ iNeighbor = cellsOnCell(iEdge, iCell)
+ if ( li_mask_is_floating_ice(cellMask(iNeighbor)) .and. &
+ .not. li_mask_is_dynamic_ice(cellMask(iNeighbor)) ) then
+ frontAblationMask(iNeighbor) = 2 ! Use 2 for these non-dynamic floating neighbors
+ endif
+ enddo
+ endif
+ enddo
+ ! Make a second pass to include potentially 'stranded' nondynamic floating cells
+ do iCell = 1, nCells
+ if (frontAblationMask(iCell) == 2) then
+ ! Check if this non-dynamic masked cell has any non-dynamic, floating, but unmasked neighbors we need to include
+ do iEdge = 1, nEdgesOnCell(iCell)
+ iNeighbor = cellsOnCell(iEdge, iCell)
+ if ((.not. li_mask_is_dynamic_ice(cellMask(iNeighbor))) .and. li_mask_is_floating_ice(cellMask(iNeighbor)) &
+ .and. frontAblationMask(iNeighbor) == 0) then
+ frontAblationMask(iNeighbor) = 3 ! Use 3 for these extended non-dynamic neighbors
+ endif
+ enddo
+ endif
+ enddo
+
+ ! Init fields for accounting
+ ablationThickness(:) = 0.0_RKIND
+ ablatedVolumeNonDynCell(:) = 0.0_RKIND
+ ablatedVolumeDynCell(:) = 0.0_RKIND
+ unablatedVolumeNonDynCell(:) = 0.0_RKIND
+ unablatedVolumeDynCell(:) = 0.0_RKIND
+ allocate(cellVolume(nCells+1))
+ cellVolume(:) = areaCell(:) * thickness(:)
+ requiredAblationVolumeNonDynEdge(:) = 0.0_RKIND
+ requiredAblationVolumeNonDynCell(:) = 0.0_RKIND
+ requiredAblationVolumeDynEdge(:) = 0.0_RKIND
+ requiredAblationVolumeDynCell(:) = 0.0_RKIND
+ allocate(thicknessForAblation(nCells+1))
+ thicknessForAblation = thickness
+ allocate(uvelForAblation(nCells+1))
+ uvelForAblation(:) = uReconstructX(1,:)
+ allocate(vvelForAblation(nCells+1))
+ vvelForAblation(:) = uReconstructY(1,:)
+ allocate(oneCellBackList(maxEdges+1))
+ oneCellBackList(:) = 0
+ allocate(twoCellsBackList((maxEdges+1)**2))
+ twoCellsBackList(:) = 0
+
+ ! 1. Calculate ablation rate for all non-dynamic cells by working with their ocean-going edges
+ ablationSubtotal1 = 0.0_RKIND
+ do iCell = 1, nCells
+ if ((frontAblationMask(iCell)>0) .and. (.not. li_mask_is_dynamic_ice(cellMask(iCell))) ) then
+ ! a1. Translate the calving front height based on dynamic cells to the non-dynamic locations
+ ! find mean (or min?) of thickness in dynamic neighbors
+ ablationVelSum = 0.0_RKIND
+ thkSum = 0.0_RKIND
+ uvelSum = 0.0_RKIND
+ vvelSum = 0.0_RKIND
+ thkCount = 0
+ nGroundedNeighbors = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if ( li_mask_is_dynamic_ice(cellMask(jCell)) .and. li_mask_is_floating_ice(cellMask(jCell)) ) then
+ thkSum = thkSum + thicknessForAblation(jCell)
+ uvelSum = uvelSum + uvelForAblation(jCell)
+ vvelSum = vvelSum + vvelforAblation(jCell)
+ ablationVelSum = ablationVelSum + ablationVelocity(jCell)
+ thkCount = thkCount + 1
+ else if ( li_mask_is_grounding_line(cellMask(jCell)) .or. li_mask_is_grounded_ice(cellMask(jCell)) ) then
+ nGroundedNeighbors = nGroundedNeighbors + 1
+ endif
+ enddo
+
+ ! if floating non-dynamic cell has *any* grounded neighbors, use ice thickness and
+ ! velocity from two cells back instead of the one-cell-back (neighboring) locations above
+ ! Note the two-cell back averaging is independent of whether those locations
+ ! are floating are grounded.
+ ! The method implemented here gives good results for Humboldt Glacier (realistic grounded margin),
+ ! but as of 3/16/21 it has not been tested at a realistic case that contains both grounded and floating
+ ! margins (e.g. an ice shelf in an embayment with grounded ice along the lateral margins). If unexpected
+ ! behavior occurs in such a case in the future, an alternative implementation here might work better:
+ ! Use 2-back values to populate 1-back locations that are grounded, and then use 1-back values to calculate
+ ! the value at each primary cell location. This would be a mix of true-1-back values for dynamic floating cells
+ ! and the corresponding 2-back values at grounded cells.
+ if ( nGroundedNeighbors > 0 ) then
+ thkSum = 0.0_RKIND
+ uvelSum = 0.0_RKIND
+ vvelSum = 0.0_RKIND
+ ablationVelSum = 0.0_RKIND
+ thkCount = 0
+ nOneCellBack = 0
+ oneCellBackList(:) = 0
+ twoCellsBackList(:) = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if ( li_mask_is_ice(cellMask(jCell)) ) then
+ nOneCellBack = nOneCellBack + 1
+ oneCellBackList(nOneCellBack) = jCell
+ endif
+ enddo
+ if ( nOneCellBack > 0 ) then
+ ! loop over oneCellBackList and add neighbors
+ counter = 0
+ do iNeighbor = 1, nOneCellBack
+ jCell = oneCellBackList(iNeighbor)
+ ! create twoCellsBackList so we don't add one cell multiple
+ ! times
+ nTwoCellsBack = 0
+ do jNeighbor = 1, nEdgesOnCell(jCell)
+ kCell = cellsOnCell(jNeighbor, jCell)
+ if ( li_mask_is_dynamic_ice(cellMask(kCell)) .and. &
+ (.not. any(oneCellBackList==kCell) ) .and. &
+ (.not. any(twoCellsBackList==kCell) ) ) then
+ counter = counter+1
+ twoCellsBackList(counter) = kCell
+ endif
+ enddo
+ nTwoCellsBack = nTwoCellsBack + counter
+ enddo
+ ! loop through twoCellsBackList and average thickness and
+ ! velocities
+ do kCell = 1, nTwoCellsBack
+ thkSum = thkSum + thicknessForAblation(twoCellsBackList(kCell))
+ uvelSum = uvelSum + uvelForAblation(twoCellsBackList(kCell))
+ vvelSum = vvelSum + vvelforAblation(twoCellsBackList(kCell))
+ ablationVelSum = ablationVelSum + ablationVelocity(twoCellsBackList(kCell))
+ thkCount = thkCount + 1
+ enddo
+ endif
+ endif
+ if (thkCount == 0) then
+ !call mpas_log_write("Found a stranded non-dynamic floating
+ !cell: cell $i with thickness=$r m.", MPAS_LOG_WARN, &
+ ! intArgs=(/iCell/), realArgs=(/thickness(iCell)/))
+ else
+ thicknessForAblation(iCell) = thkSum / real(thkCount, kind=RKIND)
+ ablationVelocity(iCell) = ablationVelSum / real(thkCount, kind=RKIND)
+ uvelForAblation(iCell) = uvelSum / real(thkCount, kind=RKIND)
+ vvelForAblation(iCell) = vvelSum / real(thkCount, kind=RKIND)
+ endif
+ endif
+ enddo
+
+
+ ! a2.Set thicknessForAblation and ablationVelocity of stranded non-dynamic cells to
+ ! average of non-dynamic neighbors. Stranded non-dynamic cells are
+ ! identified as those with frontAblationMask == 3
+ do iCell = 1, nCells
+ if ( frontAblationMask(iCell) == 3 ) then
+ ablationVelSum = 0.0_RKIND
+ thkSum = 0.0_RKIND
+ uvelSum = 0.0_RKIND
+ vvelSum = 0.0_RKIND
+ thkCount = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if ( li_mask_is_floating_ice(cellMask(jCell)) &
+ .and. (.not. li_mask_is_dynamic_ice(cellMask(jCell))) ) then
+ thkSum = thkSum + thicknessForAblation(jCell)
+ uvelSum = uvelSum + uvelForAblation(jCell)
+ vvelSum = vvelSum + vvelForAblation(jCell)
+ ablationVelSum = ablationVelSum + ablationVelocity(jCell)
+ thkCount = thkCount + 1
+ endif
+ enddo
+ if (thkCount == 0) then
+ !call mpas_log_write("Found a stranded non-dynamic floating cell: cell $i with thickness=$r m.", MPAS_LOG_WARN, &
+ ! intArgs=(/iCell/), realArgs=(/thickness(iCell)/))
+ else
+ thicknessForAblation(iCell) = thkSum / real(thkCount, kind=RKIND)
+ ablationVelocity(iCell) = ablationVelSum / real(thkCount, kind=RKIND)
+ uvelForAblation(iCell) = uvelSum / real(thkCount, kind=RKIND)
+ vvelForAblation(iCell) = vvelSum / real(thkCount, kind=RKIND)
+ endif
+ endif
+ enddo
+
+ ! b. Translate the ablationVelocity and thickness from non-dynamic cells to their ocean-going edges
+ ! to calculate the calving volume on those edges and this cell
+ do iCell = 1, nCells
+ if (frontAblationMask(iCell)>0 .and. (.not. li_mask_is_dynamic_ice(cellMask(iCell)))) then
+
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ iEdge = edgesOnCell(iNeighbor, iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_margin(edgeMask(iEdge)) .and. & !< edge is a margin
+ .not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level & ! ensure margin is w/ocn
+ ) then
+ edgeLengthScaling = scale_edge_length(angleEdge(iEdge), uvelForAblation(iCell), vvelForAblation(iCell))
+ requiredAblationVolumeNonDynEdge(iEdge) = ablationVelocity(iCell) * &
+ edgeLengthScaling * dvEdge(iEdge) * thicknessForAblation(iCell) * deltat
+ requiredAblationVolumeNonDynCell(iCell) = requiredAblationVolumeNonDynCell(iCell) + &
+ requiredAblationVolumeNonDynEdge(iEdge) ! Keep running total
+ endif
+ enddo
+
+ ! c. Apply ablationThickness here
+ removeVolumeHere = min(cellVolume(iCell), requiredAblationVolumeNonDynCell(iCell)) ! Don't use more than available
+ ablationThickness(iCell) = removeVolumeHere / areaCell(iCell)
+ ablatedVolumeNonDynCell(iCell) = removeVolumeHere
+ unablatedVolumeNonDynCell(iCell) = requiredAblationVolumeNonDynCell(iCell) - removeVolumeHere
+ cellVolume(iCell) = cellVolume(iCell) - removeVolumeHere
+ if (iCell <= nCellsSolve) ablationSubtotal1 = ablationSubtotal1 + removeVolumeHere
+ endif
+ enddo
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'unablatedVolumeNonDynCell')
+ call mpas_timer_stop("halo updates")
+ !call mpas_log_write("Done calculating calving for nondynamic floating cells. Removed $r m^3", realArgs=(/calvingSubtotal1/))
+
+
+
+ ! 2. Calculate calving for dynamic cells
+ ablationSubtotal2 = 0.0_RKIND
+
+ ! 2a1. for grounded dynamic margins, don't use the thickness there because it may be unrealistically thin due to ablation
+ ! from previous time steps. Instead copy forward the thickness from the row cells behind.
+ do iCell = 1, nCells
+ if (frontAblationMask(iCell)>0 .and. li_mask_is_margin(cellMask(iCell)) .and. &
+ li_mask_is_grounded_ice(cellMask(iCell))) then
+ thkSum = 0.0_RKIND
+ thkCount = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_dynamic_ice(cellMask(jCell)) .and. li_mask_is_grounded_ice(cellMask(jCell)) .and. &
+ .not. li_mask_is_margin(cellMask(jCell))) then
+ thkSum = thkSum + thicknessForAblation(jCell)
+ thkCount = thkCount + 1
+ endif
+ enddo
+ if (thkCount == 0) then
+ !call mpas_log_write("Found a stranded non-dynamic floating cell: cell $i with thickness=$r m.", MPAS_LOG_WARN, &
+ ! intArgs=(/iCell/), realArgs=(/thickness(iCell)/))
+ else
+ thicknessForAblation(iCell) = thkSum / real(thkCount, kind=RKIND)
+ endif
+ endif
+ enddo
+
+ ! a. Calculate calving on dynamic margin edges
+ do iCell = 1, nCells
+ if ( frontAblationMask(iCell)>0 .and. li_mask_is_dynamic_ice(cellMask(iCell)) & ! a dynamic cell in the mask...
+ .and. li_mask_is_margin(cellMask(iCell)) ) then ! that is at the edge of the ice
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if ((.not. li_mask_is_ice(cellMask(jCell))) .and. (bedTopography(jCell) <= config_sea_level)) then
+ iEdge = edgesOnCell(iNeighbor, iCell)
+ edgeLengthScaling = scale_edge_length(angleEdge(iEdge), uvelForAblation(iCell), vvelForAblation(iCell))
+ requiredAblationVolumeDynEdge(iEdge) = ablationVelocity(iCell) * &
+ edgeLengthScaling * dvEdge(iEdge) * thicknessForAblation(iCell) * deltat
+ endif
+ enddo
+ endif
+ enddo
+ ! b. copy ablation remaining in non-dynamic cells to dynamic edges
+ ! Assume height and velocity are uniform, but edge length is not.
+ do iCell = 1, nCells
+ if ( (.not. li_mask_is_dynamic_ice(cellMask(iCell))) .and. &
+ unablatedVolumeNonDynCell(iCell) > 0.0_RKIND) then
+ ! This is a non-dynamic location that still has calving to offer - a location where calving needs to be propagated
+
+ !call mpas_log_write("Passing calving from non-dynamic cell $i. $r available to pass", &
+ ! realArgs=(/unablatedVolumeNonDynCell(iCell)/), intArgs=(/iCell/))
+
+ volumeAvailableToPass = unablatedVolumeNonDynCell(iCell)
+
+ ! Find total length of interface with dynamic cells at this cell
+ ablateLengthCell = 0.0_RKIND
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ iEdge = edgesOnCell(iNeighbor, iCell)
+ if (li_mask_is_dynamic_ice(edgeMask(iEdge))) then
+ edgeLengthScaling = scale_edge_length(angleEdge(iEdge), uvelForAblation(iCell), vvelForAblation(iCell))
+ ablateLengthEdge = edgeLengthScaling * dvEdge(iEdge)
+ ablateLengthCell = ablateLengthCell + ablateLengthEdge
+ endif
+ enddo
+
+ ! Now that we know calvLengthCell, pass along the required calving volume relative to the interface length
+ if ( ablateLengthCell > 0.0_RKIND ) then
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ iEdge = edgesOnCell(iNeighbor, iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_dynamic_ice(edgeMask(iEdge))) then
+ edgeLengthScaling = scale_edge_length(angleEdge(iEdge), uvelForAblation(iCell), vvelForAblation(iCell))
+ ablateLengthEdge = edgeLengthScaling * dvEdge(iEdge)
+ if (requiredAblationVolumeDynEdge(iEdge) > 0.0_RKIND) then
+ call mpas_log_write("Unexpectedly found a dynamic edge that already has calving assigned to it." // &
+ " There is a flaw in li_apply_front_ablation_velocity that needs to be fixed!", MPAS_LOG_ERR)
+ err_tmp = 1
+ err = ior(err, err_tmp)
+ endif
+ requiredAblationVolumeDynEdge(iEdge) = ablateLengthEdge / ablateLengthCell * volumeAvailableToPass
+ unablatedVolumeNonDynCell(iCell) = unablatedVolumeNonDynCell(iCell) - requiredAblationVolumeDynEdge(iEdge)
+ !call mpas_log_write(" Passed calving $r from non-dynamic cell $i to dynamic cell $i", &
+ ! realArgs=(/requiredAblationVolumeDynEdge(iEdge)/), intArgs=(/iCell, jCell/))
+ endif
+ enddo
+ endif
+ endif
+ enddo
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'requiredAblationVolumeDynEdge')
+ call mpas_timer_stop("halo updates")
+
+ ! c. Now apply ablation to each cell
+ do iCell = 1, nCells
+ if ((li_mask_is_dynamic_ice(cellMask(iCell))) .and. (bedTopography(iCell) <= config_sea_level)) then
+ ! Can loop over all dyn cells - only ones with calving on their edges will have calving applied.
+ ! Note, we ignore any leftover calving/melting if it would be applied to cells where the bed is above sea level.
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ iEdge = edgesOnCell(iNeighbor, iCell)
+ ! No need to check what type of edge this is - only required edges are nonzero
+ requiredAblationVolumeDynCell(iCell) = requiredAblationVolumeDynCell(iCell) + &
+ requiredAblationVolumeDynEdge(iEdge) ! Keep running total
+ enddo
+ ! c. Apply calving here
+ removeVolumeHere = min(cellVolume(iCell), requiredAblationVolumeDynCell(iCell)) ! Don't use more than available
+ ablationThickness(iCell) = removeVolumeHere / areaCell(iCell)
+ ablatedVolumeDynCell(iCell) = removeVolumeHere
+ unablatedVolumeDynCell(iCell) = requiredAblationVolumeDynCell(iCell) - removeVolumeHere
+ cellVolume(iCell) = cellVolume(iCell) - removeVolumeHere
+ if (iCell <= nCellsSolve) ablationSubtotal2 = ablationSubtotal2 + removeVolumeHere
+ endif
+ enddo
+ !call mpas_log_write("Done calculating ablation for dynamic floating cells. Removed $r m^3", realArgs=(/calvingSubtotal2/))
+
+
+ ! Clean up to account for roundoff level errors that can occur
+ do iCell = 1, nCells
+ if (abs(ablationThickness(iCell) - thickness(iCell)) < ablationSmallThk) then
+ ablationThickness(iCell) = thickness(iCell)
+ endif
+ enddo
+
+ ! Clean up - zap any stranded ice. This only needs to be considered for floating ice.
+ ablationSubtotal3 = 0.0_RKIND
+ do iCell = 1, nCells
+ if (li_mask_is_floating_ice(cellMask(iCell)) .and. (.not. li_mask_is_dynamic_ice(cellMask(iCell)))) then
+ thkCount = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_dynamic_ice(cellMask(jCell))) then
+ thkCount = thkCount + 1
+ endif
+ enddo
+ if (thkCount == 0) then
+ ablationThickness(iCell) = thickness(iCell)
+ if (iCell <= nCellsSolve) ablationSubtotal3 = ablationSubtotal3 + ablationThickness(iCell)
+ endif
+ endif
+ if (ieee_is_nan(calvingThickness(iCell))) then
+ call mpas_log_write("NaN detected in calvingThickness at cell $i", MPAS_LOG_ERR, intArgs=(/iCell/))
+ err_tmp = 1
+ err = ior(err, err_tmp)
+ endif
+ enddo
+
+ ! Clean up to account for roundoff level errors that can occur
+ do iCell = 1, nCells
+ if (abs(ablationThickness(iCell) - thickness(iCell)) < ablationSmallThk) then
+ ablationThickness(iCell) = thickness(iCell)
+ endif
+ enddo
+
+
+ ! End of routine accounting/reporting
+ localInfo(1) = ablationSubtotal1
+ localInfo(2) = ablationSubtotal2
+ localInfo(3) = ablationSubtotal3
+ localInfo(4) = sum(ablationThickness(1:nCellsSolve) * areaCell(1:nCellsSolve))
+ localInfo(5) = sum(unablatedVolumeNonDynCell(1:nCellsSolve))
+ localInfo(6) = sum(unablatedVolumeDynCell(1:nCellsSolve))
+ ! NOTE: THIS WILL NOT WORK ON MULTIPLE BLOCKS PER PROCESSOR
+ call mpas_dmpar_sum_real_array(domain % dminfo, 6, localInfo, globalInfo)
+ call mpas_log_write("== Ablation complete. Total calved = $r", realArgs = (/globalInfo(4)/))
+ call mpas_log_write("== Ablated from non-dynamic cells = $r", realArgs = (/globalInfo(1)/))
+ call mpas_log_write("== Ablated from dynamic cells = $r", realArgs = (/globalInfo(2)/))
+ call mpas_log_write("== Stranded floating cells deleted = $r", realArgs = (/globalInfo(3)/))
+ call mpas_log_write("== Unablated volumes: Non-dynamic cells=$r; Dynamic cells=$r", realArgs=(/globalInfo(5),globalInfo(6)/))
+ if (((globalInfo(5) + globalInfo(6)) / (globalInfo(4) + 1.0e-30_RKIND) > 0.001_RKIND) .and. &
+ (globalInfo(4) > 1000.0_RKIND**2)) then ! Include some small amount of total calving for comparison
+ call mpas_log_write("Failed to ablate $r m^3. ($r% of total ablated)", MPAS_LOG_WARN, &
+ realArgs=(/globalInfo(5) + globalInfo(6), &
+ 100.0_RKIND * (globalInfo(5) + globalInfo(6)) / (globalInfo(4)+1.0e-30_RKIND)/))
+ endif
+ if (((globalInfo(5) + globalInfo(6)) / (globalInfo(4) + 1.0e-30_RKIND) > 0.1_RKIND) .and. &
+ (globalInfo(4) > 1000.0_RKIND**2)) then ! Include some small amount of total calving for comparison
+ call mpas_log_write("Failed to ablate an amount greater than 10% of the ice ablated. " // &
+ "Try reducing time step or li_apply_front_ablation_velocity may need improvements.", &
+ MPAS_LOG_ERR, realArgs=(/globalInfo(5) + globalInfo(6), &
+ 100.0_RKIND * (globalInfo(5) + globalInfo(6)) / (globalInfo(4)+1.0e-30_RKIND)/))
+ err_tmp = 1
+ err = ior(err, err_tmp)
+ endif
+ if (globalInfo(3) / (globalInfo(4) + 1.0e-30_RKIND) > 0.01_RKIND) then
+ ! If stranded ice deletion results in more than a small amount of the total calving flux, this routine will not
+ ! be accurate. If this error gets triggered, either try using a smaller timstep or this routine needs improving.
+ call mpas_log_write("Deleting stranded floating cells accounts for more than 1% of ablation loss." // &
+ " Try using a smaller timestep or li_apply_front_ablation_velocity may need improvements for this simulation.")
+ err_tmp = 1
+ err = ior(err, err_tmp)
+ endif
+
+ deallocate(cellVolume)
+ deallocate(thicknessForAblation)
+ deallocate(uvelForAblation)
+ deallocate(vvelForAblation)
+ deallocate(oneCellBackList)
+ deallocate(twoCellsBackList)
+ call mpas_log_write("Finished with li_apply_front_ablation_velocity")
+
+ end subroutine li_apply_front_ablation_velocity
+
+
+ ! Helper function for subroutine li_apply_front_ablation_velocity
+ ! Calculates the amount to scale an edge length based on the orientation of the edge with the surface velocity
+ function scale_edge_length(angleEdgeHere, u, v)
+ real(kind=RKIND), intent(in) :: angleEdgeHere
+ real(kind=RKIND), intent(in) :: u
+ real(kind=RKIND), intent(in) :: v
+ real(kind=RKIND) :: scale_edge_length
+
+ real(kind=RKIND) :: mag
+
+ mag = sqrt(u**2 + v**2)
+ if (mag == 0.0_RKIND) mag = 1.0_RKIND
+ scale_edge_length = abs(u/mag * cos(angleEdgeHere) + v/mag * sin(angleEdgeHere)) ! dot product of unit vectors
+ !scale_edge_length = abs(cos(angleEdgeHere - atan2(v, u)))
+ end function scale_edge_length
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine damagecalving
+!
+!> \brief Calve ice from the calving front based on the Bassis-Ma (2015) damage theory.
+!> We can use two options: "calving_rate" or "threshold".
+!> If we use "calving_rate", the calving front retreats by removing ice at a speed of k * damage,
+!> where k is a calving parameter. If we use "threshold", the ice at the calving front will be completely
+!> gone if the damage is above the threshold.
+!> \author Tong Zhang
+!> \date May. 2019
+!> \details Connect calving with the damage model
+!> Bassis, Jeremy N., and Y. Ma. "Evolution of basal crevasses links ice shelf stability to ocean forcing."
+!> Earth and Planetary Science Letters 409 (2015): 203-211.
+
+!-----------------------------------------------------------------------
+ subroutine damage_calving(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: velocityPool
+ type (mpas_pool_type), pointer :: scratchPool
+ logical, pointer :: config_print_calving_info
+ real (kind=RKIND), pointer :: config_sea_level
+ real(kind=RKIND), pointer :: config_calving_thickness
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: bedTopography
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness
+ real (kind=RKIND), dimension(:), pointer :: calvingVelocity
+ real (kind=RKIND), dimension(:), pointer :: eMax, eMin
+ real (kind=RKIND), dimension(:), pointer :: damage
+ integer, dimension(:), pointer :: calvingFrontMask
+ integer, dimension(:), pointer :: cellMask
+ real (kind=RKIND), pointer :: deltat !< time step (s)
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:,:), pointer :: edgesOnCell
+ real (kind=RKIND), dimension(:), pointer :: dvEdge
+ real (kind=RKIND), dimension(:), pointer :: areaCell
+ integer, pointer :: nCells
+ integer :: iCell, jCell, iNeighbor
+ real(kind=RKIND) :: cellCalvingFrontLength, cellCalvingFrontHeight
+ integer :: err_tmp
+ logical :: dynamicNeighbor
+ real(kind=RKIND), pointer :: config_damagecalvingParameter
+ real(kind=RKIND) :: calvingSubtotal
+ character (len=StrKIND), pointer :: config_damage_calving_method
+ real(kind=RKIND), pointer :: config_damage_calving_threshold
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_print_calving_info', config_print_calving_info)
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ call mpas_pool_get_config(liConfigs, 'config_calving_thickness', config_calving_thickness)
+ call mpas_pool_get_config(liConfigs, 'config_damagecalvingParameter', config_damagecalvingParameter)
+ call mpas_pool_get_config(liConfigs, 'config_damage_calving_method', config_damage_calving_method)
+ call mpas_pool_get_config(liConfigs, 'config_damage_calving_threshold', config_damage_calving_threshold)
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
+
+ ! get fields
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_array(meshPool, 'deltat', deltat)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'damage', damage)
+ call mpas_pool_get_array(geometryPool, 'calvingVelocity', calvingVelocity)
+ call mpas_pool_get_array(geometryPool, 'calvingFrontMask', calvingFrontMask)
+
+
+ call calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask)
+
+ if (trim(config_damage_calving_method) == 'calving_rate') then
+ if (config_damage_calving_threshold >= 1.0_RKIND .or. config_damage_calving_threshold < 0.0_RKIND) then
+ call mpas_log_write("Invalid value of config_damage_calving_threshold specified for 'calving_rate' option. " // &
+ "Valid values are in the range [0,1).", MPAS_LOG_ERR)
+ err = ior(err, err_tmp)
+ endif
+ ! First calculate the front retreat rate (m/s)
+ calvingVelocity(:) = config_damagecalvingParameter * &
+ max(0.0_RKIND, (damage(:) - config_damage_calving_threshold) / (1.0_RKIND - config_damage_calving_threshold)) &
+ * real(li_mask_is_floating_ice_int(cellMask(:)), kind=RKIND) ! calculate only for floating ice
+ call li_apply_front_ablation_velocity(meshPool, geometryPool, velocityPool, calvingThickness, calvingVelocity, &
+ applyToGrounded=.false., applyToFloating=.true., applyToGroundingLine=.false., &
+ domain=domain, err=err_tmp)
+ err = ior(err, err_tmp)
+ elseif (trim(config_damage_calving_method) == 'threshold') then
+ call apply_calving_damage_threshold(meshPool, geometryPool, scratchPool, err_tmp)
+ err = ior(err, err_tmp)
+ else
+ call mpas_log_write("Unknown value for config_damage_calving_method was specified!", MPAS_LOG_ERR)
+ endif
+
+ ! === apply calving ===
+ thickness(:) = thickness(:) - calvingThickness(:)
+
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ ! Now also remove thin floating, dynamic ice (based on chosen thickness threshold) after mask is updated.
+ ! This criteria below only remove too-thin ice at the new calving front,
+ ! meaning just one 'row' of cells per timestep. This could be expanded to continue
+ ! removing ice backward until all connected too-thin ice has been removed.
+ ! Tests of the current implementation show reasonable behavior.
+ do iCell = 1, nCells
+ if (calvingFrontMask(iCell) == 1 .and. thickness(iCell) < config_calving_thickness) then
+ calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell)
+ thickness(iCell) = 0.0_RKIND
+ endif
+ enddo
+
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ ! remove abandoned floating ice (i.e. icebergs) and add it to the calving flux
+ ! Defined as: floating ice (dynamic or non-dynamic) that is not adjacent to dynamic ice (floating or grounded)
+ ! This won't necessarily find all abandoned ice, but in practice it does a pretty good job at general cleanup
+ calvingSubtotal = 0.0_RKIND
+ do iCell = 1, nCells
+ if (li_mask_is_floating_ice(cellMask(iCell))) then
+ ! check neighbors for dynamic ice (floating or grounded)
+ dynamicNeighbor = .false.
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_dynamic_ice(cellMask(jCell))) dynamicNeighbor = .true.
+ enddo
+ if (.not. dynamicNeighbor) then ! calve this ice
+ calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell)
+ thickness(iCell) = 0.0_RKIND
+ calvingSubtotal = calvingSubtotal + calvingThickness(iCell) * areaCell(iCell)
+ endif
+ endif
+ enddo
+ ! TODO: global reduce & reporting on amount of calving generated in this step
+
+ call remove_small_islands(meshPool, geometryPool)
+
+ block => block % next
+
+ enddo
+
+ end subroutine damage_calving
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine li_calculate_damage
+!
+!> \author Tong Zhang
+!> \date May. 2019
+!> \details calulate the damage tracer for floating ice shelves (damage at grounded ice is constrained as 0)
+!> Bassis, Jeremy N., and Y. Ma. "Evolution of basal crevasses links ice shelf stability to ocean forcing."
+!> Earth and Planetary Science Letters 409 (2015): 203-211.
+
+!-----------------------------------------------------------------------
+
+ subroutine li_calculate_damage(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: thermalPool
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: velocityPool
+ type (mpas_pool_type), pointer :: scratchPool
+
+ real(kind=RKIND), pointer :: config_damage_preserve_threshold
+ character (len=StrKIND), pointer :: config_damage_gl_setting
+ real(kind=RKIND), pointer :: config_default_flowParamA
+ real(kind=RKIND), pointer :: config_flowLawExponent
+ logical, pointer :: config_print_calving_info
+
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: eMax
+ real (kind=RKIND), dimension(:), pointer :: tauMax, tauMin
+ real (kind=RKIND), dimension(:), pointer :: floatingBasalMassBal
+ real (kind=RKIND), dimension(:), pointer :: damage
+ real (kind=RKIND), dimension(:), pointer :: ddamagedt
+ real (kind=RKIND), dimension(:), pointer :: s0, nstar
+ real (kind=RKIND), dimension(:), pointer :: damageSource
+ real (kind=RKIND), dimension(:), pointer :: damageNye
+ real (kind=RKIND), dimension(:), pointer :: damageMax
+ real (kind=RKIND), pointer :: &
+ config_ice_density, & ! ice density
+ config_ocean_density ! ocean density
+
+ real (kind=RKIND), dimension(:), pointer :: principalStrainRateRatio
+
+ integer, dimension(:), pointer :: cellMask
+ real (kind=RKIND), pointer :: deltat !< time step (s)
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, pointer :: nCells
+ integer :: iCell, jCell, iNeighbor, n_damage_downstream
+ real(kind=RKIND) :: damage_downstream
+ real(kind=RKIND), dimension(:,:), pointer :: uReconstructX, uReconstructY
+ real(kind=RKIND), dimension(6) :: localMinInfo, localMaxInfo, globalMinInfo, globalMaxInfo
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_flowLawExponent', config_flowLawExponent)
+ call mpas_pool_get_config(liConfigs, 'config_print_calving_info', config_print_calving_info)
+ call mpas_pool_get_config(liConfigs, 'config_damage_preserve_threshold', config_damage_preserve_threshold)
+ call mpas_pool_get_config(liConfigs, 'config_damage_gl_setting', config_damage_gl_setting)
+ call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density)
+ call mpas_pool_get_config(liConfigs, 'config_ocean_density', config_ocean_density)
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
+
+ ! get fields
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_array(meshPool, 'deltat', deltat)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'damage', damage)
+ call mpas_pool_get_array(geometryPool, 'ddamagedt', ddamagedt)
+ call mpas_pool_get_array(geometryPool, 's0', s0)
+ call mpas_pool_get_array(geometryPool, 'nstar', nstar)
+ call mpas_pool_get_array(geometryPool, 'damageSource', damageSource)
+ call mpas_pool_get_array(geometryPool, 'damageNye', damageNye)
+ call mpas_pool_get_array(geometryPool, 'damageMax', damageMax)
+ call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
+
+ call mpas_pool_get_array(velocityPool, 'eMax', eMax)
+ call mpas_pool_get_array(velocityPool, 'tauMax', tauMax)
+ call mpas_pool_get_array(velocityPool, 'tauMin', tauMin)
+ call mpas_pool_get_array(velocityPool, 'principalStrainRateRatio', principalStrainRateRatio)
+
+ where (thickness == 0.0_RKIND)
+ principalStrainRateRatio = 0.0_RKIND
+ s0 = 0.0_RKIND
+ nstar = 0.0_RKIND
+ elsewhere
+ ! Compute the hydrostatic to tensile stress ratio (equation 24 from Bassis and Ma, 2015, EPSL, 409, C)
+ ! In Bassis & Ma this is beta, defined as ratio of principal strain rates. Here we calculate as ratio of
+ ! deviatoric stresses, which is equivalent.
+ principalStrainRateRatio = tauMin / tauMax
+
+ s0 = &
+ config_ice_density*(config_ocean_density-config_ice_density)*gravity*thickness/(2.0_RKIND*tauMax*config_ocean_density)
+
+ ! Compute the effective flow law exponent (equation 11 from Bassis and Ma, 2015, EPSL, 409, C)
+ nstar(:) = 4.0_RKIND * config_flowLawExponent * &
+ (1.0_RKIND + principalStrainRateRatio(:) + principalStrainRateRatio(:)**2) / &
+ (4.0_RKIND * (1.0_RKIND + principalStrainRateRatio(:) + principalStrainRateRatio(:)**2) + &
+ 3.0_RKIND * (config_flowLawExponent - 1.0_RKIND )* principalStrainRateRatio(:)**2)
+ endwhere
+
+
+ do iCell = 1, nCells
+ if (thickness(iCell) == 0.0_RKIND) then
+ damageSource(iCell) = 0.0_RKIND
+ else
+ damageSource(iCell) = nstar(iCell) * (1.0_RKIND - s0(iCell)) * eMax(iCell) - floatingBasalMassBal(iCell) &
+ / config_ice_density / thickness(iCell)
+ ! RHS of equation 26 from Bassis and Ma (2015, EPSL, 409, C). Note that the last set of terms after the minus sign,
+ ! mdot / rho_i / H, differs from the mdot/H in the paper because our mdot has units of kg/m^2/s and to convert that
+ ! back to the right units (1/sec) you need to multiply by a factor of m^2/kg (1/rho_i * 1/H gives that factor).
+ endif
+ enddo
+
+ !! Commented out lines immediately below here are for use with manufacured experiments
+ !ddamagedt(:) = damageSource(:)*damage(:) - 0.44/2.0 * (uReconstructX(1,:)/1000.0*(1+epsmax(:)*seconds)* &
+ ! exp(-uReconstructX(1,:)*seconds/1000.0) + damageSource(:) * (1+exp(-uReconstructX(1,:)*seconds/1000.0)))
+ !ddamagedt(:) = damageSource(:)*damage(:) - 0.44/2.0 * (uReconstructX(1,:)/1000.0*exp(-uReconstructX(1,:)*seconds/1000.0)+&
+ ! damageSource(:) * (1+exp(-uReconstructX(1,:)*seconds/1000.0)))
+
+ ddamagedt(:) = damageSource(:) * damage(:)
+
+ damage(:) = damage(:) + ddamagedt(:) * deltat
+
+ do iCell = 1, nCells
+ if (thickness(iCell) == 0.0_RKIND) then
+ damageNye(iCell) = 0.0_RKIND
+ else
+ damageNye(iCell) = (2.0_RKIND + principalStrainRateRatio(iCell)) * tauMax(iCell) / &
+ (gravity * (config_ocean_density - config_ice_density) * thickness(iCell))
+ endif
+ enddo
+
+ do iCell = 1, nCells
+ if (damage(iCell) > config_damage_preserve_threshold) then
+ damageMax(iCell) = damage(iCell)
+ end if
+ end do
+ ! save the damageMax value for restoring later if that option is chosen (i.e., do NOT allowing for healing to occur)
+
+ do iCell = 1, nCells
+ if (damage(iCell) < 0.0_RKIND) then
+ damage(iCell) = 0.0_RKIND
+ end if
+ if (damage(iCell) < damageNye(iCell)) then
+ damage(iCell) = damageNye(iCell)
+ end if
+ if (damage(iCell) > 1.0_RKIND) then
+ damage(iCell) = 1.0_RKIND
+ end if
+ end do
+ ! damage is always larger than the Nye value for initialization of damage evolution.
+
+ do iCell = 1, nCells
+ if ((li_mask_is_grounded_ice(cellMask(iCell))) .or. (thickness(iCell) .eq. 0.0_RKIND)) then
+ damage(iCell) = 0.0_RKIND
+ end if
+ end do
+ ! the damage of grounded ice is kept as 0, as the strain rate calculation is only valid for ice shelf
+
+ ! Options for initializing damage where ice goes afloat:
+ if (trim(config_damage_gl_setting) == 'extrapolate') then
+ ! set the damage for a cell at the GL to the average damage value for its neighbor cells downstream on the ice shelf
+ do iCell = 1, nCells
+ if (li_mask_is_grounding_line(cellMask(iCell))) then
+
+ damage_downstream = 0.0_RKIND
+ n_damage_downstream = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_floating_ice(cellMask(jCell))) then
+
+ damage_downstream = damage_downstream + damage(jCell)
+ n_damage_downstream = n_damage_downstream + 1
+ end if
+ end do
+
+ if (n_damage_downstream == 0) then
+ damage(iCell) = 0.0_RKIND
+ else
+ damage(iCell) = damage_downstream / n_damage_downstream
+ end if
+
+ end if
+ end do
+ elseif (trim(config_damage_gl_setting) == "nye") then
+ ! set the damage at the first floating cells to the Nye value
+ do iCell = 1, nCells
+ if (li_mask_is_grounding_line(cellMask(iCell))) then
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_floating_ice(cellMask(jCell))) then
+ damage(jCell) = damageNye(jCell)
+ end if
+ end do
+ end if
+ end do
+ else
+ call mpas_log_write("Unknown value specified for config_damage_gl_setting!", MPAS_LOG_ERR)
+ err = ior(err, 1)
+ endif
+
+ if (config_print_calving_info) then
+ ! End of routine accounting/reporting
+ localMinInfo(1) = minval(damageSource)
+ localMaxInfo(1) = maxval(damageSource)
+ localMinInfo(2) = minval(s0)
+ localMaxInfo(2) = maxval(s0)
+ localMinInfo(3) = minval(nstar)
+ localMaxInfo(3) = maxval(nstar)
+ localMinInfo(4) = minval(principalStrainRateRatio)
+ localMaxInfo(4) = maxval(principalStrainRateRatio)
+ localMinInfo(5) = minval(tauMax)
+ localMaxInfo(5) = maxval(tauMax)
+ localMinInfo(6) = minval(damage)
+ localMaxInfo(6) = maxval(damage)
+ ! NOTE: THIS WILL NOT WORK ON MULTIPLE BLOCKS PER PROCESSOR
+ call mpas_dmpar_min_real_array(domain % dminfo, 6, localMinInfo, globalMinInfo)
+ call mpas_dmpar_max_real_array(domain % dminfo, 6, localMaxInfo, globalMaxInfo)
+
+ call mpas_log_write("damageSource value range: Min=$r, Max=$r", &
+ realArgs=(/globalMinInfo(1), globalMaxInfo(1)/))
+ call mpas_log_write("s0 value range: Min=$r, Max=$r", &
+ realArgs=(/globalMinInfo(2), globalMaxInfo(2)/))
+ call mpas_log_write("nstar value range: Min=$r, Max=$r", &
+ realArgs=(/globalMinInfo(3), globalMaxInfo(3)/))
+ call mpas_log_write("principalStrainRateRatio value range: Min=$r, Max=$r", &
+ realArgs=(/globalMinInfo(4), globalMaxInfo(4)/))
+ call mpas_log_write("tauMax value range: Min=$r, Max=$r", &
+ realArgs=(/globalMinInfo(5), globalMaxInfo(5)/))
+ call mpas_log_write("damage value range: Min=$r, Max=$r", &
+ realArgs=(/globalMinInfo(6), globalMaxInfo(6)/))
+ end if
+ ! temporary message output in the log file
+
+
+ block => block % next
+
+ enddo
+
+ end subroutine li_calculate_damage
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine li_finalize_damage_after_advection
+!
+!> \author Tong Zhang
+!> \date Oct. 2019
+!> \details This routine finalizes the damage calculation after advection by several ways: 1) set the damage at grounding line
+!> using an extrapolation method or an Nye method.
+!> 2) preserve the damage to the original value before advection if it exceeds some large number
+!> (config_damage_preserve_threshold). For example, if config_damage_preserve_threshold = 0.5,
+!> then the localtions with damage > 0.5 on the ice shelf will not heal.
+!> Thus, if we turn on this function, we do not allow the damage to heal if damage > config_damage_preserve_threshold.
+!> 3) coupling rheology to damage if the option config_damage_rheology_coupling is set to True in namelist
+!-----------------------------------------------------------------------
+
+ subroutine li_finalize_damage_after_advection(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: velocityPool
+ type (mpas_pool_type), pointer :: scratchPool
+ real(kind=RKIND), pointer :: config_damage_stiffness_min
+ logical, pointer :: config_damage_rheology_coupling
+ logical, pointer :: config_preserve_damage
+ logical, pointer :: config_print_calving_info
+ character (len=StrKIND), pointer :: config_damage_gl_setting
+ real (kind=RKIND), dimension(:), pointer :: damage
+ real (kind=RKIND), dimension(:), pointer :: damageMax
+ real (kind=RKIND), dimension(:), pointer :: damageNye
+ real (kind=RKIND), dimension(:), pointer :: stiffnessFactor
+
+
+ integer, dimension(:), pointer :: cellMask
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, pointer :: nCells
+ integer :: iCell, jCell, iNeighbor, n_damage_downstream
+ real(kind=RKIND) :: damage_downstream
+ integer :: err_tmp
+
+ err = 0
+
+
+ call mpas_pool_get_config(liConfigs, 'config_damage_stiffness_min', config_damage_stiffness_min)
+ call mpas_pool_get_config(liConfigs, 'config_damage_rheology_coupling', config_damage_rheology_coupling)
+ call mpas_pool_get_config(liConfigs, 'config_damage_gl_setting', config_damage_gl_setting)
+ call mpas_pool_get_config(liConfigs, 'config_preserve_damage', config_preserve_damage)
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+
+ ! get fields
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'damage', damage)
+ call mpas_pool_get_array(geometryPool, 'damageMax', damageMax)
+ call mpas_pool_get_array(geometryPool, 'damageNye', damageNye)
+ call mpas_pool_get_array(velocityPool, 'stiffnessFactor', stiffnessFactor)
+
+ ! make sure masks are up to date. May not be necessary, but safer to do anyway.
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ if (config_preserve_damage) then
+ do iCell = 1, nCells
+ if (damage(iCell) < damageMax(iCell)) then
+ damage(iCell) = damageMax(iCell)
+ end if
+ end do
+ endif
+ ! put the damageMax value back to preserve the damage value (no heal)
+
+ where (damage < 0.0_RKIND)
+ damage = 0.0_RKIND
+ end where
+
+ where (damage > 1.0_RKIND)
+ damage = 1.0_RKIND
+ end where
+
+
+ do iCell = 1, nCells
+ if (li_mask_is_grounded_ice(cellMask(iCell)) .or. .not. li_mask_is_ice(cellMask(iCell))) then
+ damage(iCell) = 0.0_RKIND
+ end if
+ end do
+
+ if (trim(config_damage_gl_setting) == 'extrapolate') then
+ do iCell = 1, nCells
+ if (li_mask_is_grounding_line(cellMask(iCell))) then
+ damage_downstream = 0.0_RKIND
+ n_damage_downstream = 0
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_floating_ice(cellMask(jCell))) then
+
+ damage_downstream = damage_downstream + damage(jCell)
+ n_damage_downstream = n_damage_downstream + 1
+ end if
+ end do
+
+ damage(iCell) = damage_downstream
+
+ if (n_damage_downstream == 0) then
+ damage(iCell) = 0.0_RKIND
+ else
+ damage(iCell) = damage_downstream / n_damage_downstream
+ end if
+
+ end if
+ end do
+ !set the damage at GL to the mean damage value for its neighboring floating cells
+
+ elseif (trim(config_damage_gl_setting) == 'nye') then
+ do iCell = 1, nCells
+ if (li_mask_is_grounding_line(cellMask(iCell))) then
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_floating_ice(cellMask(jCell))) then
+ damage(jCell) = damageNye(jCell)
+ end if
+ end do
+ end if
+ end do
+ ! always set the damage at the first floating cells to the Nye value
+ endif
+
+ if (config_damage_rheology_coupling) then
+ do iCell = 1, nCells
+ if (li_mask_is_floating_ice(cellMask(iCell))) then
+ stiffnessFactor(iCell) = 1.0_RKIND - damage(iCell)
+ if (stiffnessFactor(iCell) < config_damage_stiffness_min) then
+ stiffnessFactor(iCell) = config_damage_stiffness_min
+ end if
+ end if
+ end do
+ end if
+
+
+ block => block % next
+
+ enddo
+
+ end subroutine li_finalize_damage_after_advection
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine apply_calving_damage_threshold
+!
+!> \brief Calve any ice that is damaged beyond a specified threshold
+!> \author Tong Zhang, Matt Hoffman
+!> \date Nov. 2020, March 2021
+!> \details This routine specified floating ice to be calved wherever the damage
+!> value exceeds a specified threshold, assuming the ice is connected to the calving
+!> front.
+!-----------------------------------------------------------------------
+ subroutine apply_calving_damage_threshold(meshPool, geometryPool, scratchPool, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), pointer, intent(in) :: meshPool !< Input: Mesh pool
+ type (mpas_pool_type), pointer, intent(in) :: scratchPool !< Input: scratch pool
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), pointer, intent(inout) :: geometryPool !< Input: geometry pool
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness !< Output: the applied calving rate as a thickness
+ real (kind=RKIND), dimension(:), pointer :: thickness, damage, bedTopography
+ integer, dimension(:), pointer :: groundedMarineMarginMask
+ real(kind=RKIND), pointer :: config_damage_calving_threshold
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:), pointer :: cellMask
+ integer, pointer :: nCells
+ integer :: iCell, iNeighbor, jCell, iEdge
+ integer :: nEmptyNeighbors
+ real (kind=RKIND), pointer :: config_sea_level
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_damage_calving_threshold', config_damage_calving_threshold)
+
+ ! get fields
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'damage', damage)
+ call mpas_pool_get_array(geometryPool, 'groundedMarineMarginMask', groundedMarineMarginMask)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+
+ calvingThickness(:) = 0.0_RKIND
+
+ groundedMarineMarginMask(:) = 0
+ do iCell = 1, nCells
+ ! Define marine marginal cells as those that are (1) at the ice
+ ! margin, (2) have at least one neighboring cell without ice, (3) contain
+ ! grounded ice, and (4) have bed topography below sea level.
+ ! OR is adjacent to an inactive floating margin cell
+
+ ! Check if neighboring cells contain ice and have bed topo below sea level
+ nEmptyNeighbors = 0
+ do iEdge = 1, nEdgesOnCell(iCell)
+ iNeighbor = cellsOnCell(iEdge, iCell)
+ if ( (((thickness(iNeighbor) == 0.0_RKIND) &
+ .and. bedTopography(iNeighbor) < config_sea_level)) &
+ .or. ((li_mask_is_floating_ice(cellMask(iNeighbor)) &
+ .and. li_mask_is_margin(cellMask(iNeighbor)) &
+ .and. (.not. li_mask_is_dynamic_ice(cellMask(iNeighbor)))))) then
+ nEmptyNeighbors = nEmptyNeighbors + 1
+ endif
+ enddo
+
+ if ( nEmptyNeighbors > 0 &
+ .and. li_mask_is_grounded_ice(cellMask(iCell)) &
+ .and. bedTopography(iCell) < config_sea_level &
+ .and. li_mask_is_dynamic_ice(cellMask(iCell)) ) then
+
+ groundedMarineMarginMask(iCell) = 1
+ else
+ groundedMarineMarginMask(iCell) = 0
+ endif
+ enddo
+
+ ! The calving volume needs to be distributed in three ways:
+ ! 1. We need to first remove any "thin" ice in front of this cell
+ ! 2. Then we remove ice from this cell if damage > threshold
+ do iCell = 1, nCells
+ if ( (li_mask_is_floating_ice(cellMask(iCell)) .and. li_mask_is_dynamic_ice(cellMask(iCell)) ) & ! floating dynamic
+ .and. li_mask_is_margin(cellMask(iCell)) &
+ .and. (damage(iCell) .ge. config_damage_calving_threshold)) then
+
+ ! First remove ice from "thin" neighbors
+ do iNeighbor = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(iNeighbor, iCell)
+ if (li_mask_is_floating_ice(cellMask(jCell)) .and. .not. li_mask_is_dynamic_ice(cellMask(jCell))) then
+ ! this is a thin neighbor - remove the whole cell volume
+ calvingThickness(jCell) = thickness(jCell)
+ endif
+ enddo
+
+ calvingThickness(iCell) = thickness(iCell)
+ ! < apply to the field that will be used in thickness units
+
+ ! Now calved away the neighboring cells if the damage is also > the threshold value
+ ! I choose to disable this section (i.e., no recursive calving) -- TZ
+ !TODO: a flood fill algorithm might be needed for this threshold method in the future
+ !do iNeighbor = 1, nEdgesOnCell(iCell)
+ ! jCell = cellsOnCell(iNeighbor, iCell)
+ ! if (li_mask_is_floating_ice(cellMask(jCell)) .and. li_mask_is_dynamic_ice(cellMask(jCell)) &
+ ! .and. (.not. li_mask_is_dynamic_margin(jCell)) .and. (damage(jCell) .gt. config_damage_calving_threshold)) then
+ ! removeVolumeHere = cellVolume(jCell)
+ ! < how much we want to remove here
+ ! calvingThickness(jCell) = removeVolumeHere / areaCell(jCell)
+ ! < apply to the field that will be used in thickness units
+ ! cellVolume(jCell) = cellVolume(jCell) - removeVolumeHere
+ ! update accounting on cell volume
+ ! endif
+ !enddo
+
+ endif ! if cell is calving margin
+
+ enddo ! cell loop
+
+ end subroutine apply_calving_damage_threshold
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine mask_calving
+!
+!> \brief Calve ice based on a mask that is input
+!> \author Matthew Hoffman
+!> \date July 2019
+!> \details This routine uses the field calvingMask to eliminate floating
+!> ice. Locations marked with 0 will not be calved. Locations with all
+!> all other values will be calved. Note that time-varying values
+!> can be input.
+!-----------------------------------------------------------------------
+ subroutine mask_calving(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: velocityPool
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness
+ integer, dimension(:), pointer :: calvingMask
+ integer, dimension(:), pointer :: cellMask
+ integer :: err_tmp
+
+ err = 0
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+
+ ! get fields
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'calvingMask', calvingMask)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+
+ calvingThickness = 0.0_RKIND
+
+ ! === apply calving ===
+ where (li_mask_is_floating_ice(cellMask) .and. (calvingMask >= 1))
+ calvingThickness = thickness
+ thickness = 0.0_RKIND
+ end where
+
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ call remove_small_islands(meshPool, geometryPool)
+
+ block => block % next
+ enddo
+
+ end subroutine mask_calving
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! routine calculate_calving_front_mask
+!
+!> \brief Calculate mask indicating position of effective calving front
+!> \author Matthew Hoffman
+!> \date Feb. 2018
+!> \details Mmake mask for effective calving front.
+!> This is last dynamic floating cell, but also make sure it has a neighbor that is open ocean or thin floating ice.
+!-----------------------------------------------------------------------
+ subroutine calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), intent(in) :: meshPool !< Input: Mesh pool
+ type (mpas_pool_type), intent(in) :: geometryPool !< Input: geometry pool
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, dimension(:), intent(out) :: calvingFrontMask !< Output: calving front mask
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ integer, pointer :: nCells
+ integer :: iCell, iNeighbor, jCell, jNeighbor, kCell
+ logical :: oceanNeighborCell, oceanNeighborEdge
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:,:), pointer :: edgesOnCell ! list of edges that neighbor each cell
integer, dimension(:), pointer :: cellMask
real (kind=RKIND), dimension(:), pointer :: bedTopography
real (kind=RKIND), pointer :: config_sea_level
@@ -1362,30 +3192,37 @@ subroutine calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask
call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ !calvingFrontMaskEdge = 0 !initialize
calvingFrontMask = 0 !initialize
do iCell = 1, nCells
if ( (li_mask_is_floating_ice(cellMask(iCell))) .and. (li_mask_is_dynamic_margin(cellMask(iCell))) ) then
- oceanNeighbor = .false.
+ oceanNeighborCell = .false.
do iNeighbor = 1, nEdgesOnCell(iCell)
jCell = cellsOnCell(iNeighbor, iCell)
+ oceanNeighborEdge = .false.
if (li_mask_is_floating_ice(cellMask(jCell)) .and. .not. li_mask_is_dynamic_ice(cellMask(jCell))) then
! make sure this neighbor is adjacent to open ocean (and not thin floating ice up against the coast)
do jNeighbor = 1, nEdgesOnCell(jCell)
kCell = cellsOnCell(jNeighbor, jCell)
if (.not. li_mask_is_ice(cellMask(kCell)) .and. bedTopography(kCell) < config_sea_level) then
- oceanNeighbor = .true. ! iCell neighbors thin ice that in turn neighbors open ocean
+ oceanNeighborEdge = .true. ! iCell neighbors thin ice that in turn neighbors open ocean
endif
enddo
endif
if (.not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level) then
- oceanNeighbor = .true. ! this is an open ocean neighbor
+ oceanNeighborEdge = .true. ! this is an open ocean neighbor
endif
+ !if (oceanNeighborEdge) then
+ ! calvingFrontMaskEdge(edgesOnCell(iNeighbor, iCell)) = 1
+ !endif
+ oceanNeighborCell = (oceanNeighborCell .or. oceanNeighborEdge)
enddo
- if (oceanNeighbor) then
+ if (oceanNeighborCell) then
calvingFrontMask(iCell) = 1
endif
endif
@@ -1394,6 +3231,216 @@ subroutine calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask
end subroutine calculate_calving_front_mask
+ subroutine remove_icebergs(domain)
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: domain !< Input/Output: domain object
+
+
+ ! Local variables
+ logical, pointer :: config_remove_icebergs
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: velocityPool
+
+ type (field1dInteger), pointer :: contiguousDynamicIceField
+ type (field1dInteger), pointer :: contiguousDynamicIceOldField
+
+ real (kind=RKIND), dimension(:), pointer :: calvingThickness ! thickness of ice that calves (computed in this subroutine)
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ integer, dimension(:), pointer :: cellMask
+ integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell
+ integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell
+
+ integer, dimension(:), pointer :: contiguousDynamicIce, contiguousDynamicIceOld
+ integer, pointer :: nCells, nCellsSolve
+ integer, dimension(:), pointer :: nCellsArray
+ integer :: iCell, jCell, n
+ integer :: newMaskCountLocal, newMaskCountLocalAccum, newMaskCountGlobal
+ integer :: err_tmp, err
+ integer :: globalLoopCount, localLoopCount
+ integer :: localIcebergCellCount, globalIcebergCellCount
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_remove_icebergs', config_remove_icebergs)
+ if (.not. config_remove_icebergs) then
+ return ! skip this entire routine if disabled
+ endif
+
+ call mpas_timer_start("iceberg detection")
+ call mpas_log_write("Iceberg-detection flood-fill begin.")
+ ! Allocate needed scratch fields
+
+ block => domain % blocklist
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_field(geometryPool, 'contiguousDynamicIce', contiguousDynamicIceField)
+ call mpas_allocate_scratch_field(contiguousDynamicIceField, single_block_in = .false.)
+
+ call mpas_pool_get_field(geometryPool, 'contiguousDynamicIceOld', contiguousDynamicIceOldField)
+ call mpas_allocate_scratch_field(contiguousDynamicIceOldField, single_block_in = .false.)
+
+ call mpas_log_write("Iceberg-detection flood-fill: allocated.")
+ ! First mark grounded ice to initialize flood fill mask
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'contiguousDynamicIce', contiguousDynamicIce)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_dimension(geometryPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+
+ ! make sure masks are up to date. May not be necessary, but safer to do anyway.
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ call mpas_log_write("Iceberg-detection flood-fill: updated masks.")
+ contiguousDynamicIce(:) = 0 ! initialize
+ newMaskCountLocal = 0
+ do iCell = 1, nCellsSolve
+ if (li_mask_is_grounded_ice(cellMask(iCell)) .and. li_mask_is_dynamic_ice(cellMask(iCell))) then
+ contiguousDynamicIce(iCell) = 1
+ newMaskCountLocal = newMaskCountLocal + 1
+ endif
+ enddo
+ call mpas_log_write("Initialized $i cells to local mask", intArgs=(/newMaskCountLocal/))
+
+ block => block % next
+ end do
+
+ call mpas_log_write("Iceberg-detection flood-fill initialization complete.")
+
+ ! Outer loop over processors (should also have a loop over blocks)
+ ! Inner loop over cells on that processor
+
+ ! Initialize global mask count
+ call mpas_dmpar_sum_int(domain % dminfo, newMaskCountLocal, newMaskCountGlobal)
+ globalLoopCount = 0
+
+ call mpas_log_write("Initialized $i cells to global mask", intArgs=(/newMaskCountGlobal/))
+
+ do while (newMaskCountGlobal > 0)
+ globalLoopCount = globalLoopCount + 1
+ call mpas_log_write(" Starting global processor loop $i", intArgs=(/globalLoopCount/))
+ ! First Update halos
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'contiguousDynamicIce')
+ call mpas_timer_stop("halo updates")
+
+ ! initialize counter of cells locally updated during this outer loop
+ newMaskCountLocalAccum = 0
+
+ ! Now update (advance) mask locally
+
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'contiguousDynamicIce', contiguousDynamicIce)
+ call mpas_pool_get_array(geometryPool, 'contiguousDynamicIceOld', contiguousDynamicIceOld)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_dimension(meshPool, 'nCellsArray', nCellsArray)
+
+
+ ! initialize local loop
+ localLoopCount = 0
+ newMaskCountLocal = 1 ! need to make sure we enter the loop
+ do while (newMaskCountLocal > 0)
+ localLoopCount = localLoopCount + 1
+ call mpas_log_write(" Starting local cell loop $i", intArgs=(/localLoopCount/))
+
+ ! initialize
+ newMaskCountLocal = 0
+ contiguousDynamicIceOld(:) = contiguousDynamicIce(:)
+
+ do iCell = 1, nCellsArray(1) ! this gives owned cells only
+ if (contiguousDynamicIceOld(iCell) == 0 .and. & ! this cell not yet marked
+ li_mask_is_dynamic_ice(cellMask(iCell))) then ! and is dynamic
+ ! If it has a marked neighbor, then add it to the mask
+ do n = 1, nEdgesOnCell(iCell)
+ jCell = cellsOnCell(n, iCell)
+ if (contiguousDynamicIceOld(jCell) == 1) then
+ contiguousDynamicIce(iCell) = 1
+ newMaskCountLocal = newMaskCountLocal + 1
+ exit ! skip the rest of this do-loop - no need to check additional neighbors
+ endif
+ enddo
+ endif ! if not already marked
+ enddo ! loop over cells
+
+ ! Accumulate cells added locally until we do the next global reduce
+ newMaskCountLocalAccum = newMaskCountLocalAccum + newMaskCountLocal
+ call mpas_log_write(" Added $i new cells to local mask", intArgs=(/newMaskCountLocal/))
+ enddo ! local mask loop
+
+ block => block % next
+ end do
+
+ ! update count of cells added to mask globally
+ call mpas_dmpar_sum_int(domain % dminfo, newMaskCountLocalAccum, newMaskCountGlobal)
+ call mpas_log_write(" Added $i new cells to global mask", intArgs=(/newMaskCountGlobal/))
+
+ if (globalLoopCount>200) then
+ call mpas_log_write("Too many global loops!", MPAS_LOG_ERR)
+ endif
+ end do ! global loop
+
+
+ ! Now remove any ice that was not flood-filled - these are icebergs
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'contiguousDynamicIce', contiguousDynamicIce)
+ call mpas_pool_get_array(geometryPool, 'contiguousDynamicIceOld', contiguousDynamicIceOld)
+ call mpas_pool_get_dimension(geometryPool, 'nCells', nCells)
+ call mpas_pool_get_dimension(geometryPool, 'nCellsSolve', nCellsSolve)
+
+ contiguousDynamicIceOld(:) = 0
+ do iCell = 1, nCellsSolve
+ if (contiguousDynamicIce(iCell) == 0 .and. li_mask_is_dynamic_ice(cellMask(iCell))) then
+ calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell) ! remove any remaining ice here
+ thickness(iCell) = 0.0_RKIND
+ contiguousDynamicIceOld(iCell) = 1 ! debug: make this a mask of where icebergs were removed
+ endif
+ enddo
+ localIcebergCellCount = sum(contiguousDynamicIceOld)
+
+! where(contiguousDynamicIce == 0 .and. li_mask_is_dynamic_ice(cellMask))
+! calvingThickness = calvingThickness + thickness ! remove any remaining ice here
+! thickness = 0.0_RKIND
+! end where
+
+ block => block % next
+ end do
+
+ ! Calculate total iceberg cells removed (not needed but useful for log - note requires extra reduce!)
+ call mpas_dmpar_sum_int(domain % dminfo, localIcebergCellCount, globalIcebergCellCount)
+
+ ! update halo - probably not needed?
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'thickness')
+ call mpas_timer_stop("halo updates")
+
+ ! clean up
+ call mpas_deallocate_scratch_field(contiguousDynamicIceField, single_block_in=.false.)
+ call mpas_deallocate_scratch_field(contiguousDynamicIceOldField, single_block_in=.false.)
+
+ call mpas_log_write("Iceberg-detection flood-fill complete. Removed $i iceberg cells.", intArgs=(/globalIcebergCellCount/))
+ call mpas_timer_stop("iceberg detection")
+ end subroutine remove_icebergs
+
+
end module li_calving
diff --git a/src/core_landice/mode_forward/mpas_li_core.F b/src/core_landice/mode_forward/mpas_li_core.F
index f8ebbb81db..2e19d28344 100644
--- a/src/core_landice/mode_forward/mpas_li_core.F
+++ b/src/core_landice/mode_forward/mpas_li_core.F
@@ -456,7 +456,8 @@ function li_core_run(domain) result(err)
! write the timestamp to file
call mpas_new_unit(restartTimestampUnit)
- open(restartTimestampUnit, file=config_restart_timestamp_name, form='formatted', status='replace', iostat=err_tmp2)
+ open(restartTimestampUnit, file=config_restart_timestamp_name, form='formatted', &
+ status='replace', iostat=err_tmp2)
if (err_tmp2 > 0) then
call mpas_log_write('Error opening file to write restart timestamp:' // &
trim(config_restart_timestamp_name), MPAS_LOG_ERR)
@@ -896,7 +897,7 @@ subroutine landice_init_block(block, dminfo, err)
! Init for reconstruction of velocity
! Note: mpas_init_reconstruct fails with the MISMIP3d periodic mesh
! because x_period and y_period are not set properly.
- ! That should be fixed for that test, but a workaround is to
+ ! That should be fixed for that test, but a workaround is to
! disable these two calls for those runs.
call mpas_rbf_interp_initialize(meshPool)
call mpas_init_reconstruct(meshPool)
@@ -1036,7 +1037,8 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr)
call mpas_set_time(curr_time=stopTime, dateTimeString=config_stop_time, ierr=err_tmp)
ierr = ior(ierr,err_tmp)
if(startTime + runduration /= stopTime) then
- call mpas_log_write('config_run_duration and config_stop_time are inconsistent: using config_run_duration.', MPAS_LOG_WARN)
+ call mpas_log_write('config_run_duration and config_stop_time are inconsistent: using config_run_duration.', &
+ MPAS_LOG_WARN)
end if
end if
else if (trim(config_stop_time) /= "none") then
diff --git a/src/core_landice/mode_forward/mpas_li_core_interface.F b/src/core_landice/mode_forward/mpas_li_core_interface.F
index db27f38305..df57153dee 100644
--- a/src/core_landice/mode_forward/mpas_li_core_interface.F
+++ b/src/core_landice/mode_forward/mpas_li_core_interface.F
@@ -100,6 +100,9 @@ function li_setup_packages(configPool, packagePool, iocontext) result(ierr)
! Local variables
character (len=StrKIND), pointer :: config_velocity_solver
+ character (len=StrKIND), pointer :: config_basal_mass_bal_float
+ character (len=StrKIND), pointer :: config_front_mass_bal_grounded
+ character (len=StrKIND), pointer :: config_thermal_solver
logical, pointer :: config_SGH
logical, pointer :: config_adaptive_timestep_include_DCFL
logical, pointer :: config_write_albany_ascii_mesh
@@ -108,17 +111,26 @@ function li_setup_packages(configPool, packagePool, iocontext) result(ierr)
logical, pointer :: SIAvelocityActive
logical, pointer :: hydroActive
logical, pointer :: observationsActive
+ logical, pointer :: ismip6ShelfMeltActive
+ logical, pointer :: ismip6GroundedFaceMeltActive
+ logical, pointer :: thermalActive
ierr = 0
call mpas_pool_get_config(configPool, 'config_velocity_solver', config_velocity_solver)
call mpas_pool_get_config(configPool, 'config_SGH', config_SGH)
call mpas_pool_get_config(configPool, 'config_write_albany_ascii_mesh', config_write_albany_ascii_mesh)
+ call mpas_pool_get_config(configPool, 'config_basal_mass_bal_float', config_basal_mass_bal_float)
+ call mpas_pool_get_config(configPool, 'config_front_mass_bal_grounded', config_front_mass_bal_grounded)
+ call mpas_pool_get_config(configPool, 'config_thermal_solver', config_thermal_solver)
call mpas_pool_get_package(packagePool, 'SIAvelocityActive', SIAvelocityActive)
call mpas_pool_get_package(packagePool, 'higherOrderVelocityActive', higherOrderVelocityActive)
call mpas_pool_get_package(packagePool, 'hydroActive', hydroActive)
call mpas_pool_get_package(packagePool, 'observationsActive', observationsActive)
+ call mpas_pool_get_package(packagePool, 'ismip6ShelfMeltActive', ismip6ShelfMeltActive)
+ call mpas_pool_get_package(packagePool, 'ismip6GroundedFaceMeltActive', ismip6GroundedFaceMeltActive)
+ call mpas_pool_get_package(packagePool, 'thermalActive', thermalActive)
if (trim(config_velocity_solver) == 'sia') then
SIAvelocityActive = .true.
@@ -141,6 +153,26 @@ function li_setup_packages(configPool, packagePool, iocontext) result(ierr)
"'config_write_albany_ascii_mesh' is set to .true.")
endif
+ if (trim(config_basal_mass_bal_float) == 'ismip6') then
+ ismip6ShelfMeltActive = .true.
+ call mpas_log_write("The 'ismip6Melt' package and assocated variables have been enabled because " // &
+ "'config_basal_mass_bal_float' is set to 'ismip6'")
+ endif
+
+ if (trim(config_front_mass_bal_grounded) == 'ismip6') then
+ ismip6GroundedFaceMeltActive=.true.
+ call mpas_log_write("The 'ismip6GroundedFaceMelt' package and assocated variables have been enabled because " // &
+ "'config_front_mass_bal_grounded' is set to 'ismip6'")
+ endif
+
+ if ((trim(config_thermal_solver) == 'temperature') .or. (trim(config_thermal_solver) == 'enthalpy')) then
+ thermalActive = .true.
+ call mpas_log_write("The 'thermal' package and assocated variables have been enabled because " // &
+ "'config_thermal_solver' is set to either 'temperature' or 'enthalpy'.")
+ endif
+
+
+
! call setup packages in analysis driver
call li_analysis_setup_packages(configPool, packagePool, ierr)
diff --git a/src/core_landice/mode_forward/mpas_li_diagnostic_vars.F b/src/core_landice/mode_forward/mpas_li_diagnostic_vars.F
index 82c9db2659..ab47f0d226 100644
--- a/src/core_landice/mode_forward/mpas_li_diagnostic_vars.F
+++ b/src/core_landice/mode_forward/mpas_li_diagnostic_vars.F
@@ -376,7 +376,7 @@ end subroutine li_calculate_apparent_diffusivity
!> transition temperature (-10 deg C at 0 pressure).
!> Values for $A0, Q, \Phi$ differ from PB1982.
!>
-!> All options are adjusted by the enhancement factor (which defaults to 1.0).
+!> The result is NOT adjusted by an enhancement factor.
!-----------------------------------------------------------------------
subroutine li_calculate_flowParamA(meshPool, temperature, thickness, flowParamA, err)
@@ -417,7 +417,6 @@ subroutine li_calculate_flowParamA(meshPool, temperature, thickness, flowParamA,
integer, pointer :: nCells, nVertLevels
character (len=StrKIND), pointer :: config_flowParamA_calculation
real (kind=RKIND), pointer :: config_default_flowParamA, &
- config_enhancementFactor, &
config_dynamic_thickness, &
config_ice_density
integer :: iCell, iLevel, err_tmp
@@ -434,7 +433,6 @@ subroutine li_calculate_flowParamA(meshPool, temperature, thickness, flowParamA,
call mpas_pool_get_array(meshPool, 'layerCenterSigma', layerCenterSigma)
call mpas_pool_get_config(liConfigs, 'config_flowParamA_calculation', config_flowParamA_calculation)
- call mpas_pool_get_config(liConfigs, 'config_enhancementFactor', config_enhancementFactor)
call mpas_pool_get_config(liConfigs, 'config_default_flowParamA', config_default_flowParamA)
call mpas_pool_get_config(liConfigs, 'config_dynamic_thickness', config_dynamic_thickness)
call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density)
@@ -499,10 +497,6 @@ subroutine li_calculate_flowParamA(meshPool, temperature, thickness, flowParamA,
end select
!print *,'max flwa', maxval(flowParamA)
- !print *,'config_enhancementFactor', config_enhancementFactor
-
- ! Include enhancement factor
- flowParamA = flowParamA * config_enhancementFactor
err = ior(err, err_tmp)
diff --git a/src/core_landice/mode_forward/mpas_li_iceshelf_melt.F b/src/core_landice/mode_forward/mpas_li_iceshelf_melt.F
new file mode 100644
index 0000000000..130a043bf0
--- /dev/null
+++ b/src/core_landice/mode_forward/mpas_li_iceshelf_melt.F
@@ -0,0 +1,1396 @@
+! Copyright (c) 2013-2018, Los Alamos National Security, LLC (LANS)
+! and the University Corporation for Atmospheric Research (UCAR).
+!
+! Unless noted otherwise source code is licensed under the BSD license.
+! Additional copyright and license information can be found in the LICENSE file
+! distributed with this code, or at http://mpas-dev.github.com/license.html
+!
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! li_iceshelf_melt
+!
+!> \brief MPAS land ice vertical temperature/enthalpy solver
+!> \author William Lipscomb
+!> \date October 2015
+!> \details
+!> This module contains solvers for the vertical temperature
+!> and/or enthalpy profile.
+!
+!-----------------------------------------------------------------------
+
+module li_iceshelf_melt
+
+ use mpas_derived_types
+ use mpas_pool_routines
+ use mpas_dmpar
+ use mpas_timer
+ use mpas_abort
+ use mpas_log
+
+ use li_setup
+ use li_mask
+ use li_constants
+
+ implicit none
+ private
+
+ !--------------------------------------------------------------------
+ !
+ ! Public parameters
+ !
+ !--------------------------------------------------------------------
+
+ !--------------------------------------------------------------------
+ !
+ ! Public member functions
+ !
+ !--------------------------------------------------------------------
+
+ public :: li_basal_melt_floating_ice, li_face_melt_grounded_ice
+
+ !--------------------------------------------------------------------
+ !
+ ! Private module variables
+ !
+ !--------------------------------------------------------------------
+
+!***********************************************************************
+ contains
+!***********************************************************************
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine li_face_melt_grounded_ice
+!
+!> \brief MPAS land ice solver for face melt of grounded ice
+!> \author Trevor Hillebrand
+!> \date February 2021
+!> \details
+!> This routine computes face melting for floating ice.
+!> The following options are supported:
+!> (1) Do nothing (config_front_mass_bal_grounded = 'none')
+!> (2) Prescribed uniform face melt speed (config_front_mass_bal_grounded = 'uniform')
+!> (3) Face melt speed as in ISMIP6 (config_front_mass_bal_grounded = 'ismip6')
+
+!-----------------------------------------------------------------------
+
+ subroutine li_face_melt_grounded_ice(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ type (block_type), pointer :: block
+
+ type (mpas_pool_type), pointer :: geometryPool
+ character(len=StrKIND), pointer :: &
+ config_front_mass_bal_grounded ! option for submarine mass balance
+ ! at grounded glacier front
+ real (kind=RKIND), dimension(:), pointer :: faceMeltSpeed, faceMeltingThickness
+ integer :: err_tmp
+
+ err = 0
+ err_tmp = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_front_mass_bal_grounded', config_front_mass_bal_grounded)
+
+ if ( trim(config_front_mass_bal_grounded) == 'ismip6' &
+ .or. trim(config_front_mass_bal_grounded) == 'uniform' ) then
+ call grounded_face_melt_ismip6(domain, err_tmp)
+ err = ior(err, err_tmp)
+ elseif ( trim(config_front_mass_bal_grounded) == 'none' ) then
+ ! Zero entire field
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_array(geometryPool, 'faceMeltSpeed', faceMeltSpeed)
+ call mpas_pool_get_array(geometryPool, 'faceMeltingThickness', faceMeltingThickness)
+
+ faceMeltSpeed(:) = 0.0_RKIND
+ faceMeltingThickness(:) = 0.0_RKIND
+
+ block => block % next
+ enddo ! associated(block)
+ else
+ call mpas_log_write('Unknown option selected for config_front_mass_bal_grounded:' // &
+ trim(config_front_mass_bal_grounded), MPAS_LOG_ERR)
+ err = ior(err, 1)
+ endif
+
+ end subroutine li_face_melt_grounded_ice
+!-----------------------------------------------------------------------
+!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||r
+!
+! ! routine li_basal_melt_floating_ice
+!
+!> \brief MPAS land ice solver for basal melt of floating ice
+!> \author William Lipscomb
+!> \date November 2015
+!> \details
+!> This routine computes basal melting for floating ice.
+!> The following options are supported:
+!> (1) Do nothing (config_basal_mass_bal_float = 'none')
+!> (2) Read melt rate from a file (config_basal_mass_bal_float = 'file')
+!> (2) Prescribed constant basal melt rate (config_basal_mass_bal_float = 'constant')
+!> (3) Basal melt rate as in MISMIP+ (config_basal_mass_bal_float = 'mismip')
+
+!-----------------------------------------------------------------------
+
+ subroutine li_basal_melt_floating_ice(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ type (block_type), pointer :: block
+
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: geometryPool
+ type (mpas_pool_type), pointer :: velocityPool ! needed for mask subroutine
+ type (mpas_pool_type), pointer :: scratchPool
+
+ integer, pointer :: &
+ nCellsSolve ! number of locally owned cells
+
+ logical, pointer :: &
+ config_print_thermal_info ! if true, print debug info
+
+ character(len=StrKIND), pointer :: &
+ config_basal_mass_bal_float ! option for basal mass balance of floating ice
+
+ character(len=StrKIND), pointer :: &
+ config_front_mass_bal_grounded ! option for submarine mass balance
+ ! at grounded glacier front
+
+ real(kind=RKIND), pointer :: &
+ config_thermal_thickness, & ! minimum thickness (m) for temperature calculations
+ config_sea_level, & ! sea level (m) relative to z = 0
+ config_bmlt_float_flux, & ! constant heat flux (W/m^2) applied to the base of floating ice; positive upward
+ config_bmlt_float_xlimit ! x value (m) defining region where bmlt_float_flux is applied;
+ ! melt only where abs(x) > xlimit
+ real (kind=RKIND), pointer :: config_ice_density !< ice density
+
+ integer, dimension(:), pointer :: &
+ cellMask ! bit mask describing whether ice is floating, dynamically active, etc.
+
+ type (field1dInteger), pointer :: thermalCellMaskField
+
+ integer, dimension(:), pointer :: &
+ thermalCellMask ! mask for thermal calculations
+ ! = 1 where thickness > config_thermal_thickness, elsewhere = 0
+
+ real (kind=RKIND), dimension(:), pointer :: &
+ xCell ! x coordinate for each cell (m)
+
+ real (kind=RKIND), dimension(:), pointer :: &
+ floatingBasalMassBal, & ! basal mass balance for floating ice
+ thickness, & ! ice thickness (m)
+ lowerSurface, & ! lower surface elevation (m)
+ bedTopography ! bed topography (m; negative below sea level)
+
+ real(kind=RKIND), pointer :: daysSinceStart
+
+ integer :: iCell, err_tmp
+
+ ! Local variables for some melt methods
+
+ real(kind=RKIND) :: &
+ bmlt_float_rate ! constant basal melt rate (m/s)
+ ! = config_bmlt_float_flux / (config_ice_density*latent_heat_ice)
+ real(kind=RKIND) :: hCavity ! depth of ice cavity beneath floating ice (m)
+ real(kind=RKIND) :: zDraft ! draft of floating ice (m below sea level)
+
+ ! basal melting parameters for MISMIP+ experiment
+ ! Note: These could be made user-configurable, but are hardwired for now because there are no plans
+ ! to run MISMIP+ with different values
+ real(kind=RKIND), parameter :: &
+ bmlt_float_omega = 0.20_RKIND / scyr, & ! time scale for basal melting (s^-1)
+ ! MISMIP+ default value = 0.2 yr^-1
+ bmlt_float_h0 = 75._RKIND, & ! scale for sub-shelf cavity thickness (m)
+ ! MISMIP+ default value = 75 m
+ bmlt_float_z0 = -100._RKIND ! scale for ice draft (m)
+ ! MISMIP+ default value = -100 m
+
+ real(kind=RKIND) :: GLdepth, CFdepth ! ice shelf draft stats needed by the temperature_profile method:
+ ! characteristic grounding line depth, calving front depth
+
+
+ err = 0
+ err_tmp = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_float', config_basal_mass_bal_float)
+ call mpas_pool_get_config(liConfigs, 'config_front_mass_bal_grounded', config_front_mass_bal_grounded)
+ call mpas_pool_get_config(liConfigs, 'config_print_thermal_info', config_print_thermal_info)
+
+ if (config_print_thermal_info) then
+ call mpas_log_write('Solving for basal melting of floating ice, config_basal_mass_bal_float = ' // &
+ trim(config_basal_mass_bal_float) )
+ endif
+
+ ! Simple options handled here
+ if (trim(config_basal_mass_bal_float) == 'none') then
+
+ ! Zero entire field
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
+
+ floatingBasalMassBal = 0.0_RKIND
+
+ block => block % next
+ enddo ! associated(block)
+
+ return ! skip the rest of this routine
+
+ elseif (trim(config_basal_mass_bal_float) == 'file') then
+
+ return ! already set; nothing to do
+
+ endif
+
+ ! get rest of config variables
+ call mpas_pool_get_config(liConfigs, 'config_thermal_thickness', config_thermal_thickness)
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ call mpas_pool_get_config(liConfigs, 'config_bmlt_float_flux', config_bmlt_float_flux)
+ call mpas_pool_get_config(liConfigs, 'config_bmlt_float_xlimit', config_bmlt_float_xlimit)
+ call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density)
+
+ ! The temp-profile method needs a global reduction before it can operate, so do that here
+ ! before the main option block
+ if (trim(config_basal_mass_bal_float) == 'temperature_profile') then
+ call calc_iceshelf_draft_info(domain, GLdepth, CFdepth, err_tmp)
+ err = ior(err, err_tmp)
+ if (config_print_thermal_info) then
+ call mpas_log_write('GLdepth=$r, CFdepth=$r', realArgs=(/GLdepth, CFdepth/))
+ endif
+ endif
+
+ if (trim(config_basal_mass_bal_float) == 'ismip6') then
+ call iceshelf_melt_ismip6(domain, err_tmp)
+ err = ior(err, err_tmp)
+
+ return ! do not enter block loop below - we are done here
+ endif
+
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+
+ ! get pools
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
+
+ ! get dimensions
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+
+ ! get fields from the mesh pool
+ call mpas_pool_get_array(meshPool, 'xCell', xCell)
+ call mpas_pool_get_array(meshPool, 'daysSinceStart',daysSinceStart)
+
+ ! get fields from the geometry pool
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
+
+ ! get fields from the scratch pool
+ call mpas_pool_get_field(scratchPool, 'iceCellMask', thermalCellMaskField)
+ call mpas_allocate_scratch_field(thermalCellMaskField, .true.)
+ thermalCellMask => thermalCellMaskField % array
+
+ ! calculate masks - so we know where the ice is floating
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ ! calculate a mask to identify ice that is thick enough to be thermally active
+ do iCell = 1, nCellsSolve
+ if (thickness(iCell) > config_thermal_thickness) then
+ thermalCellMask(iCell) = 1
+ else
+ thermalCellMask(iCell) = 0
+ endif
+ enddo
+
+ ! -----------------
+ ! Compute basal melting for floating ice.
+ ! -----------------
+
+ ! initialize to zero melt
+ floatingBasalMassBal(:) = 0.0_RKIND
+ if (trim(config_basal_mass_bal_float) == 'none') then
+ ! Do nothing, handled above
+
+ elseif (trim(config_basal_mass_bal_float) == 'file') then
+ ! Do nothing, handled above
+
+ elseif (trim(config_basal_mass_bal_float) == 'constant') then
+
+ ! set melt rate to a constant value for floating ice
+ ! allow basal melt in ice-free ocean cells, in case ice is advected to those cells by the transport scheme
+
+ bmlt_float_rate = config_bmlt_float_flux / (config_ice_density*latent_heat_ice) ! convert W/m^2 to m/s
+
+ floatingBasalMassBal(:) = 0.0_RKIND
+
+ do iCell = 1, nCellsSolve
+ if ( (li_mask_is_floating_ice(cellMask(iCell))) .or. &
+ (bedTopography(iCell) < config_sea_level .and. thermalCellMask(iCell) == 0) ) then
+ ! ice is present and floating, or ice-free ocean
+
+ ! Provided xCell > bmlt_float_xlimit, prescribe a uniform basal melt rate.
+ ! The default is 0.0, but for MISMIP+ the prescribed value of xlimit is 480 km.
+ if (abs(xCell(iCell)) >= config_bmlt_float_xlimit) then ! basal melting is allowed
+ floatingBasalMassBal(iCell) = -bmlt_float_rate
+ endif
+
+ endif ! ice is present and floating
+
+ enddo ! iCell
+
+ ! change units from m/s to kg/m2/s
+ floatingBasalMassBal(:) = floatingBasalMassBal(:) * config_ice_density
+
+ elseif (trim(config_basal_mass_bal_float) == 'mismip') then
+
+ ! compute melt rate (m/s) based on bed depth and cavity thickness
+ ! The MISMIP+ formula is as follows:
+ !
+ ! bmlt_float = omega * tanh(H_c/H_0) * max(z_0 - z_d, 0)
+ !
+ ! where H_c = lsrf - topg is the cavity thickness
+ ! z_d = lsrf - eus is the ice draft
+ ! omega = a time scale = 0.2 yr^{-1} by default
+ ! H_0 = 75 m by default
+ ! z_0 = -100 m by default
+
+ ! allow basal melt in ice-free ocean cells, in case ice is advected to those cells by the transport scheme
+
+ floatingBasalMassBal(:) = 0.0_RKIND
+
+ do iCell = 1, nCellsSolve
+
+ if ( (li_mask_is_floating_ice(cellMask(iCell))) .or. &
+ (bedTopography(iCell) < config_sea_level .and. thermalCellMask(iCell) == 0) ) then
+ ! ice is present and floating, or ice-free ocean
+
+ hCavity = lowerSurface(iCell) - bedTopography(iCell)
+ zDraft = lowerSurface(iCell) - config_sea_level
+ floatingBasalMassBal(iCell) = -bmlt_float_omega * tanh(hCavity/bmlt_float_h0) * max(bmlt_float_z0 - &
+ zDraft, 0.0_RKIND)
+
+ endif ! ice is present and floating
+ enddo ! iCell
+
+ ! change units from m/s to kg/m2/s
+ floatingBasalMassBal(:) = floatingBasalMassBal(:) * config_ice_density
+
+ elseif (trim(config_basal_mass_bal_float) == 'seroussi') then
+
+ call basal_melt_thwaites_seroussi(floatingBasalMassBal, daysSinceStart, lowerSurface, cellMask, &
+ config_sea_level, config_ice_density, nCellsSolve, err_tmp)
+ err = ior(err, err_tmp)
+
+ elseif (trim(config_basal_mass_bal_float) == 'temperature_profile') then
+
+ call iceshelf_melt_param_from_temp_profile(nCellsSolve, lowerSurface, cellMask, &
+ config_sea_level, config_ice_density, config_print_thermal_info, &
+ GLdepth, CFdepth, daysSinceStart, floatingBasalMassBal, err_tmp)
+ err = ior(err, err_tmp)
+
+ else
+
+ call mpas_log_write('Unknown option selected for config_basal_mass_bal_float:' // &
+ trim(config_basal_mass_bal_float), MPAS_LOG_ERR)
+ err = ior(err, 1)
+
+ endif ! config_basal_mass_bal_float
+
+
+ ! clean up
+ call mpas_deallocate_scratch_field(thermalCellMaskField, .true.)
+
+ block => block % next
+ enddo ! associated(block)
+
+
+ end subroutine li_basal_melt_floating_ice
+!-----------------------------------------------------------------------
+
+
+!***********************************************************************
+!***********************************************************************
+! Private subroutines:
+!***********************************************************************
+!***********************************************************************
+
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine basal_melt_thwaites_seroussi
+!
+!> \brief Calculate ice shelf melt rate from depth param.
+!> \author William Lipscomb
+!> \date November 2015
+!> \details
+!> Melt rate parameterization from:
+!> Seroussi, H., Y. Nakayama, E. Larour, D. Menemenlis, M. Morlighem, E. Rignot, and A. Khazendar (2017),
+!> Continued retreat of Thwaites Glacier, West Antarctica, controlled by bed topography and ocean circulation,
+!> Geophys. Res. Lett., 1-9, doi:10.1002/2017GL072910.
+!> for Thwaites Glacier.
+!> Specifically, this is a linear fit of melt with shelf draft from the Supplemental Information, Figure S1.
+!> The linear relation is modified by a:
+!> * depth above which there is no melt (Antarctic Surface Water saturation)
+!> * a maximum melt rate (Circumpolar Deep Water saturation)
+!> * a depth below which melt stops increasing (minimum sill height)
+
+!-----------------------------------------------------------------------
+
+ subroutine basal_melt_thwaites_seroussi(floatingBasalMassBal, daysSinceStart, lowerSurface, cellMask, &
+ config_sea_level, config_ice_density, nCellsSolve, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ real(kind=RKIND), pointer, intent(in) :: daysSinceStart
+ real (kind=RKIND), dimension(:), pointer, intent(in) :: lowerSurface !< lower surface elevation (m)
+ integer, dimension(:), pointer, intent(in) :: &
+ cellMask !< bit mask describing whether ice is floating, dynamically active, etc.
+ real(kind=RKIND), pointer, intent(in) :: &
+ config_sea_level !< sea level (m) relative to z = 0
+ real (kind=RKIND), pointer, intent(in) :: config_ice_density !< ice density
+ integer, pointer :: &
+ nCellsSolve !< number of locally owned cells
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ real (kind=RKIND), dimension(:), pointer, intent(out) :: &
+ floatingBasalMassBal !< basal mass balance for floating ice
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ real (kind=RKIND) :: slopeSer ! slope of relation between depth and melt rate
+ real (kind=RKIND) :: interceptSer ! depth at which melting goes to 0
+ real (kind=RKIND) :: maxMeltSer ! maximum allowable melt rate
+ real (kind=RKIND) :: sillDepth ! depth below which melt rate no longer increases
+ real (kind=RKIND), pointer :: config_basal_mass_bal_seroussi_amplitude
+ real (kind=RKIND), pointer :: config_basal_mass_bal_seroussi_period
+ real (kind=RKIND), pointer :: config_basal_mass_bal_seroussi_phase
+ real(kind=RKIND) :: hCavity ! depth of ice cavity beneath floating ice (m)
+ real(kind=RKIND) :: zDraft ! draft of floating ice (m below sea level)
+ integer :: iCell
+
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_seroussi_amplitude', &
+ config_basal_mass_bal_seroussi_amplitude) ! meters
+ call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_seroussi_period', &
+ config_basal_mass_bal_seroussi_period) ! years
+ call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_seroussi_phase', &
+ config_basal_mass_bal_seroussi_phase) ! cycles
+
+ slopeSer = 0.088_RKIND ! slope of relation between depth and melt rate (melt (m/yr) per depth (m))
+ interceptSer = -100.0_RKIND ! depth (m) at which melting goes to 0 (negative meaning below sea level)
+ maxMeltSer = 50.0_RKIND ! maximum allowable melt rate (m/yr) (positive meaning melting)
+ sillDepth = -650.0_RKIND ! depth below which melt stops increasing (m) (negative meaning below sea level)
+
+ if (config_basal_mass_bal_seroussi_period <= 0.0_RKIND) then
+ call mpas_log_write("Value for config_basal_mass_bal_seroussi_period has to be a positive real value.", MPAS_LOG_ERR)
+ err = ior(err, 1)
+ endif
+
+ ! Modify intercept height for variability parameters
+ interceptSer = interceptSer + config_basal_mass_bal_seroussi_amplitude * &
+ sin( (2.0_RKIND * pii / config_basal_mass_bal_seroussi_period) * (daysSinceStart/365.0_RKIND) &
+ + 2.0_RKIND * pii * config_basal_mass_bal_seroussi_phase)
+
+ ! Initialize before computing
+ floatingBasalMassBal(:) = 0.0_RKIND
+
+ do iCell = 1, nCellsSolve
+
+ ! Shut off melt at an arbitrary shallow depth to discourage ice from disappearing.
+ if ( (li_mask_is_floating_ice(cellMask(iCell))) .and. (lowerSurface(iCell) < -10.0_RKIND) ) then
+ ! ice is present and floating
+
+ zDraft = lowerSurface(iCell) - config_sea_level
+ ! Coefficients for m/yr melt rate (in units of Seroussi figure but without negative meaning melting)
+ floatingBasalMassBal(iCell) = max(-1.0_RKIND * maxMeltSer, min(0.0_RKIND, slopeSer * &
+ (max(zDraft, sillDepth) - interceptSer)))
+
+ endif ! ice is present
+ enddo ! iCell
+
+ ! change units from m/yr to kg/m2/s
+ floatingBasalMassBal(:) = floatingBasalMassBal(:) * config_ice_density / scyr
+
+
+ end subroutine basal_melt_thwaites_seroussi
+!-----------------------------------------------------------------------
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine iceshelf_melt_param_from_temp_profile
+!
+!> \brief Calculate ice shelf melt rate using parameterization based on ocean temperature profile
+!> \author Matthew Hoffman, based on parameterization developed by Xylar Asay-Davis
+!> \date October 2018
+!> \details Melt rate parameterization by Xylar Asay-Davis used in Thwaites variability paper
+!> in prep. by Hoffman et al.
+!> Parameterization takes a ocean temperature profile and sill depth as input.
+!> The temp. profile is adjusted for cavity temperature behind the sill,
+!> assuming constant temp. below the sill depth.
+!> Then a local temp profile in the boundary layer is estimated assuming exponential
+!> decay from the cavity profile to a plume profile at infinite distance downstream
+!> from the grounding line, accounting for the pressure-melt temperature.
+!> The melt rate is calculated as proportional to the product of the boundary layer
+!> temperature profile and the mean cavity temperature.
+!-----------------------------------------------------------------------
+
+ subroutine iceshelf_melt_param_from_temp_profile(nCellsSolve, lowerSurface, cellMask, &
+ config_sea_level, config_ice_density, print_debug, zGL, zCavityMax, daysSinceStart, floatingBasalMassBal, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ integer, intent(in) :: nCellsSolve !< number of locally owned cells
+ real (kind=RKIND), dimension(:), intent(in) :: lowerSurface !< ice shelf draft
+ integer, dimension(:), intent(in) :: cellMask !< bitmask on cells
+ real (kind=RKIND), intent(in) :: config_sea_level, config_ice_density
+ logical, intent(in) :: print_debug
+ real(kind=RKIND), intent(in) :: zGL, & !< mean grounding line elevation (m),
+ !< it's a scalar now, but eventually may want smoothed spatial field
+ zCavityMax !< depth below which mean thermal forcing is averaged
+ real(kind=RKIND), pointer, intent(in) :: daysSinceStart
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ real (kind=RKIND), dimension(:), intent(out) :: floatingBasalMassBal !< BMB for ice shelves
+ integer, intent(out) :: err
+
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ ! parameters for param.
+ real(kind=RKIND), pointer :: slopeDraft !< characteristic slope of ice shelf draft
+ real(kind=RKIND), pointer :: plumeThickness !< characteristic plume thickness (m)
+ real(kind=RKIND), parameter :: E0 = 0.036_RKIND !< entrainment parameter (Jenkins 1991)
+ real(kind=RKIND), parameter :: Stanton = 5.9e-4_RKIND !< Stanton number (Jenkins et al. 2010)
+
+ ! All depths are written as elevation relative to sea level (negative values)
+ ! variables describing regional profile
+ real(kind=RKIND), pointer :: zThermoclineTopBase
+ !< depth at top of thermocline (temp assumed constant above this), before variability adjustment
+ real(kind=RKIND), pointer :: zThermoclineBotBase
+ !< depth at bottom of thermocline (temp assumed constant below this), before variability adjustment
+ real(kind=RKIND) :: zThermoclineTop
+ !< depth at top of thermocline (temp assumed constant above this), after variability adjustment
+ real(kind=RKIND) :: zThermoclineBot
+ !< depth at bottom of thermocline (temp assumed constant below this), after variability adjustment
+ real(kind=RKIND), pointer :: TThermoclineTop !< temperature at top of thermocline (constant shallow water mass temp.)
+ real(kind=RKIND), pointer :: TThermoclineBot !< temperature at bottom of thermocline (constant deep water mass temp.)
+
+ real(kind=RKIND), pointer :: variabilityAmplitude !< amplitude in optional sinusoidal variab. applied to thermocline depths
+ real(kind=RKIND), pointer :: variabilityPeriod !< period in optional sinusoidal variability applied to thermocline depths
+ real(kind=RKIND), pointer :: variabilityPhase !< phase in optional sinusoidal variability applied to thermocline depths
+ real(kind=RKIND) :: depthOffset !< depth offset in thermocline depths due to variability
+
+ ! variables that are general to any depth
+ real(kind=RKIND), pointer :: zSill !< sill depth
+ real(kind=RKIND) :: TSill !< temperature at the sill depth
+ real(kind=RKIND) :: TGL !< temperature at grounding line depth
+ real(kind=RKIND) :: TFmean !< mean thermal forcing within the cavity
+ real(kind=RKIND), pointer :: kappa !< constant for non-local, quadratic melt param.
+ ! variables specific to a given depth
+ real(kind=RKIND) :: draft !< elevation of ice shelf draft (m)
+ real(kind=RKIND) :: Tregional !< regional temperature at given depth (comes from imposed profile)
+ real(kind=RKIND) :: Tcavity !< temperature in cavity at given depth
+ real(kind=RKIND) :: Tfreeze !< freezing temperature at given depth
+ real(kind=RKIND) :: Tinfinity !< limit of exponential decay of T at given depth
+ real(kind=RKIND) :: Tplume !< temperature in plume at a given depth
+ real(kind=RKIND) :: zeta !< length scale of decay of plume temperature
+
+ ! other
+ integer :: nLevels
+ integer :: iCell, z
+ real(kind=RKIND) :: zr
+
+ err = 0
+
+ ! get namelist options
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_melt_scale_factor', kappa)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_sill_elevation', zSill)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_plume_thickness', plumeThickness)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_draft_slope', slopeDraft)
+ ! Get temp. profile parameters
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_thermocline_upper_depth', zThermoclineTopBase)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_thermocline_upper_temp', TThermoclineTop)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_thermocline_lower_depth', zThermoclineBotBase)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_thermocline_lower_temp', TThermoclineBot)
+ ! Get variability parameters
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_variability_amplitude', variabilityAmplitude)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_variability_period', variabilityPeriod)
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_variability_phase', variabilityPhase)
+
+
+ ! Account for variability in thermocline depth
+ if (variabilityPeriod <= 0.0_RKIND) then
+ call mpas_log_write("Value for config_temperature_profile_variability_period must be a positive real value.", &
+ MPAS_LOG_ERR)
+ err = ior(err, 1)
+ endif
+ depthOffset = variabilityAmplitude * sin( (2.0_RKIND * pii / variabilityPeriod) * (daysSinceStart/365.0_RKIND) &
+ + 2.0_RKIND * pii * variabilityPhase)
+ zThermoclineTop = zThermoclineTopBase + depthOffset
+ zThermoclineBot = zThermoclineBotBase + depthOffset
+
+ ! Calculate variables independent of depth
+ zeta = slopeDraft * plumeThickness / (E0 * slopeDraft + Stanton)
+
+ ! calculate temperature at sill
+ if (zSill >= zThermoclineTop) then
+ TSill = TThermoclineTop
+ elseif (zSill <= zThermoclineBot) then
+ TSill = TThermoclineBot
+ else
+ TSill = (TThermoclineTop - TThermoclineBot) * &
+ (zSill - zThermoclineBot) / (zThermoclineTop - zThermoclineBot) + TThermoclineBot
+ endif
+ if (print_debug) then
+ call mpas_log_write("kappa=$r, plumeThickness=$r, slopeDraft=$r, zeta=$r", realArgs=(/kappa, plumeThickness, &
+ slopeDraft, zeta/))
+ call mpas_log_write("TSill=$r at zSill=$r", realArgs=(/TSill, zSill/))
+ endif
+
+ ! calculate temperature at GL (allowing for no sill - sill deeper than GL depth)
+ if (zGL < zSill) then
+ TGL = TSill
+ elseif (zGL >= zThermoclineTop) then
+ TGL = TThermoclineTop
+ elseif (zGL <= zThermoclineBot) then
+ TGL = TThermoclineBot
+ else
+ TGL = (TThermoclineTop - TThermoclineBot) * &
+ (zGL - zThermoclineBot) / (zThermoclineTop - zThermoclineBot) + TThermoclineBot
+ endif
+ if (print_debug) then
+ call mpas_log_write("TGL=$r at zGL=$r", realArgs=(/TGL, zGL/))
+ endif
+
+ ! Need to calculate a mean thermal forcing within the plume
+ ! Ideally this would be a function of the ice shelf hypsometry,
+ ! but for simplicity calculate assuming a linear (ramp) ice shelf shape.
+ ! Average between the GL depth and an arbitrary ice shelf thickness at calving front.
+ ! (We think that is better than averaging all the way to surface, even if that thin
+ ! shelf thickness does not match that of the modeled ice shelf.)
+ TFmean = 0.0_RKIND
+ nLevels = 0
+ do z = ceiling(zGL), floor(zCavityMax), 1 ! Discretize in 1 m increments
+ zr = real(z, kind=RKIND) ! convert once to real data type
+ nLevels = nLevels + 1
+ ! calculate Tcavity for this depth (allowing for no sill - sill deeper than GL depth)
+ if (zr < zSill) then
+ Tcavity = TSill
+ elseif (zr >= zThermoclineTop) then
+ Tcavity = TThermoclineTop
+ elseif (zr <= zThermoclineBot) then
+ Tcavity = TThermoclineBot
+ else
+ Tcavity = (TThermoclineTop - TThermoclineBot) * &
+ (zr - zThermoclineBot) / (zThermoclineTop - zThermoclineBot) + TThermoclineBot
+ endif
+ ! calculate Tfreeze for this depth
+ Tfreeze = ocean_freezing_temperature(zr)
+ ! calculate Tinfinity for this depth
+ Tinfinity = (E0 * slopeDraft * Tcavity + Stanton * Tfreeze) / (E0 * slopeDraft + Stanton)
+ ! calculate Tplume for this depth
+ Tplume = Tinfinity + (TGL - Tinfinity) * exp(min(-1.0_RKIND * (zr - zGL) / zeta, 0.0_RKIND))
+ ! now add to sum of TFmean
+ TFmean = TFmean + (Tplume - Tfreeze)
+ enddo
+ ! now find the average
+ if (nLevels > 0) then
+ TFmean = TFmean / real(nLevels, kind=RKIND)
+ else
+ call mpas_log_write("iceshelf_melt_param_from_temp_profile found 0 levels over which to average mean thermal forcing!",&
+ MPAS_LOG_ERR)
+ err = ior(err, 1)
+ endif
+ if (print_debug) then
+ call mpas_log_write("TFmean=$r", realArgs=(/TFmean/))
+ endif
+
+ ! Now calculate melt rate at each grid cell
+ do iCell = 1, nCellsSolve
+ if (li_mask_is_floating_ice(cellMask(iCell))) then
+ if (lowerSurface(iCell) > -20.0_RKIND) then
+ ! Shut off melt at an arbitrary shallow depth to prevent ice from melting out entirely
+ floatingBasalMassBal(iCell) = 0.0_RKIND
+ else
+ ! Calculate melt rate here
+ draft = lowerSurface(iCell) - config_sea_level
+ ! calculate Tcavity for this depth (allowing for no sill - sill deeper than GL depth)
+ if (draft < zSill) then
+ Tcavity = TSill
+ elseif (draft >= zThermoclineTop) then
+ Tcavity = TThermoclineTop
+ elseif (draft <= zThermoclineBot) then
+ Tcavity = TThermoclineBot
+ else
+ Tcavity = (TThermoclineTop - TThermoclineBot) * &
+ (draft - zThermoclineBot) / (zThermoclineTop - zThermoclineBot) + TThermoclineBot
+ endif
+ ! calculate Tfreeze for this depth
+ Tfreeze = ocean_freezing_temperature(draft)
+ ! calculate Tinfinity for this depth
+ Tinfinity = (E0 * slopeDraft * Tcavity + Stanton * Tfreeze) / (E0 * slopeDraft + Stanton)
+ ! calculate Tplume for this depth
+ Tplume = Tinfinity + (TGL - Tinfinity) * exp(min(-1.0_RKIND * (draft - zGL) / zeta, 0.0_RKIND))
+ ! now add to sum of TFmean
+ floatingBasalMassBal(iCell) = kappa * TFmean * (Tplume - Tfreeze) ! in m/yr, +=melting
+ !floatingBasalMassBal(iCell) = Tplume
+ endif
+ else ! not floating
+ floatingBasalMassBal(iCell) = 0.0_RKIND
+ endif
+ enddo
+ floatingBasalMassBal(:) = floatingBasalMassBal(:) * (-1.0_RKIND) * config_ice_density / scyr ! convert to BMB
+
+ end subroutine iceshelf_melt_param_from_temp_profile
+!-----------------------------------------------------------------------
+
+
+ function ocean_freezing_temperature(depth) result(temp)
+ real(kind=RKIND), intent(in) :: depth
+ real(kind=RKIND), parameter :: Sref = 34.4_RKIND !< Reference salinity (made up, typical for MISOMIP1)
+ real(kind=RKIND) :: temp
+
+ ! function to calculate freezing temperature from Jenkins (1991)
+ temp = 0.0901_RKIND - 0.0575_RKIND * SRef + 7.61e-4_RKIND * depth
+
+ end function ocean_freezing_temperature
+!-----------------------------------------------------------------------
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine calc_iceshelf_draft_info
+!
+!> \brief Calculate characteristic grounding line and calving front depths underneath ice shelves
+!> \author Matthew Hoffman
+!> \date October 2018
+!> \details Grounding line and calving front depths are used by the
+!> temperature_profile iceshelf melt method, but must be calculated before the
+!> method is called because they require a global reduce.
+!> Different options for how to calculated these depths could be implemented.
+!> For the GL depth, an approximation of the mean depth of deepest specified-fraction of the
+!> grounding line is used. For the CF depth, the mean of the calving front
+!> is used.
+!-----------------------------------------------------------------------
+
+ subroutine calc_iceshelf_draft_info(domain, GLdepth, CFdepth, err)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ real (kind=RKIND), intent(out) :: GLdepth !< mean grounding line depth
+ real (kind=RKIND), intent(out) :: CFdepth !< mean calving front depth
+ integer, intent(out) :: err
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ type (block_type), pointer :: block
+
+ type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: geometryPool
+
+ integer, pointer :: &
+ nCellsSolve ! number of locally owned cells
+
+ logical, pointer :: &
+ config_print_thermal_info ! if true, print debug info
+
+ real(kind=RKIND), pointer :: &
+ config_sea_level ! sea level (m) relative to z = 0
+
+ integer, dimension(:), pointer :: &
+ cellMask ! bit mask describing whether ice is floating, dynamically active, etc.
+
+ real (kind=RKIND), dimension(:), pointer :: lowerSurface ! lower surface elevation (m)
+
+ real (kind=RKIND), dimension(:), pointer :: areaCell ! cell area (m^2)
+ integer, dimension(:), pointer :: nEdgesOnCell
+ integer, dimension(:,:), pointer :: cellsOnCell
+
+ real(kind=RKIND) :: sumCFdepth, sumCFarea
+ integer :: iCell, jCell
+ real(kind=RKIND), dimension(2) :: localCFSums, globalCFSums ! Vars for CF global reduction
+
+ real(kind=RKIND), parameter :: binWidth = 10.0_RKIND !< width of depth bins in meters
+ real(kind=RKIND), parameter :: binMinimum = -4000.0_RKIND !< depth of bottom of deepest bin in meters
+ integer, parameter :: nBinsMax = 500 !< Maximum possible number of bins - needs to be set to cover the range
+ !< defined by the previous two variables and sea level (which is run-time configurable)
+ integer :: nBins !< number of bins - calculated below
+ real(kind=RKIND), dimension(nBinsMax) :: binDepth !< depth in m at bottom of each bin
+ real(kind=RKIND), dimension(nBinsMax) :: binWeightSum !< sum of cell weights in this bin
+ real(kind=RKIND), dimension(nBinsMax) :: binWeightedDepthSum !< weighted-depth sum over cells in this bin
+ real(kind=RKIND), dimension(2*nBinsMax) :: localGLSums, globalGLSums ! Vars for GL global reduction
+ real(kind=RKIND) :: cumBinWeightedDepthSum, cumBinWeightSum !< cumulative sums over bins for final calculation
+ real(kind=RKIND) :: totalBinWeight !< sum of weights in all bins
+ real(kind=RKIND), pointer :: weightThreshold !< fraction of deepest GL depths to average overn
+
+ integer :: indexBin
+
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_temperature_profile_GL_depth_fraction', weightThreshold)
+
+ ! need to first determine bin info (could happen on init, but cheap to recompute each timestep)
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ nBins = ceiling((config_sea_level - binMinimum) / binWidth) ! round up
+ do indexBin = 1, nBins
+ binDepth = binMinimum + real(indexBin-1, kind=RKIND) * binWidth ! calc. lower limit of each bin
+ enddo
+
+ ! Calculate average GL and CF depths on this processor, looping over blocks.
+ ! Note that these are somewhat approximate calculations.
+ ! Note that the GL in cellMask includes grounded cells next to open ocean,
+ ! which we do NOT want included, so instead we here identify the GL depth at
+ ! cells that are floating and have a grounded neighbor.
+ ! (Also, the GL cell mask identifies the last grounded cell, not the first floating cell,
+ ! which also isn't what we want.)
+ ! Also, ideally the weighted average for GL and CF depths would be weighted
+ ! based on GL and CF lengths. That is substantially more work for little
+ ! expected improvement (and we would have to make a decision about what elevation to
+ ! assign to edges), so I instead use cell area weighted averages.
+ ! The GL and CF depths do not need to be highly accurate, so these approximations
+ ! are assumed to be fine.
+ binWeightSum(:) = 0.0_RKIND
+ binWeightedDepthSum(:) = 0.0_RKIND
+ sumCFdepth = 0.0_RKIND
+ sumCFarea = 0.0_RKIND
+ ! init bins for GL calcs
+ ! block loop
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+
+ do iCell = 1, nCellsSolve
+ ! First calc. GL stat
+ if (li_mask_is_floating_ice(cellMask(iCell)) .and. li_mask_is_dynamic_ice(cellMask(iCell))) then
+ ! See if a neighbor is grounded ice
+ do jCell = 1, nEdgesOnCell(iCell)
+ if (li_mask_is_grounded_ice(cellMask(cellsOnCell(jCell, iCell)))) then ! we found the first floating cell
+ ! check for reasonable values first
+ if (lowerSurface(iCell) < binMinimum) then
+ call mpas_log_write("calc_iceshelf_draft_info found a grounding line depth below the minimum search " // &
+ "depth of $r. Adjust binMinimum and related parameters and recompile.", &
+ MPAS_LOG_ERR, realArgs = (/binMinimum/))
+ err = ior(err, 1)
+ return
+ elseif (lowerSurface(iCell) > config_sea_level) then
+ call mpas_log_write("calc_iceshelf_draft_info found a grounding line depth above sea level."&
+ // " Adjust hard-coded parameters and recompile.", MPAS_LOG_ERR)
+ err = ior(err, 1)
+ return
+ endif
+ ! Find which bin this location falls in
+ indexBin = floor((lowerSurface(iCell) - binMinimum) / binWidth) + 1
+
+
+ ! Use the sqrt of cell area as the weighting function (it should be a linear measure, not an area measure)
+ binWeightedDepthSum(indexBin) = binWeightedDepthSum(indexBin) + lowerSurface(iCell) * sqrt(areaCell(iCell))
+ binWeightSum(indexBin) = binWeightSum(indexBin) + sqrt(areaCell(iCell))
+ !call mpas_log_write("GL cell: $i, $r, $r", intArgs=(/iCell/), &
+ !realArgs=(/lowerSurface(iCell), areaCell(iCell)/))
+ exit ! skip the rest of the loop around neighbors
+ endif
+ enddo
+ endif
+ ! Now calc. CF stat
+ if (li_mask_is_floating_ice(cellMask(iCell)) .and. li_mask_is_dynamic_margin(cellMask(iCell))) then
+ ! accumulate area-weighted CF depth and area
+ sumCFdepth = sumCFdepth + lowerSurface(iCell) * areaCell(iCell)
+ sumCFarea = sumCFarea + areaCell(iCell)
+ endif
+ enddo
+
+ block => block % next
+ enddo ! associated(block)
+
+ ! --- Global reduction for GL stat ---
+ ! pack communication array
+ localGLSums(1:nBins) = binWeightedDepthSum(1:nBins)
+ localGLSums(nBins+1:2*nBins) = binWeightSum(1:nBins)
+ ! global reduction
+ call mpas_dmpar_sum_real_array(domain % dminfo, 2*nBins, localGLSums(:), globalGLSums(:))
+ ! unpack communication array
+ binWeightedDepthSum(1:nBins) = globalGLSums(1:nBins)
+ binWeightSum(1:nBins) = globalGLSums(nBins+1:2*nBins)
+ ! sum up through bins until threshold is reached
+ totalBinWeight = sum(binWeightSum(1:nBins))
+ if (totalBinweight > 0.0_RKIND) then
+ cumBinWeightedDepthSum = 0.0_RKIND
+ cumBinWeightSum = 0.0_RKIND
+ do indexBin = 1, nBins
+ cumBinWeightedDepthSum = cumBinWeightedDepthSum + binWeightedDepthSum(indexBin)
+ cumBinWeightSum = cumBinWeightSum + binWeightSum(indexBin)
+ ! check if we've reached threshold
+ if (cumBinWeightSum / totalBinweight > weightThreshold) then
+ ! We reached the desired threshold of deepest samples. Make final calculation and quit.
+ GLdepth = cumBinWeightedDepthSum / cumBinWeightSum
+ exit ! skip the rest of the loop over bins
+ endif
+ enddo
+ else
+ ! Most likely situation: no GL! So do nothing.
+ endif
+
+ ! --- Global reduction for CF stat ---
+ localCFSums = (/sumCFdepth, sumCFarea/)
+ ! sum up over all procs
+ call mpas_dmpar_sum_real_array(domain % dminfo, 2, localCFSums(:), globalCFSums(:))
+ if (globalCFSums(2) > 0.0_RKIND) then
+ CFdepth = globalCFSums(1) / globalCFSums(2)
+ else
+ CFdepth = 0.0_RKIND
+ endif
+
+ end subroutine calc_iceshelf_draft_info
+!-----------------------------------------------------------------------
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine iceshelf_melt_ismip6
+!
+!> \brief Calculate ice shelf melt rate using parameterization from ISMIP6
+!> \author Matthew Hoffman
+!> \date July 2019
+!> \details
+!> http://www.climate-cryosphere.org/wiki/index.php?title=ISMIP6-Projections-Antarctica
+!> It is a quadratic method of the form:
+!> melt = gamma * physicalconstant * (TF(x,z,y_draft) + deltaT_basin) * | + deltatT_basin|
+!> where TF is local thermal forcing at each grid cell and is the mean
+!> thermal forcing for all of the ice shelf grid cells in an entire basin
+!-----------------------------------------------------------------------
+
+ subroutine iceshelf_melt_ismip6(domain, err)
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err
+
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ integer :: iCell
+ integer, pointer :: nOceanLayers
+ integer :: ksup, kk, kinf
+ integer, pointer :: nCellsSolve
+ real(kind=RKIND), pointer :: rhoi, rhosw
+ real(kind=RKIND) :: cste
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool, meshPool
+ real (kind=RKIND), dimension(:,:), pointer :: TFocean
+ real (kind=RKIND), dimension(:), pointer :: zOcean
+ real (kind=RKIND), dimension(:), pointer :: TFdraft
+ real (kind=RKIND), dimension(:), pointer :: deltaT
+ real (kind=RKIND), dimension(:), pointer :: ismip6shelfMelt_offset
+ integer, dimension(:), pointer :: basinNumber
+ real (kind=RKIND), dimension(:), pointer :: lowerSurface
+ real (kind=RKIND), dimension(:), pointer :: areaCell
+ real (kind=RKIND), dimension(:), allocatable :: mean_TF, IS_area
+ integer, parameter :: maxNumBasins = 32
+ integer, dimension(:), pointer :: cellMask
+ real(kind=RKIND), dimension(maxNumBasins*2) :: localSums, globalSums
+ real (kind=RKIND), pointer :: gamma0
+ real (kind=RKIND), dimension(:), pointer :: floatingBasalMassBal
+ real (kind=RKIND) :: coef
+ integer :: i
+
+ err = 0
+
+ call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi)
+ call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhosw)
+ cste = (rhosw*cp_seawater/(rhoi*latent_heat_ice))**2 ! in K^(-2)
+
+ allocate(mean_TF(maxNumBasins))
+ allocate(IS_area(maxNumBasins))
+
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_dimension(meshPool, 'nISMIP6OceanLayers', nOceanLayers)
+
+ ! Get 3d thermal forcing (had to be read-in)
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_3dThermalForcing', TFocean)
+
+ ! Get z-coords for ocean data
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_zOcean', zOcean)
+
+ ! Get basin numbers
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_basin', basinNumber)
+
+! NOTE: Would need to do a global max for this check to work
+! if (maxval(basinNumber)+1 > maxNumBasins) then
+! call mpas_log_write("Field ismip6shelfMelt_basin contains a value greater than the hard-coded value" // &
+! "for maxNumBasins in iceshelf_melt_ismip6. Please adjust maxNumBasins and recompile or correct input data.", &
+! MPAS_LOG_ERR)
+! end if
+
+ ! Get shelf draft and mask
+ call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+
+ ! Get TFdraft field that we will calculate
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_TFdraft', TFdraft)
+
+ mean_TF(:) = 0.d0
+ IS_area(:) = 0.d0
+
+ do iCell = 1, nCellsSolve
+
+ if ( li_mask_is_floating_ice(cellMask(iCell)) ) then
+ ! 1 - Linear interpolation of the thermal forcing on the ice draft depth :
+ ksup=1
+ do kk=2,nOceanLayers-1
+ if ( zOcean(kk) >= lowerSurface(iCell) ) ksup = kk
+ enddo
+ kinf = ksup + 1
+ if ((zOcean(ksup)-zOcean(kinf)) == 0) then
+ call mpas_log_write("iceshelf_melt_ismip6: Invalid value for zOcean. " // &
+ "ksup=$i kinf=$i zOcean(ksup)=$r zOcean(kinf)=$r iCell=$i lowerSurface=$r", MPAS_LOG_ERR, &
+ intArgs=(/ksup, kinf, iCell/), &
+ realArgs=(/zOcean(ksup), zOcean(kinf), lowerSurface(iCell) /) )
+ err = ior(err, 1)
+ endif
+ !call mpas_log_write("kinf=$i, zOcean(kinf)=$r, TFocean=$r",realArgs=(/zOcean(kinf),TFocean(kinf,iCell)/), &
+ ! intArgs=(/kinf/))
+ !call mpas_log_write("ksup=$i, zOcean(ksup)=$r, TFocean=$r",realArgs=(/zOcean(ksup),TFocean(ksup,iCell)/), &
+ ! intArgs=(/ksup/))
+ TFdraft(iCell) = ( (zOcean(ksup)-lowerSurface(iCell)) * TFocean(kinf, iCell) &
+ + (lowerSurface(iCell)-zOcean(kinf)) * TFocean(ksup, iCell) ) / (zOcean(ksup)-zOcean(kinf))
+
+ ! 2 - Mean Thermal forcing in individual basins (NB: fortran norm while basins start at zero):
+ mean_TF(basinNumber(iCell)+1) = mean_TF(basinNumber(iCell)+1) + areaCell(iCell) * TFdraft(iCell)
+ IS_area(basinNumber(iCell)+1) = IS_area(basinNumber(iCell)+1) + areaCell(iCell)
+
+ else
+ TFdraft(iCell) = 0.d0
+ endif
+ enddo
+
+ block => block % next
+ enddo ! associated(block)
+
+ ! global sum mean_TF and IS_area
+ localSums(1:maxNumBasins) = mean_TF(:)
+ localSums(maxNumBasins+1:2*maxNumBasins) = IS_area(:)
+ call mpas_dmpar_sum_real_array(domain % dminfo, 2*maxNumBasins, localSums(:), globalSums(:))
+ mean_TF(:) = globalSums(1:maxNumBasins)
+ IS_area(:) = globalSums(maxNumBasins+1:2*maxNumBasins)
+ do i = 1, maxNumBasins
+ if (IS_area(i) > 0.0_RKIND) then
+ mean_TF(i) = mean_TF(i) / IS_area(i) ! actual mean TF per basin
+ call mpas_log_write("basin=$i, mean_TF=$r", intArgs=(/i-1/), realArgs=(/mean_TF(i)/))
+ else ! avoid divide by zero for invalid indices
+ mean_TF(i) = 0.0_RKIND
+ endif
+ enddo
+
+
+ ! Now calculate melt rate
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_gamma0', gamma0)
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_basin', basinNumber)
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_TFdraft', TFdraft)
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_deltaT', deltaT)
+ call mpas_pool_get_array(geometryPool, 'ismip6shelfMelt_offset', ismip6shelfMelt_offset)
+ call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+
+ call mpas_log_write("iceshelf_melt_ismip6: gamma0=$r", realArgs=(/gamma0/))
+ floatingBasalMassBal(:) = 0.0_RKIND
+ coef = gamma0 * cste / scyr * rhoi
+ do iCell = 1, nCellsSolve
+ if ( li_mask_is_floating_ice(cellMask(iCell)) ) then
+ floatingBasalMassBal(iCell) = -1.0_RKIND * coef * (TFdraft(iCell) + deltaT(iCell)) * &
+ abs(mean_TF(basinNumber(iCell)+1) + deltaT(iCell)) + ismip6shelfMelt_offset(iCell)
+ endif
+ enddo
+
+ block => block % next
+ enddo ! associated(block)
+
+ deallocate(mean_TF)
+ deallocate(IS_area)
+
+ end subroutine iceshelf_melt_ismip6
+!-----------------------------------------------------------------------
+
+!-----------------------------------------------------------------------
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine grounded_face_melt_ismip6
+!
+!> \brief Calculate grounded glacier submarine melt rate using parameterization from ISMIP6
+!> \author Trevor Hillebrand
+!> \date April 2020
+!> \details
+!> http://www.climate-cryosphere.org/wiki/index.php?title=ISMIP6-Projections-Greenland
+!> https://www.the-cryosphere.net/14/985/2020/tc-14-985-2020.pdf
+!> https://agupubs-onlinelibrary-wiley-com.lanl.idm.oclc.org/doi/full/10.1002/2016GL068784
+!> Melt parameterization of the form:
+!> melt_rate = (A * h * q_sg^alpha + B) * TF^beta
+!> where TF is local thermal forcing at each grid cell, h is water depth at ice front
+!> q_sg is subglacial water glux in m/day. Default values A = 3e-4, alpha = 0.39, B = 0.15
+!> beta=1.18
+!-----------------------------------------------------------------------
+
+
+ subroutine grounded_face_melt_ismip6(domain, err)
+
+ use li_calving
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ integer, intent(out) :: err
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ integer :: iCell, iNeighbor, iEdge, nEmptyNeighbors
+ real (kind=RKIND), pointer :: rhoi
+ integer, pointer :: nCells, nCellsSolve
+ integer, dimension(:,:), pointer :: cellsOnCell, edgesOnCell
+ real (kind=RKIND) :: waterDepth
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: geometryPool, meshPool, velocityPool
+ real (kind=RKIND), pointer :: seaLevel
+ real (kind=RKIND), dimension(:), pointer :: thickness, faceMeltingThickness
+ real (kind=RKIND), dimension(:), pointer :: bedTopography
+ real (kind=RKIND), dimension(:), pointer :: lowerSurface
+ real (kind=RKIND), dimension(:), pointer :: TFocean, ismip6Runoff
+ real (kind=RKIND), dimension(:), pointer :: areaCell
+ integer, dimension(:), pointer :: cellMask, edgeMask, nEdgesOnCell
+ real (kind=RKIND), pointer :: aSubglacial ! param A
+ real (kind=RKIND), pointer :: alphaSubglacial ! param alpha
+ real (kind=RKIND), pointer :: B ! param B
+ real (kind=RKIND), pointer :: betaTF ! param beta
+ real (kind=RKIND), pointer :: addTFocean ! adjust ocean thermal forcing
+ real (kind=RKIND), pointer :: config_uniform_face_melt_rate
+ character(len=StrKIND), pointer :: config_front_mass_bal_grounded
+ real (kind=RKIND), parameter :: secPerDay = 86400.0_RKIND
+ real (kind=RKIND), parameter :: rhow = 1000.0_RKIND ! subglacial runoff density
+ real (kind=RKIND), dimension(:), pointer :: faceMeltSpeed
+ real (kind=RKIND), dimension(:), allocatable :: faceMeltSpeedVertAvg !vertically averaged faceMeltSpeed
+ !to pass to li_apply_front_ablation_velocity,
+ !because faceMeltSpeed is only below water-line
+ integer :: err_tmp
+ logical :: applyToFloating, applyToGrounded, applyToGroundingLine
+
+ err = 0
+ call mpas_log_write('Starting face melt routine')
+
+ ! Define logicals for call to li_apply_front_ablation_velocity
+ applyToFloating = .false. ! if true, only apply to floating ice
+ applyToGrounded = .false. ! if true, only apply to grounded
+ applyToGroundingLine = .true. ! if true, apply at grounding line
+
+ ! Get sea level, bedTopography, ice density
+ call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi)
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', seaLevel)
+
+ ! Get melt parameters
+ call mpas_pool_get_config(liConfigs, 'config_beta_ocean_thermal_forcing', betaTF)
+ call mpas_pool_get_config(liConfigs, 'config_alpha_subglacial_discharge', alphaSubglacial)
+ call mpas_pool_get_config(liConfigs, 'config_subglacial_discharge_coefficient', aSubglacial)
+ call mpas_pool_get_config(liConfigs, 'config_subglacial_discharge_intercept', B)
+ call mpas_pool_get_config(liConfigs, 'config_add_ocean_thermal_forcing', addTFocean)
+ call mpas_pool_get_config(liConfigs, 'config_uniform_face_melt_rate', config_uniform_face_melt_rate)
+ call mpas_pool_get_config(liConfigs, 'config_front_mass_bal_grounded', config_front_mass_bal_grounded)
+
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+
+ ! Get ISMIP6 forcing fields
+ call mpas_pool_get_array(geometryPool, 'ismip6_2dThermalForcing', TFocean)
+ call mpas_pool_get_array(geometryPool, 'ismip6Runoff', ismip6Runoff)
+
+ ! Get mesh and geometry arrays
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
+ call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
+ call mpas_pool_get_array(geometryPool, 'faceMeltingThickness', faceMeltingThickness)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'faceMeltSpeed', faceMeltSpeed)
+
+ faceMeltSpeed(:) = 0.0_RKIND
+ allocate(faceMeltSpeedVertAvg(nCells+1))
+ faceMeltSpeedVertAvg(:) = 0.0_RKIND
+
+ ! Calculate face melting for each cell
+ do iCell = 1, nCellsSolve
+
+ if ( bedTopography(iCell) < 0.0_RKIND ) then
+ waterDepth = seaLevel - bedTopography(iCell)
+ else
+ waterDepth = 0.0_RKIND
+ endif
+
+ if (trim(config_front_mass_bal_grounded) == 'ismip6') then
+ ! Calculate ice front melt rate at each cell
+ faceMeltSpeed(iCell) = (aSubglacial * waterDepth * & ! m s^-1
+ (ismip6Runoff(iCell) / rhow * secPerDay)**alphaSubglacial &
+ + B) * max(0.0_RKIND, TFocean(iCell) + addTFocean)**betaTF / secPerDay
+ elseif (trim(config_front_mass_bal_grounded) == 'uniform') then
+ faceMeltSpeed(iCell) = config_uniform_face_melt_rate
+ endif
+
+ enddo
+
+ where ( (thickness > 0.0_RKIND) .and. (lowerSurface < 0.0_RKIND) )
+ faceMeltSpeedVertAvg(:) = faceMeltSpeed(:) * abs(lowerSurface(:)) / thickness(:)
+ end where
+
+ call mpas_log_write("calling li_apply_front_ablation_velocity from grounded_face_melt_ismip6")
+ ! Distribute melt among neighbors
+ call li_apply_front_ablation_velocity(meshPool, geometryPool, velocityPool, &
+ faceMeltingThickness, faceMeltSpeedVertAvg, applyToGrounded, &
+ applyToFloating, applyToGroundingLine, domain, err)
+
+
+ ! Update halos on calvingThickness or faceMeltingThickness before applying it.
+ ! Testing seemed to indicate this is not necessary, but I don't understand
+ ! why not, so leaving it.
+ ! NOTE: THIS WILL NOT WORK ON MULTIPLE BLOCKS PER PROCESSOR
+ call mpas_timer_start("halo updates")
+ call mpas_dmpar_field_halo_exch(domain, 'faceMeltingThickness')
+ call mpas_timer_stop("halo updates")
+
+ ! Apply facemelt: open the Ark
+ thickness(:) = thickness(:) - faceMeltingThickness(:)
+
+ ! update mask
+ call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
+ err = ior(err, err_tmp)
+
+ block => block % next
+ enddo ! associated(block)
+
+ deallocate(faceMeltSpeedVertAvg)
+
+ end subroutine grounded_face_melt_ismip6
+!-----------------------------------------------------------------------
+
+
+ !***********************************************************************
+ end module li_iceshelf_melt
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
+
diff --git a/src/core_landice/mode_forward/mpas_li_sia.F b/src/core_landice/mode_forward/mpas_li_sia.F
index dd67a365b0..b22001c4f2 100644
--- a/src/core_landice/mode_forward/mpas_li_sia.F
+++ b/src/core_landice/mode_forward/mpas_li_sia.F
@@ -297,7 +297,7 @@ subroutine li_sia_solve(meshPool, geometryPool, thermalPool, velocityPool, err)
real (kind=RKIND), dimension(:), pointer :: upperSurface
integer, dimension(:,:), pointer :: baryCellsOnVertex
real (kind=RKIND), dimension(:,:), pointer :: baryWeightsOnVertex
- integer :: cell1_is_dynamic, cell2_is_dynamic
+ real (kind=RKIND) :: cell1_is_dynamic, cell2_is_dynamic
integer :: err_tmp
err = 0
@@ -398,8 +398,8 @@ subroutine li_sia_solve(meshPool, geometryPool, thermalPool, velocityPool, err)
if ( li_mask_is_dynamic_ice(edgeMask(iEdge)) ) then
cell1 = cellsOnEdge(1,iEdge)
cell2 = cellsOnEdge(2,iEdge)
- cell1_is_dynamic = li_mask_is_dynamic_ice_int(cellMask(cell1))
- cell2_is_dynamic = li_mask_is_dynamic_ice_int(cellMask(cell2))
+ cell1_is_dynamic = real(li_mask_is_dynamic_ice_int(cellMask(cell1)), kind=RKIND)
+ cell2_is_dynamic = real(li_mask_is_dynamic_ice_int(cellMask(cell2)), kind=RKIND)
! Calculate thickness on edge - 2nd order
thicknessEdge = (thickness(cell1) + thickness(cell2) ) * 0.5_RKIND
@@ -416,9 +416,7 @@ subroutine li_sia_solve(meshPool, geometryPool, thermalPool, velocityPool, err)
do iLevel = nVertInterfaces-1, 1, -1 ! Loop upwards from second lowest level to surface
! Calculate flwa on edge for this level - 2nd order, except can't do centered difference
! into areas where flwa may not be valid, so excluding the downwind flwa value in non-dynamic cells
-! flwaLevelEdge = (flowParamA(iLevel, cell1) + flowParamA(iLevel, cell2) ) * 0.5_RKIND
- flwaLevelEdge = (flowParamA(iLevel, cell1) * cell1_is_dynamic + &
- flowParamA(iLevel, cell2) * cell2_is_dynamic) / &
+ flwaLevelEdge = (flowParamA(iLevel, cell1) * cell1_is_dynamic + flowParamA(iLevel, cell2) * cell2_is_dynamic) / &
(cell1_is_dynamic + cell2_is_dynamic)
! Calculate SIA velocity for this layer interface by adding on incremental velocity for the layer below
diff --git a/src/core_landice/mode_forward/mpas_li_subglacial_hydro.F b/src/core_landice/mode_forward/mpas_li_subglacial_hydro.F
index 0bb10c0312..4fd30f26c8 100644
--- a/src/core_landice/mode_forward/mpas_li_subglacial_hydro.F
+++ b/src/core_landice/mode_forward/mpas_li_subglacial_hydro.F
@@ -93,6 +93,7 @@ subroutine li_SGH_init(domain, err)
!-----------------------------------------------------------------
! Pools pointers
logical, pointer :: config_SGH
+ logical, pointer :: config_ocean_connection_N
type (block_type), pointer :: block
type (mpas_pool_type), pointer :: meshPool
type (mpas_pool_type), pointer :: hydroPool
@@ -117,10 +118,15 @@ subroutine li_SGH_init(domain, err)
call mpas_pool_get_config(liConfigs, 'config_SGH', config_SGH)
if (.not. config_SGH) then
+ call mpas_pool_get_config(liConfigs, 'config_ocean_connection_N', config_ocean_connection_N)
+ if (config_ocean_connection_N) then
+ call ocean_connection_N(domain)
+ endif
! If SGH is not active, skip everything
return
endif
+
call mpas_timer_start("hydro init")
call mpas_log_write('Beginning subglacial hydro init.')
@@ -226,6 +232,7 @@ subroutine li_SGH_solve(domain, err)
!-----------------------------------------------------------------
! Pools pointers
logical, pointer :: config_SGH
+ logical, pointer :: config_ocean_connection_N
logical, pointer :: config_SGH_chnl_active
character (len=StrKIND), pointer :: config_SGH_basal_melt
type (block_type), pointer :: block
@@ -278,6 +285,10 @@ subroutine li_SGH_solve(domain, err)
call mpas_pool_get_config(liConfigs, 'config_SGH', config_SGH)
if (.not. config_SGH) then
+ call mpas_pool_get_config(liConfigs, 'config_ocean_connection_N', config_ocean_connection_N)
+ if (config_ocean_connection_N) then
+ call ocean_connection_N(domain)
+ endif
! If SGH is not active, skip everything
return
endif
@@ -335,7 +346,7 @@ subroutine li_SGH_solve(domain, err)
call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool)
call mpas_pool_get_array(hydroPool, 'basalMeltInput', basalMeltInput)
call mpas_pool_get_array(geometryPool,'groundedBasalMassBal',groundedBasalMassBal)
- basalMeltInput = -1.0 * groundedBasalMassBal ! TODO: Ensure positive flux?
+ basalMeltInput = -1.0_RKIND * groundedBasalMassBal ! TODO: Ensure positive flux?
elseif (trim(config_SGH_basal_melt) == 'basal_heat') then
call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool)
call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
@@ -691,13 +702,16 @@ subroutine calc_edge_quantities(block, err)
type (mpas_pool_type), pointer :: geometryPool
type (mpas_pool_type), pointer :: hydroPool
real (kind=RKIND), dimension(:), pointer :: bedTopography
+ real (kind=RKIND), dimension(:), pointer :: thickness
real (kind=RKIND), dimension(:), pointer :: hydropotentialBase
+ real (kind=RKIND), dimension(:), pointer :: hydropotential
real (kind=RKIND), dimension(:), pointer :: hydropotentialBaseVertex
real (kind=RKIND), dimension(:), pointer :: waterPressure
real (kind=RKIND), dimension(:), pointer :: waterThicknessEdge
real (kind=RKIND), dimension(:), pointer :: waterThicknessEdgeUpwind
real (kind=RKIND), dimension(:), pointer :: waterThickness
real (kind=RKIND), dimension(:), pointer :: hydropotentialBaseSlopeNormal
+ real (kind=RKIND), dimension(:), pointer :: hydropotentialSlopeNormal
real (kind=RKIND), dimension(:), pointer :: waterPressureSlopeNormal
real (kind=RKIND), dimension(:), pointer :: hydropotentialBaseSlopeTangent
real (kind=RKIND), dimension(:), pointer :: gradMagPhiEdge
@@ -720,6 +734,8 @@ subroutine calc_edge_quantities(block, err)
real (kind=RKIND), pointer :: alpha, beta
real (kind=RKIND), pointer :: conduc_coeff
character (len=StrKIND), pointer :: config_SGH_tangent_slope_calculation
+ real (kind=RKIND), pointer :: config_sea_level
+ real (kind=RKIND), pointer :: rhoo
integer, pointer :: nEdges
integer, pointer :: nCells
integer, pointer :: nVertices
@@ -745,14 +761,19 @@ subroutine calc_edge_quantities(block, err)
call mpas_pool_get_config(liConfigs, 'config_SGH_beta', beta)
call mpas_pool_get_config(liConfigs, 'config_SGH_conduc_coeff', conduc_coeff)
call mpas_pool_get_config(liConfigs, 'config_SGH_tangent_slope_calculation', config_SGH_tangent_slope_calculation)
+ call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
+ call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhoo)
call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness)
call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure)
call mpas_pool_get_array(hydroPool, 'hydropotentialBase', hydropotentialBase)
+ call mpas_pool_get_array(hydroPool, 'hydropotential', hydropotential)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_array(hydroPool, 'waterThicknessEdge', waterThicknessEdge)
call mpas_pool_get_array(hydroPool, 'waterThicknessEdgeUpwind', waterThicknessEdgeUpwind)
call mpas_pool_get_array(hydroPool, 'hydropotentialBaseSlopeNormal', hydropotentialBaseSlopeNormal)
+ call mpas_pool_get_array(hydroPool, 'hydropotentialSlopeNormal', hydropotentialSlopeNormal)
call mpas_pool_get_array(hydroPool, 'waterPressureSlopeNormal', waterPressureSlopeNormal)
call mpas_pool_get_array(meshPool, 'dcEdge', dcEdge)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
@@ -767,6 +788,7 @@ subroutine calc_edge_quantities(block, err)
call mpas_pool_get_array(hydroPool, 'waterFluxAdvec', waterFluxAdvec)
call mpas_pool_get_array(hydroPool, 'waterFluxDiffu', waterFluxDiffu)
call mpas_pool_get_array(hydroPool, 'waterFluxMask', waterFluxMask)
+ call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
do iEdge = 1, nEdges
@@ -784,14 +806,74 @@ subroutine calc_edge_quantities(block, err)
endif
hydropotentialBaseSlopeNormal(iEdge) = (hydropotentialBase(cell2) - hydropotentialBase(cell1)) / dcEdge(iEdge)
+ hydropotentialSlopeNormal(iEdge) = (hydropotential(cell2) - hydropotential(cell1)) / dcEdge(iEdge)
waterPressureSlopeNormal(iEdge) = (waterPressure(cell2) - waterPressure(cell1)) / dcEdge(iEdge)
end do
+ ! At terrestrial margin, ignore the downslope bed topography gradient. Including it can lead to unrealistically large
+ ! hydropotential gradients and unstable channel growth.
+ ! We also want to do this at marine margins because otherwise the offshore topography can create a barrier to flow,
+ ! but that is unrealistic.
+ ! So for all boundaries of the hydro system, the hydropotential at the margin should be determined by the geometry
+ ! at the edge of the cell in a 1-sided sense
+ do iEdge = 1, nEdges
+ if ( (li_mask_is_margin(edgeMask(iEdge)) .and. li_mask_is_grounded_ice(edgeMask(iEdge))) .or. &
+ (li_mask_is_grounding_line(edgeMask(iEdge)))) then
+ cell1 = cellsOnEdge(1, iEdge)
+ cell2 = cellsOnEdge(2, iEdge)
+ if (li_mask_is_grounded_ice(cellMask(cell1))) then ! cell2 is the icefree cell - replace phi there with cell1 Phig
+ hydropotentialBaseSlopeNormal(iEdge) = (rho_water * gravity * bedTopography(cell1) + &
+ max(rhoo * gravity * (config_sea_level - bedTopography(cell1)), 0.0_RKIND) - &
+ hydropotentialBase(cell1)) / dcEdge(iEdge)
+ hydropotentialSlopeNormal(iEdge) = (rho_water * gravity * bedTopography(cell1) + &
+ max(rhoo * gravity * (config_sea_level - bedTopography(cell1)), 0.0_RKIND) - &
+ hydropotential(cell1)) / dcEdge(iEdge)
+ else ! cell1 is the icefree cell - replace phi there with cell2 Phig
+ hydropotentialBaseSlopeNormal(iEdge) = (hydropotentialBase(cell2) - &
+ ( rho_water * gravity * bedTopography(cell2) + &
+ max(rhoo * gravity * (config_sea_level - bedTopography(cell2)), 0.0_RKIND) ) ) / dcEdge(iEdge)
+ hydropotentialSlopeNormal(iEdge) = (hydropotential(cell2) - &
+ ( rho_water * gravity * bedTopography(cell2) + &
+ max(rhoo * gravity * (config_sea_level - bedTopography(cell2)), 0.0_RKIND) ) ) / dcEdge(iEdge)
+ endif ! which cell is icefree
+ endif ! if edge of grounded ice
+ end do
+
+ ! Disallow flow from ocean to glacier, or land to glacier,
+ ! which can occur under some circumstances
+ ! For ocean this is invalid because ocean water has a different density!
+ ! For land this would only happen if there is a supply of water, which is not currently handled.
+ ! Do this by simply zeroing the hydropotential gradient in those cases.
+ ! (Do this step only after the other hydropotential special cases are treated above.)
+ do iEdge = 1, nEdges
+ ! Find edges along GL or margin to check for 'backwards' flow
+ if ((li_mask_is_grounding_line(edgeMask(iEdge))) .or. &
+ li_mask_is_margin(edgeMask(iEdge)) ) then
+ ! Now check if flow is backwards
+ cell1 = cellsOnEdge(1, iEdge)
+ cell2 = cellsOnEdge(2, iEdge)
+ if (hydropotentialBaseSlopeNormal(iEdge) > 0.0_RKIND) then
+ ! flow is from cell2 to cell1
+ if (.not. li_mask_is_grounded_ice(cellMask(cell2))) then
+ hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND
+ hydropotentialSlopeNormal(iEdge) = 0.0_RKIND
+ endif
+ else ! phi<=0
+ ! flow is from cell1 to cell2
+ if (.not. li_mask_is_grounded_ice(cellMask(cell1))) then
+ hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND
+ hydropotentialSlopeNormal(iEdge) = 0.0_RKIND
+ endif
+ endif
+ endif ! GL edge or grounded margin
+ end do
+
! Calculate tangent slope of hydropotentialBase - three possible methods to consider
! Calculate hydropotentialBaseVertex if needed
- call mpas_pool_get_array(hydroPool, 'hydropotentialBaseVertex', hydropotentialBaseVertex) ! this array could be protected by logic if desired
+ call mpas_pool_get_array(hydroPool, 'hydropotentialBaseVertex', hydropotentialBaseVertex)
+ ! < this array could be protected by logic if desired
select case (trim(config_SGH_tangent_slope_calculation))
case ('from_vertex_barycentric')
call mpas_pool_get_array(meshPool, 'baryCellsOnVertex', baryCellsOnVertex)
@@ -830,13 +912,8 @@ subroutine calc_edge_quantities(block, err)
gradMagPhiEdge = sqrt(hydropotentialBaseSlopeNormal**2 + hydropotentialBaseSlopeTangent**2)
! calculate effective conductivity on edges
- ! OLD: USE REGULARIZATION: effectiveConducEdge(:) = conduc_coeff * waterThicknessEdge(:)**(alpha-1.0_RKIND) * (gradMagPhiEdge(:)+1.0e-10_RKIND)**(beta - 2.0_RKIND) ! 1e-10 used for regularization
- ! Do not calculate the conductivity where it is tiny to avoid blowups
- where(gradMagPhiEdge < 0.01_RKIND)
- effectiveConducEdge(:) = 0.0_RKIND
- elsewhere
- effectiveConducEdge(:) = conduc_coeff * waterThicknessEdge(:)**(alpha-1.0_RKIND) * gradMagPhiEdge(:)**(beta - 2.0_RKIND)
- end where
+ effectiveConducEdge(:) = conduc_coeff * waterThicknessEdge(:)**(alpha-1.0_RKIND) *&
+ (gradMagPhiEdge(:)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization
! calculate diffusivity on edges
diffusivity(:) = rho_water * gravity * effectiveConducEdge(:) * waterThicknessEdge(:)
@@ -866,6 +943,12 @@ subroutine calc_edge_quantities(block, err)
waterFluxDiffu = 0.0_RKIND
waterVelocity = 0.0_RKIND
end where
+ where (waterThicknessEdgeUpwind == 0.0_RKIND) ! if no water to give, should have no flux!
+ waterFluxAdvec = 0.0_RKIND ! Should already be 0
+ waterFluxDiffu = 0.0_RKIND ! Might not be 0
+ waterVelocity = 0.0_RKIND
+ end where
+
waterFlux(:) = waterFluxAdvec(:) + waterFluxDiffu(:)
!--------------------------------------------------------------------
@@ -923,7 +1006,7 @@ subroutine check_timestep(domain, timeLeft, err)
type (block_type), pointer :: block
real (kind=RKIND), pointer :: deltat
integer, pointer :: nEdgesSolve
- logical, pointer :: config_SGH_chnl_active
+ logical, pointer :: config_SGH_chnl_active, config_SGH_chnl_include_DCFL
! in the following variables, "Proc" indicates the value on the current processor,
! and "Block" indicates value on current block
real (kind=RKIND) :: dtSGHadvecBlock, dtSGHadvecProc
@@ -992,10 +1075,13 @@ subroutine check_timestep(domain, timeLeft, err)
if (config_SGH_chnl_active) then
! Calculate channel advection limited time step
- dtSGHadvecChanBlock = 0.5_RKIND * minval(dcEdge(1:nEdgesSolve) / (abs(channelVelocity(1:nEdgesSolve)) + 1.0e-12_RKIND)) ! regularize
+ dtSGHadvecChanBlock = 0.5_RKIND * minval(dcEdge(1:nEdgesSolve) / (abs(channelVelocity(1:nEdgesSolve)) &
+ + 1.0e-12_RKIND))
+ ! regularize
dtSGHadvecChanProc = min(dtSGHadvecChanProc, dtSGHadvecChanBlock)
! Calculate channel diffusion limited time step
- dtSGHdiffuChanBlock = 0.25_RKIND * minval(dcEdge(1:nEdgesSolve)**2 / (channelDiffusivity(1:nEdgesSolve) + 1.0e-12_RKIND))
+ dtSGHdiffuChanBlock = 0.25_RKIND * minval(dcEdge(1:nEdgesSolve)**2 / (channelDiffusivity(1:nEdgesSolve) + &
+ 1.0e-12_RKIND))
dtSGHdiffuChanProc = min(dtSGHdiffuChanProc, dtSGHdiffuChanBlock)
endif
@@ -1035,11 +1121,15 @@ subroutine check_timestep(domain, timeLeft, err)
! ---
call mpas_pool_get_config(liConfigs, 'config_SGH_adaptive_timestep_fraction', CFLfraction)
call mpas_pool_get_config(liConfigs, 'config_SGH_max_adaptive_timestep', maxDt)
+ call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_include_DCFL', config_SGH_chnl_include_DCFL)
! Find smallest of 3 or 5 limiting time steps
proposedDt = min(deltatSGHadvec, deltatSGHdiffu, deltatSGHpressure)
if (config_SGH_chnl_active) then
- proposedDt = min(proposedDt, deltatSGHadvecChannel, deltatSGHdiffuChannel)
+ proposedDt = min(proposedDt, deltatSGHadvecChannel)
+ if (config_SGH_chnl_include_DCFL) then
+ proposedDt = min(proposedDt, deltatSGHdiffuChannel)
+ endif
endif
proposedDt = proposedDt * CFLfraction
@@ -1048,7 +1138,8 @@ subroutine check_timestep(domain, timeLeft, err)
if (proposedDt >= timeLeft) then
if (config_SGH_chnl_active) then
call mpas_log_write("deltatSGH: used=$r, advec=$r, diffu=$r, pressure=$r, advecChannel=$r, diffuChannel=$r", &
- realArgs=(/deltatSGH, deltatSGHadvec, deltatSGHdiffu, deltatSGHpressure, deltatSGHadvecChannel, deltatSGHdiffuChannel/))
+ realArgs=(/deltatSGH, deltatSGHadvec, deltatSGHdiffu, deltatSGHpressure, deltatSGHadvecChannel, &
+ deltatSGHdiffuChannel/))
else
call mpas_log_write("deltatSGH: used=$r, advec=$r, diffu=$r, pressure=$r", &
realArgs=(/deltatSGH, deltatSGHadvec, deltatSGHdiffu, deltatSGHpressure/))
@@ -1092,10 +1183,12 @@ subroutine check_timestep(domain, timeLeft, err)
call mpas_log_write("deltatSGH > deltatSGHpressure $r > $r", MPAS_LOG_WARN, realArgs=(/deltatSGH, deltatSGHpressure/))
endif
if (config_SGH_chnl_active .and. (deltatSGH > deltatSGHadvecChannel)) then
- call mpas_log_write("deltatSGH > deltatSGHadvecChannel $r > $r", MPAS_LOG_WARN, realArgs=(/deltatSGH, deltatSGHadvecChannel/))
+ call mpas_log_write("deltatSGH > deltatSGHadvecChannel $r > $r", MPAS_LOG_WARN, &
+ realArgs=(/deltatSGH, deltatSGHadvecChannel/))
endif
- if (config_SGH_chnl_active .and. (deltatSGH > deltatSGHdiffuChannel)) then
- call mpas_log_write("deltatSGH > deltatSGHdiffuChannel $r > $r", MPAS_LOG_WARN, realArgs=(/deltatSGH, deltatSGHdiffuChannel/))
+ if (config_SGH_chnl_active .and. config_SGH_chnl_include_DCFL .and. (deltatSGH > deltatSGHdiffuChannel)) then
+ call mpas_log_write("deltatSGH > deltatSGHdiffuChannel $r > $r", MPAS_LOG_WARN, &
+ realArgs=(/deltatSGH, deltatSGHdiffuChannel/))
endif
!--------------------------------------------------------------------
@@ -1163,10 +1256,12 @@ subroutine calc_pressure(block, err)
real (kind=RKIND), pointer :: creepCoeff
real (kind=RKIND), pointer :: porosity
integer, pointer :: nVertLevels
+ integer, pointer :: nCells
character (len=StrKIND), pointer :: config_SGH_pressure_calc
real (kind=RKIND), pointer :: config_sea_level
real (kind=RKIND), pointer :: rhoo
integer :: err_tmp
+ integer :: iCell
err = 0
err_tmp = 0
@@ -1189,6 +1284,7 @@ subroutine calc_pressure(block, err)
call mpas_pool_get_config(liConfigs, 'config_SGH_pressure_calc', config_SGH_pressure_calc)
call mpas_pool_get_dimension(meshPool, 'nVertLevels', nVertLevels)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure)
call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure)
@@ -1217,7 +1313,8 @@ subroutine calc_pressure(block, err)
! basalMeltInput(:) / rhoi ! Hewitt 2011 opening
openingRate = max(0.0_RKIND, openingRate)
- closingRate(:) = creepCoeff * flowParamA(nVertLevels, :) * effectivePressure(:)**3 * waterThickness(:)
+ closingRate(:) = creepCoeff * flowParamA(nVertLevels, :) * &
+ effectivePressure(:)**3 * waterThickness(:)
! closingRate(:) = waterThickness(:) * effectivePressure(:) / 1.0e13_RKIND
! ! Hewitt 2011 creep closure form. Denominator is ice viscosity
@@ -1234,7 +1331,8 @@ subroutine calc_pressure(block, err)
elsewhere (.not. li_mask_is_ice(cellMask))
waterPressure = 0.0_RKIND
elsewhere
- waterPressure = (zeroOrderSum - divergence - divergenceChannel - channelAreaChangeCell) * rho_water * gravity * deltatSGH / porosity + waterPressureOld
+ waterPressure = (zeroOrderSum - divergence - divergenceChannel - channelAreaChangeCell) * &
+ rho_water * gravity * deltatSGH / porosity + waterPressureOld
end where
case ('overburden')
@@ -1254,10 +1352,12 @@ subroutine calc_pressure(block, err)
waterPressure = max(0.0_RKIND, waterPressure)
waterPressure = min(waterPressure, rhoi * gravity * thickness)
! set pressure correctly under floating ice and open ocean
- where ( (li_mask_is_floating_ice(cellMask)) .or. &
- ((.not. li_mask_is_ice(cellMask)) .and. (bedTopography < config_sea_level) ) )
- waterPressure = rhoo * gravity * (config_sea_level - bedTopography)
- end where
+ do iCell = 1, nCells
+ if ( li_mask_is_floating_ice(cellMask(iCell)) .or. &
+ ((.not. li_mask_is_ice(cellMask(iCell))) .and. (bedTopography(iCell) < config_sea_level) ) ) then
+ waterPressure(iCell) = rhoo * gravity * (config_sea_level - bedTopography(iCell))
+ endif
+ enddo
waterPressureTendency = (waterPressure - waterPressureOld) / deltatSGH
@@ -1330,8 +1430,9 @@ subroutine calc_pressure_diag_vars(block, err)
call mpas_pool_get_array(hydroPool, 'hydropotential', hydropotential)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
- effectivePressure = rhoi * gravity * thickness - waterPressure ! this should evalute to 0 for floating ice if Pw set correctly there.
- where (.not. li_mask_is_ice(cellmask))
+ effectivePressure = rhoi * gravity * thickness - waterPressure
+ ! < this should evalute to 0 for floating ice if Pw set correctly there.
+ where (.not. li_mask_is_grounded_ice(cellmask))
effectivePressure = 0.0_RKIND ! zero effective pressure where no ice to avoid confusion
end where
@@ -1400,7 +1501,7 @@ subroutine update_channel(block, err)
real (kind=RKIND), dimension(:), pointer :: channelVelocity
real (kind=RKIND), dimension(:), pointer :: gradMagPhiEdge
real (kind=RKIND), dimension(:), pointer :: waterFlux
- real (kind=RKIND), dimension(:), pointer :: hydropotentialBaseSlopeNormal
+ real (kind=RKIND), dimension(:), pointer :: hydropotentialSlopeNormal
real (kind=RKIND), dimension(:), pointer :: waterPressureSlopeNormal
real (kind=RKIND), dimension(:), pointer :: channelOpeningRate
real (kind=RKIND), dimension(:), pointer :: channelClosingRate
@@ -1445,7 +1546,7 @@ subroutine update_channel(block, err)
call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge)
call mpas_pool_get_array(hydroPool, 'channelVelocity', channelVelocity)
call mpas_pool_get_array(hydroPool, 'gradMagPhiEdge', gradMagPhiEdge)
- call mpas_pool_get_array(hydroPool, 'hydropotentialBaseSlopeNormal', hydropotentialBaseSlopeNormal)
+ call mpas_pool_get_array(hydroPool, 'hydropotentialSlopeNormal', hydropotentialSlopeNormal)
call mpas_pool_get_array(hydroPool, 'waterPressureSlopeNormal', waterPressureSlopeNormal)
call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux)
call mpas_pool_get_array(hydroPool, 'channelOpeningRate', channelOpeningRate)
@@ -1465,7 +1566,8 @@ subroutine update_channel(block, err)
where(gradMagPhiEdge < 0.01_RKIND)
channelDischarge(:) = 0.0_RKIND
elsewhere
- channelDischarge = -1.0_RKIND * Kc * channelArea**alpha_c * gradMagPhiEdge**(beta_c - 2.0_RKIND) * hydropotentialBaseSlopeNormal
+ channelDischarge = -1.0_RKIND * Kc * channelArea**alpha_c * gradMagPhiEdge**(beta_c - 2.0_RKIND) * &
+ hydropotentialSlopeNormal
end where
where (waterFluxMask == 2)
@@ -1473,12 +1575,20 @@ subroutine update_channel(block, err)
channelArea = 0.0_RKIND
end where
- ! Note: an edge with only one grounded cell neighbor is called floating, so this logic retains channel vars on those edges to allow channel discharge across GL
+ ! Note: an edge with only one grounded cell neighbor is called floating, so this logic retains channel vars
+ ! on those edges to allow channel discharge across GL
where (.not. ( (li_mask_is_grounded_ice(edgeMask)) .or. (li_mask_is_grounding_line(edgeMask)) ) )
channelArea = 0.0_RKIND
channelDischarge = 0.0_RKIND
end where
+ ! Disable channels from forming if there is no sheet flux
+ ! TODO: Make a function of sheet dissipation threshold?
+ where (abs(waterFlux) <= 1e-10_RKIND)
+ channelArea = 0.0_RKIND
+ channelDischarge = 0.0_RKIND
+ end where
+
channelVelocity = channelDischarge / (channelArea + 1.0e-12_RKIND)
! diffusivity used only to limit channel dt right now
@@ -1489,8 +1599,8 @@ subroutine update_channel(block, err)
Kc * channelArea**(alpha_c - 1.0_RKIND) * gradMagPhiEdge**(beta_c - 2.0_RKIND))
end where
- channelMelt = (abs(channelDischarge * hydropotentialBaseSlopeNormal) & ! channel dissipation
- + abs(waterFlux * hydropotentialBaseSlopeNormal * config_SGH_incipient_channel_width) & ! some sheet dissipation
+ channelMelt = (abs(channelDischarge * hydropotentialSlopeNormal) & ! channel dissipation
+ + abs(waterFlux * hydropotentialSlopeNormal * config_SGH_incipient_channel_width) & !some sheet dissipation
) / latent_heat_ice
channelPressureFreeze = -1.0_RKIND * iceMeltingPointPressureDependence * cp_freshwater * rho_water * &
(channelDischarge + waterFlux * config_SGH_incipient_channel_width) &
@@ -1509,7 +1619,7 @@ subroutine update_channel(block, err)
cell2 = cellsOnEdge(2, iEdge)
! Not sure if these ought to be upwind average, but using centered
- flowParamAChannel(iEdge) = 0.5_RKIND * ( flowParamA(nVertLevels, cell1) + flowParamA(nVertLevels, cell2) )
+ flowParamAChannel(iEdge) = 0.5_RKIND * (flowParamA(nVertLevels, cell1) + flowParamA(nVertLevels, cell2) )
channelEffectivePressure(iEdge) = 0.5_RKIND * (effectivePressure(cell1) + effectivePressure(cell2))
end do
channelClosingRate(:) = creep_coeff * channelArea(:) * flowParamAChannel(:) * channelEffectivePressure(:)**3
@@ -1599,7 +1709,8 @@ subroutine evolve_channel(block, err)
iEdge = edgesOnCell(iEdgeOnCell, iCell)
! add on advective & diffusive fluxes
divergenceChannel(iCell) = divergenceChannel(iCell) - channelDischarge(iEdge) * edgeSignOnCell(iEdgeOnCell, iCell)
- channelAreaChangeCell(iCell) = channelChangeRate(iEdge) * dcEdge(iEdge) * 0.5_RKIND ! only half of channel is in this cell
+ channelAreaChangeCell(iCell) = channelChangeRate(iEdge) * dcEdge(iEdge) * 0.5_RKIND
+ ! < only half of channel is in this cell
end do ! edges
end do ! cells
divergenceChannel(1:nCellsSolve) = divergenceChannel(1:nCellsSolve) / areaCell(1:nCellsSolve)
@@ -1739,7 +1850,8 @@ subroutine shmip_timevarying_forcing(block, err)
call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface)
temperature0 = -16.0_RKIND * cos(2.0_RKIND * pii / 365.0 * daysSinceStart) - 5.0_RKIND + DT
- externalWaterInput(:) = (upperSurface(:) * (-0.0075_RKIND) + temperature0) * (0.01_RKIND / 86400.0_RKIND) * 1000.0_RKIND ! the 1000 factor converts from m/s to kg/m2/s
+ externalWaterInput(:) = (upperSurface(:) * (-0.0075_RKIND) + temperature0) * (0.01_RKIND / 86400.0_RKIND) * 1000.0_RKIND
+ ! < the 1000 factor converts from m/s to kg/m2/s
where (externalWaterInput < 0.0_RKIND)
externalWaterInput = 0.0_RKIND
end where
@@ -1754,4 +1866,65 @@ subroutine shmip_timevarying_forcing(block, err)
end subroutine shmip_timevarying_forcing
+
+!***********************************************************************
+!
+! routine ocean_connection_N
+!
+!> \brief Calculate effective pressure assuming perfect ocean connection
+!> \author Matt Hoffman
+!> \date 02 June 2020
+!> \details
+!> This routine calculates effective pressure assuming a perfect hydrologic
+!> connection with the ocean. It can be used as a simple alternative to the
+!> full subglacial hydrology.
+!-----------------------------------------------------------------------
+ subroutine ocean_connection_N(domain)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+ type (domain_type), intent(inout) :: domain !< Input/Output: domain object
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ type (block_type), pointer :: block
+ type (mpas_pool_type), pointer :: hydroPool
+ type (mpas_pool_type), pointer :: geometryPool
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:), pointer :: bedTopography
+ real (kind=RKIND), dimension(:), pointer :: effectivePressure
+ real (kind=RKIND), pointer :: rhoi, rhoo
+
+ ! Calculate N assuming perfect ocean connection
+ call mpas_log_write('Calculating N assuming perfect ocean connection.')
+
+ call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi)
+ call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhoo)
+ block => domain % blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool)
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
+ call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure)
+ effectivePressure = rhoi * gravity * thickness - rhoi * gravity * max(0.0_RKIND, -1.0_RKIND * rhoo/rhoi * bedTopography)
+ effectivePressure = max(effectivePressure, 0.0_RKIND) ! This is just to zero out N in the open ocean to avoid confusion
+
+ block => block % next
+ end do
+
+ !--------------------------------------------------------------------
+ end subroutine ocean_connection_N
+
+
end module li_subglacial_hydro
diff --git a/src/core_landice/mode_forward/mpas_li_thermal.F b/src/core_landice/mode_forward/mpas_li_thermal.F
index a3774f1224..31da8a4b1a 100644
--- a/src/core_landice/mode_forward/mpas_li_thermal.F
+++ b/src/core_landice/mode_forward/mpas_li_thermal.F
@@ -51,8 +51,9 @@ module li_thermal
public :: li_thermal_init, li_thermal_solver, &
li_init_linear_temperature_in_column, &
li_temperature_to_enthalpy, li_enthalpy_to_temperature, &
+ li_temperature_to_enthalpy_kelvin, li_enthalpy_to_temperature_kelvin, &
li_compute_pressure_melting_point_fields, &
- li_basal_melt_floating_ice
+ li_basal_friction, li_heat_dissipation_sia
!--------------------------------------------------------------------
!
@@ -121,7 +122,8 @@ subroutine li_thermal_init(domain, err)
character(len=StrKIND), pointer :: &
config_thermal_solver, & ! solver option ('temperature' or 'enthalpy')
config_temperature_init, & ! temperature initialization option ('linear' or 'file')
- config_surface_air_temperature_source, & ! surface air temperature initialization option ('constant' or 'file' or 'lapse')
+ config_surface_air_temperature_source, & ! surface air temperature initialization option
+ ! ('constant' or 'file' or 'lapse')
config_basal_heat_flux_source ! basal heat flux initialization option ('constant' or 'file')
real (kind=RKIND), pointer :: &
@@ -149,11 +151,12 @@ subroutine li_thermal_init(domain, err)
real (kind=RKIND), dimension(:), pointer :: &
thickness, & ! ice thickness
- upperSurface ! ice upper surface
+ upperSurface, & ! ice upper surface
+ basalWaterThickness
real (kind=RKIND), dimension(:,:), pointer :: &
temperature, & ! interior ice temperature (K)
- waterfrac, & ! interior water fraction (unitless)
+ waterFrac, & ! interior water fraction (unitless)
enthalpy ! interior ice enthalpy (J m^{-3})
real (kind=RKIND), dimension(:), pointer :: &
@@ -236,10 +239,11 @@ subroutine li_thermal_init(domain, err)
! get arrays from the geometry pool
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface)
+ call mpas_pool_get_array(geometryPool, 'basalWaterThickness', basalWaterThickness)
! get arrays from the thermal pool
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
- call mpas_pool_get_array(thermalPool, 'waterfrac', waterfrac)
+ call mpas_pool_get_array(thermalPool, 'waterFrac', waterFrac)
call mpas_pool_get_array(thermalPool, 'enthalpy', enthalpy)
call mpas_pool_get_array(thermalPool, 'surfaceAirTemperature', surfaceAirTemperature)
call mpas_pool_get_array(thermalPool, 'surfaceTemperature', surfaceTemperature)
@@ -257,7 +261,8 @@ subroutine li_thermal_init(domain, err)
if (config_print_thermal_info) &
call mpas_log_write('Initialize sfc air temp: $r', realArgs=(/config_surface_air_temperature_value/))
elseif (trim(config_surface_air_temperature_source) == 'lapse') then
- surfaceAirTemperature(:) = config_surface_air_temperature_value - config_surface_air_temperature_lapse_rate * upperSurface(:)
+ surfaceAirTemperature(:) = config_surface_air_temperature_value - config_surface_air_temperature_lapse_rate &
+ * upperSurface(:)
if (config_print_thermal_info) &
call mpas_log_write('Initialize sfc air temp to $r with lapse rate of $r', &
realArgs=(/config_surface_air_temperature_value, config_surface_air_temperature_lapse_rate/))
@@ -367,27 +372,15 @@ subroutine li_thermal_init(domain, err)
! The default is (1).
! If restarting, we always do (3).
! If (2) or (3), then the temperature should already have been read in, and there is
- ! nothing to do here (except possibly to set waterfrac).
+ ! nothing to do here (except possibly to set waterFrac).
- if (config_do_restart) then
+ if (config_do_restart .or. (trim(config_temperature_init) == 'file')) then
! nothing to do; temperature was read from the restart file
- !TODO - Make sure waterfrac is also read, if needed
if (config_print_thermal_info) then
- call mpas_log_write('Initialized ice temperature from the restart file')
+ call mpas_log_write('Initialized ice temperature (and waterFrac if required) from file.')
endif
- elseif (trim(config_temperature_init) == 'file') then
-
- ! Temperature was read from the input file
- if (config_print_thermal_info) then
- call mpas_log_write('Initialized ice temperature from the input file')
- endif
-
- ! initialize waterfrac, in case we are using the enthalpy solver
- !TODO - Allow waterfrac to be read from the input file?
- waterfrac(:,:) = 0.0_RKIND
-
elseif (trim(config_temperature_init) == 'sfc_air_temperature') then
allocate(pmpTemperatureCol(nVertLevels))
@@ -407,7 +400,7 @@ subroutine li_thermal_init(domain, err)
enddo
deallocate(pmpTemperatureCol)
- waterfrac(:,:) = 0.0_RKIND
+ waterFrac(:,:) = 0.0_RKIND
if (config_print_thermal_info) then
call mpas_log_write('Initialized ice column temperature to the surface air temperature')
@@ -430,7 +423,7 @@ subroutine li_thermal_init(domain, err)
thickness(iCell), &
surfaceAirTemperature(iCell), &
temperature(:,iCell), &
- waterfrac(:,iCell), &
+ waterFrac(:,iCell), &
surfaceTemperature(iCell), &
basalTemperature(iCell))
@@ -504,8 +497,8 @@ subroutine li_thermal_init(domain, err)
call mpas_dmpar_field_halo_exch(domain, 'temperature')
if (trim(config_thermal_solver) == 'enthalpy') then
- ! prognostic variables are temperature and waterfrac, so need to update waterfrac too
- call mpas_dmpar_field_halo_exch(domain, 'waterfrac')
+ ! prognostic variables are temperature and waterFrac, so need to update waterFrac too
+ call mpas_dmpar_field_halo_exch(domain, 'waterFrac')
endif
call mpas_timer_stop("halo updates")
@@ -540,7 +533,7 @@ subroutine li_init_linear_temperature_in_column(&
thickness, &
surfaceAirTemperature, &
temperature, &
- waterfrac, &
+ waterFrac, &
surfaceTemperature, &
basalTemperature)
@@ -564,7 +557,7 @@ subroutine li_init_linear_temperature_in_column(&
real(kind=RKIND), dimension(nVertLevels), intent(out) :: &
temperature, & !< Output: interior ice temperature at midpoint of each layer
- waterfrac !< Output: interior water fraction at midpoint of each layer
+ waterFrac !< Output: interior water fraction at midpoint of each layer
real(kind=RKIND), intent(out) :: &
surfaceTemperature, & !< Output: surface ice temperature
@@ -618,8 +611,8 @@ subroutine li_init_linear_temperature_in_column(&
temperature(:) = min(temperature(:), pmptemp(:) - pmpt_offset)
- ! set waterfrac = 0
- waterfrac(:) = 0.0_RKIND
+ ! set waterFrac = 0
+ waterFrac(:) = 0.0_RKIND
end subroutine li_init_linear_temperature_in_column
@@ -719,8 +712,8 @@ subroutine li_thermal_solver(domain, err)
surfaceAirTemperature, & ! surface air temperature (K)
basalHeatFlux, & ! basal heat flux into the ice (W m^{-2}, positive upward)
basalFrictionFlux, & ! basal frictional flux into the ice (W m^{-2})
- surfaceConductiveFlux, & ! conductive heat flux at the upper surface (W m^{-2}, positive down)
- basalConductiveFlux, & ! conductive heat flux at the lower surface (W m^{-2}, positive down)
+ surfaceConductiveFlux, & ! conductive heat flux at the upper surface (W m^{-2}, positive down)
+ basalConductiveFlux, & ! conductive heat flux at the lower surface (W m^{-2}, positive down)
groundedBasalMassBal, & ! basal mass balance for grounded ice
floatingBasalMassBal, & ! basal mass balance for floating ice
basalWaterThickness, & ! basal water thickness (m)
@@ -729,7 +722,7 @@ subroutine li_thermal_solver(domain, err)
real (kind=RKIND), dimension(:,:), pointer :: &
temperature, & ! interior ice temperature (K)
- waterfrac, & ! interior water fraction (unitless)
+ waterFrac, & ! interior water fraction (unitless)
enthalpy, & ! interior ice enthalpy (J m^{-3})
heatDissipation ! interior heat dissipation (deg/s)
@@ -834,7 +827,7 @@ subroutine li_thermal_solver(domain, err)
! get fields from the thermal pool
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
- call mpas_pool_get_array(thermalPool, 'waterfrac', waterfrac)
+ call mpas_pool_get_array(thermalPool, 'waterFrac', waterFrac)
call mpas_pool_get_array(thermalPool, 'enthalpy', enthalpy)
call mpas_pool_get_array(thermalPool, 'surfaceTemperature', surfaceTemperature)
call mpas_pool_get_array(thermalPool, 'basalTemperature', basalTemperature)
@@ -875,24 +868,15 @@ subroutine li_thermal_solver(domain, err)
enddo
- ! === Calculate mechanical heating terms ===
-
- if (trim(config_velocity_solver) == 'sia') then
- ! Compute interior heat dissipation
- call heat_dissipation_sia(domain, err_tmp)
- err = ior(err, err_tmp)
- endif ! sia
- ! (FO dissipation is calculated within dycore)
-
- ! Compute heat flux due to basal friction
- ! appropriate for SIA or FO dycore, assuming Taub=beta*ub
- call basal_friction(domain, err_tmp)
- err = ior(err, err_tmp)
+ ! === mechanical heating terms now calculated in li_velocity_solve ===
+ ! (this makes restarts easier because just heatDissipation and basalFrictionFlux
+ ! need to be restart variables, rather than all of their inputs.)
! === Update surfaceTemperature if using a lapse rate ===
if (trim(config_surface_air_temperature_source) == 'lapse') then
- surfaceAirTemperature(:) = config_surface_air_temperature_value - config_surface_air_temperature_lapse_rate * upperSurface(:)
+ surfaceAirTemperature(:) = config_surface_air_temperature_value - config_surface_air_temperature_lapse_rate &
+ * upperSurface(:)
endif
! ================================
@@ -966,13 +950,13 @@ subroutine li_thermal_solver(domain, err)
if (trim(config_thermal_solver) == 'enthalpy') then
- ! Given temperature and waterfrac in ice interior, compute enthalpy
+ ! Given temperature and waterFrac in ice interior, compute enthalpy
call li_temperature_to_enthalpy(&
layerCenterSigma, &
thickness(iCell), &
temperature(:,iCell), &
- waterfrac(:,iCell), &
+ waterFrac(:,iCell), &
enthalpy(:,iCell))
surfaceEnthalpy = surfaceTemperature(iCell) * rhoi*cp_ice
@@ -982,11 +966,11 @@ subroutine li_thermal_solver(domain, err)
call mpas_log_write(' ')
call mpas_log_write('Before prognostic enthalpy, iCell = $i', intArgs=(/indexToCellID(iCell)/))
call mpas_log_write('thickness = $r', realArgs=(/thickness(iCell)/))
- call mpas_log_write('Temperature (C), waterfrac, enthalpy/(rhoi*cp_ice):')
+ call mpas_log_write('Temperature (C), waterFrac, enthalpy/(rhoi*cp_ice):')
call mpas_log_write('0 $r', realArgs=(/surfaceEnthalpy/(rhoi*cp_ice)/))
do k = 1, nVertLevels
call mpas_log_write('$i $r $r $r', intArgs=(/k/), realArgs= &
- (/temperature(k,iCell), waterfrac(k,iCell), enthalpy(k,iCell)/(rhoi*cp_ice)/))
+ (/temperature(k,iCell), waterFrac(k,iCell), enthalpy(k,iCell)/(rhoi*cp_ice)/))
enddo
call mpas_log_write('$i $r', intArgs=(/nVertLevels+1/), realArgs=(/basalEnthalpy/(rhoi*cp_ice)/))
endif
@@ -1010,7 +994,7 @@ subroutine li_thermal_solver(domain, err)
temperature(:,iCell), &
surfaceTemperature(iCell), &
basalTemperature(iCell), &
- waterfrac(:,iCell), &
+ waterFrac(:,iCell), &
enthalpy(:,iCell), &
heatDissipation(:,iCell), &
basalHeatFlux(iCell), &
@@ -1063,28 +1047,37 @@ subroutine li_thermal_solver(domain, err)
basalConductiveFlux(iCell) = -diffusivity(nVertLevels+1)/thickness(iCell) * &
denth_bot/(1.0_RKIND - layerCenterSigma(nVertLevels))
- ! convert enthalpy in ice interior back to temperature and waterfrac
+ ! convert enthalpy in ice interior back to temperature and waterFrac
call li_enthalpy_to_temperature(&
layerCenterSigma, &
thickness(iCell), &
enthalpy(:,iCell), &
temperature(:,iCell), &
- waterfrac(:,iCell), &
+ waterFrac(:,iCell), &
surfaceEnthalpy, &
surfaceTemperature(iCell), &
basalEnthalpy, &
basalTemperature(iCell))
+ basalConductiveFlux(iCell) = -iceConductivity/thickness(iCell) * &
+ (basalTemperature(iCell)-temperature(nVertLevels,iCell))/(1.0_RKIND - layerCenterSigma(nVertLevels))
+ ! TZ: The basal conductive flux should be calculated using temperature, not
+ ! enthalpy. If we use enthalpy, basalConductiveFlux will always equals to basal heat flux, causing problem
+ ! At ice surface, it is unlikely there will be temperate ice. In addition, we can't know exactly the water
+ ! fraction if the ice is temperate at surface. So in this case we will just use enthalpy and don't consider
+ ! the latent heat of water.
+
+
if (verboseColumn) then
call mpas_log_write(' ')
call mpas_log_write('After prognostic enthalpy, iCell = $i', intArgs=(/indexToCellID(iCell)/))
call mpas_log_write('thickness = $r', realArgs=(/thickness(iCell)/))
- call mpas_log_write('Temperature, waterfrac, enthalpy/(rhoi*cp_ice):')
+ call mpas_log_write('Temperature, waterFrac, enthalpy/(rhoi*cp_ice):')
call mpas_log_write('0 $r', realArgs=(/surfaceEnthalpy/(rhoi*cp_ice)/))
do k = 1, nVertLevels
call mpas_log_write('$i $r $r $r', intArgs=(/k/), realArgs= &
- (/temperature(k,iCell), waterfrac(k,iCell), enthalpy(k,iCell)/(rhoi*cp_ice)/))
+ (/temperature(k,iCell), waterFrac(k,iCell), enthalpy(k,iCell)/(rhoi*cp_ice)/))
enddo
call mpas_log_write('$i $r', intArgs=(/nVertLevels+1/), realArgs=(/basalEnthalpy/(rhoi*cp_ice)/))
endif
@@ -1221,8 +1214,10 @@ subroutine li_thermal_solver(domain, err)
call mpas_log_write('config_thermal_thickness: $r', realArgs=(/config_thermal_thickness/))
call mpas_log_write(' ')
call mpas_log_write('Interior fluxes:')
- call mpas_log_write('sfc conductive flx (W/m^2, positive down)=$r', realArgs=(/surfaceConductiveFlux(iCell)/))
- call mpas_log_write('bed conductive flx (W/m^2, positive down)=$r', realArgs=(/basalConductiveFlux(iCell)/))
+ call mpas_log_write('sfc conductive flx (W/m^2, positive down)=$r', &
+ realArgs=(/surfaceConductiveFlux(iCell)/))
+ call mpas_log_write('bed conductive flx (W/m^2, positive down)=$r', &
+ realArgs=(/basalConductiveFlux(iCell)/))
call mpas_log_write('column heat dissipation (W/m^2) =$r', realArgs=(/columnHeatDissipation/))
call mpas_log_write('Net flux (W/m^2) =$r', realArgs=(/deltaEnergy/deltat/))
call mpas_log_write(' ')
@@ -1230,7 +1225,8 @@ subroutine li_thermal_solver(domain, err)
call mpas_log_write('initialEnergy (J/m^2) =$r', realArgs=(/initialEnergy/))
call mpas_log_write('finalEnergy (J/m^2) =$r', realArgs=(/finalEnergy/))
call mpas_log_write(' ')
- call mpas_log_write('Energy imbalance (J/m^2)=$r', realArgs=(/finalEnergy - initialEnergy - deltaEnergy/))
+ call mpas_log_write('Energy imbalance (J/m^2)=$r', &
+ realArgs=(/finalEnergy - initialEnergy - deltaEnergy/))
call mpas_log_write(' ')
call mpas_log_write('Basal fluxes:')
call mpas_log_write('frictional =$r', realArgs=(/basalFrictionFlux(iCell)/))
@@ -1240,8 +1236,8 @@ subroutine li_thermal_solver(domain, err)
endif ! verboseColumn
call mpas_log_write('li_thermal, energy conservation error: iCell=$i, imbalance=$r (W/m2):', MPAS_LOG_WARN, &
- intArgs=(/indexToCellID(iCell)/), realArgs=(/(finalEnergy - initialEnergy - deltaEnergy)/deltat/))
- err = 0
+ intArgs=(/indexToCellID(iCell)/), realArgs=(/(finalEnergy - initialEnergy - deltaEnergy)/deltat/))
+ !err = ior(err, 1)
endif ! energy conservation error
@@ -1254,7 +1250,7 @@ subroutine li_thermal_solver(domain, err)
surfaceTemperature(iCell) = 0.0_RKIND
basalTemperature(iCell) = 0.0_RKIND
temperature(:,iCell) = 0.0_RKIND
- waterfrac(:,iCell) = 0.0_RKIND
+ waterFrac(:,iCell) = 0.0_RKIND
enthalpy(:,iCell) = 0.0_RKIND
endif ! thickness > config_thermal_thickness
@@ -1283,7 +1279,7 @@ subroutine li_thermal_solver(domain, err)
thickness, &
temperature, &
basalTemperature, &
- waterfrac, &
+ waterFrac, &
enthalpy, &
basalFrictionFlux, &
basalHeatFlux, &
@@ -1306,7 +1302,8 @@ subroutine li_thermal_solver(domain, err)
mintemp = minval(temperature(:,iCell))
if (maxtemp > maxtempThreshold) then
- call mpas_log_write('maxtemp > maxtempThreshold: iCell=$i, maxtemp = $r', intArgs=(/iCell/), realArgs=(/maxtemp/))
+ call mpas_log_write('maxtemp > maxtempThreshold: iCell=$i, maxtemp = $r', intArgs=(/iCell/), &
+ realArgs=(/maxtemp/))
call mpas_log_write('thickness = $r', realArgs=(/thickness(iCell)/))
call mpas_log_write('temperature:')
do k = 1, nVertLevels
@@ -1316,7 +1313,8 @@ subroutine li_thermal_solver(domain, err)
endif
if (mintemp < mintempThreshold) then
- call mpas_log_write('mintemp < mintempThreshold: iCell=$i, mintemp = $r', intArgs=(/iCell/), realArgs=(/mintemp/))
+ call mpas_log_write('mintemp < mintempThreshold: iCell=$i, mintemp = $r', intArgs=(/iCell/), &
+ realArgs=(/mintemp/))
call mpas_log_write('thickness = $r', realArgs=(/thickness(iCell)/))
call mpas_log_write('temperature:')
do k = 1, nVertLevels
@@ -1327,6 +1325,9 @@ subroutine li_thermal_solver(domain, err)
enddo ! iCell
+ case default
+ call mpas_log_write("Unknown thermal solver specified: " // trim(config_thermal_solver), MPAS_LOG_ERR)
+ err = ior(err, 1)
end select ! config_thermal_solver
! It is possible that internal melting was computed above for floating ice and assigned
@@ -1370,8 +1371,8 @@ subroutine li_thermal_solver(domain, err)
call mpas_dmpar_field_halo_exch(domain, 'temperature')
if (trim(config_thermal_solver) == 'enthalpy') then
- ! prognostic variables are temperature and waterfrac, so need to update waterfrac too
- call mpas_dmpar_field_halo_exch(domain, 'waterfrac')
+ ! prognostic variables are temperature and waterFrac, so need to update waterFrac too
+ call mpas_dmpar_field_halo_exch(domain, 'waterFrac')
endif
call mpas_timer_stop("halo updates")
@@ -1383,209 +1384,10 @@ subroutine li_thermal_solver(domain, err)
end subroutine li_thermal_solver
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! ! routine li_basal_melt_floating_ice
-!
-!> \brief MPAS land ice solver for basal melt of floating ice
-!> \author William Lipscomb
-!> \date November 2015
-!> \details
-!> This routine computes basal melting for floating ice.
-!> The following options are supported:
-!> (1) Do nothing (config_basal_mass_bal_float = 'none')
-!> (2) Read melt rate from a file (config_basal_mass_bal_float = 'file')
-!> (2) Prescribed constant basal melt rate (config_basal_mass_bal_float = 'constant')
-!> (3) Basal melt rate as in MISMIP+ (config_basal_mass_bal_float = 'mismip')
-
-!-----------------------------------------------------------------------
-
- subroutine li_basal_melt_floating_ice(domain, err)
-
- !-----------------------------------------------------------------
- ! input variables
- !-----------------------------------------------------------------
-
- !-----------------------------------------------------------------
- ! input/output variables
- !-----------------------------------------------------------------
- type (domain_type), intent(inout) :: &
- domain !< Input/Output: domain object
-
- !-----------------------------------------------------------------
- ! output variables
- !-----------------------------------------------------------------
- integer, intent(out) :: err !< Output: error flag
-
- !-----------------------------------------------------------------
- ! local variables
- !-----------------------------------------------------------------
-
- type (block_type), pointer :: block
-
- type (mpas_pool_type), pointer :: meshPool
- type (mpas_pool_type), pointer :: geometryPool
- type (mpas_pool_type), pointer :: velocityPool ! needed for mask subroutine
- type (mpas_pool_type), pointer :: scratchPool
-
- integer, pointer :: &
- nCellsSolve ! number of locally owned cells
-
- logical, pointer :: &
- config_print_thermal_info ! if true, print debug info
-
- character(len=StrKIND), pointer :: &
- config_basal_mass_bal_float ! option for basal mass balance of floating ice
-
- real(kind=RKIND), pointer :: &
- config_thermal_thickness, & ! minimum thickness (m) for temperature calculations
- config_sea_level, & ! sea level (m) relative to z = 0
- config_bmlt_float_flux, & ! constant heat flux (W/m^2) applied to the base of floating ice; positive upward
- config_bmlt_float_xlimit ! x value (m) defining region where bmlt_float_flux is applied; melt only where abs(x) > xlimit
-
- integer, dimension(:), pointer :: &
- cellMask ! bit mask describing whether ice is floating, dynamically active, etc.
-
- type (field1dInteger), pointer :: thermalCellMaskField
-
- integer, dimension(:), pointer :: &
- thermalCellMask ! mask for thermal calculations
- ! = 1 where thickness > config_thermal_thickness, elsewhere = 0
-
- real (kind=RKIND), dimension(:), pointer :: &
- xCell ! x coordinate for each cell (m)
-
- real (kind=RKIND), dimension(:), pointer :: &
- floatingBasalMassBal, & ! basal mass balance for floating ice
- thickness, & ! ice thickness (m)
- lowerSurface, & ! lower surface elevation (m)
- bedTopography ! bed topography (m; negative below sea level)
-
- real(kind=RKIND), pointer :: daysSinceStart
-
- integer :: iCell, err_tmp
-
- err = 0
- err_tmp = 0
-
- call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_float', config_basal_mass_bal_float)
-
- if (trim(config_basal_mass_bal_float) == 'none') then
-
- ! Zero entire field
-
- ! block loop
- block => domain % blocklist
- do while (associated(block))
- call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
- call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
-
- floatingBasalMassBal = 0.0_RKIND
-
- block => block % next
- enddo ! associated(block)
-
- elseif (trim(config_basal_mass_bal_float) == 'file') then
-
- return ! already set; nothing to do
-
- endif
-
- ! get rest of config variables
- call mpas_pool_get_config(liConfigs, 'config_print_thermal_info', config_print_thermal_info)
- call mpas_pool_get_config(liConfigs, 'config_thermal_thickness', config_thermal_thickness)
- call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
- call mpas_pool_get_config(liConfigs, 'config_bmlt_float_flux', config_bmlt_float_flux)
- call mpas_pool_get_config(liConfigs, 'config_bmlt_float_xlimit', config_bmlt_float_xlimit)
-
- if (config_print_thermal_info) then
- call mpas_log_write('Solving for basal melting of floating ice, config_basal_mass_bal_float = ' // &
- trim(config_basal_mass_bal_float) )
- endif
-
- ! block loop
- block => domain % blocklist
- do while (associated(block))
-
- ! get pools
- call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
- call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
- call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
- call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
-
- ! get dimensions
- call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
-
- ! get fields from the mesh pool
- call mpas_pool_get_array(meshPool, 'xCell', xCell)
- call mpas_pool_get_array(meshPool, 'daysSinceStart',daysSinceStart)
-
- ! get fields from the geometry pool
- call mpas_pool_get_array(geometryPool, 'thickness', thickness)
- call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
- call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
- call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
- call mpas_pool_get_array(geometryPool, 'floatingBasalMassBal', floatingBasalMassBal)
-
- ! get fields from the scratch pool
- call mpas_pool_get_field(scratchPool, 'iceCellMask', thermalCellMaskField)
- call mpas_allocate_scratch_field(thermalCellMaskField, .true.)
- thermalCellMask => thermalCellMaskField % array
-
- ! calculate masks - so we know where the ice is floating
- call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp)
- err = ior(err, err_tmp)
-
- ! calculate a mask to identify ice that is thick enough to be thermally active
- do iCell = 1, nCellsSolve
- if (thickness(iCell) > config_thermal_thickness) then
- thermalCellMask(iCell) = 1
- else
- thermalCellMask(iCell) = 0
- endif
- enddo
-
- ! Compute basal melting for floating ice.
-
- call basal_melt_floating_ice(&
- config_basal_mass_bal_float, &
- nCellsSolve, &
- xCell, &
- daysSinceStart, &
- thermalCellMask, &
- li_mask_is_floating_ice_int(cellMask), &
- lowerSurface, &
- bedTopography, &
- config_sea_level, &
- config_bmlt_float_flux, &
- config_bmlt_float_xlimit, &
- floatingBasalMassBal, &
- err_tmp)
- err = ior(err, err_tmp)
-
- !WHL - debug
- ! write(stdoutUnit,*) 'Computed basal melt for floating ice'
- ! write(stdoutUnit,*) ' '
- ! write(stdoutUnit,*) 'iCell, thickness, basal mbal:'
- ! do iCell = 1, nCellsSolve
- ! if (li_mask_is_floating_ice(cellMask(iCell))) then
- ! write(stdoutUnit,*) iCell, thickness(iCell), floatingBasalMassBal(iCell)*scyr/rhoi
- ! endif
- ! enddo
- ! write(stdoutUnit,*) 'Done with basal melt for floating ice'
-
- ! clean up
- call mpas_deallocate_scratch_field(thermalCellMaskField, .true.)
-
- block => block % next
- enddo ! associated(block)
-
-
- end subroutine li_basal_melt_floating_ice
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
-! ! routine heat_dissipation_sia
+! ! routine li_heat_dissipation_sia
!
!> \brief MPAS land ice heat dissipation for SIA velocity solver
!> \author William Lipscomb
@@ -1595,7 +1397,7 @@ end subroutine li_basal_melt_floating_ice
!> in the ice interior, based on the shallow-ice approximation.
!-----------------------------------------------------------------------
- subroutine heat_dissipation_sia(domain, err)
+ subroutine li_heat_dissipation_sia(domain, err)
!-----------------------------------------------------------------
! input/output variables
@@ -1677,7 +1479,7 @@ subroutine heat_dissipation_sia(domain, err)
weightEdge ! edge weight for averaging to cell center
real (kind=RKIND), dimension(:), allocatable :: &
- flowParamAEdge ! flow parameter averaged to edge
+ flowParamAEdge ! flow parameter averaged to edge.
integer :: iCell, iCell1, iCell2, iEdge, iEdgeOnCell, iLayer
@@ -1841,12 +1643,12 @@ subroutine heat_dissipation_sia(domain, err)
block => block % next
enddo ! associated(block)
- end subroutine heat_dissipation_sia
+ end subroutine li_heat_dissipation_sia
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
-! ! routine basal_friction
+! ! routine li_basal_friction
!
!> \brief MPAS heat flux due to basal friction for SIA dynamics
!> \author William Lipscomb
@@ -1856,7 +1658,7 @@ end subroutine heat_dissipation_sia
!> base of the ice, based on the shallow-ice approximation.
!-----------------------------------------------------------------------
- subroutine basal_friction(domain, err)
+ subroutine li_basal_friction(domain, err)
!-----------------------------------------------------------------
! input/output variables
@@ -1877,6 +1679,7 @@ subroutine basal_friction(domain, err)
type (block_type), pointer :: block
type (mpas_pool_type), pointer :: meshPool
+ type (mpas_pool_type), pointer :: geometryPool
type (mpas_pool_type), pointer :: velocityPool
type (mpas_pool_type), pointer :: thermalPool
@@ -1892,11 +1695,16 @@ subroutine basal_friction(domain, err)
integer, pointer :: &
nCellsSolve ! number of cells
+ integer, pointer :: &
+ nCells ! number of cells
+
real(kind=RKIND), dimension(:), pointer :: &
basalSpeed, & ! basal ice speed, reconstructed at cell centers (m s^{-1})
betaSolve, & ! basal traction parameter (Pa m^{-1} s); use betaSolve to treat floating ice correctly
basalFrictionFlux ! heat flux due to basal friction (W^{m-2}), computed in this subroutine
+ integer, dimension(:), pointer :: cellMask
+
integer :: iCell
!----------------------------------------------------------------
@@ -1924,15 +1732,20 @@ subroutine basal_friction(domain, err)
! get pools
call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
! get dimensions
call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
! get fields from the mesh pool
call mpas_pool_get_array(meshPool, 'indexToCellID', indexToCellID) ! diagnostic only
+ ! get fields from the geometry pool
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+
! get fields from the velocity pool
call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed)
@@ -1948,7 +1761,14 @@ subroutine basal_friction(domain, err)
if (config_print_thermal_info) call mpas_log_write('Compute basal friction flux')
! Compute basal frictional heating for each cell
- basalFrictionFlux(:) = betaSolve(:) * basalSpeed(:)**2 * scyr ! TODO: If beta units are changed to be SI, remove this factor
+ do iCell = 1, nCells
+ if (li_mask_is_grounded_ice(cellMask(iCell))) then
+ basalFrictionFlux(iCell) = betaSolve(iCell) * basalSpeed(iCell)**2 * scyr
+ else
+ basalFrictionFlux(iCell) = 0.0_RKIND ! Ensure no friction flux under floating ice
+ endif
+ enddo
+ ! < TODO: If beta units are changed to be SI, remove scyr factor
! Optional debugging output
if (config_print_thermal_info) then
@@ -1963,7 +1783,74 @@ subroutine basal_friction(domain, err)
block => block % next
enddo ! associated(block)
- end subroutine basal_friction
+ end subroutine li_basal_friction
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine li_temperature_to_enthalpy_kelvin
+!
+!> \brief MPAS convert temperature to enthalpy
+!> \author William Lipscomb, Tong Zhang
+!> \date April 2018
+!> \details
+!> This routine computes the enthalpy in each layer of an ice column,
+!> given the temperature (K) and water fraction.
+!-----------------------------------------------------------------------
+
+ subroutine li_temperature_to_enthalpy_kelvin(&
+ layerCenterSigma, &
+ thickness, &
+ temperature, &
+ waterFrac, &
+ enthalpy)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(:), intent(in) :: &
+ layerCenterSigma !< Input: sigma coordinate at midpoint of each layer
+
+ real (kind=RKIND), intent(in) :: &
+ thickness !< Input: ice thickness
+
+ real (kind=RKIND), dimension(:), intent(in) :: &
+ temperature, & !< Input: interior ice temperature
+ waterFrac !< Input: interior water fraction
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(:), intent(out) :: &
+ enthalpy !< Output: interior ice enthalpy
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(size(layerCenterSigma)) :: &
+ pmpTemperature ! pressure melting point temperature
+
+ integer :: k, nVertLevels
+
+ nVertLevels = size(layerCenterSigma)
+
+ ! Find pressure melting point temperature in column
+
+ call pressure_melting_point_column(&
+ layerCenterSigma, &
+ thickness, &
+ pmpTemperature)
+
+ ! Solve for enthalpy
+
+ do k = 1, nVertLevels
+ enthalpy(k) = (1.0_RKIND - waterFrac(k)) * rhoi * cp_ice * temperature(k) &
+ + waterFrac(k) * rhoi * (cp_ice * (pmpTemperature(k)+kelvin_to_celsius) + latent_heat_ice)
+ end do
+
+ end subroutine li_temperature_to_enthalpy_kelvin
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
@@ -1981,7 +1868,7 @@ subroutine li_temperature_to_enthalpy(&
layerCenterSigma, &
thickness, &
temperature, &
- waterfrac, &
+ waterFrac, &
enthalpy)
!-----------------------------------------------------------------
@@ -1996,7 +1883,7 @@ subroutine li_temperature_to_enthalpy(&
real (kind=RKIND), dimension(:), intent(in) :: &
temperature, & !< Input: interior ice temperature
- waterfrac !< Input: interior water fraction
+ waterFrac !< Input: interior water fraction
!-----------------------------------------------------------------
! output variables
@@ -2026,10 +1913,37 @@ subroutine li_temperature_to_enthalpy(&
! Solve for enthalpy
do k = 1, nVertLevels
- enthalpy(k) = (1.0_RKIND - waterfrac(k)) * rhoi * cp_ice * temperature(k) &
- + waterfrac(k) * rho_water * (cp_ice * pmpTemperature(k) + latent_heat_ice)
+ enthalpy(k) = (1.0_RKIND - waterFrac(k)) * rhoi * cp_ice * temperature(k) &
+ + waterFrac(k) * rhoi * (cp_ice * pmpTemperature(k) + latent_heat_ice)
end do
+ ! TZ: we should use rhoi instead of rho_water in the second term here.
+
+
+ ! TZ: Here is the reason: from Eqn (6) in the Aschwanden et
+ ! al. (2012) paper "An enthalpy formulation for glaciers and ice sheets",
+
+ ! rho * H = rho_i * H_i + rho_w * H_w,
+
+ ! where rho_i and rho_w are not the ice and water density, but the partial
+ ! density, i.e., rho_i = mass_ice/volume, rho_w = mass_water/volume.
+ ! Because water fraction is very small in general, rho_i approximates to
+ ! rhoi (ice density), rho_w is close to 0.
+ ! Also note that in MALI the enthalpy is equal to the enthalpy density
+ ! (rho*H) in Aschwanden's paper (they don't have density in their
+ ! enthaly definition, but we do). Thus, Let's denote MALI's enthalpy as
+ ! E, and denote W as the water content, then
+
+ ! E = rho * H = rho_i * H_i + rho_w * H_w = (1-W) * H_i + W * H_w
+ ! E = (1-W) * rho * cp * T + W * (rho * cp * T_pmp + rho*L)
+
+ ! As rho approximates to rhoi, we have
+
+ ! E = (1-W) * rhoi * cp * T + W * rhoi * (cp*T_pmp + L)
+
+ ! This is what we get in the code. We can easily do the derivation
+ ! according to Eqns (1-11) in Aschwanden's paper.
+
end subroutine li_temperature_to_enthalpy
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -2049,7 +1963,7 @@ subroutine li_enthalpy_to_temperature(&
thickness, &
enthalpy, &
temperature, &
- waterfrac, &
+ waterFrac, &
surfaceEnthalpy, &
surfaceTemperature, &
basalEnthalpy, &
@@ -2084,7 +1998,7 @@ subroutine li_enthalpy_to_temperature(&
temperature !< Output: interior ice temperature
real (kind=RKIND), dimension(:), intent(out) :: &
- waterfrac !< Output: interior water fraction
+ waterFrac !< Output: interior water fraction
real (kind=RKIND), intent(out), optional :: &
surfaceTemperature, & !< Output: surface ice temperature
@@ -2119,18 +2033,18 @@ subroutine li_enthalpy_to_temperature(&
pmpEnthalpy(:) = pmpTemperature(:) * rhoi*cp_ice
pmpEnthalpyBed = pmpTemperatureBed * rhoi*cp_ice
- ! Solve for temperature and waterfrac in ice interior
+ ! Solve for temperature and waterFrac in ice interior
! ice interior
do k = 1, nVertLevels
if (enthalpy(k) >= pmpEnthalpy(k)) then ! temperate ice
temperature(k) = pmpTemperature(k)
- waterfrac(k) = (enthalpy(k) - pmpenthalpy(k)) / &
- ((rho_water-rhoi)*cp_ice*pmpTemperature(k) + rho_water*latent_heat_ice)
+ waterFrac(k) = (enthalpy(k) - pmpenthalpy(k)) / &
+ ((rho_water-rhoi)*cp_ice*pmpTemperature(k) + rhoi *latent_heat_ice)
else ! cold ice
temperature(k) = enthalpy(k) / (rhoi*cp_ice)
- waterfrac(k) = 0.0_RKIND
+ waterFrac(k) = 0.0_RKIND
endif
enddo ! k
@@ -2169,6 +2083,142 @@ subroutine li_enthalpy_to_temperature(&
end subroutine li_enthalpy_to_temperature
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ! routine li_enthalpy_to_temperature_kelvin
+!
+!> \brief MPAS convert enthalpy to temperature
+!> \author William Lipscomb, Tong Zhang
+!> \date April 2018
+!> \details
+!> This routine computes the temperature (K) and water fraction in each layer
+!> of an ice column, given the enthalpy.
+!-----------------------------------------------------------------------
+
+ subroutine li_enthalpy_to_temperature_kelvin(&
+ layerCenterSigma, &
+ thickness, &
+ enthalpy, &
+ temperature, &
+ waterFrac, &
+ surfaceEnthalpy, &
+ surfaceTemperature, &
+ basalEnthalpy, &
+ basalTemperature)
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(:), intent(in) :: &
+ layerCenterSigma !< Input: sigma coordinate at midpoint of each layer
+
+ real (kind=RKIND), intent(in) :: &
+ thickness !< Input: ice thickness
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(:), intent(inout) :: &
+ enthalpy !< Input/output: interior ice enthalpy
+
+ real (kind=RKIND), intent(inout) , optional :: &
+ surfaceEnthalpy, & !< Input/output: surface ice enthalpy
+ basalEnthalpy !< Input/output: basal ice enthalpy
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(:), intent(out) :: &
+ temperature !< Output: interior ice temperature
+
+ real (kind=RKIND), dimension(:), intent(out) :: &
+ waterFrac !< Output: interior water fraction
+
+ real (kind=RKIND), intent(out), optional :: &
+ surfaceTemperature, & !< Output: surface ice temperature
+ basalTemperature !< Output: basal ice temperature
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+
+ real (kind=RKIND), dimension(size(layerCenterSigma)) :: pmpTemperature
+ real (kind=RKIND), dimension(size(layerCenterSigma)) :: pmpEnthalpy
+
+ real (kind=RKIND) :: pmpTemperatureBed
+ real (kind=RKIND) :: pmpEnthalpyBed
+
+ integer :: k, nVertLevels
+
+ nVertLevels = size(layerCenterSigma)
+
+ ! Find pressure melting point temperature in ice interior
+ call pressure_melting_point_column(&
+ layerCenterSigma, &
+ thickness, &
+ pmpTemperature)
+
+ ! find pressure melting point temperature at bed
+ call pressure_melting_point(&
+ thickness, &
+ pmpTemperatureBed)
+
+ ! Find pressure melting point enthalpy
+ pmpEnthalpy(:) = (pmpTemperature(:)+kelvin_to_celsius) * rhoi*cp_ice
+ pmpEnthalpyBed = (pmpTemperatureBed+kelvin_to_celsius) * rhoi*cp_ice
+
+ ! Solve for temperature and waterFrac in ice interior
+
+ ! ice interior
+
+ do k = 1, nVertLevels
+ if (enthalpy(k) >= pmpEnthalpy(k)) then ! temperate ice
+ temperature(k) = (pmpTemperature(k)+kelvin_to_celsius)
+ waterFrac(k) = (enthalpy(k) - pmpEnthalpy(k)) / &
+ ((rho_water-rhoi)*cp_ice*(pmpTemperature(k)+kelvin_to_celsius) + rhoi *latent_heat_ice)
+ else ! cold ice
+ temperature(k) = enthalpy(k) / (rhoi*cp_ice)
+ waterFrac(k) = 0.0_RKIND
+ endif
+ enddo ! k
+
+ ! surface temperature (optional)
+
+ if (present(surfaceEnthalpy) .and. present(surfaceTemperature)) then
+
+ if (surfaceEnthalpy >= (kelvin_to_celsius*rhoi*cp_ice)) then ! temperate ice
+ surfaceTemperature = kelvin_to_celsius
+ ! Reset surfaceEnthalpy to agree with the surface temperature.
+ ! This is consistent with energy conservation because the top surface
+ ! is infinitesimally thin.
+ surfaceEnthalpy = kelvin_to_celsius*rhoi*cp_ice
+ else ! cold ice
+ surfaceTemperature = surfaceEnthalpy / (rhoi*cp_ice)
+ endif
+
+ endif
+
+ ! basal temperature (optional)
+
+ if (present(basalEnthalpy) .and. present(basalTemperature)) then
+
+ k = nVertLevels + 1
+ if (basalEnthalpy >= pmpEnthalpyBed) then ! temperate ice
+ basalTemperature = (pmpTemperatureBed+kelvin_to_celsius)
+ ! Reset basalEnthalpy to agree with the surface temperature.
+ ! This is consistent with energy conservation because the lower surface
+ ! is infinitesimally thin.
+ basalEnthalpy = pmpEnthalpyBed
+ else ! cold ice
+ basalTemperature = basalEnthalpy / (rhoi*cp_ice)
+ endif
+
+ endif
+
+ end subroutine li_enthalpy_to_temperature_kelvin
!***********************************************************************
!***********************************************************************
! Private subroutines:
@@ -2353,7 +2403,7 @@ subroutine enthalpy_matrix_elements(&
temperature, &
surfaceTemperature, &
basalTemperature, &
- waterfrac, &
+ waterFrac, &
enthalpy, &
heatDissipation, &
basalHeatFlux, &
@@ -2393,7 +2443,7 @@ subroutine enthalpy_matrix_elements(&
real(kind=RKIND), dimension(nVertLevels), intent(in) :: &
temperature, & !< Input: ice temperature (deg C)
- waterfrac, & !< Input: water fraction (unitless)
+ waterFrac, & !< Input: water fraction (unitless)
enthalpy !< Input: specific enthalpy (J/m^3)
real(kind=RKIND), intent(in) :: &
@@ -2442,6 +2492,7 @@ subroutine enthalpy_matrix_elements(&
real(kind=RKIND) :: dEnthalpy ! enthalpy difference between adjacent layers
real(kind=RKIND) :: dEnthalpyTemp ! difference in temperature component of enthalpy between adjacent layers
real(kind=RKIND) :: avgFactor ! factor for averaging diffusivity, 0 <= avgFactor <= 1
+ real(kind=RKIND) :: tempDiffusivityFactor ! factor for estimating the diffusivity in temperate ice, normally it should < 1
integer :: k
@@ -2449,8 +2500,19 @@ subroutine enthalpy_matrix_elements(&
harmonic_avg = .false. ! if true, take the harmonic average of diffusivity in adjacent layers
! if false, take the arithmetic average
+ real(kind=RKIND), pointer :: &
+ config_temp_diffusive_factor ! option for basal mass balance of floating ice
+
+ call mpas_pool_get_config(liConfigs, 'config_temp_diffusive_factor', config_temp_diffusive_factor)
+
+ tempDiffusivityFactor = config_temp_diffusive_factor
+ ! TZ: this value is somehow empirical, and the default value (1.0e-5) is picked according to Kleiner's benchemark B.
+ ! In Greve and Blatter (2016) 'Comparison of thermodynamics solvers in the polythermal ice sheet model SICOPOLIS',
+ ! it was 1.0e-3 [] (p14, section 4)
+ ! i.e., kt = 1.0e-3 * kc
+
diffusivityCold = iceConductivity / (rhoi*cp_ice)
- diffusivityTemperate = diffusivityCold / 100.0_RKIND
+ diffusivityTemperate = diffusivityCold * tempDiffusivityFactor
! set enthalpy at surface and bed
surfaceEnthalpy = surfaceTemperature * rhoi*cp_ice
@@ -2503,7 +2565,7 @@ subroutine enthalpy_matrix_elements(&
enthalpyTemp(0) = surfaceEnthalpy
do k = 1, nVertLevels
- enthalpyTemp(k) = (1.0_RKIND - waterfrac(k)) * rhoi*cp_ice*temperature(k)
+ enthalpyTemp(k) = (1.0_RKIND - waterFrac(k)) * rhoi*cp_ice*temperature(k)
enddo
enthalpyTemp(nVertLevels+1) = basalEnthalpy
@@ -2525,6 +2587,8 @@ subroutine enthalpy_matrix_elements(&
if (abs(dEnthalpy) > 1.e-20_RKIND * rho_water * latent_heat_ice) then
avgFactor = max(0.0_RKIND, dEnthalpyTemp/dEnthalpy)
avgFactor = min(1.0_RKIND, avgFactor)
+ ! TZ: Here temperature is in Celsius. dEnthalpyTemp <= 0 in temperate ice as waterFrac increases
+ ! (or temperature decreases) with depth
else
avgFactor = 0.0_RKIND
endif
@@ -2540,6 +2604,7 @@ subroutine enthalpy_matrix_elements(&
end do
+
! Compute subdiagonal, diagonal, and superdiagonal matrix elements
! Assume backward Euler time stepping
@@ -2553,10 +2618,12 @@ subroutine enthalpy_matrix_elements(&
factor = deltat / thickness**2
- subd(2:nVertLevels+1) = -factor * diffusivity(1:nVertLevels) * dsigmaTerm(1:nVertLevels,1)
+ subd(2:nVertLevels+1) = -factor * diffusivity(1:nVertLevels) * dsigmaTerm(1:nVertLevels,1)
supd(2:nVertLevels+1) = -factor * diffusivity(2:nVertLevels+1) * dsigmaTerm(1:nVertLevels,2)
diag(2:nVertLevels+1) = 1.0_RKIND - subd(2:nVertLevels+1) - supd(2:nVertLevels+1)
rhs(2:nVertLevels+1) = enthalpy(1:nVertLevels) + heatDissipation(1:nVertLevels) * deltat * rhoi * cp_ice
+ !TZ: Make sure the heat advection is using the upwind scheme, or the solution will not be stable
+
! Note: heatDissipation has units of phi/rhoi/cp_ice, where phi has units of W m^-3..
! For an enthalpy calculation, we want just phi, hence heatDissipation * rhoi * cp_ice
@@ -2577,10 +2644,12 @@ subroutine enthalpy_matrix_elements(&
else ! grounded ice
+
if (abs(temperature(nVertLevels) - pmpTemperature(nVertLevels)) < 0.001_RKIND) then
! Positive-thickness basal temperate boundary Layer
!WHL - Not sure whether this condition is ideal. It implies that basalEnthalpy = enthalpy(nVertLevels).
+ !TZ: This condition means the base is temperate AND there is temperate layer above it. It's physical
subd(nVertLevels+2) = -1.0_RKIND
diag(nVertLevels+2) = 1.0_RKIND
@@ -2641,7 +2710,7 @@ subroutine basal_melt_grounded_ice(&
thickness, &
temperature, &
basalTemperature, &
- waterfrac, &
+ waterFrac, &
enthalpy, &
basalFrictionFlux, &
basalHeatFlux, &
@@ -2686,8 +2755,7 @@ subroutine basal_melt_grounded_ice(&
thickness, & !< Input: ice thickness (m)
basalFrictionFlux, & !< Input: basal frictional heating flux (W m-2), >= 0
basalHeatFlux, & !< Input: geothermal heating flux (W m-2), positive up
- basalConductiveFlux, & !< Input: heat conducted from ice interior to bed (W m-2), positive down
- basalWaterThickness !< Input: thickness of basal water layer (m)
+ basalConductiveFlux !< Input: heat conducted from ice interior to bed (W m-2), positive down
integer, dimension(:), intent(in) :: &
iceMask, & !< Input: = 1 where ice exists (thickness > config_thermal_thickness), else = 0
@@ -2701,10 +2769,11 @@ subroutine basal_melt_grounded_ice(&
temperature !< Input/output: temperature (deg C)
real(kind=RKIND), dimension(:), intent(inout) :: &
- basalTemperature !< Input/output: basal temperature (deg C)
+ basalTemperature, & !< Input/output: basal temperature (deg C)
+ basalWaterThickness !< Input: thickness of basal water layer (m)
real(kind=RKIND), dimension(:,:), intent(inout) :: &
- waterfrac !< Input/output: water fraction
+ waterFrac !< Input/output: water fraction
!-----------------------------------------------------------------
! output variables
@@ -2730,12 +2799,15 @@ subroutine basal_melt_grounded_ice(&
real(kind=RKIND) :: internalMeltRate ! internal melt rate, transferred to bed (m/s)
real(kind=RKIND) :: excessWater ! thickness of excess meltwater (m)
- real(kind=RKIND), parameter :: &
- maxWaterfrac = 0.01_RKIND ! maximum allowed water fraction; excess drains to bed
-
+ real(kind=RKIND) :: maxwaterFrac ! maximum allowed water fraction; excess drains to bed
+ real(kind=RKIND), pointer :: &
+ config_max_water_fraction ! maximum allowable water fraction before additional melt drains
real(kind=RKIND), parameter :: &
eps11 = 1.0e-11_RKIND ! small number
+ call mpas_pool_get_config(liConfigs, 'config_max_water_fraction', config_max_water_fraction)
+
+ maxwaterFrac = config_max_water_fraction
! Compute melt rate for grounded ice
@@ -2761,6 +2833,8 @@ subroutine basal_melt_grounded_ice(&
! and overlying layers with a different enthalpy also melt.
netBasalFlux = basalFrictionFlux(iCell) + basalHeatFlux(iCell) + basalConductiveFlux(iCell) ! W/m^2
+ !call mpas_log_write("netBasalFlux G condFlux $r $r $r", realArgs=(/netBasalFlux, basalHeatFlux(iCell), &
+ !basalConductiveFlux(iCell)/))
if (abs(netBasalFlux) < eps11) then ! netBasalFlux might be slightly different from zero
! because of rounding errors; if so, then zero out
@@ -2768,11 +2842,23 @@ subroutine basal_melt_grounded_ice(&
endif
if (trim(config_thermal_solver) == 'enthalpy') then
- groundedBasalMassBal(iCell) = -netBasalFlux / (latent_heat_ice * rhoi - enthalpy(nVertLevels,iCell))
+ !groundedBasalMassBal(iCell) = -netBasalFlux / (latent_heat_ice * rhoi - enthalpy(nVertLevels,iCell))
+ groundedBasalMassBal(iCell) = -netBasalFlux / (latent_heat_ice * rhoi) / (1-waterFrac(nVertLevels,iCell))
+ ! TZ: Don't understand yet why WHL added enthalpy(nVertLevels,iCell) here
+ ! TZ: After a long discussion with Matt Hoffman, we decide to revise it
+ ! to the form as Eqn (66) in Aschwanden and others (2012) "An
+ ! enthalpy formulation for glaciers and ice sheets". An extra
+ ! term (1-w) would be more accurate.
+ basalWaterThickness(iCell) = basalWaterThickness(iCell) - deltat*groundedBasalMassBal(iCell)
+ ! TZ: allow basalWaterThickness freely accumulate here. Change it to something else for difference cases
+ if (basalWaterThickness(iCell) < 0.0_RKIND) then
+ basalWaterThickness(iCell) = 0.0_RKIND
+ endif
else ! temperature solver
groundedBasalMassBal(iCell) = -netBasalFlux / (latent_heat_ice * rhoi) ! m/s
endif
+
endif ! ice is present and grounded
! Add internal melting
@@ -2783,14 +2869,14 @@ subroutine basal_melt_grounded_ice(&
if (trim(config_thermal_solver) == 'enthalpy') then
- ! Add internal melting associated with waterfrac > maxWaterfrac (1%)
+ ! Add internal melting associated with waterFrac > maxwaterFrac (1%)
!TODO - Add correction for rhoi/rhow here? Or melting ice that is already partly melted?
do k = 1, nVertLevels
- if (waterfrac(k,iCell) > maxWaterfrac) then
+ if (waterFrac(k,iCell) > maxwaterFrac) then
! compute melt rate associated with excess water
- excessWater = (waterfrac(k,iCell) - maxWaterfrac) * thickness(iCell) * (layerInterfaceSigma(k+1) &
+ excessWater = (waterFrac(k,iCell) - maxwaterFrac) * thickness(iCell) * (layerInterfaceSigma(k+1) &
- layerInterfaceSigma(k)) ! m
internalMeltRate = excessWater / deltat
@@ -2799,10 +2885,10 @@ subroutine basal_melt_grounded_ice(&
! If so, then this melting will later be switched from groundedBasalMassBall to floatingBasalMassBal.
groundedBasalMassBal(iCell) = groundedBasalMassBal(iCell) - internalMeltRate ! m/s
- ! reset waterfrac to max value
- waterfrac(k,iCell) = maxWaterfrac
+ ! reset waterFrac to max value
+ waterFrac(k,iCell) = maxwaterFrac
- endif ! waterfrac > maxWaterfrac
+ endif ! waterFrac > maxwaterFrac
enddo ! k
elseif (config_thermal_solver == 'temperature') then
@@ -2880,238 +2966,6 @@ subroutine basal_melt_grounded_ice(&
end subroutine basal_melt_grounded_ice
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! ! routine basal_melt_floating_ice
-!
-!> \brief MPAS melt rate at base of floating ice
-!> \author William Lipscomb
-!> \date November 2015
-!> \details
-!> This routine computes the melt rate at the base of floating ice.
-!-----------------------------------------------------------------------
-
- subroutine basal_melt_floating_ice(&
- config_basal_mass_bal_float, &
- nCellsSolve, &
- xCell, &
- daysSinceStart, &
- iceMask, &
- floatingMask, &
- lowerSurface, &
- bedTopography, &
- config_sea_level, &
- config_bmlt_float_flux, &
- config_bmlt_float_xlimit, &
- floatingBasalMassBal, &
- err)
-
- !-----------------------------------------------------------------
- ! input variables
- !-----------------------------------------------------------------
-
- character(len=strKIND), intent(in) :: &
- config_basal_mass_bal_float !< Input: option for computing basal mass balance for floating ice
-
- integer, intent(in) :: &
- nCellsSolve !< Input: number of locally owned cells
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- xCell !< Input: x coordinate for each cell
-
- real(kind=RKIND), pointer, intent(in) :: daysSinceStart
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- lowerSurface, & !< Input: lower surface elevation (m)
- bedTopography !< Input: elevation of bed topography (m)
-
- real(kind=RKIND), intent(in) :: &
- config_sea_level !< Input: sea level relative to z = 0 (m)
-
- integer, dimension(:), intent(in) :: &
- iceMask, & !< Input: = 1 where ice exists (thickness > config_thermal_thickness), else = 0
- floatingMask !< Input: = 1 where ice is floating, else = 0
-
- ! inputs for constant melt rate as in MISMIP+ Ice2 experiments
- real(kind=RKIND), intent(in) :: &
- config_bmlt_float_flux, & !< Input: constant heat flux (W/m^2) applied to the base of floating ice; positive upward
- !< MISMIP+ default value = 975.17 W/m^2 (gives melt rate of 100 m/yr)
- config_bmlt_float_xlimit !< Input: x value (m) defining region where bmlt_float_flux is applied;
- !< melt only where abs(x) > xlimit
- !< MISMIP+ default value = 480 km
-
- !-----------------------------------------------------------------
- ! output variables
- !-----------------------------------------------------------------
-
- real(kind=RKIND), dimension(:), intent(out):: &
- floatingBasalMassBal !< Output: basal mass balance for floating ice
-
- integer, intent(out) :: err
-
- !-----------------------------------------------------------------
- ! local variables
- !-----------------------------------------------------------------
-
- real(kind=RKIND) :: &
- bmlt_float_rate ! constant basal melt rate (m/s)
- ! = config_bmlt_float_flux / (rhoi*latent_heat_ice)
- integer :: iCell
-
- real(kind=RKIND) :: hCavity ! depth of ice cavity beneath floating ice (m)
- real(kind=RKIND) :: zDraft ! draft of floating ice (m below sea level)
-
- ! basal melting parameters for MISMIP+ experiment
- ! Note: These could be made user-configurable, but are hardwired for now because there are no plans
- ! to run MISMIP+ with different values
- real(kind=RKIND), parameter :: &
- bmlt_float_omega = 0.20_RKIND / scyr, & ! time scale for basal melting (s^-1)
- ! MISMIP+ default value = 0.2 yr^-1
- bmlt_float_h0 = 75._RKIND, & ! scale for sub-shelf cavity thickness (m)
- ! MISMIP+ default value = 75 m
- bmlt_float_z0 = -100._RKIND ! scale for ice draft (m)
- ! MISMIP+ default value = -100 m
-
- ! basal melt parameters for Seroussi param.
- real (kind=RKIND) :: slopeSer ! slope of relation between depth and melt rate
- real (kind=RKIND) :: interceptSer ! depth at which melting goes to 0
- real (kind=RKIND) :: maxMeltSer ! maximum allowable melt rate
- real (kind=RKIND) :: sillDepth ! depth below which melt rate no longer increases
- real (kind=RKIND), pointer :: config_basal_mass_bal_seroussi_amplitude
- real (kind=RKIND), pointer :: config_basal_mass_bal_seroussi_period
- real (kind=RKIND), pointer :: config_basal_mass_bal_seroussi_phase
-
-
- ! Compute melt rate for floating ice
- err = 0
-
- ! initialize to zero melt
- floatingBasalMassBal(:) = 0.0_RKIND
- if (trim(config_basal_mass_bal_float) == 'none') then
- ! Do nothing, handled in calling routine
-
- elseif (trim(config_basal_mass_bal_float) == 'file') then
- ! Do nothing, handled in calling routine
-
- elseif (trim(config_basal_mass_bal_float) == 'constant') then
-
- ! set melt rate to a constant value for floating ice
- ! allow basal melt in ice-free ocean cells, in case ice is advected to those cells by the transport scheme
-
- bmlt_float_rate = config_bmlt_float_flux / (rhoi*latent_heat_ice) ! convert W/m^2 to m/s
-
- floatingBasalMassBal(:) = 0.0_RKIND
-
- do iCell = 1, nCellsSolve
- if ( floatingMask(iCell) == 1 .or. &
- (bedTopography(iCell) < config_sea_level .and. iceMask(iCell) == 0) ) then
- ! ice is present and floating, or ice-free ocean
-
- ! Provided xCell > bmlt_float_xlimit, prescribe a uniform basal melt rate.
- ! The default is 0.0, but for MISMIP+ the prescribed value of xlimit is 480 km.
- if (abs(xCell(iCell)) >= config_bmlt_float_xlimit) then ! basal melting is allowed
- floatingBasalMassBal(iCell) = -bmlt_float_rate
- endif
-
- endif ! ice is present and floating
-
- enddo ! iCell
-
- ! change units from m/s to kg/m2/s
- floatingBasalMassBal(:) = floatingBasalMassBal(:) * rhoi
-
- elseif (trim(config_basal_mass_bal_float) == 'mismip') then
-
- ! compute melt rate (m/s) based on bed depth and cavity thickness
- ! The MISMIP+ formula is as follows:
- !
- ! bmlt_float = omega * tanh(H_c/H_0) * max(z_0 - z_d, 0)
- !
- ! where H_c = lsrf - topg is the cavity thickness
- ! z_d = lsrf - eus is the ice draft
- ! omega = a time scale = 0.2 yr^{-1} by default
- ! H_0 = 75 m by default
- ! z_0 = -100 m by default
-
- ! allow basal melt in ice-free ocean cells, in case ice is advected to those cells by the transport scheme
-
- floatingBasalMassBal(:) = 0.0_RKIND
-
- do iCell = 1, nCellsSolve
-
- if ( floatingMask(iCell) == 1 .or. &
- (bedTopography(iCell) < config_sea_level .and. iceMask(iCell) == 0) ) then
- ! ice is present and floating, or ice-free ocean
-
- hCavity = lowerSurface(iCell) - bedTopography(iCell)
- zDraft = lowerSurface(iCell) - config_sea_level
- floatingBasalMassBal(iCell) = -bmlt_float_omega * tanh(hCavity/bmlt_float_h0) * max(bmlt_float_z0 - &
- zDraft, 0.0_RKIND)
-
- endif ! ice is present and floating
- enddo ! iCell
-
- ! change units from m/s to kg/m2/s
- floatingBasalMassBal(:) = floatingBasalMassBal(:) * rhoi
-
- elseif (trim(config_basal_mass_bal_float) == 'seroussi') then
-
- ! Melt rate parameterization from:
- ! Seroussi, H., Y. Nakayama, E. Larour, D. Menemenlis, M. Morlighem, E. Rignot, and A. Khazendar (2017), Continued retreat of Thwaites Glacier, West Antarctica, controlled by bed topography and ocean circulation, Geophys. Res. Lett., 1-9, doi:10.1002/2017GL072910.
- ! for Thwaites Glacier.
- ! Specifically, this is a linear fit of melt with shelf draft from the Supplemental Information, Figure S1.
- ! The linear relation is modified by a:
- ! * depth above which there is no melt (Antarctic Surface Water saturation)
- ! * a maximum melt rate (Circumpolar Deep Water saturation)
- ! * a depth below which melt stops increasing (minimum sill height)
-
- call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_seroussi_amplitude', config_basal_mass_bal_seroussi_amplitude) ! meters
- call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_seroussi_period', config_basal_mass_bal_seroussi_period) ! years
- call mpas_pool_get_config(liConfigs, 'config_basal_mass_bal_seroussi_phase', config_basal_mass_bal_seroussi_phase) ! cycles
-
- slopeSer = 0.088_RKIND ! slope of relation between depth and melt rate (melt (m/yr) per depth (m))
- interceptSer = -100.0_RKIND ! depth (m) at which melting goes to 0 (negative meaning below sea level)
- maxMeltSer = 50.0_RKIND ! maximum allowable melt rate (m/yr) (positive meaning melting)
- sillDepth = -650.0_RKIND ! depth below which melt stops increasing (m) (negative meaning below sea level)
-
- if (config_basal_mass_bal_seroussi_period <= 0.0_RKIND) then
- call mpas_log_write("Value for config_basal_mass_bal_seroussi_period has to be a positive real value.", MPAS_LOG_ERR)
- err = ior(err, 1)
- endif
-
- ! Modify intercept height for variability parameters
- interceptSer = interceptSer + config_basal_mass_bal_seroussi_amplitude * &
- sin( (2.0_RKIND * pii / config_basal_mass_bal_seroussi_period) * (daysSinceStart/365.0_RKIND) &
- + 2.0_RKIND * pii * config_basal_mass_bal_seroussi_phase)
-
- ! Initialize before computing
- floatingBasalMassBal(:) = 0.0_RKIND
-
- do iCell = 1, nCellsSolve
-
- ! Shut off melt at an arbitrary shallow depth to discourage ice from disappearing.
- if ( (floatingMask(iCell) == 1) .and. (lowerSurface(iCell) < -10.0_RKIND) ) then
- ! ice is present and floating
-
- zDraft = lowerSurface(iCell) - config_sea_level
- ! Coefficients for m/yr melt rate (in units of Seroussi figure but without negative meaning melting)
- floatingBasalMassBal(iCell) = max(-1.0_RKIND * maxMeltSer, min(0.0_RKIND, slopeSer * (max(zDraft, sillDepth) - interceptSer)))
-
- endif ! ice is present
- enddo ! iCell
-
- ! change units from m/yr to kg/m2/s
- floatingBasalMassBal(:) = floatingBasalMassBal(:) * rhoi / scyr
-
- else
-
- call mpas_log_write('Unknown option selected for config_basal_mass_bal_float:' // trim(config_basal_mass_bal_float), MPAS_LOG_ERR)
- err = ior(err, 1)
-
- endif ! config_basal_mass_bal_float
-
-
- end subroutine basal_melt_floating_ice
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
@@ -3312,5 +3166,3 @@ end module li_thermal
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-
-
diff --git a/src/core_landice/mode_forward/mpas_li_time_integration_fe.F b/src/core_landice/mode_forward/mpas_li_time_integration_fe.F
index 18178aac71..e36e7ee13e 100644
--- a/src/core_landice/mode_forward/mpas_li_time_integration_fe.F
+++ b/src/core_landice/mode_forward/mpas_li_time_integration_fe.F
@@ -29,8 +29,9 @@ module li_time_integration_fe
use mpas_log
use li_advection
- use li_calving, only: li_calve_ice, li_restore_calving_front
- use li_thermal, only: li_thermal_solver, li_basal_melt_floating_ice
+ use li_calving, only: li_calve_ice, li_restore_calving_front, li_calculate_damage, li_finalize_damage_after_advection
+ use li_thermal, only: li_thermal_solver
+ use li_iceshelf_melt
use li_diagnostic_vars
use li_setup
use li_constants
@@ -79,6 +80,7 @@ subroutine li_time_integrator_forwardeuler(domain, err)
use li_subglacial_hydro
use li_velocity
+ use li_bedtopo
!-----------------------------------------------------------------
! input variables
@@ -103,10 +105,14 @@ subroutine li_time_integrator_forwardeuler(domain, err)
integer :: err_tmp
logical, pointer :: config_restore_calving_front
+ logical, pointer :: config_calculate_damage
+ logical, pointer :: config_finalize_damage_after_advection
err = 0
call mpas_pool_get_config(liConfigs, 'config_restore_calving_front', config_restore_calving_front)
+ call mpas_pool_get_config(liConfigs, 'config_calculate_damage',config_calculate_damage)
+ call mpas_pool_get_config(liConfigs, 'config_finalize_damage_after_advection',config_finalize_damage_after_advection)
! === Prepare for advection (including CFL checks) ===========
! This has to come first currently, because it sets the time step!
@@ -115,6 +121,13 @@ subroutine li_time_integrator_forwardeuler(domain, err)
err = ior(err, err_tmp)
call mpas_timer_stop("advection prep")
+!TODO: Determine whether grounded melting should in fact be called first
+! === Face melting for grounded ice ===========
+ call mpas_timer_start("face melting for grounded ice")
+ call li_face_melt_grounded_ice(domain, err_tmp)
+ err = ior(err, err_tmp)
+ call mpas_timer_stop("face melting for grounded ice")
+
! === Basal melting for floating ice ===========
call mpas_timer_start("basal melting for floating ice")
call li_basal_melt_floating_ice(domain, err_tmp)
@@ -127,12 +140,28 @@ subroutine li_time_integrator_forwardeuler(domain, err)
err = ior(err, err_tmp)
call mpas_timer_stop("vertical therm")
+! === calculate damage ===========
+ if (config_calculate_damage) then
+ call mpas_timer_start("damage")
+ call li_calculate_damage(domain, err_tmp)
+ err = ior(err, err_tmp)
+ call mpas_timer_stop("damage")
+ endif
+
! === Compute new state for prognostic variables ==================================
call mpas_timer_start("advect thickness and tracers")
call advection_solver(domain, err_tmp)
err = ior(err, err_tmp)
call mpas_timer_stop("advect thickness and tracers")
+! === finalize damage after advection ===========
+ if (config_finalize_damage_after_advection) then
+ call mpas_timer_start("finalize damage")
+ call li_finalize_damage_after_advection(domain, err_tmp)
+ err = ior(err, err_tmp)
+ call mpas_timer_stop("finalize damage")
+ endif
+
! === Update subglacial hydrology ===========
! It's not clear where the best place to call this should be.
! Seems sensible to put it after thermal evolution is complete to get updated basal melting source term.
@@ -168,6 +197,13 @@ subroutine li_time_integrator_forwardeuler(domain, err)
call mpas_dmpar_field_halo_exch(domain, 'vertexMask')
call mpas_timer_stop("halo updates")
+! === Update bed topo =====================
+! It's not clear when the best time to do this is.
+! Seems cleaner to do it either before or after all of the time evolution of the ice
+! is complete. Putting it after.
+ call li_bedtopo_solve(domain, err=err_tmp)
+ err = ior(err, err_tmp)
+
! === Solve Velocity =====================
! During time-stepping, we always solveVelo
call li_velocity_solve(domain, solveVelo=.true., err=err_tmp)
@@ -246,11 +282,15 @@ subroutine prepare_advection(domain, err)
real (kind=RKIND), dimension(:,:), pointer :: normalVelocity
real (kind=RKIND), dimension(:,:), pointer :: layerNormalVelocity
+ integer, dimension(:), pointer :: edgeMask
logical, pointer :: config_print_thickness_advection_info
logical, pointer :: config_adaptive_timestep
logical, pointer :: config_adaptive_timestep_include_DCFL
+ character (len=StrKIND), pointer :: &
+ config_thickness_advection ! method for advecting thickness and tracers
+
integer :: &
allowableAdvecDtProcNumberHere, &
allowableAdvecDtProcNumber
@@ -300,6 +340,16 @@ subroutine prepare_advection(domain, err)
call mpas_pool_get_config(liConfigs, 'config_print_thickness_advection_info', config_print_thickness_advection_info)
call mpas_pool_get_config(liConfigs, 'config_adaptive_timestep', config_adaptive_timestep)
call mpas_pool_get_config(liConfigs, 'config_adaptive_timestep_include_DCFL', config_adaptive_timestep_include_DCFL)
+ call mpas_pool_get_config(liConfigs, 'config_thickness_advection', config_thickness_advection)
+
+ if (trim(config_thickness_advection) == 'none') then
+ if (config_adaptive_timestep) then
+ call mpas_log_write("Adaptive time stepper cannot be used when config_thickness_advection is set to 'none'", &
+ MPAS_LOG_ERR)
+ err = ior(err,1)
+ endif
+ return ! skip this routine
+ endif
allowableAdvecDtAllProcs = 0.0_RKIND
allowableDiffDtAllProcs = 0.0_RKIND
@@ -308,8 +358,6 @@ subroutine prepare_advection(domain, err)
! Initialize
- err = 0
-
allowableAdvecDtOnProc = 1.0e36_RKIND ! set to large number
allowableDiffDtOnProc = 1.0e36_RKIND ! set to large number
@@ -322,6 +370,7 @@ subroutine prepare_advection(domain, err)
call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
call mpas_pool_get_array(velocityPool, 'normalVelocity', normalVelocity)
+ call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
call mpas_pool_get_array(velocityPool, 'layerNormalVelocity', layerNormalVelocity)
! compute normal velocities and advective CFL limit for this block
@@ -329,6 +378,7 @@ subroutine prepare_advection(domain, err)
call li_layer_normal_velocity( &
meshPool, &
normalVelocity, &
+ edgeMask, &
layerNormalVelocity, &
allowableAdvecDt, &
err_tmp)
@@ -475,14 +525,16 @@ subroutine prepare_advection(domain, err)
! Check for CFL error before finishing
if (deltat > allowableAdvecDtOnProc) then
call mpas_log_write('Advective CFL violation on this processor. ' // &
- 'Maximum allowable time step for this processor is (Days_hhh:mmm:sss): ' // trim(allowableAdvecDtOnProcString), MPAS_LOG_ERR)
+ 'Maximum allowable time step for this processor is (Days_hhh:mmm:sss): ' // trim(allowableAdvecDtOnProcString), &
+ MPAS_LOG_ERR)
err = ior(err,1)
endif
! Local diffusive CFL info
if ( (config_adaptive_timestep_include_DCFL) .and. (deltat > allowableDiffDtOnProc) ) then
call mpas_log_write('Diffusive CFL violation on this processor. ' // &
- 'Maximum allowable time step for this processor is (Days_hhh:mmm:sss): ' // trim(allowableDiffDtOnProcString), MPAS_LOG_WARN)
+ 'Maximum allowable time step for this processor is (Days_hhh:mmm:sss): ' // trim(allowableDiffDtOnProcString), &
+ MPAS_LOG_WARN)
endif
if (err > 0) then
@@ -568,7 +620,7 @@ subroutine advection_solver(domain, err)
real (kind=RKIND), dimension(:), pointer :: thickness
real (kind=RKIND), dimension(:,:), pointer :: temperature
- real (kind=RKIND), dimension(:,:), pointer :: waterfrac
+ real (kind=RKIND), dimension(:,:), pointer :: waterFrac
real (kind=RKIND), dimension(:,:), pointer :: enthalpy
integer, pointer :: nCells
@@ -594,7 +646,7 @@ subroutine advection_solver(domain, err)
! Halo updates
! Note: The layer thickness and tracers must be up to date in halos before calling the advection subroutines.
- ! The thermal tracers (temperature, waterfrac, enthalpy) are updated at the end of li_thermal_solver.
+ ! The thermal tracers (temperature, waterFrac, enthalpy) are updated at the end of li_thermal_solver.
! But thickness (which is used by subroutine li_advection_thickness_tracers) needs an update here. TODO: confirm this
call mpas_timer_start("halo updates")
@@ -730,7 +782,7 @@ subroutine advection_solver(domain, err)
call mpas_dmpar_field_halo_exch(domain, 'thickness')
call mpas_dmpar_field_halo_exch(domain, 'temperature')
- call mpas_dmpar_field_halo_exch(domain, 'waterfrac')
+ call mpas_dmpar_field_halo_exch(domain, 'waterFrac')
call mpas_dmpar_field_halo_exch(domain, 'enthalpy')
call mpas_timer_stop("halo updates")
@@ -845,7 +897,9 @@ subroutine set_timestep(allowableAdvecDt, allowableDiffDt, clock, dtSeconds, err
call mpas_get_timeInterval(intervalToNextForceTime, dt=secondsToNextForceTime, ierr=err_tmp)
err = ior(err,err_tmp)
if (secondsToNextForceTime - real(floor(secondsToNextForceTime, KIND=8), RKIND) /= 0.0_RKIND) then
- call mpas_log_write("set_timestep found secondsToNextForceTime not equal to 0.0: $r, decimal part=$r", MPAS_LOG_ERR, realArgs=(/secondsToNextForceTime, secondsToNextForceTime - real(floor(secondsToNextForceTime, KIND=8), RKIND)/))
+ call mpas_log_write("set_timestep found secondsToNextForceTime not equal to 0.0: $r, decimal part=$r", &
+ MPAS_LOG_ERR, realArgs=(/secondsToNextForceTime, secondsToNextForceTime - &
+ real(floor(secondsToNextForceTime, KIND=8), RKIND)/))
err = ior(err, 1)
endif
!print *, proposedDt, secondsToNextForceTime
diff --git a/src/core_landice/mode_forward/mpas_li_velocity.F b/src/core_landice/mode_forward/mpas_li_velocity.F
index 3cf93c79b5..5bf5e0b03f 100644
--- a/src/core_landice/mode_forward/mpas_li_velocity.F
+++ b/src/core_landice/mode_forward/mpas_li_velocity.F
@@ -180,6 +180,7 @@ subroutine li_velocity_block_init(block, err)
!-----------------------------------------------------------------
character (len=StrKIND), pointer :: config_velocity_solver
+ type (mpas_pool_type), pointer :: velocityPool
err = 0
@@ -226,6 +227,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
use mpas_vector_reconstruction
use li_mask
use li_advection
+ use li_thermal
!-----------------------------------------------------------------
! input variables
@@ -256,6 +258,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
type (mpas_pool_type), pointer :: thermalPool
type (mpas_pool_type), pointer :: scratchPool
type (mpas_pool_type), pointer :: velocityPool
+ type (mpas_pool_type), pointer :: hydroPool
! pointers to get from pools
character (len=StrKIND), pointer :: config_velocity_solver
logical, pointer :: config_do_velocity_reconstruction_for_external_dycore
@@ -265,6 +268,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
integer, pointer :: nEdgesSolve
integer, pointer :: nEdges
integer, pointer :: nVertInterfaces
+ integer, pointer :: nCells
integer, dimension(:), pointer :: edgeMask, cellMask, vertexMask, vertexMaskOld
integer, dimension(:,:), pointer :: dirichletVelocityMaskOld, dirichletVelocityMaskNew
real (kind=RKIND), dimension(:,:), pointer :: normalVelocity, normalVelocityInitial
@@ -273,9 +277,10 @@ subroutine li_velocity_solve(domain, solveVelo, err)
real (kind=RKIND), dimension(:,:), pointer :: edgeNormalVectors
real (kind=RKIND), dimension(:), pointer :: thickness
real (kind=RKIND), dimension(:), pointer :: surfaceSpeed, basalSpeed
+ real (kind=RKIND), dimension(:), pointer :: xvelmean, yvelmean
real (kind=RKIND), dimension(:), pointer :: normalSlopeEdge
real (kind=RKIND), dimension(:), pointer :: dcEdge
- integer, dimension(:), pointer :: floatingEdges
+ real (kind=RKIND), dimension(:), pointer :: layerInterfaceFractions
integer, dimension(:,:), pointer :: cellsOnEdge
integer, dimension(:,:), pointer :: cellsOnVertex
integer, dimension(:,:), pointer :: verticesOnEdge
@@ -307,7 +312,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
config_do_velocity_reconstruction_for_external_dycore)
call mpas_pool_get_config(liConfigs, 'config_print_velocity_cleanup_details', config_print_velocity_cleanup_details)
call mpas_pool_get_config(liConfigs, 'config_dynamic_thickness', config_dynamic_thickness)
- call mpas_pool_get_config(liConfigs, 'config_adaptive_timestep_include_DCFL', config_adaptive_timestep_include_DCFL)
+ call mpas_pool_get_config(liConfigs, 'config_adaptive_timestep_include_DCFL', config_adaptive_timestep_include_DCFL)
uphillMarginEdgesFixed = 0
@@ -381,7 +386,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
maxThicknessOnProc = 0.0_RKIND ! initialize to
procDynamicVertexMaskChanged = 0
procDirichletMaskChanged = 0
-
+
block => domain % blocklist
do while (associated(block))
call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
@@ -392,11 +397,8 @@ subroutine li_velocity_solve(domain, solveVelo, err)
maxThicknessOnProc = max(maxThicknessOnProc, maxval(thickness))
! The interface expects an array where 1's are floating edges and 0's are non-floating edges.
- call mpas_pool_get_array(velocityPool, 'floatingEdges', floatingEdges)
call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
- floatingEdges = li_mask_is_floating_ice_int(edgeMask)
call mpas_pool_get_array(geometryPool, 'vertexMask', vertexMask, timeLevel=1)
- call li_calculate_extrapolate_floating_edgemask(meshPool, vertexMask, floatingEdges)
! Determine if the vertex mask changed during this time step for this block (needed for external dycores)
! TODO: There may be some aspects of the mask that are ok change for external dycores,
@@ -434,12 +436,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
! check for thickness on any proc
call mpas_dmpar_max_real(domain % dminfo, maxThicknessOnProc, maxThicknessAllProcs)
- ! Update halos on mask - the outermost cells/edges/vertices may be wrong for
- ! mask components that need neighbor information
- call mpas_timer_start("halo updates")
- call mpas_dmpar_field_halo_exch(domain, 'floatingEdges')
- call mpas_timer_stop("halo updates")
-
+
! Determine if the vertex mask has changed on any processor and store the value for later use
! (need to exit the block loop to do so)
! TODO Update all blocks with result (if ever support multiple blocks)
@@ -464,6 +461,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool)
call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve)
call mpas_pool_get_array(velocityPool, 'normalVelocity', normalVelocity)
@@ -499,7 +497,7 @@ subroutine li_velocity_solve(domain, solveVelo, err)
uReconstructZ = 0.0_RKIND
call mpas_log_write("Notice: Skipping velocity solve because there is no dynamic ice in domain.", MPAS_LOG_WARN)
else
- call li_velocity_external_solve(meshPool, geometryPool, thermalPool, scratchPool, velocityPool, err_tmp)
+ call li_velocity_external_solve(meshPool, geometryPool, thermalPool, hydroPool, scratchPool, velocityPool, err_tmp)
endif
case('simple')
@@ -585,6 +583,8 @@ subroutine li_velocity_solve(domain, solveVelo, err)
call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
+ call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
+ call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool)
! ---
! --- Calculate reconstructed velocities
@@ -592,6 +592,8 @@ subroutine li_velocity_solve(domain, solveVelo, err)
! do this after velocity halo update in case velocities on the 1-halo edge are wrong (depends on velocity solver)
! Still do this even if we didn't calculate velocity because on a restart these will be defined at the initial time.
call mpas_pool_get_dimension(meshPool, 'nVertInterfaces', nVertInterfaces)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_array(meshPool, 'layerInterfaceFractions', layerInterfaceFractions)
call mpas_pool_get_array(velocityPool, 'normalVelocity', normalVelocity)
call mpas_pool_get_array(velocityPool, 'uReconstructX', uReconstructX)
call mpas_pool_get_array(velocityPool, 'uReconstructY', uReconstructY)
@@ -600,6 +602,8 @@ subroutine li_velocity_solve(domain, solveVelo, err)
call mpas_pool_get_array(velocityPool, 'uReconstructMeridional', uReconstructMeridional)
call mpas_pool_get_array(velocityPool, 'surfaceSpeed', surfaceSpeed)
call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed)
+ call mpas_pool_get_array(velocityPool, 'xvelmean', xvelmean)
+ call mpas_pool_get_array(velocityPool, 'yvelmean', yvelmean)
! Velocities need to be reconstructed at cell centers for the native SIA dycore and for prescribed simple velocities.
! External dycores return their native velocities at cell center locations,
@@ -633,28 +637,49 @@ subroutine li_velocity_solve(domain, solveVelo, err)
uReconstructMeridional = uReconstructY
end if
+ ! ---
+ ! --- Remove floating ice where velocity is unrealistically fast
+ ! --- (Removed ice is added to calving flux)
+ ! --- (TODO: make this a namelist option?)
+ ! ---
+ call remove_fast_ice(meshPool, uReconstructX, uReconstructY, normalVelocity, geometryPool)
+
! ---
! --- Calculate diagnostic speed arrays
! ---
surfaceSpeed = sqrt(uReconstructX(1,:)**2 + uReconstructY(1,:)**2)
basalSpeed = sqrt(uReconstructX(nVertInterfaces,:)**2 + uReconstructY(nVertInterfaces,:)**2)
+ ! calculate vertical mean velocity
+ do iCell = 1, nCells
+ xvelmean(iCell) = sum(uReconstructX(:,iCell) * layerInterfaceFractions(:))
+ yvelmean(iCell) = sum(uReconstructY(:,iCell) * layerInterfaceFractions(:))
+ enddo
! ---
! --- Calculate strain rates on cell centers
! ---
- call calculate_strain_rates(meshPool, velocityPool, err_tmp)
+ call calculate_strain_rates_and_stresses(meshPool, geometryPool, thermalPool, scratchPool, velocityPool, err)
err = ior(err, err_tmp)
- ! ---
- ! --- Remove floating ice where velocity is unrealistically fast
- ! --- (Removed ice is added to calving flux)
- ! --- (TODO: make this a namelist option?)
- ! ---
- call remove_fast_ice(surfaceSpeed, geometryPool)
-
block => block % next
end do
+ ! calculate velocity-related thermal source term fields
+ ! (do it here to make restarts easier - this way only the fields need to be restart
+ ! variables, rather than the fields that are input to the calculations.)
+ if (solveVelo .and. (trim(config_velocity_solver) /= 'none')) then
+
+ ! (on a restart value, do not try to calculate these - instead use the fields in the restart file)
+ call li_basal_friction(domain, err_tmp)
+ err = ior(err, err_tmp)
+
+ if (trim(config_velocity_solver) == 'sia') then
+ ! For FO solver, heatDissipation is passed back from Albany
+ call li_heat_dissipation_sia(domain, err_tmp)
+ err = ior(err, err_tmp)
+ endif
+ endif
+
! === error check
if (err > 0) then
call mpas_log_write("An error has occurred in li_velocity_solve.", MPAS_LOG_ERR)
@@ -782,12 +807,13 @@ subroutine calculate_beta(block, err)
type (mpas_pool_type), pointer :: hydroPool
type (mpas_pool_type), pointer :: geometryPool
type (mpas_pool_type), pointer :: velocityPool
+ type (mpas_pool_type), pointer :: thermalPool
type (mpas_pool_type), pointer :: meshPool
real (kind=RKIND), dimension(:), pointer :: betaSolve, beta
- real (kind=RKIND), dimension(:), pointer :: effectivePressure
+ real (kind=RKIND), dimension(:), pointer :: basalTemperature, basalPmpTemperature
integer, dimension(:), pointer :: cellMask
logical, pointer :: config_use_glp
- logical, pointer :: config_beta_use_effective_pressure
+ logical, pointer :: config_beta_thawed_only
logical, pointer :: hydroActive
real (kind=RKIND) :: betaAccum
integer :: nBetaValues
@@ -800,10 +826,11 @@ subroutine calculate_beta(block, err)
err = 0
call mpas_pool_get_config(liConfigs, 'config_use_glp', config_use_glp)
- call mpas_pool_get_config(liConfigs, 'config_beta_use_effective_pressure', config_beta_use_effective_pressure)
+ call mpas_pool_get_config(liConfigs, 'config_beta_thawed_only', config_beta_thawed_only)
call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool)
call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool)
+ call mpas_pool_get_subpool(block % structs, 'thermal', thermalPool)
call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
call mpas_pool_get_array(velocityPool, 'betaSolve', betaSolve)
@@ -812,73 +839,35 @@ subroutine calculate_beta(block, err)
betaSolve = beta
- if (config_beta_use_effective_pressure) then
- call mpas_pool_get_package(liPackages, 'hydroActive', hydroActive)
- if (.not. hydroActive) then
- call mpas_log_write("config_beta_use_effective_pressure can only be used if the subglacial hydrology model is active.", &
- MPAS_LOG_ERR)
- err = ior(err, 1)
- return
- endif
- call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool)
- call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure)
- betaSolve = betaSolve * effectivePressure
-
- ! if using N-based friction with GLP, copy the value of beta across the grounding line
- ! to the floating side for the GLP to work properly
- if (config_use_glp) then
- call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
- call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
- call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell)
-
- do iCell = 1, nCells
- if (li_mask_is_floating_ice(cellMask(iCell))) then
- nBetaValues = 0
- betaAccum = 0.0_RKIND
- do iCell2 = 1, nEdgesOnCell(iCell)
- neighbor = cellsOnCell(iCell2, iCell)
- if (li_mask_is_grounded_ice(cellMask(neighbor))) then
- betaAccum = betaAccum + betaSolve(neighbor)
- nBetaValues = nBetaValues + 1
- endif
- enddo
- if (nBetaValues > 0) then
- betaSolve(iCell) = betaAccum / real(nBetaValues, kind=RKIND) ! take average of neighboring betas ! TODO: could do this in log space
- endif
- endif ! if iCell is floating
- enddo ! cell loop
- endif ! is using GLP with hydro friction law
- ! TODO: not sure if halo update needed here.
-
- end if ! if config_beta_use_effective_pressure
-
-
- if (.not. config_use_glp) then
- where (li_mask_is_floating_ice(cellMask))
- betaSolve = 0.0_RKIND
+ if (config_beta_thawed_only) then
+ call mpas_pool_get_array(thermalPool, 'basalTemperature', basalTemperature)
+ call mpas_pool_get_array(thermalPool, 'basalPmpTemperature', basalPmpTemperature)
+ where (basalPmpTemperature - basalTemperature > 0.01_RKIND)
+ ! Use a small difference to account for roundoff. 0.01 is value used in thermal module.
+ betaSolve = 1.0e6_RKIND ! no-slip value for frozen bed locations
end where
endif
-
!--------------------------------------------------------------------
end subroutine calculate_beta
!***********************************************************************
!
-! routine calculate_strain_rates
+! routine calculate_strain_rates_and_stresses
!
-!> \brief Calulates strain rates on cell centers
+!> \brief Calulates strain rates and stresses on cell centers
!> \author Matt Hoffman
!> \date Feb. 2018
!> \details
-!> This routine calculates strain rates on cell centers.
+!> This routine calculates strain rates and stresses on cell centers.
!
!-----------------------------------------------------------------------
- subroutine calculate_strain_rates(meshPool, velocityPool, err)
+ subroutine calculate_strain_rates_and_stresses(meshPool, geometryPool, thermalPool, scratchPool, velocityPool, err)
use li_setup
+ use li_diagnostic_vars
!-----------------------------------------------------------------
! input variables
@@ -886,6 +875,13 @@ subroutine calculate_strain_rates(meshPool, velocityPool, err)
type (mpas_pool_type), intent(in) :: &
meshPool !< Input: mesh object
+ type (mpas_pool_type), intent(in) :: &
+ geometryPool !< Input: geometry object
+ type (mpas_pool_type), intent(in) :: &
+ thermalPool !< Input: thermal object
+ type (mpas_pool_type), intent(in) :: &
+ scratchPool !< Input: scratch object
+
!-----------------------------------------------------------------
! input/output variables
!-----------------------------------------------------------------
@@ -900,44 +896,118 @@ subroutine calculate_strain_rates(meshPool, velocityPool, err)
!-----------------------------------------------------------------
! local variables
!-----------------------------------------------------------------
- real(kind=RKIND), dimension(:), pointer :: exx, eyy, exy, eyx, eTheta, eMax, eMin
- real(kind=RKIND), dimension(:,:), pointer :: uReconstructX, uReconstructY
+ real(kind=RKIND), dimension(:), pointer :: exx, eyy, exy, eTheta, eMax, eMin, dudy, dvdx
+ real(kind=RKIND), dimension(:), pointer :: xvelmean, yvelmean
+ real(kind=RKIND), dimension(:), pointer :: tauxx, tauyy, tauxy, tauMax, tauMin
integer :: err_tmp
+ real(kind=RKIND), pointer :: config_flowLawExponent
+
+ real (kind=RKIND), dimension(:), pointer :: thickness
+ real (kind=RKIND), dimension(:,:), pointer :: temperature
+ real (kind=RKIND), dimension(:,:), pointer :: flowParamA
+ real (kind=RKIND), dimension(:), pointer :: effectiveViscosity
+ real (kind=RKIND), dimension(:), pointer :: stiffnessFactor
+
+ type (field1dReal), pointer :: meanFlowParamAVar
+ real (kind=RKIND), dimension(:), pointer :: meanFlowParamA
+
+ integer, pointer :: nVertLevels
+ integer, pointer :: nCells
+
+ integer :: iCell
+
+ real(kind=RKIND) :: eEff
+
err = 0
- call mpas_pool_get_array(velocityPool, 'uReconstructX', uReconstructX)
- call mpas_pool_get_array(velocityPool, 'uReconstructY', uReconstructY)
+ call mpas_pool_get_array(velocityPool, 'xvelmean', xvelmean)
+ call mpas_pool_get_array(velocityPool, 'yvelmean', yvelmean)
+
+ call mpas_pool_get_config(liConfigs, 'config_flowLawExponent', config_flowLawExponent)
+
+ call mpas_pool_get_dimension(meshPool, 'nVertLevels', nVertLevels)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+
call mpas_pool_get_array(velocityPool, 'exx', exx)
call mpas_pool_get_array(velocityPool, 'eyy', eyy)
+ call mpas_pool_get_array(velocityPool, 'dudy', dudy)
+ call mpas_pool_get_array(velocityPool, 'dvdx', dvdx)
call mpas_pool_get_array(velocityPool, 'exy', exy)
- call mpas_pool_get_array(velocityPool, 'eyx', eyx)
call mpas_pool_get_array(velocityPool, 'eTheta', eTheta)
call mpas_pool_get_array(velocityPool, 'eMax', eMax)
call mpas_pool_get_array(velocityPool, 'eMin', eMin)
+ call mpas_pool_get_array(velocityPool, 'tauxx', tauxx)
+ call mpas_pool_get_array(velocityPool, 'tauyy', tauyy)
+ call mpas_pool_get_array(velocityPool, 'tauxy', tauxy)
+ call mpas_pool_get_array(velocityPool, 'tauMax', tauMax)
+ call mpas_pool_get_array(velocityPool, 'tauMin', tauMin)
+
+ call mpas_pool_get_array(thermalPool, 'temperature', temperature)
+ call mpas_pool_get_array(velocityPool, 'flowParamA', flowParamA)
+ call mpas_pool_get_array(velocityPool, 'stiffnessFactor', stiffnessFactor)
+
+ call mpas_pool_get_array(geometryPool, 'thickness', thickness)
+ call mpas_pool_get_array(geometryPool, 'effectiveViscosity', effectiveViscosity)
+
+ call mpas_pool_get_field(scratchPool, 'meanFlowParamA', meanFlowParamAVar)
+ call mpas_allocate_scratch_field(meanFlowParamAVar, .true.)
+ meanFlowParamA => meanFlowParamAVar % array
+
! Calculate strain rates
- call li_compute_gradient_2d(meshPool, uReconstructX(1,:), exx, exy, err_tmp)
+ call li_compute_gradient_2d(meshPool, xvelmean, exx, dudy, err_tmp)
err = ior(err, err_tmp)
- call li_compute_gradient_2d(meshPool, uReconstructY(1,:), eyx, eyy, err_tmp)
+ call li_compute_gradient_2d(meshPool, yvelmean, dvdx, eyy, err_tmp)
err = ior(err, err_tmp)
+ exy = 0.5_RKIND * (dudy + dvdx)
+
! Calculate principal strain rate angle
- eTheta = 0.5_RKIND * atan( (exy + eyx) / (exx - eyy + 1.0e-42_RKIND) )
+ eTheta = 0.5_RKIND * atan( (2.0_RKIND * exy) / (exx - eyy + 1.0e-42_RKIND) )
! Calculate principal strain rates
- eMax = 0.5_RKIND * (exx + eyy) + sqrt( (0.5_RKIND * (exx - eyy))**2 + (0.25_RKIND*(exy + eyx))**2)
- eMin = 0.5_RKIND * (exx + eyy) - sqrt( (0.5_RKIND * (exx - eyy))**2 + (0.25_RKIND*(exy + eyx))**2)
+ eMax = 0.5_RKIND * (exx + eyy) + sqrt( (0.5_RKIND * (exx - eyy))**2 + exy**2)
+ eMin = 0.5_RKIND * (exx + eyy) - sqrt( (0.5_RKIND * (exx - eyy))**2 + exy**2)
+
+ call li_calculate_flowParamA(meshPool, temperature, thickness, flowParamA, err_tmp)
+ err = ior(err, err_tmp)
+
+ ! calculate the depth-averaged flow parameter A
+ meanFlowParamA(:) = sum(flowParamA(:,:), dim=1)/REAL(nVertLevels, kind=RKIND)
+
+ ! calculate effective viscosity from strain rate and flow param.
+ do iCell = 1, nCells
+ eEff = sqrt(exx(iCell)**2 + eyy(iCell)**2 + exx(iCell)*eyy(iCell) + exy(iCell)**2) ! effective strain rate
+ if (eEff == 0.0_RKIND) then
+ effectiveViscosity(iCell) = 0.0_RKIND
+ else
+ effectiveViscosity(iCell) = &
+ 0.5_RKIND*stiffnessFactor(iCell)*meanFlowParamA(iCell)**(-1.0_RKIND/config_flowLawExponent)* &
+ eEff**((1.0_RKIND-config_flowLawExponent)/config_flowLawExponent)
+ endif
+ enddo
+
+ ! calculate deviatoric stresses
+ tauxx(:) = 2.0_RKIND*effectiveViscosity(:)*exx(:)
+ tauyy(:) = 2.0_RKIND*effectiveViscosity(:)*eyy(:)
+ tauxy(:) = 2.0_RKIND*effectiveViscosity(:)*exy(:)
+
+ ! calculate principal stresses
+ tauMin(:) = (tauxx(:)+tauyy(:))/2.0_RKIND - sqrt(((tauxx(:)-tauyy(:))/2.0_RKIND)**2 + tauxy(:)**2)
+ tauMax(:) = (tauxx(:)+tauyy(:))/2.0_RKIND + sqrt(((tauxx(:)-tauyy(:))/2.0_RKIND)**2 + tauxy(:)**2)
+
+ call mpas_deallocate_scratch_field(meanFlowParamAVar, .true.)
!--------------------------------------------------------------------
- end subroutine calculate_strain_rates
+ end subroutine calculate_strain_rates_and_stresses
!***********************************************************************
!
! routine remove_fast_ice
!
-!> \brief Removes floating ice with a fast surface speed, presumably an iceberg
+!> \brief Removes ice with a fast surface speed, presumably an iceberg
!> \author Matt Hoffman
!> \date March 2018
!> \details
@@ -945,18 +1015,21 @@ end subroutine calculate_strain_rates
!
!-----------------------------------------------------------------------
- subroutine remove_fast_ice(surfaceSpeed, geometryPool)
+ subroutine remove_fast_ice(meshPool, uReconstructX, uReconstructY, normalVelocity, geometryPool)
use li_mask
!-----------------------------------------------------------------
! input variables
!-----------------------------------------------------------------
- real(kind=RKIND), dimension(:) :: surfaceSpeed
+ type (mpas_pool_type), intent(in) :: meshPool
!-----------------------------------------------------------------
! input/output variables
!-----------------------------------------------------------------
+ real(kind=RKIND), dimension(:,:), intent(inout) :: uReconstructX
+ real(kind=RKIND), dimension(:,:), intent(inout) :: uReconstructY
+ real(kind=RKIND), dimension(:,:), intent(inout) :: normalVelocity
type (mpas_pool_type), intent(inout) :: geometryPool
!-----------------------------------------------------------------
@@ -966,19 +1039,51 @@ subroutine remove_fast_ice(surfaceSpeed, geometryPool)
!-----------------------------------------------------------------
! local variables
!-----------------------------------------------------------------
+ real(kind=RKIND), pointer :: config_unrealistic_velocity
+ integer, pointer :: nCells
+ integer, dimension(:), pointer :: nEdgesOnCell
+ integer, dimension(:,:), pointer :: edgesOnCell
real(kind=RKIND), dimension(:), pointer :: thickness, calvingThickness
+ real(kind=RKIND), dimension(:), pointer :: upperSurface, lowerSurface
integer, dimension(:), pointer :: cellMask
- real(kind=RKIND), parameter :: highSpeed = 0.00318471337_RKIND ! 100,000 m/yr in m/s
+ integer :: iCell, iEdgeOnCell, iEdge
+ integer :: cellCount
+ call mpas_pool_get_config(liConfigs, 'config_unrealistic_velocity', config_unrealistic_velocity)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness)
+ call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface)
+ call mpas_pool_get_array(geometryPool, 'lowerSurface', lowerSurface)
- where (li_mask_is_floating_ice(cellMask) .and. (surfaceSpeed > highSpeed))
+
+ cellCount = 0
+ do iCell = 1, nCells
+ if ((li_mask_is_ice(cellMask(iCell))) .and. &
+ (sqrt(uReconstructX(1,iCell)**2 + uReconstructY(1,iCell)**2) > config_unrealistic_velocity)) then
! "fast" ice that is removed is added to the calving flux
- calvingThickness = calvingThickness + thickness
- thickness = 0.0_RKIND
- end where
+ calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell)
+ thickness(iCell) = 0.0_RKIND
+ uReconstructX(:,iCell) = 0.0_RKIND
+ uReconstructY(:,iCell) = 0.0_RKIND
+ do iEdgeOnCell = 1, nEdgesOnCell(iCell)
+ iEdge = edgesOnCell(iEdgeOnCell,iCell)
+ normalVelocity(:,iEdge) = 0.0_RKIND
+ enddo
+ upperSurface(iCell) = 0.0_RKIND
+ lowerSurface(iCell) = 0.0_RKIND
+ ! TODO Should also zero temperature/tracers
+ cellCount = cellCount + 1
+ endif
+ end do
+
+ if (cellCount > 0) then
+ call mpas_log_write("Removed $i cells due to speeds greater than $r m/s.", &
+ intArgs=(/cellCount/), realArgs=(/config_unrealistic_velocity/))
+ endif
!--------------------------------------------------------------------
end subroutine remove_fast_ice
diff --git a/src/core_landice/mode_forward/mpas_li_velocity_external.F b/src/core_landice/mode_forward/mpas_li_velocity_external.F
index ecf6e20d07..b769369042 100644
--- a/src/core_landice/mode_forward/mpas_li_velocity_external.F
+++ b/src/core_landice/mode_forward/mpas_li_velocity_external.F
@@ -62,8 +62,9 @@ module li_velocity_external
! Note: Could add all interface routines to this interface...
! For now, just trying it with this new routine.
subroutine velocity_solver_set_parameters(gravity, config_ice_density, config_ocean_density, config_sea_level, &
- config_default_flowParamA, config_enhancementFactor, &
+ config_default_flowParamA, &
config_flowLawExponent, config_dynamic_thickness, iceMeltingPointPressureDependence, &
+ config_thermal_thickness, &
li_mask_ValueDynamicIce, li_mask_ValueIce, config_use_glp) &
bind(C, name="velocity_solver_set_parameters")
@@ -71,8 +72,9 @@ subroutine velocity_solver_set_parameters(gravity, config_ice_density, config_oc
INTEGER(C_INT) :: li_mask_ValueDynamicIce, li_mask_ValueIce
REAL(C_DOUBLE) :: config_ice_density, config_ocean_density, config_sea_level, config_default_flowParamA, &
- config_enhancementFactor, config_flowLawExponent, config_dynamic_thickness, gravity, &
- iceMeltingPointPressureDependence
+ config_flowLawExponent, config_dynamic_thickness, gravity, &
+ iceMeltingPointPressureDependence, &
+ config_thermal_thickness
LOGICAL(C_BOOL) :: config_use_glp
end subroutine velocity_solver_set_parameters
@@ -148,8 +150,8 @@ subroutine li_velocity_external_init(domain, err)
call mpas_pool_get_config(liConfigs, 'config_velocity_solver', config_velocity_solver)
! Check for configuration options that are incompatible with external velocity solver conventions
- if (config_num_halos < 2) then
- call mpas_log_write("External velocity solvers require that config_num_halos >= 2", MPAS_LOG_ERR)
+ if (config_num_halos < 3) then
+ call mpas_log_write("External velocity solvers require that config_num_halos >= 3", MPAS_LOG_ERR)
err_tmp = 1
endif
err = ior(err,err_tmp)
@@ -261,7 +263,7 @@ subroutine li_velocity_external_block_init(block, err)
real (kind=RKIND), pointer :: radius
type (field1DInteger), pointer :: indexToCellIDField, indexToEdgeIDField, indexToVertexIDField
real (kind=RKIND), pointer :: config_ice_density, config_ocean_density, config_sea_level, config_default_flowParamA, &
- config_enhancementFactor, config_flowLawExponent, config_dynamic_thickness
+ config_thermal_thickness, config_flowLawExponent, config_dynamic_thickness
logical, pointer :: config_use_glp
! halo exchange arrays
@@ -327,7 +329,7 @@ subroutine li_velocity_external_block_init(block, err)
call velocity_solver_set_grid_data(nCells, nEdges, nVertices, nVertInterfaces, &
nCellsSolve, nEdgesSolve, nVerticesSolve, maxNEdgesOnCell, radius, &
cellsOnEdge, cellsOnVertex, verticesOnCell, verticesOnEdge, edgesOnCell, &
- nEdgesOnCell, indexToCellID, &
+ nEdgesOnCell, indexToCellID, indexToEdgeID, indexToVertexID, &
xCell, yCell, zCell, xVertex, yVertex, zVertex, areaTriangle, &
sendCellsArray, recvCellsArray, &
sendEdgesArray, recvEdgesArray, &
@@ -351,15 +353,16 @@ subroutine li_velocity_external_block_init(block, err)
call mpas_pool_get_config(liConfigs, 'config_ocean_density', config_ocean_density)
call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level)
call mpas_pool_get_config(liConfigs, 'config_default_flowParamA', config_default_flowParamA)
- call mpas_pool_get_config(liConfigs, 'config_enhancementFactor', config_enhancementFactor)
call mpas_pool_get_config(liConfigs, 'config_flowLawExponent', config_flowLawExponent)
+ call mpas_pool_get_config(liConfigs, 'config_thermal_thickness', config_thermal_thickness)
call mpas_pool_get_config(liConfigs, 'config_dynamic_thickness', config_dynamic_thickness)
call mpas_pool_get_config(liConfigs, 'config_use_glp', config_use_glp)
#if defined(USE_EXTERNAL_L1L2) || defined(USE_EXTERNAL_FIRSTORDER) || defined(USE_EXTERNAL_STOKES)
call velocity_solver_set_parameters(gravity, config_ice_density, config_ocean_density, config_sea_level, &
- config_default_flowParamA, config_enhancementFactor, &
+ config_default_flowParamA, &
config_flowLawExponent, config_dynamic_thickness, &
iceMeltingPointPressureDependence, &
+ config_thermal_thickness, &
li_mask_ValueAlbanyActive, li_mask_ValueIce, &
logical(config_use_glp, KIND=1) )
@@ -390,7 +393,7 @@ end subroutine li_velocity_external_block_init
!
!-----------------------------------------------------------------------
- subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scratchPool, velocityPool, err)
+ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, hydroPool, scratchPool, velocityPool, err)
use li_mask
@@ -409,6 +412,9 @@ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scrat
type (mpas_pool_type), intent(in) :: &
thermalPool !< Input: thermal information
+ type (mpas_pool_type), intent(in) :: &
+ hydroPool !< Input: hydro information
+
type (mpas_pool_type), intent(in) :: &
scratchPool !< Input: scratch information
@@ -437,23 +443,34 @@ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scrat
real (kind=RKIND), dimension(:), pointer :: &
thickness, bedTopography, lowerSurface, upperSurface, layerThicknessFractions, betaSolve, sfcMassBal
+ real (kind=RKIND), dimension(:), pointer :: drivingStressVert
+ real (kind=RKIND), dimension(:), pointer :: drivingStress
real (kind=RKIND), dimension(:,:), pointer :: &
normalVelocity, uReconstructX, uReconstructY, uReconstructZ
real (kind=RKIND), dimension(:,:), pointer :: temperature
+ real (kind=RKIND), dimension(:), pointer :: stiffnessFactor
+ real (kind=RKIND), dimension(:), pointer :: effectivePressure
+ real (kind=RKIND), dimension(:), pointer :: effectivePressureLimited
+ real (kind=RKIND), dimension(:), pointer :: muFriction
real (kind=RKIND), pointer :: deltat
- integer, dimension(:), pointer :: vertexMask, cellMask, edgeMask, floatingEdges
+ integer, dimension(:), pointer :: vertexMask, cellMask, edgeMask
integer, dimension(:,:), pointer :: dirichletVelocityMask
character (len=StrKIND), pointer :: config_velocity_solver
logical, pointer :: config_always_compute_fem_grid
logical, pointer :: config_output_external_velocity_solver_data
+ logical, pointer :: config_nonconvergence_error
real (kind=RKIND), pointer :: config_ice_density
+ real (kind=RKIND), pointer :: config_effective_pressure_max
integer, pointer :: anyDynamicVertexMaskChanged
integer, pointer :: dirichletMaskChanged
integer, pointer :: nEdges
+ integer, pointer :: nCells
+ integer, pointer :: nVertLevels
integer, pointer :: timestepNumber
type (field2dReal), pointer :: dissipationVertexField
real (kind=RKIND), dimension(:,:), pointer :: heatDissipation ! on cells
integer :: iEdge
+ integer :: iCell
real(kind=RKIND), parameter :: secondsInYear = 365.0_RKIND * 24.0_RKIND * 3600.0_RKIND
!< The value of seconds in a year assumed by external dycores
integer, target :: err_tmp
@@ -467,13 +484,16 @@ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scrat
call mpas_pool_get_config(liConfigs, 'config_always_compute_fem_grid', config_always_compute_fem_grid)
call mpas_pool_get_config(liConfigs, 'config_output_external_velocity_solver_data', &
config_output_external_velocity_solver_data)
+ call mpas_pool_get_config(liConfigs, 'config_nonconvergence_error', config_nonconvergence_error)
call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density)
+ call mpas_pool_get_config(liConfigs, 'config_effective_pressure_max', config_effective_pressure_max)
! Mesh variables
call mpas_pool_get_array(meshPool, 'layerThicknessFractions', layerThicknessFractions)
call mpas_pool_get_array(meshPool, 'deltat', deltat)
call mpas_pool_get_array(meshPool, 'timestepNumber', timestepNumber)
call mpas_pool_get_dimension(meshPool, 'nEdges', nEdges)
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
! Geometry variables
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
@@ -495,16 +515,29 @@ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scrat
call mpas_pool_get_array(velocityPool, 'uReconstructY', uReconstructY)
call mpas_pool_get_array(velocityPool, 'uReconstructZ', uReconstructZ)
call mpas_pool_get_array(velocityPool, 'betaSolve', betaSolve)
+ call mpas_pool_get_array(velocityPool, 'drivingStressVert', drivingStressVert)
+ call mpas_pool_get_array(velocityPool, 'drivingStress', drivingStress)
+ call mpas_pool_get_array(velocityPool, 'muFriction', muFriction)
call mpas_pool_get_array(velocityPool, 'anyDynamicVertexMaskChanged', anyDynamicVertexMaskChanged)
call mpas_pool_get_array(velocityPool, 'dirichletMaskChanged', dirichletMaskChanged)
call mpas_pool_get_array(velocityPool, 'dirichletVelocityMask', dirichletVelocityMask, timeLevel = 1)
- call mpas_pool_get_array(velocityPool, 'floatingEdges', floatingEdges)
+ call mpas_pool_get_array(velocityPool, 'stiffnessFactor', stiffnessFactor)
+
+ ! Hydro variables
+ call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure)
+ call mpas_pool_get_array(velocityPool, 'effectivePressureLimited', effectivePressureLimited)
#if defined(USE_EXTERNAL_L1L2) || defined(USE_EXTERNAL_FIRSTORDER) || defined(USE_EXTERNAL_STOKES)
! Capture Albany output
call interface_redirect_stdout(timestepNumber)
#endif
+ ! Create version of effectivePressure field with limits applied
+ do iCell = 1, nCells
+ effectivePressureLimited(iCell) = max(0.0_RKIND, effectivePressure(iCell)) ! Never pass a negative N
+ effectivePressureLimited(iCell) = min(config_effective_pressure_max, effectivePressureLimited(iCell))
+ enddo
+
! ==================================================================
! External dycore calls to be made only when vertex mask changes
! ==================================================================
@@ -515,7 +548,7 @@ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scrat
(dirichletMaskChanged == 1) ) then
call mpas_log_write("Generating new external velocity solver FEM grid.", flushNow=.true.)
call generate_fem_grid(config_velocity_solver, vertexMask, cellMask, dirichletVelocityMask, &
- floatingEdges, layerThicknessFractions, lowerSurface, thickness, err)
+ layerThicknessFractions, lowerSurface, thickness, err)
endif
@@ -564,23 +597,33 @@ subroutine li_velocity_external_solve(meshPool, geometryPool, thermalPool, scrat
call mpas_timer_start("velocity_solver_solve_FO")
err_albany => err_tmp
call velocity_solver_solve_FO(bedTopography, lowerSurface, thickness, &
- betaSolve, sfcMassBal, temperature, &
+ betaSolve, sfcMassBal, temperature, stiffnessFactor, &
+ effectivePressureLimited, muFriction, &
uReconstructX, uReconstructY, & ! Dirichlet boundary values to apply where dirichletVelocityMask=1
- normalVelocity, dissipationVertexField % array, uReconstructX, uReconstructY, & ! return values
+ normalVelocity, drivingStressVert, dissipationVertexField % array, uReconstructX, uReconstructY, & ! return values
deltat, err_albany) ! return values
-! call velocity_solver_estimate_SS_SMB(normalVelocity, mesh % sfcMassBal % array) ! this was used only for some ice2sea experiments, and is not a general routine to use
call mpas_timer_stop("velocity_solver_solve_FO")
- if (err_tmp > 0) then
- call mpas_log_write("Albany velocity solve encountered an error! Check log.albany.0000.out for more information.", MPAS_LOG_ERR)
+ if (err_tmp == 1) then
+ if (config_nonconvergence_error) then
+ call mpas_log_write("Albany velocity solve failed to converge! " // &
+ "Check log.albany.0000.out for more information.", MPAS_LOG_ERR)
+ else
+ call mpas_log_write("Albany velocity solve failed to converge! " // &
+ "Check log.albany.0000.out for more information.", MPAS_LOG_WARN)
+ err_tmp = 0
+ endif
endif
err = ior(err,err_tmp)
+
! Now interpolate from vertices to cell centers
call li_interpolate_vertex_to_cell_2d(meshPool, dissipationVertexField % array, heatDissipation)
heatDissipation = heatDissipation / (config_ice_density * cp_ice)
call mpas_deallocate_scratch_field(dissipationVertexField, .true.)
+ call li_interpolate_vertex_to_cell_1d(meshPool, drivingStressVert, drivingStress)
+
if (config_output_external_velocity_solver_data) then
call mpas_timer_start("velocity_solver export")
call velocity_solver_export_FO_velocity()
@@ -683,7 +726,7 @@ subroutine li_velocity_external_finalize(err)
#if defined(USE_EXTERNAL_L1L2) || defined(USE_EXTERNAL_FIRSTORDER) || defined(USE_EXTERNAL_STOKES)
! This call is needed for using any of the external velocity solvers
- ! call velocity_solver_finalize()
+ call velocity_solver_finalize()
#else
call mpas_log_write("To run with an external velocity solver you must compile MPAS with one.", MPAS_LOG_ERR)
err = 1
@@ -736,10 +779,16 @@ subroutine li_velocity_external_write_albany_mesh(domain)
observedSurfaceVelocityX, observedSurfaceVelocityY, observedSurfaceVelocityUncertainty
real (kind=RKIND), dimension(:), pointer :: observedThicknessTendency, observedThicknessTendencyUncertainty
real (kind=RKIND), dimension(:,:), pointer :: temperature
- integer, dimension(:), pointer :: vertexMask, cellMask, edgeMask, floatingEdges, indexToCellID
+ real (kind=RKIND), dimension(:), pointer :: surfaceAirTemperature, basalHeatFlux
+ integer, dimension(:), pointer :: vertexMask, cellMask, edgeMask, indexToCellID
+ real (kind=RKIND), dimension(:,:), pointer :: layerThickness
+ real (kind=RKIND), dimension(:), pointer :: stiffnessFactor
+ real (kind=RKIND), dimension(:), pointer :: effectivePressure
+ real (kind=RKIND), dimension(:), pointer :: muFriction
integer, dimension(:,:), pointer :: dirichletVelocityMask
- type (mpas_pool_type), pointer :: meshPool, geometryPool, thermalPool, observationsPool, velocityPool
+ type (mpas_pool_type), pointer :: meshPool, geometryPool, thermalPool, observationsPool, velocityPool, scratchPool, hydroPool
real (kind=RKIND), pointer :: config_sea_level, config_ice_density, config_ocean_density
+ integer :: iCell
integer :: err
call mpas_pool_get_config(liConfigs, 'config_write_albany_ascii_mesh', config_write_albany_ascii_mesh)
@@ -764,10 +813,6 @@ subroutine li_velocity_external_write_albany_mesh(domain)
call mpas_log_write("config_velocity solver needs to be set to 'FO' for config_write_albany_ascii_mesh to work.", &
MPAS_LOG_CRIT)
endif
- ! check nProcs
- if (domain % dminfo % nProcs /= 1) then
- call mpas_log_write("config_write_albany_ascii_mesh currently only works on 1 processor.", MPAS_LOG_CRIT)
- endif
! check nBlocks
if (domain % dminfo % total_blocks /= 1) then
call mpas_log_write("config_write_albany_ascii_mesh currently only works on 1 block per processor.", MPAS_LOG_CRIT)
@@ -778,8 +823,10 @@ subroutine li_velocity_external_write_albany_mesh(domain)
call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool)
call mpas_pool_get_subpool(domain % blocklist % structs, 'geometry', geometryPool)
call mpas_pool_get_subpool(domain % blocklist % structs, 'thermal', thermalPool)
+ call mpas_pool_get_subpool(domain % blocklist % structs, 'hydro', hydroPool)
call mpas_pool_get_subpool(domain % blocklist % structs, 'velocity', velocityPool)
call mpas_pool_get_subpool(domain % blocklist % structs, 'observations', observationsPool)
+ call mpas_pool_get_subpool(domain % blocklist % structs, 'scratch', scratchPool)
! Mesh variables
call mpas_pool_get_array(meshPool, 'layerThicknessFractions', layerThicknessFractions)
@@ -794,14 +841,21 @@ subroutine li_velocity_external_write_albany_mesh(domain)
call mpas_pool_get_array(geometryPool, 'vertexMask', vertexMask, timeLevel = 1)
call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
+ call mpas_pool_get_array(geometryPool, 'layerThickness', layerThickness)
! Velocity variables
call mpas_pool_get_array(velocityPool, 'beta', beta)
- call mpas_pool_get_array(velocityPool, 'floatingEdges', floatingEdges)
+ call mpas_pool_get_array(velocityPool, 'muFriction', muFriction)
call mpas_pool_get_array(velocityPool, 'dirichletVelocityMask', dirichletVelocityMask, timeLevel = 1)
+ call mpas_pool_get_array(velocityPool, 'stiffnessFactor', stiffnessFactor)
! Thermal variables
call mpas_pool_get_array(thermalPool, 'temperature', temperature)
+ call mpas_pool_get_array(thermalPool, 'surfaceAirTemperature', surfaceAirTemperature)
+ call mpas_pool_get_array(thermalPool, 'basalHeatFlux', basalHeatFlux)
+
+ ! hydro variables
+ call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure)
! Observation variables
call mpas_pool_get_array(observationsPool, 'observedSurfaceVelocityX', observedSurfaceVelocityX)
@@ -815,7 +869,7 @@ subroutine li_velocity_external_write_albany_mesh(domain)
!----
- ! Calculate diagnostic variables to get 1. lowerSurface, 2. mask fields 3. floatingedges and updated edgemask.
+ ! Calculate diagnostic variables to get 1. lowerSurface, 2. mask fields 3. updated edgemask.
! We could call diagnostic_solve_before_velocity to do all that, but the way
! code is currently organized, that would be a circular dependency.a
@@ -828,18 +882,23 @@ subroutine li_velocity_external_write_albany_mesh(domain)
lowerSurface = bedTopography
end where
- floatingEdges = li_mask_is_floating_ice_int(edgeMask)
- call li_calculate_extrapolate_floating_edgemask(meshPool, vertexMask, floatingEdges)
+ ! Ensure BMB uncertainty is 0 for grounded ice (and no ice locations)
+ where (.not. (li_mask_is_floating_ice(cellMask)))
+ floatingBasalMassBalUncertainty = 0.0_RKIND
+ end where
! Create FEM mesh
call mpas_log_write("Generating new external velocity solver FEM grid.", flushNow=.true.)
call generate_fem_grid(config_velocity_solver, vertexMask, cellMask, dirichletVelocityMask, &
- floatingEdges, layerThicknessFractions, lowerSurface, thickness, err)
+ layerThicknessFractions, lowerSurface, thickness, err)
! call the C++ routine to write the mesh
call mpas_log_write("Writing Albany ASCII mesh.", flushNow=.true.)
call write_ascii_mesh(indexToCellID, bedTopography, lowerSurface, &
beta, temperature, &
+ surfaceAirTemperature, basalHeatFlux, &
+ stiffnessFactor, &
+ effectivePressure, muFriction, &
thickness, thicknessUncertainty, &
sfcMassBal, sfcMassBalUncertainty, &
floatingBasalMassBal, floatingBasalMassBalUncertainty, &
@@ -850,6 +909,7 @@ subroutine li_velocity_external_write_albany_mesh(domain)
call interface_reset_stdout()
+
! kill the model so we don't actually run the forward model
call mpas_log_write("Write of Albany ASCII mesh complete. Terminating execution normally.", MPAS_LOG_CRIT)
@@ -942,14 +1002,14 @@ end subroutine interface_stokes_init
!
!-----------------------------------------------------------------------
- subroutine generate_fem_grid(config_velocity_solver, vertexMask, cellMask, dirichletVelocityMask, floatingEdges, &
+ subroutine generate_fem_grid(config_velocity_solver, vertexMask, cellMask, dirichletVelocityMask, &
layerThicknessFractions, lowerSurface, thickness, err)
!-----------------------------------------------------------------
! input variables
!-----------------------------------------------------------------
character (len=StrKIND), pointer :: config_velocity_solver
- integer, pointer, dimension(:), intent(in) :: vertexMask, cellMask, floatingEdges
+ integer, pointer, dimension(:), intent(in) :: vertexMask, cellMask
integer, pointer, dimension(:,:), intent(in) :: dirichletVelocityMask
real(kind=RKIND), pointer, dimension(:), intent(in) :: layerThicknessFractions, &
lowerSurface, thickness
@@ -972,7 +1032,7 @@ subroutine generate_fem_grid(config_velocity_solver, vertexMask, cellMask, diric
#if defined(USE_EXTERNAL_L1L2) || defined(USE_EXTERNAL_FIRSTORDER) || defined(USE_EXTERNAL_STOKES)
call mpas_timer_start("velocity_solver_compute_2d_grid")
- call velocity_solver_compute_2d_grid(vertexMask, cellMask, dirichletVelocityMask, floatingEdges)
+ call velocity_solver_compute_2d_grid(vertexMask, cellMask, dirichletVelocityMask)
call mpas_timer_stop("velocity_solver_compute_2d_grid")
#else
call mpas_log_write("To run with an external velocity solver you must compile MPAS with one.", MPAS_LOG_ERR)
@@ -996,7 +1056,7 @@ subroutine generate_fem_grid(config_velocity_solver, vertexMask, cellMask, diric
case ('FO') ! ===============================================
#ifdef USE_EXTERNAL_FIRSTORDER
call mpas_timer_start("velocity_solver_extrude_3d_grid")
- call velocity_solver_extrude_3d_grid(layerThicknessFractions, lowerSurface, thickness)
+ call velocity_solver_extrude_3d_grid(layerThicknessFractions)
call mpas_timer_stop("velocity_solver_extrude_3d_grid")
call mpas_timer_start("velocity_solver_init_FO")
call velocity_solver_init_FO(layerThicknessFractions)
diff --git a/src/core_landice/shared/mpas_li_constants.F b/src/core_landice/shared/mpas_li_constants.F
index 156642d421..6f3a63181f 100644
--- a/src/core_landice/shared/mpas_li_constants.F
+++ b/src/core_landice/shared/mpas_li_constants.F
@@ -29,6 +29,7 @@ module li_constants
triple_point => SHR_CONST_TKTRIP,&
rho_water => SHR_CONST_RHOFW, &
cp_freshwater => SHR_CONST_CPFW, &
+ cp_seawater => SHR_CONST_CPSW, &
pii => SHR_CONST_PI, &
gravity => SHR_CONST_G
implicit none
@@ -45,6 +46,7 @@ module li_constants
real (kind=RKIND), parameter, public :: triple_point = 273.16_RKIND !< Triple point of water (K)
real (kind=RKIND), parameter, public :: rho_water = 1000.0_RKIND !< Density of fresh water (kg m^-3)
real (kind=RKIND), parameter, public :: cp_freshwater = 4.188e3_RKIND !< heat capacity of freshwater (J/kg/K)
+ real (kind=RKIND), parameter, public :: cp_seawater = 3.974e3_RKIND !< heat capacity of seawater (J/kg/K)
real (kind=RKIND), parameter, public :: pii = 3.141592653589793_RKIND !< Constant: Pi
real (kind=RKIND), parameter, public :: gravity = 9.80616_RKIND !< Constant: Acceleration due to gravity [m s-2]
@@ -61,8 +63,8 @@ module li_constants
!< These values are from the Ocean Water Freezing Point Calculator,
!< http://www.csgnetwork.com/h2ofreezecalc.html (25 Nov. 2014)
- real (kind=RKIND), parameter, public :: &
- iceMeltingPointPressureDependence = 9.7456e-8_RKIND ! Dependence of ice melting point on pressure (K Pa^-1)
+ real (kind=RKIND), parameter, public :: iceMeltingPointPressureDependence = 7.9e-8_RKIND
+ !< Clausius-Clapeyron constant: Dependence of ice melting point on pressure (K Pa^-1)
! conversion factors
real (kind=RKIND), parameter, public :: kelvin_to_celsius = 273.15_RKIND !< factor to convert Kelvin to Celsius
diff --git a/src/core_landice/shared/mpas_li_mask.F b/src/core_landice/shared/mpas_li_mask.F
index 4436e0a511..9ccf0fb4b1 100644
--- a/src/core_landice/shared/mpas_li_mask.F
+++ b/src/core_landice/shared/mpas_li_mask.F
@@ -200,14 +200,24 @@ subroutine li_calculate_mask_init(geometryPool, err)
integer, dimension(:), pointer :: cellMask
real(KIND=RKIND), dimension(:), pointer :: thickness
logical, pointer :: config_do_restart
+ integer, pointer :: config_num_halos, config_number_of_blocks
+ integer :: err_tmp
err = 0
+ err_tmp = 0
! Assign pointers and variables
- call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask, timeLevel=1)
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
call mpas_pool_get_config(liConfigs, 'config_do_restart', config_do_restart)
+ call mpas_pool_get_config(liConfigs, 'config_num_halos', config_num_halos)
+
+ if (config_num_halos < 3) then
+ call mpas_log_write("MALI requires that config_num_halos >= 3. (edgeMask calculations require it.)", MPAS_LOG_ERR)
+ err_tmp = 1
+ endif
+ err = ior(err,err_tmp)
if (config_do_restart .eqv. .false.) then ! We only want to set this bit of the mask when a new simulation starts,
! but not during a restart.
@@ -289,6 +299,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
logical :: aCellOnEdgeHasIce, aCellOnEdgeHasNoIce, aCellOnEdgeHasDynamicIce, aCellOnEdgeHasNoDynamicIce, &
aCellOnEdgeIsFloating
logical :: aCellOnEdgeIsGrounded
+ logical :: aCellOnEdgeIsOpenOcean
integer :: numCellsOnVertex
integer :: numDiriDynamicCells, numDiriNondynamicCells, numExtendedCells
logical :: validVertex
@@ -313,7 +324,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge)
call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography)
- call mpas_pool_get_array(geometryPool, 'cellMask', cellMask)
+ call mpas_pool_get_array(geometryPool, 'cellMask', cellMask, timeLevel=1)
call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask)
call mpas_pool_get_array(geometryPool, 'vertexMask', vertexMask, timeLevel=1)
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
@@ -357,7 +368,9 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
if (li_mask_is_ice(cellMask(i))) then
isMargin = .false.
do j=1,nEdgesOnCell(i) ! Check if any neighbors are non-ice
- isMargin = ( isMargin .or. (.not. li_mask_is_ice(cellMask(cellsOnCell(j,i)))) )
+ if (cellsOnCell(j,i) <= nCells) then
+ isMargin = ( isMargin .or. (.not. li_mask_is_ice(cellMask(cellsOnCell(j,i)))) )
+ endif
enddo
if (isMargin) then
cellMask(i) = ior(cellMask(i), li_mask_ValueMargin)
@@ -399,8 +412,8 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
(trim(config_velocity_solver) == 'Stokes') ) then
! HO external FEM dycore
! Identify cells where the ice is above the ice dynamics thickness limit but not with a dirichletVelocity condition set
- where ( li_mask_is_dynamic_ice(cellMask) .and. & ! same as for SIA case
- (maxval(dirichletVelocityMask(1:nVertInterfaces-1, :), dim=1) == 0) ) ! but exclude dirichletVelocityMask
+ where ( li_mask_is_dynamic_ice(cellMask) ) ! .and. & ! same as for SIA case
+ ! (maxval(dirichletVelocityMask(1:nVertInterfaces-1, :), dim=1) == 0) ) ! but exclude dirichletVelocityMask
! locations set as lateral b.c. We don't want to consider dirichlet b.c. on the basal boundary,
! so we ignore the basal level
cellMask = ior(cellMask, li_mask_ValueAlbanyActive)
@@ -414,7 +427,9 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
if (li_mask_is_dynamic_ice(cellMask(i))) then
isMargin = .false.
do j=1,nEdgesOnCell(i) ! Check if any neighbors are not dynamic
- isMargin = ( isMargin .or. (.not. li_mask_is_dynamic_ice(cellMask(cellsOnCell(j,i)))) )
+ if (cellsOnCell(j,i) <= nCells) then
+ isMargin = ( isMargin .or. (.not. li_mask_is_dynamic_ice(cellMask(cellsOnCell(j,i)))) )
+ endif
enddo
if (isMargin) then
cellMask(i) = ior(cellMask(i), li_mask_ValueDynamicMargin)
@@ -446,7 +461,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
do j=1,nEdgesOnCell(i) ! Check if any neighbors are floating or open ocean
iCellNeighbor = cellsOnCell(j,i)
if (li_mask_is_floating_ice(cellMask(iCellNeighbor)) .or. &
- ((bedTopography(iCellNeighbor) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(iCellNeighbor)))) ) then
+ ((bedTopography(iCellNeighbor) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(iCellNeighbor)))) ) then
cellMask(i) = ior(cellMask(i), li_mask_ValueGroundingLine)
endif
cycle ! no need to look at additional neighbors
@@ -580,6 +595,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
aCellOnEdgeHasNoDynamicIce = .false.
aCellOnEdgeIsFloating = .false.
aCellOnEdgeIsGrounded = .false.
+ aCellOnEdgeIsOpenOcean = .false.
do j = 1, 2
iCell = cellsOnEdge(j,i)
aCellOnEdgeHasIce = (aCellOnEdgeHasIce .or. li_mask_is_ice(cellMask(iCell)))
@@ -588,6 +604,8 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
aCellOnEdgeHasNoDynamicIce = (aCellOnEdgeHasNoDynamicIce .or. (.not. (li_mask_is_dynamic_ice(cellMask(iCell)))))
aCellOnEdgeIsFloating = (aCellOnEdgeIsFloating .or. li_mask_is_floating_ice(cellMask(iCell)))
aCellOnEdgeIsGrounded = (aCellOnEdgeIsGrounded .or. li_mask_is_grounded_ice(cellMask(iCell)))
+ aCellOnEdgeIsOpenOcean = aCellOnEdgeIsOpenOcean .or. &
+ ((bedTopography(iCell) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(iCell))))
end do
if (aCellOnEdgeHasIce) then
edgeMask(i) = ior(edgeMask(i), li_mask_ValueIce)
@@ -600,7 +618,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
if (aCellOnEdgeIsFloating) then
edgeMask(i) = ior(edgeMask(i), li_mask_ValueFloating)
endif
- if (aCellOnEdgeIsFloating .and. aCellOnEdgeIsGrounded) then
+ if (aCellOnEdgeIsGrounded .and. (aCellOnEdgeIsFloating .or. aCellOnEdgeIsOpenOcean)) then
edgeMask(i) = ior(edgeMask(i), li_mask_ValueGroundingLine)
endif
if (aCellOnEdgeHasIce .and. aCellOnEdgeHasNoIce) then
@@ -626,66 +644,6 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err)
end subroutine li_calculate_mask
-!***********************************************************************
-!
-! routine li_calculate_extrapolate_floating_edgemask
-!
-!> \brief Extrapolates floating edges forward as needed by external FEM dycores
-!> \author Matt Hoffman
-!> \date 29 January 2015
-!> \details
-!> External FEM dycores include the first non-ice cells in their mesh. They
-!> also use a mask to apply floating lateral boundary conditions on edges.
-!> Because they include extra cell center locations in their meshes, the triangle
-!> edges connecting these extra nodes will not be covered by the standard
-!> MPAS edge mask. This routine deals with this problem by 'extrapolating'
-!> the floating edge mask forward to cover the edges connecting these extra nodes.
-!> It does so by looping over edges, and setting as floating any edge that has
-!> at least one neighboring vertex that is 'floating'. This makes use of the
-!> convention that "Floating vertices have at least one neighboring cell floating".
-!
-!-----------------------------------------------------------------------
-
- subroutine li_calculate_extrapolate_floating_edgemask(meshPool, vertexMask, floatingEdges)
-
- !-----------------------------------------------------------------
- ! input variables
- !-----------------------------------------------------------------
- type (mpas_pool_type), intent(in) :: &
- meshPool !< Input: mesh information
- !-----------------------------------------------------------------
- ! input/output variables
- !-----------------------------------------------------------------
- integer, dimension(:), intent(inout) :: &
- vertexMask !< Input/Output: vertexMask
-
- integer, dimension(:), intent(inout) :: &
- floatingEdges !< Input/Output: 0/1 mask of floating edges
-
- !-----------------------------------------------------------------
- ! output variables
- !-----------------------------------------------------------------
-
- !-----------------------------------------------------------------
- ! local variables
- !-----------------------------------------------------------------
- integer, dimension(:,:), pointer :: verticesOnEdge
- integer, pointer :: nEdges
- integer :: iEdge
-
- call mpas_pool_get_dimension(meshPool, 'nEdges', nEdges)
- call mpas_pool_get_array(meshPool, 'verticesOnEdge', verticesOnEdge)
-
- ! Build floatingEdges mask that is extended forward one extra edge
- do iEdge = 1, nEdges
- floatingEdges(iEdge) = maxval(li_mask_is_floating_ice_int(vertexMask(verticesOnEdge(:, iEdge))))
- enddo
-
- ! Now includes vertices that include 2 cells with ice and one extended floating cell
- ! This will be when the two cells with ice were Dirichlet cells
- end subroutine li_calculate_extrapolate_floating_edgemask
-
-
! ===================================
! Functions for decoding bitmasks - will work with cellMask, edgeMask, or vertexMask
! ===================================
diff --git a/src/core_landice/shared/mpas_li_setup.F b/src/core_landice/shared/mpas_li_setup.F
index 94f38212ef..060f7a67c7 100644
--- a/src/core_landice/shared/mpas_li_setup.F
+++ b/src/core_landice/shared/mpas_li_setup.F
@@ -49,6 +49,7 @@ module li_setup
li_setup_vertical_grid, &
li_setup_sign_and_index_fields, &
li_setup_wachspress_vertex_to_cell_weights, &
+ li_interpolate_vertex_to_cell_1d, &
li_interpolate_vertex_to_cell_2d, &
li_cells_to_vertices_1dfield_using_kiteAreas, &
li_calculate_layerThickness, &
@@ -186,12 +187,15 @@ subroutine li_setup_vertical_grid(meshPool, geometryPool, err)
! Pool pointers
integer, pointer :: nVertLevels ! Dimensions
real (kind=RKIND), dimension(:), pointer :: layerThicknessFractions, layerCenterSigma, layerInterfaceSigma
+ real (kind=RKIND), dimension(:), pointer :: layerInterfaceFractions
real (kind=RKIND), dimension(:), pointer :: thickness
logical, pointer :: config_do_restart
! Truly locals
integer :: k
real (kind=RKIND) :: fractionTotal
+ err = 0
+
! Get pool stuff
call mpas_pool_get_config(liConfigs, 'config_do_restart', config_do_restart)
call mpas_pool_get_dimension(meshPool, 'nVertLevels', nVertLevels)
@@ -199,6 +203,7 @@ subroutine li_setup_vertical_grid(meshPool, geometryPool, err)
call mpas_pool_get_array(meshPool, 'layerThicknessFractions', layerThicknessFractions)
call mpas_pool_get_array(meshPool, 'layerCenterSigma', layerCenterSigma)
call mpas_pool_get_array(meshPool, 'layerInterfaceSigma', layerInterfaceSigma)
+ call mpas_pool_get_array(meshPool, 'layerInterfaceFractions', layerInterfaceFractions)
call mpas_pool_get_array(geometryPool, 'thickness', thickness)
! Check that layerThicknessFractions are valid
@@ -231,6 +236,13 @@ subroutine li_setup_vertical_grid(meshPool, geometryPool, err)
end do
layerInterfaceSigma(nVertLevels+1) = 1.0_RKIND
+ ! layerInterfaceFractions are the fraction associated with each interface
+ layerInterfaceFractions(1) = 0.5_RKIND * layerThicknessFractions(1)
+ do k = 2, nVertLevels
+ layerInterfaceFractions(k) = 0.5_RKIND * (layerThicknessFractions(k-1) + layerThicknessFractions(k))
+ end do
+ layerInterfaceFractions(nVertLevels+1) = 0.5_RKIND * layerThicknessFractions(nVertLevels)
+
!--------------------------------------------------------------------
end subroutine li_setup_vertical_grid
@@ -371,7 +383,7 @@ subroutine li_setup_wachspress_vertex_to_cell_weights(meshPool)
integer :: nVerticesOnThisCell
real(kind=RKIND), dimension(:,:), allocatable :: vertexCoordsOnCell
type (mpas_pool_type), pointer :: meshPoolPointer
-
+ real(kind=RKIND), dimension(3) :: coords
! Get pool stuff
call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
call mpas_pool_get_dimension(meshPool, 'maxEdges', maxEdges)
@@ -385,7 +397,8 @@ subroutine li_setup_wachspress_vertex_to_cell_weights(meshPool)
call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
call mpas_pool_get_array(meshPool, 'verticesOnCell', verticesOnCell)
- meshPoolPointer => meshPool ! mpas_wachspress_coordinates expected a pointer to the mesh pool instead of just the mesh pool itself
+ meshPoolPointer => meshPool ! mpas_wachspress_coordinates expected a pointer to the mesh pool
+ ! instead of just the mesh pool itself
allocate(vertexCoordsOnCell(3, maxEdges))
@@ -395,9 +408,12 @@ subroutine li_setup_wachspress_vertex_to_cell_weights(meshPool)
iVertex = verticesOnCell(v, iCell)
vertexCoordsOnCell(:, v) = (/ xVertex(iVertex), yVertex(iVertex), zVertex(iVertex) /)
enddo
+ coords(1) = xCell(iCell)
+ coords(2) = yCell(iCell)
+ coords(3) = zCell(iCell)
wachspressWeightVertex(1:nVerticesOnThisCell, iCell) = mpas_wachspress_coordinates( &
nVerticesOnThisCell, vertexCoordsOnCell(:, 1:nVerticesOnThisCell), &
- (/ xCell(iCell), yCell(iCell), zCell(iCell) /), meshPoolPointer)
+ coords, meshPoolPointer)
end do
deallocate(vertexCoordsOnCell)
@@ -405,6 +421,68 @@ subroutine li_setup_wachspress_vertex_to_cell_weights(meshPool)
end subroutine li_setup_wachspress_vertex_to_cell_weights
+!***********************************************************************
+!
+! routine li_interpolate_vertex_to_cell_1d
+!
+!> \brief Interpolates from vertices to cell centers using Wachspress functions
+!> \author Matt Hoffman
+!> \date 03 March 2020
+!> \details
+!> This routine interpolated from vertices to cell center values using
+!> Wachspress functions in MPAS operators.
+!
+!-----------------------------------------------------------------------
+ subroutine li_interpolate_vertex_to_cell_1d(meshPool, vertexValue, cellValue)
+ use mpas_geometry_utils
+
+ !-----------------------------------------------------------------
+ ! input variables
+ !-----------------------------------------------------------------
+ type (mpas_pool_type), intent(in) :: meshPool !< Input: mesh object
+
+ real(kind=RKIND), dimension(:), pointer, intent(in) :: vertexValue !< value on vertices
+
+ !-----------------------------------------------------------------
+ ! input/output variables
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ ! output variables
+ !-----------------------------------------------------------------
+ real(kind=RKIND), dimension(:), intent(out) :: cellValue !< value on cells
+
+ !-----------------------------------------------------------------
+ ! local variables
+ !-----------------------------------------------------------------
+ ! Pool pointers
+ real(kind=RKIND), dimension(:,:), pointer :: wachspressWeightVertex
+ integer, dimension(:), pointer :: nEdgesOnCell
+ integer, dimension(:,:), pointer :: verticesOnCell
+ integer, pointer :: nCells, maxEdges
+ integer :: iCell, iVertex, v
+ integer :: nVerticesOnThisCell
+
+ ! Get pool stuff
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCells)
+ call mpas_pool_get_dimension(meshPool, 'maxEdges', maxEdges)
+ call mpas_pool_get_array(meshPool, 'wachspressWeightVertex', wachspressWeightVertex)
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'verticesOnCell', verticesOnCell)
+
+ cellValue(:) = 0.0_RKIND
+ do iCell = 1, nCells
+ nVerticesOnThisCell = nEdgesOnCell(iCell)
+ do v = 1, nVerticesOnThisCell
+ iVertex = verticesOnCell(v, iCell)
+ cellValue(iCell) = cellValue(iCell) + wachspressWeightVertex(v, iCell) * vertexValue(iVertex)
+ enddo
+ end do
+
+ !--------------------------------------------------------------------
+ end subroutine li_interpolate_vertex_to_cell_1d
+
+
!***********************************************************************
!
! routine li_interpolate_vertex_to_cell_2d
@@ -434,7 +512,7 @@ subroutine li_interpolate_vertex_to_cell_2d(meshPool, vertexValue, cellValue)
!-----------------------------------------------------------------
! output variables
!-----------------------------------------------------------------
- real(kind=RKIND), dimension(:,:), pointer, intent(in) :: cellValue !< value on cells
+ real(kind=RKIND), dimension(:,:), intent(out) :: cellValue !< value on cells
!-----------------------------------------------------------------
! local variables
@@ -525,7 +603,7 @@ subroutine li_cells_to_vertices_1dfield_using_kiteAreas(meshPool, fieldCells, fi
cellIndex = cellsOnVertex(iCell, iVertex)
baryweight = 0.0_RKIND
do iCell2 = 1, vertexDegree
- if (iCell2 /= icell) baryweight = baryweight + 0.5 * kiteAreasOnVertex(iCell2, iVertex)
+ if (iCell2 /= icell) baryweight = baryweight + 0.5_RKIND * kiteAreasOnVertex(iCell2, iVertex)
enddo
fVertexAccum = fVertexAccum + baryweight * fieldCells(cellIndex) ! add the contribution from this cell's kite
weightAccum = weightAccum + kiteAreasOnVertex(iCell, iVertex) ! This doesn't match areaTriangle for obtuse triangles!!!
diff --git a/src/core_ocean/build_options.mk b/src/core_ocean/build_options.mk
index e979a3b0a3..cea9e4665a 100644
--- a/src/core_ocean/build_options.mk
+++ b/src/core_ocean/build_options.mk
@@ -8,7 +8,7 @@ FCINCLUDES += -I$(ROOT_DIR)/core_ocean/mode_forward -I$(ROOT_DIR)/core_ocean/mod
FCINCLUDES += -I$(ROOT_DIR)/core_ocean/shared -I$(ROOT_DIR)/core_ocean/analysis_members
FCINCLUDES += -I$(ROOT_DIR)/core_ocean/cvmix/src/shared
FCINCLUDES += -I$(ROOT_DIR)/core_ocean/BGC
-FCINCLUDES += -I$(ROOT_DIR)/core_ocean/gotm/include
+FCINCLUDES += -I$(ROOT_DIR)/core_ocean/gotm/build/modules
override CPPFLAGS += -DCORE_OCEAN
report_builds:
diff --git a/src/core_seaice/LICENSE b/src/core_seaice/LICENSE
new file mode 100644
index 0000000000..0bf5064708
--- /dev/null
+++ b/src/core_seaice/LICENSE
@@ -0,0 +1,19 @@
+This software is open source software available under the BSD-3 license.
+
+Copyright (c) 2018 Los Alamos National Security, LLC.
+
+All rights reserved.
+
+Copyright 2018. Los Alamos National Security, LLC. This software was produced under U.S. Government contract DE-AC52-06NA25396 for Los Alamos National Laboratory (LANL), which is operated by Los Alamos National Security, LLC for the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce derivative works, such modified software should be clearly marked, so as not to confuse it with the version available from LANL.
+
+Additionally, redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+- Neither the name of Los Alamos National Security, LLC, Los Alamos National Laboratory, LANL, the U.S. Government, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+
+
+THIS SOFTWARE IS PROVIDED BY LOS ALAMOS NATIONAL SECURITY, LLC AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LOS ALAMOS NATIONAL SECURITY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/core_seaice/Registry.xml b/src/core_seaice/Registry.xml
index ec09f05f5e..999756cdab 100644
--- a/src/core_seaice/Registry.xml
+++ b/src/core_seaice/Registry.xml
@@ -92,6 +92,18 @@
definition="3"
description="Number of spectral intervals in the radiation calculation"
/>
+
+
+
+
+
+
@@ -397,6 +420,14 @@
description="Restart the ice biogeochemistry"
possible_values="true or false"
/>
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
+
+
+
+
@@ -628,6 +691,10 @@
description="Run the ridging column physics calculation."
possible_values="true or false"
/>
+
@@ -666,6 +733,20 @@
possible_values="true or false"
icepack_name="tr_aero"
/>
+
+
+
@@ -779,7 +860,7 @@
possible_values="positive real number less than 1"
icepack_name="grid_o_t"
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -1647,6 +1784,61 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1872,6 +2068,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
@@ -2132,6 +2376,8 @@
+
+
@@ -2160,12 +2406,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2178,6 +2436,10 @@
+
+
+
+
@@ -2260,6 +2522,26 @@
+
+
+
+
@@ -2390,12 +2672,12 @@
packages="pkgTracerVerticalIron"
/>
@@ -2431,6 +2713,10 @@
+
+
+
+
@@ -2499,6 +2785,10 @@
+
+
+
+
@@ -2567,6 +2857,10 @@
+
+
+
+
@@ -2634,6 +2928,10 @@
+
+
+
+
@@ -2708,6 +3006,14 @@
+
+
+
+
+
+
+
+
@@ -2847,6 +3153,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3030,6 +3348,10 @@
+
+
+
+
@@ -3104,6 +3426,14 @@
+
+
+
+
+
+
+
+
@@ -3354,6 +3684,8 @@
+
+
@@ -3420,6 +3752,14 @@
+
+
+
+
+
+
+
+
@@ -3490,6 +3830,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -3570,6 +3921,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3592,12 +3957,28 @@
+
+
+
+
+
+
+
+
@@ -3748,6 +4133,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include "analysis_members/Registry_seaice_analysis_members.xml"
diff --git a/src/core_seaice/analysis_members/Registry_seaice_conservation_check.xml b/src/core_seaice/analysis_members/Registry_seaice_conservation_check.xml
index 3917b7aa8b..2048529b13 100644
--- a/src/core_seaice/analysis_members/Registry_seaice_conservation_check.xml
+++ b/src/core_seaice/analysis_members/Registry_seaice_conservation_check.xml
@@ -23,111 +23,182 @@
description="Logical flag determining if the conservation check is written to the log file."
possible_values="true or false"
/>
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/core_seaice/analysis_members/Registry_seaice_regional_statistics.xml b/src/core_seaice/analysis_members/Registry_seaice_regional_statistics.xml
index c48764ba67..1f58e7e36c 100644
--- a/src/core_seaice/analysis_members/Registry_seaice_regional_statistics.xml
+++ b/src/core_seaice/analysis_members/Registry_seaice_regional_statistics.xml
@@ -28,12 +28,6 @@
-
-
diff --git a/src/core_seaice/analysis_members/Registry_seaice_time_series_stats_monthly.xml b/src/core_seaice/analysis_members/Registry_seaice_time_series_stats_monthly.xml
index dec40cc486..d817a5661f 100644
--- a/src/core_seaice/analysis_members/Registry_seaice_time_series_stats_monthly.xml
+++ b/src/core_seaice/analysis_members/Registry_seaice_time_series_stats_monthly.xml
@@ -1,7 +1,7 @@
\brief Setup packages for MPAS-Ocean analysis driver
+!> \brief Setup packages for MPAS-Seaice analysis driver
!> \author Mark Petersen
!> \date November 2013
!> \details
@@ -358,12 +351,12 @@ end subroutine seaice_analysis_bootstrap!}}}
!
! routine seaice_analysis_init
!
-!> \brief Initialize MPAS-Ocean analysis driver
+!> \brief Initialize MPAS-Seaice analysis driver
!> \author Mark Petersen
!> \date November 2013
!> \details
!> This routine calls all initializations required for the
-!> MPAS-Ocean analysis driver.
+!> MPAS-Seaice analysis driver.
!
!-----------------------------------------------------------------------
@@ -500,12 +493,12 @@ end subroutine seaice_analysis_init!}}}
!
! routine seaice_analysis_compute_startup
!
-!> \brief Driver for MPAS-Ocean analysis computations
+!> \brief Driver for MPAS-Seaice analysis computations
!> \author Mark Petersen
!> \date November 2013
!> \details
!> This routine calls all computation subroutines required for the
-!> MPAS-Ocean analysis driver.
+!> MPAS-Seaice analysis driver.
!
!-----------------------------------------------------------------------
@@ -599,7 +592,7 @@ end subroutine seaice_analysis_compute_startup!}}}
! routine seaice_analysis_precompute
!
!> \brief Driver for MPAS-Seaice analysis computations
-!> \author MPAS-Ocean/Seaice development team
+!> \author MPAS-Seaice/Seaice development team
!> \date November 2013
!> \details
!> This routine calls all pre timestep computation subroutines
@@ -692,12 +685,12 @@ end subroutine seaice_analysis_precompute!}}}
!
! routine seaice_analysis_compute
!
-!> \brief Driver for MPAS-Ocean analysis computations
+!> \brief Driver for MPAS-Seaice analysis computations
!> \author Mark Petersen
!> \date November 2013
!> \details
!> This routine calls all computation subroutines required for the
-!> MPAS-Ocean analysis driver.
+!> MPAS-Seaice analysis driver.
!
!-----------------------------------------------------------------------
@@ -788,12 +781,12 @@ end subroutine seaice_analysis_compute!}}}
!
! routine seaice_analysis_restart
!
-!> \brief Save restart for MPAS-Ocean analysis driver
+!> \brief Save restart for MPAS-Seaice analysis driver
!> \author Mark Petersen
!> \date November 2013
!> \details
!> This routine calls all subroutines required to prepare to save
-!> the restart state for the MPAS-Ocean analysis driver.
+!> the restart state for the MPAS-Seaice analysis driver.
!
!-----------------------------------------------------------------------
@@ -862,12 +855,12 @@ end subroutine seaice_analysis_restart!}}}
!
! routine seaice_analysis_write
!
-!> \brief Driver for MPAS-Ocean analysis output
+!> \brief Driver for MPAS-Seaice analysis output
!> \author Mark Petersen
!> \date November 2013
!> \details
!> This routine calls all output writing subroutines required for the
-!> MPAS-Ocean analysis driver.
+!> MPAS-Seaice analysis driver.
!> At this time this is just a stub, and all analysis output is written
!> to the output file specified by config_output_name.
!
@@ -985,12 +978,12 @@ end subroutine seaice_analysis_write!}}}
!
! routine seaice_analysis_finalize
!
-!> \brief Finalize MPAS-Ocean analysis driver
+!> \brief Finalize MPAS-Seaice analysis driver
!> \author Mark Petersen
!> \date November 2013
!> \details
!> This routine calls all finalize routines required for the
-!> MPAS-Ocean analysis driver.
+!> MPAS-Seaice analysis driver.
!
!-----------------------------------------------------------------------
diff --git a/src/core_seaice/analysis_members/mpas_seaice_area_variables.F b/src/core_seaice/analysis_members/mpas_seaice_area_variables.F
index f5e2b9da29..b69518518d 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_area_variables.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_area_variables.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_area_variables
diff --git a/src/core_seaice/analysis_members/mpas_seaice_conservation_check.F b/src/core_seaice/analysis_members/mpas_seaice_conservation_check.F
index a1401357a3..7799655f54 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_conservation_check.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_conservation_check.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_conservation_check
@@ -123,6 +116,9 @@ end subroutine seaice_bootstrap_conservation_check!}}}
subroutine seaice_init_conservation_check(domain, instance, err)!{{{
+ use seaice_constants, only: &
+ pii
+
!-----------------------------------------------------------------
!
! input variables
@@ -153,8 +149,121 @@ subroutine seaice_init_conservation_check(domain, instance, err)!{{{
!
!-----------------------------------------------------------------
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(MPAS_pool_type), pointer :: &
+ conservationCheckAMPool, &
+ conservationCheckAreaAMPool, &
+ meshPool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ latCell, &
+ areaCell
+
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
+ real(kind=RKIND), pointer :: &
+ earthRadius, &
+ earthArea
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ domainArea
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nHemispheres
+
+ integer :: &
+ iCell, &
+ iHemisphere
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ sumArray, &
+ sumArrayOut
+
+ integer, parameter :: &
+ nVars = 1
+
+ integer :: &
+ nSums
+
err = 0
+ call MPAS_pool_get_config(domain % configs, "config_earth_radius", earthRadius)
+
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+ nSums = nHemispheres * nVars
+
+ allocate(sumArray(nSums))
+ allocate(sumArrayOut(nSums))
+
+ sumArray = 0.0_RKIND
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "domainArea", domainArea)
+ call MPAS_pool_get_array(meshPool, "latCell", latCell)
+ call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
+
+ earthArea = 4.0_RKIND * pii * earthRadius**2
+
+ do iCell = 1, nCellsSolve
+
+ ! global
+ cellInHemisphere(1,iCell) = 1
+
+ ! northern hemisphere
+ if (latCell(iCell) >= 0.0) then
+ cellInHemisphere(2,iCell) = 1
+ else
+ cellInHemisphere(2,iCell) = 0
+ endif
+
+ ! southern hemisphere
+ if (latCell(iCell) < 0.0) then
+ cellInHemisphere(3,iCell) = 1
+ else
+ cellInHemisphere(3,iCell) = 0
+ endif
+
+ ! domain area
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iHemisphere) = sumArray(iHemisphere) + areaCell(iCell)
+ endif
+ enddo ! iHemisphere
+
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ ! perform the sums over processors
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nSums, sumArray, sumArrayOut)
+
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "domainArea", domainArea)
+
+ do iHemisphere = 1, nHemispheres
+ domainArea(iHemisphere) = sumArrayOut(iHemisphere)
+ enddo ! iHemisphere
+
+ ! cleanup
+ deallocate(sumArray)
+ deallocate(sumArrayOut)
+
end subroutine seaice_init_conservation_check!}}}
!***********************************************************************
@@ -208,15 +317,20 @@ subroutine seaice_precompute_conservation_check(domain, instance, timeLevel, err
conservationCheckAMPool, &
conservationCheckEnergyAMPool, &
conservationCheckMassAMPool, &
- conservationCheckSaltAMPool
+ conservationCheckSaltAMPool, &
+ conservationCheckCarbonAMPool
integer, pointer :: &
performConservationPrecompute
- real(kind=RKIND), pointer :: &
+ logical, pointer :: &
+ config_use_column_biogeochemistry
+
+ real(kind=RKIND), dimension(:), pointer :: &
initialEnergy, &
initialMass, &
- initialSalt
+ initialSalt, &
+ initialCarbon
err = 0
@@ -246,6 +360,18 @@ subroutine seaice_precompute_conservation_check(domain, instance, timeLevel, err
call compute_total_salt(domain, initialSalt)
+ ! initial total carbon
+ call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckCarbonAM", conservationCheckCarbonAMPool)
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "initialCarbon", initialCarbon)
+
+ if (config_use_column_biogeochemistry) then
+ call compute_total_carbon(domain, initialCarbon)
+ else
+ initialCarbon = 0.0_RKIND
+ endif
+
performConservationPrecompute = 0
endif
@@ -309,8 +435,12 @@ subroutine seaice_compute_conservation_check(domain, instance, timeLevel, err)!{
conservationCheckAMPool
integer, pointer :: &
+ nAccumulate, &
performConservationPrecompute
+ logical, pointer :: &
+ config_use_column_biogeochemistry
+
type(MPAS_Time_type) :: &
currentTime
@@ -319,17 +449,25 @@ subroutine seaice_compute_conservation_check(domain, instance, timeLevel, err)!{
err = 0
- call MPAS_pool_get_config(domain % blocklist % configs, "config_AM_conservationCheck_write_to_logfile", &
- config_AM_conservationCheck_write_to_logfile)
+ ! number of accumulations
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate)
+ nAccumulate = nAccumulate + 1
+
+ call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", &
+ config_AM_conservationCheck_write_to_logfile)
if (config_AM_conservationCheck_write_to_logfile .and. &
MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
- call mpas_log_write('==========================================================')
+ call mpas_log_write('===================================================================================')
currentTime = MPAS_get_clock_time(domain % clock, MPAS_NOW, ierr=ierr)
call MPAS_get_time(currentTime, dateTimeString=timeStr, ierr=ierr)
call mpas_log_write(' Conservation checks: '//trim(timeStr))
endif
+ ! area analysis
+ call area_analysis(domain, err)
+
! energy conservation check
call energy_conservation(domain, err)
@@ -339,19 +477,182 @@ subroutine seaice_compute_conservation_check(domain, instance, timeLevel, err)!{
! salt conservation check
call salt_conservation(domain, err)
+ ! initial total carbon
+ call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+ if (config_use_column_biogeochemistry) call carbon_conservation(domain, err)
+
if (config_AM_conservationCheck_write_to_logfile .and. &
MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
- call mpas_log_write('==========================================================')
+ call mpas_log_write('===================================================================================')
+ endif
- ! set precompute to happen next timestep
+ ! set precompute to happen next timestep after output
+ if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
call MPAS_pool_get_array(conservationCheckAMPool, "performConservationPrecompute", performConservationPrecompute)
performConservationPrecompute = 1
-
endif
end subroutine seaice_compute_conservation_check!}}}
+!***********************************************************************
+!
+! routine area_analysis
+!
+!> \brief Compute MPAS-Seaice analysis member
+!> \author Adrian K. Turner
+!> \date 1st April 2021
+!> \details
+!> Analyses areas used in the model.
+!
+!-----------------------------------------------------------------------
+
+ subroutine area_analysis(domain, err)
+
+ type(domain_type), intent(inout) :: &
+ domain
+
+ integer, intent(out) :: &
+ err !< Output: error flag
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(MPAS_pool_type), pointer :: &
+ conservationCheckAMPool, &
+ conservationCheckAreaAMPool, &
+ meshPool, &
+ tracersAggregatePool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ areaCell, &
+ latCell, &
+ iceAreaCell
+
+ real(kind=RKIND), pointer :: &
+ earthRadius, &
+ earthArea
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ sumArray, &
+ sumArrayOut
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ domainArea, &
+ accumulatedSeaIceArea
+
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
+ real(kind=RKIND) :: &
+ seaiceAreaCell
+
+ logical, pointer :: &
+ config_AM_conservationCheck_write_to_logfile
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nHemispheres
+
+ integer :: &
+ iCell, &
+ iHemisphere, &
+ ierr
+
+ integer, parameter :: &
+ nVars = 1
+
+ integer :: &
+ nSums
+
+ call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", &
+ config_AM_conservationCheck_write_to_logfile)
+
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+ nSums = nHemispheres * nVars
+
+ allocate(sumArray(nSums))
+ allocate(sumArrayOut(nSums))
+
+ sumArray = 0.0_RKIND
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nHemispheres", nHemispheres)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
+
+ call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
+ call MPAS_pool_get_array(meshPool, "latCell", latCell)
+ call MPAS_pool_get_array(tracersAggregatePool, "iceAreaCell", iceAreaCell)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
+
+ do iCell = 1, nCellsSolve
+
+ seaiceAreaCell = areaCell(iCell) * iceAreaCell(iCell)
+
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iHemisphere) = sumArray(iHemisphere) + seaiceAreaCell
+ endif
+ enddo ! iHemisphere
+
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ ! perform the sums over processors
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nSums, sumArray, sumArrayOut)
+
+ ! accumulate fluxes
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "accumulatedSeaIceArea", accumulatedSeaIceArea)
+
+ do iHemisphere = 1, nHemispheres
+ accumulatedSeaIceArea(iHemisphere) = accumulatedSeaIceArea(iHemisphere) + sumArrayOut(iHemisphere)
+ enddo ! iHemisphere
+
+ ! cleanup
+ deallocate(sumArray)
+ deallocate(sumArrayOut)
+
+ !-------------------------------------------------------------
+ ! Area analysis
+ !-------------------------------------------------------------
+
+ if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
+
+ call MPAS_pool_get_config(domain % configs, "config_earth_radius", earthRadius)
+
+ !-------------------------------------------------------------
+ ! Output to log file
+ !-------------------------------------------------------------
+
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "domainArea", domainArea)
+
+ if (config_AM_conservationCheck_write_to_logfile) then
+
+ call mpas_log_write('-----------------------------------------------------------------------------------')
+ call mpas_log_write(' Area analysis Global NH SH')
+ call mpas_log_write(' ')
+ call mpas_log_write(' Earth radius (m) = '//trim(hemisphere_format((/earthRadius/))))
+ call mpas_log_write(' Earth area (m2) = '//trim(hemisphere_format((/earthArea/))))
+ call mpas_log_write(' Domain area (m2) = '//trim(hemisphere_format(domainArea)))
+ call mpas_log_write(' Sea-ice area (m2) = '//trim(hemisphere_format(accumulatedSeaIceArea)))
+
+ endif
+
+ endif
+
+ end subroutine area_analysis
+
!***********************************************************************
!
! routine energy_conservation
@@ -378,25 +679,46 @@ subroutine energy_conservation(domain, err)
err !< Output: error flag
type(block_type), pointer :: &
- block
+ blockPtr
type(MPAS_pool_type), pointer :: &
- conservationCheckEnergyAMPool
+ conservationCheckEnergyAMPool, &
+ conservationCheckAMPool, &
+ conservationCheckAreaAMPool
- real(kind=RKIND), pointer :: &
+ real(kind=RKIND), dimension(:), pointer :: &
initialEnergy, &
finalEnergy, &
energyChange, &
+ energyChangeFlux, &
netEnergyFlux, &
absoluteEnergyError, &
relativeEnergyError
- real(kind=RKIND), pointer :: &
- accumulatedSurfaceHeatFlux, &
- accumulatedOceanHeatFlux, &
- accumulatedFreezingPotential, &
- accumulatedSnowfallHeat, &
- accumulatedLatentHeat
+ real(kind=RKIND), dimension(:), pointer :: &
+ energyConsSurfaceHeatFlux, &
+ energyConsAbsorbedShortwaveFlux, &
+ energyConsOceanShortwaveFlux, &
+ energyConsSensibleHeatFlux, &
+ energyConsLongwaveUp, &
+ energyConsLongwaveDown, &
+ energyConsOceanHeatFlux, &
+ energyConsFreezingPotential, &
+ energyConsSnowfallHeat, &
+ energyConsLatentHeat
+
+ real(kind=RKIND) :: &
+ surfaceHeatCell, &
+ surfaceHeatFluxCell, &
+ absorbedShortwaveFluxCell, &
+ oceanShortwaveFluxCell, &
+ sensibleHeatFluxCell, &
+ longwaveUpCell, &
+ longwaveDownCell, &
+ oceanHeatCell, &
+ freezingPotentialCell, &
+ snowfallHeatCell, &
+ latentHeatCell
real(kind=RKIND), dimension(:), allocatable :: &
sumArray, &
@@ -428,56 +750,79 @@ subroutine energy_conservation(domain, err)
freezingMeltingPotentialInitial, &
snowfallRate
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
real(kind=RKIND), pointer :: &
- dt
+ dt, &
+ earthArea
logical, pointer :: &
config_calc_surface_temperature, &
config_AM_conservationCheck_write_to_logfile
integer, pointer :: &
- nCellsSolve
+ nCellsSolve, &
+ nHemispheres, &
+ nAccumulate
integer :: &
iCell, &
+ iHemisphere, &
+ iSumPrev, &
ierr
- integer, parameter :: &
- nSums = 5
+ integer :: &
+ nVars
+
+ integer :: &
+ nSums
- character(len=17) :: &
- formatString
+ real(kind=RKIND) :: &
+ fluxScale
+
+ logical, parameter :: &
+ defaultLatentHeatFormulation = .true.
err = 0
- call MPAS_pool_get_config(domain % blocklist % configs, "config_dt", dt)
- call MPAS_pool_get_config(domain % blocklist % configs, "config_AM_conservationCheck_write_to_logfile", &
- config_AM_conservationCheck_write_to_logfile)
+ call MPAS_pool_get_config(domain % blocklist % configs, "config_calc_surface_temperature", config_calc_surface_temperature)
+ if (config_calc_surface_temperature) then
+ nVars = 9
+ else
+ nVars = 5
+ endif
+
+ call MPAS_pool_get_config(domain % configs, "config_dt", dt)
+ call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", &
+ config_AM_conservationCheck_write_to_logfile)
!-------------------------------------------------------------
! Net heat flux to ice
!-------------------------------------------------------------
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+ nSums = nHemispheres * nVars
+
allocate(sumArray(nSums))
allocate(sumArrayOut(nSums))
sumArray = 0.0_RKIND
- block => domain % blocklist
- do while (associated(block))
-
- call MPAS_pool_get_config(block % configs, "config_calc_surface_temperature", config_calc_surface_temperature)
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
- call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve)
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracersAggregatePool)
- call MPAS_pool_get_subpool(block % structs, "icestate", icestatePool)
- call MPAS_pool_get_subpool(block % structs, "shortwave", shortwavePool)
- call MPAS_pool_get_subpool(block % structs, "ocean_fluxes", oceanFluxesPool)
- call MPAS_pool_get_subpool(block % structs, "atmos_fluxes", atmosFluxesPool)
- call MPAS_pool_get_subpool(block % structs, "atmos_coupling", atmosCouplingPool)
- call MPAS_pool_get_subpool(block % structs, "diagnostics", diagnosticsPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "icestate", icestatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "shortwave", shortwavePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "ocean_fluxes", oceanFluxesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "atmos_fluxes", atmosFluxesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "atmos_coupling", atmosCouplingPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "diagnostics", diagnosticsPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
call MPAS_pool_get_array(tracersAggregatePool, "iceAreaCell", iceAreaCell)
@@ -493,16 +838,37 @@ subroutine energy_conservation(domain, err)
call MPAS_pool_get_array(atmosCouplingPool, "longwaveDown", longwaveDown)
call MPAS_pool_get_array(atmosCouplingPool, "snowfallRate", snowfallRate)
call MPAS_pool_get_array(diagnosticsPool, "freezingMeltingPotentialInitial", freezingMeltingPotentialInitial)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
- ! surface heat flux
- if (config_calc_surface_temperature) then
+ do iCell = 1, nCellsSolve
+
+ oceanHeatCell = -oceanHeatFluxArea(iCell) * areaCell(iCell)
+ freezingPotentialCell = -max(0.0_RKIND, freezingMeltingPotentialInitial(iCell)) * areaCell(iCell)
+ snowfallHeatCell = -snowfallRate(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell) * Lfresh
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+1) = sumArray(iSumPrev+1) + oceanHeatCell
+ sumArray(iSumPrev+2) = sumArray(iSumPrev+2) + freezingPotentialCell
+ sumArray(iSumPrev+3) = sumArray(iSumPrev+3) + snowfallHeatCell
+ endif
+ enddo ! iHemisphere
+
+ enddo ! iCell
+
+ if (defaultLatentHeatFormulation) then
do iCell = 1, nCellsSolve
- sumArray(1) = sumArray(1) + &
- (absorbedShortwaveFlux(iCell) - oceanShortwaveFlux(iCell) + &
- sensibleHeatFlux(iCell) + longwaveUp(iCell)) * iceAreaCell(iCell) * areaCell(iCell) + &
- longwaveDown(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell)
+ latentHeatCell = latentHeatFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell)
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+4) = sumArray(iSumPrev+4) + latentHeatCell
+ endif
+ enddo ! iHemisphere
enddo ! iCell
@@ -510,30 +876,61 @@ subroutine energy_conservation(domain, err)
do iCell = 1, nCellsSolve
- sumArray(1) = sumArray(1) + &
- (surfaceHeatFlux(iCell) - latentHeatFlux(iCell)) * iceAreaCell(iCell) * areaCell(iCell)
+ latentHeatCell = evaporativeWaterFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell) * Lvap
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+4) = sumArray(iSumPrev+4) + latentHeatCell
+ endif
+ enddo ! iHemisphere
enddo ! iCell
endif
- do iCell = 1, nCellsSolve
+ ! surface heat flux
+ if (config_calc_surface_temperature) then
+
+ do iCell = 1, nCellsSolve
+
+ absorbedShortwaveFluxCell = absorbedShortwaveFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell)
+ oceanShortwaveFluxCell = -oceanShortwaveFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell)
+ sensibleHeatFluxCell = sensibleHeatFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell)
+ longwaveUpCell = longwaveUp(iCell) * iceAreaCell(iCell) * areaCell(iCell)
+ longwaveDownCell = longwaveDown(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell)
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+5) = sumArray(iSumPrev+5) + absorbedShortwaveFluxCell
+ sumArray(iSumPrev+6) = sumArray(iSumPrev+6) + oceanShortwaveFluxCell
+ sumArray(iSumPrev+7) = sumArray(iSumPrev+7) + sensibleHeatFluxCell
+ sumArray(iSumPrev+8) = sumArray(iSumPrev+8) + longwaveUpCell
+ sumArray(iSumPrev+9) = sumArray(iSumPrev+9) + longwaveDownCell
+ endif
+ enddo ! iHemisphere
+
+ enddo ! iCell
- ! ocean heat flux
- sumArray(2) = sumArray(2) + oceanHeatFluxArea(iCell) * areaCell(iCell)
+ else
- ! freezing potential
- sumArray(3) = sumArray(3) + max(0.0_RKIND, freezingMeltingPotentialInitial(iCell)) * areaCell(iCell)
+ do iCell = 1, nCellsSolve
- ! snowfall heat input
- sumArray(4) = sumArray(4) - snowfallRate(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell) * Lfresh
+ surfaceHeatFluxCell = (surfaceHeatFlux(iCell) - latentHeatFlux(iCell)) * iceAreaCell(iCell) * areaCell(iCell)
- ! latent heat
- sumArray(5) = sumArray(5) + evaporativeWaterFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell) * Lvap
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+5) = sumArray(iSumPrev+5) + surfaceHeatFluxCell
+ endif
+ enddo ! iHemisphere
- enddo ! iCell
+ enddo ! iCell
- block => block % next
+ endif
+
+ blockPtr => blockPtr % next
enddo
! perform the sums over processors
@@ -542,17 +939,39 @@ subroutine energy_conservation(domain, err)
! accumulate fluxes
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckEnergyAM", conservationCheckEnergyAMPool)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedSurfaceHeatFlux", accumulatedSurfaceHeatFlux)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedOceanHeatFlux", accumulatedOceanHeatFlux)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedFreezingPotential", accumulatedFreezingPotential)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedSnowfallHeat", accumulatedSnowfallHeat)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedLatentHeat", accumulatedLatentHeat)
-
- accumulatedSurfaceHeatFlux = accumulatedSurfaceHeatFlux + sumArrayOut(1)
- accumulatedOceanHeatFlux = accumulatedOceanHeatFlux + sumArrayOut(2)
- accumulatedFreezingPotential = accumulatedFreezingPotential + sumArrayOut(3)
- accumulatedSnowfallHeat = accumulatedSnowfallHeat + sumArrayOut(4)
- accumulatedLatentHeat = accumulatedLatentHeat + sumArrayOut(5)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsOceanHeatFlux", energyConsOceanHeatFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsFreezingPotential", energyConsFreezingPotential)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSnowfallHeat", energyConsSnowfallHeat)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsLatentHeat", energyConsLatentHeat)
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ energyConsOceanHeatFlux (iHemisphere) = energyConsOceanHeatFlux (iHemisphere) + sumArrayOut(iSumPrev+1)
+ energyConsFreezingPotential(iHemisphere) = energyConsFreezingPotential(iHemisphere) + sumArrayOut(iSumPrev+2)
+ energyConsSnowfallHeat (iHemisphere) = energyConsSnowfallHeat (iHemisphere) + sumArrayOut(iSumPrev+3)
+ energyConsLatentHeat (iHemisphere) = energyConsLatentHeat (iHemisphere) + sumArrayOut(iSumPrev+4)
+ enddo ! iHemisphere
+
+ if (config_calc_surface_temperature) then
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsAbsorbedShortwaveFlux", energyConsAbsorbedShortwaveFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsOceanShortwaveFlux", energyConsOceanShortwaveFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSensibleHeatFlux", energyConsSensibleHeatFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsLongwaveUp", energyConsLongwaveUp)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsLongwaveDown", energyConsLongwaveDown)
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ energyConsAbsorbedShortwaveFlux(iHemisphere) = energyConsAbsorbedShortwaveFlux(iHemisphere) + sumArrayOut(iSumPrev+5)
+ energyConsOceanShortwaveFlux (iHemisphere) = energyConsOceanShortwaveFlux (iHemisphere) + sumArrayOut(iSumPrev+6)
+ energyConsSensibleHeatFlux (iHemisphere) = energyConsSensibleHeatFlux (iHemisphere) + sumArrayOut(iSumPrev+7)
+ energyConsLongwaveUp (iHemisphere) = energyConsLongwaveUp (iHemisphere) + sumArrayOut(iSumPrev+8)
+ energyConsLongwaveDown (iHemisphere) = energyConsLongwaveDown (iHemisphere) + sumArrayOut(iSumPrev+9)
+ enddo ! iHemisphere
+ else
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSurfaceHeatFlux", energyConsSurfaceHeatFlux)
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ energyConsSurfaceHeatFlux(iHemisphere) = energyConsSurfaceHeatFlux(iHemisphere) + sumArrayOut(iSumPrev+5)
+ enddo ! iHemisphere
+ endif
! cleanup
deallocate(sumArray)
@@ -564,6 +983,13 @@ subroutine energy_conservation(domain, err)
if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
+ ! convert fluxes to fluxes per m2 of whole earth and per second
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate)
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea)
+ fluxScale = 1.0_RKIND / (earthArea * real(nAccumulate))
+
! get initial energy
call MPAS_pool_get_array(conservationCheckEnergyAMPool, "initialEnergy", initialEnergy)
@@ -573,24 +999,56 @@ subroutine energy_conservation(domain, err)
! compute the energy change
call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyChange", energyChange)
- energyChange = finalEnergy - initialEnergy
+ energyChange(:) = finalEnergy(:) - initialEnergy(:)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyChangeFlux", energyChangeFlux)
+ energyChangeFlux(:) = energyChange(:) * (fluxScale / dt)
+
+ ! surface heat flux
+ if (config_calc_surface_temperature) then
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSurfaceHeatFlux", energyConsSurfaceHeatFlux)
+ energyConsSurfaceHeatFlux(:) = &
+ energyConsAbsorbedShortwaveFlux(:) + &
+ energyConsOceanShortwaveFlux(:) + &
+ energyConsSensibleHeatFlux(:) + &
+ energyConsLongwaveUp(:) + &
+ energyConsLongwaveDown(:)
+ endif
! calculate the final net energy flux to the ice
call MPAS_pool_get_array(conservationCheckEnergyAMPool, "netEnergyFlux", netEnergyFlux)
-
- netEnergyFlux = &
- accumulatedSurfaceHeatFlux &
- + accumulatedSnowfallHeat &
- + accumulatedLatentHeat &
- - accumulatedOceanHeatFlux &
- - accumulatedFreezingPotential
-
- ! compute the final energy error
+ netEnergyFlux(:) = &
+ energyConsSurfaceHeatFlux(:) &
+ + energyConsSnowfallHeat(:) &
+ + energyConsLatentHeat(:) &
+ + energyConsOceanHeatFlux(:) &
+ + energyConsFreezingPotential(:)
+
+ ! absolute error
call MPAS_pool_get_array(conservationCheckEnergyAMPool, "absoluteEnergyError", absoluteEnergyError)
+ absoluteEnergyError(:) = netEnergyFlux(:) * dt - energyChange(:)
+
+ ! rescale fluxes
+ energyConsSurfaceHeatFlux(:) = energyConsSurfaceHeatFlux(:) * fluxScale
+ energyConsAbsorbedShortwaveFlux(:) = energyConsAbsorbedShortwaveFlux(:) * fluxScale
+ energyConsOceanShortwaveFlux(:) = energyConsOceanShortwaveFlux(:) * fluxScale
+ energyConsSensibleHeatFlux(:) = energyConsSensibleHeatFlux(:) * fluxScale
+ energyConsLongwaveUp(:) = energyConsLongwaveUp(:) * fluxScale
+ energyConsLongwaveDown(:) = energyConsLongwaveDown(:) * fluxScale
+ energyConsSnowfallHeat(:) = energyConsSnowfallHeat(:) * fluxScale
+ energyConsLatentHeat(:) = energyConsLatentHeat(:) * fluxScale
+ energyConsOceanHeatFlux(:) = energyConsOceanHeatFlux(:) * fluxScale
+ energyConsFreezingPotential(:) = energyConsFreezingPotential(:) * fluxScale
+ netEnergyFlux(:) = netEnergyFlux(:) * fluxScale
+
+ ! relative flux error
call MPAS_pool_get_array(conservationCheckEnergyAMPool, "relativeEnergyError", relativeEnergyError)
-
- absoluteEnergyError = netEnergyFlux * dt - energyChange
- relativeEnergyError = absoluteEnergyError / (finalEnergy - 1.0_RKIND) ! why the minus 1????
+ do iHemisphere = 1, nHemispheres
+ if (abs(finalEnergy(iHemisphere)) > 0.0) then
+ relativeEnergyError(iHemisphere) = absoluteEnergyError(iHemisphere) / finalEnergy(iHemisphere)
+ else
+ relativeEnergyError(iHemisphere) = 0.0_RKIND
+ endif
+ enddo ! iHemisphere
!-------------------------------------------------------------
! Output to log file
@@ -598,26 +1056,31 @@ subroutine energy_conservation(domain, err)
if (config_AM_conservationCheck_write_to_logfile) then
- formatString = "(a32,2x,1pe24.17)"
-
- call mpas_log_write('----------------------------------------------------------')
+ call mpas_log_write('-----------------------------------------------------------------------------------')
call mpas_log_write(' Energy conservation check')
call mpas_log_write(' ')
- call mpas_log_write(' Initial energy (J) = $r', realArgs=(/initialEnergy/))
- call mpas_log_write(' Final energy (J) = $r', realArgs=(/finalEnergy/))
- call mpas_log_write(' Energy change (J) = $r', realArgs=(/energyChange/))
+ call mpas_log_write(' Initial energy (J) = '//trim(hemisphere_format(initialEnergy)))
+ call mpas_log_write(' Final energy (J) = '//trim(hemisphere_format(finalEnergy)))
+ call mpas_log_write(' Energy change (J) = '//trim(hemisphere_format(energyChange)))
+ call mpas_log_write(' Energy change flux (W/m2) = '//trim(hemisphere_format(energyChangeFlux)))
+ call mpas_log_write(' ')
+ call mpas_log_write(' Surface heat flux (W/m2) = '//trim(hemisphere_format(energyConsSurfaceHeatFlux)))
+ call mpas_log_write(' Absorbed shortwave flux (W/m2) = '//trim(hemisphere_format(energyConsAbsorbedShortwaveFlux)))
+ call mpas_log_write(' Ocean Shortwave flux (W/m2) = '//trim(hemisphere_format(energyConsOceanShortwaveFlux)))
+ call mpas_log_write(' Sensible heat flux (W/m2) = '//trim(hemisphere_format(energyConsSensibleHeatFlux)))
+ call mpas_log_write(' Longwave up (W/m2) = '//trim(hemisphere_format(energyConsLongwaveUp)))
+ call mpas_log_write(' Longwave down (W/m2) = '//trim(hemisphere_format(energyConsLongwaveDown)))
+ call mpas_log_write(' Ocean heat flux (W/m2) = '//trim(hemisphere_format(energyConsOceanHeatFlux)))
+ call mpas_log_write(' Freezing heat flux (W/m2) = '//trim(hemisphere_format(energyConsFreezingPotential)))
+ call mpas_log_write(' Snowfall heat flux (W/m2) = '//trim(hemisphere_format(energyConsSnowfallHeat)))
+ call mpas_log_write(' Latent heat flux (W/m2) = '//trim(hemisphere_format(energyConsLatentHeat)))
call mpas_log_write(' ')
- call mpas_log_write(' Surface heat flux (W) = $r', realArgs=(/accumulatedSurfaceHeatFlux/))
- call mpas_log_write(' Ocean heat flux (W) = $r', realArgs=(/accumulatedOceanHeatFlux/))
- call mpas_log_write(' Freezing heat flux (W) = $r', realArgs=(/accumulatedFreezingPotential/))
- call mpas_log_write(' Snowfall heat flux (W) = $r', realArgs=(/accumulatedSnowfallHeat/))
- call mpas_log_write(' Latent heat flux (W) = $r', realArgs=(/accumulatedLatentHeat/))
- call mpas_log_write(' Net energy flux (W) = $r', realArgs=(/netEnergyFlux/))
- call mpas_log_write(' Net energy flux (J) = $r', realArgs=(/netEnergyFlux * dt/))
+ call mpas_log_write(' Net energy change (J) = '//trim(hemisphere_format((netEnergyFlux * dt) / fluxScale)))
+ call mpas_log_write(' Net energy flux (W/m2) = '//trim(hemisphere_format(netEnergyFlux)))
call mpas_log_write(' ')
- call mpas_log_write(' Absolute energy error (J) = $r', realArgs=(/absoluteEnergyError/))
- call mpas_log_write(' Absolute energy error (W) = $r', realArgs=(/absoluteEnergyError / dt/))
- call mpas_log_write(' Relative energy error = $r', realArgs=(/relativeEnergyError/))
+ call mpas_log_write(' Absolute energy error (J) = '//trim(hemisphere_format(absoluteEnergyError)))
+ call mpas_log_write(' Absolute energy error (W/m2) = '//trim(hemisphere_format((absoluteEnergyError * fluxScale) / dt)))
+ call mpas_log_write(' Relative energy error = '//trim(hemisphere_format(relativeEnergyError)))
endif
@@ -650,25 +1113,35 @@ subroutine mass_conservation(domain, err)
err !< Output: error flag
type(block_type), pointer :: &
- block
+ blockPtr
type(MPAS_pool_type), pointer :: &
- conservationCheckMassAMPool
+ conservationCheckMassAMPool, &
+ conservationCheckAMPool, &
+ conservationCheckAreaAMPool
- real(kind=RKIND), pointer :: &
+ real(kind=RKIND), dimension(:), pointer :: &
initialMass, &
finalMass, &
massChange, &
+ massChangeFlux, &
netMassFlux, &
absoluteMassError, &
relativeMassError
- real(kind=RKIND), pointer :: &
- accumulatedRainfallRate, &
- accumulatedSnowfallRate, &
- accumulatedEvaporation, &
- accumulatedFreshWater, &
- accumulatedFrazilWater
+ real(kind=RKIND), dimension(:), pointer :: &
+ massConsRainfallRate, &
+ massConsSnowfallRate, &
+ massConsEvaporation, &
+ massConsFreshWater, &
+ massConsFrazilWater
+
+ real(kind=RKIND) :: &
+ rainfallCell, &
+ snowfallCell, &
+ evaporativeWaterCell, &
+ oceanFreshWaterCell, &
+ frazilCell
real(kind=RKIND), dimension(:), allocatable :: &
sumArray, &
@@ -693,8 +1166,12 @@ subroutine mass_conservation(domain, err)
oceanFreshWaterFluxArea, &
frazilFormation
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
real(kind=RKIND), pointer :: &
- dt
+ dt, &
+ earthArea
logical, pointer :: &
config_update_ocean_fluxes, &
@@ -704,48 +1181,59 @@ subroutine mass_conservation(domain, err)
config_thermodynamics_type
integer, pointer :: &
- nCellsSolve
+ nCellsSolve, &
+ nHemispheres, &
+ nAccumulate
integer :: &
iCell, &
+ iHemisphere, &
+ iSumPrev, &
ierr
integer, parameter :: &
- nSums = 5
+ nVars = 5
+
+ integer :: &
+ nSums
- character(len=17) :: &
- formatString
+ real(kind=RKIND) :: &
+ fluxScale
err = 0
- call MPAS_pool_get_config(domain % blocklist % configs, "config_dt", dt)
- call MPAS_pool_get_config(domain % blocklist % configs, "config_AM_conservationCheck_write_to_logfile", &
- config_AM_conservationCheck_write_to_logfile)
+ call MPAS_pool_get_config(domain % configs, "config_dt", dt)
+ call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", &
+ config_AM_conservationCheck_write_to_logfile)
!-------------------------------------------------------------
! Net mass flux to ice
!-------------------------------------------------------------
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+ nSums = nHemispheres * nVars
+
allocate(sumArray(nSums))
allocate(sumArrayOut(nSums))
sumArray = 0.0_RKIND
- block => domain % blocklist
- do while (associated(block))
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
- call MPAS_pool_get_config(block % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes)
- call MPAS_pool_get_config(block % configs, "config_thermodynamics_type", config_thermodynamics_type)
+ call MPAS_pool_get_config(blockPtr % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes)
+ call MPAS_pool_get_config(blockPtr % configs, "config_thermodynamics_type", config_thermodynamics_type)
- call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve)
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracersAggregatePool)
- call MPAS_pool_get_subpool(block % structs, "icestate", icestatePool)
- call MPAS_pool_get_subpool(block % structs, "atmos_coupling", atmosCouplingPool)
- call MPAS_pool_get_subpool(block % structs, "atmos_fluxes", atmosFluxesPool)
- call MPAS_pool_get_subpool(block % structs, "ocean_fluxes", oceanFluxesPool)
- call MPAS_pool_get_subpool(block % structs, "melt_growth_rates", meltGrowthRatesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "icestate", icestatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "atmos_coupling", atmosCouplingPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "atmos_fluxes", atmosFluxesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "ocean_fluxes", oceanFluxesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "melt_growth_rates", meltGrowthRatesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
call MPAS_pool_get_array(tracersAggregatePool, "iceAreaCell", iceAreaCell)
@@ -755,40 +1243,45 @@ subroutine mass_conservation(domain, err)
call MPAS_pool_get_array(atmosFluxesPool, "evaporativeWaterFlux", evaporativeWaterFlux)
call MPAS_pool_get_array(oceanFluxesPool, "oceanFreshWaterFluxArea", oceanFreshWaterFluxArea)
call MPAS_pool_get_array(meltGrowthRatesPool, "frazilFormation", frazilFormation)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
do iCell = 1, nCellsSolve
- ! rainfall
- sumArray(1) = sumArray(1) + &
- rainfallRate(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell)
+ rainfallCell = rainfallRate(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell)
+ snowfallCell = snowfallRate(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell)
+ evaporativeWaterCell = evaporativeWaterFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell)
+ oceanFreshWaterCell = -oceanFreshWaterFluxArea(iCell) * areaCell(iCell)
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+1) = sumArray(iSumPrev+1) + rainfallCell
+ sumArray(iSumPrev+2) = sumArray(iSumPrev+2) + snowfallCell
+ sumArray(iSumPrev+3) = sumArray(iSumPrev+3) + evaporativeWaterCell
+ sumArray(iSumPrev+4) = sumArray(iSumPrev+4) + oceanFreshWaterCell
+ endif
+ enddo ! iHemisphere
- ! snowfall
- sumArray(2) = sumArray(2) + &
- snowfallRate(iCell) * iceAreaCellInitial(iCell) * areaCell(iCell)
+ enddo ! iCell
- ! evaporation
- sumArray(3) = sumArray(3) + &
- evaporativeWaterFlux(iCell) * iceAreaCell(iCell) * areaCell(iCell)
-
- ! fresh water flux to ocean
- sumArray(4) = sumArray(4) + &
- oceanFreshWaterFluxArea(iCell) * areaCell(iCell)
-
- enddo ! iCell
-
- if (config_update_ocean_fluxes .and. trim(config_thermodynamics_type) == "mushy") then
+ ! frazil ice
+ if (config_update_ocean_fluxes .and. trim(config_thermodynamics_type) == "mushy") then
do iCell = 1, nCellsSolve
- ! frazil ice
- sumArray(5) = sumArray(5) + &
- (frazilFormation(iCell) * areaCell(iCell) * rhoi) / dt
+ frazilCell = (frazilFormation(iCell) * areaCell(iCell) * rhoi) / dt
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+5) = sumArray(iSumPrev+5) + frazilCell
+ endif
+ enddo ! iHemisphere
enddo ! iCell
endif
- block => block % next
+ blockPtr => blockPtr % next
enddo
! perform the sums over processors
@@ -797,17 +1290,20 @@ subroutine mass_conservation(domain, err)
! accumulate fluxes
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckMassAM", conservationCheckMassAMPool)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedRainfallRate", accumulatedRainfallRate)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedSnowfallRate", accumulatedSnowfallRate)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedEvaporation", accumulatedEvaporation)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedFreshWater", accumulatedFreshWater)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedFrazilWater", accumulatedFrazilWater)
-
- accumulatedRainfallRate = accumulatedRainfallRate + sumArrayOut(1)
- accumulatedSnowfallRate = accumulatedSnowfallRate + sumArrayOut(2)
- accumulatedEvaporation = accumulatedEvaporation + sumArrayOut(3)
- accumulatedFreshWater = accumulatedFreshWater + sumArrayOut(4)
- accumulatedFrazilWater = accumulatedFrazilWater + sumArrayOut(5)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsRainfallRate", massConsRainfallRate)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsSnowfallRate", massConsSnowfallRate)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsEvaporation", massConsEvaporation)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsFreshWater", massConsFreshWater)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsFrazilWater", massConsFrazilWater)
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ massConsRainfallRate(iHemisphere) = massConsRainfallRate(iHemisphere) + sumArrayOut(iSumPrev+1)
+ massConsSnowfallRate(iHemisphere) = massConsSnowfallRate(iHemisphere) + sumArrayOut(iSumPrev+2)
+ massConsEvaporation (iHemisphere) = massConsEvaporation (iHemisphere) + sumArrayOut(iSumPrev+3)
+ massConsFreshWater (iHemisphere) = massConsFreshWater (iHemisphere) + sumArrayOut(iSumPrev+4)
+ massConsFrazilWater (iHemisphere) = massConsFrazilWater (iHemisphere) + sumArrayOut(iSumPrev+5)
+ enddo ! iHemisphere
! cleanup
deallocate(sumArray)
@@ -819,6 +1315,13 @@ subroutine mass_conservation(domain, err)
if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
+ ! convert to fluxes per m2 of whole earth and per second
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate)
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea)
+ fluxScale = 1.0_RKIND / (earthArea * real(nAccumulate))
+
! get initial mass
call MPAS_pool_get_array(conservationCheckMassAMPool, "initialMass", initialMass)
@@ -828,24 +1331,40 @@ subroutine mass_conservation(domain, err)
! compute the energy change
call MPAS_pool_get_array(conservationCheckMassAMPool, "massChange", massChange)
- massChange = finalMass - initialMass
+ massChange(:) = finalMass(:) - initialMass(:)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massChangeFlux", massChangeFlux)
+ massChangeFlux(:) = massChange(:) * (fluxScale / dt)
! calculate the final net energy flux to the ice
call MPAS_pool_get_array(conservationCheckMassAMPool, "netMassFlux", netMassFlux)
+ netMassFlux(:) = &
+ massConsRainfallRate(:) &
+ + massConsSnowfallRate(:) &
+ + massConsEvaporation(:) &
+ + massConsFreshWater(:) &
+ + massConsFrazilWater(:)
+
+ ! absolute error
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "absoluteMassError", absoluteMassError)
+ absoluteMassError(:) = netMassFlux(:) * dt - massChange(:)
- netMassFlux = &
- accumulatedRainfallRate &
- + accumulatedSnowfallRate &
- + accumulatedEvaporation &
- - accumulatedFreshWater &
- + accumulatedFrazilWater
+ ! rescale fluxes
+ massConsRainfallRate(:) = massConsRainfallRate(:) * fluxScale
+ massConsSnowfallRate(:) = massConsSnowfallRate(:) * fluxScale
+ massConsEvaporation(:) = massConsEvaporation(:) * fluxScale
+ massConsFreshWater(:) = massConsFreshWater(:) * fluxScale
+ massConsFrazilWater(:) = massConsFrazilWater(:) * fluxScale
+ netMassFlux(:) = netMassFlux(:) * fluxScale
! compute the final energy error
- call MPAS_pool_get_array(conservationCheckMassAMPool, "absoluteMassError", absoluteMassError)
call MPAS_pool_get_array(conservationCheckMassAMPool, "relativeMassError", relativeMassError)
-
- absoluteMassError = netMassFlux * dt - massChange
- relativeMassError = absoluteMassError / (finalmass + 1.0_RKIND) ! why the plus 1????
+ do iHemisphere = 1, nHemispheres
+ if (abs(finalMass(iHemisphere)) > 0.0) then
+ relativeMassError(iHemisphere) = absoluteMassError(iHemisphere) / finalMass(iHemisphere)
+ else
+ relativeMassError(iHemisphere) = 0.0_RKIND
+ endif
+ enddo ! iHemisphere
!-------------------------------------------------------------
! Output to log file
@@ -853,26 +1372,26 @@ subroutine mass_conservation(domain, err)
if (config_AM_conservationCheck_write_to_logfile) then
- formatString = "(a32,2x,1pe24.17)"
-
- call mpas_log_write('----------------------------------------------------------')
+ call mpas_log_write('-----------------------------------------------------------------------------------')
call mpas_log_write(' Mass conservation check')
call mpas_log_write(' ')
- call mpas_log_write(' Initial mass (kg) = $r', realArgs=(/initialMass/))
- call mpas_log_write(' Final mass (kg) = $r', realArgs=(/finalMass/))
- call mpas_log_write(' Mass change (kg) = $r', realArgs=(/massChange/))
+ call mpas_log_write(' Initial mass (kg) = '//trim(hemisphere_format(initialMass)))
+ call mpas_log_write(' Final mass (kg) = '//trim(hemisphere_format(finalMass)))
+ call mpas_log_write(' Mass change (kg) = '//trim(hemisphere_format(massChange)))
+ call mpas_log_write(' Mass change flux (kg/m2s) = '//trim(hemisphere_format(massChangeFlux)))
call mpas_log_write(' ')
- call mpas_log_write(' Rainfall mass flux (kg/s) = $r', realArgs=(/accumulatedRainfallRate/))
- call mpas_log_write(' Snowfall mass flux (kg/s) = $r', realArgs=(/accumulatedSnowfallRate/))
- call mpas_log_write(' Evaporative mass flux (kg/s) = $r', realArgs=(/accumulatedEvaporation/))
- call mpas_log_write(' Fresh water mass flux (kg/s) = $r', realArgs=(/accumulatedFreshWater/))
- call mpas_log_write(' Frazil water flux (kg/s) = $r', realArgs=(/accumulatedFrazilWater/))
- call mpas_log_write(' Net mass flux (kg/s) = $r', realArgs=(/netMassFlux/))
- call mpas_log_write(' Net mass flux (kg) = $r', realArgs=(/netMassFlux * dt/))
+ call mpas_log_write(' Rainfall mass flux (kg/m2s) = '//trim(hemisphere_format(massConsRainfallRate)))
+ call mpas_log_write(' Snowfall mass flux (kg/m2s) = '//trim(hemisphere_format(massConsSnowfallRate)))
+ call mpas_log_write(' Evaporative mass flux (kg/m2s) = '//trim(hemisphere_format(massConsEvaporation)))
+ call mpas_log_write(' Fresh water mass flux (kg/m2s) = '//trim(hemisphere_format(massConsFreshWater)))
+ call mpas_log_write(' Frazil water flux (kg/m2s) = '//trim(hemisphere_format(massConsFrazilWater)))
call mpas_log_write(' ')
- call mpas_log_write(' Absolute mass error (kg) = $r', realArgs=(/absoluteMassError/))
- call mpas_log_write(' Absolute mass error (kg/s) = $r', realArgs=(/absoluteMassError / dt/))
- call mpas_log_write(' Relative mass error = $r', realArgs=(/relativeMassError/))
+ call mpas_log_write(' Net mass change (kg) = '//trim(hemisphere_format((netMassFlux * dt) / fluxScale)))
+ call mpas_log_write(' Net mass flux (kg/m2s) = '//trim(hemisphere_format(netMassFlux)))
+ call mpas_log_write(' ')
+ call mpas_log_write(' Absolute mass error (kg) = '//trim(hemisphere_format(absoluteMassError)))
+ call mpas_log_write(' Absolute mass error (kg/m2s) = '//trim(hemisphere_format((absoluteMassError * fluxScale) / dt)))
+ call mpas_log_write(' Relative mass error = '//trim(hemisphere_format(relativeMassError)))
endif
@@ -906,22 +1425,25 @@ subroutine salt_conservation(domain, err)
err !< Output: error flag
type(block_type), pointer :: &
- block
+ blockPtr
type(MPAS_pool_type), pointer :: &
- conservationCheckSaltAMPool
+ conservationCheckSaltAMPool, &
+ conservationCheckAMPool, &
+ conservationCheckAreaAMPool
- real(kind=RKIND), pointer :: &
+ real(kind=RKIND), dimension(:), pointer :: &
initialSalt, &
finalSalt, &
saltChange, &
+ saltChangeFlux, &
netSaltFlux, &
absoluteSaltError, &
relativeSaltError
- real(kind=RKIND), pointer :: &
- accumulatedOceanSaltFlux, &
- accumulatedFrazilSaltFlux
+ real(kind=RKIND), dimension(:), pointer :: &
+ saltConsOceanSaltFlux, &
+ saltConsFrazilSaltFlux
real(kind=RKIND), dimension(:), allocatable :: &
sumArray, &
@@ -937,8 +1459,16 @@ subroutine salt_conservation(domain, err)
oceanSaltFluxArea, &
frazilFormation
+ real(kind=RKIND) :: &
+ frazilCell, &
+ oceanSaltCell
+
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
real(kind=RKIND), pointer :: &
- dt
+ dt, &
+ earthArea
logical, pointer :: &
config_update_ocean_fluxes, &
@@ -948,70 +1478,93 @@ subroutine salt_conservation(domain, err)
config_thermodynamics_type
integer, pointer :: &
- nCellsSolve
+ nCellsSolve, &
+ nHemispheres, &
+ nAccumulate
integer :: &
iCell, &
+ iHemisphere, &
+ iSumPrev, &
ierr
integer, parameter :: &
- nSums = 2
+ nVars = 2
- character(len=17) :: &
- formatString
+ integer :: &
+ nSums
+
+ real(kind=RKIND) :: &
+ fluxScale
err = 0
- call MPAS_pool_get_config(domain % blocklist % configs, "config_dt", dt)
- call MPAS_pool_get_config(domain % blocklist % configs, "config_AM_conservationCheck_write_to_logfile", &
- config_AM_conservationCheck_write_to_logfile)
+ call MPAS_pool_get_config(domain % configs, "config_dt", dt)
+ call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", &
+ config_AM_conservationCheck_write_to_logfile)
!-------------------------------------------------------------
! Net salt flux to ice
!-------------------------------------------------------------
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+ nSums = nHemispheres * nVars
+
allocate(sumArray(nSums))
allocate(sumArrayOut(nSums))
sumArray = 0.0_RKIND
- block => domain % blocklist
- do while (associated(block))
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
- call MPAS_pool_get_config(block % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes)
- call MPAS_pool_get_config(block % configs, "config_thermodynamics_type", config_thermodynamics_type)
+ call MPAS_pool_get_config(blockPtr % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes)
+ call MPAS_pool_get_config(blockPtr % configs, "config_thermodynamics_type", config_thermodynamics_type)
- call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve)
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "ocean_fluxes", oceanFluxesPool)
- call MPAS_pool_get_subpool(block % structs, "melt_growth_rates", meltGrowthRatesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "ocean_fluxes", oceanFluxesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "melt_growth_rates", meltGrowthRatesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
call MPAS_pool_get_array(oceanFluxesPool, "oceanSaltFluxArea", oceanSaltFluxArea)
call MPAS_pool_get_array(meltGrowthRatesPool, "frazilFormation", frazilFormation)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
do iCell = 1, nCellsSolve
- ! salt flux to ocean
- sumArray(1) = sumArray(1) + &
- oceanSaltFluxArea(iCell) * areaCell(iCell)
+ oceanSaltCell = -oceanSaltFluxArea(iCell) * areaCell(iCell)
+
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+1) = sumArray(iSumPrev+1) + oceanSaltCell
+ endif
+ enddo ! iHemisphere
enddo ! iCell
+ ! frazil
if (config_update_ocean_fluxes .and. trim(config_thermodynamics_type) == "mushy") then
do iCell = 1, nCellsSolve
- ! frazil ice
- sumArray(2) = sumArray(2) + &
- (frazilFormation(iCell) * areaCell(iCell) * rhoi * ice_ref_salinity * 0.001_RKIND) / dt
+ frazilCell = (frazilFormation(iCell) * areaCell(iCell) * rhoi * ice_ref_salinity * 0.001_RKIND) / dt
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iSumPrev+2) = sumArray(iSumPrev+2) + frazilCell
+ endif
+ enddo ! iHemisphere
+
enddo ! iCell
endif
- block => block % next
+ blockPtr => blockPtr % next
enddo
! perform the sums over processors
@@ -1020,11 +1573,14 @@ subroutine salt_conservation(domain, err)
! accumulate fluxes
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckSaltAM", conservationCheckSaltAMPool)
- call MPAS_pool_get_array(conservationCheckSaltAMPool, "accumulatedOceanSaltFlux", accumulatedOceanSaltFlux)
- call MPAS_pool_get_array(conservationCheckSaltAMPool, "accumulatedFrazilSaltFlux", accumulatedFrazilSaltFlux)
+ call MPAS_pool_get_array(conservationCheckSaltAMPool, "saltConsOceanSaltFlux", saltConsOceanSaltFlux)
+ call MPAS_pool_get_array(conservationCheckSaltAMPool, "saltConsFrazilSaltFlux", saltConsFrazilSaltFlux)
- accumulatedOceanSaltFlux = accumulatedOceanSaltFlux + sumArrayOut(1)
- accumulatedFrazilSaltFlux = accumulatedFrazilSaltFlux + sumArrayOut(2)
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ saltConsOceanSaltFlux (iHemisphere) = saltConsOceanSaltFlux (iHemisphere) + sumArrayOut(iSumPrev+1)
+ saltConsFrazilSaltFlux(iHemisphere) = saltConsFrazilSaltFlux(iHemisphere) + sumArrayOut(iSumPrev+2)
+ enddo ! iHemisphere
! cleanup
deallocate(sumArray)
@@ -1036,6 +1592,13 @@ subroutine salt_conservation(domain, err)
if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
+ ! convert fluxes to fluxes per m2 of whole earth and per second
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate)
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea)
+ fluxScale = 1.0_RKIND / (earthArea * real(nAccumulate))
+
! get initial salt content
call MPAS_pool_get_array(conservationCheckSaltAMPool, "initialSalt", initialSalt)
@@ -1045,21 +1608,34 @@ subroutine salt_conservation(domain, err)
! compute the salt content change
call MPAS_pool_get_array(conservationCheckSaltAMPool, "saltChange", saltChange)
- saltChange = finalSalt - initialSalt
+ saltChange(:) = finalSalt(:) - initialSalt(:)
+ call MPAS_pool_get_array(conservationCheckSaltAMPool, "saltChangeFlux", saltChangeFlux)
+ saltChangeFlux(:) = saltChange(:) * (fluxScale / dt)
! calculate the final net salt flux to the ice
call MPAS_pool_get_array(conservationCheckSaltAMPool, "netSaltFlux", netSaltFlux)
+ netSaltFlux(:) = &
+ + saltConsOceanSaltFlux(:) &
+ + saltConsFrazilSaltFlux(:)
+
+ ! absolute error
+ call MPAS_pool_get_array(conservationCheckSaltAMPool, "absoluteSaltError", absoluteSaltError)
+ absoluteSaltError(:) = netSaltFlux(:) * dt - saltChange(:)
- netSaltFlux = &
- - accumulatedOceanSaltFlux &
- + accumulatedFrazilSaltFlux
+ ! rescale fluxes
+ saltConsOceanSaltFlux(:) = saltConsOceanSaltFlux(:) * fluxScale
+ saltConsFrazilSaltFlux(:) = saltConsFrazilSaltFlux(:) * fluxScale
+ netSaltFlux(:) = netSaltFlux(:) * fluxScale
! compute the final salt error
- call MPAS_pool_get_array(conservationCheckSaltAMPool, "absoluteSaltError", absoluteSaltError)
call MPAS_pool_get_array(conservationCheckSaltAMPool, "relativeSaltError", relativeSaltError)
-
- absoluteSaltError = netSaltFlux * dt - saltChange
- relativeSaltError = absoluteSaltError / (finalSalt - 1.0_RKIND) ! why the minus 1????
+ do iHemisphere = 1, nHemispheres
+ if (abs(finalSalt(iHemisphere)) > 0.0) then
+ relativeSaltError(iHemisphere) = absoluteSaltError(iHemisphere) / finalSalt(iHemisphere)
+ else
+ relativeSaltError(iHemisphere) = 0.0_RKIND
+ endif
+ enddo ! iHemisphere
!-------------------------------------------------------------
! Output to log file
@@ -1067,23 +1643,23 @@ subroutine salt_conservation(domain, err)
if (config_AM_conservationCheck_write_to_logfile) then
- formatString = "(a32,2x,1pe24.17)"
-
- call mpas_log_write('----------------------------------------------------------')
+ call mpas_log_write('-----------------------------------------------------------------------------------')
call mpas_log_write(' Salt conservation check')
call mpas_log_write(' ')
- call mpas_log_write(' Initial salt (kg) = $r', realArgs=(/initialSalt/))
- call mpas_log_write(' Final salt (kg) = $r', realArgs=(/finalSalt/))
- call mpas_log_write(' Salt change (kg) = $r', realArgs=(/saltChange/))
+ call mpas_log_write(' Initial salt (kg) = '//trim(hemisphere_format(initialSalt)))
+ call mpas_log_write(' Final salt (kg) = '//trim(hemisphere_format(finalSalt)))
+ call mpas_log_write(' Salt change (kg) = '//trim(hemisphere_format(saltChange)))
+ call mpas_log_write(' Salt change flux (kg/m2s) = '//trim(hemisphere_format(saltChangeFlux)))
call mpas_log_write(' ')
- call mpas_log_write(' Ocean salt flux (kg/s) = $r', realArgs=(/accumulatedOceanSaltFlux/))
- call mpas_log_write(' Frazil salt flux (kg/s) = $r', realArgs=(/accumulatedFrazilSaltFlux/))
- call mpas_log_write(' Net salt flux (kg/s) = $r', realArgs=(/netSaltFlux/))
- call mpas_log_write(' Net salt flux (kg) = $r', realArgs=(/netSaltFlux * dt/))
+ call mpas_log_write(' Ocean salt flux (kg/m2s) = '//trim(hemisphere_format(saltConsOceanSaltFlux)))
+ call mpas_log_write(' Frazil salt flux (kg/m2s) = '//trim(hemisphere_format(saltConsFrazilSaltFlux)))
call mpas_log_write(' ')
- call mpas_log_write(' Absolute mass error (kg) = $r', realArgs=(/absoluteSaltError/))
- call mpas_log_write(' Absolute mass error (kg/s) = $r', realArgs=(/absoluteSaltError / dt/))
- call mpas_log_write(' Relative salt error = $r', realArgs=(/relativeSaltError/))
+ call mpas_log_write(' Net salt change (kg) = '//trim(hemisphere_format((netSaltFlux * dt) / fluxScale)))
+ call mpas_log_write(' Net salt flux (kg/m2s) = '//trim(hemisphere_format(netSaltFlux)))
+ call mpas_log_write(' ')
+ call mpas_log_write(' Absolute mass error (kg) = '//trim(hemisphere_format(absoluteSaltError)))
+ call mpas_log_write(' Absolute mass error (kg/m2s) = '//trim(hemisphere_format((absoluteSaltError * fluxScale) / dt)))
+ call mpas_log_write(' Relative salt error = '//trim(hemisphere_format(relativeSaltError)))
endif
@@ -1091,6 +1667,233 @@ subroutine salt_conservation(domain, err)
end subroutine salt_conservation
+!***********************************************************************
+!
+! routine carbon_conservation
+!
+!> \brief Compute MPAS-Seaice analysis member
+!> \author Nicole Jeffery
+!> \date 27 May 2020
+!> \details
+!> This routine conducts all computations to verify carbon conservation
+!> in seaice.
+!
+!-----------------------------------------------------------------------
+
+ subroutine carbon_conservation(domain, err)
+
+ type (domain_type), intent(inout) :: &
+ domain
+
+ integer, intent(out) :: &
+ err !< Output: error flag
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(MPAS_pool_type), pointer :: &
+ conservationCheckCarbonAMPool, &
+ conservationCheckAMPool, &
+ conservationCheckAreaAMPool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ initialCarbon, &
+ finalCarbon, &
+ carbonChange, &
+ carbonChangeFlux, &
+ netCarbonFlux, &
+ absoluteCarbonError, &
+ relativeCarbonError
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ carbonConsOceanCarbonFlux
+
+ real(kind=RKIND) :: &
+ totalOceanCarbonCell
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ sumArray, &
+ sumArrayOut
+
+ type(MPAS_pool_type), pointer :: &
+ meshPool, &
+ biogeochemistryPool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ areaCell, &
+ totalOceanCarbonFlux
+
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
+ real(kind=RKIND), pointer :: &
+ dt, &
+ earthArea
+
+ logical, pointer :: &
+ config_AM_conservationCheck_write_to_logfile
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nHemispheres, &
+ nAccumulate
+
+ integer :: &
+ iCell, &
+ iHemisphere, &
+ iSumPrev, &
+ ierr
+
+ integer, parameter :: &
+ nVars = 1
+
+ integer :: &
+ nSums
+
+ real(kind=RKIND) :: &
+ fluxScale
+
+ err = 0
+
+ call MPAS_pool_get_config(domain % configs, "config_dt", dt)
+ call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", &
+ config_AM_conservationCheck_write_to_logfile)
+
+ !-------------------------------------------------------------
+ ! Net carbon flux to ice
+ !-------------------------------------------------------------
+
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+ nSums = nHemispheres * nVars
+
+ allocate(sumArray(nSums))
+ allocate(sumArrayOut(nSums))
+
+ sumArray = 0.0_RKIND
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "biogeochemistry", biogeochemistryPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
+
+ call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
+ call MPAS_pool_get_array(biogeochemistryPool, "totalOceanCarbonFlux", totalOceanCarbonFlux)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
+
+ do iCell = 1, nCellsSolve
+
+ ! carbon flux to ocean
+ totalOceanCarbonCell = totalOceanCarbonFlux(iCell) * areaCell(iCell)
+ do iHemisphere = 1, nHemispheres
+ iSumPrev = (iHemisphere-1) * nVars
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ sumArray(iHemisphere) = sumArray(iHemisphere) + totalOceanCarbonCell
+ endif
+ enddo ! iHemisphere
+
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ ! perform the sums over processors
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nSums, sumArray, sumArrayOut)
+
+ ! accumulate fluxes
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckCarbonAM", conservationCheckCarbonAMPool)
+
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "carbonConsOceanCarbonFlux", carbonConsOceanCarbonFlux)
+
+ do iHemisphere = 1, nHemispheres
+ carbonConsOceanCarbonFlux(iHemisphere) = carbonConsOceanCarbonFlux(iHemisphere) + sumArrayOut(iHemisphere)
+ enddo ! iHemisphere
+
+ ! cleanup
+ deallocate(sumArray)
+ deallocate(sumArrayOut)
+
+ !-------------------------------------------------------------
+ ! Carbon conservation error
+ !-------------------------------------------------------------
+
+ if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then
+
+ ! convert fluxes to fluxes per m2 of whole earth and per second
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate)
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool)
+ call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea)
+ fluxScale = 1.0_RKIND / (earthArea * real(nAccumulate))
+
+ ! get initial carbon content
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "initialCarbon", initialCarbon)
+
+ ! get final carbon content
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "finalCarbon", finalCarbon)
+ call compute_total_carbon(domain, finalCarbon)
+
+ ! compute the carbon content change
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "carbonChange", carbonChange)
+ carbonChange(:) = finalCarbon(:) - initialCarbon(:)
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "carbonChangeFlux", carbonChangeFlux)
+ carbonChangeFlux(:) = carbonChange(:) * (fluxScale / dt)
+
+ ! calculate the final net carbon flux to the ice
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "netCarbonFlux", netCarbonFlux)
+ netCarbonFlux(:) = &
+ - carbonConsOceanCarbonFlux(:)
+
+ ! absolute error
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "absoluteCarbonError", absoluteCarbonError)
+ absoluteCarbonError(:) = netCarbonFlux(:) * dt - carbonChange(:)
+
+ ! rescale fluxes
+ carbonConsOceanCarbonFlux(:) = carbonConsOceanCarbonFlux(:) * fluxScale
+ netCarbonFlux(:) = netCarbonFlux(:) * fluxScale
+
+ ! compute the final carbon error
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "relativeCarbonError", relativeCarbonError)
+ do iHemisphere = 1, nHemispheres
+ if (abs(finalCarbon(iHemisphere)) > 0.0) then
+ relativeCarbonError(iHemisphere) = absoluteCarbonError(iHemisphere) / finalCarbon(iHemisphere)
+ else
+ relativeCarbonError(iHemisphere) = 0.0_RKIND
+ endif
+ enddo ! iHemisphere
+
+ !-------------------------------------------------------------
+ ! Output to log file
+ !-------------------------------------------------------------
+
+ if (config_AM_conservationCheck_write_to_logfile) then
+
+ call mpas_log_write('-----------------------------------------------------------------------------')
+ call mpas_log_write(' Carbon conservation check')
+ call mpas_log_write(' ')
+ call mpas_log_write(' Initial carbon (mmol) = '//trim(hemisphere_format(initialCarbon)))
+ call mpas_log_write(' Final carbon (mmol) = '//trim(hemisphere_format(finalCarbon)))
+ call mpas_log_write(' Carbon change (mmol) = '//trim(hemisphere_format(carbonChange)))
+ call mpas_log_write(' Carbon change flux (mmol/m2s) = '//trim(hemisphere_format(carbonChange)))
+ call mpas_log_write(' ')
+ call mpas_log_write(' Ocean carbon flux (mmol/m2s) = '//trim(hemisphere_format(carbonConsOceanCarbonFlux)))
+ call mpas_log_write(' ')
+ call mpas_log_write(' Net carbon change (mmol) = '//trim(hemisphere_format((netCarbonFlux * dt) / fluxScale)))
+ call mpas_log_write(' Net carbon flux (mmol/m2s) = '//trim(hemisphere_format(netCarbonFlux)))
+ call mpas_log_write(' ')
+ call mpas_log_write(' Absolute carbon error (mmol) = '//trim(hemisphere_format(absoluteCarbonError)))
+ call mpas_log_write(' Absolute carbon error/s (mmol/m2s) = '//trim(hemisphere_format((absoluteCarbonError * fluxScale) / dt)))
+ call mpas_log_write(' Relative carbon error = '//trim(hemisphere_format(relativeCarbonError)))
+
+ endif
+
+ endif
+
+ end subroutine carbon_conservation
+
!***********************************************************************
!
! routine compute_total_energy
@@ -1108,21 +1911,23 @@ subroutine compute_total_energy(domain, totalEnergy)
type (domain_type), intent(inout) :: &
domain
- real(kind=RKIND), intent(out) :: &
+ real(kind=RKIND), dimension(:), intent(out) :: &
totalEnergy
type(block_type), pointer :: &
- block
+ blockPtr
type(MPAS_pool_type), pointer :: &
meshPool, &
- tracersPool
+ tracersPool, &
+ conservationCheckAMPool
integer, pointer :: &
nCellsSolve, &
nCategories, &
nIceLayers, &
- nSnowLayers
+ nSnowLayers, &
+ nHemispheres
real(kind=RKIND), dimension(:), pointer :: &
areaCell
@@ -1133,6 +1938,9 @@ subroutine compute_total_energy(domain, totalEnergy)
iceVolumeCategory, &
snowVolumeCategory
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
real(kind=RKIND) :: &
nIceLayersInverse, &
nSnowLayersInverse
@@ -1141,39 +1949,51 @@ subroutine compute_total_energy(domain, totalEnergy)
iCell, &
iCategory, &
iIceLayer, &
- iSnowLayer
+ iSnowLayer, &
+ iHemisphere
real(kind=RKIND) :: &
+ energyCell
+
+ real(kind=RKIND), dimension(:), allocatable :: &
energy
- energy = 0.0_RKIND
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
- block => domain % blocklist
- do while (associated(block))
+ allocate(energy(nHemispheres))
+ energy(:) = 0.0_RKIND
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "tracers", tracersPool)
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
- call MPAS_pool_get_dimension(block % dimensions, 'nCellsSolve', nCellsSolve)
- call MPAS_pool_get_dimension(block % dimensions, 'nCategories', nCategories)
- call MPAS_pool_get_dimension(block % dimensions, 'nIceLayers', nIceLayers)
- call MPAS_pool_get_dimension(block % dimensions, 'nSnowLayers', nSnowLayers)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers", tracersPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCellsSolve', nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCategories', nCategories)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nIceLayers', nIceLayers)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nSnowLayers', nSnowLayers)
call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
call MPAS_pool_get_array(tracersPool, "iceEnthalpy", iceEnthalpy, 1)
call MPAS_pool_get_array(tracersPool, "snowEnthalpy", snowEnthalpy, 1)
call MPAS_pool_get_array(tracersPool, "iceVolumeCategory", iceVolumeCategory, 1)
call MPAS_pool_get_array(tracersPool, "snowVolumeCategory", snowVolumeCategory, 1)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
nIceLayersInverse = 1.0_RKIND / real(nIceLayers,RKIND)
nSnowLayersInverse = 1.0_RKIND / real(nSnowLayers,RKIND)
do iCell = 1, nCellsSolve
+
+ energyCell = 0.0;
+
do iCategory = 1, nCategories
do iIceLayer = 1, nIceLayers
- energy = energy + &
+ energyCell = energyCell + &
iceEnthalpy(iIceLayer,iCategory,iCell) * &
iceVolumeCategory(1,iCategory,iCell) * &
nIceLayersInverse * &
@@ -1183,7 +2003,7 @@ subroutine compute_total_energy(domain, totalEnergy)
do iSnowLayer = 1, nSnowLayers
- energy = energy + &
+ energyCell = energyCell + &
snowEnthalpy(iSnowLayer,iCategory,iCell) * &
snowVolumeCategory(1,iCategory,iCell) * &
nSnowLayersInverse * &
@@ -1192,13 +2012,23 @@ subroutine compute_total_energy(domain, totalEnergy)
enddo ! iIceLayer
enddo ! iCategory
+
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ energy(iHemisphere) = energy(iHemisphere) + energyCell
+ endif
+ enddo ! iHemisphere
+
enddo ! iCell
- block => block % next
+ blockPtr => blockPtr % next
enddo
! sum across processors
- call MPAS_dmpar_sum_real(domain % dminfo, energy, totalEnergy)
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nHemispheres, energy, totalEnergy)
+
+ ! clean up
+ deallocate(energy)
end subroutine compute_total_energy
@@ -1223,20 +2053,22 @@ subroutine compute_total_mass(domain, totalMass)
type (domain_type), intent(inout) :: &
domain
- real(kind=RKIND), intent(out) :: &
+ real(kind=RKIND), dimension(:), intent(out) :: &
totalMass
type(block_type), pointer :: &
- block
+ blockPtr
type(MPAS_pool_type), pointer :: &
meshPool, &
tracersPool, &
- tracersAggregatePool
+ tracersAggregatePool, &
+ conservationCheckAMPool
integer, pointer :: &
nCellsSolve, &
- nCategories
+ nCategories, &
+ nHemispheres
real(kind=RKIND), dimension(:), pointer :: &
areaCell, &
@@ -1250,29 +2082,40 @@ subroutine compute_total_mass(domain, totalMass)
levelIceArea, &
levelIceVolume
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
logical, pointer :: &
config_use_topo_meltponds
integer :: &
iCell, &
- iCategory
+ iCategory, &
+ iHemisphere
real(kind=RKIND) :: &
+ massCell
+
+ real(kind=RKIND), dimension(:), allocatable :: &
mass
- mass = 0.0_RKIND
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+
+ allocate(mass(nHemispheres))
+ mass(:) = 0.0_RKIND
- block => domain % blocklist
- do while (associated(block))
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
- call MPAS_pool_get_config(block % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "tracers", tracersPool)
- call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers", tracersPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
- call MPAS_pool_get_dimension(block % dimensions, 'nCellsSolve', nCellsSolve)
- call MPAS_pool_get_dimension(block % dimensions, 'nCategories', nCategories)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCellsSolve', nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCategories', nCategories)
call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
call MPAS_pool_get_array(tracersAggregatePool, "iceVolumeCell", iceVolumeCell)
@@ -1280,38 +2123,56 @@ subroutine compute_total_mass(domain, totalMass)
call MPAS_pool_get_array(tracersPool, "iceAreaCategory", iceAreaCategory, 1)
call MPAS_pool_get_array(tracersPool, "levelIceArea", levelIceArea, 1)
call MPAS_pool_get_array(tracersPool, "levelIceVolume", levelIceVolume, 1)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
do iCell = 1, nCellsSolve
! ice and snow mass
- mass = mass + &
+ massCell = &
(iceVolumeCell(iCell) * rhoi + &
snowVolumeCell(iCell) * rhos) * areaCell(iCell)
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ mass(iHemisphere) = mass(iHemisphere) + massCell
+ endif
+ enddo ! iHemisphere
+
enddo ! iCell
if (config_use_topo_meltponds) then
do iCell = 1, nCellsSolve
+ massCell = 0.0;
+
do iCategory = 1, nCategories
! pond mass
- mass = mass + &
+ massCell = massCell + &
iceAreaCategory(1,icategory,iCell) * levelIceArea(1,icategory,iCell) * &
levelIceVolume(1,icategory,iCell) * areaCell(iCell)
enddo ! iCategory
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ mass(iHemisphere) = mass(iHemisphere) + massCell
+ endif
+ enddo ! iHemisphere
+
enddo ! iCell
endif
- block => block % next
+ blockPtr => blockPtr % next
enddo
! sum across processors
- call MPAS_dmpar_sum_real(domain % dminfo, mass, totalMass)
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nHemispheres, mass, totalMass)
+
+ ! clean up
+ deallocate(mass)
end subroutine compute_total_mass
@@ -1337,18 +2198,20 @@ subroutine compute_total_salt(domain, totalSalt)
type (domain_type), intent(inout) :: &
domain
- real(kind=RKIND), intent(out) :: &
+ real(kind=RKIND), dimension(:), intent(out) :: &
totalSalt
type(block_type), pointer :: &
- block
+ blockPtr
type(MPAS_pool_type), pointer :: &
meshPool, &
- tracersAggregatePool
+ tracersAggregatePool, &
+ conservationCheckAMPool
integer, pointer :: &
- nCellsSolve
+ nCellsSolve, &
+ nHemispheres
real(kind=RKIND), dimension(:), pointer :: &
areaCell, &
@@ -1357,44 +2220,418 @@ subroutine compute_total_salt(domain, totalSalt)
real(kind=RKIND), dimension(:,:,:), pointer :: &
iceVolumeCategory
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
integer :: &
iCell, &
- iCategory
+ iCategory, &
+ iHemisphere
real(kind=RKIND) :: &
+ saltCell
+
+ real(kind=RKIND), dimension(:), allocatable :: &
salt
- salt = 0.0_RKIND
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+
+ allocate(salt(nHemispheres))
+ salt(:) = 0.0_RKIND
- block => domain % blocklist
- do while (associated(block))
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracersAggregatePool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
- call MPAS_pool_get_dimension(block % dimensions, 'nCellsSolve', nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCellsSolve', nCellsSolve)
call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
call MPAS_pool_get_array(tracersAggregatePool, "iceVolumeCell", iceVolumeCell)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
do iCell = 1, nCellsSolve
! ice and snow mass
- salt = salt + &
+ saltCell = &
iceVolumeCell(iCell) * areaCell(iCell)
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ salt(iHemisphere) = salt(iHemisphere) + saltCell
+ endif
+ enddo ! iHemisphere
+
enddo ! iCell
- block => block % next
+ blockPtr => blockPtr % next
enddo
- salt = salt * rhoi * ice_ref_salinity * 0.001_RKIND
+ salt(:) = salt(:) * rhoi * ice_ref_salinity * 0.001_RKIND
! sum across processors
- call MPAS_dmpar_sum_real(domain % dminfo, salt, totalSalt)
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nHemispheres, salt, totalSalt)
+
+ ! clean up
+ deallocate(salt)
end subroutine compute_total_salt
+!***********************************************************************
+!
+! routine compute_total_carbon
+!
+!> \brief Compute total carbon of sea ice system
+!> \author Nicole Jeffery
+!> \date 27 May 2020
+!> \details
+!> Calculate the total carbon of the sea ice system
+!
+!-----------------------------------------------------------------------
+
+ subroutine compute_total_carbon(domain, totalCarbon)
+
+ type (domain_type), intent(inout) :: &
+ domain
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ totalCarbon
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(MPAS_pool_type), pointer :: &
+ meshPool, &
+ biogeochemistryPool, &
+ conservationCheckAMPool
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nHemispheres
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ totalCarbonContentCell, &
+ areaCell
+
+ integer, dimension(:,:), pointer :: &
+ cellInHemisphere
+
+ integer :: &
+ iCell, &
+ iHemisphere
+
+ real(kind=RKIND) :: &
+ carbonCell
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ carbon
+
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres)
+
+ allocate(carbon(nHemispheres))
+ carbon(:) = 0.0_RKIND
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "biogeochemistry", biogeochemistryPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool)
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCellsSolve', nCellsSolve)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, 'nHemispheres', nHemispheres)
+
+ call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
+ call MPAS_pool_get_array(biogeochemistryPool, "totalCarbonContentCell", totalCarbonContentCell)
+ call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere)
+
+ call compute_carbon_cell(blockPtr,totalCarbonContentCell)
+
+ do iCell = 1, nCellsSolve
+
+ ! ice carbon mass (mmols)
+ carbonCell = totalCarbonContentCell(iCell) * areaCell(iCell)
+
+ do iHemisphere = 1, nHemispheres
+ if (cellInHemisphere(iHemisphere,iCell) == 1) then
+ carbon(iHemisphere) = carbon(iHemisphere) + carbonCell
+ endif
+ enddo ! iHemisphere
+
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ ! sum across processors
+ call MPAS_dmpar_sum_real_array(domain % dminfo, nHemispheres, carbon, totalCarbon)
+
+ ! clean up
+ deallocate(carbon)
+
+ end subroutine compute_total_carbon
+
+!***********************************************************************
+!
+! compute_carbon_cell
+!
+!> \brief
+!> \author Nicole Jeffery, LANL
+!> \date 26 May 2020
+!> \details Calculate the total carbon concentration in the sea ice cell
+!> by summing the appropriate biogeochemical tracers in units of mmol C
+!>
+!> Total carbon = algal nitrogen groups * (C to N ratios) + dissolved carbon groups
+!> + dissolved inorganic carbon + dissolved organic nitrogen * (C to N ratio)
+!> + humic material
+!
+!-----------------------------------------------------------------------
+
+ subroutine compute_carbon_cell(blockPtr,totalCarbonContentCell)
+
+ use seaice_constants, only: &
+ skeletalLayerThickness
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ totalCarbonContentCell
+
+ type(block_type), intent(in) :: &
+ blockPtr
+
+ logical, pointer :: &
+ config_use_skeletal_biochemistry, &
+ config_use_vertical_biochemistry, &
+ config_use_vertical_tracers, &
+ config_use_carbon, &
+ config_use_DON, &
+ config_use_humics
+
+ integer, pointer :: &
+ nBioLayersP1, &
+ nBioLayers, &
+ nAlgae, &
+ nDOC, &
+ nDIC, &
+ nDON
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ biogeochemistry, &
+ tracers_aggregate
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ brineFractionCell, &
+ iceVolumeCell
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ skeletalAlgaeConcCell, &
+ skeletalDOCConcCell, &
+ skeletalDICConcCell, &
+ skeletalDONConcCell, &
+ skeletalHumicsConcCell, &
+ verticalAlgaeConcCell, &
+ verticalDOCConcCell, &
+ verticalDICConcCell, &
+ verticalDONConcCell, &
+ verticalHumicsConcCell
+
+ real(kind=RKIND), pointer :: &
+ config_ratio_C_to_N_diatoms, &
+ config_ratio_C_to_N_small_plankton, &
+ config_ratio_C_to_N_phaeocystis, &
+ config_ratio_C_to_N_proteins
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nCategories
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ ratio_C_to_N, &
+ verticalGridSpace
+
+ real(kind=RKIND) :: &
+ totalOceanCarbonCell
+
+ integer :: &
+ iBioTracers, &
+ iBioCount, &
+ iLayers, &
+ iCell
+
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry)
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_vertical_tracers", config_use_vertical_tracers)
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_carbon", config_use_carbon)
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_DON", config_use_DON)
+ call MPAS_pool_get_config(blockPtr % configs, "config_use_humics",config_use_humics)
+ call MPAS_pool_get_config(blockPtr % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms)
+ call MPAS_pool_get_config(blockPtr % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton)
+ call MPAS_pool_get_config(blockPtr % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis)
+ call MPAS_pool_get_config(blockPtr % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins)
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nBioLayers", nBioLayers)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nBioLayersP1", nBioLayersP1)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nAlgae", nAlgae)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nDOC", nDOC)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nDIC", nDIC)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nDON", nDON)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracers_aggregate)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", mesh)
+ call MPAS_pool_get_subpool(blockPtr % structs, "biogeochemistry", biogeochemistry)
+
+ call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve)
+
+ call MPAS_pool_get_array(tracers_aggregate, "skeletalAlgaeConcCell", skeletalAlgaeConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "skeletalDOCConcCell", skeletalDOCConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "skeletalDICConcCell", skeletalDICConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "skeletalDONConcCell", skeletalDONConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "skeletalHumicsConcCell", skeletalHumicsConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "verticalAlgaeConcCell", verticalAlgaeConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "verticalDOCConcCell", verticalDOCConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "verticalDICConcCell", verticalDICConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "verticalDONConcCell", verticalDONConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "verticalHumicsConcCell", verticalHumicsConcCell)
+ call MPAS_pool_get_array(tracers_aggregate, "brineFractionCell", brineFractionCell)
+ call MPAS_pool_get_array(tracers_aggregate, "iceVolumeCell", iceVolumeCell)
+
+ allocate(ratio_C_to_N(3))
+ allocate(verticalGridSpace(nBioLayersP1))
+
+ ratio_C_to_N(1) = config_ratio_C_to_N_diatoms
+ ratio_C_to_N(2) = config_ratio_C_to_N_small_plankton
+ ratio_C_to_N(3) = config_ratio_C_to_N_phaeocystis
+
+ verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND)
+ verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND
+ verticalGridSpace(nBioLayersP1) = verticalGridSpace(1)
+
+ totalCarbonContentCell(:) = 0.0_RKIND
+
+ if (config_use_skeletal_biochemistry) then
+ do iCell = 1, nCellsSolve
+
+ ! algal nitrogen
+ do iBioTracers = 1, nAlgae
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + skeletalAlgaeConcCell(iBioTracers,iCell)* &
+ skeletalLayerThickness * ratio_C_to_N(iBioTracers)
+ enddo
+
+ if (config_use_carbon) then
+
+ ! DOC
+ do iBioTracers = 1, nDOC
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + skeletalDOCConcCell(iBioTracers,iCell)* &
+ skeletalLayerThickness
+ enddo
+
+ ! DIC
+ do iBioTracers = 1, nDIC
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + skeletalDICConcCell(iBioTracers,iCell)* &
+ skeletalLayerThickness
+ enddo
+ endif
+
+ ! DON
+ if (config_use_DON) then
+ do iBioTracers = 1, nDON
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + skeletalDONConcCell(iBioTracers,iCell)* &
+ config_ratio_C_to_N_proteins * skeletalLayerThickness
+ enddo
+ endif
+
+ ! humic material
+ if (config_use_humics) &
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + skeletalHumicsConcCell(1,iCell)* &
+ skeletalLayerThickness
+
+ enddo ! iCell
+
+ elseif (config_use_vertical_tracers) then
+
+ do iCell = 1, nCellsSolve
+
+ if (config_use_vertical_biochemistry) then
+ iBioCount = 0
+
+ ! algal nitrogen
+ do iBioTracers = 1, nAlgae
+
+ do iLayers = 1,nBioLayersP1
+ iBiocount = iBiocount + 1
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + &
+ verticalAlgaeConcCell(iBioCount,iCell) * ratio_C_to_N(iBioTracers) * &
+ verticalGridSpace(iLayers) * iceVolumeCell(iCell) * brineFractionCell(iCell)
+ enddo
+ iBiocount = iBioCount + 2
+ enddo
+ endif
+
+ if (config_use_carbon) then
+ iBioCount = 0
+
+ ! DOC
+ do iBioTracers = 1, nDOC
+
+ do iLayers = 1,nBioLayersP1
+ iBioCount = iBioCount + 1
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + &
+ verticalDOCConcCell(iBioCount,iCell) * verticalGridSpace(iLayers) * &
+ iceVolumeCell(iCell) * brineFractionCell(iCell)
+ enddo
+ iBiocount = iBioCount + 2
+ enddo
+ iBioCount = 0
+
+ ! DIC
+ do iBioTracers = 1, nDIC
+
+ do iLayers = 1,nBioLayersP1
+ iBioCount = iBioCount + 1
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + &
+ verticalDICConcCell(iBioCount,iCell) * verticalGridSpace(iLayers) * &
+ iceVolumeCell(iCell) * brineFractionCell(iCell)
+ enddo
+ iBiocount = iBioCount + 2
+ enddo
+ endif
+
+ if (config_use_DON) then
+ iBioCount = 0
+
+ ! dissolve organic nitrogen
+ do iBioTracers = 1, nDON
+
+ do iLayers = 1,nBioLayersP1
+ iBiocount = iBiocount + 1
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + &
+ verticalDONConcCell(iBioCount,iCell) * config_ratio_C_to_N_proteins * &
+ verticalGridSpace(iLayers) * iceVolumeCell(iCell) * brineFractionCell(iCell)
+ enddo
+ iBiocount = iBioCount + 2
+ enddo
+ endif
+
+ ! humic material
+ if (config_use_humics) then
+ do iLayers = 1, nBioLayersP1
+ totalCarbonContentCell(iCell) = totalCarbonContentCell(iCell) + &
+ verticalHumicsConcCell(iLayers,iCell) * verticalGridSpace(iLayers) * &
+ iceVolumeCell(iCell) * brineFractionCell(iCell)
+ enddo
+ endif
+
+
+ enddo ! iCell
+ endif
+
+ deallocate(ratio_C_to_N)
+ deallocate(verticalGridSpace)
+
+ end subroutine compute_carbon_cell
+
!***********************************************************************
!
! routine reset_accumulated_variables
@@ -1413,62 +2650,101 @@ subroutine reset_accumulated_variables(domain)
domain
type(MPAS_pool_type), pointer :: &
+ conservationCheckAMPool, &
conservationCheckEnergyAMPool, &
conservationCheckMassAMPool, &
- conservationCheckSaltAMPool
+ conservationCheckSaltAMPool, &
+ conservationCheckCarbonAMPool
- real(kind=RKIND), pointer :: &
- accumulatedSurfaceHeatFlux, &
- accumulatedOceanHeatFlux, &
- accumulatedFreezingPotential, &
- accumulatedSnowfallHeat, &
- accumulatedLatentHeat, &
- accumulatedRainfallRate, &
- accumulatedSnowfallRate, &
- accumulatedEvaporation, &
- accumulatedFreshWater, &
- accumulatedFrazilWater, &
- accumulatedOceanSaltFlux, &
- accumulatedFrazilSaltFlux
+ integer, pointer :: &
+ nAccumulate
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ energyConsSurfaceHeatFlux, &
+ energyConsAbsorbedShortwaveFlux, &
+ energyConsOceanShortwaveFlux, &
+ energyConsSensibleHeatFlux, &
+ energyConsLongwaveUp, &
+ energyConsLongwaveDown, &
+ energyConsOceanHeatFlux, &
+ energyConsFreezingPotential, &
+ energyConsSnowfallHeat, &
+ energyConsLatentHeat
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ massConsRainfallRate, &
+ massConsSnowfallRate, &
+ massConsEvaporation, &
+ massConsFreshWater, &
+ massConsFrazilWater
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ saltConsOceanSaltFlux, &
+ saltConsFrazilSaltFlux
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ carbonConsOceanCarbonFlux
+
+ ! number of accumulations
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool)
+ call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate)
+ nAccumulate = 0
! heat
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckEnergyAM", conservationCheckEnergyAMPool)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedSurfaceHeatFlux", accumulatedSurfaceHeatFlux)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedOceanHeatFlux", accumulatedOceanHeatFlux)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedFreezingPotential", accumulatedFreezingPotential)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedSnowfallHeat", accumulatedSnowfallHeat)
- call MPAS_pool_get_array(conservationCheckEnergyAMPool, "accumulatedLatentHeat", accumulatedLatentHeat)
-
- accumulatedSurfaceHeatFlux = 0.0_RKIND
- accumulatedOceanHeatFlux = 0.0_RKIND
- accumulatedFreezingPotential = 0.0_RKIND
- accumulatedSnowfallHeat = 0.0_RKIND
- accumulatedLatentHeat = 0.0_RKIND
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSurfaceHeatFlux", energyConsSurfaceHeatFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsAbsorbedShortwaveFlux", energyConsAbsorbedShortwaveFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsOceanShortwaveFlux", energyConsOceanShortwaveFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSensibleHeatFlux", energyConsSensibleHeatFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsLongwaveUp", energyConsLongwaveUp)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsLongwaveDown", energyConsLongwaveDown)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsOceanHeatFlux", energyConsOceanHeatFlux)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsFreezingPotential", energyConsFreezingPotential)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsSnowfallHeat", energyConsSnowfallHeat)
+ call MPAS_pool_get_array(conservationCheckEnergyAMPool, "energyConsLatentHeat", energyConsLatentHeat)
+
+ energyConsSurfaceHeatFlux(:) = 0.0_RKIND
+ energyConsAbsorbedShortwaveFlux(:) = 0.0_RKIND
+ energyConsOceanShortwaveFlux(:) = 0.0_RKIND
+ energyConsSensibleHeatFlux(:) = 0.0_RKIND
+ energyConsLongwaveUp(:) = 0.0_RKIND
+ energyConsLongwaveDown(:) = 0.0_RKIND
+ energyConsOceanHeatFlux(:) = 0.0_RKIND
+ energyConsFreezingPotential(:) = 0.0_RKIND
+ energyConsSnowfallHeat(:) = 0.0_RKIND
+ energyConsLatentHeat(:) = 0.0_RKIND
! mass
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckMassAM", conservationCheckMassAMPool)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedRainfallRate", accumulatedRainfallRate)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedSnowfallRate", accumulatedSnowfallRate)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedEvaporation", accumulatedEvaporation)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedFreshWater", accumulatedFreshWater)
- call MPAS_pool_get_array(conservationCheckMassAMPool, "accumulatedFrazilWater", accumulatedFrazilWater)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsRainfallRate", massConsRainfallRate)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsSnowfallRate", massConsSnowfallRate)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsEvaporation", massConsEvaporation)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsFreshWater", massConsFreshWater)
+ call MPAS_pool_get_array(conservationCheckMassAMPool, "massConsFrazilWater", massConsFrazilWater)
- accumulatedRainfallRate = 0.0_RKIND
- accumulatedSnowfallRate = 0.0_RKIND
- accumulatedEvaporation = 0.0_RKIND
- accumulatedFreshWater = 0.0_RKIND
- accumulatedFrazilWater = 0.0_RKIND
+ massConsRainfallRate(:) = 0.0_RKIND
+ massConsSnowfallRate(:) = 0.0_RKIND
+ massConsEvaporation(:) = 0.0_RKIND
+ massConsFreshWater(:) = 0.0_RKIND
+ massConsFrazilWater(:) = 0.0_RKIND
! salt
call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckSaltAM", conservationCheckSaltAMPool)
- call MPAS_pool_get_array(conservationCheckSaltAMPool, "accumulatedOceanSaltFlux", accumulatedOceanSaltFlux)
- call MPAS_pool_get_array(conservationCheckSaltAMPool, "accumulatedFrazilSaltFlux", accumulatedFrazilSaltFlux)
+ call MPAS_pool_get_array(conservationCheckSaltAMPool, "saltConsOceanSaltFlux", saltConsOceanSaltFlux)
+ call MPAS_pool_get_array(conservationCheckSaltAMPool, "saltConsFrazilSaltFlux", saltConsFrazilSaltFlux)
- accumulatedOceanSaltFlux = 0.0_RKIND
- accumulatedFrazilSaltFlux = 0.0_RKIND
+ saltConsOceanSaltFlux(:) = 0.0_RKIND
+ saltConsFrazilSaltFlux(:) = 0.0_RKIND
+
+ ! carbon
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckCarbonAM", conservationCheckCarbonAMPool)
+
+ call MPAS_pool_get_array(conservationCheckCarbonAMPool, "carbonConsOceanCarbonFlux", carbonConsOceanCarbonFlux)
+
+ carbonConsOceanCarbonFlux(:) = 0.0_RKIND
end subroutine reset_accumulated_variables
@@ -1570,6 +2846,43 @@ subroutine seaice_finalize_conservation_check(domain, instance, err)!{{{
end subroutine seaice_finalize_conservation_check!}}}
+!***********************************************************************
+!
+! routine hemisphere_format
+!
+!> \brief Format output string
+!> \author Adrian K. Turner
+!> \date 13th April 2021
+!> \details
+!> Formats output string for hemispheric values
+!
+!-----------------------------------------------------------------------
+
+ function hemisphere_format(arrayIn) result(outStr)
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ arrayIn
+
+ character(len=strKIND) :: &
+ outStr
+
+ character(len=16) :: &
+ valStr
+
+ integer :: &
+ i
+
+ outStr = ""
+
+ do i = 1, size(arrayIn)
+
+ write(valStr,fmt=' (es15.6)') arrayIn(i)
+ outStr = trim(outStr)//valStr
+
+ enddo ! i
+
+ end function hemisphere_format
+
!-----------------------------------------------------------------------
end module seaice_conservation_check
diff --git a/src/core_seaice/analysis_members/mpas_seaice_deactivate_unneeded_fields.F b/src/core_seaice/analysis_members/mpas_seaice_deactivate_unneeded_fields.F
index 3b202cdecb..63859a1e39 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_deactivate_unneeded_fields.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_deactivate_unneeded_fields.F
@@ -1,9 +1,3 @@
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_deactivate_unneeded_fields
diff --git a/src/core_seaice/analysis_members/mpas_seaice_geographical_vectors.F b/src/core_seaice/analysis_members/mpas_seaice_geographical_vectors.F
index e8a7cbed80..b7dc9c79d8 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_geographical_vectors.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_geographical_vectors.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_geographical_vectors
diff --git a/src/core_seaice/analysis_members/mpas_seaice_high_frequency_output.F b/src/core_seaice/analysis_members/mpas_seaice_high_frequency_output.F
index bc23a2ce3e..b116060633 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_high_frequency_output.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_high_frequency_output.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_high_frequency_output
diff --git a/src/core_seaice/analysis_members/mpas_seaice_ice_present.F b/src/core_seaice/analysis_members/mpas_seaice_ice_present.F
index 0c1e78399e..6f146235e4 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_ice_present.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_ice_present.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_ice_present
diff --git a/src/core_seaice/analysis_members/mpas_seaice_ice_shelves.F b/src/core_seaice/analysis_members/mpas_seaice_ice_shelves.F
index 49e667c1b2..2a72d0c19c 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_ice_shelves.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_ice_shelves.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_ice_shelves
diff --git a/src/core_seaice/analysis_members/mpas_seaice_load_balance.F b/src/core_seaice/analysis_members/mpas_seaice_load_balance.F
index e3d9138a4b..2ef0138895 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_load_balance.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_load_balance.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_load_balance
diff --git a/src/core_seaice/analysis_members/mpas_seaice_maximum_ice_presence.F b/src/core_seaice/analysis_members/mpas_seaice_maximum_ice_presence.F
index 119983876d..fdea4d5629 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_maximum_ice_presence.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_maximum_ice_presence.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_maximum_ice_presence
diff --git a/src/core_seaice/analysis_members/mpas_seaice_miscellaneous.F b/src/core_seaice/analysis_members/mpas_seaice_miscellaneous.F
index 6ed36c9932..9575834577 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_miscellaneous.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_miscellaneous.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_miscellaneous
diff --git a/src/core_seaice/analysis_members/mpas_seaice_pointwise_stats.F b/src/core_seaice/analysis_members/mpas_seaice_pointwise_stats.F
index 7efd727227..17fffe6f10 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_pointwise_stats.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_pointwise_stats.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_pointwise_stats
diff --git a/src/core_seaice/analysis_members/mpas_seaice_pond_diagnostics.F b/src/core_seaice/analysis_members/mpas_seaice_pond_diagnostics.F
index 371b89a2b5..006c48bc8e 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_pond_diagnostics.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_pond_diagnostics.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_pond_diagnostics
diff --git a/src/core_seaice/analysis_members/mpas_seaice_regional_statistics.F b/src/core_seaice/analysis_members/mpas_seaice_regional_statistics.F
index 41d1bdd81b..0880357639 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_regional_statistics.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_regional_statistics.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_regional_statistics
@@ -768,6 +761,8 @@ subroutine create_new_output_field_1D(&
outputField % isVarArray = .false.
outputField % isPersistent = .true.
+ allocate(outputField % attLists(1))
+
end subroutine create_new_output_field_1D
!***********************************************************************
@@ -830,6 +825,8 @@ subroutine create_new_output_field_2D(&
outputField % isVarArray = .false.
outputField % isPersistent = .true.
+ allocate(outputField % attLists(1))
+
end subroutine create_new_output_field_2D
!***********************************************************************
@@ -1092,14 +1089,13 @@ subroutine fixed_regional_statistics(domain)
call MPAS_pool_get_array(velocitySolverPool, "icePressure", icePressure)
call MPAS_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
call MPAS_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
+ call MPAS_pool_get_array(velocitySolverPool, "uVelocityCell", uVelocityCell)
+ call MPAS_pool_get_array(velocitySolverPool, "vVelocityCell", vVelocityCell)
call MPAS_pool_get_array(velocitySolverPool, "dynamicallyLockedCellsMask", dynamicallyLockedCellsMask)
call MPAS_pool_get_array(regionsPool, 'regionCellMasks', regionCellMasks)
call MPAS_pool_get_array(regionsPool, 'regionVertexMasks', regionVertexMasks)
- call MPAS_pool_get_array(regionalStatisticsAMPool, 'uVelocityCell', uVelocityCell)
- call MPAS_pool_get_array(regionalStatisticsAMPool, 'vVelocityCell', vVelocityCell)
-
! cell centre velocity for velocity statistics
call seaice_interpolate_vertex_to_cell(meshPool, boundaryPool, uVelocityCell, uVelocity)
call seaice_interpolate_vertex_to_cell(meshPool, boundaryPool, vVelocityCell, vVelocity)
diff --git a/src/core_seaice/analysis_members/mpas_seaice_ridging_diagnostics.F b/src/core_seaice/analysis_members/mpas_seaice_ridging_diagnostics.F
index fd12e97a98..911bf4582a 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_ridging_diagnostics.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_ridging_diagnostics.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_ridging_diagnostics
diff --git a/src/core_seaice/analysis_members/mpas_seaice_temperatures.F b/src/core_seaice/analysis_members/mpas_seaice_temperatures.F
index 412a00962f..587b78bbe6 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_temperatures.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_temperatures.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_temperatures
diff --git a/src/core_seaice/analysis_members/mpas_seaice_time_series_stats.F b/src/core_seaice/analysis_members/mpas_seaice_time_series_stats.F
index 442494b979..31d108e478 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_time_series_stats.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_time_series_stats.F
@@ -1,11 +1,3 @@
-! Copyright (c) 2015, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
-
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
! seaice_time_series_stats
!
@@ -161,7 +153,7 @@ module seaice_time_series_stats
'repeat_interval'
character (len=StrKIND), parameter :: RESET_INTERVAL_TOKEN = 'reset_interval'
- character (len=StrKIND), parameter :: CURRENT_CORE_NAME = 'MPAS-Ocean'
+ character (len=StrKIND), parameter :: CURRENT_CORE_NAME = 'MPAS-Seaice'
character (len=4), parameter :: NONE_TOKEN = 'none'
!***********************************************************************
@@ -214,12 +206,12 @@ end subroutine seaice_bootstrap_time_series_stats!}}}
!***********************************************************************
! routine seaice_init_time_series_stats
!
-!> \brief Initialize MPAS-Ocean analysis member
+!> \brief Initialize MPAS-Seaice analysis member
!> \author Jon Woodring
!> \date September 1, 2015
!> \details
!> This routine conducts all initializations required for the
-!> MPAS-Ocean analysis member.
+!> MPAS-Seaice analysis member.
!-----------------------------------------------------------------------
subroutine seaice_init_time_series_stats(domain, instance, err)!{{{
! input variables
@@ -276,12 +268,12 @@ end subroutine seaice_init_time_series_stats!}}}
!***********************************************************************
! routine seaice_compute_time_series_stats
!
-!> \brief Compute MPAS-Ocean analysis member
+!> \brief Compute MPAS-Seaice analysis member
!> \author Jon Woodring
!> \date September 1, 2015
!> \details
!> This routine conducts all computation required for this
-!> MPAS-Ocean analysis member.
+!> MPAS-Seaice analysis member.
!-----------------------------------------------------------------------
subroutine seaice_compute_time_series_stats(domain, timeLevel, instance, err)!{{{
! input variables
@@ -356,12 +348,12 @@ end subroutine seaice_compute_time_series_stats!}}}
!***********************************************************************
! routine seaice_restart_time_series_stats
!
-!> \brief Save restart for MPAS-Ocean analysis member
+!> \brief Save restart for MPAS-Seaice analysis member
!> \author Jon Woodring
!> \date September 1, 2015
!> \details
!> This routine conducts computation required to save a restart state
-!> for the MPAS-Ocean analysis member.
+!> for the MPAS-Seaice analysis member.
!-----------------------------------------------------------------------
subroutine seaice_restart_time_series_stats(domain, instance, err)!{{{
! input variables
@@ -385,12 +377,12 @@ end subroutine seaice_restart_time_series_stats!}}}
!***********************************************************************
! routine seaice_finalize_time_series_stats
!
-!> \brief Finalize MPAS-Ocean analysis member
+!> \brief Finalize MPAS-Seaice analysis member
!> \author Jon Woodring
!> \date September 1, 2015
!> \details
!> This routine conducts all finalizations required for this
-!> MPAS-Ocean analysis member.
+!> MPAS-Seaice analysis member.
!-----------------------------------------------------------------------
subroutine seaice_finalize_time_series_stats(domain, instance, err)!{{{
! input variables
diff --git a/src/core_seaice/analysis_members/mpas_seaice_unit_conversion.F b/src/core_seaice/analysis_members/mpas_seaice_unit_conversion.F
index 316e542a2e..97e69ca262 100644
--- a/src/core_seaice/analysis_members/mpas_seaice_unit_conversion.F
+++ b/src/core_seaice/analysis_members/mpas_seaice_unit_conversion.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_unit_conversion
diff --git a/src/core_seaice/column/Makefile b/src/core_seaice/column/Makefile
index 822ecc1305..c938731957 100644
--- a/src/core_seaice/column/Makefile
+++ b/src/core_seaice/column/Makefile
@@ -28,7 +28,8 @@ OBJS = ice_colpkg.o \
ice_brine.o \
ice_algae.o \
ice_zbgc.o \
- ice_zbgc_shared.o
+ ice_zbgc_shared.o \
+ ice_snow.o
all: $(OBJS)
@@ -40,7 +41,7 @@ ice_constants_colpkg.F90:
cp constants/cice/ice_constants_colpkg.F90 .
endif
-ice_colpkg.o: ice_kinds_mod.o ice_constants_colpkg.o ice_warnings.o ice_colpkg_shared.o ice_therm_shared.o ice_orbital.o ice_atmo.o ice_age.o ice_firstyear.o ice_flux_colpkg.o ice_meltpond_cesm.o ice_meltpond_lvl.o ice_meltpond_topo.o ice_therm_vertical.o ice_itd.o ice_therm_itd.o ice_shortwave.o ice_mechred.o ice_colpkg_tracers.o ice_atmo.o ice_mushy_physics.o ice_zbgc.o ice_zbgc_shared.o ice_aerosol.o ice_algae.o ice_brine.o ice_zsalinity.o
+ice_colpkg.o: ice_kinds_mod.o ice_constants_colpkg.o ice_warnings.o ice_colpkg_shared.o ice_therm_shared.o ice_orbital.o ice_atmo.o ice_age.o ice_firstyear.o ice_flux_colpkg.o ice_meltpond_cesm.o ice_meltpond_lvl.o ice_meltpond_topo.o ice_therm_vertical.o ice_itd.o ice_therm_itd.o ice_shortwave.o ice_mechred.o ice_colpkg_tracers.o ice_atmo.o ice_mushy_physics.o ice_zbgc.o ice_zbgc_shared.o ice_aerosol.o ice_algae.o ice_brine.o ice_zsalinity.o ice_snow.o
ice_kinds_mod.o:
@@ -90,7 +91,7 @@ ice_mechred.o: ice_kinds_mod.o ice_constants_colpkg.o ice_itd.o ice_colpkg_trace
ice_aerosol.o: ice_kinds_mod.o ice_constants_colpkg.o ice_colpkg_shared.o ice_colpkg_tracers.o ice_zbgc_shared.o
-ice_algae.o: ice_kinds_mod.o ice_constants_colpkg.o ice_colpkg_shared.o ice_colpkg_tracers.o ice_zbgc_shared.o ice_aerosol.o
+ice_algae.o: ice_kinds_mod.o ice_constants_colpkg.o ice_colpkg_shared.o ice_colpkg_tracers.o ice_zbgc_shared.o ice_aerosol.o ice_warnings.o
ice_brine.o: ice_kinds_mod.o ice_constants_colpkg.o ice_colpkg_shared.o ice_colpkg_tracers.o ice_zbgc_shared.o ice_therm_mushy.o ice_mushy_physics.o ice_therm_shared.o
@@ -98,6 +99,8 @@ ice_zbgc.o: ice_kinds_mod.o ice_constants_colpkg.o ice_colpkg_shared.o ice_colpk
ice_zbgc_shared.o: ice_kinds_mod.o ice_constants_colpkg.o ice_colpkg_shared.o
+ice_snow.o: ice_kinds_mod.o ice_constants_colpkg.o ice_warnings.o ice_therm_vertical.o ice_colpkg_shared.o
+
.F90.o:
$(RM) $@ $*.mod
diff --git a/src/core_seaice/column/constants/cesm/ice_constants_colpkg.F90 b/src/core_seaice/column/constants/cesm/ice_constants_colpkg.F90
index c8adacab52..b1a73fd337 100644
--- a/src/core_seaice/column/constants/cesm/ice_constants_colpkg.F90
+++ b/src/core_seaice/column/constants/cesm/ice_constants_colpkg.F90
@@ -25,8 +25,13 @@ module ice_constants_colpkg
rhoi = SHR_CONST_RHOICE ,&! density of ice (kg/m^3)
rhow = SHR_CONST_RHOSW ,&! density of seawater (kg/m^3)
cp_air = SHR_CONST_CPDAIR ,&! specific heat of air (J/kg/K)
+
! (Briegleb JGR 97 11475-11485 July 1992)
- emissivity= 0.95_dbl_kind ,&! emissivity of snow and ice
+ !emissivity= 0.95_dbl_kind ,&! emissivity of snow and ice
+ ! Emissivity has been changed to unity here so that coupling is
+ ! physically correct - instantaneous radiative coupling in CIME
+ emissivity= 1.0_dbl_kind ,&! emissivity of snow and ice
+
cp_ice = SHR_CONST_CPICE ,&! specific heat of fresh ice (J/kg/K)
cp_ocn = SHR_CONST_CPSW ,&! specific heat of ocn (J/kg/K)
! freshwater value needed for enthalpy
@@ -38,11 +43,12 @@ module ice_constants_colpkg
dragio = 0.00536_dbl_kind ,&! ice-ocn drag coefficient
#endif
- albocn = 0.06_dbl_kind ,&! ocean albedo
+ albocn = 0.06_dbl_kind ,&! ocean albedo
gravit = SHR_CONST_G ,&! gravitational acceleration (m/s^2)
viscosity_dyn = 1.79e-3_dbl_kind, & ! dynamic viscosity of brine (kg/m/s)
- Tocnfrz= -34.0_dbl_kind*depressT,&! freezing temp of seawater (C),
- ! used as Tsfcn for open water
+ Tocnfrz = -1.8_dbl_kind ,&! freezing temp of seawater (C), used
+ ! as Tsfcn for open water only when
+ ! tfrz_option is 'minus1p8' or null
rhofresh = SHR_CONST_RHOFW ,&! density of fresh water (kg/m^3)
zvir = SHR_CONST_ZVIR ,&! rh2o/rair - 1.0
vonkar = SHR_CONST_KARMAN,&! von Karman constant
@@ -80,12 +86,16 @@ module ice_constants_colpkg
ksno = 0.30_dbl_kind ,&! thermal conductivity of snow (W/m/deg)
zref = 10._dbl_kind ,&! reference height for stability (m)
hs_min = 1.e-4_dbl_kind ,&! min snow thickness for computing zTsn (m)
- snowpatch = 0.005_dbl_kind ! parameter for fractional snow area (m)
+ snowpatch = 0.005_dbl_kind , & ! parameter for fractional snow area (m)
!tcx note cice snowpatch = 0.02
- integer (kind=int_kind), parameter :: &
- nspint = 3 ! number of solar spectral intervals
-
+ ! biogeochemistry
+ sk_l = 0.03_dbl_kind ! (m) skeletal layer thickness
+
+ integer (kind=int_kind), parameter, public :: &
+ nspint = 3 ,& ! number of solar spectral intervals
+ nspint_5bd = 5 ! number of solar spectral intervals with config_use_snicar_ad
+
! weights for albedos
! 4 Jan 2007 BPB Following are appropriate for complete cloud
! in a summer polar atmosphere with 1.5m bare sea ice surface:
@@ -116,6 +126,12 @@ module ice_constants_colpkg
real(kind=dbl_kind),public :: eccf ! earth orbit eccentricity factor
logical(kind=log_kind),public :: log_print ! Flags print of status/error
+ ! snow parameters
+ real (kind=dbl_kind), parameter, public :: &
+ snwlvlfac = 0.3_dbl_kind, & ! 30% rule: fractional increase in snow depth
+ ! over ridged ice, compared with level ice
+ rhosmin = 100.0_dbl_kind ! minimum snow density (kg/m^3)
+
!-----------------------------------------------------------------
! numbers used in column package
!-----------------------------------------------------------------
diff --git a/src/core_seaice/column/constants/cice/ice_constants_colpkg.F90 b/src/core_seaice/column/constants/cice/ice_constants_colpkg.F90
index 0a6c705164..a42413cacc 100644
--- a/src/core_seaice/column/constants/cice/ice_constants_colpkg.F90
+++ b/src/core_seaice/column/constants/cice/ice_constants_colpkg.F90
@@ -26,6 +26,7 @@ module ice_constants_colpkg
cp_air = 1005.0_dbl_kind ,&! specific heat of air (J/kg/K)
! (Briegleb JGR 97 11475-11485 July 1992)
emissivity= 0.95_dbl_kind ,&! emissivity of snow and ice
+!echmod emissivity= 0.985_dbl_kind ,&! emissivity of snow and ice
cp_ice = 2106._dbl_kind ,&! specific heat of fresh ice (J/kg/K)
cp_ocn = 4218._dbl_kind ,&! specific heat of ocn (J/kg/K)
! freshwater value needed for enthalpy
@@ -34,8 +35,9 @@ module ice_constants_colpkg
albocn = 0.06_dbl_kind ,&! ocean albedo
gravit = 9.80616_dbl_kind ,&! gravitational acceleration (m/s^2)
viscosity_dyn = 1.79e-3_dbl_kind, & ! dynamic viscosity of brine (kg/m/s)
- Tocnfrz = -1.8_dbl_kind ,&! freezing temp of seawater (C),
- ! used as Tsfcn for open water
+ Tocnfrz = -1.8_dbl_kind ,&! freezing temp of seawater (C), used
+ ! as Tsfcn for open water only when
+ ! tfrz_option is 'minus1p8' or null
rhofresh = 1000.0_dbl_kind ,&! density of fresh water (kg/m^3)
zvir = 0.606_dbl_kind ,&! rh2o/rair - 1.0
vonkar = 0.4_dbl_kind ,&! von Karman constant
@@ -72,11 +74,15 @@ module ice_constants_colpkg
ksno = 0.30_dbl_kind ,&! thermal conductivity of snow (W/m/deg)
zref = 10._dbl_kind ,&! reference height for stability (m)
hs_min = 1.e-4_dbl_kind ,&! min snow thickness for computing zTsn (m)
- snowpatch = 0.02_dbl_kind ! parameter for fractional snow area (m)
+ snowpatch = 0.02_dbl_kind, & ! parameter for fractional snow area (m)
+
+ ! biogeochemistry
+ sk_l = 0.03_dbl_kind ! (m) skeletal layer thickness
integer (kind=int_kind), parameter, public :: &
- nspint = 3 ! number of solar spectral intervals
-
+ nspint = 3 ,& ! number of solar spectral intervals
+ nspint_5bd = 5 ! number of solar spectral intervals used in SNICAR
+
! weights for albedos
! 4 Jan 2007 BPB Following are appropriate for complete cloud
! in a summer polar atmosphere with 1.5m bare sea ice surface:
@@ -107,6 +113,12 @@ module ice_constants_colpkg
real(kind=dbl_kind),public :: eccf ! earth orbit eccentricity factor
logical(kind=log_kind),public :: log_print ! Flags print of status/error
+ ! snow parameters
+ real (kind=dbl_kind), parameter, public :: &
+ snwlvlfac = 0.3_dbl_kind, & ! 30% rule: fractional increase in snow depth
+ ! over ridged ice, compared with level ice
+ rhosmin = 100.0_dbl_kind ! minimum snow density (kg/m^3)
+
!-----------------------------------------------------------------
! numbers used in column package
!-----------------------------------------------------------------
diff --git a/src/core_seaice/column/ice_aerosol.F90 b/src/core_seaice/column/ice_aerosol.F90
index b5f5e8007d..c3e6a9d0bf 100644
--- a/src/core_seaice/column/ice_aerosol.F90
+++ b/src/core_seaice/column/ice_aerosol.F90
@@ -455,12 +455,13 @@ subroutine update_snow_bgc (dt, nblyr, &
vice_old, vsno_old, &
vicen, vsnon, &
aicen, flux_bio_atm,&
- zbgc_atm, flux_bio)
+ zbgc_atm, flux_bio, &
+ bio_index_o)
- use ice_colpkg_shared, only: hi_ssl, hs_ssl
+ use ice_colpkg_shared, only: hi_ssl, hs_ssl, hs_ssl_min
use ice_constants_colpkg, only: c0, rhos, rhoi, hs_min, puny, &
- c2, c1
- use ice_zbgc_shared, only: kscavz
+ c2, c1, p5
+ use ice_zbgc_shared, only: kscavz
integer (kind=int_kind), intent(in) :: &
nbtrcr, & ! number of distinct snow tracers
@@ -469,7 +470,8 @@ subroutine update_snow_bgc (dt, nblyr, &
ntrcr ! number of tracers
integer (kind=int_kind), dimension (nbtrcr), intent(in) :: &
- bio_index
+ bio_index, &
+ bio_index_o ! provides index of scavenging (kscavz) data array
real (kind=dbl_kind), intent(in) :: &
dt ! time step
@@ -488,9 +490,11 @@ subroutine update_snow_bgc (dt, nblyr, &
vice_old, &
vsno_old
- real (kind=dbl_kind),dimension(nbtrcr), intent(inout) :: &
+ real (kind=dbl_kind),dimension(nbtrcr), intent(out) :: &
zbgc_snow, & ! aerosol contribution from snow to ice
- zbgc_atm, & ! and atm to ice concentration * volume (kg or mmol/m^3*m)
+ zbgc_atm ! and atm to ice concentration * volume (kg or mmol/m^3*m)
+
+ real (kind=dbl_kind),dimension(nbtrcr), intent(inout) :: &
flux_bio ! total ocean tracer flux (mmol/m^2/s)
real (kind=dbl_kind), dimension(nbtrcr), &
@@ -508,6 +512,9 @@ subroutine update_snow_bgc (dt, nblyr, &
real (kind=dbl_kind) :: &
dzssl, dzssl_new, & ! snow ssl thickness
dzint, dzint_new, & ! snow interior thickness
+ dz, & !
+ hi, & ! ice thickness (m)
+ hilyr, & ! ice layer thickness (m)
hs, & ! snow thickness (m)
dhs_evap, & ! snow thickness change due to evap
dhs_melts, & ! ... due to surface melt
@@ -541,6 +548,11 @@ subroutine update_snow_bgc (dt, nblyr, &
zbgc_atm(:) = c0
hs_old = vsno_old/aice_old
+ if (aice_old .gt. puny) then
+ hs_old = vsno_old/aice_old
+ else
+ hs_old = c0
+ end if
hslyr_old = hs_old/real(nslyr,kind=dbl_kind)
dzssl = min(hslyr_old/c2, hs_ssl)
@@ -549,40 +561,46 @@ subroutine update_snow_bgc (dt, nblyr, &
if (aicen > c0) then
ar = c1/aicen
hs = vsnon*ar
- dhs_melts = -melts
- dhs_snoice = snoice*rhoi/rhos
+ hi = vicen*ar
else ! ice disappeared during time step
- ar = c1
- hs = vsnon/aice_old
- dhs_melts = -melts
- dhs_snoice = snoice*rhoi/rhos
+ ar = c1
+ hs = c0
+ hi = c0
+ if (aice_old > c0) hs = vsnon/aice_old
endif
-
+ hilyr = hi/real(nblyr,kind=dbl_kind)
+ hslyr = hs/real(nslyr,kind=dbl_kind)
+ dzssl_new = min(hslyr/c2, hs_ssl)
+ dhs_melts = -melts
+ dhs_snoice = snoice*rhoi/rhos
dhs_evap = hs - (hs_old + dhs_melts - dhs_snoice &
+ fsnow/rhos*dt)
! trcrn() has units kg/m^3
- if ((vsno_old .le. puny) .or. (vsnon .le. puny)) then
-
+ if (dzssl_new .lt. hs_ssl_min) then ! Put atm BC/dust flux directly into the sea ice
do k=1,nbtrcr
flux_bio(k) = flux_bio(k) + &
(trcrn(bio_index(k)+ nblyr+1)*dzssl+ &
- trcrn(bio_index(k)+ nblyr+2)*dzint)/dt
+ trcrn(bio_index(k)+ nblyr+2)*dzint)/dt
trcrn(bio_index(k) + nblyr+1) = c0
trcrn(bio_index(k) + nblyr+2) = c0
- zbgc_atm(k) = zbgc_atm(k) &
- + flux_bio_atm(k)*dt
+ if (hilyr .lt. hs_ssl_min) then
+ flux_bio(k) = flux_bio(k) + flux_bio_atm(k)
+ else
+ zbgc_atm(k) = zbgc_atm(k) &
+ + flux_bio_atm(k)*dt
+ end if
enddo
- else
-
+ else
+
do k=1,nbtrcr
flux_bio_o(k) = flux_bio(k)
aerosno (k,1) = trcrn(bio_index(k)+ nblyr+1) * dzssl
aerosno (k,2) = trcrn(bio_index(k)+ nblyr+2) * dzint
aerosno0(k,:) = aerosno(k,:)
- aerotot0(k) = aerosno(k,2) + aerosno(k,1)
+ aerotot0(k) = aerosno(k,2) + aerosno(k,1)
enddo
!-------------------------------------------------------------------
@@ -590,7 +608,47 @@ subroutine update_snow_bgc (dt, nblyr, &
!-------------------------------------------------------------------
dzint = dzint + min(dzssl + dhs_evap, c0)
dzssl = max(dzssl + dhs_evap, c0)
-
+ if (dzssl <= puny) then
+ do k = 1,nbtrcr
+ aerosno(k,2) = aerosno(k,2) + aerosno(k,1)
+ aerosno(k,1) = c0
+ end do
+ end if
+ if (dzint <= puny) then
+ do k = 1,nbtrcr
+ flux_bio(k) = flux_bio(k) + (aerosno(k,2) + aerosno(k,1))/dt
+ aerosno(k,2) = c0
+ aerosno(k,1) = c0
+ end do
+ end if
+ !------------------------------------------------------------------
+ ! snowfall
+ !-------------------------------------------------------------------
+ if (fsnow > c0) then
+ sloss1 = c0
+ dz = min(fsnow/rhos*dt,dzssl)
+ do k = 1, nbtrcr
+ if (dzssl > puny) &
+ sloss1 = aerosno(k,1)*dz/dzssl
+ aerosno(k,1) = max(c0,aerosno(k,1) - sloss1)
+ aerosno(k,2) = aerosno(k,2) + sloss1
+ end do
+ dzssl = dzssl - dz + fsnow/rhos*dt
+ dzint = dzint + dz
+ end if
+ if (dzssl <= puny) then
+ do k = 1,nbtrcr
+ aerosno(k,2) = aerosno(k,2) + aerosno(k,1)
+ aerosno(k,1) = c0
+ end do
+ end if
+ if (dzint <= puny) then
+ do k = 1,nbtrcr
+ flux_bio(k) = flux_bio(k) + (aerosno(k,2) + aerosno(k,1))/dt
+ aerosno(k,2) = c0
+ aerosno(k,1) = c0
+ end do
+ end if
!-------------------------------------------------------------------
! surface snow melt
!-------------------------------------------------------------------
@@ -598,39 +656,37 @@ subroutine update_snow_bgc (dt, nblyr, &
do k = 1, nbtrcr
sloss1 = c0
sloss2 = c0
- if (dzssl > puny) &
- sloss1 = kscavz(k)*aerosno(k,1) &
- *min(-dhs_melts,dzssl)/dzssl
- aerosno(k,1) = aerosno(k,1) - sloss1
- if (dzint > puny) &
- sloss2 = kscavz(k)*aerosno(k,2) &
- *max(-dhs_melts-dzssl,c0)/dzint
- aerosno(k,2) = aerosno(k,2) - sloss2
- zbgc_snow(k) = zbgc_snow(k) + (sloss1+sloss2)
- enddo !
+ if (dzssl > puny) &
+ sloss1 = kscavz(bio_index_o(k))*aerosno(k,1) &
+ *min(-dhs_melts,dzssl)/dzssl
+ aerosno(k,1) = max(c0,aerosno(k,1) - sloss1)
+ if (dzint > puny) &
+ sloss2 = kscavz(bio_index_o(k))*aerosno(k,2) &
+ *max(-dhs_melts-dzssl,c0)/dzint
+ aerosno(k,2) = max(c0,aerosno(k,2) - sloss2)
+ flux_bio(k) = flux_bio(k) + (sloss1+sloss2)/dt ! all not scavenged ends in ocean
+ enddo
! update snow thickness
dzint=dzint+min(dzssl+dhs_melts, c0)
dzssl=max(dzssl+dhs_melts, c0)
- if ( dzssl <= puny ) then ! ssl melts away
- aerosno(:,2) = aerosno(:,1) + aerosno(:,2)
- aerosno(:,1) = c0
+ if ( dzssl .le. puny ) then ! ssl melts away
+ do k = 1,nbtrcr
+ aerosno(k,2) = aerosno(k,1) + aerosno(k,2)
+ aerosno(k,1) = c0
+ end do
dzssl = max(dzssl, c0)
endif
- if (dzint <= puny ) then ! all snow melts away
- zbgc_snow(:) = zbgc_snow(:) &
- + max(c0,aerosno(:,1) + aerosno(:,2))
- aerosno(:,:) = c0
+ if (dzint .le. puny ) then ! all snow melts away
+ do k = 1,nbtrcr
+ zbgc_snow(k) = zbgc_snow(k) &
+ + aerosno(k,1) + aerosno(k,2)
+ aerosno(k,:) = c0
+ enddo
dzint = max(dzint, c0)
endif
- endif
-
- !-------------------------------------------------------------------
- ! snowfall
- !-------------------------------------------------------------------
- if (fsnow > c0) dzssl = dzssl + fsnow/rhos*dt
-
+ endif ! -dhs_melts > puny
!-------------------------------------------------------------------
! snow-ice formation
!-------------------------------------------------------------------
@@ -638,39 +694,46 @@ subroutine update_snow_bgc (dt, nblyr, &
do k = 1, nbtrcr
sloss1 = c0
sloss2 = c0
- if (dzint > puny) &
- sloss2 = min(dhs_snoice, dzint) &
- *aerosno(k,2)/dzint
- aerosno(k,2) = aerosno(k,2) - sloss2
- if (dzssl > puny) &
+ if (dzint > puny .and. aerosno(k,2) > c0) &
+ sloss2 = min(dhs_snoice, dzint) &
+ *aerosno(k,2)/dzint
+ aerosno(k,2) = max(c0,aerosno(k,2) - sloss2)
+ if (dzssl > puny .and. aerosno(k,1) > c0) &
sloss1 = max(dhs_snoice-dzint, c0) &
*aerosno(k,1)/dzssl
- aerosno(k,1) = aerosno(k,1) - sloss1
+
+ aerosno(k,1) = max(c0,aerosno(k,1) - sloss1)
+ flux_bio(k) = flux_bio(k) &
+ + kscavz(bio_index_o(k)) * (sloss2+sloss1)/dt
zbgc_snow(k) = zbgc_snow(k) &
- + (sloss2+sloss1)
+ + (c1-kscavz(bio_index_o(k)))*(sloss2+sloss1)
enddo
- dzssl = dzssl - max(dhs_snoice-dzint, c0)
+ dzssl = max(c0,dzssl - max(dhs_snoice-dzint, c0))
dzint = max(dzint-dhs_snoice, c0)
- endif
+ endif ! dhs_snowice > puny
!-------------------------------------------------------------------
! aerosol deposition
!-------------------------------------------------------------------
- if (aicen > c0) then
- hs = vsnon * ar
- else
- hs = c0
- endif
- if (hs >= hs_min) then !should this really be hs_min or 0?
- ! should use same hs_min value as in radiation
+ ! if (aicen > c0) then
+ ! hs = vsnon * ar
+ ! else
+ ! hs = c0
+ ! endif
+ ! Spread out the atm dust flux in the snow interior for small snow surface layers
+ if (dzssl .ge. hs_ssl*p5) then
+
do k=1,nbtrcr
aerosno(k,1) = aerosno(k,1) &
+ flux_bio_atm(k)*dt
enddo
- else
+ else
+ dz = (hs_ssl*p5 - dzssl)/(hs_ssl*p5)
do k=1,nbtrcr
- zbgc_atm(k) = zbgc_atm(k) &
- + flux_bio_atm(k)*dt
+ aerosno(k,1) = aerosno(k,1) &
+ + flux_bio_atm(k)*dt*(c1-dz)
+ aerosno(k,2) = aerosno(k,2) &
+ + flux_bio_atm(k)*dt*dz
enddo
endif
@@ -690,30 +753,31 @@ subroutine update_snow_bgc (dt, nblyr, &
endif
if (dzint <= puny) then ! nothing in Snow Int
do k = 1, nbtrcr
- zbgc_snow(k) = zbgc_snow(k) + max(c0,aerosno(k,2))
+ zbgc_snow(k) = zbgc_snow(k) + max(c0,aerosno(k,2)+aerosno(k,1))
+ aerosno(k,1) = c0
aerosno(k,2) = c0
enddo
endif
hslyr = hs/real(nslyr,kind=dbl_kind)
dzssl_new = min(hslyr/c2, hs_ssl)
- dzint_new = hs - dzssl_new
+ dzint_new = max(c0,hs - dzssl_new)
- if (hs > hs_min) then !should this really be hs_min or 0?
+ if (hs > hs_min) then
do k = 1, nbtrcr
dznew = min(dzssl_new-dzssl, c0)
sloss1 = c0
- if (dzssl > puny) &
+ if (dzssl > puny .and. aerosno(k,1) > c0) &
sloss1 = dznew*aerosno(k,1)/dzssl ! not neccesarily a loss
- dznew = max(dzssl_new-dzssl, c0)
- if (dzint > puny) &
- sloss1 = sloss1 + aerosno(k,2)*dznew/dzint
- aerosno(k,1) = aerosno(k,1) + sloss1
- aerosno(k,2) = aerosno(k,2) - sloss1
+ dznew = max(dzssl_new-dzssl, c0)
+ if (dzint > puny .and. aerosno(k,2) > c0) &
+ sloss1 = aerosno(k,2)*dznew/dzint
+ aerosno(k,1) = max(c0,aerosno(k,1) + sloss1)
+ aerosno(k,2) = max(c0,aerosno(k,2) - sloss1)
enddo
else
zbgc_snow(:) = zbgc_snow(:) &
- + max(c0,aerosno(:,1) + aerosno(:,2))
+ + aerosno(:,1) + aerosno(:,2)
aerosno(:,:) = c0
endif
@@ -722,11 +786,16 @@ subroutine update_snow_bgc (dt, nblyr, &
!-------------------------------------------------------------------
do k = 1, nbtrcr
aerotot(k) = aerosno(k,2) + aerosno(k,1) &
- + zbgc_snow(k) + zbgc_atm(k)
+ + zbgc_snow(k) + zbgc_atm(k)
aero_cons(k) = aerotot(k)-aerotot0(k) &
- - ( flux_bio_atm(k) &
+ - ( flux_bio_atm(k) &
- (flux_bio(k)-flux_bio_o(k))) * dt
- if (aero_cons(k) > puny .or. zbgc_snow(k) + zbgc_atm(k) < c0) then
+ if (aerotot0(k) > aerotot(k) .and. aerotot0(k) > c0) then
+ aero_cons(k) = aero_cons(k)/aerotot0(k)
+ else if (aerotot(k) > c0) then
+ aero_cons(k) = aero_cons(k)/aerotot(k)
+ end if
+ if (aero_cons(k) > puny .or. zbgc_snow(k) + zbgc_atm(k) < c0) then
write(warning,*) 'Conservation failure: aerosols in snow'
call add_warning(warning)
write(warning,*) 'test aerosol 1'
@@ -754,14 +823,13 @@ subroutine update_snow_bgc (dt, nblyr, &
!-------------------------------------------------------------------
! reload tracers
!-------------------------------------------------------------------
- if (vsnon > puny) then
+ if (dzssl_new > puny .and. dzint_new > puny .and. vsnon > puny) then
do k = 1,nbtrcr
- trcrn(bio_index(k)+nblyr+1)=aerosno(k,1)/dzssl_new
+ trcrn(bio_index(k)+nblyr+1)=aerosno(k,1)/dzssl_new
trcrn(bio_index(k)+nblyr+2)=aerosno(k,2)/dzint_new
enddo
else
do k = 1,nbtrcr
- zbgc_snow(k) = (zbgc_snow(k) + aerosno(k,1) + aerosno(k,2))
trcrn(bio_index(k)+nblyr+1)= c0
trcrn(bio_index(k)+nblyr+2)= c0
enddo
diff --git a/src/core_seaice/column/ice_algae.F90 b/src/core_seaice/column/ice_algae.F90
index cb63dddf7a..1468fc9b0a 100644
--- a/src/core_seaice/column/ice_algae.F90
+++ b/src/core_seaice/column/ice_algae.F90
@@ -33,11 +33,11 @@ subroutine zbio (dt, nblyr, &
snoice, nbtrcr, &
fsnow, ntrcr, &
trcrn, bio_index, &
- aice_old, &
+ bio_index_o, aice_old, &
vice_old, vsno_old, &
vicen, vsnon, &
- aicen, flux_bio_atm,&
- n_cat, n_algae, &
+ aicen, flux_bio_atm,&
+ n_cat, n_algae, &
n_doc, n_dic, &
n_don, &
n_fed, n_fep, &
@@ -62,12 +62,13 @@ subroutine zbio (dt, nblyr, &
PP_net, ice_bio_net, &
snow_bio_net, grow_net, &
totalChla, &
+ flux_bion, &
l_stop, stop_label)
use ice_aerosol, only: update_snow_bgc
- use ice_constants_colpkg, only: c0, c1, puny
+ use ice_constants_colpkg, only: c0, c1, puny, p5
use ice_zbgc, only: merge_bgc_fluxes
-
+
integer (kind=int_kind), intent(in) :: &
nblyr, & ! number of bio layers
nslyr, & ! number of snow layers
@@ -80,7 +81,8 @@ subroutine zbio (dt, nblyr, &
ntrcr ! number of tracers
integer (kind=int_kind), dimension (nbtrcr), intent(in) :: &
- bio_index
+ bio_index, & ! references index of bio tracer (nbtrcr) to tracer array (ntrcr)
+ bio_index_o ! references index of data arrays (eg. kscavz)
real (kind=dbl_kind), intent(in) :: &
dt, & ! time step
@@ -109,14 +111,15 @@ subroutine zbio (dt, nblyr, &
dh_top_chl, & ! change in brine top (m) felt by algae
dh_direct ! surface flooding or surface runoff (m)
- real (kind=dbl_kind), dimension (nbtrcr), intent(inout) :: &
+ real (kind=dbl_kind), dimension (:), intent(inout) :: &
snow_bio_net,& ! net bio tracer in snow (mmol/m^2)
ice_bio_net, & ! net bio tracer in ice (mmol/m^2)
fbio_atmice, & ! bio flux from atm to ice (mmol/m^2/s)
fbio_snoice, & ! bio flux from snow to ice (mmol/m^2/s)
- flux_bio ! total ocean tracer flux (mmol/m^2/s)
+ flux_bio, & ! total ocean tracer flux (mmol/m^2/s)
+ flux_bion ! category ocean tracer flux (mmol/m^2/s)
- real (kind=dbl_kind), intent(inout) :: &
+ real (kind=dbl_kind), intent(in) :: &
hbri_old ! brine height (m)
real (kind=dbl_kind), dimension (nblyr+2), intent(inout) :: &
@@ -125,40 +128,40 @@ subroutine zbio (dt, nblyr, &
real (kind=dbl_kind), dimension (nblyr+1), intent(in) :: &
igrid , & ! biology vertical interface points
iTin , & ! salinity vertical interface points
- iphin , & ! Porosity on the igrid
+ iphin , & ! Porosity on the igrid
iDin ! Diffusivity/h on the igrid (1/s)
-
+
real (kind=dbl_kind), dimension (nilyr+1), intent(in) :: &
- cgrid , & ! CICE vertical coordinate
- icgrid , & ! CICE interface coordinate
- fswthrul ! visible short wave radiation on icgrid (W/m^2)
+ cgrid , & ! CICE vertical coordinate
+ icgrid , & ! CICE interface coordinate
+ fswthrul ! visible short wave radiation on icgrid (W/m^2)
- real (kind=dbl_kind), dimension(nbtrcr), &
+ real (kind=dbl_kind), dimension(:), &
intent(in) :: &
flux_bio_atm ! aerosol/bgc deposition rate (mmol/m^2 s)
real (kind=dbl_kind), dimension(ntrcr), &
intent(inout) :: &
- trcrn
+ trcrn
- real (kind=dbl_kind), dimension (nblyr+1), intent(inout) :: &
- zfswin ! visible Short wave flux on igrid (W/m^2)
-
- real (kind=dbl_kind), dimension (nblyr+1), intent(inout) :: &
+ real (kind=dbl_kind), dimension (nblyr+1), intent(inout) :: &
+ zfswin ! visible Short wave flux on igrid (W/m^2)
+
+ real (kind=dbl_kind), dimension (nblyr+1), intent(inout) :: &
Zoo ! N losses to the system from reaction terms
- ! (ie. zooplankton/bacteria) (mmol/m^3)
+ ! (ie. zooplankton/bacteria) (mmol/m^3)
- real (kind=dbl_kind), dimension (nbtrcr), intent(in) :: &
+ real (kind=dbl_kind), dimension (nbtrcr), intent(in) :: &
!change to inout when updating ocean fields
- ocean_bio ! ocean concentrations (mmol/m^3)
+ ocean_bio ! ocean concentrations (mmol/m^3)
real (kind=dbl_kind), dimension (nblyr+2), intent(in) :: &
bphin ! Porosity on the bgrid
- real (kind=dbl_kind), intent(inout):: &
+ real (kind=dbl_kind), intent(inout):: &
PP_net , & ! net PP (mg C/m^2/d) times aice
grow_net , & ! net specific growth (m/d) times vice
- upNO , & ! tot nitrate uptake rate (mmol/m^2/d) times aice
+ upNO , & ! tot nitrate uptake rate (mmol/m^2/d) times aice
upNH , & ! tot ammonium uptake rate (mmol/m^2/d) times aice
totalChla ! total chla (mg chla/m^2)
@@ -181,9 +184,6 @@ subroutine zbio (dt, nblyr, &
upNHn , & ! algal ammonium uptake rate (mmol/m^3/s)
grow_alg ! algal growth rate (mmol/m^3/s)
- real (kind=dbl_kind), dimension (nbtrcr) :: &
- flux_bion !tracer flux to ocean
-
real (kind=dbl_kind),dimension(nbtrcr) :: &
zbgc_snown, & ! aerosol contribution from snow to ice
zbgc_atmn ! and atm to ice concentration * volume (mmol/m^3*m)
@@ -194,9 +194,15 @@ subroutine zbio (dt, nblyr, &
flux_bio_sno !
real (kind=dbl_kind) :: &
- Tot_Nit, & !
- hsnow_i, & ! initial snow thickness (m)
- hsnow_f ! final snow thickness (m)
+ Tot_Nit, & !
+ hsnow_i, & ! initial snow thickness (m)
+ hsnow_f, & ! final snow thickness (m)
+ carbonError ! carbon conservation error (mmol/m2)
+
+ real (kind=dbl_kind) :: &
+ carbonInitial, & ! initial carbon content (mmol/m2)
+ carbonFinal, & ! final carbon content (mmol/m2)
+ carbonFlux ! carbon flux (mmol/m2/s)
logical (kind=log_kind) :: &
write_flux_diag
@@ -204,8 +210,18 @@ subroutine zbio (dt, nblyr, &
real (kind=dbl_kind) :: &
a_ice
+ real (kind=dbl_kind), parameter :: &
+ accuracy = 1.0e-13_dbl_kind
+
character(len=char_len_long) :: &
- warning
+ warning
+
+ real (kind=dbl_kind), dimension (nblyr+1) :: &
+ zspace ! vertical grid spacing
+
+ zspace(:) = c1/real(nblyr,kind=dbl_kind)
+ zspace(1) = p5*zspace(1)
+ zspace(nblyr+1) = p5*zspace(nblyr+1)
zbgc_snown(:) = c0
zbgc_atmn (:) = c0
@@ -213,21 +229,22 @@ subroutine zbio (dt, nblyr, &
flux_bio_sno(:) = c0
Tot_BGC_i (:) = c0
Tot_BGC_f (:) = c0
+ Zoo (:) = c0
hsnow_i = c0
hsnow_f = c0
write_flux_diag = .false.
-
- if (write_flux_diag) then
- if (aice_old > c0) then
- hsnow_i = vsno_old/aice_old
- do mm = 1,nbtrcr
- call bgc_column_sum (nblyr, nslyr, hsnow_i, hbri_old, &
+
+ call bgc_carbon_sum(nblyr, hbri_old, trcrn(:), carbonInitial,n_doc,n_dic,n_algae,n_don)
+
+ if (aice_old > puny) then
+ hsnow_i = vsno_old/aice_old
+ do mm = 1,nbtrcr
+ call bgc_column_sum (nblyr, nslyr, hsnow_i, hbri_old, &
trcrn(bio_index(mm):bio_index(mm)+nblyr+2), &
Tot_BGC_i(mm))
- enddo
- endif
+ enddo
endif
-
+
call update_snow_bgc (dt, nblyr, &
nslyr, &
meltt, melts, &
@@ -239,25 +256,26 @@ subroutine zbio (dt, nblyr, &
vice_old, vsno_old, &
vicen, vsnon, &
aicen, flux_bio_atm, &
- zbgc_atmn, flux_bio_sno)
+ zbgc_atmn, flux_bio_sno, &
+ bio_index_o)
call z_biogeochemistry (n_cat, dt, &
nilyr, nslyr, &
nblyr, nbtrcr, &
- n_algae, n_doc, &
+ n_algae, n_doc, &
n_dic, n_don, &
n_fed, n_fep, &
n_zaero, first_ice, &
- aicen, vicen, &
- hice_old, ocean_bio, &
+ aicen, vicen, &
+ hice_old, ocean_bio, &
flux_bion, bphin, &
- iphin, trcrn, &
+ iphin, trcrn, &
iDin, sss, &
fswthrul, grow_alg, &
upNOn, upNHn, &
dh_top, dh_bot, &
dh_top_chl, dh_bot_chl,&
- zfswin, hbri, &
+ zfswin, hbri, &
hbri_old, darcy_V, &
darcy_V_chl, bgrid, &
igrid, icgrid, &
@@ -267,14 +285,39 @@ subroutine zbio (dt, nblyr, &
Zoo, meltb, &
congel, l_stop, &
stop_label)
-
+
do mm = 1,nbtrcr
flux_bion(mm) = flux_bion(mm) + flux_bio_sno(mm)
enddo
- if (write_flux_diag) then
- if (aicen > c0) then
+ call bgc_carbon_sum(nblyr, hbri, trcrn(:), carbonFinal,n_doc,n_dic,n_algae,n_don)
+ call bgc_carbon_flux(flux_bio_atm,flux_bion,n_doc,n_dic,n_algae,n_don,carbonFlux)
+
+ carbonError = carbonInitial-carbonFlux*dt-carbonFinal
+
+ if (abs(carbonError) > accuracy * maxval ((/carbonInitial, carbonFinal/))) then
+ write(warning,*) 'carbonError:', carbonError
+ call add_warning(warning)
+ write(warning,*) 'carbonInitial:', carbonInitial
+ call add_warning(warning)
+ write(warning,*) 'carbonFinal:', carbonFinal
+ call add_warning(warning)
+ write(warning,*) 'carbonFlux (positive into ocean):', carbonFlux
+ call add_warning(warning)
+ write(warning,*) 'accuracy * maxval ((/carbonInitial, carbonFinal/:)', accuracy * maxval ((/carbonInitial, carbonFinal/))
+ call add_warning(warning)
+ if (aicen > c0) then
hsnow_f = vsnon/aicen
+ write(warning,*) 'after z_biogeochemistry'
+ call add_warning(warning)
+ write(warning,*) 'Remaining carbon after algal_dyn: Zoo'
+ call add_warning(warning)
+ do mm = 1,nblyr+1
+ write(warning,*) 'layer mm, Zoo(mm)'
+ call add_warning(warning)
+ write(warning,*) mm,Zoo(mm)
+ call add_warning(warning)
+ end do
do mm = 1,nbtrcr
call bgc_column_sum (nblyr, nslyr, hsnow_f, hbri, &
trcrn(bio_index(mm):bio_index(mm)+nblyr+2), &
@@ -295,6 +338,8 @@ subroutine zbio (dt, nblyr, &
call add_warning(warning)
write(warning,*) Tot_BGC_i(mm) + flux_bio_atm(mm)*dt - flux_bion(mm)*dt
call add_warning(warning)
+ !l_stop = .true.
+ !stop_label = "carbon conservation in ice_algae.F90"
enddo
endif
endif
@@ -303,7 +348,7 @@ subroutine zbio (dt, nblyr, &
call merge_bgc_fluxes (dt, nblyr, &
bio_index, n_algae, &
- nbtrcr, aicen, &
+ nbtrcr, aicen, &
vicen, vsnon, &
ntrcr, iphin, &
trcrn, &
@@ -314,8 +359,9 @@ subroutine zbio (dt, nblyr, &
fbio_snoice, fbio_atmice,&
PP_net, ice_bio_net,&
snow_bio_net, grow_alg, &
- grow_net, totalChla)
-
+ grow_net, totalChla, &
+ nslyr)
+
if (write_flux_diag) then
if (aicen > c0) then
if (n_cat .eq. 1) a_ice = c0
@@ -337,12 +383,12 @@ subroutine zbio (dt, nblyr, &
endif
endif
- end subroutine zbio
+ end subroutine zbio
!=======================================================================
- subroutine sklbio (dt, ntrcr, &
- nilyr, &
+ subroutine sklbio (dt, Tf, &
+ ntrcr, nilyr, &
nbtrcr, n_algae, &
n_zaero, n_doc, &
n_dic, n_don, &
@@ -375,6 +421,7 @@ subroutine sklbio (dt, ntrcr, &
real (kind=dbl_kind), intent(in) :: &
dt, & ! time step
+ Tf, & ! basal freezing temperature (C)
hmix, & ! mixed layer depth (m)
aicen, & ! ice area fraction
meltb, & ! bottom melt (m)
@@ -428,8 +475,8 @@ subroutine sklbio (dt, ntrcr, &
fswthru, first_ice, &
trcrn, upNOn, &
upNHn, grow_alg, &
- hin, l_stop, &
- stop_label)
+ hin, Tf, &
+ l_stop, stop_label)
if (l_stop) return
@@ -459,12 +506,12 @@ subroutine skl_biogeochemistry (dt, nilyr, &
fswthru, first_ice, &
trcrn, upNOn, &
upNHn, grow_alg_skl, &
- hin, l_stop, &
- stop_label)
+ hin, Tf, &
+ l_stop, stop_label)
- use ice_constants_colpkg, only: p5, p05, p1, c1, c0, puny, c10
+ use ice_constants_colpkg, only: p5, p05, p1, c1, c0, puny, c10, sk_l
use ice_colpkg_tracers, only: nt_bgc_N, ntrcr, bio_index
- use ice_colpkg_shared, only: dEdd_algae, bgc_flux_type, sk_l, R_chl2N
+ use ice_colpkg_shared, only: dEdd_algae, bgc_flux_type, R_chl2N
integer (kind=int_kind), intent(in) :: &
nilyr , & ! number of ice layers
@@ -478,6 +525,7 @@ subroutine skl_biogeochemistry (dt, nilyr, &
aicen , & ! ice area
meltb , & ! bottom ice melt
congel , & ! bottom ice growth
+ Tf , & ! bottom freezing temperature
fswthru ! shortwave passing through ice to ocean
logical (kind=log_kind), intent(in) :: &
@@ -527,20 +575,20 @@ subroutine skl_biogeochemistry (dt, nilyr, &
grow_val , & ! (m/x)
rphi_sk , & ! 1 / skeletal layer porosity
cinit_tmp , & ! temporary variable for concentration (mmol/m^2)
- Nerror ! change in total nitrogen from reactions
+ Cerror , & ! change in total carbon from reactions (mmol/m^3)
+ nitrification ! nitrate from nitrification (mmol/m^3)
real (kind=dbl_kind), parameter :: &
PVc = 1.e-6_dbl_kind , & ! type 'constant' piston velocity for interface (m/s)
PV_scale_growth = p5 , & ! scale factor in Jin code PV during ice growth
PV_scale_melt = p05 , & ! scale factor in Jin code PV during ice melt
growth_max = 1.85e-10_dbl_kind , & ! PVt function reaches maximum here. (m/s)
- Tin_bot = -1.8_dbl_kind , & ! temperature of the ice bottom (oC)
MJ1 = 9.667e-9_dbl_kind , & ! (m/s) coefficients in Jin2008
MJ2 = 38.8_dbl_kind , & ! (1) from:4.49e-4_dbl_kind*secday
MJ3 = 1.04e7_dbl_kind , & ! 1/(m/s) from: 1.39e-3_dbl_kind*secday^2
PV_frac_max = 0.9_dbl_kind ! Maximum Piston velocity is 90% of skeletal layer/dt
- logical (kind=log_kind) :: conserve_N
+ logical (kind=log_kind) :: conserve_C
character(len=char_len_long) :: &
warning ! warning message
@@ -550,11 +598,11 @@ subroutine skl_biogeochemistry (dt, nilyr, &
!-----------------------------------------------------------------
l_stop = .false.
- conserve_N = .true.
+ conserve_C = .true.
Zoo_skl = c0
rphi_sk = c1/phi_sk
PVt = c0
- iTin = Tin_bot
+ iTin = Tf
do nn = 1, nbtrcr
cinit (nn) = c0
@@ -564,6 +612,7 @@ subroutine skl_biogeochemistry (dt, nilyr, &
react (nn) = c0
PVflag (nn) = c1
cling (nn) = c0
+ nitrification = c0
!-----------------------------------------------------------------
! only the dominant tracer_type affects behavior
@@ -577,9 +626,6 @@ subroutine skl_biogeochemistry (dt, nilyr, &
endif
ice_growth = (congel-meltb)/dt
- if (first_ice) then
- trcrn(bio_index(nn)) = ocean_bio(nn) ! * sk_l*rphi_sk
- endif ! first_ice
cinit (nn) = trcrn(bio_index(nn)) * sk_l * rphi_sk
cinit_v(nn) = cinit(nn)/sk_l
if (cinit(nn) < c0) then
@@ -661,7 +707,8 @@ subroutine skl_biogeochemistry (dt, nilyr, &
iTin, &
upNOn, upNHn, &
Zoo_skl, &
- Nerror, conserve_N)
+ Cerror, conserve_C,&
+ nitrification)
!-----------------------------------------------------------------
! compute new tracer concencentrations
@@ -691,8 +738,8 @@ subroutine skl_biogeochemistry (dt, nilyr, &
! Currently not coupled with ocean biogeochemistry
! ocean_bio(nn) = ocean_bio(nn) + flux_bio(nn)/hmix*aicen
- if (.not. conserve_N) then
- write(warning,*) 'N not conserved in skl_bgc, Nerror:',Nerror
+ if (.not. conserve_C) then
+ write(warning,*) 'C not conserved in skl_bgc, Cerror:',Cerror
call add_warning(warning)
write(warning,*) 'sk_bgc < 0 after algal fluxes, nn,cinit,flux_bio',&
nn,cinit(nn),flux_bio(nn)
@@ -735,14 +782,14 @@ end subroutine skl_biogeochemistry
!=======================================================================
!
-! Solve the scalar vertical diffusion equation implicitly using
+! Solve the scalar vertical diffusion equation implicitly using
! tridiag_solver. Calculate the diffusivity from temperature and salinity.
-!
-! NOTE: In this subroutine, trcrn(nt_fbri) is the volume fraction of ice with
-! dynamic salinity or the height ratio == hinS/vicen*aicen, where hinS is the
+!
+! NOTE: In this subroutine, trcrn(nt_fbri) is the volume fraction of ice with
+! dynamic salinity or the height ratio == hinS/vicen*aicen, where hinS is the
! height of the brine surface relative to the bottom of the ice. This volume fraction
-! may be > 1 in which case there is brine above the ice surface (meltponds).
-!
+! may be > 1 in which case there is brine above the ice surface (meltponds).
+!
subroutine z_biogeochemistry (n_cat, dt, &
nilyr, nslyr, &
@@ -751,16 +798,16 @@ subroutine z_biogeochemistry (n_cat, dt, &
n_dic, n_don, &
n_fed, n_fep, &
n_zaero, first_ice, &
- aicen, vicen, &
- hice_old, ocean_bio, &
+ aicen, vicen, &
+ hice_old, ocean_bio, &
flux_bio, bphin, &
- iphin, trcrn, &
+ iphin, trcrn, &
iDin, sss, &
fswthrul, grow_alg, &
upNOn, upNHn, &
dh_top, dh_bot, &
dh_top_chl, dh_bot_chl,&
- zfswin, hbri, &
+ zfswin, hbri, &
hbri_old, darcy_V, &
darcy_V_chl, bgrid, &
i_grid, ic_grid, &
@@ -768,14 +815,14 @@ subroutine z_biogeochemistry (n_cat, dt, &
dhice, zbgc_atm, &
iTin, dh_direct, &
Zoo, meltb, &
- congel, l_stop, &
+ congel, l_stop, &
stop_label)
use ice_colpkg_tracers, only: nt_fbri, nt_zbgc_frac, &
ntrcr, nlt_bgc_Nit, tr_bgc_Fe, tr_zaero, &
nlt_bgc_Fed, nlt_zaero, bio_index, tr_bgc_N, &
- nlt_bgc_N
- use ice_constants_colpkg, only: c0, c1, c2, p5, puny, pi
+ nlt_bgc_N, tr_bgc_C, nlt_bgc_DIC
+ use ice_constants_colpkg, only: c0, c1, c2, p5, puny, pi, p1
use ice_colpkg_shared, only: hi_ssl, dEdd_algae, solve_zbgc, &
R_dFe2dust, dustFe_sol, algal_vel
@@ -787,12 +834,12 @@ subroutine z_biogeochemistry (n_cat, dt, &
nbtrcr, n_algae, & ! number of bgc tracers, number of autotrophs
n_zaero, & ! number of aerosols
n_doc, n_dic, n_don, n_fed, n_fep
-
+
logical (kind=log_kind), intent(in) :: &
first_ice ! initialized values should be used
real (kind=dbl_kind), intent(in) :: &
- dt , & ! time step
+ dt , & ! time step
hbri , & ! brine height (m)
dhice , & ! change due to sublimation/condensation (m)
bphi_min , & ! surface porosity
@@ -813,24 +860,24 @@ subroutine z_biogeochemistry (n_cat, dt, &
real (kind=dbl_kind), dimension (:), intent(inout) :: &
bgrid , & ! biology nondimensional vertical grid points
flux_bio , & ! total ocean tracer flux (mmol/m^2/s)
- zfswin , & ! visible Short wave flux on igrid (W/m^2)
+ zfswin , & ! visible Short wave flux on igrid (W/m^2)
Zoo , & ! N losses to the system from reaction terms
- ! (ie. zooplankton/bacteria) (mmol/m^3)
+ ! (ie. zooplankton/bacteria) (mmol/m^3)
trcrn ! bulk tracer concentration (mmol/m^3)
real (kind=dbl_kind), dimension (:), intent(in) :: &
i_grid , & ! biology vertical interface points
iTin , & ! salinity vertical interface points
- iphin , & ! Porosity on the igrid
+ iphin , & ! Porosity on the igrid
iDin , & ! Diffusivity/h on the igrid (1/s)
- ic_grid , & ! CICE interface coordinate
- fswthrul , & ! visible short wave radiation on icgrid (W/m^2)
+ ic_grid , & ! CICE interface coordinate
+ fswthrul , & ! visible short wave radiation on icgrid (W/m^2)
zbgc_snow , & ! tracer input from snow (mmol/m^3*m)
zbgc_atm , & ! tracer input from atm (mmol/m^3 *m)
- ocean_bio , & ! ocean concentrations (mmol/m^3)
+ ocean_bio , & ! ocean concentrations (mmol/m^3)
bphin ! Porosity on the bgrid
- real (kind=dbl_kind), intent(inout) :: &
+ real (kind=dbl_kind), intent(in) :: &
hbri_old ! brine height (m)
real (kind=dbl_kind), dimension (:,:), intent(out) :: &
@@ -853,15 +900,16 @@ subroutine z_biogeochemistry (n_cat, dt, &
! local variables
integer (kind=int_kind) :: &
- k, m, mm, nn ! vertical biology layer index
+ k, m, mm, nn ! vertical biology layer index
real (kind=dbl_kind) :: &
- hin , & ! ice thickness (m)
+ hin , & ! ice thickness (m)
hin_old , & ! ice thickness before current melt/growth (m)
ice_conc , & ! algal concentration in ice above hin > hinS
sum_old , & !
sum_new , & !
sum_tot , & !
+ sum_initial , & !
zspace , & ! 1/nblyr
darcyV , & !
dhtop , & !
@@ -871,7 +919,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
dhflood ! >=0 (m) surface flooding from the ocean
real (kind=dbl_kind), dimension (nblyr+2) :: &
- bphin_N ! porosity for tracer model has minimum
+ bphin_N ! porosity for tracer model has minimum
! bphin_N >= bphimin
real (kind=dbl_kind), dimension (nblyr+1) :: &
@@ -884,7 +932,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
D_spdiag , & ! artificial diffusion matrix
D_sbdiag , & ! artificial diffusion matrix
biomat_low , & ! Low order solution
- Nerror ! Change in N after reactions
+ Cerror ! Change in N after reactions
real (kind=dbl_kind), dimension(nblyr+1,nbtrcr):: &
react ! biological sources and sinks for equation matrix
@@ -915,21 +963,23 @@ subroutine z_biogeochemistry (n_cat, dt, &
trtmp ! temporary, remapped tracers
logical (kind=log_kind), dimension(nblyr+1) :: &
- conserve_N
+ conserve_C
real (kind=dbl_kind), dimension(nblyr+1):: & ! temporary variables for
- Diff , & ! diffusivity
+ Diff , & ! diffusivity
initcons , & ! initial concentration
biocons , & ! new concentration
dmobile , & !
initcons_mobile,&!
- initcons_stationary
-
+ initcons_stationary, &
+ dz , & ! normalized vertical grid spacing
+ nitrification ! nitrate produced from nitrification (mmol/m3)
+
real (kind=dbl_kind), dimension (nilyr+1):: &
icegrid ! correct for large ice surface layers
real (kind=dbl_kind):: &
- top_conc ! 1% (min_bgc) of surface concentration
+ top_conc ! 1% (min_bgc) of surface concentration
! when hin > hbri: just used in sw calculation
real (kind=dbl_kind):: &
@@ -943,34 +993,39 @@ subroutine z_biogeochemistry (n_cat, dt, &
V_c , & ! volume of collector (um^3)
V_alg ! volume of algae (um^3)
- real (kind=dbl_kind), dimension(nbtrcr) :: &
- mobile ! c1 if mobile, c0 otherwise
+ real (kind=dbl_kind), dimension(nbtrcr) :: &
+ mobile ! c0 if mobile, c1 otherwise
! local parameters
-
+
real (kind=dbl_kind), parameter :: &
accuracy = 1.0e-14_dbl_kind, &
r_c = 3.0e3_dbl_kind , & ! ice crystal radius (um)
- r_bac= 15.0_dbl_kind , & ! diatom large radius (um)
+ r_bac= 4.7_dbl_kind , & ! diatom large radius (um)
r_alg= 10.0_dbl_kind , & ! diatom small radius (um)
- N_vol = 0.04e-12_dbl_kind , & ! (g) Nitrogen per um^3
- Ng_to_mmol =0.0140067_dbl_kind , & ! (g/mmol) Nitrogen
- f_s = c1 , & ! fracton of sites available for saturation
- f_a = c1 , & ! fraction of collector available for attachment
- f_v = 0.7854 ! fraction of algal coverage on area availabel for attachment 4(pi r^2)/(4r)^2 [Johnson et al, 1995, water res. research]
-
+ Nquota_A = 0.88_dbl_kind, & ! slope in Nitrogen quota to cell volume fit
+ ! (Lomas et al. 2019, Edwards et al. 2012)
+ Nquota_I = 0.0408_dbl_kind, & ! Intercept in N quota to cell volume fit
+ f_s = p1, & ! fracton of sites available for saturation
+ f_a = 0.3_dbl_kind, & !c1 , & ! fraction of collector available for attachment
+ f_v = 0.7854 ! fraction of algal coverage on area availabel for attachment
+ ! 4(pi r^2)/(4r)^2 [Johnson et al, 1995, water res. research]
+
integer, parameter :: &
nt_zfswin = 1 ! for interpolation of short wave to bgrid
character(len=char_len_long) :: &
- warning ! warning message
+ warning ! warning message
!-------------------------------------
- ! Initialize
- !-----------------------------------
+ ! Initialize
+ !-----------------------------------
l_stop = .false.
zspace = c1/real(nblyr,kind=dbl_kind)
+ dz(:) = zspace
+ dz(1) = zspace/c2
+ dz(nblyr+1) = zspace/c2
in_init_cons(:,:) = c0
atm_add_cons(:) = c0
sum_react(:) = c0
@@ -979,7 +1034,8 @@ subroutine z_biogeochemistry (n_cat, dt, &
darcyV = c0
C_top(:) = c0
mobile(:) = c0
- conserve_N(:) = .true.
+ conserve_C(:) = .true.
+ nitrification(:) = c0
do m = 1, nbtrcr
do k = 1, nblyr+1
@@ -989,22 +1045,20 @@ subroutine z_biogeochemistry (n_cat, dt, &
iphin_N(k) = iphin(k)
bphin_N(1) = bphi_min
- if (first_ice) then
- trcrn(bio_index(m) + k-1) = ocean_bio(m)*zbgc_init_frac(m)
- in_init_cons(k,m) = trcrn(bio_index(m) + k-1)*hbri_old
- elseif (abs(trcrn(bio_index(m) + k-1)) < puny) then
+ if (abs(trcrn(bio_index(m) + k-1)) < puny) then
+ flux_bio(m) = flux_bio(m) + trcrn(bio_index(m) + k-1)* hbri_old * dz(k)/dt
trcrn(bio_index(m) + k-1) = c0
in_init_cons(k,m) = c0
else
in_init_cons(k,m) = trcrn(bio_index(m) + k-1)* hbri_old
- endif ! first_ice
+ endif
if (trcrn(bio_index(m) + k-1) < c0 ) then
write(warning,*)'zbgc initialization error, first ice = ', first_ice
call add_warning(warning)
write(warning,*)'Category,m:',n_cat,m
call add_warning(warning)
- write(warning,*)'hbri,hbri_old'
+ write(warning,*)'hbri,hbri_old'
call add_warning(warning)
write(warning,*) hbri,hbri_old
call add_warning(warning)
@@ -1014,7 +1068,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
call add_warning(warning)
l_stop = .true.
stop_label = 'zbgc initialization error'
- endif
+ endif
if (l_stop) return
enddo !k
enddo !m
@@ -1025,7 +1079,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
ice_conc = c0
hin = vicen/aicen
- hin_old = hice_old
+ hin_old = hice_old
!-----------------------------------------------------------------
! calculate the saturation concentration for attachment: Sat_conc
@@ -1034,13 +1088,13 @@ subroutine z_biogeochemistry (n_cat, dt, &
phi_max = maxval(bphin_N(2:nblyr+1))
S_col = 4.0_dbl_kind*pi*r_c**2
P_b = pi*r_bac**2 !*10-6 for colloids
- V_c = 4.0_dbl_kind*pi*r_c**3/3.0_dbl_kind*(1.0e-6_dbl_kind)**3 ! (m^3) sphere
+ V_c = 4.0_dbl_kind*pi*r_c**3/3.0_dbl_kind !*(1.0e-6_dbl_kind)**3 (m^3) sphere
V_alg = pi/6.0_dbl_kind*r_bac*r_alg**2 ! prolate spheroid (*10-9 for colloids)
- Sat_conc= f_s*f_a*f_v*(c1-phi_max)/V_c*S_col/P_b*N_vol*V_alg/Ng_to_mmol
- !mmol/m^3 (algae, don, hum...) and umols/m^3 for colloids
+ Sat_conc= f_s*f_a*f_v*(c1-phi_max)/V_c*S_col/P_b*(V_alg)**Nquota_A*Nquota_I * 1.0e9_dbl_kind
+ !mmol/m^3 (algae, don, hum...) and umols/m^3 for colloids
!-----------------------------------------------------------------
- ! convert surface dust flux (n_zaero > 2) to dFe(1) flux
+ ! convert surface dust flux (n_zaero > 2) to dFe(1) flux
!-----------------------------------------------------------------
dust_Fe(:) = c0
@@ -1052,22 +1106,22 @@ subroutine z_biogeochemistry (n_cat, dt, &
R_dFe2dust * dustFe_sol
! dust_Fe(nlt_zaero(m)) = -(zbgc_snow(nlt_zaero(m)) + zbgc_atm(nlt_zaero(m))) * &
! dustFe_sol
- enddo
+ enddo
endif
- do m = 1,nbtrcr
+ do m = 1,nbtrcr
!-----------------------------------------------------------------
! time constants for mobile/stationary phase changes
!-----------------------------------------------------------------
-
- if (m .ne. nlt_bgc_N(1)) then
+
+ if (m .ne. nlt_bgc_N(1)) then
if (hin_old > hin) then !melting
rtau_rel(m) = c1/tau_rel(m)
rtau_ret(m) = c0
else !not melting
rtau_ret(m) = c1/tau_ret(m)
rtau_rel(m) = c0
- endif
+ endif
elseif (tr_bgc_N .and. hin_old > hin + algal_vel*dt) then
rtau_rel(m) = c1/tau_rel(m)
rtau_ret(m) = c0
@@ -1082,38 +1136,38 @@ subroutine z_biogeochemistry (n_cat, dt, &
darcyV = darcy_V
C_top(m) = in_init_cons(1,m)*trcrn(nt_zbgc_frac+m-1)!mobile fraction
source(m) = abs(zbgc_snow(m) + zbgc_atm(m) + dust_Fe(m))
- dhflood = max(c0,-dh_direct) ! ocean water flooding surface
- dhrunoff = max(c0,dh_direct)
-
- if (dhtop+darcyV/bphin_N(1)*dt < -puny) then !snow/top ice melt
- C_top(m) = (zbgc_snow(m)+zbgc_atm(m) + dust_Fe(m))/abs(dhtop &
- + darcyV/bphin_N(1)*dt + puny)*hbri_old
- elseif (dhtop+darcyV/bphin_N(1)*dt >= -puny .and. &
- abs((zbgc_snow(m)+zbgc_atm(m) + dust_Fe(m)) + &
- ocean_bio(m)*bphin_N(1)*dhflood) > puny) then
- atm_add_cons(m) = abs(zbgc_snow(m) + zbgc_atm(m)+ dust_Fe(m)) + &
- ocean_bio(m)*bphin_N(1)*dhflood
- else ! only positive fluxes
+ dhflood = max(c0,-dh_direct) ! ocean water flooding surface
+ dhrunoff = max(c0,dh_direct)
+
+ if (dhtop+darcyV/bphin_N(1)*dt < -puny) then !snow/top ice melt
+ C_top(m) = (zbgc_snow(m)+zbgc_atm(m) + dust_Fe(m))/abs(dhtop &
+ + darcyV/bphin_N(1)*dt + puny)*hbri_old
+ elseif (dhtop+darcyV/bphin_N(1)*dt >= -puny .and. &
+ abs((zbgc_snow(m)+zbgc_atm(m) + dust_Fe(m)) + &
+ ocean_bio(m)*bphin_N(1)*dhflood) > puny) then
+ atm_add_cons(m) = abs(zbgc_snow(m) + zbgc_atm(m)+ dust_Fe(m)) + &
+ ocean_bio(m)*bphin_N(1)*dhflood
+ else ! only positive fluxes
atm_add_cons(m) = abs(zbgc_snow(m) + zbgc_atm(m)+ dust_Fe(m))
- endif
+ endif
- C_bot(m) = ocean_bio(m)*hbri_old*iphin_N(nblyr+1)
+ C_bot(m) = ocean_bio(m)*hbri_old*iphin_N(nblyr+1)
enddo ! m
!-----------------------------------------------------------------
- ! Interpolate shortwave flux, fswthrul (defined at top to bottom with nilyr+1
+ ! Interpolate shortwave flux, fswthrul (defined at top to bottom with nilyr+1
! evenly spaced with spacing = (1/nilyr) to grid variable zfswin:
!-----------------------------------------------------------------
- trtmp(:) = c0
+ trtmp(:) = c0
trtmp0(:)= c0
zfswin(:) = c0
do k = 1, nilyr+1
! contains cice values (fswthrul(1) is surface value)
! and fwsthrul(nilyr+1) is output
- trtmp0(nt_zfswin+k-1) = fswthrul(k)
+ trtmp0(nt_zfswin+k-1) = fswthrul(k)
enddo !k
call remap_zbgc(ntrcr, nilyr+1, &
@@ -1123,7 +1177,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
hin, hbri, &
ic_grid(1:nilyr+1), &
i_grid(1:nblyr+1),ice_conc, &
- l_stop, stop_label)
+ l_stop, stop_label)
if (l_stop) return
@@ -1131,8 +1185,8 @@ subroutine z_biogeochemistry (n_cat, dt, &
zfswin(k) = trtmp(nt_zfswin+k-1)
enddo
!-----------------------------------------------------------------
- ! Initialze Biology
- !-----------------------------------------------------------------
+ ! Initialze Biology
+ !-----------------------------------------------------------------
do mm = 1, nbtrcr
mobile(mm) = c0
@@ -1145,31 +1199,34 @@ subroutine z_biogeochemistry (n_cat, dt, &
!-----------------------------------------------------------------
! Compute FCT
- !-----------------------------------------------------------------
+ !-----------------------------------------------------------------
- do mm = 1, nbtrcr
+ do mm = 1, nbtrcr
- if (hbri_old > thinS .and. hbri > thinS) then
+ if (hbri_old > thinS .and. hbri > thinS) then
do k = 1,nblyr+1
initcons_mobile(k) = in_init_cons(k,mm)*trcrn(nt_zbgc_frac+mm-1)
- initcons_stationary(k) = mobile(mm)*(in_init_cons(k,mm)-initcons_mobile(k))
+ initcons_stationary(k) = max(c0,in_init_cons(k,mm)-initcons_mobile(k))
+
+! allow release of Nitrate/silicate, but not adsorption *
dmobile(k) = mobile(mm)*(initcons_mobile(k)*(exp(-dt*rtau_ret( mm))-c1) + &
- initcons_stationary(k)*(c1-exp(-dt*rtau_rel(mm))))
+ initcons_stationary(k)*(c1-exp(-dt*rtau_rel(mm)))) + &
+ (1-mobile(mm))*initcons_stationary(k)*(c1-exp(-dt*rtau_rel(mm)))
initcons_mobile(k) = max(c0,initcons_mobile(k) + dmobile(k))
initcons_stationary(k) = max(c0,initcons_stationary(k) - dmobile(k))
if (initcons_stationary(k)/hbri_old > Sat_conc) then
initcons_mobile(k) = initcons_mobile(k) + initcons_stationary(k) - Sat_conc*hbri_old
- initcons_stationary(k) = Sat_conc*hbri_old
+ initcons_stationary(k) = Sat_conc*hbri_old
endif
- Diff(k) = iDin(k)
- initcons(k) = initcons_mobile(k)
+ Diff(k) = iDin(k)
+ initcons(k) = initcons_mobile(k)
biocons(k) = initcons_mobile(k)
enddo
call compute_FCT_matrix &
(initcons,sbdiagz, dt, nblyr, &
- diagz, spdiagz, rhsz, bgrid, &
+ diagz, spdiagz, rhsz, bgrid, &
i_grid, darcyV, dhtop, &
dhbot, iphin_N, &
Diff, hbri_old, &
@@ -1197,19 +1254,19 @@ subroutine z_biogeochemistry (n_cat, dt, &
source(mm))
if (l_stop) return
-
- call compute_FCT_corr &
+
+ call compute_FCT_corr &
(initcons, &
biocons, dt, nblyr, &
- D_sbdiag, D_spdiag, ML_diag)
+ D_sbdiag, D_spdiag, ML_diag)
top_conc = c0 ! or frazil ice concentration
-
+
! assume diatoms actively maintain there relative position in the ice
- if (mm .ne. nlt_bgc_N(1)) then
-
- call regrid_stationary &
+ if (mm .ne. nlt_bgc_N(1)) then
+
+ call regrid_stationary &
(initcons_stationary, hbri_old, &
hbri, dt, &
ntrcr, &
@@ -1218,8 +1275,8 @@ subroutine z_biogeochemistry (n_cat, dt, &
l_stop, stop_label, &
meltb, congel)
- elseif (tr_bgc_N .and. mm .eq. nlt_bgc_N(1)) then
- if (meltb > algal_vel*dt .or. aicen < 0.001_dbl_kind) then
+ elseif (tr_bgc_N .and. mm .eq. nlt_bgc_N(1)) then
+ if (meltb > algal_vel*dt .or. aicen < 0.001_dbl_kind) then
call regrid_stationary &
(initcons_stationary, hbri_old, &
@@ -1228,7 +1285,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
nblyr, top_conc, &
i_grid, flux_bio(mm),&
l_stop, stop_label, &
- meltb, congel)
+ meltb, congel)
endif
endif
@@ -1236,21 +1293,32 @@ subroutine z_biogeochemistry (n_cat, dt, &
biomat_cons(:,mm) = biocons(:) + initcons_stationary(:)
+ sum_initial = (in_init_cons(1,mm) + in_init_cons(nblyr+1,mm))*zspace/c2
sum_old = (biomat_low(1) + biomat_low(nblyr+1))*zspace/c2
sum_new = (biocons(1)+ biocons(nblyr+1))*zspace/c2
sum_tot = (biomat_cons(1,mm) + biomat_cons(nblyr+1,mm))*zspace/c2
do k = 2,nblyr
+ sum_initial = sum_initial + in_init_cons(k,mm)*zspace
sum_old = sum_old + biomat_low(k)*zspace
sum_new = sum_new + biocons(k)*zspace
sum_tot = sum_tot + biomat_cons(k,mm)*zspace
enddo
trcrn(nt_zbgc_frac+mm-1) = zbgc_frac_init(mm)
- if (sum_tot > c0 .and. mobile(mm) > c0) trcrn(nt_zbgc_frac+mm-1) = sum_new/sum_tot
-
- if (abs(sum_new-sum_old) > accuracy*sum_old .or. &
+ if (sum_tot > c0) trcrn(nt_zbgc_frac+mm-1) = sum_new/sum_tot
+
+ if (abs(sum_initial-sum_tot-flux_bio(mm)*dt + source(mm)) > accuracy*max(sum_initial,sum_tot) .or. &
+! if (abs(sum_new-sum_old) > accuracy*sum_old .or. &
minval(biocons(:)) < c0 .or. minval(initcons_stationary(:)) < c0 &
.or. l_stop) then
- write(warning,*)'zbgc FCT tracer solution failed,nn', nn
+ write(warning,*)'zbgc FCT tracer solution failed,mm', mm
+ call add_warning(warning)
+ write(warning,*)'sum_new,sum_tot,sum_initial,flux_bio(mm),source(mm):'
+ call add_warning(warning)
+ write(warning,*)sum_new,sum_tot,sum_initial,flux_bio(mm),source(mm)
+ call add_warning(warning)
+ write(warning,*)'error = sum_initial-sum_tot-flux_bio(mm)*dt+source(mm)'
+ call add_warning(warning)
+ write(warning,*)sum_initial-sum_tot-flux_bio(mm)*dt+source(mm)
call add_warning(warning)
write(warning,*)'sum_new,sum_old:',sum_new,sum_old
call add_warning(warning)
@@ -1279,54 +1347,76 @@ subroutine z_biogeochemistry (n_cat, dt, &
write(warning,*)'Category,mm:',n_cat,mm
call add_warning(warning)
! l_stop = .true.
- stop_label = 'zbgc FCT tracer solution failed'
+ stop_label = 'zbgc FCT tracer solution warning'
endif
if (l_stop) return
- else
-
+ else
+
Call thin_ice_flux(hbri,hbri_old,iphin_N, biomat_cons(:,mm), &
flux_bio(mm),source(mm), &
i_grid, dt, nblyr,ocean_bio(mm))
endif ! thin or not
- do k = 1,nblyr+1
- biomat_brine(k,mm) = biomat_cons(k,mm)/hbri/iphin_N(k)
+ do k = 1,nblyr+1
+ biomat_brine(k,mm) = biomat_cons(k,mm)/hbri/iphin_N(k)
enddo ! k
- enddo ! mm
+ enddo ! mm
- react(:,:) = c0
+ react(:,:) = c0
grow_alg(:,:) = c0
if (solve_zbgc) then
- do k = 1, nblyr+1
+ do k = 1, nblyr+1
call algal_dyn (dt, &
n_zaero, n_doc, n_dic, n_don, n_fed, n_fep, &
dEdd_algae, &
- zfswin(k), react(k,:), &
+ zfswin(k), react(k,:), &
biomat_brine(k,:), nbtrcr, &
grow_alg(k,:), n_algae, &
iTin(k), &
upNOn(k,:), upNHn(k,:), &
Zoo(k), &
- Nerror(k), conserve_N(k))
-
+ Cerror(k), conserve_C(k), &
+ nitrification(k))
enddo ! k
endif ! solve_zbgc
!-----------------------------------------------------------------
! Update the tracer variable
!-----------------------------------------------------------------
-
+
+ sum_new = c0
+ sum_tot = c0
+
do m = 1,nbtrcr
do k = 1,nblyr+1 ! back to bulk quantity
- bio_tmp = (biomat_brine(k,m) + react(k,m))*iphin_N(k)
-
- if (.not. conserve_N(k)) then
- write(warning, *) 'N in algal_dyn not conserved'
+ bio_tmp = (biomat_brine(k,m) + react(k,m))*iphin_N(k)
+ if (tr_bgc_C .and. m .eq. nlt_bgc_DIC(1) .and. bio_tmp < -puny) then ! satisfy DIC demands from ocean
+ write(warning, *) 'DIC demand from ocean'
+ call add_warning(warning)
+ write(warning, *) 'm, nlt_bgc_DIC(1), bio_tmp, react(k,m):'
+ call add_warning(warning)
+ write(warning, *) m, nlt_bgc_DIC(1), bio_tmp, react(k,m)
call add_warning(warning)
- write(warning, *) 'Nerror(k):', Nerror(k)
+ flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri_old/dt
+ bio_tmp = c0
+ end if
+ if (m .eq. nlt_bgc_Nit) then
+ initcons_mobile(k) = max(c0,(biomat_brine(k,m)-nitrification(k) + &
+ react(k,m))*iphin_N(k)*trcrn(nt_zbgc_frac+m-1))
+ initcons_stationary(k) = max(c0,((c1-trcrn(nt_zbgc_frac+m-1))*(biomat_brine(k,m)- &
+ nitrification(k) + react(k,m)) + nitrification(k))*iphin_N(k))
+
+ sum_new = sum_new + initcons_mobile(k)*dz(k)
+ sum_tot = sum_tot + (initcons_mobile(k) + initcons_stationary(k))*dz(k)
+
+ end if ! m .eq. nlt_bgc_Nit
+ if (.not. conserve_C(k)) then
+ write(warning, *) 'C in algal_dyn not conserved'
+ call add_warning(warning)
+ write(warning, *) 'Cerror(k):', Cerror(k)
call add_warning(warning)
write(warning, *) 'k,m,hbri,hbri_old,bio_tmp,biomat_cons(k,m),ocean_bio(m)'
call add_warning(warning)
@@ -1337,10 +1427,11 @@ subroutine z_biogeochemistry (n_cat, dt, &
write(warning, *) react(k,m),iphin_N(k),biomat_brine(k,m)
call add_warning(warning)
l_stop = .true.
- stop_label = 'N in algal_dyn not conserved'
- elseif (abs(bio_tmp) < puny) then
+ stop_label = 'C in algal_dyn not conserved'
+ elseif (abs(bio_tmp) < puny) then
+ flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri_old/dt
bio_tmp = c0
- elseif (bio_tmp > 1.0e6_dbl_kind) then
+ elseif (bio_tmp > 1.0e8_dbl_kind) then
write(warning, *) 'very large bgc value'
call add_warning(warning)
write(warning, *) 'k,m,hbri,hbri_old,bio_tmp,biomat_cons(k,m),ocean_bio(m)'
@@ -1373,6 +1464,7 @@ subroutine z_biogeochemistry (n_cat, dt, &
l_stop = .true.
stop_label = 'negative bgc'
endif
+ trcrn(bio_index(m)+k-1) = max(c0, bio_tmp)
if (l_stop) then
write(warning, *) 'trcrn(nt_zbgc_frac+m-1):',trcrn(nt_zbgc_frac+m-1)
call add_warning(warning)
@@ -1386,26 +1478,14 @@ subroutine z_biogeochemistry (n_cat, dt, &
call add_warning(warning)
return
endif
- trcrn(bio_index(m)+k-1) = max(c0, bio_tmp)
- if (ocean_bio(m) .le. c0 .and. flux_bio(m) < c0) then
- ! if (flux_bio(m) < -1.0e-12_dbl_kind) then
- ! write(warning, *) 'no ocean_bio but flux_bio < c0'
- ! call add_warning(warning)
- ! write(warning, *) 'm,ocean_bio(m),flux_bio(m)'
- ! call add_warning(warning)
- ! write(warning, *) m,ocean_bio(m),flux_bio(m)
- ! call add_warning(warning)
- ! write(warning, *) 'setting flux_bio(m) = c0'
- ! call add_warning(warning)
- ! l_stop = .true.
- ! stop_label = 'flux_bio < 0 when ocean_bio = 0'
- ! endif
- flux_bio(m) = max(c0,flux_bio(m))
- endif
enddo ! k
- enddo ! m
-
-770 format (I6,D16.6)
+ if (m .eq. nlt_bgc_Nit .and. MAXVAL(nitrification) > c0) then
+ trcrn(nt_zbgc_frac+m-1) = zbgc_frac_init(m)
+ if (sum_tot > c0) trcrn(nt_zbgc_frac+m-1) = sum_new/sum_tot
+ end if
+ enddo ! m
+
+770 format (I6,D16.6)
781 format (I6,I6,I6)
790 format (I6,I6)
791 format (f24.17)
@@ -1425,29 +1505,30 @@ end subroutine z_biogeochemistry
subroutine algal_dyn (dt, &
n_zaero, n_doc, n_dic, n_don, n_fed, n_fep, &
dEdd_algae, &
- fswthru, reactb, &
+ fswthru, reactb, &
ltrcrn, nbtrcr, &
grow_alg, n_algae, &
T_bot, &
upNOn, upNHn, &
Zoo, &
- Nerror, conserve_N)
+ Cerror, conserve_C, &
+ nitrification)
use ice_constants_colpkg, only: p1, p5, c0, c1, secday, puny
use ice_colpkg_shared, only: max_algae, max_DON, max_DOC, R_C2N, R_chl2N, &
- T_max, fsal , fr_resp , &
- op_dep_min , fr_graze_s , &
- fr_graze_e , fr_mort2min , &
- fr_dFe , k_nitrif , &
- t_iron_conv , max_loss , &
- max_dfe_doc1 , fr_resp_s , &
- y_sk_DMS , t_sk_conv , &
- t_sk_ox
+ T_max, fsal , fr_resp , &
+ op_dep_min , fr_graze_s , &
+ fr_graze_e , fr_mort2min , &
+ fr_dFe , k_nitrif , &
+ t_iron_conv , max_loss , &
+ max_dfe_doc1 , fr_resp_s , &
+ y_sk_DMS , t_sk_conv , &
+ t_sk_ox , R_C2N_DON
use ice_zbgc_shared, only: chlabs, alpha2max_low, beta2max, mu_max, &
grow_Tdep, fr_graze, mort_pre, mort_Tdep, &
- k_exude, K_Nit, K_Am, K_Sil, K_Fe, &
- f_don, kn_bac, f_don_Am, &
+ k_exude, K_Nit, K_Am, K_Sil, K_Fe, &
+ f_don, kn_bac, f_don_Am, &
f_doc, f_exude, k_bac
use ice_colpkg_tracers, only: tr_brine, nt_fbri, &
@@ -1468,13 +1549,14 @@ subroutine algal_dyn (dt, &
n_algae ! number of autotrophic types
real (kind=dbl_kind), intent(in) :: &
- dt , & ! time step
+ dt , & ! time step
T_bot , & ! ice temperature (oC)
fswthru ! average shortwave passing through current ice layer (W/m^2)
real (kind=dbl_kind), intent(inout) :: &
Zoo, & ! N losses from zooplankton/bacteria... (mmol/m^3)
- Nerror ! Change in N after reactions (mmol/m^3)
+ Cerror, & ! Change in C after reactions (mmol/m^3)
+ nitrification ! nitrate produced through nitrification (mmol/m3)
real (kind=dbl_kind), dimension (:), intent(out) :: &
grow_alg,& ! algal growth rate (mmol/m^3/s)
@@ -1485,55 +1567,62 @@ subroutine algal_dyn (dt, &
reactb ! biological reaction terms (mmol/m3)
real (kind=dbl_kind), dimension(:), intent(in) :: &
- ltrcrn ! brine concentrations in layer (mmol/m^3)
+ ltrcrn ! brine concentrations in layer (mmol/m^3)
- logical (kind=log_kind), intent(inout) :: &
- conserve_N
+ logical (kind=log_kind), intent(inout) :: &
+ conserve_C
- logical (kind=log_kind), intent(in) :: &
+ logical (kind=log_kind), intent(in) :: &
dEdd_algae ! .true. chla impact on shortwave computed in dEdd
! local variables
!------------------------------------------------------------------------------------
! 3 possible autotrophs nt_bgc_N(1:3): diatoms, flagellates, phaeocystis
- ! 2 types of dissolved organic carbon nt_bgc_DOC(1:2):
+ ! 2 types of dissolved organic carbon nt_bgc_DOC(1:2):
! polysaccharids, lipids
! 1 DON (proteins)
! 1 particulate iron (nt_bgc_Fe) n_fep
- ! 1 dossp;ved orpm m+fed
- ! Limiting macro/micro nutrients: nt_bgc_Nit -> nitrate, nt_bgc_NH -> ammonium,
- ! nt_bgc_Sil -> silicate, nt_bgc_Fe -> dissolved iron
+ ! 1 dossp;ved orpm m+fed
+ ! Limiting macro/micro nutrients: nt_bgc_Nit -> nitrate, nt_bgc_NH -> ammonium,
+ ! nt_bgc_Sil -> silicate, nt_bgc_Fe -> dissolved iron
! --------------------------------------------------------------------------------------
real (kind=dbl_kind), parameter, dimension(max_algae) :: &
alpha2max_high = (/ 0.25_dbl_kind, 0.25_dbl_kind, 0.25_dbl_kind/) ! light limitation (1/(W/m^2))
+ real (kind=dbl_kind), parameter, dimension(max_algae) :: &
+ graze_exponent = (/ 0.333_dbl_kind, c1, c1/) ! Implicit grazing exponent (Dunneet al. 2005)
+
+ real (kind=dbl_kind), parameter :: &
+ graze_conc = 1.36_dbl_kind ! (mmol N/m^3) converted from Dunne et al 2005
+ ! data fit for phytoplankton (1.9 mmol C/m^3) to
+ ! ice algal N with 20% porosity and C/N = 7
integer (kind=int_kind) :: k, n
real (kind=dbl_kind), dimension(n_algae) :: &
- Nin , & ! algal nitrogen concentration on volume (mmol/m^3)
+ Nin , & ! algal nitrogen concentration on volume (mmol/m^3)
Cin , & ! algal carbon concentration on volume (mmol/m^3)
chlin ! algal chlorophyll concentration on volume (mg/m^3)
real (kind=dbl_kind), dimension(n_doc) :: &
- Docin ! dissolved organic carbon concentration on volume (mmolC/m^3)
+ Docin ! dissolved organic carbon concentration on volume (mmolC/m^3)
real (kind=dbl_kind), dimension(n_dic) :: &
- Dicin ! dissolved inorganic carbon concentration on volume (mmolC/m^3)
+ Dicin ! dissolved inorganic carbon concentration on volume (mmolC/m^3)
real (kind=dbl_kind), dimension(n_don) :: & !proteins
- Donin ! dissolved organic nitrogen concentration on volume (mmolN/m^3)
+ Donin ! dissolved organic nitrogen concentration on volume (mmolN/m^3)
real (kind=dbl_kind), dimension(n_fed) :: & !iron
- Fedin ! dissolved iron concentration on volume (umol/m^3)
+ Fedin ! dissolved iron concentration on volume (umol/m^3)
real (kind=dbl_kind), dimension(n_fep) :: & !iron
- Fepin ! algal nitrogen concentration on volume (umol/m^3)
+ Fepin ! algal nitrogen concentration on volume (umol/m^3)
real (kind=dbl_kind) :: &
- Nitin , & ! nitrate concentration on volume (mmol/m^3)
- Amin , & ! ammonia/um concentration on volume (mmol/m^3)
- Silin , & ! silicon concentration on volume (mmol/m^3)
+ Nitin , & ! nitrate concentration on volume (mmol/m^3)
+ Amin , & ! ammonia/um concentration on volume (mmol/m^3)
+ Silin , & ! silicon concentration on volume (mmol/m^3)
DMSPpin , & ! DMSPp concentration on volume (mmol/m^3)
DMSPdin , & ! DMSPd concentration on volume (mmol/m^3)
DMSin , & ! DMS concentration on volume (mmol/m^3)
@@ -1542,7 +1631,7 @@ subroutine algal_dyn (dt, &
Iavg_loc ! bottom layer attenuated Fswthru (W/m^2)
real (kind=dbl_kind), dimension(n_algae) :: &
- L_lim , & ! overall light limitation
+ L_lim , & ! overall light limitation
Nit_lim , & ! overall nitrate limitation
Am_lim , & ! overall ammonium limitation
N_lim , & ! overall nitrogen species limitation
@@ -1580,7 +1669,7 @@ subroutine algal_dyn (dt, &
fr_graze_p , & ! fraction of N grazed that becomes protein
! (rest is assimilated) < (1-fr_graze_a)
! and fr_graze_a*fr_graze_e becomes ammonia
- fr_mort_p ! fraction of N mortality that becomes protein
+ fr_mort_p ! fraction of N mortality that becomes protein
! < (1-fr_mort2min)
real (kind=dbl_kind), dimension(n_algae) :: &
@@ -1598,6 +1687,10 @@ subroutine algal_dyn (dt, &
DOC_r , & ! net DOC removal (mmol/m^3)
DOC_s ! net DOC sources (mmol/m^3)
+ real (kind=dbl_kind), dimension(n_dic) :: &
+ DIC_r , & ! net DIC removal (mmol/m^3)
+ DIC_s ! net DIC sources (mmol/m^3)
+
real (kind=dbl_kind), dimension(n_don) :: &
DON_r , & ! net DON removal (mmol/m^3)
DON_s ! net DON sources (mmol/m^3)
@@ -1614,7 +1707,8 @@ subroutine algal_dyn (dt, &
rFep ! ratio of particulate Fe to tot Fep
real (kind=dbl_kind) :: &
- dN , & ! change in N (mmol/m^3)
+ dN , & ! change in Nitrogen (mmol N/m^3)
+ dC , & ! change in Carbon (mmol C/m^3)
N_s_p , & ! algal nitrogen photosynthesis (mmol/m^3)
N_r_g , & ! algal nitrogen losses to grazing (mmol/m^3)
N_r_r , & ! algal nitrogen losses to respiration (mmol/m^3)
@@ -1626,7 +1720,7 @@ subroutine algal_dyn (dt, &
Nit_r , & ! net nitrate removal (mmol/m^3)
Am_s_e , & ! ammonium source from excretion (mmol/m^3)
Am_s_r , & ! ammonium source from respiration (mmol/m^3)
- Am_s_mo , & ! ammonium source from mort/remin (mmol/m^3)
+ Am_s_mo , & ! ammonium source from mort/remin (mmol/m^3)
Am_r_p , & ! ammonium uptake by algae (mmol/m^3)
Am_r_n , & ! ammonium removal to nitrification (mmol/m^3)
Am_s , & ! net ammonium sources (mmol/m^3)
@@ -1636,7 +1730,7 @@ subroutine algal_dyn (dt, &
Fe_r_p , & ! iron uptake by algae (nM)
DOC_r_c , & ! net doc removal from bacterial consumption (mmol/m^3)
doc_s_m , & ! protein source due to algal mortality (mmol/m^3)
- doc_s_g ! protein source due to grazing (mmol/m^3)
+ doc_s_g ! protein source due to grazing (mmol/m^3)
real (kind=dbl_kind) :: &
DMSPd_s_r , & ! skl dissolved DMSP from respiration (mmol/m^3)
@@ -1660,12 +1754,12 @@ subroutine algal_dyn (dt, &
character(len=char_len_long) :: &
warning ! warning message
-
+
!-----------------------------------------------------------------------
! Initialize
!-----------------------------------------------------------------------
- conserve_N = .true.
+ conserve_C = .true.
Nin(:) = c0
Cin(:) = c0
chlin(:) = c0
@@ -1680,7 +1774,7 @@ subroutine algal_dyn (dt, &
DMSPpin = c0
DMSPdin = c0
DMSin = c0
- PONin = c0
+ PONin = c0
U_Am_tot = c0
U_Nit_tot = c0
U_Sil_tot = c0
@@ -1691,8 +1785,10 @@ subroutine algal_dyn (dt, &
U_Fe_f(:) = c0
DOC_s(:) = c0
DOC_r(:) = c0
+ DIC_s(:) = c0
+ DIC_r(:) = c0
DOC_r_c = c0
- nitrif = c0
+ nitrif = c0
mort_N = c0
mort_C = c0
graze_N = c0
@@ -1700,15 +1796,15 @@ subroutine algal_dyn (dt, &
exude_C = c0
resp_N = c0
growth_N = c0
- Nit_r = c0
+ Nit_r = c0
Am_s = c0
- Am_r = c0
+ Am_r = c0
Sil_r = c0
Fed_r(:) = c0
Fed_s(:) = c0
Fep_r(:) = c0
Fep_s(:) = c0
- DMSPd_s = c0
+ DMSPd_s = c0
dTemp = min(T_bot-T_max,c0)
Fed_tot = c0
Fed_tot_r = c0
@@ -1718,12 +1814,12 @@ subroutine algal_dyn (dt, &
Fep_tot_r = c0
Fep_tot_s = c0
rFep(:) = c0
-
+
Nitin = ltrcrn(nlt_bgc_Nit)
op_dep = c0
do k = 1, n_algae
Nin(k) = ltrcrn(nlt_bgc_N(k))
- chlin(k) = R_chl2N(k)* Nin(k)
+ chlin(k) = R_chl2N(k)* Nin(k)
op_dep = op_dep + chlabs(k)*chlin(k)
enddo
if (tr_bgc_C) then
@@ -1742,19 +1838,19 @@ subroutine algal_dyn (dt, &
if (tr_bgc_DMS) then
! DMSPpin = ltrcrn(nlt_bgc_DMSPp)
DMSPdin = ltrcrn(nlt_bgc_DMSPd)
- DMSin = ltrcrn(nlt_bgc_DMS)
+ DMSin = ltrcrn(nlt_bgc_DMS)
endif
- if (tr_bgc_PON) PONin = ltrcrn(nlt_bgc_PON)
+ if (tr_bgc_PON) PONin = ltrcrn(nlt_bgc_PON)
if (tr_bgc_DON) then
do k = 1, n_don
DONin(k) = ltrcrn(nlt_bgc_DON(k))
enddo
endif
if (tr_bgc_Fe ) then
- do k = 1, n_fed
+ do k = 1, n_fed
Fedin(k) = ltrcrn(nlt_bgc_Fed(k))
enddo
- do k = 1, n_fep
+ do k = 1, n_fep
Fepin(k) = ltrcrn(nlt_bgc_Fep(k))
enddo
endif
@@ -1793,10 +1889,10 @@ subroutine algal_dyn (dt, &
do k = 1, n_algae
! With light inhibition ! Maybe include light inhibition for diatoms but phaeocystis
- L_lim = (c1 - exp(-alpha2max_low(k)*Iavg_loc)) * exp(-beta2max(k)*Iavg_loc)
+ L_lim = (c1 - exp(-alpha2max_low(k)*Iavg_loc)) * exp(-beta2max(k)*Iavg_loc)
! Without light inhibition
- !L_lim(k) = (c1 - exp(-alpha2max_low(k)*Iavg_loc))
+ !L_lim(k) = (c1 - exp(-alpha2max_low(k)*Iavg_loc))
!-----------------------------------------------------------------------
! Nutrient limitation
@@ -1807,7 +1903,7 @@ subroutine algal_dyn (dt, &
N_lim(k) = Nit_lim(k)
if (tr_bgc_Am) then
Am_lim(k) = Amin/(Amin + K_Am(k))
- N_lim(k) = min(c1, Nit_lim(k) + Am_lim(k))
+ N_lim(k) = min(c1, Nit_lim(k) + Am_lim(k))
endif
Sil_lim(k) = c1
if (tr_bgc_Sil .and. K_Sil(k) > c0) Sil_lim(k) = Silin/(Silin + K_Sil(k))
@@ -1816,13 +1912,13 @@ subroutine algal_dyn (dt, &
! Iron limitation
!-----------------------------------------------------------------------
- Fe_lim(k) = c1
+ Fe_lim(k) = c1
if (tr_bgc_Fe .and. K_Fe (k) > c0) Fe_lim (k) = Fed_tot/(Fed_tot + K_Fe(k))
-
+
!----------------------------------------------------------------------------
- ! Growth and uptake computed within the bottom layer
- ! Note here per A93 discussions and MBJ model, salinity is a universal
- ! restriction. Comparison with available column nutrients inserted
+ ! Growth and uptake computed within the bottom layer
+ ! Note here per A93 discussions and MBJ model, salinity is a universal
+ ! restriction. Comparison with available column nutrients inserted
! but in tests had no effect.
! Primary production reverts to SE form, see MBJ below and be careful
!----------------------------------------------------------------------------
@@ -1830,7 +1926,7 @@ subroutine algal_dyn (dt, &
growmax_N(k) = mu_max(k) / secday * exp(grow_Tdep(k) * dTemp)* Nin(k) *fsal
grow_N(k) = min(L_lim(k), N_lim(k), Sil_lim(k), Fe_lim(k)) * growmax_N(k)
potU_Nit(k) = Nit_lim(k)* growmax_N(k)
- potU_Am(k) = Am_lim(k)* growmax_N(k)
+ potU_Am(k) = Am_lim(k)* growmax_N(k)
U_Am(k) = min(grow_N(k), potU_Am(k))
U_Nit(k) = grow_N(k) - U_Am(k)
U_Sil(k) = R_Si2N(k) * grow_N(k)
@@ -1850,8 +1946,8 @@ subroutine algal_dyn (dt, &
if (tr_bgc_Sil) U_Sil_tot = min(U_Sil_tot, max_loss * Silin/dt)
if (tr_bgc_Fe) U_Fe_tot = min(U_Fe_tot, max_loss * Fed_tot/dt)
- U_Nit_tot = min(U_Nit_tot, max_loss * Nitin/dt)
- U_Am_tot = min(U_Am_tot, max_loss * Amin/dt)
+ U_Nit_tot = min(U_Nit_tot, max_loss * Nitin/dt)
+ U_Am_tot = min(U_Am_tot, max_loss * Amin/dt)
do k = 1, n_algae
U_Am(k) = U_Am_f(k)*U_Am_tot
@@ -1875,13 +1971,13 @@ subroutine algal_dyn (dt, &
U_Am(k) = fr_Am(k) * grow_N(k)
U_Sil(k) = R_Si2N(k) * grow_N(k)
U_Fe (k) = R_Fe2N(k) * grow_N(k)
-
+
!-----------------------------------------------------------------------
! Define reaction terms
!-----------------------------------------------------------------------
! Since the framework remains incomplete at this point,
- ! it is assumed as a starting expedient that
+ ! it is assumed as a starting expedient that
! DMSP loss to melting results in 10% conversion to DMS
! which is then given a ten day removal constant.
! Grazing losses are channeled into rough spillage and assimilation
@@ -1889,32 +1985,32 @@ subroutine algal_dyn (dt, &
!--------------------------------------------------------------------
! Algal reaction term
- ! N_react = (grow_N*(c1 - fr_graze-fr_resp) - mort)*dt
+ ! v1: N_react = (grow_N*(c1 - fr_graze-fr_resp) - mort)*dt
+ ! v2: N_react = (grow_N*(c1 - fr_graze * (N/graze_conc)**graze_exp-fr_resp) - mort)*dt
+ ! with maximum grazing less than max_loss * Nin(k)/dt
!--------------------------------------------------------------------
- resp(k) = fr_resp * grow_N(k)
- graze(k) = fr_graze(k) * grow_N(k)
+ resp(k) = fr_resp * grow_N(k)
+ graze(k) = min(max_loss * Nin(k)/dt, grow_N(k) * fr_graze(k) * (Nin(k)/graze_conc)**graze_exponent(k))
mort(k) = min(max_loss * Nin(k)/dt, mort_pre(k)* exp(mort_Tdep(k)*dTemp) * Nin(k) / secday)
-
+
! history variables
grow_alg(k) = grow_N(k)
upNOn(k) = U_Nit(k)
upNHn(k) = U_Am(k)
- N_s_p = grow_N(k) * dt
- N_r_g = graze(k) * dt
+ N_s_p = grow_N(k) * dt
+ N_r_g = graze(k) * dt
N_r_r = resp(k) * dt
N_r_mo = mort(k) * dt
- N_s(k) = (c1- fr_resp - fr_graze(k)) * grow_N(k) *dt !N_s_p
- N_r(k) = mort(k) * dt !N_r_g + N_r_mo + N_r_r
-
+ N_s(k) = N_s_p !(c1- fr_resp - fr_graze(k)) * grow_N(k) *dt
+ N_r(k) = N_r_g + N_r_mo + N_r_r !mort(k) * dt
graze_N = graze_N + graze(k)
graze_C = graze_C + R_C2N(k)*graze(k)
- mort_N = mort_N + mort(k)
+ mort_N = mort_N + mort(k)
mort_C = mort_C + R_C2N(k)*mort(k)
resp_N = resp_N + resp(k)
growth_N = growth_N + grow_N(k)
-
enddo ! n_algae
!--------------------------------------------------------------------
! Ammonium source: algal grazing, respiration, and mortality
@@ -1928,35 +2024,36 @@ subroutine algal_dyn (dt, &
!--------------------------------------------------------------------
! Nutrient net loss terms: algal uptake
!--------------------------------------------------------------------
-
+
do k = 1, n_algae
Am_r_p = U_Am(k) * dt
- Am_r = Am_r + Am_r_p
- Nit_r_p = U_Nit(k) * dt
- Nit_r = Nit_r + Nit_r_p
+ Am_r = Am_r + Am_r_p
+ Nit_r_p = U_Nit(k) * dt
+ Nit_r = Nit_r + Nit_r_p
Sil_r_p = U_Sil(k) * dt
- Sil_r = Sil_r + Sil_r_p
+ Sil_r = Sil_r + Sil_r_p
Fe_r_p = U_Fe (k) * dt
- Fed_tot_r = Fed_tot_r + Fe_r_p
- exude_C = exude_C + k_exude(k)* R_C2N(k)*Nin(k) / secday
+ Fed_tot_r = Fed_tot_r + Fe_r_p
+ exude_C = exude_C + k_exude(k)* R_C2N(k)*Nin(k) / secday
+ DIC_r(1) = DIC_r(1) + (c1-fr_resp)*grow_N(k) * R_C2N(k) * dt
enddo
!--------------------------------------------------------------------
! nitrification
!--------------------------------------------------------------------
-
- nitrif = k_nitrif /secday * Amin
+ nitrification = c0
+ nitrif = k_nitrif /secday * Amin
Am_r = Am_r + nitrif*dt
Nit_s_n = nitrif * dt !source from NH4
- Nit_s = Nit_s_n
+ Nit_s = Nit_s_n
!--------------------------------------------------------------------
! PON: currently using PON to shadow nitrate
!
- ! N Losses are counted in Zoo. These arise from mortality not
- ! remineralized (Zoo_s_m), assimilated grazing not excreted (Zoo_s_a),
- !spilled N not going to DON (Zoo_s_s) and bacterial recycling
- ! of DON (Zoo_s_b).
+ ! N Losses are counted in Zoo. These arise from mortality not
+ ! remineralized (Zoo_s_m), assimilated grazing not excreted (Zoo_s_a),
+ !spilled N not going to DON (Zoo_s_s) and bacterial recycling
+ ! of DON (Zoo_s_b).
!--------------------------------------------------------------------
if (tr_bgc_Am) then
@@ -1966,29 +2063,31 @@ subroutine algal_dyn (dt, &
else
Zoo_s_a = graze_N*dt*(c1-fr_graze_s)
Zoo_s_s = graze_N*fr_graze_s*dt
- Zoo_s_m = mort_N*dt
+ Zoo_s_m = mort_N*dt
endif
Zoo_s_b = c0
!--------------------------------------------------------------------
! DON (n_don = 1)
- ! Proteins
+ ! Proteins
!--------------------------------------------------------------------
DON_r(:) = c0
DON_s(:) = c0
if (tr_bgc_DON) then
- do n = 1, n_don
+ do n = 1, n_don
DON_r(n) = kn_bac(n)/secday * DONin(n) * dt
- DON_s(n) = graze_N*f_don(n)*fr_graze_s * dt
+ !DON_s(n) = (c1 - fr_graze_s + fr_graze_e*fr_graze_s)* graze_N * dt !fr_graze_N*f_don(n)*fr_graze_s * dt
+ DON_s(n) = graze_N*dt - Am_s_e + mort_N*dt - Am_s_mo
Zoo_s_s = Zoo_s_s - DON_s(n)
Zoo_s_b = Zoo_s_b + DON_r(n)*(c1-f_don_Am(n))
- !Am_s = Am_s + DON_r(n)*f_don_Am(n)
+ Am_s = Am_s + DON_r(n)*f_don_Am(n)
+ DIC_s(1) = DIC_s(1) + DON_r(n) * R_C2N_DON(n)
enddo
endif
-
+
Zoo = Zoo_s_a + Zoo_s_s + Zoo_s_m + Zoo_s_b
!--------------------------------------------------------------------
@@ -1996,18 +2095,19 @@ subroutine algal_dyn (dt, &
! polysaccharids, lipids
!--------------------------------------------------------------------
- do n = 1, n_doc
-
+ do n = 1, n_doc
DOC_r(n) = k_bac(n)/secday * DOCin(n) * dt
- DOC_s(n) = f_doc(n)*(fr_graze_s *graze_C + mort_C)*dt &
- + f_exude(n)*exude_C
+! DOC_s(n) = f_doc(n)*(fr_graze_s *graze_C + mort_C)*dt &
+! + f_exude(n)*exude_C
+ DOC_s(n) = f_doc(n) * (graze_C*dt + mort_C*dt - DON_s(1) * R_C2N_DON(1))
+ DIC_s(1) = DIC_s(1) + DOC_r(n)
enddo
!--------------------------------------------------------------------
! Iron sources from remineralization (follows ammonium but reduced)
! only Fed_s(1) has remineralized sources
!--------------------------------------------------------------------
-
+
Fed_s(1) = Fed_s(1) + Am_s * R_Fe2N(1) * fr_dFe ! remineralization source
!--------------------------------------------------------------------
@@ -2016,38 +2116,39 @@ subroutine algal_dyn (dt, &
!--------------------------------------------------------------------
if (tr_bgc_C .and. tr_bgc_Fe) then
- if (DOCin(1) > c0) then
- if (Fed_tot/DOCin(1) > max_dfe_doc1) then
- do n = 1,n_fed ! low saccharid:dFe ratio leads to
- Fed_r_l(n) = Fedin(n)/t_iron_conv*dt/secday ! loss of bioavailable Fe to particulate fraction
- Fep_tot_s = Fep_tot_s + Fed_r_l(n)
- Fed_r(n) = Fed_r_l(n) ! removal due to particulate scavenging
- enddo
- do n = 1,n_fep
- Fep_s(n) = rFep(n)* Fep_tot_s ! source from dissolved Fe
- enddo
- elseif (Fed_tot/DOCin(1) < max_dfe_doc1) then
- do n = 1,n_fep ! high saccharid:dFe ratio leads to
+ if (DOCin(1) > c0) then
+ !if (Fed_tot/DOCin(1) > max_dfe_doc1) then
+ ! do n = 1,n_fed ! low saccharid:dFe ratio leads to
+ ! Fed_r_l(n) = Fedin(n)/t_iron_conv*dt/secday ! loss of bioavailable Fe to particulate fraction
+ ! Fep_tot_s = Fep_tot_s + Fed_r_l(n)
+ ! Fed_r(n) = Fed_r_l(n) ! removal due to particulate scavenging
+ ! enddo
+ ! do n = 1,n_fep
+ ! Fep_s(n) = rFep(n)* Fep_tot_s ! source from dissolved Fe
+ ! enddo
+ !elseif (Fed_tot/DOCin(1) < max_dfe_doc1) then
+ if (Fed_tot/DOCin(1) < max_dfe_doc1) then
+ do n = 1,n_fep ! high saccharid:dFe ratio leads to
Fep_r(n) = Fepin(n)/t_iron_conv*dt/secday ! gain of bioavailable Fe from particulate fraction
Fed_tot_s = Fed_tot_s + Fep_r(n)
- enddo
+ enddo
do n = 1,n_fed
Fed_s(n) = Fed_s(n) + rFed(n)* Fed_tot_s ! source from particulate Fe
- enddo
+ enddo
endif
endif !Docin(1) > c0
endif
if (tr_bgc_Fe) then
do n = 1,n_fed
Fed_r(n) = Fed_r(n) + rFed(n)*Fed_tot_r ! scavenging + uptake
- enddo
+ enddo
- ! source from algal mortality/grazing and fraction of remineralized nitrogen that does
+ ! source from algal mortality/grazing and fraction of remineralized nitrogen that does
! not become immediately bioavailable
do n = 1,n_fep
- Fep_s(n) = Fep_s(n) + rFep(n)* (Am_s * R_Fe2N(1) * (c1-fr_dFe))
- enddo ! losses not direct to Fed
+ Fep_s(n) = Fep_s(n) + rFep(n)* (Am_s * R_Fe2N(1) * (c1-fr_dFe))
+ enddo ! losses not direct to Fed
endif
!--------------------------------------------------------------------
@@ -2055,7 +2156,7 @@ subroutine algal_dyn (dt, &
!--------------------------------------------------------------------
! Grazing losses are channeled into rough spillage and assimilation
! then onward and the MBJ mortality channel is included
- ! It is assumed as a starting expedient that
+ ! It is assumed as a starting expedient that
! DMSP loss to melting gives partial conversion to DMS in product layer
! which then undergoes Stefels removal.
@@ -2069,16 +2170,16 @@ subroutine algal_dyn (dt, &
DMSPd_s_r = fr_resp_s * R_S2N(k) * resp(k) * dt !respiration fraction to DMSPd
DMSPd_s_mo= fr_mort2min * R_S2N(k)* mort(k) * dt !mortality and extracellular excretion
- DMSPd_s = DMSPd_s + DMSPd_s_r + DMSPd_s_mo
+ DMSPd_s = DMSPd_s + DMSPd_s_r + DMSPd_s_mo
enddo
DMSPd_r = (c1/t_sk_conv) * (c1/secday) * (DMSPdin) * dt
!--------------------------------------------------------------------
- ! DMS reaction term + DMSPd loss term
+ ! DMS reaction term + DMSPd loss term
! DMS_react = ([\DMSPd]*y_sk_DMS/t_sk_conv - c1/t_sk_ox *[\DMS])*dt
!--------------------------------------------------------------------
- DMS_s_c = y_sk_DMS * DMSPd_r
+ DMS_s_c = y_sk_DMS * DMSPd_r
DMS_r_o = DMSin * dt / (t_sk_ox * secday)
DMS_s = DMS_s_c
DMS_r = DMS_r_o
@@ -2088,19 +2189,27 @@ subroutine algal_dyn (dt, &
!-----------------------------------------------------------------------
dN = c0
+ dC = c0
do k = 1,n_algae
reactb(nlt_bgc_N(k)) = N_s(k) - N_r(k)
dN = dN + reactb(nlt_bgc_N(k))
+ dC = dC + reactb(nlt_bgc_N(k)) * R_C2N(k)
enddo
if (tr_bgc_C) then
! do k = 1,n_algae
! reactb(nlt_bgc_C(k)) = R_C2N(k)*reactb(nlt_bgc_N(k))
! enddo
do k = 1,n_doc
- reactb(nlt_bgc_DOC(k))= DOC_s(k) - DOC_r(k)
+ reactb(nlt_bgc_DOC(k))= DOC_s(k) - DOC_r(k)
+ dC = dC + reactb(nlt_bgc_DOC(k))
+ enddo
+ do k = 1,n_dic
+ reactb(nlt_bgc_DIC(k))= DIC_s(k) - DIC_r(k)
+ dC = dC + reactb(nlt_bgc_DIC(k))
enddo
endif
reactb(nlt_bgc_Nit) = Nit_s - Nit_r
+ nitrification = Nit_s_n
dN = dN + reactb(nlt_bgc_Nit)
if (tr_bgc_Am) then
reactb(nlt_bgc_Am) = Am_s - Am_r
@@ -2111,42 +2220,92 @@ subroutine algal_dyn (dt, &
endif
if (tr_bgc_DON) then
do k = 1,n_don
- reactb(nlt_bgc_DON(k))= DON_s(k) - DON_r(k)
+ reactb(nlt_bgc_DON(k))= DON_s(k) - DON_r(k)
dN = dN + reactb(nlt_bgc_DON(k))
+ dC = dC + reactb(nlt_bgc_DON(k)) * R_C2N_DON(k)
enddo
- endif
+ endif
+ Cerror = dC
if (tr_bgc_Fe ) then
do k = 1,n_fed
- reactb(nlt_bgc_Fed(k))= Fed_s (k) - Fed_r (k)
+ reactb(nlt_bgc_Fed(k))= Fed_s (k) - Fed_r (k)
enddo
do k = 1,n_fep
- reactb(nlt_bgc_Fep(k))= Fep_s (k) - Fep_r (k)
+ reactb(nlt_bgc_Fep(k))= Fep_s (k) - Fep_r (k)
enddo
- endif
+ endif
if (tr_bgc_DMS) then
reactb(nlt_bgc_DMSPd) = DMSPd_s - DMSPd_r
reactb(nlt_bgc_DMS) = DMS_s - DMS_r
endif
- Nerror = dN + Zoo
- ! if (abs(Nerror) > max(reactb(:))*1.0e-5) then
- ! conserve_N = .false.
- ! write(warning, *) 'Conservation error!'
- ! call add_warning(warning)
- ! write(warning, *) 'Nerror,dN, DONin(1),kn_bac(1),secday,dt,n_doc'
- ! call add_warning(warning)
- ! write(warning, *) Nerror,dN, DONin(1),kn_bac(1),secday,dt,n_doc
- ! call add_warning(warning)
- ! write(warning, *) 'reactb(nlt_bgc_Nit),reactb(nlt_bgc_N(1)),reactb(nlt_bgc_N(2)'
- ! call add_warning(warning)
- ! write(warning, *) reactb(nlt_bgc_Nit),reactb(nlt_bgc_N(1)),reactb(nlt_bgc_N(2))
- ! call add_warning(warning)
- ! write(warning, *) 'reactb(nlt_bgc_Am),reactb(nlt_bgc_DON(1)), DON_r(1),DON_s(1)'
- ! call add_warning(warning)
- ! write(warning, *) reactb(nlt_bgc_Am),reactb(nlt_bgc_DON(1)),DON_r(1),DON_s(1)
- ! call add_warning(warning)
- ! write(warning, *) 'Zoo:',Zoo
- ! endif
-
+ if (tr_bgc_C) then
+ if (abs(dC) > maxval(abs(reactb(:)))*1.0e-13_dbl_kind .or. &
+ abs(dN) > maxval(abs(reactb(:)))*1.0e-13_dbl_kind) then
+ conserve_C = .false.
+ write(warning, *) 'Conservation error!'
+ call add_warning(warning)
+ if (tr_bgc_DON) then
+ write(warning, *) 'dN,DONin(1), kn_bac(1),secday,dt,n_doc'
+ call add_warning(warning)
+ write(warning, *) dN, DONin(1),kn_bac(1),secday,dt,n_doc
+ call add_warning(warning)
+ write(warning, *) 'reactb(nlt_bgc_DON(1)), DON_r(1),DON_s(1)'
+ call add_warning(warning)
+ write(warning, *) reactb(nlt_bgc_DON(1)),DON_r(1),DON_s(1)
+ call add_warning(warning)
+ end if
+ write(warning, *) 'dN,secday,dt,n_doc'
+ call add_warning(warning)
+ write(warning, *) dN,secday,dt,n_doc
+ call add_warning(warning)
+ write(warning, *) 'reactb(nlt_bgc_Nit),reactb(nlt_bgc_N(1)),reactb(nlt_bgc_N(2)'
+ call add_warning(warning)
+ write(warning, *) reactb(nlt_bgc_Nit),reactb(nlt_bgc_N(1)),reactb(nlt_bgc_N(2))
+ call add_warning(warning)
+ if (tr_bgc_Am) then
+ write(warning, *) 'reactb(nlt_bgc_Am),Am_r, Am_s'
+ call add_warning(warning)
+ write(warning, *) reactb(nlt_bgc_Am),Am_r, Am_s
+ call add_warning(warning)
+ end if
+ write(warning, *) 'dC'
+ call add_warning(warning)
+ write(warning, *) dC
+ call add_warning(warning)
+ do k = 1,n_doc
+ write(warning, *) 'DOCin'
+ call add_warning(warning)
+ write(warning, *) DOCin(k)
+ call add_warning(warning)
+ write(warning, *) 'reactb(nlt_bgc_DOC)'
+ call add_warning(warning)
+ write(warning, *) reactb(nlt_bgc_DOC(k))
+ call add_warning(warning)
+ write(warning, *) 'DOC_r,DOC_s'
+ call add_warning(warning)
+ write(warning, *) DOC_r(k),DOC_s(k)
+ end do
+ do k = 1,n_dic
+ write(warning, *) 'DICin'
+ call add_warning(warning)
+ write(warning, *) DICin(k)
+ call add_warning(warning)
+ write(warning, *) 'reactb(nlt_bgc_DIC)'
+ call add_warning(warning)
+ write(warning, *) reactb(nlt_bgc_DIC(k))
+ call add_warning(warning)
+ write(warning, *) 'DIC_r,DIC_s'
+ call add_warning(warning)
+ write(warning, *) DIC_r(k),DIC_s(k)
+ end do
+ call add_warning(warning)
+ write(warning, *) 'Zoo'
+ call add_warning(warning)
+ write(warning, *) Zoo
+ call add_warning(warning)
+ endif
+ endif
+
end subroutine algal_dyn
!=======================================================================
@@ -2618,7 +2777,7 @@ subroutine check_conservation_FCT &
(C_init, C_new, C_low, S_top, &
S_bot, L_bot, L_top, dt, &
fluxbio, l_stop, nblyr, &
- source)
+ source)
use ice_constants_colpkg, only: p5, c1, c4, c0
@@ -2637,13 +2796,13 @@ subroutine check_conservation_FCT &
S_bot , & ! bottom flux into ice (mmol/m^2/s)
L_bot , & ! remaining bottom flux into ice (mmol/m^2/s)
L_top , & ! remaining top flux into ice (mmol/m^2/s)
- dt , &
+ dt , &
source ! nutrient source from snow and atmosphere (mmol/m^2)
real (kind=dbl_kind), intent(inout) :: &
fluxbio ! (mmol/m^2/s) positive down (into the ocean)
- logical (kind=log_kind), intent(inout) :: &
+ logical (kind=log_kind), intent(inout) :: &
l_stop ! false if conservation satisfied within error
! local variables
@@ -2660,13 +2819,13 @@ subroutine check_conservation_FCT &
character(len=char_len_long) :: &
warning ! warning message
-
+
zspace = c1/real(nblyr,kind=dbl_kind)
l_stop = .false.
!-------------------------------------
! Ocean flux: positive into the ocean
- !-------------------------------------
+ !-------------------------------------
C_init_tot = (C_init(1) + C_init(nblyr+1))*zspace*p5
C_new_tot = (C_new(1) + C_new(nblyr+1))*zspace*p5
C_low(1) = C_new(1)
@@ -2678,35 +2837,51 @@ subroutine check_conservation_FCT &
C_low(k) = C_new(k)
enddo
- accuracy = 1.0e-14_dbl_kind*max(c1, C_init_tot, C_new_tot)
+ accuracy = 1.0e-14_dbl_kind*max(c1, C_init_tot, C_new_tot)
fluxbio = (C_init_tot - C_new_tot + source)/dt
diff_dt =C_new_tot - C_init_tot - (S_top+S_bot+L_bot*C_new(nblyr+1)+L_top*C_new(1))*dt
- if (minval(C_low) < c0) then
+ if (minval(C_low) < c0) then
write(warning,*) 'Positivity of zbgc low order solution failed: C_low:',C_low
+ call add_warning(warning)
l_stop = .true.
endif
-
+
if (abs(diff_dt) > accuracy ) then
!l_stop = .true.
write(warning,*) 'Conservation of zbgc low order solution failed: diff_dt:',&
diff_dt
+ call add_warning(warning)
write(warning,*) 'Total initial tracer', C_init_tot
+ call add_warning(warning)
write(warning,*) 'Total final1 tracer', C_new_tot
+ call add_warning(warning)
write(warning,*) 'bottom final tracer', C_new(nblyr+1)
+ call add_warning(warning)
write(warning,*) 'top final tracer', C_new(1)
+ call add_warning(warning)
write(warning,*) 'Near bottom final tracer', C_new(nblyr)
+ call add_warning(warning)
write(warning,*) 'Near top final tracer', C_new(2)
+ call add_warning(warning)
write(warning,*) 'Top flux*dt into ice:', S_top*dt
+ call add_warning(warning)
write(warning,*) 'Bottom flux*dt into ice:', S_bot*dt
+ call add_warning(warning)
write(warning,*) 'Remaining bot flux*dt into ice:', L_bot*C_new(nblyr+1)*dt
+ call add_warning(warning)
write(warning,*) 'S_bot*dt + L_bot*C_new(nblyr+1)*dt'
+ call add_warning(warning)
write(warning,*) S_bot*dt + L_bot*C_new(nblyr+1)*dt
+ call add_warning(warning)
write(warning,*) 'fluxbio*dt:', fluxbio*dt
+ call add_warning(warning)
write(warning,*) 'fluxbio:', fluxbio
+ call add_warning(warning)
write(warning,*) 'Remaining top flux*dt into ice:', L_top*C_new(1)*dt
+ call add_warning(warning)
endif
-
+
end subroutine check_conservation_FCT
!=======================================================================
@@ -2717,7 +2892,7 @@ end subroutine check_conservation_FCT
subroutine bgc_column_sum (nblyr, nslyr, hsnow, hbrine, xin, xout)
- use ice_colpkg_shared, only: hs_ssl
+ use ice_colpkg_shared, only: hs_ssl
use ice_constants_colpkg, only: p5, c1, c0
integer (kind=int_kind), intent(in) :: &
@@ -2729,7 +2904,7 @@ subroutine bgc_column_sum (nblyr, nslyr, hsnow, hbrine, xin, xout)
real (kind=dbl_kind), intent(in) :: &
hsnow, & ! snow thickness
- hbrine ! brine height
+ hbrine ! brine height
real (kind=dbl_kind), intent(out) :: &
xout ! output field
@@ -2748,7 +2923,7 @@ subroutine bgc_column_sum (nblyr, nslyr, hsnow, hbrine, xin, xout)
hslyr = hsnow/real(nslyr,kind=dbl_kind)
dzssl = min(hslyr*p5, hs_ssl)
dzint = max(c0,hsnow - dzssl)
- zspace = c1/real(nblyr,kind=dbl_kind)
+ zspace = c1/real(nblyr,kind=dbl_kind)
xout = c0
xout = (xin(1) + xin(nblyr+1))*hbrine*p5*zspace
@@ -2759,6 +2934,153 @@ subroutine bgc_column_sum (nblyr, nslyr, hsnow, hbrine, xin, xout)
end subroutine bgc_column_sum
+!=======================================================================
+
+! Find the total carbon concentration by summing the appropriate
+! biogeochemical tracers in units of mmol C/m2
+!
+! author: Nicole Jeffery, LANL
+
+ subroutine bgc_carbon_sum (nblyr, hbrine, xin, xout, n_doc, n_dic, n_algae, n_don)
+
+ use ice_colpkg_shared, only: hs_ssl, R_C2N, R_C2N_DON
+ use ice_constants_colpkg, only: p5, c1, c0
+ use ice_colpkg_tracers, only: tr_bgc_N, tr_bgc_C, tr_bgc_hum, &
+ tr_bgc_DON, nt_bgc_hum, nt_bgc_N, nt_bgc_DOC, nt_bgc_DIC, nt_bgc_DON
+
+ integer (kind=int_kind), intent(in) :: &
+ nblyr, & ! number of ice layers
+ n_doc, n_dic, n_algae, n_don
+
+ real (kind=dbl_kind), dimension(:), intent(in) :: &
+ xin ! input field, all tracers and column
+
+ real (kind=dbl_kind), intent(in) :: &
+ hbrine ! brine height
+
+ real (kind=dbl_kind), intent(out) :: &
+ xout ! output field mmol/m2 carbon
+
+ ! local variables
+
+ real (kind=dbl_kind), dimension(nblyr+1) :: &
+ zspace ! brine layer thickness/hbrine
+
+ integer (kind=int_kind) :: &
+ n, m, iBioCount, iLayer, nBGC ! category/layer index
+
+ zspace(:) = c1/real(nblyr,kind=dbl_kind)
+ zspace(1) = p5*zspace(1)
+ zspace(nblyr+1) = zspace(1)
+
+ xout = c0
+
+ if (tr_bgc_N) then
+ iBioCount = c0
+ do m = 1, n_algae
+ nBGC = nt_bgc_N(1)
+ do n = 1, nblyr+1
+ iLayer = iBioCount + n-1
+ xout = xout + xin(nBGC+iLayer)*zspace(n)*hbrine*R_C2N(m)
+ enddo
+ iBioCount = iBioCount + nblyr+3
+ enddo
+ endif
+ if (tr_bgc_C) then
+ iBioCount = c0
+ nBGC = nt_bgc_DOC(1)
+ do m = 1, n_doc
+ do n = 1, nblyr+1
+ iLayer = iBioCount + n-1
+ xout = xout + xin(nBGC+iLayer)*zspace(n)*hbrine
+ enddo
+ iBioCount = iBioCount + nblyr+3
+ enddo
+ do m = 1, n_dic
+ do n = 1, nblyr+1
+ iLayer = iBioCount + n-1
+ xout = xout + xin(nBGC+iLayer)*zspace(n)*hbrine
+ enddo
+ iBioCount = iBioCount + nblyr+3
+ enddo
+ endif
+
+ if (tr_bgc_DON) then
+ iBioCount = c0
+ do m = 1, n_don
+ nBGC = nt_bgc_DON(1)
+ do n = 1, nblyr+1
+ iLayer = iBioCount + n-1
+ xout = xout + xin(nBGC+iLayer)*zspace(n)*hbrine*R_C2N_DON(m)
+ enddo
+ iBioCount = iBioCount + nblyr+3
+ enddo
+ endif
+ if (tr_bgc_hum) then
+ nBGC = nt_bgc_hum
+ do n = 1, nblyr+1
+ iLayer = n-1
+ xout = xout + xin(nBGC+iLayer)*zspace(n)*hbrine
+ enddo
+ endif
+
+ end subroutine bgc_carbon_sum
+
+!=======================================================================
+
+! Find the total carbon flux by summing the fluxes for the appropriate
+! biogeochemical each grid cell, sum field over all ice and snow layers
+!
+! author: Nicole Jeffery, LANL
+
+ subroutine bgc_carbon_flux (flux_bio_atm, flux_bion, n_doc, &
+ n_dic, n_algae, n_don, Tot_Carbon_flux)
+
+ use ice_colpkg_shared, only: R_C2N, R_C2N_DON
+ use ice_constants_colpkg, only: c0
+ use ice_colpkg_tracers, only: tr_bgc_N, tr_bgc_C, tr_bgc_hum, &
+ tr_bgc_DON, nlt_bgc_hum, nlt_bgc_N, nlt_bgc_C, nlt_bgc_DOC, &
+ nlt_bgc_DIC, nlt_bgc_DON
+
+ integer (kind=int_kind), intent(in) :: &
+ n_doc, n_dic, n_algae, n_don
+
+ real (kind=dbl_kind), dimension(:), intent(in) :: &
+ flux_bio_atm, & ! input field, all tracers and column
+ flux_bion
+
+ real (kind=dbl_kind), intent(out) :: &
+ Tot_Carbon_flux ! output field mmol/m2/s carbon
+
+ ! local variables
+ integer (kind=int_kind) :: &
+ m ! biology index
+
+ Tot_Carbon_flux = c0
+
+ if (tr_bgc_N) then
+ do m = 1, n_algae
+ Tot_Carbon_flux = Tot_Carbon_flux - (flux_bio_atm(nlt_bgc_N(m)) - flux_bion(nlt_bgc_N(m)))*R_C2N(m)
+ enddo
+ endif
+ if (tr_bgc_C) then
+ do m = 1, n_doc
+ Tot_Carbon_flux = Tot_Carbon_flux - flux_bio_atm(nlt_bgc_DOC(m)) + flux_bion(nlt_bgc_DOC(m))
+ enddo
+ do m = 1, n_dic
+ Tot_Carbon_flux = Tot_Carbon_flux - flux_bio_atm(nlt_bgc_DIC(m)) + flux_bion(nlt_bgc_DIC(m))
+ enddo
+ endif
+ if (tr_bgc_DON) then
+ do m = 1, n_don
+ Tot_Carbon_flux = Tot_Carbon_flux - (flux_bio_atm(nlt_bgc_DON(m)) - flux_bion(nlt_bgc_DON(m)))*R_C2N_DON(m)
+ enddo
+ endif
+ if (tr_bgc_hum) &
+ Tot_Carbon_flux = Tot_Carbon_flux - flux_bio_atm(nlt_bgc_hum) + flux_bion(nlt_bgc_hum)
+
+ end subroutine bgc_carbon_flux
+
!=======================================================================
end module ice_algae
diff --git a/src/core_seaice/column/ice_atmo.F90 b/src/core_seaice/column/ice_atmo.F90
index c5cd8c95a0..e1a1d4bd86 100644
--- a/src/core_seaice/column/ice_atmo.F90
+++ b/src/core_seaice/column/ice_atmo.F90
@@ -129,6 +129,7 @@ subroutine atmo_boundary_layer (sfctype, &
real (kind=dbl_kind) :: &
ustar , & ! ustar (m/s)
+ ustar_prev , & ! ustar_prev (m/s)
tstar , & ! tstar
qstar , & ! qstar
rdn , & ! sqrt of neutral exchange coefficient (momentum)
@@ -256,7 +257,13 @@ subroutine atmo_boundary_layer (sfctype, &
! iterate to converge on Z/L, ustar, tstar and qstar
!------------------------------------------------------------
- do k = 1, natmiter
+ ustar_prev = c2 * ustar
+
+ k = 0
+ do while (abs(ustar - ustar_prev)/ustar > 0 .and. k <= natmiter)
+
+ ustar_prev = ustar
+ k = k + 1
! compute stability & evaluate all stability functions
hol = vonkar * gravit * zlvl &
diff --git a/src/core_seaice/column/ice_brine.F90 b/src/core_seaice/column/ice_brine.F90
index 25d0b9a4ac..442aa45ca7 100644
--- a/src/core_seaice/column/ice_brine.F90
+++ b/src/core_seaice/column/ice_brine.F90
@@ -50,10 +50,10 @@ subroutine preflushing_changes (n_cat, &
fbri, dhbr_top, dhbr_bot, &
hbr_old, hin,hsn, firstice, &
l_stop, stop_label)
-
+
integer (kind=int_kind), intent(in) :: &
n_cat ! category
-
+
real (kind=dbl_kind), intent(in) :: &
aicen , & ! concentration of ice
vicen , & ! volume per unit area of ice (m)
@@ -61,10 +61,11 @@ subroutine preflushing_changes (n_cat, &
meltb , & ! bottom ice melt (m)
meltt , & ! top ice melt (m)
congel , & ! bottom ice growth (m)
- snoice ! top ice growth from flooding (m)
-
+ snoice , & ! top ice growth from flooding (m)
+ hice_old ! old ice thickness (m)
+
real (kind=dbl_kind), intent(out) :: &
- hbr_old ! old brine height (m)
+ hbr_old ! old brine height (m)
real (kind=dbl_kind), intent(inout) :: &
hin , & ! ice thickness (m)
@@ -74,8 +75,7 @@ subroutine preflushing_changes (n_cat, &
real (kind=dbl_kind), intent(inout) :: &
fbri , & ! trcrn(nt_fbri)
dhbr_top , & ! brine change in top for diagnostics (m)
- dhbr_bot , & ! brine change in bottom for diagnostics (m)
- hice_old ! old ice thickness (m)
+ dhbr_bot
logical (kind=log_kind), intent(in) :: &
firstice ! if true, initialized values should be used
@@ -98,29 +98,32 @@ subroutine preflushing_changes (n_cat, &
!-----------------------------------------------------------------
l_stop = .false.
- if (fbri <= c0) then
+ if (fbri < c0) then
write(warning, *) 'fbri, hice_old', fbri, hice_old
call add_warning(warning)
write(warning, *) 'vicen, aicen', vicen, aicen
- call add_warning(warning)
+ call add_warning(warning)
l_stop = .true.
stop_label = 'ice_brine preflushing: fbri <= c0'
endif
-
- hin = vicen / aicen
- hsn = vsnon / aicen
+ hin = c0
+ hsn = c0
+ if (aicen > puny) then
+ hin = vicen / aicen
+ hsn = vsnon / aicen
+ endif
hin_old = max(c0, hin + meltb + meltt - congel - snoice)
dhice = hin_old - hice_old ! change due to subl/cond
- dhbr_top = meltt - snoice - dhice
+ dhbr_top = meltt - snoice - dhice
dhbr_bot = congel - meltb
- if ((hice_old < puny) .OR. (hin_old < puny) .OR. firstice) then
- hice_old = hin
- dhbr_top = c0
- dhbr_bot = c0
- dhice = c0
- fbri = c1
- endif
+ !if ((hice_old < puny) .OR. (hin_old < puny) ) then !.OR. firstice) then
+ ! hice_old = hin
+ ! dhbr_top = c0
+ ! dhbr_bot = c0
+ ! dhice = c0
+ ! fbri = c1
+ !endif
hbr_old = fbri * hice_old
@@ -177,7 +180,7 @@ subroutine compute_microS_mushy (n_cat, nilyr, nblyr, &
kperm , & ! average ice permeability (m^2)
bphi_min ! surface porosity
- real (kind=dbl_kind), intent(inout) :: &
+ real (kind=dbl_kind), intent(in) :: &
hbr_old ! previous timestep brine height (m)
real (kind=dbl_kind), dimension (nblyr+1), &
@@ -256,7 +259,6 @@ subroutine compute_microS_mushy (n_cat, nilyr, nblyr, &
! map Sin and qin (cice) profiles to bgc grid
surface_S = min_salin
- hbr_old = min(hbr_old, maxhbr*hice_old)
hinc_old = hice_old
hbrc_old = hbr_old
@@ -447,15 +449,15 @@ end subroutine prepare_hbrine
!=======================================================================
-! Changes include brine height increases from ice and snow surface melt,
+! Changes include brine height increases from ice and snow surface melt,
! congelation growth, and upward pressure driven flow from snow loading.
-!
-! Decreases arise from downward flushing and bottom melt.
!
-! NOTE: In this subroutine, trcrn(nt_fbri) is the volume fraction of ice
-! with dynamic salinity or the height ratio == hbr/vicen*aicen, where
-! hbr is the height of the brine surface relative to the bottom of the
-! ice. This volume fraction may be > 1 in which case there is brine
+! Decreases arise from downward flushing and bottom melt.
+!
+! NOTE: In this subroutine, trcrn(nt_fbri) is the volume fraction of ice
+! with dynamic salinity or the height ratio == hbr/vicen*aicen, where
+! hbr is the height of the brine surface relative to the bottom of the
+! ice. This volume fraction may be > 1 in which case there is brine
! above the ice surface (ponds).
subroutine update_hbrine (meltb, meltt, &
@@ -475,7 +477,7 @@ subroutine update_hbrine (meltb, meltt, &
real (kind=dbl_kind), intent(in) :: &
dt ! timestep
-
+
real (kind=dbl_kind), intent(in):: &
meltb, & ! bottom melt over dt (m)
meltt, & ! true top melt over dt (m)
@@ -485,29 +487,29 @@ subroutine update_hbrine (meltb, meltt, &
hin_old, & ! past timestep ice thickness (m)
hbr_old, & ! previous timestep hbr
phi_snow, & ! porosity of snow
- kperm, & ! avg ice permeability
- bphin, & ! upper brine porosity
+ kperm, & ! avg ice permeability
+ bphin, & ! upper brine porosity
snoice, & ! snoice change (m)
dhS_bottom, & ! change in bottom hbr initially before darcy flow
aice0 ! open water area fraction
real (kind=dbl_kind), intent(inout):: &
darcy_V , & ! Darcy velocity: m/s
- darcy_V_chl, & ! Darcy velocity: m/s for bgc
+ darcy_V_chl, & ! Darcy velocity: m/s for bgc
dhS_top , & ! change in top hbr before darcy flow
- dh_bot_chl , & ! change in bottom for algae
- dh_top_chl , & ! change in bottom for algae
- hbr , & ! thickness of brine (m)
- fbri , & ! brine height ratio tracer (hbr/hin)
- bphi_min ! surface porosity
+ dh_bot_chl , & ! change in bottom for algae
+ dh_top_chl , & ! change in bottom for algae
+ hbr , & ! thickness of brine (m)
+ fbri , & ! brine height ratio tracer (hbr/hin)
+ bphi_min ! surface porosity
real (kind=dbl_kind), intent(out):: &
dh_direct ! surface flooding or runoff (m)
-
+
! local variables
- real (kind=dbl_kind) :: &
- hbrmin , & ! thinS or hin
+ real (kind=dbl_kind) :: &
+ hbrmin , & ! thinS or hin
dhbr_hin , & ! hbr-hin
hbrocn , & ! brine height above sea level (m) hbr-h_ocn
dhbr , & ! change in brine surface
@@ -520,61 +522,61 @@ subroutine update_hbrine (meltb, meltt, &
real (kind=dbl_kind), parameter :: &
dh_min = p001 ! brine remains within dh_min of sea level
! when ice thickness is less than thinS
-
+
hbrocn = c0
darcy_V = c0
- darcy_V_chl = c0
+ darcy_V_chl = c0
hbrocn_new = c0
- h_ocn = rhosi/rhow*hin + rhos/rhow*hsn
+ h_ocn = rhosi/rhow*hin + rhos/rhow*hsn
dh_direct = c0
-
+
if (hbr_old > thinS .AND. hin_old > thinS .AND. hin > thinS ) then
hbrmin = thinS
- dhS_top = -max(c0, min(hin_old-hbr_old, meltt)) * rhoi/rhow
+ dhS_top = -max(c0, min(hin_old-hbr_old, meltt)) * rhoi/rhow
dhS_top = dhS_top - max(c0, melts) * rhos/rhow
dh_top_chl = dhS_top
- dhbr = dhS_bottom - dhS_top
- hbr = max(puny, hbr_old+dhbr)
+ dhbr = dhS_bottom - dhS_top
+ hbr = max(puny, hbr_old+dhbr)
hbrocn = hbr - h_ocn
darcy_coeff = max(c0, kperm*gravit/(viscos*hbr_old))
- if (hbrocn > c0 .AND. hbr > thinS ) then
- bphi_min = bphin
+ if (hbrocn > c0 .AND. hbr > thinS ) then
+ bphi_min = bphin
dhrunoff = -dhS_top*aice0
hbrocn = max(c0,hbrocn - dhrunoff)
hbrocn_new = hbrocn*exp(-darcy_coeff/bphi_min*dt)
hbr = max(hbrmin, h_ocn + hbrocn_new)
hbrocn_new = hbr-h_ocn
darcy_V = -SIGN((hbrocn-hbrocn_new)/dt*bphi_min, hbrocn)
- darcy_V_chl= darcy_V
+ darcy_V_chl= darcy_V
dhS_top = dhS_top - darcy_V*dt/bphi_min + dhrunoff
dh_top_chl = dh_top_chl - darcy_V_chl*dt/bphi_min + dhrunoff
dh_direct = dhrunoff
elseif (hbrocn < c0 .AND. hbr > thinS) then
hbrocn_new = hbrocn*exp(-darcy_coeff/bphi_min*dt)
- dhflood = max(c0,hbrocn_new - hbrocn)*aice0
+ dhflood = max(c0,hbrocn_new - hbrocn)*aice0
hbr = max(hbrmin, h_ocn + hbrocn_new)
darcy_V = -SIGN((hbrocn-hbrocn_new + dhflood)/dt*bphi_min, hbrocn)
- darcy_V_chl= darcy_V
+ darcy_V_chl= darcy_V
dhS_top = dhS_top - darcy_V*dt/bphi_min - dhflood
dh_top_chl = dh_top_chl - darcy_V_chl*dt/bphi_min - dhflood
dh_direct = -dhflood
endif
-
- dh_bot_chl = dhS_bottom
-
- else ! very thin brine height
+
+ dh_bot_chl = dhS_bottom
+
+ else ! very thin brine height
hbrmin = min(thinS, hin)
hbr = max(hbrmin, hbr_old+dhS_bottom-dhS_top)
dhbr_hin = hbr - h_ocn
if (abs(dhbr_hin) > dh_min) &
- hbr = max(hbrmin, h_ocn + SIGN(dh_min,dhbr_hin))
+ hbr = max(hbrmin, h_ocn + SIGN(dh_min,dhbr_hin))
dhS_top = hbr_old - hbr + dhS_bottom
dh_top_chl = dhS_top
dh_bot_chl = dhS_bottom
- endif
-
- fbri = hbr/hin
+ endif
+
+ fbri = hbr/hin
end subroutine update_hbrine
@@ -625,7 +627,7 @@ subroutine compute_microS (n_cat, nilyr, nblyr, &
sst ! ocean temperature (oC)
real (kind=dbl_kind), dimension(ntrcr), intent(inout) :: &
- trcrn
+ trcrn
real (kind=dbl_kind), intent(inout) :: &
hbr_old , & ! old brine height
diff --git a/src/core_seaice/column/ice_colpkg.F90 b/src/core_seaice/column/ice_colpkg.F90
index 2951fb8156..285d439840 100644
--- a/src/core_seaice/column/ice_colpkg.F90
+++ b/src/core_seaice/column/ice_colpkg.F90
@@ -36,6 +36,7 @@ module ice_colpkg
! time stepping
public :: &
+ colpkg_step_snow, &
colpkg_step_therm1, &
colpkg_biogeochemistry, &
colpkg_step_therm2, &
@@ -56,7 +57,9 @@ module ice_colpkg
colpkg_snow_temperature, &
colpkg_liquidus_temperature, &
colpkg_sea_freezing_temperature, &
- colpkg_enthalpy_snow
+ colpkg_enthalpy_ice, &
+ colpkg_enthalpy_snow, &
+ colpkg_salinity_profile
! warning messages
public :: &
@@ -259,6 +262,10 @@ subroutine colpkg_init_itd(ncat, hin_max, l_stop, stop_label)
endif ! kcatbound
+ if (kitd == 1) then
+ hin_max(ncat) = 999.9_dbl_kind ! arbitrary big number
+ endif
+
end subroutine colpkg_init_itd
!=======================================================================
@@ -379,7 +386,31 @@ subroutine colpkg_init_thermo(nilyr, sprofile)
end subroutine colpkg_init_thermo
!=======================================================================
+! Initial salinity profile
+!
+! authors: C. M. Bitz, UW
+! William H. Lipscomb, LANL
+
+ function colpkg_salinity_profile(zn) result(salinity)
+
+ use ice_colpkg_shared, only: saltmax
+ use ice_constants_colpkg, only: c1, c2, pi
+
+ real(kind=dbl_kind), intent(in) :: &
+ zn ! depth
+
+ real(kind=dbl_kind) :: &
+ salinity ! initial salinity profile
+
+ real (kind=dbl_kind), parameter :: &
+ nsal = 0.407_dbl_kind, &
+ msal = 0.573_dbl_kind
+
+ salinity = (saltmax/c2)*(c1-cos(pi*zn**(nsal/(msal+zn))))
+ end function colpkg_salinity_profile
+
+!=======================================================================
! Compute orbital parameters for the specified date.
!
! author: Bruce P. Briegleb, NCAR
@@ -389,10 +420,13 @@ subroutine colpkg_init_orbit(l_stop, stop_label)
use ice_constants_colpkg, only: iyear_AD, eccen, obliqr, lambm0, &
mvelpp, obliq, mvelp, decln, eccf, log_print
-#ifndef CCSMCOUPLED
+#ifdef CCSMCOUPLED
+ use shr_orb_mod, only: shr_orb_params
+#else
use ice_orbital, only: shr_orb_params
#endif
+
logical (kind=log_kind), intent(out) :: &
l_stop ! if true, abort the model
@@ -403,7 +437,10 @@ subroutine colpkg_init_orbit(l_stop, stop_label)
iyear_AD = 1950
log_print = .false. ! if true, write out orbital parameters
-#ifndef CCSMCOUPLED
+#ifdef CCSMCOUPLED
+ call shr_orb_params( iyear_AD, eccen , obliq , mvelp , &
+ obliqr , lambm0, mvelpp, log_print)
+#else
call shr_orb_params( iyear_AD, eccen , obliq , mvelp , &
obliqr , lambm0, mvelpp, log_print, &
l_stop, stop_label)
@@ -741,7 +778,7 @@ subroutine colpkg_init_zbgc (nblyr, nilyr, nslyr, &
f_don_Am_protein ,f_doc_s, f_doc_l, &
f_exude_s, f_exude_l, k_bac_s, k_bac_l, &
algaltype_diatoms, algaltype_sp, algaltype_phaeo, &
- doctype_s, doctype_l, dontype_protein, &
+ doctype_s, doctype_l, dictype_1, dontype_protein, &
fedtype_1, feptype_1, zaerotype_bc1, zaerotype_bc2, &
zaerotype_dust1, zaerotype_dust2, zaerotype_dust3, &
zaerotype_dust4, &
@@ -968,6 +1005,7 @@ subroutine colpkg_init_zbgc (nblyr, nilyr, nslyr, &
humtype , & !
doctype_s , & !
doctype_l , & !
+ dictype_1 , & !
dontype_protein , & !
fedtype_1 , & !
feptype_1 , & !
@@ -1118,7 +1156,7 @@ subroutine colpkg_init_zbgc (nblyr, nilyr, nslyr, &
F_abs_chl(3) = F_abs_chl_phaeo
R_Fe2DON(1) = ratio_Fe2DON
- R_C2N(1) = ratio_C2N_proteins
+ R_C2N_DON(1) = ratio_C2N_proteins
R_Fe2DOC(1) = ratio_Fe2DOC_s
R_Fe2DOC(2) = ratio_Fe2DOC_l
@@ -1176,6 +1214,9 @@ subroutine colpkg_init_zbgc (nblyr, nilyr, nslyr, &
K_Fe(2) = K_Fe_sp
K_Fe(3) = K_Fe_phaeo
+ f_doc(1) = f_doc_s
+ f_doc(2) = f_doc_l
+
f_don(1) = f_don_protein
kn_bac(1) = kn_bac_protein
f_don_Am(1) = f_don_Am_protein
@@ -1192,6 +1233,8 @@ subroutine colpkg_init_zbgc (nblyr, nilyr, nslyr, &
doctype(1) = doctype_s
doctype(2) = doctype_l
+ dictype(1) = dictype_1
+
dontype(1) = dontype_protein
fedtype(1) = fedtype_1
@@ -1622,7 +1665,7 @@ end function colpkg_liquidus_temperature
function colpkg_sea_freezing_temperature(sss) result(Tf)
use ice_colpkg_shared, only: tfrz_option
- use ice_constants_colpkg, only: depressT
+ use ice_constants_colpkg, only: depressT, Tocnfrz
real(dbl_kind), intent(in) :: sss
real(dbl_kind) :: Tf
@@ -1637,7 +1680,7 @@ function colpkg_sea_freezing_temperature(sss) result(Tf)
else
- Tf = -1.8_dbl_kind
+ Tf = Tocnfrz
endif
@@ -1693,6 +1736,33 @@ function colpkg_snow_temperature(qin) result(Tsn)
end function colpkg_snow_temperature
+!=======================================================================
+
+ function colpkg_enthalpy_ice(zTin, zSin) result(qin)
+
+ use ice_colpkg_shared, only: ktherm
+ use ice_mushy_physics, only: enthalpy_mush
+ use ice_constants_colpkg, only: depressT, rhoi, cp_ice, Lfresh, cp_ocn, c1
+
+ real(kind=dbl_kind), intent(in) :: zTin
+ real(kind=dbl_kind), intent(in) :: zSin
+ real(kind=dbl_kind) :: qin
+
+ real(kind=dbl_kind) :: Tmlt
+
+ if (ktherm == 2) then
+
+ qin = enthalpy_mush(zTin, zSin)
+
+ else
+
+ Tmlt = -zSin*depressT
+ qin = -(rhoi * (cp_ice*(Tmlt-zTin) + Lfresh*(c1-Tmlt/zTin) - cp_ocn*Tmlt))
+
+ endif
+
+ end function colpkg_enthalpy_ice
+
!=======================================================================
function colpkg_enthalpy_snow(zTsn) result(qsn)
@@ -1717,6 +1787,7 @@ end function colpkg_enthalpy_snow
! Elizabeth C. Hunke, LANL
subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
+ aice0 , &
aicen_init , &
vicen_init , vsnon_init , &
aice , aicen , &
@@ -1725,10 +1796,12 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
uvel , vvel , &
Tsfc , zqsn , &
zqin , zSin , &
+ smice , smliq , &
alvl , vlvl , &
apnd , hpnd , &
ipnd , &
iage , FY , &
+ rsnw , use_smliq_pnd,&
aerosno , aeroice , &
uatm , vatm , &
wind , zlvl , &
@@ -1753,7 +1826,7 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
fbot , &
frzmlt , rside , &
fsnow , frain , &
- fpond , &
+ fpond , fsloss , &
fsurf , fsurfn , &
fcondtop , fcondtopn , &
fswsfcn , fswintn , &
@@ -1774,6 +1847,7 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
meltb , meltbn , &
meltl , &
melts , meltsn , &
+ meltsliq , meltsliqn , &
congel , congeln , &
snoice , snoicen , &
dsnown , frazil , &
@@ -1785,16 +1859,18 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
use ice_aerosol, only: update_aerosol
use ice_atmo, only: neutral_drag_coeffs
use ice_age, only: increment_age
- use ice_constants_colpkg, only: rhofresh, rhoi, rhos, c0, c1, puny
+ use ice_constants_colpkg, only: rhofresh, rhoi, rhos, c0, c1, puny, &
+ snwlvlfac
use ice_firstyear, only: update_FYarea
use ice_flux_colpkg, only: set_sfcflux, merge_fluxes
use ice_meltpond_cesm, only: compute_ponds_cesm
use ice_meltpond_lvl, only: compute_ponds_lvl
use ice_meltpond_topo, only: compute_ponds_topo
+ use ice_snow, only: drain_snow
use ice_therm_shared, only: hi_min
use ice_therm_vertical, only: frzmlt_bottom_lateral, thermo_vertical
use ice_colpkg_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, &
- tr_pond_cesm, tr_pond_lvl, tr_pond_topo
+ tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow, tr_rsnw
integer (kind=int_kind), intent(in) :: &
ncat , & ! number of thickness categories
@@ -1812,12 +1888,14 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
logical (kind=log_kind), intent(in) :: &
lmask_n , & ! northern hemisphere mask
- lmask_s ! southern hemisphere mask
+ lmask_s , & ! southern hemisphere mask
+ use_smliq_pnd ! if true, use snow liquid tracer for ponds
logical (kind=log_kind), intent(in), optional :: &
prescribed_ice ! if .true., use prescribed ice instead of computed
real (kind=dbl_kind), intent(inout) :: &
+ aice0 , & ! open water fraction
aice , & ! sea ice concentration
vice , & ! volume per unit area of ice (m)
vsno , & ! volume per unit area of snow (m)
@@ -1831,6 +1909,7 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
rhoa , & ! air density (kg/m^3)
frain , & ! rainfall rate (kg/m^2 s)
fsnow , & ! snowfall rate (kg/m^2 s)
+ fsloss , & ! blowing snow loss to leads (kg/m^2/s)
fpond , & ! fresh water flux to ponds (kg/m^2/s)
fresh , & ! fresh water flux to ocean (kg/m^2/s)
fsalt , & ! salt flux to ocean (kg/m^2/s)
@@ -1881,6 +1960,7 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
sss , & ! sea surface salinity (ppt)
meltt , & ! top ice melt (m/step-->cm/day)
melts , & ! snow melt (m/step-->cm/day)
+ meltsliq , & ! snow melt mass (kg/m^2/step-->kg/m^2/day)
meltb , & ! basal ice melt (m/step-->cm/day)
meltl , & ! lateral ice melt (m/step-->cm/day)
mlt_onset , & ! day of year that sfc melting begins
@@ -1917,6 +1997,7 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
dhsn , & ! depth difference for snow on sea ice and pond ice
ffracn , & ! fraction of fsurfn used to melt ipond
meltsn , & ! snow melt (m)
+ meltsliqn , & ! snow melt mass (kg/m^2)
melttn , & ! top ice melt (m)
meltbn , & ! bottom ice melt (m)
congeln , & ! congelation ice growth (m)
@@ -1927,8 +2008,11 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
zqsn , & ! snow layer enthalpy (J m-3)
zqin , & ! ice layer enthalpy (J m-3)
zSin , & ! internal ice layer salinities
+ smice , & ! ice mass tracer in snow (kg/m^3)
+ smliq , & ! liquid water mass tracer in snow (kg/m^3)
Sswabsn , & ! SW radiation absorbed in snow layers (W m-2)
- Iswabsn ! SW radiation absorbed in ice layers (W m-2)
+ Iswabsn , & ! SW radiation absorbed in ice layers (W m-2)
+ rsnw ! snow grain radius (10^-6 m) in snow layers
real (kind=dbl_kind), dimension(:,:,:), intent(inout) :: &
aerosno , & ! snow aerosol tracer (kg/m^2)
@@ -1971,6 +2055,26 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
raice , & ! 1/aice
pond ! water retained in ponds (m)
+ !---------------------------------------------------------------
+ ! Initialize rate of snow loss to leads
+ !---------------------------------------------------------------
+
+ fsloss = fsnow*aice0
+
+ !---------------------------------------------------------------
+ ! 30% rule for snow redistribution: precip factor
+ !---------------------------------------------------------------
+
+ if (trim(snwredist) == '30percent') then
+ worka = c0
+ do n = 1, ncat
+ worka = worka + alvl(n)
+ enddo
+ worka = worka * snwlvlfac/(c1+snwlvlfac)
+ fsloss = fsloss + fsnow*(c1-worka)
+ fsnow = fsnow* worka
+ endif ! snwredist
+
!-----------------------------------------------------------------
! Adjust frzmlt to account for ice-ocean heat fluxes since last
! call to coupler.
@@ -2015,6 +2119,7 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
do n = 1, ncat
meltsn (n) = c0
+ meltsliqn(n) = c0
melttn (n) = c0
meltbn (n) = c0
congeln(n) = c0
@@ -2108,13 +2213,15 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
vicen (n), vsnon (n), &
Tsfc (n), zSin (:,n), &
zqin (:,n), zqsn (:,n), &
- apnd (n), hpnd (n), &
- iage (n), tr_pond_topo, &
+ smice (:,n), smliq (:,n), &
+ tr_snow, apnd (n), &
+ hpnd (n), iage (n), &
+ tr_pond_topo, &
flw, potT, &
Qa, rhoa, &
fsnow, fpond, &
fbot, Tbot, &
- sss, &
+ sss, rsnw (:,n), &
lhcoef, shcoef, &
fswsfcn (n), fswintn (n), &
Sswabsn(:,n), Iswabsn(:,n), &
@@ -2122,12 +2229,13 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
fsensn (n), flatn (n), &
flwoutn, evapn, &
freshn, fsaltn, &
- fhocnn, &
+ fhocnn, frain, &
melttn (n), meltsn (n), &
- meltbn (n), &
+ meltbn (n), meltsliqn(n), &
congeln (n), snoicen (n), &
mlt_onset, frz_onset, &
yday, dsnown (n), &
+ tr_rsnw, &
l_stop, stop_label, &
prescribed_ice)
@@ -2162,6 +2270,18 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
endif ! aicen_init
+ !-----------------------------------------------------------------
+ ! Transport liquid water in snow between layers and
+ ! compute the meltpond contribution
+ !-----------------------------------------------------------------
+
+ if (use_smliq_pnd) then
+ call drain_snow (dt, nslyr, &
+ vsnon (n) , aicen (n), &
+ smice (:,n), smliq (:,n), &
+ meltsliqn(n))
+ endif
+
!-----------------------------------------------------------------
! Melt ponds
! If using tr_pond_cesm, the full calculation is performed here.
@@ -2171,7 +2291,6 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
!call ice_timer_start(timer_ponds)
if (tr_pond) then
-
if (tr_pond_cesm) then
rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n)
call compute_ponds_cesm(dt, hi_min, &
@@ -2180,7 +2299,9 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
frain, &
aicen (n), vicen (n), &
vsnon (n), Tsfc (n), &
- apnd (n), hpnd (n))
+ apnd (n), hpnd (n), &
+ meltsliqn(n), &
+ use_smliq_pnd)
elseif (tr_pond_lvl) then
rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n)
@@ -2198,7 +2319,9 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
zqin(:,n), zSin(:,n), &
Tsfc (n), alvl (n), &
apnd (n), hpnd (n), &
- ipnd (n))
+ ipnd (n), &
+ meltsliqn(n), &
+ use_smliq_pnd)
elseif (tr_pond_topo) then
if (aicen_init(n) > puny) then
@@ -2206,10 +2329,14 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
! collect liquid water in ponds
! assume salt still runs off
rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n)
- pond = rfrac/rhofresh * (melttn(n)*rhoi &
- + meltsn(n)*rhos &
- + frain *dt)
-
+ if (use_smliq_pnd) then
+ pond = rfrac/rhofresh * (melttn(n)*rhoi &
+ + meltsliqn(n))
+ else
+ pond = rfrac/rhofresh * (melttn(n)*rhoi &
+ + meltsn(n)*rhos &
+ + frain *dt)
+ endif
! if pond does not exist, create new pond over full ice area
! otherwise increase pond depth without changing pond area
if (apnd(n) < puny) then
@@ -2251,10 +2378,10 @@ subroutine colpkg_step_therm1(dt, ncat, nilyr, nslyr, n_aero, &
fhocn, fswthru, &
melttn (n), meltsn(n), &
meltbn (n), congeln(n), &
- snoicen(n), &
+ snoicen(n), meltsliqn(n), &
meltt, melts, &
meltb, congel, &
- snoice, &
+ snoice, meltsliq, &
Uref, Urefn)
enddo ! ncat
@@ -2287,7 +2414,7 @@ end subroutine colpkg_step_therm1
! authors: William H. Lipscomb, LANL
! Elizabeth C. Hunke, LANL
- subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
+ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nbtrcr, &
nilyr, nslyr, &
hin_max, nblyr, &
aicen, &
@@ -2313,14 +2440,14 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
frazil_diag, &
frz_onset, yday)
- use ice_constants_colpkg, only: puny
+ use ice_constants_colpkg, only: puny, c0
use ice_itd, only: aggregate_area, reduce_area, cleanup_itd
use ice_therm_itd, only: linear_itd, add_new_ice, lateral_melt
- use ice_colpkg_tracers, only: ntrcr, nbtrcr, tr_aero, tr_pond_topo
+ use ice_colpkg_tracers, only: ntrcr, tr_aero, tr_pond_topo, tr_brine, nt_fbri, bio_index
integer (kind=int_kind), intent(in) :: &
ncat , & ! number of thickness categories
- nltrcr , & ! number of zbgc tracers
+ nbtrcr , & ! number of zbgc tracers
nblyr , & ! number of bio layers
nilyr , & ! number of ice layers
nslyr , & ! number of snow layers
@@ -2329,7 +2456,7 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
logical (kind=log_kind), intent(in) :: &
update_ocn_f ! if true, update fresh water and salt fluxes
- real (kind=dbl_kind), dimension(0:ncat), intent(inout) :: &
+ real (kind=dbl_kind), dimension(0:ncat), intent(in) :: &
hin_max ! category boundaries (m)
real (kind=dbl_kind), intent(in) :: &
@@ -2421,6 +2548,8 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
! Compute fractional ice area in each grid cell.
!-----------------------------------------------------------------
+ flux_bio(:) = c0
+
call aggregate_area (ncat, aicen, aice, aice0)
if (kitd == 1) then
@@ -2431,21 +2560,21 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
if (aice > puny) then
- call linear_itd (ncat, hin_max, &
- nilyr, nslyr, &
- ntrcr, trcr_depend, &
- trcr_base, &
- n_trcr_strata, &
- nt_strata, &
+ call linear_itd (ncat, hin_max, &
+ nilyr, nslyr, &
+ ntrcr, trcr_depend, &
+ trcr_base, &
+ n_trcr_strata, &
+ nt_strata, Tf, &
aicen_init, &
vicen_init, &
aicen, &
- trcrn, &
+ trcrn, &
vicen, &
vsnon, &
- aice , &
- aice0 , &
- fpond, l_stop, &
+ aice, &
+ aice0, &
+ fpond, l_stop, &
stop_label)
if (l_stop) return
@@ -2465,7 +2594,7 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
call add_new_ice (ncat, nilyr, &
nblyr, &
n_aero, dt, &
- ntrcr, nltrcr, &
+ ntrcr, nbtrcr, &
hin_max, ktherm, &
aicen, trcrn, &
vicen, vsnon(1), &
@@ -2478,7 +2607,7 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
salinz, phi_init, &
dSin0_frazil, bgrid, &
cgrid, igrid, &
- nbtrcr, flux_bio, &
+ flux_bio, &
ocean_bio, fzsal, &
frazil_diag, &
l_stop, stop_label)
@@ -2517,7 +2646,8 @@ subroutine colpkg_step_therm2 (dt, ncat, n_aero, nltrcr, &
! categories with very small areas.
!-----------------------------------------------------------------
- call cleanup_itd (dt, ntrcr, &
+ call cleanup_itd (dt, Tf, &
+ ntrcr, &
nilyr, nslyr, &
ncat, hin_max, &
aicen, trcrn(1:ntrcr,:), &
@@ -2647,7 +2777,7 @@ end subroutine colpkg_prep_radiation
! Elizabeth C. Hunke, LANL
subroutine colpkg_step_radiation (dt, ncat, &
- n_algae, tr_zaero, &
+ n_algae, &
nblyr, ntrcr, &
nbtrcr, nbtrcr_sw, &
nilyr, nslyr, &
@@ -2661,6 +2791,8 @@ subroutine colpkg_step_radiation (dt, ncat, &
vsnon, Tsfcn, &
alvln, apndn, &
hpndn, ipndn, &
+ snwredist, &
+ rsnow, &
aeron, &
zbion, &
trcrn, &
@@ -2688,13 +2820,28 @@ subroutine colpkg_step_radiation (dt, ncat, &
albpndn, apeffn, &
snowfracn, &
dhsn, ffracn, &
- l_print_point, &
- initonly)
+ l_print_point, &
+ initonly, &
+ asm_prm_ice_drc, &
+ asm_prm_ice_dfs, &
+ ss_alb_ice_drc, &
+ ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, &
+ ext_cff_mss_ice_dfs, &
+ kaer_tab_5bd, &
+ waer_tab_5bd, &
+ gaer_tab_5bd, &
+ kaer_bc_tab_5bd, &
+ waer_bc_tab_5bd, &
+ gaer_bc_tab_5bd, &
+ bcenh_5bd, &
+ rsnw_dEddn)
use ice_constants_colpkg, only: c0, puny
use ice_shortwave, only: run_dEdd, shortwave_ccsm3, compute_shortwave_trcr
use ice_colpkg_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, &
- tr_bgc_N, tr_aero
+ tr_bgc_N, tr_aero, tr_rsnw, tr_zaero
+
use ice_colpkg_shared, only: z_tracers, skl_bgc
integer (kind=int_kind), intent(in) :: &
@@ -2745,7 +2892,8 @@ subroutine colpkg_step_radiation (dt, ncat, &
real (kind=dbl_kind), dimension(:,:), intent(in) :: &
kaer_tab, & ! aerosol mass extinction cross section (m2/kg)
waer_tab, & ! aerosol single scatter albedo (fraction)
- gaer_tab ! aerosol asymmetry parameter (cos(theta))
+ gaer_tab, & ! aerosol asymmetry parameter (cos(theta))
+ rsnow ! snow grain radius tracer (10^-6 m)
real (kind=dbl_kind), dimension(:,:), intent(in) :: &
kaer_bc_tab, & ! aerosol mass extinction cross section (m2/kg)
@@ -2766,6 +2914,9 @@ subroutine colpkg_step_radiation (dt, ncat, &
ipndn , & ! pond refrozen lid thickness (m)
fbri ! brine fraction
+ character(len=char_len), intent(in) :: &
+ snwredist ! type of snow redistribution
+
real(kind=dbl_kind), dimension(:,:), intent(in) :: &
aeron , & ! aerosols (kg/m^3)
trcrn ! tracers
@@ -2788,6 +2939,7 @@ subroutine colpkg_step_radiation (dt, ncat, &
albicen , & ! bare ice
albsnon , & ! snow
albpndn , & ! pond
+ rsnw_dEddn, & ! snow grain radius (um)
apeffn ! effective pond area used for radiation calculation
real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
@@ -2798,12 +2950,35 @@ subroutine colpkg_step_radiation (dt, ncat, &
logical (kind=log_kind), intent(in) :: &
l_print_point, & ! flag for printing diagnostics
dEdd_algae , & ! .true. use prognostic chla in dEdd
- modal_aero , & ! .true. use modal aerosol optical treatment
- tr_zaero
+ modal_aero ! .true. use modal aerosol optical treatment
logical (kind=log_kind), optional :: &
initonly ! flag to indicate init only, default is false
+
+ ! snow grain single-scattering properties for
+ ! direct (drc) and diffuse (dfs) shortwave incidents
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Model SNICAR snow SSP
+ asm_prm_ice_drc, & ! snow asymmetry factor (cos(theta))
+ asm_prm_ice_dfs, & ! snow asymmetry factor (cos(theta))
+ ss_alb_ice_drc, & ! snow single scatter albedo (fraction)
+ ss_alb_ice_dfs, & ! snow single scatter albedo (fraction)
+ ext_cff_mss_ice_drc, & ! snow mass extinction cross section (m2/kg)
+ ext_cff_mss_ice_dfs ! snow mass extinction cross section (m2/kg)
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: &
+ kaer_tab_5bd, & ! aerosol mass extinction cross section (m2/kg)
+ waer_tab_5bd, & ! aerosol single scatter albedo (fraction)
+ gaer_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Modal aerosol treatment
+ kaer_bc_tab_5bd, & ! aerosol mass extinction cross section (m2/kg)
+ waer_bc_tab_5bd, & ! aerosol single scatter albedo (fraction)
+ gaer_bc_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:,:), intent(in) :: & ! Modal aerosol treatment
+ bcenh_5bd ! BC absorption enhancement factor
+
! local variables
integer (kind=int_kind) :: &
@@ -2877,6 +3052,8 @@ subroutine colpkg_step_radiation (dt, ncat, &
vsnon, Tsfcn, &
alvln, apndn, &
hpndn, ipndn, &
+ snwredist, &
+ rsnow, tr_rsnw, &
aeron, kalg, &
zbion, &
heat_capacity, &
@@ -2907,8 +3084,23 @@ subroutine colpkg_step_radiation (dt, ncat, &
albpndn, apeffn, &
snowfracn, &
dhsn, ffracn, &
+ rsnw_dEddn, &
l_print_point, &
- linitonly)
+ linitonly, &
+ use_snicar, &
+ asm_prm_ice_drc, &
+ asm_prm_ice_dfs, &
+ ss_alb_ice_drc, &
+ ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, &
+ ext_cff_mss_ice_dfs, &
+ kaer_tab_5bd, &
+ waer_tab_5bd, &
+ gaer_tab_5bd, &
+ kaer_bc_tab_5bd, &
+ waer_bc_tab_5bd, &
+ gaer_bc_tab_5bd, &
+ bcenh_5bd)
else ! .not. dEdd
@@ -2983,6 +3175,7 @@ subroutine colpkg_step_ridge (dt, ndtd, &
nblyr, &
ncat, hin_max, &
rdg_conv, rdg_shear, &
+ Tf, &
aicen, &
trcrn, &
vicen, vsnon, &
@@ -3010,7 +3203,8 @@ subroutine colpkg_step_ridge (dt, ndtd, &
use ice_colpkg_tracers, only: tr_pond_topo, tr_aero, tr_brine, ntrcr, nbtrcr
real (kind=dbl_kind), intent(in) :: &
- dt ! time step
+ dt , & ! time step
+ Tf ! ocean freezing temperature
integer (kind=int_kind), intent(in) :: &
ncat , & ! number of thickness categories
@@ -3125,7 +3319,8 @@ subroutine colpkg_step_ridge (dt, ndtd, &
aredistn, vredistn, &
dardg1ndt, dardg2ndt, &
dvirdgndt, &
- araftn, vraftn)
+ araftn, vraftn, &
+ Tf)
if (l_stop) return
@@ -3135,7 +3330,8 @@ subroutine colpkg_step_ridge (dt, ndtd, &
!-----------------------------------------------------------------
dtt = dt * ndtd ! for proper averaging over thermo timestep
- call cleanup_itd (dtt, ntrcr, &
+ call cleanup_itd (dtt, Tf, &
+ ntrcr, &
nilyr, nslyr, &
ncat, hin_max, &
aicen, trcrn, &
@@ -3167,7 +3363,7 @@ end subroutine colpkg_step_ridge
! authors: C. M. Bitz, UW
! W. H. Lipscomb, LANL
- subroutine colpkg_aggregate (ncat, &
+ subroutine colpkg_aggregate (ncat, Tf, &
aicen, trcrn, &
vicen, vsnon, &
aice, trcr, &
@@ -3186,6 +3382,9 @@ subroutine colpkg_aggregate (ncat, &
ncat , & ! number of thickness categories
ntrcr ! number of tracers in use
+ real (kind=dbl_kind), intent(in) :: &
+ Tf ! ocean freezing temperature (Celsius)
+
real (kind=dbl_kind), dimension (:), intent(in) :: &
aicen , & ! concentration of ice
vicen , & ! volume per unit area of ice (m)
@@ -3273,7 +3472,8 @@ subroutine colpkg_aggregate (ncat, &
atrcr, aice, &
vice , vsno, &
trcr_base, n_trcr_strata, &
- nt_strata, trcr)
+ nt_strata, trcr, &
+ Tf)
deallocate (atrcr)
@@ -3474,6 +3674,7 @@ subroutine colpkg_atm_boundary(sfctype, &
if (present(uvel)) then
worku = uvel
endif
+ ! should this be for vvel,workv?
if (present(uvel)) then
worku = uvel
endif
@@ -3610,6 +3811,208 @@ subroutine colpkg_ocn_mixed_layer (alvdr_ocn, swvdr, &
end subroutine colpkg_ocn_mixed_layer
+!=======================================================================
+!
+! Updates snow tracers
+!
+! authors: Elizabeth C. Hunke, LANL
+! Nicole Jeffery, LANL
+
+ subroutine colpkg_step_snow (dt, wind, &
+ nilyr, &
+ nslyr, ncat, &
+ aice, aicen, &
+ vicen, vsnon, &
+ alvl, vlvl, &
+ smice, smliq, &
+ rhos_effn, rhos_eff, &
+ rhos_cmpn, rhos_cmp, &
+ rsnw, zqin1, &
+ zSin1, Tsfc, &
+ zqsn, &
+ fresh, fhocn, &
+ fsloss, fsnow, &
+ rhosnew, rhosmax, &
+ windmin, drhosdwind, &
+ snowage_tau, &
+ snowage_kappa, &
+ snowage_drdt0, &
+ idx_T_max, &
+ idx_Tgrd_max, &
+ idx_rhos_max, &
+ l_stop, &
+ stop_label)
+
+ use ice_colpkg_tracers, only: tr_snow, tr_rsnw
+ use ice_constants_colpkg, only: c0, puny, rhos
+ use ice_snow, only: snow_effective_density, update_snow_radius, &
+ snow_redist
+
+ integer (kind=int_kind), intent(in) :: &
+ nslyr, & ! number of snow layers
+ nilyr, & ! number of ice layers
+ ncat, & ! number of thickness categories
+ idx_T_max, & ! dimensions of snow parameter matrix
+ idx_Tgrd_max, &
+ idx_rhos_max
+
+ real (kind=dbl_kind), intent(in) :: &
+ dt , & ! time step
+ wind , & ! wind speed (m/s)
+ fsnow , & ! snowfall rate (kg m-2 s-1)
+ aice , & ! ice area fraction
+ rhosnew, & ! new snow density (kg/m^3)
+ rhosmax, & ! maximum snow density (kg/m^3)
+ windmin, & ! minimum wind speed to compact snow (m/s)
+ drhosdwind ! wind compaction factor (kg s/m^4)
+
+ real (kind=dbl_kind), dimension(:), intent(in) :: &
+ aicen, & ! ice area fraction
+ vicen, & ! ice volume (m)
+ Tsfc , & ! surface temperature (C)
+ zqin1, & ! ice upper layer enthalpy
+ zSin1, & ! ice upper layer salinity
+ alvl, & ! level ice area tracer
+ vlvl ! level ice volume tracer
+
+ real (kind=dbl_kind), intent(inout) :: &
+ fresh , & ! fresh water flux to ocean (kg/m^2/s)
+ fhocn , & ! net heat flux to ocean (W/m^2)
+ fsloss ! snow loss to leads (kg/m^2/s)
+
+ real (kind=dbl_kind), dimension(:), intent(inout) :: &
+ vsnon ! snow volume (m)
+
+ real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
+ zqsn , & ! snow enthalpy (J/m^3)
+ smice , & ! mass of ice in snow (kg/m^3)
+ smliq , & ! mass of liquid in snow (kg/m^3)
+ rsnw , & ! snow grain radius (10^-6 m)
+ rhos_effn, & ! effective snow density: content (kg/m^3)
+ rhos_cmpn ! effective snow density: compaction (kg/m^3)
+
+ real (kind=dbl_kind), intent(inout) :: &
+ rhos_eff , & ! mean effective snow density: content (kg/m^3)
+ rhos_cmp ! mean effective snow density: compaction (kg/m^3)
+
+ ! dry snow aging parameters
+ real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: &
+ snowage_tau, & ! (10^-6 m)
+ snowage_kappa, & !
+ snowage_drdt0 ! (10^-6 m/hr)
+
+ logical (kind=log_kind), intent(inout) :: &
+ l_stop ! if true, print diagnostics and abort model
+
+ character (len=*), intent(out) :: &
+ stop_label ! abort error message
+
+ ! local temporary variables
+
+ integer (kind=int_kind) :: n
+
+ real (kind=dbl_kind), dimension(ncat) :: &
+ zTin, & ! ice upper layer temperature (oC)
+ hsn , & ! snow thickness (m)
+ hin ! ice thickness
+
+ real (kind=dbl_kind) :: &
+ vsno, & ! snow volume (m)
+ tmp1, tmp2
+
+ character(len=char_len_long) :: &
+ warning ! warning message
+
+ l_stop = .false.
+ stop_label = ''
+
+ if (tr_snow) then
+
+ !-----------------------------------------------------------------
+ ! Compute effective density of snow
+ !-----------------------------------------------------------------
+
+ vsno = c0
+ do n = 1, ncat
+ vsno = vsno + vsnon(n)
+ enddo
+
+ call snow_effective_density(nslyr, ncat, &
+ vsnon, vsno, &
+ smice, smliq, &
+ rhosnew, &
+ rhos_effn, rhos_eff, &
+ rhos_cmpn, rhos_cmp)
+
+ !-----------------------------------------------------------------
+ ! Redistribute snow based on wind
+ !-----------------------------------------------------------------
+
+ tmp1 = rhos*vsno + fresh*dt
+
+ if (snwredist(1:3) == 'ITD' .and. aice > puny) then
+ call snow_redist(dt, &
+ nslyr, ncat, &
+ wind, aicen(:), &
+ vicen(:), vsnon(:), &
+ zqsn(:,:),snwredist, &
+ alvl(:), vlvl(:), &
+ fresh, fhocn, &
+ fsloss, rhos_cmpn, &
+ fsnow, rhosmax, &
+ windmin, drhosdwind, &
+ l_stop, stop_label)
+ endif
+
+ vsno = c0
+ do n = 1, ncat
+ vsno = vsno + vsnon(n)
+ enddo
+ tmp2 = rhos*vsno + fresh*dt
+ if (abs(tmp1-tmp2)>puny) then
+ write(warning,*) ' '
+ call add_warning(warning)
+ write(warning,*)'tmp1 ne tmp2',tmp1, tmp2
+ call add_warning(warning)
+ stop_label ='snow redistribution error'
+ l_stop = .true.
+ endif
+
+ endif ! tr_snow
+
+ !-----------------------------------------------------------------
+ ! Adjust snow grain radius
+ !-----------------------------------------------------------------
+
+ if (tr_rsnw) then
+ do n = 1, ncat
+ zTin(n)= c0
+ hsn(n) = c0
+ hin(n) = c0
+ if (aicen(n) > puny) then
+ zTin(n) = colpkg_ice_temperature(zqin1(n),zSin1(n))
+ hsn(n) = vsnon(n)/aicen(n)
+ hin(n) = vicen(n)/aicen(n)
+ endif
+ enddo
+
+ call update_snow_radius (dt, ncat, &
+ nslyr, nilyr, &
+ rsnw, hin, &
+ Tsfc, zTin, &
+ hsn, zqsn, &
+ smice, smliq, &
+ rsnw_fall, rsnw_tmax, &
+ snowage_tau, &
+ snowage_kappa, &
+ snowage_drdt0, &
+ idx_T_max, &
+ idx_Tgrd_max, &
+ idx_rhos_max)
+ endif
+
+ end subroutine colpkg_step_snow
+
!=======================================================================
! subroutine to set the column package internal parameters
@@ -3626,6 +4029,7 @@ subroutine colpkg_init_parameters(&
phi_c_slow_mode_in, &
phi_i_mushy_in, &
shortwave_in, &
+ use_snicar_in, &
albedo_type_in, &
albicev_in, &
albicei_in, &
@@ -3774,7 +4178,8 @@ subroutine colpkg_init_parameters(&
dmspdtype_in, &
humtype_in, &
doctype_s_in, &
- doctype_l_in, &
+ doctype_l_in, &
+ dictype_1_in, &
dontype_protein_in, &
fedtype_1_in, &
feptype_1_in, &
@@ -3793,7 +4198,15 @@ subroutine colpkg_init_parameters(&
F_abs_chl_diatoms_in, &
F_abs_chl_sp_in, &
F_abs_chl_phaeo_in, &
- ratio_C2N_proteins_in)
+ ratio_C2N_proteins_in, &
+ snwredist_in, &
+ use_smliq_pnd_in, &
+ rsnw_fall_in, &
+ rsnw_tmax_in, &
+ rhosnew_in, &
+ rhosmax_in, &
+ windmin_in, &
+ drhosdwind_in)
!restore_bgc_in)
use ice_colpkg_shared, only: &
@@ -3809,6 +4222,7 @@ subroutine colpkg_init_parameters(&
phi_c_slow_mode, &
phi_i_mushy, &
shortwave, &
+ use_snicar, &
albedo_type, &
albicev, &
albicei, &
@@ -3958,6 +4372,7 @@ subroutine colpkg_init_parameters(&
humtype , &
doctype_s , &
doctype_l , &
+ dictype_1 , &
dontype_protein , &
fedtype_1 , &
feptype_1 , &
@@ -3976,7 +4391,15 @@ subroutine colpkg_init_parameters(&
F_abs_chl_diatoms , &
F_abs_chl_sp , &
F_abs_chl_phaeo , &
- ratio_C2N_proteins
+ ratio_C2N_proteins , &
+ snwredist, &
+ use_smliq_pnd, &
+ rsnw_fall, &
+ rsnw_tmax, &
+ rhosnew, &
+ rhosmax, &
+ windmin, &
+ drhosdwind
!restore_bgc
!-----------------------------------------------------------------------
@@ -4037,6 +4460,12 @@ subroutine colpkg_init_parameters(&
rsnw_mlt_in , & ! maximum melting snow grain radius (10^-6 m)
kalg_in ! algae absorption coefficient for 0.5 m thick layer
+ ! snicar 5 band system, set in namelist
+ logical (kind=log_kind), intent(in) :: &
+ use_snicar_in ! if true, use 5-band snicar IOPs for
+ ! shortwave radiative calculation of
+ ! snow-coverd sea ice
+
!-----------------------------------------------------------------------
! Parameters for ridging and strength
!-----------------------------------------------------------------------
@@ -4229,6 +4658,7 @@ subroutine colpkg_init_parameters(&
humtype_in , & !
doctype_s_in , & !
doctype_l_in , & !
+ dictype_1_in , & !
dontype_protein_in , & !
fedtype_1_in , & !
feptype_1_in , & !
@@ -4274,6 +4704,32 @@ subroutine colpkg_init_parameters(&
real (kind=dbl_kind), intent(in) :: &
hp1_in ! critical parameter for pond ice thickness
+!-----------------------------------------------------------------------
+! Parameters for snow
+!-----------------------------------------------------------------------
+
+ ! snow metamorphism parameters, set in namelist
+ real (kind=dbl_kind), intent(in) :: &
+ rsnw_fall_in , & ! fallen snow grain radius (10^-6 m)) 54.5 um CLM **
+ ! 30 um is minimum for defined mie properties
+ rsnw_tmax_in , & ! maximum dry metamorphism snow grain radius (10^-6 m)
+ ! 1500 um is maximum for defined mie properties
+ rhosnew_in , & ! new snow density (kg/m^3)
+ rhosmax_in , & ! maximum snow density (kg/m^3)
+ windmin_in , & ! minimum wind speed to compact snow (m/s)
+ drhosdwind_in ! wind compaction factor (kg s/m^4)
+
+ character(len=char_len), intent(in) :: &
+ snwredist_in ! type of snow redistribution
+ ! '30percent' = 30% rule, precip only
+ ! '30percentsw' = 30% rule with shortwave
+ ! 'ITDsd' = Lecomte PhD, 2014
+ ! 'ITDrdg' = like ITDsd but use level/ridged ice
+ ! 'default' or 'none' = none
+
+ logical (kind=log_kind), intent(in) :: &
+ use_smliq_pnd_in ! if true, use snow liquid tracer for ponds
+
ktherm = ktherm_in
conduct = conduct_in
fbot_xfer_type = fbot_xfer_type_in
@@ -4286,6 +4742,7 @@ subroutine colpkg_init_parameters(&
phi_c_slow_mode = phi_c_slow_mode_in
phi_i_mushy = phi_i_mushy_in
shortwave = shortwave_in
+ use_snicar = use_snicar_in
albedo_type = albedo_type_in
albicev = albicev_in
albicei = albicei_in
@@ -4434,6 +4891,7 @@ subroutine colpkg_init_parameters(&
humtype = humtype_in
doctype_s = doctype_s_in
doctype_l = doctype_l_in
+ dictype_1 = dictype_1_in
dontype_protein = dontype_protein_in
fedtype_1 = fedtype_1_in
feptype_1 = feptype_1_in
@@ -4453,6 +4911,14 @@ subroutine colpkg_init_parameters(&
F_abs_chl_sp = F_abs_chl_sp_in
F_abs_chl_phaeo = F_abs_chl_phaeo_in
ratio_C2N_proteins = ratio_C2N_proteins_in
+ snwredist = snwredist_in
+ use_smliq_pnd = use_smliq_pnd_in
+ rsnw_fall = rsnw_fall_in
+ rsnw_tmax = rsnw_tmax_in
+ rhosnew = rhosnew_in
+ rhosmax = rhosmax_in
+ windmin = windmin_in
+ drhosdwind = drhosdwind_in
end subroutine colpkg_init_parameters
@@ -4467,6 +4933,8 @@ subroutine colpkg_init_tracer_flags(&
tr_pond_cesm_in , & ! if .true., use cesm pond tracer
tr_pond_lvl_in , & ! if .true., use level-ice pond tracer
tr_pond_topo_in , & ! if .true., use explicit topography-based ponds
+ tr_snow_in , & ! if .true., use snow trcrs (smice, smliq, rhos_cmp)
+ tr_rsnw_in , & ! if .true., use snow grain radius tracer
tr_aero_in , & ! if .true., use aerosol tracers
tr_brine_in , & ! if .true., brine height differs from ice thickness
tr_bgc_S_in , & ! if .true., use zsalinity
@@ -4492,6 +4960,8 @@ subroutine colpkg_init_tracer_flags(&
tr_pond_cesm , & ! if .true., use cesm pond tracer
tr_pond_lvl , & ! if .true., use level-ice pond tracer
tr_pond_topo , & ! if .true., use explicit topography-based ponds
+ tr_snow , & ! if .true., use snow trcrs (smice, smliq, rhos_cmp)
+ tr_rsnw , & ! if .true., use snow grain radius tracer
tr_aero , & ! if .true., use aerosol tracers
tr_brine , & ! if .true., brine height differs from ice thickness
tr_bgc_S , & ! if .true., use zsalinity
@@ -4517,6 +4987,8 @@ subroutine colpkg_init_tracer_flags(&
tr_pond_cesm_in , & ! if .true., use cesm pond tracer
tr_pond_lvl_in , & ! if .true., use level-ice pond tracer
tr_pond_topo_in , & ! if .true., use explicit topography-based ponds
+ tr_snow_in , & ! if .true., use snow trcrs (smice, smliq, rhos_cmp)
+ tr_rsnw_in , & ! if .true., use snow grain radius tracer
tr_aero_in , & ! if .true., use aerosol tracers
tr_brine_in , & ! if .true., brine height differs from ice thickness
tr_bgc_S_in , & ! if .true., use zsalinity
@@ -4540,6 +5012,8 @@ subroutine colpkg_init_tracer_flags(&
tr_pond_cesm = tr_pond_cesm_in
tr_pond_lvl = tr_pond_lvl_in
tr_pond_topo = tr_pond_topo_in
+ tr_snow = tr_snow_in
+ tr_rsnw = tr_rsnw_in
tr_aero = tr_aero_in
tr_brine = tr_brine_in
tr_bgc_S = tr_bgc_S_in
@@ -4574,6 +5048,10 @@ subroutine colpkg_init_tracer_indices(&
nt_hpnd_in, & ! melt pond depth
nt_ipnd_in, & ! melt pond refrozen lid thickness
nt_aero_in, & ! starting index for aerosols in ice
+ nt_smice_in, & ! snow ice mass
+ nt_smliq_in, & ! snow liquid mass
+ nt_rsnw_in, & ! snow grain radius
+ nt_rhos_in, & ! snow density
nt_zaero_in, & ! black carbon and other aerosols
nt_bgc_N_in , & ! diatoms, phaeocystis, pico/small
nt_bgc_C_in , & ! diatoms, phaeocystis, pico/small
@@ -4635,6 +5113,10 @@ subroutine colpkg_init_tracer_indices(&
nt_hpnd, & ! melt pond depth
nt_ipnd, & ! melt pond refrozen lid thickness
nt_aero, & ! starting index for aerosols in ice
+ nt_smice, & ! snow ice mass
+ nt_smliq, & ! snow liquid mass
+ nt_rsnw, & ! snow grain radius
+ nt_rhos, & ! snow density
nt_zaero, & ! black carbon and other aerosols
nt_bgc_N , & ! diatoms, phaeocystis, pico/small
nt_bgc_C , & ! diatoms, phaeocystis, pico/small
@@ -4690,6 +5172,10 @@ subroutine colpkg_init_tracer_indices(&
nt_hpnd_in, & ! melt pond depth
nt_ipnd_in, & ! melt pond refrozen lid thickness
nt_aero_in, & ! starting index for aerosols in ice
+ nt_smice_in, & ! snow ice mass
+ nt_smliq_in, & ! snow liquid mass
+ nt_rsnw_in, & ! snow grain radius
+ nt_rhos_in, & ! snow density
nt_bgc_Nit_in, & ! nutrients
nt_bgc_Am_in, & !
nt_bgc_Sil_in, & !
@@ -4773,6 +5259,10 @@ subroutine colpkg_init_tracer_indices(&
nt_hpnd = nt_hpnd_in
nt_ipnd = nt_ipnd_in
nt_aero = nt_aero_in
+ nt_smice = nt_smice_in
+ nt_smliq = nt_smliq_in
+ nt_rsnw = nt_rsnw_in
+ nt_rhos = nt_rhos_in
nt_bgc_Nit = nt_bgc_Nit_in
nt_bgc_Am = nt_bgc_Am_in
nt_bgc_Sil = nt_bgc_Sil_in
@@ -4894,20 +5384,21 @@ subroutine colpkg_biogeochemistry(dt, &
nblyr, nilyr, nslyr, n_algae, n_zaero, ncat, &
n_doc, n_dic, n_don, n_fed, n_fep, &
meltbn, melttn, congeln, snoicen, &
- sst, sss, fsnow, meltsn, hmix, salinz, &
+ sst, sss, Tf, fsnow, meltsn, hmix, salinz, &
hin_old, flux_bio, flux_bio_atm, &
aicen_init, vicen_init, aicen, vicen, vsnon, &
aice0, trcrn, vsnon_init, skl_bgc, &
max_algae, max_nbtrcr, &
+ flux_bion, &
l_stop, stop_label)
use ice_algae, only: zbio, sklbio
use ice_brine, only: preflushing_changes, compute_microS_mushy, &
- update_hbrine, compute_microS
+ update_hbrine, compute_microS
use ice_colpkg_shared, only: solve_zsal, z_tracers, phi_snow
use ice_colpkg_tracers, only: nt_fbri, tr_brine, &
- nt_bgc_S, nt_qice, nt_sice, nt_zbgc_frac, bio_index
- use ice_constants_colpkg, only: c0, c1, puny
+ nt_bgc_S, nt_qice, nt_sice, nt_zbgc_frac, bio_index, bio_index_o
+ use ice_constants_colpkg, only: c0, c1, puny, p5
use ice_zsalinity, only: zsalinity
use ice_zbgc_shared, only: zbgc_frac_init
@@ -4928,7 +5419,7 @@ subroutine colpkg_biogeochemistry(dt, &
real (kind=dbl_kind), dimension (:), intent(inout) :: &
bgrid , & ! biology nondimensional vertical grid points
igrid , & ! biology vertical interface points
- cgrid , & ! CICE vertical coordinate
+ cgrid , & ! CICE vertical coordinate
icgrid , & ! interface grid for CICE (shortwave variable)
ocean_bio , & ! contains all the ocean bgc tracer concentrations
fbio_snoice , & ! fluxes from snow to ice
@@ -4937,9 +5428,9 @@ subroutine colpkg_biogeochemistry(dt, &
dhbr_bot , & ! brine bottom change
darcy_V , & ! darcy velocity positive up (m/s)
hin_old , & ! old ice thickness
- sice_rho , & ! avg sea ice density (kg/m^3)
- ice_bio_net , & ! depth integrated tracer (mmol/m^2)
- snow_bio_net , & ! depth integrated snow tracer (mmol/m^2)
+ sice_rho , & ! avg sea ice density (kg/m^3)
+ ice_bio_net , & ! depth integrated tracer (mmol/m^2)
+ snow_bio_net , & ! depth integrated snow tracer (mmol/m^2)
flux_bio ! all bio fluxes to ocean
logical (kind=log_kind), dimension (:), intent(inout) :: &
@@ -4948,21 +5439,24 @@ subroutine colpkg_biogeochemistry(dt, &
! during a single time step from ice that was
! there the entire time step (true until ice forms)
+ real (kind=dbl_kind), dimension (:,:), intent(out) :: &
+ flux_bion ! per categeory ice to ocean biogeochemistry flux (mmol/m2/s)
+
real (kind=dbl_kind), dimension (:,:), intent(inout) :: &
Zoo , & ! N losses accumulated in timestep (ie. zooplankton/bacteria)
! mmol/m^3
- bphi , & ! porosity of layers
+ bphi , & ! porosity of layers
bTiz , & ! layer temperatures interpolated on bio grid (C)
zfswin , & ! Shortwave flux into layers interpolated on bio grid (W/m^2)
- iDi , & ! igrid Diffusivity (m^2/s)
- iki , & ! Ice permeability (m^2)
- trcrn ! tracers
+ iDi , & ! igrid Diffusivity (m^2/s)
+ iki , & ! Ice permeability (m^2)
+ trcrn ! tracers
real (kind=dbl_kind), intent(inout) :: &
grow_net , & ! Specific growth rate (/s) per grid cell
PP_net , & ! Total production (mg C/m^2/s) per grid cell
hbri , & ! brine height, area-averaged for comparison with hi (m)
- zsal_tot , & ! Total ice salinity in per grid cell (g/m^2)
+ zsal_tot , & ! Total ice salinity in per grid cell (g/m^2)
fzsal , & ! Total flux of salt to ocean at time step for conservation
fzsal_g , & ! Total gravity drainage flux
upNO , & ! nitrate uptake rate (mmol/m^2/d) times aice
@@ -4970,7 +5464,7 @@ subroutine colpkg_biogeochemistry(dt, &
totalChla ! ice integrated chla and summed over all algal groups (mg/m^2)
logical (kind=log_kind), intent(inout) :: &
- Rayleigh_criteria ! .true. means Ra_c was reached
+ Rayleigh_criteria ! .true. means Ra_c was reached
real (kind=dbl_kind), dimension (:,:), intent(in) :: &
fswpenln ! visible SW entering ice layers (W m-2)
@@ -4982,11 +5476,11 @@ subroutine colpkg_biogeochemistry(dt, &
meltbn , & ! bottom melt in category n (m)
congeln , & ! congelation ice formation in category n (m)
snoicen , & ! snow-ice formation in category n (m)
- salinz , & ! initial salinity profile (ppt)
- flux_bio_atm, & ! all bio fluxes to ice from atmosphere
+ salinz , & ! initial salinity profile (ppt)
+ flux_bio_atm, & ! all bio fluxes to ice from atmosphere
aicen_init , & ! initial ice concentration, for linear ITD
vicen_init , & ! initial ice volume (m), for linear ITD
- vsnon_init , & ! initial snow volume (m), for aerosol
+ vsnon_init , & ! initial snow volume (m), for aerosol
aicen , & ! concentration of ice
vicen , & ! volume per unit area of ice (m)
vsnon ! volume per unit area of snow (m)
@@ -4996,12 +5490,13 @@ subroutine colpkg_biogeochemistry(dt, &
sss , & ! sea surface salinity (ppt)
sst , & ! sea surface temperature (C)
hmix , & ! mixed layer depth (m)
+ Tf , & ! basal freezing temperature (C)
fsnow ! snowfall rate (kg/m^2 s)
logical (kind=log_kind), intent(in) :: &
skl_bgc ! if true, solve skeletal biochemistry
- logical (kind=log_kind), intent(inout) :: &
+ logical (kind=log_kind), intent(inout) :: &
l_stop ! if true, abort the model
character (len=*), intent(inout) :: stop_label
@@ -5018,7 +5513,7 @@ subroutine colpkg_biogeochemistry(dt, &
hbr_old , & ! old brine thickness before growh/melt
dhice , & ! change due to sublimation/condensation (m)
kavg , & ! average ice permeability (m^2)
- bphi_o , & ! surface ice porosity
+ bphi_o , & ! surface ice porosity
hbrin , & ! brine height
dh_direct ! surface flooding or runoff
@@ -5030,19 +5525,30 @@ subroutine colpkg_biogeochemistry(dt, &
real (kind=dbl_kind), dimension (nblyr+1) :: &
! Defined on Bio Grid interfaces
- iphin , & ! porosity
+ iphin , & ! porosity
ibrine_sal , & ! brine salinity (ppt)
ibrine_rho , & ! brine_density (kg/m^3)
iTin ! Temperature on the interface grid (oC)
- real (kind=dbl_kind) :: &
+ real (kind=dbl_kind) :: &
sloss ! brine flux contribution from surface runoff (g/m^2)
+ real (kind=dbl_kind), dimension (ncat) :: &
+ hbrnInitial, & ! inital brine height
+ hbrnFinal ! category initial and final brine heights
+
! for bgc sk
- real (kind=dbl_kind) :: &
+ real (kind=dbl_kind) :: &
dh_bot_chl , & ! Chlorophyll may or may not flush
dh_top_chl , & ! Chlorophyll may or may not flush
- darcy_V_chl
+ darcy_V_chl
+
+ real (kind=dbl_kind), dimension (nblyr+1) :: &
+ zspace ! vertical grid spacing
+
+ zspace(:) = c1/real(nblyr,kind=dbl_kind)
+ zspace(1) = p5*zspace(1)
+ zspace(nblyr+1) = p5*zspace(nblyr+1)
l_stop = .false.
@@ -5051,11 +5557,16 @@ subroutine colpkg_biogeochemistry(dt, &
!-----------------------------------------------------------------
! initialize
!-----------------------------------------------------------------
+ flux_bion(:,n) = c0
hin_old(n) = c0
- if (aicen_init(n) > puny) then
+ hbrnFinal(n) = c0
+ hbrnInitial(n) = c0
+
+ if (aicen_init(n) > puny) then
hin_old(n) = vicen_init(n) &
/ aicen_init(n)
else
+
first_ice(n) = .true.
if (tr_brine) trcrn(nt_fbri,n) = c1
do mm = 1,nbtrcr
@@ -5066,7 +5577,7 @@ subroutine colpkg_biogeochemistry(dt, &
endif
if (aicen(n) > puny) then
-
+
dh_top_chl = c0
dh_bot_chl = c0
darcy_V_chl= c0
@@ -5077,7 +5588,7 @@ subroutine colpkg_biogeochemistry(dt, &
kavg = c0
bphi_o = c0
sloss = c0
-
+
!-----------------------------------------------------------------
! brine dynamics
!-----------------------------------------------------------------
@@ -5085,24 +5596,25 @@ subroutine colpkg_biogeochemistry(dt, &
dhbr_top(n) = c0
dhbr_bot(n) = c0
- if (tr_brine) then
- if (trcrn(nt_fbri,n) .le. c0) trcrn(nt_fbri,n) = c1
+ if (tr_brine) then
dhice = c0
call preflushing_changes (n, aicen (n), &
vicen (n), vsnon (n), &
meltbn (n), melttn (n), &
congeln (n), snoicen(n), &
- hin_old (n), dhice, &
+ hin_old (n), dhice, &
trcrn(nt_fbri,n), &
dhbr_top(n), dhbr_bot(n), &
hbr_old, hin, &
hsn, first_ice(n), &
l_stop, stop_label)
+ hbrnInitial(n) = hbr_old
+
if (l_stop) return
- if (solve_zsal) then
+ if (solve_zsal) then
call compute_microS (n, nilyr, nblyr, &
bgrid, cgrid, igrid, &
@@ -5116,7 +5628,7 @@ subroutine colpkg_biogeochemistry(dt, &
salinz(1:nilyr), l_stop, stop_label)
if (l_stop) return
- else
+ else
! Requires the average ice permeability = kavg(:)
! and the surface ice porosity = zphi_o(:)
@@ -5127,14 +5639,14 @@ subroutine colpkg_biogeochemistry(dt, &
call compute_microS_mushy (n, nilyr, nblyr, &
bgrid, cgrid, igrid, &
trcrn(:,n), hin_old(n), hbr_old, &
- sss, sst, bTiz(:,n), &
+ sss, sst, bTiz(:,n), &
iTin(:), bphi(:,n), kavg, &
bphi_o, phi_snow, bSin(:), &
brine_sal(:), brine_rho(:), iphin(:), &
ibrine_rho(:), ibrine_sal(:), sice_rho(n), &
iDi(:,n), l_stop, stop_label)
- endif ! solve_zsal
+ endif ! solve_zsal
call update_hbrine (meltbn (n), melttn(n), &
meltsn (n), dt, &
@@ -5145,18 +5657,19 @@ subroutine colpkg_biogeochemistry(dt, &
trcrn(nt_fbri,n), &
snoicen(n), &
dhbr_top(n), dhbr_bot(n), &
- dh_top_chl, dh_bot_chl, &
+ dh_top_chl, dh_bot_chl, &
kavg, bphi_o, &
- darcy_V (n), darcy_V_chl, &
+ darcy_V (n), darcy_V_chl, &
bphi(2,n), aice0, &
dh_direct)
-
- hbri = hbri + hbrin * aicen(n)
- if (solve_zsal) then
+ hbri = hbri + hbrin * aicen(n)
+ hbrnFinal(n) = hbrin
+
+ if (solve_zsal) then
call zsalinity (n, dt, &
- nilyr, bgrid, &
+ nilyr, bgrid, &
cgrid, igrid, &
trcrn(nt_bgc_S:nt_bgc_S+nblyr-1,n), &
trcrn(nt_qice:nt_qice+nilyr-1,n), &
@@ -5167,8 +5680,8 @@ subroutine colpkg_biogeochemistry(dt, &
iki(:,n), hbr_old, &
hbrin, hin, &
hin_old(n), iDi(:,n), &
- darcy_V(n), brine_sal, &
- brine_rho, ibrine_sal, &
+ darcy_V(n), brine_sal, &
+ brine_rho, ibrine_sal, &
ibrine_rho, dh_direct, &
Rayleigh_criteria, &
first_ice(n), sss, &
@@ -5176,9 +5689,9 @@ subroutine colpkg_biogeochemistry(dt, &
dhbr_bot(n), &
l_stop, stop_label, &
fzsal, fzsal_g, &
- bphi_o, nblyr, &
+ bphi_o, nblyr, &
vicen(n), aicen_init(n), &
- zsal_tot)
+ zsal_tot)
if (l_stop) return
@@ -5190,26 +5703,27 @@ subroutine colpkg_biogeochemistry(dt, &
! biogeochemistry
!-----------------------------------------------------------------
- if (z_tracers) then
-
+ if (z_tracers) then
+
call zbio (dt, nblyr, &
nslyr, nilyr, &
melttn(n), &
meltsn(n), meltbn (n), &
- congeln(n), snoicen(n), &
+ congeln(n), snoicen(n), &
nbtrcr, fsnow, &
ntrcr, trcrn(1:ntrcr,n), &
- bio_index(1:nbtrcr), aicen_init(n), &
+ bio_index(1:nbtrcr), bio_index_o(:), &
+ aicen_init(n), &
vicen_init(n), vsnon_init(n), &
vicen(n), vsnon(n), &
- aicen(n), flux_bio_atm(1:nbtrcr), &
+ aicen(n), flux_bio_atm(:), &
n, n_algae, &
n_doc, n_dic, &
n_don, &
n_fed, n_fep, &
n_zaero, first_ice(n), &
- hin_old(n), ocean_bio(1:nbtrcr), &
- bphi(:,n), iphin, &
+ hin_old(n), ocean_bio(:), &
+ bphi(:,n), iphin, &
iDi(:,n), sss, &
fswpenln(:,n), &
dhbr_top(n), dhbr_bot(n), &
@@ -5222,25 +5736,26 @@ subroutine colpkg_biogeochemistry(dt, &
bphi_o, &
dhice, iTin, &
Zoo(:,n), &
- flux_bio(1:nbtrcr), dh_direct, &
+ flux_bio(:), dh_direct, &
upNO, upNH, &
fbio_snoice, fbio_atmice, &
- PP_net, ice_bio_net (1:nbtrcr), &
- snow_bio_net(1:nbtrcr),grow_net, &
+ PP_net, ice_bio_net (:), &
+ snow_bio_net(:), grow_net, &
totalChla, &
+ flux_bion(:,n), &
l_stop, stop_label)
-
+
if (l_stop) return
-
+
elseif (skl_bgc) then
- call sklbio (dt, ntrcr, &
- nilyr, &
+ call sklbio (dt, Tf, &
+ ntrcr, nilyr, &
nbtrcr, n_algae, &
n_zaero, n_doc, &
n_dic, n_don, &
n_fed, n_fep, &
- flux_bio (1:nbtrcr), ocean_bio(1:nbtrcr), &
+ flux_bio (1:nbtrcr), ocean_bio(:), &
hmix, aicen (n), &
meltbn (n), congeln (n), &
fswthrun (n), first_ice(n), &
@@ -5255,7 +5770,16 @@ subroutine colpkg_biogeochemistry(dt, &
endif ! skl_bgc
first_ice(n) = .false.
-
+ else
+ do mm = 1, nbtrcr
+ do k = 1, nblyr+1
+ flux_bion(mm,n) = flux_bion(mm,n) + trcrn(bio_index(mm) + k-1,n) * &
+ hin_old(n) * zspace(k)/dt * trcrn(nt_fbri,n)
+ flux_bio(mm) = flux_bio(mm) + trcrn(bio_index(mm) + k-1,n) * &
+ vicen_init(n) * zspace(k)/dt * trcrn(nt_fbri,n)
+ trcrn(bio_index(mm) + k-1,n) = c0
+ enddo
+ enddo
endif ! aicen > puny
enddo ! ncat
@@ -5268,8 +5792,8 @@ end subroutine colpkg_biogeochemistry
subroutine colpkg_init_hbrine(bgrid, igrid, cgrid, &
icgrid, swgrid, nblyr, nilyr, phi_snow)
- use ice_constants_colpkg, only: c1, c1p5, c2, p5, c0, rhoi, rhos
-
+ use ice_constants_colpkg, only: c1, c1p5, c2, p5, c0, rhoi, rhos, p25
+
integer (kind=int_kind), intent(in) :: &
nilyr, & ! number of ice layers
nblyr ! number of bio layers
@@ -5282,9 +5806,9 @@ subroutine colpkg_init_hbrine(bgrid, igrid, cgrid, &
real (kind=dbl_kind), dimension (nblyr+1), intent(out) :: &
igrid ! biology vertical interface points
-
+
real (kind=dbl_kind), dimension (nilyr+1), intent(out) :: &
- cgrid , & ! CICE vertical coordinate
+ cgrid , & ! CICE vertical coordinate
icgrid , & ! interface grid for CICE (shortwave variable)
swgrid ! grid for ice tracers used in dEdd scheme
@@ -5292,65 +5816,65 @@ subroutine colpkg_init_hbrine(bgrid, igrid, cgrid, &
k , & ! vertical index
n ! thickness category index
- real (kind=dbl_kind) :: &
+ real (kind=dbl_kind) :: &
zspace ! grid spacing for CICE vertical grid
if (phi_snow .le. c0) phi_snow = c1-rhos/rhoi
!-----------------------------------------------------------------
- ! Calculate bio gridn: 0 to 1 corresponds to ice top to bottom
+ ! Calculate bio gridn: 0 to 1 corresponds to ice top to bottom
!-----------------------------------------------------------------
- bgrid(:) = c0 ! zsalinity grid points
+ bgrid(:) = c0 ! zsalinity grid points
bgrid(nblyr+2) = c1 ! bottom value
- igrid(:) = c0 ! bgc interface grid points
+ igrid(:) = c0 ! bgc interface grid points
igrid(1) = c0 ! ice top
igrid(nblyr+1) = c1 ! ice bottom
-
+
zspace = c1/max(c1,(real(nblyr,kind=dbl_kind)))
do k = 2, nblyr+1
bgrid(k) = zspace*(real(k,kind=dbl_kind) - c1p5)
enddo
-
+
do k = 2, nblyr
igrid(k) = p5*(bgrid(k+1)+bgrid(k))
enddo
!-----------------------------------------------------------------
- ! Calculate CICE cgrid for interpolation ice top (0) to bottom (1)
+ ! Calculate CICE cgrid for interpolation ice top (0) to bottom (1)
!-----------------------------------------------------------------
-
+
cgrid(1) = c0 ! CICE vertical grid top point
zspace = c1/(real(nilyr,kind=dbl_kind)) ! CICE grid spacing
-
+
do k = 2, nilyr+1
- cgrid(k) = zspace * (real(k,kind=dbl_kind) - c1p5)
- enddo
+ cgrid(k) = zspace * (real(k,kind=dbl_kind) - c1p5)
+ enddo
!-----------------------------------------------------------------
! Calculate CICE icgrid for ishortwave interpolation top(0) , bottom (1)
!-----------------------------------------------------------------
-
- icgrid(1) = c0
+
+ icgrid(1) = c0
zspace = c1/(real(nilyr,kind=dbl_kind)) ! CICE grid spacing
-
+
do k = 2, nilyr+1
icgrid(k) = zspace * (real(k,kind=dbl_kind)-c1)
- enddo
+ enddo
!------------------------------------------------------------------------
! Calculate CICE swgrid for dEdd ice: top of ice (0) , bottom of ice (1)
! Does not include snow
! see ice_shortwave.F90
! swgrid represents the layer index of the delta-eddington ice layer index
- !------------------------------------------------------------------------
+ !------------------------------------------------------------------------
zspace = c1/(real(nilyr,kind=dbl_kind)) ! CICE grid spacing
- swgrid(1) = min(c1/60.0_dbl_kind, zspace/c2)
+ swgrid(1) = min(c1/60.0_dbl_kind, zspace*p25)
swgrid(2) = zspace/c2 !+ swgrid(1)
do k = 3, nilyr+1
swgrid(k) = zspace * (real(k,kind=dbl_kind)-c1p5)
- enddo
+ enddo
end subroutine colpkg_init_hbrine
@@ -5416,7 +5940,7 @@ subroutine colpkg_init_ocean_conc (amm, dmsp, dms, algalN, doc, dic, don, &
doc(2) = 9.0_dbl_kind ! lipids
doc(3) = c1 !
do k = 1, max_dic
- dic(k) = c1
+ dic(k) = 1950.0_dbl_kind ! 1950-2260 mmol C/m3 (Tynan et al. 2015)
enddo
do k = 1, max_don
don(k) = 12.9_dbl_kind
@@ -5629,12 +6153,15 @@ subroutine colpkg_get_warnings(warningsOut)
warningsOut
integer :: &
- iWarning
+ iWarning, &
+ nWarnings
+
+ nWarnings = get_number_warnings()
if (allocated(warningsOut)) deallocate(warningsOut)
- allocate(warningsOut(get_number_warnings()))
+ allocate(warningsOut(nWarnings))
- do iWarning = 1, get_number_warnings()
+ do iWarning = 1, nWarnings
warningsOut(iWarning) = trim(get_warning(iWarning))
enddo
diff --git a/src/core_seaice/column/ice_colpkg_shared.F90 b/src/core_seaice/column/ice_colpkg_shared.F90
index 5e49c598c1..cb8125cbd2 100644
--- a/src/core_seaice/column/ice_colpkg_shared.F90
+++ b/src/core_seaice/column/ice_colpkg_shared.F90
@@ -89,7 +89,14 @@ module ice_colpkg_shared
real (kind=dbl_kind), parameter, public :: &
hi_ssl = 0.050_dbl_kind, & ! ice surface scattering layer thickness (m)
- hs_ssl = 0.040_dbl_kind ! snow surface scattering layer thickness (m)
+ hs_ssl = 0.040_dbl_kind, & ! snow surface scattering layer thickness (m)
+ hs_ssl_min = 5.0e-4_dbl_kind ! minimum snow scattering layer thickness for aerosol accumulation (m)
+
+ ! snicar 5 band system, set in namelist
+ logical (kind=log_kind), public :: &
+ use_snicar ! if true, use 5-band snicar IOPs for
+ ! shortwave radiative calculation of
+ ! snow-coverd sea ice
!-----------------------------------------------------------------------
! Parameters for ridging and strength
@@ -171,6 +178,47 @@ module ice_colpkg_shared
real (kind=dbl_kind), public :: &
hp1 ! critical parameter for pond ice thickness
+!-----------------------------------------------------------------------
+! Parameters for snow
+!-----------------------------------------------------------------------
+
+ ! snow metamorphism parameters, set in namelist
+ real (kind=dbl_kind), public :: &
+ rsnw_fall , & ! fallen snow grain radius (10^-6 m)) 54.5 um CLM **
+ ! 30 um is minimum for defined mie properties
+ rsnw_tmax , & ! maximum dry metamorphism snow grain radius (10^-6 m)
+ ! 1500 um is maximum for defined mie properties
+ rhosnew , & ! new snow density (kg/m^3)
+ rhosmax , & ! maximum snow density (kg/m^3)
+ windmin , & ! minimum wind speed to compact snow (m/s)
+ drhosdwind ! wind compaction factor (kg s/m^4)
+
+ character(len=char_len), public :: &
+ snwredist ! type of snow redistribution
+ ! '30percent' = 30% rule, precip only
+ ! '30percentsw' = 30% rule with shortwave
+ ! 'ITDsd' = Lecomte PhD, 2014
+ ! 'ITDrdg' = like ITDsd but use level/ridged ice
+ ! 'default' or 'none' = none
+
+ logical (kind=log_kind), public :: &
+ use_smliq_pnd ! if true, use snow liquid tracer for ponds
+
+ ! indices for aging lookup table [idx]
+ integer(kind=int_kind), parameter, public :: &
+ idx_T_max = 11 , & ! maxiumum temperature index
+ idx_T_min = 1 , & ! minimum temperature index
+ idx_Tgrd_max = 31 , & ! maxiumum temperature gradient index
+ idx_Tgrd_min = 1 , & ! minimum temperature gradient index
+ idx_rhos_max = 8 , & ! maxiumum snow density index
+ idx_rhos_min = 1 ! minimum snow density index
+
+ ! dry snow aging parameters
+ real (kind=dbl_kind), dimension(8,31,11), public :: &
+ snowage_tau, & ! (10^-6 m)
+ snowage_kappa, & !
+ snowage_drdt0 ! (10^-6 m/hr)
+
!-----------------------------------------------------------------------
! Parameters for biogeochemistry
!-----------------------------------------------------------------------
@@ -345,6 +393,7 @@ module ice_colpkg_shared
humtype , & !
doctype_s , & !
doctype_l , & !
+ dictype_1 , & !
dontype_protein , & !
fedtype_1 , & !
feptype_1 , & !
@@ -374,8 +423,8 @@ module ice_colpkg_shared
! Algal types: Diatoms, flagellates, Phaeocycstis
! DOC : Proteins, EPS, Lipids
!-----------------------------------------------------------------
- real (kind=dbl_kind), parameter, dimension(max_dic), public :: &
- dictype = (/-c1/) ! not in namelist
+ real (kind=dbl_kind), dimension(max_dic), public :: &
+ dictype ! added to namelist
real (kind=dbl_kind), dimension(max_algae), public :: &
algaltype ! tau_min for both retention and release
@@ -407,9 +456,7 @@ module ice_colpkg_shared
!-----------------------------------------------------------------
real (kind=dbl_kind), parameter, public :: &
- rhosi = 940.0_dbl_kind, & ! average sea ice density
- ! Cox and Weeks, 1982: 919-974 kg/m^2
- sk_l = 0.03_dbl_kind ! skeletal layer thickness (m)
+ rhosi = 940.0_dbl_kind
real (kind=dbl_kind), dimension(max_algae), public :: &
R_C2N , & ! algal C to N (mole/mole)
diff --git a/src/core_seaice/column/ice_colpkg_tracers.F90 b/src/core_seaice/column/ice_colpkg_tracers.F90
index b703e93143..8bb2f5710d 100644
--- a/src/core_seaice/column/ice_colpkg_tracers.F90
+++ b/src/core_seaice/column/ice_colpkg_tracers.F90
@@ -34,6 +34,10 @@ module ice_colpkg_tracers
nt_apnd , & ! melt pond area fraction
nt_hpnd , & ! melt pond depth
nt_ipnd , & ! melt pond refrozen lid thickness
+ nt_smice , & ! mass of ice in snow
+ nt_smliq , & ! mass of liquid water in snow
+ nt_rhos , & ! effective snow density (compaction)
+ nt_rsnw , & ! effective snow grain radius
nt_aero , & ! starting index for aerosols in ice
nt_bgc_Nit, & ! nutrients
nt_bgc_Am, & !
@@ -54,6 +58,8 @@ module ice_colpkg_tracers
tr_pond_cesm, & ! if .true., use cesm pond tracer
tr_pond_lvl , & ! if .true., use level-ice pond tracer
tr_pond_topo, & ! if .true., use explicit topography-based ponds
+ tr_snow , & ! if .true., use snow tracers (ice, liquid water mass)
+ tr_rsnw , & ! if .true., use dynamic snow grain radius tracer
tr_aero , & ! if .true., use aerosol tracers
tr_brine ! if .true., brine height differs from ice thickness
@@ -158,9 +164,10 @@ subroutine colpkg_compute_tracers (ntrcr, trcr_depend, &
atrcrn, aicen, &
vicen, vsnon, &
trcr_base, n_trcr_strata, &
- nt_strata, trcrn)
+ nt_strata, trcrn, &
+ Tf)
- use ice_constants_colpkg, only: c0, c1, puny, Tocnfrz
+ use ice_constants_colpkg, only: c0, c1, puny
integer (kind=int_kind), intent(in) :: &
ntrcr ! number of tracers in use
@@ -182,7 +189,8 @@ subroutine colpkg_compute_tracers (ntrcr, trcr_depend, &
real (kind=dbl_kind), intent(in) :: &
aicen , & ! concentration of ice
vicen , & ! volume per unit area of ice (m)
- vsnon ! volume per unit area of snow (m)
+ vsnon , & ! volume per unit area of snow (m)
+ Tf ! ocean freezing temperature (Celsius)
real (kind=dbl_kind), dimension (ntrcr), intent(out) :: &
trcrn ! ice tracers
@@ -215,7 +223,7 @@ subroutine colpkg_compute_tracers (ntrcr, trcr_depend, &
trcrn(it) = atrcrn(it) / aicen
else
trcrn(it) = c0
- if (it == nt_Tsfc) trcrn(it) = Tocnfrz ! surface temperature
+ if (it == nt_Tsfc) trcrn(it) = Tf ! surface temperature
endif
else
diff --git a/src/core_seaice/column/ice_firstyear.F90 b/src/core_seaice/column/ice_firstyear.F90
index 01b898a00c..d0d259150c 100755
--- a/src/core_seaice/column/ice_firstyear.F90
+++ b/src/core_seaice/column/ice_firstyear.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_firstyear.F90 1012 2015-06-26 12:34:09Z eclare $
+! SVN:$Id: ice_firstyear.F90 1099 2015-12-12 18:12:30Z eclare $
!=======================================================================
!
! First year concentration tracer for sea ice
diff --git a/src/core_seaice/column/ice_flux_colpkg.F90 b/src/core_seaice/column/ice_flux_colpkg.F90
index 760f6b87b7..4806fdcecc 100644
--- a/src/core_seaice/column/ice_flux_colpkg.F90
+++ b/src/core_seaice/column/ice_flux_colpkg.F90
@@ -47,10 +47,12 @@ subroutine merge_fluxes (aicen, &
Tref, Qref, &
fresh, fsalt, &
fhocn, fswthru, &
- melttn, meltsn, meltbn, congeln, snoicen, &
- meltt, melts, &
- meltb, &
- congel, snoice, &
+ melttn, meltsn, &
+ meltbn, congeln, &
+ snoicen, meltsliqn, &
+ meltt, melts, &
+ meltb, congel, &
+ snoice, meltsliq, &
Uref, Urefn )
! single category fluxes
@@ -77,6 +79,7 @@ subroutine merge_fluxes (aicen, &
melttn , & ! top ice melt (m)
meltbn , & ! bottom ice melt (m)
meltsn , & ! snow melt (m)
+ meltsliqn,& ! snow liquid contribution to meltpond (kg/m^2)
congeln , & ! congelation ice growth (m)
snoicen ! snow-ice growth (m)
@@ -104,6 +107,7 @@ subroutine merge_fluxes (aicen, &
meltt , & ! top ice melt (m)
meltb , & ! bottom ice melt (m)
melts , & ! snow melt (m)
+ meltsliq, & ! snow liquid contribution to meltponds (kg/m^2)
congel , & ! congelation ice growth (m)
snoice ! snow-ice growth (m)
@@ -151,6 +155,7 @@ subroutine merge_fluxes (aicen, &
melts = melts + meltsn * aicen
congel = congel + congeln * aicen
snoice = snoice + snoicen * aicen
+ meltsliq = meltsliq + meltsliqn * aicen
end subroutine merge_fluxes
diff --git a/src/core_seaice/column/ice_itd.F90 b/src/core_seaice/column/ice_itd.F90
index 5fa2b5f14b..a9de8a2ba7 100644
--- a/src/core_seaice/column/ice_itd.F90
+++ b/src/core_seaice/column/ice_itd.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_itd.F90 1182 2017-03-16 19:29:26Z njeffery $
+! SVN:$Id: ice_itd.F90 1196 2017-04-18 13:32:23Z eclare $
!=======================================================================
! Routines to initialize the ice thickness distribution and
@@ -28,7 +28,7 @@ module ice_itd
use ice_kinds_mod
use ice_constants_colpkg, only: c0, c1, c2, p001, puny, p5, &
- Lfresh, rhos, ice_ref_salinity, hs_min, cp_ice, Tocnfrz, rhoi
+ Lfresh, rhos, ice_ref_salinity, hs_min, cp_ice, rhoi
use ice_warnings, only: &
add_warning
@@ -89,7 +89,7 @@ end subroutine aggregate_area
subroutine rebin (ntrcr, trcr_depend, &
trcr_base, &
n_trcr_strata, &
- nt_strata, &
+ nt_strata, Tf, &
aicen, trcrn, &
vicen, vsnon, &
ncat, hin_max, &
@@ -103,6 +103,9 @@ subroutine rebin (ntrcr, trcr_depend, &
trcr_depend, & ! = 0 for aicen tracers, 1 for vicen, 2 for vsnon
n_trcr_strata ! number of underlying tracer layers
+ real (kind=dbl_kind), intent(in) :: &
+ Tf ! ocean freezing temperature (C)
+
real (kind=dbl_kind), dimension (:,:), intent(in) :: &
trcr_base ! = 0 or 1 depending on tracer dependency
! argument 2: (1) aice, (2) vice, (3) vsno
@@ -207,7 +210,7 @@ subroutine rebin (ntrcr, trcr_depend, &
trcr_depend, &
trcr_base, &
n_trcr_strata, &
- nt_strata, &
+ nt_strata, Tf, &
aicen, trcrn, &
vicen, vsnon, &
hicen, donor, &
@@ -255,7 +258,7 @@ subroutine rebin (ntrcr, trcr_depend, &
trcr_depend, &
trcr_base, &
n_trcr_strata, &
- nt_strata, &
+ nt_strata, Tf, &
aicen, trcrn, &
vicen, vsnon, &
hicen, donor, &
@@ -345,7 +348,7 @@ subroutine shift_ice (ntrcr, ncat, &
trcr_depend, &
trcr_base, &
n_trcr_strata, &
- nt_strata, &
+ nt_strata, Tf, &
aicen, trcrn, &
vicen, vsnon, &
hicen, donor, &
@@ -362,6 +365,9 @@ subroutine shift_ice (ntrcr, ncat, &
trcr_depend, & ! = 0 for aicen tracers, 1 for vicen, 2 for vsnon
n_trcr_strata ! number of underlying tracer layers
+ real (kind=dbl_kind), intent(in) :: &
+ Tf ! ocean freezing temperature (C)
+
real (kind=dbl_kind), dimension (:,:), intent(in) :: &
trcr_base ! = 0 or 1 depending on tracer dependency
! argument 2: (1) aice, (2) vice, (3) vsno
@@ -647,11 +653,12 @@ subroutine shift_ice (ntrcr, ncat, &
! Compute new tracers
!-----------------------------------------------------------------
- call colpkg_compute_tracers (ntrcr, trcr_depend, &
- atrcrn(:,n), aicen(n), &
- vicen(n), vsnon(n), &
+ call colpkg_compute_tracers (ntrcr, trcr_depend, &
+ atrcrn(:,n), aicen(n), &
+ vicen(n), vsnon(n), &
trcr_base, n_trcr_strata, &
- nt_strata, trcrn(:,n))
+ nt_strata, trcrn(:,n), &
+ Tf)
enddo ! ncat
@@ -744,7 +751,8 @@ end subroutine column_conservation_check
!
! author: William H. Lipscomb, LANL
- subroutine cleanup_itd (dt, ntrcr, &
+ subroutine cleanup_itd (dt, Tf, &
+ ntrcr, &
nilyr, nslyr, &
ncat, hin_max, &
aicen, trcrn, &
@@ -774,7 +782,8 @@ subroutine cleanup_itd (dt, ntrcr, &
n_aero ! number of aerosol tracers
real (kind=dbl_kind), intent(in) :: &
- dt ! time step
+ dt , & ! time step
+ Tf ! ocean freezing temperature (Celsius)
real (kind=dbl_kind), dimension(0:ncat), intent(in) :: &
hin_max ! category boundaries (m)
@@ -916,7 +925,7 @@ subroutine cleanup_itd (dt, ntrcr, &
call rebin (ntrcr, trcr_depend, &
trcr_base, &
n_trcr_strata, &
- nt_strata, &
+ nt_strata, Tf, &
aicen, trcrn, &
vicen, vsnon, &
ncat, hin_max, &
@@ -929,7 +938,8 @@ subroutine cleanup_itd (dt, ntrcr, &
!-----------------------------------------------------------------
if (limit_aice) then
- call zap_small_areas (dt, ntrcr, &
+ call zap_small_areas (dt, Tf, &
+ ntrcr, &
ncat, n_aero, &
nblyr, &
nilyr, nslyr, &
@@ -1016,7 +1026,8 @@ end subroutine cleanup_itd
!
! author: William H. Lipscomb, LANL
- subroutine zap_small_areas (dt, ntrcr, &
+ subroutine zap_small_areas (dt, Tf, &
+ ntrcr, &
ncat, n_aero, &
nblyr, &
nilyr, nslyr, &
@@ -1035,7 +1046,8 @@ subroutine zap_small_areas (dt, ntrcr, &
nt_apnd, nt_hpnd, nt_fbri, tr_brine, nt_bgc_S, &
bio_index
use ice_colpkg_shared, only: solve_zsal, skl_bgc, z_tracers, min_salin, &
- sk_l, rhosi
+ rhosi
+ use ice_constants_colpkg, only: sk_l
use ice_zbgc_shared, only: zap_small_bgc
integer (kind=int_kind), intent(in) :: &
@@ -1048,7 +1060,8 @@ subroutine zap_small_areas (dt, ntrcr, &
nbtrcr ! number of biology tracers
real (kind=dbl_kind), intent(in) :: &
- dt ! time step
+ dt , & ! time step
+ Tf ! ocean freezing temperature (Celsius)
real (kind=dbl_kind), intent(inout) :: &
aice , & ! total ice concentration
@@ -1188,7 +1201,7 @@ subroutine zap_small_areas (dt, ntrcr, &
aice0 = aice0 + aicen(n)
aicen(n) = c0
vicen(n) = c0
- trcrn(nt_Tsfc,n) = Tocnfrz
+ trcrn(nt_Tsfc,n) = Tf
!-----------------------------------------------------------------
! Zap snow
@@ -1382,7 +1395,7 @@ subroutine zap_snow(dt, nslyr, &
endif ! tr_aero
if (z_tracers) then
- dvssl = min(p5*vsnon, hs_ssl*aicen) !snow surface layer
+ dvssl = min(p5*vsnon/real(nslyr,kind=dbl_kind), hs_ssl*aicen) !snow surface layer
dvint = vsnon- dvssl !snow interior
do it = 1, nbtrcr
diff --git a/src/core_seaice/column/ice_mechred.F90 b/src/core_seaice/column/ice_mechred.F90
index 668621fee7..2754cd1c2a 100644
--- a/src/core_seaice/column/ice_mechred.F90
+++ b/src/core_seaice/column/ice_mechred.F90
@@ -100,7 +100,8 @@ subroutine ridge_ice (dt, ndtd, &
aredistn, vredistn, &
dardg1ndt, dardg2ndt, &
dvirdgndt, &
- araftn, vraftn)
+ araftn, vraftn, &
+ Tf)
use ice_colpkg_tracers, only: nt_qice, nt_qsno, nt_fbri, nt_sice
@@ -114,7 +115,8 @@ subroutine ridge_ice (dt, ndtd, &
real (kind=dbl_kind), intent(in) :: &
mu_rdg , & ! gives e-folding scale of ridged ice (m^.5)
- dt ! time step
+ dt , & ! time step
+ Tf ! ocean freezing temperature (C)
real (kind=dbl_kind), dimension(0:ncat), intent(inout) :: &
hin_max ! category limits (m)
@@ -371,7 +373,8 @@ subroutine ridge_ice (dt, ndtd, &
msnow_mlt, esnow_mlt, &
maero, mpond, &
l_stop, stop_label, &
- aredistn, vredistn)
+ aredistn, vredistn, &
+ Tf)
if (l_stop) return
@@ -1043,7 +1046,8 @@ subroutine ridge_shift (ntrcr, dt, &
msnow_mlt, esnow_mlt, &
maero, mpond, &
l_stop, stop_label, &
- aredistn, vredistn)
+ aredistn, vredistn, &
+ Tf)
use ice_colpkg_tracers, only: nt_qsno, nt_fbri, &
nt_alvl, nt_vlvl, nt_aero, tr_aero, &
@@ -1058,7 +1062,8 @@ subroutine ridge_shift (ntrcr, dt, &
krdg_redist ! selects redistribution function
real (kind=dbl_kind), intent(in) :: &
- dt ! time step (s)
+ dt, & ! time step (s)
+ Tf ! ocean freezing temperature (C)
integer (kind=int_kind), dimension (:), intent(in) :: &
trcr_depend, & ! = 0 for aicen tracers, 1 for vicen, 2 for vsnon
@@ -1529,7 +1534,8 @@ subroutine ridge_shift (ntrcr, dt, &
atrcrn(:,n), aicen(n), &
vicen(n), vsnon(n), &
trcr_base, n_trcr_strata, &
- nt_strata, trcrn(:,n))
+ nt_strata, trcrn(:,n), &
+ Tf)
enddo
end subroutine ridge_shift
diff --git a/src/core_seaice/column/ice_meltpond_cesm.F90 b/src/core_seaice/column/ice_meltpond_cesm.F90
index 815b6b4c4e..47d926d113 100644
--- a/src/core_seaice/column/ice_meltpond_cesm.F90
+++ b/src/core_seaice/column/ice_meltpond_cesm.F90
@@ -35,7 +35,8 @@ subroutine compute_ponds_cesm(dt, hi_min, &
rfrac, meltt, &
melts, frain, &
aicen, vicen, vsnon, &
- Tsfcn, apnd, hpnd)
+ Tsfcn, apnd, hpnd, &
+ meltsliqn, use_smliq_pnd)
real (kind=dbl_kind), intent(in) :: &
dt, & ! time step (s)
@@ -43,6 +44,7 @@ subroutine compute_ponds_cesm(dt, hi_min, &
pndaspect ! ratio of pond depth to pond fraction
real (kind=dbl_kind), intent(in) :: &
+ meltsliqn, & ! liquid input from snow liquid tracer
rfrac, & ! water fraction retained for melt ponds
meltt, &
melts, &
@@ -58,6 +60,9 @@ subroutine compute_ponds_cesm(dt, hi_min, &
apnd, &
hpnd
+ logical (kind=log_kind), intent(in) :: &
+ use_smliq_pnd ! use snow liquid and ice tracers
+
! local temporary variables
real (kind=dbl_kind) :: &
@@ -104,11 +109,18 @@ subroutine compute_ponds_cesm(dt, hi_min, &
!-----------------------------------------------------------
! Update pond volume
!-----------------------------------------------------------
- volpn = volpn &
+ if (use_smliq_pnd) then
+ volpn = volpn &
+ + rfrac/rhofresh*(meltt*rhoi &
+ + meltsliqn) &
+ * aicen
+ else
+ volpn = volpn &
+ rfrac/rhofresh*(meltt*rhoi &
+ melts*rhos &
+ frain* dt)&
* aicen
+ endif
!-----------------------------------------------------------
! Shrink pond volume under freezing conditions
diff --git a/src/core_seaice/column/ice_meltpond_lvl.F90 b/src/core_seaice/column/ice_meltpond_lvl.F90
index 8a2dbe0b6e..ada156d6be 100644
--- a/src/core_seaice/column/ice_meltpond_lvl.F90
+++ b/src/core_seaice/column/ice_meltpond_lvl.F90
@@ -41,7 +41,8 @@ subroutine compute_ponds_lvl(dt, nilyr, &
aicen, vicen, vsnon, &
qicen, sicen, &
Tsfcn, alvl, &
- apnd, hpnd, ipnd)
+ apnd, hpnd, ipnd, &
+ meltsliqn, use_smliq_pnd)
integer (kind=int_kind), intent(in) :: &
nilyr, & ! number of ice layers
@@ -68,7 +69,8 @@ subroutine compute_ponds_lvl(dt, nilyr, &
fsurfn,& ! atm-ice surface heat flux (W/m2)
aicen, & ! ice area fraction
vicen, & ! ice volume (m)
- vsnon ! snow volume (m)
+ vsnon, & ! snow volume (m)
+ meltsliqn ! liquid contribution to meltponds in dt (kg/m^2)
real (kind=dbl_kind), &
intent(inout) :: &
@@ -86,6 +88,9 @@ subroutine compute_ponds_lvl(dt, nilyr, &
intent(out) :: &
ffrac ! fraction of fsurfn over pond used to melt ipond
+ logical (kind=log_kind), intent(in) :: &
+ use_smliq_pnd ! use snow liquid and ice tracers
+
! local temporary variables
real (kind=dbl_kind) :: &
@@ -151,9 +156,14 @@ subroutine compute_ponds_lvl(dt, nilyr, &
! update pond volume
!-----------------------------------------------------------
! add melt water
- dvn = rfrac/rhofresh*(meltt*rhoi &
+ if (use_smliq_pnd) then
+ dvn = rfrac/rhofresh*(meltt*rhoi &
+ + meltsliqn)*aicen
+ else
+ dvn = rfrac/rhofresh*(meltt*rhoi &
+ melts*rhos &
+ frain* dt)*aicen
+ endif
! shrink pond volume under freezing conditions
if (trim(frzpnd) == 'cesm') then
diff --git a/src/core_seaice/column/ice_mushy_physics.F90 b/src/core_seaice/column/ice_mushy_physics.F90
index 3279de5250..9f2bf32a89 100644
--- a/src/core_seaice/column/ice_mushy_physics.F90
+++ b/src/core_seaice/column/ice_mushy_physics.F90
@@ -4,7 +4,7 @@ module ice_mushy_physics
use ice_constants_colpkg, only: c0, c1, c2, c4, c8, c10, c1000, &
p001, p01, p05, p1, p2, p5, pi, bignum, puny, ice_ref_salinity, &
viscosity_dyn, rhow, rhoi, rhos, cp_ocn, cp_ice, Lfresh, gravit, &
- hs_min, ksno
+ ksno
implicit none
diff --git a/src/core_seaice/column/ice_shortwave.F90 b/src/core_seaice/column/ice_shortwave.F90
index 5c1d1a1593..506b98505d 100644
--- a/src/core_seaice/column/ice_shortwave.F90
+++ b/src/core_seaice/column/ice_shortwave.F90
@@ -45,8 +45,10 @@ module ice_shortwave
use ice_constants_colpkg, only: c0, c1, c1p5, c2, c3, c4, c10, &
p01, p1, p15, p25, p5, p75, puny, &
albocn, Timelt, snowpatch, awtvdr, awtidr, awtvdf, awtidf, &
- kappav, hs_min, rhofresh, rhos, nspint
+ kappav, hs_min, rhofresh, rhos, nspint, nspint_5bd, snwlvlfac
use ice_colpkg_shared, only: hi_ssl, hs_ssl, modal_aero, max_aero
+ use ice_colpkg_shared, only: hi_ssl, hs_ssl, modal_aero, rsnw_fall, &
+ rsnw_tmax
use ice_warnings, only: add_warning
implicit none
@@ -684,6 +686,8 @@ subroutine run_dEdd(dt, tr_aero, &
vsnon, Tsfcn, &
alvln, apndn, &
hpndn, ipndn, &
+ snwredist, &
+ rsnow, tr_rsnw, &
aeron, kalg, &
zbion, &
heat_capacity, &
@@ -715,8 +719,23 @@ subroutine run_dEdd(dt, tr_aero, &
albpndn, apeffn, &
snowfracn, &
dhsn, ffracn, &
+ rsnw_dEddn, &
l_print_point, &
- initonly)
+ initonly, &
+ use_snicar, &
+ asm_prm_ice_drc, &
+ asm_prm_ice_dfs, &
+ ss_alb_ice_drc, &
+ ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, &
+ ext_cff_mss_ice_dfs, &
+ kaer_tab_5bd, &
+ waer_tab_5bd, &
+ gaer_tab_5bd, &
+ kaer_bc_tab_5bd, &
+ waer_bc_tab_5bd, &
+ gaer_bc_tab_5bd, &
+ bcenh_5bd)
use ice_orbital, only: compute_coszen
@@ -737,6 +756,7 @@ subroutine run_dEdd(dt, tr_aero, &
tr_pond_cesm, & ! if .true., use explicit topography-based ponds
tr_pond_lvl , & ! if .true., use explicit topography-based ponds
tr_pond_topo, & ! if .true., use explicit topography-based ponds
+ tr_rsnw, & ! if .true., use snow grain radius tracer
dEdd_algae, & ! .true. use prognostic chla in dEdd
tr_bgc_N, & ! .true. active bgc (skl or z)
tr_zaero, & ! .true. use zaerosols
@@ -765,6 +785,27 @@ subroutine run_dEdd(dt, tr_aero, &
waer_bc_tab, & ! aerosol single scatter albedo (fraction)
gaer_bc_tab ! aerosol asymmetry parameter (cos(theta))
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Model SNICAR snow SSP
+ asm_prm_ice_drc, & ! snow asymmetry factor (cos(theta))
+ asm_prm_ice_dfs, & ! snow asymmetry factor (cos(theta))
+ ss_alb_ice_drc, & ! snow single scatter albedo (fraction)
+ ss_alb_ice_dfs, & ! snow single scatter albedo (fraction)
+ ext_cff_mss_ice_drc, & ! snow mass extinction cross section (m2/kg)
+ ext_cff_mss_ice_dfs ! snow mass extinction cross section (m2/kg)
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: &
+ kaer_tab_5bd, & ! aerosol mass extinction cross section (m2/kg)
+ waer_tab_5bd, & ! aerosol single scatter albedo (fraction)
+ gaer_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Modal aerosol treatment
+ kaer_bc_tab_5bd, & ! aerosol mass extinction cross section (m2/kg)
+ waer_bc_tab_5bd, & ! aerosol single scatter albedo (fraction)
+ gaer_bc_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:,:), intent(in) :: & ! Modal aerosol treatment
+ bcenh_5bd ! BC absorption enhancement factor
+
real (kind=dbl_kind), dimension(:,:,:), intent(in) :: & ! Modal aerosol treatment
bcenh ! BC absorption enhancement factor
@@ -800,11 +841,16 @@ subroutine run_dEdd(dt, tr_aero, &
hpndn, & ! pond depth (m)
ipndn ! pond refrozen lid thickness (m)
+ character(len=char_len), intent(in) :: &
+ snwredist ! type of snow redistribution
+
real(kind=dbl_kind), dimension(:,:), intent(in) :: &
+ rsnow, & ! snow grain radius tracer (10^-6 m)
aeron, & ! aerosols (kg/m^3)
zbion ! zaerosols (kg/m^3) + chlorophyll on shorthwave grid
real(kind=dbl_kind), dimension(:), intent(inout) :: &
+ rsnw_dEddn, & ! snow grain radius if .not. tr_rsnw (10^-6 m)
dhsn ! depth difference for snow on sea ice and pond ice
real(kind=dbl_kind), intent(inout) :: &
@@ -829,6 +875,11 @@ subroutine run_dEdd(dt, tr_aero, &
Iswabsn , & ! SW radiation absorbed in ice layers (W m-2)
fswpenln ! visible SW entering ice layers (W m-2)
+ logical (kind=log_kind), intent(in) :: &
+ use_snicar ! if true, use 5-band snicar IOPs for
+ ! shortwave radiative calculation of
+ ! snow-coverd sea ice
+
logical (kind=log_kind), intent(in) :: &
l_print_point
@@ -841,7 +892,10 @@ subroutine run_dEdd(dt, tr_aero, &
! snow variables for Delta-Eddington shortwave
real (kind=dbl_kind) :: &
fsn , & ! snow horizontal fraction
- hsn ! snow depth (m)
+ hsn , & ! snow depth (m)
+ hsnlvl , & ! snow depth over level ice (m)
+ vsn , & ! snow volume
+ alvl ! area fraction of level ice
real (kind=dbl_kind), dimension (nslyr) :: &
rhosnwn , & ! snow density (kg/m3)
@@ -854,6 +908,7 @@ subroutine run_dEdd(dt, tr_aero, &
integer (kind=int_kind) :: &
n , & ! thickness category index
+ k , & ! snow layer index
na ! aerosol index
real (kind=dbl_kind) :: &
@@ -865,6 +920,7 @@ subroutine run_dEdd(dt, tr_aero, &
hmx , & ! maximum available snow infiltration equivalent depth
dhs , & ! local difference in snow depth on sea ice and pond ice
spn , & ! snow depth on refrozen pond (m)
+ rnslyr , & ! 1/nslyr
tmp ! 0 or 1
logical (kind=log_kind) :: &
@@ -898,6 +954,7 @@ subroutine run_dEdd(dt, tr_aero, &
rsnwn(:) = c0
apeffn(n) = c0 ! for history
snowfracn(n) = c0 ! for history
+ rsnw_dEddn(n) = c0 ! for history
if (aicen(n) > puny) then
@@ -906,7 +963,8 @@ subroutine run_dEdd(dt, tr_aero, &
aicen(n), vsnon(n), &
Tsfcn(n), fsn, &
hs0, hsn, &
- rhosnwn, rsnwn)
+ rhosnwn, rsnwn, &
+ rsnow(:,n), tr_rsnw)
! set pond properties
if (tr_pond_cesm) then
@@ -925,6 +983,26 @@ subroutine run_dEdd(dt, tr_aero, &
fsn = min(fsn, c1-fpn)
apeffn(n) = fpn ! for history
elseif (tr_pond_lvl) then
+ hsnlvl = hsn ! initialize
+ if (trim(snwredist) == '30percentsw') then
+ hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n)))
+ ! snow volume over level ice
+ alvl = aicen(n) * alvln(n)
+ if (alvl > puny) then
+ vsn = hsnlvl * alvl
+ else
+ vsn = vsnon(n)
+ alvl = aicen(n)
+ endif
+ ! set snow properties over level ice
+ call shortwave_dEdd_set_snow(nslyr, R_snw, &
+ dT_mlt, rsnw_mlt, &
+ alvl, vsn, &
+ Tsfcn(n), fsn, &
+ hs0, hsnlvl, &
+ rhosnwn(:), rsnwn(:), &
+ rsnow(:,n), tr_rsnw)
+ endif ! snwredist
fpn = c0 ! fraction of ice covered in pond
hpn = c0 ! pond depth over fpn
! refrozen pond lid thickness avg over ice
@@ -933,8 +1011,8 @@ subroutine run_dEdd(dt, tr_aero, &
dhs = dhsn(n) ! snow depth difference, sea ice - pond
if (.not. linitonly .and. ipn > puny .and. &
dhs < puny .and. fsnow*dt > hs_min) &
- dhs = hsn - fsnow*dt ! initialize dhs>0
- spn = hsn - dhs ! snow depth on pond ice
+ dhs = hsnlvl - fsnow*dt ! initialize dhs>0
+ spn = hsnlvl - dhs ! snow depth on pond ice
if (.not. linitonly .and. ipn*spn < puny) dhs = c0
dhsn(n) = dhs ! save: constant until reset to 0
@@ -959,7 +1037,7 @@ subroutine run_dEdd(dt, tr_aero, &
! infiltrate snow
hp = hpn
if (hp > puny) then
- hs = hsn
+ hs = hsnlvl ! melt ponds reside on level ice
rp = rhofresh*hp/(rhofresh*hp + rhos*hs)
if (rp < p15) then
fpn = c0
@@ -968,8 +1046,9 @@ subroutine run_dEdd(dt, tr_aero, &
hmx = hs*(rhofresh - rhos)/rhofresh
tmp = max(c0, sign(c1, hp-hmx)) ! 1 if hp>=hmx, else 0
hp = (rhofresh*hp + rhos*hs*tmp) &
- / (rhofresh - rhos*(c1-tmp))
- hsn = hs - hp*fpn*(c1-tmp)
+ / (rhofresh - rhos*(c1-tmp))
+!echmod hsn = hs - hp*fpn*(c1-tmp)
+ hsn = hsn - hp*fpn*(c1-tmp)
hpn = hp * tmp
fpn = fpn * tmp
endif
@@ -1015,7 +1094,7 @@ subroutine run_dEdd(dt, tr_aero, &
fpn = c0
hpn = c0
endif ! pond type
-
+
snowfracn(n) = fsn ! for history
call shortwave_dEdd(n_aero, n_zaero, &
@@ -1035,7 +1114,7 @@ subroutine run_dEdd(dt, tr_aero, &
kaer_bc_tab, &
waer_bc_tab, &
gaer_bc_tab, &
- bcenh, modal_aero, &
+ bcenh, modal_aero, &
kalg, &
swvdr, swvdf, &
swidr, swidf, &
@@ -1048,7 +1127,28 @@ subroutine run_dEdd(dt, tr_aero, &
albicen(n), &
albsnon(n), albpndn(n), &
fswpenln(:,n), zbion(:,n), &
- l_print_point)
+ l_print_point, &
+ use_snicar, &
+ asm_prm_ice_drc, &
+ asm_prm_ice_dfs, &
+ ss_alb_ice_drc, &
+ ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, &
+ ext_cff_mss_ice_dfs, &
+ kaer_tab_5bd, &
+ waer_tab_5bd, &
+ gaer_tab_5bd, &
+ kaer_bc_tab_5bd, &
+ waer_bc_tab_5bd, &
+ gaer_bc_tab_5bd, &
+ bcenh_5bd)
+
+ if (.not. tr_rsnw) then
+ rnslyr = c1/max(c1,(real(nslyr,kind=dbl_kind)))
+ do k = 1,nslyr
+ rsnw_dEddn(n) = rsnw_dEddn(n) + rsnwn(k)*rnslyr
+ enddo
+ endif
endif ! aicen > puny
@@ -1113,7 +1213,21 @@ subroutine shortwave_dEdd (n_aero, n_zaero, &
Iswabs, albice, &
albsno, albpnd, &
fswpenl, zbio, &
- l_print_point)
+ l_print_point, &
+ use_snicar, &
+ asm_prm_ice_drc, &
+ asm_prm_ice_dfs, &
+ ss_alb_ice_drc, &
+ ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, &
+ ext_cff_mss_ice_dfs, &
+ kaer_tab_5bd, &
+ waer_tab_5bd, &
+ gaer_tab_5bd, &
+ kaer_bc_tab_5bd, &
+ waer_bc_tab_5bd, &
+ gaer_bc_tab_5bd, &
+ bcenh_5bd)
integer (kind=int_kind), intent(in) :: &
nilyr , & ! number of ice layers
@@ -1189,6 +1303,11 @@ subroutine shortwave_dEdd (n_aero, n_zaero, &
albsno , & ! snow albedo, for history
albpnd ! pond albedo, for history
+ logical (kind=log_kind), intent(in) :: &
+ use_snicar ! if true, use 5-band snicar IOPs for
+ ! shortwave radiative calculation of
+ ! snow-coverd sea ice
+
logical (kind=log_kind) , intent(in) :: &
l_print_point
@@ -1236,6 +1355,29 @@ subroutine shortwave_dEdd (n_aero, n_zaero, &
character(len=char_len_long) :: &
warning ! warning message
+ ! snow grain single-scattering properties for
+ ! direct (drc) and diffuse (dfs) shortwave incidents
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Model SNICAR snow SSP
+ asm_prm_ice_drc, & ! snow asymmetry factor (cos(theta))
+ asm_prm_ice_dfs, & ! snow asymmetry factor (cos(theta))
+ ss_alb_ice_drc, & ! snow single scatter albedo (fraction)
+ ss_alb_ice_dfs, & ! snow single scatter albedo (fraction)
+ ext_cff_mss_ice_drc, & ! snow mass extinction cross section (m2/kg)
+ ext_cff_mss_ice_dfs ! snow mass extinction cross section (m2/kg)
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: &
+ kaer_tab_5bd, & ! aerosol mass extinction cross section (m2/kg)
+ waer_tab_5bd, & ! aerosol single scatter albedo (fraction)
+ gaer_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Modal aerosol treatment
+ kaer_bc_tab_5bd, & ! aerosol mass extinction cross section (m2/kg)
+ waer_bc_tab_5bd, & ! aerosol single scatter albedo (fraction)
+ gaer_bc_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:,:), intent(in) :: & ! Modal aerosol treatment
+ bcenh_5bd ! BC absorption enhancement factor
+
!-----------------------------------------------------------------------
klev = nslyr + nilyr + 1 ! number of radiation layers - 1
@@ -1257,6 +1399,7 @@ subroutine shortwave_dEdd (n_aero, n_zaero, &
fswsfc = c0
fswint = c0
fswthru = c0
+
! compute fraction of nir down direct to total over all points:
fnidr = c0
if( swidr + swidf > puny ) then
@@ -1339,22 +1482,52 @@ subroutine shortwave_dEdd (n_aero, n_zaero, &
! calculate snow covered sea ice
srftyp = 1
- call compute_dEdd(nilyr, nslyr, klev, klevp, &
- n_zaero, zbio, dEdd_algae, &
- nlt_chl_sw,nlt_zaero_sw, tr_bgc_N, &
- tr_zaero, &
- heat_capacity, fnidr, coszen, &
- n_aero, tr_aero, R_ice, R_pnd, &
- kaer_tab, waer_tab, gaer_tab, &
- kaer_bc_tab, waer_bc_tab, gaer_bc_tab, &
- bcenh, modal_aero, kalg, &
- swvdr, swvdf, swidr, swidf, srftyp, &
- hs, rhosnw, rsnw, hi, hp, &
- fs, aero_mp, avdrl, avdfl, &
- aidrl, aidfl, &
- fswsfc, fswint, &
- fswthru, Sswabs, &
- Iswabs, fswpenl)
+ if (use_snicar) then ! use 5-band snicar IOPs for snow
+ call compute_dEdd_5bd(nilyr, nslyr, klev, klevp, &
+ n_zaero, zbio, dEdd_algae, &
+ nlt_chl_sw,nlt_zaero_sw, tr_bgc_N, &
+ tr_zaero, &
+ heat_capacity, fnidr, coszen, &
+ n_aero, tr_aero, R_ice, R_pnd, &
+ kaer_tab_5bd, waer_tab_5bd, gaer_tab_5bd, &
+ kaer_bc_tab_5bd, waer_bc_tab_5bd, gaer_bc_tab_5bd,&
+ bcenh_5bd, modal_aero, kalg, &
+ swvdr, swvdf, swidr, swidf, srftyp, &
+ hs, rhosnw, rsnw, hi, hp, &
+ fs, aero_mp, avdrl, avdfl, &
+ aidrl, aidfl, &
+ fswsfc, fswint, &
+ fswthru, Sswabs, &
+ Iswabs, fswpenl, &
+ asm_prm_ice_drc, asm_prm_ice_dfs, &
+ ss_alb_ice_drc, ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, ext_cff_mss_ice_dfs)
+
+ alvdr = alvdr + avdrl *fs
+ alvdf = alvdf + avdfl *fs
+ alidr = alidr + aidrl *fs
+ alidf = alidf + aidfl *fs
+ ! for history
+ albsno = albsno &
+ + awtvdr*avdrl + awtidr*aidrl &
+ + awtvdf*avdfl + awtidf*aidfl
+ else ! use 3 band IOPs for snow
+ call compute_dEdd(nilyr, nslyr, klev, klevp, &
+ n_zaero, zbio, dEdd_algae, &
+ nlt_chl_sw,nlt_zaero_sw, tr_bgc_N, &
+ tr_zaero, &
+ heat_capacity, fnidr, coszen, &
+ n_aero, tr_aero, R_ice, R_pnd, &
+ kaer_tab, waer_tab, gaer_tab, &
+ kaer_bc_tab, waer_bc_tab, gaer_bc_tab, &
+ bcenh, modal_aero, kalg, &
+ swvdr, swvdf, swidr, swidf, srftyp, &
+ hs, rhosnw, rsnw, hi, hp, &
+ fs, aero_mp, avdrl, avdfl, &
+ aidrl, aidfl, &
+ fswsfc, fswint, &
+ fswthru, Sswabs, &
+ Iswabs, fswpenl)
alvdr = alvdr + avdrl *fs
alvdf = alvdf + avdfl *fs
@@ -1364,9 +1537,11 @@ subroutine shortwave_dEdd (n_aero, n_zaero, &
albsno = albsno &
+ awtvdr*avdrl + awtidr*aidrl &
+ awtvdf*avdfl + awtidf*aidfl
+ endif ! end if using 5band snicar subroutine
+
endif
endif
-
+
hi = c0
! sea ice points with sun above horizon
@@ -2368,15 +2543,12 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
g(k) = gs
enddo ! k
-
! aerosol in snow
- if (tr_zaero .and. dEdd_algae) then
+ if (tr_zaero .and. dEdd_algae) then
do k = 0,nslyr
- gzaer(ns,k) = gzaer(ns,k)/(wzaer(ns,k)+puny)
- wzaer(ns,k) = wzaer(ns,k)/(tzaer(ns,k)+puny)
- g(k) = (g(k)*w0(k)*tau(k) + gzaer(ns,k)*wzaer(ns,k)*tzaer(ns,k)) / &
- (w0(k)*tau(k) + wzaer(ns,k)*tzaer(ns,k))
- w0(k) = (w0(k)*tau(k) + wzaer(ns,k)*tzaer(ns,k)) / &
+ g(k) = (g(k)*w0(k)*tau(k) + gzaer(ns,k)) / &
+ (w0(k)*tau(k) + wzaer(ns,k))
+ w0(k) = (w0(k)*tau(k) + wzaer(ns,k)) / &
(tau(k) + tzaer(ns,k))
tau(k) = tau(k) + tzaer(ns,k)
enddo
@@ -2389,7 +2561,7 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
do na=1,4*n_aero,4
! mgf++
if (modal_aero) then
- if (na == 1) then
+ if (na == 1) then
!interstitial BC
taer = taer + &
aero_mp(na)*kaer_bc_tab(ns,k_bcexs(k))
@@ -2399,7 +2571,7 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
gaer = gaer + &
aero_mp(na)*kaer_bc_tab(ns,k_bcexs(k))* &
waer_bc_tab(ns,k_bcexs(k))*gaer_bc_tab(ns,k_bcexs(k))
- elseif (na == 5)then
+ elseif (na == 5)then
!within-ice BC
taer = taer + &
aero_mp(na)*kaer_bc_tab(ns,k_bcins(k))* &
@@ -2464,7 +2636,7 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
gaer = gaer + &
(aero_mp(na+1)/rnslyr)*kaer_bc_tab(ns,k_bcins(k))* &
waer_bc_tab(ns,k_bcins(k))*gaer_bc_tab(ns,k_bcins(k))
-
+
else
! other species (dust)
taer = taer + &
@@ -2510,9 +2682,9 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
! no aerosol in pond
enddo ! k
endif ! srftyp
-
+
! set optical properties of sea ice
-
+
! bare or snow-covered sea ice layers
if( srftyp <= 1 ) then
! ssl
@@ -2542,7 +2714,7 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
if( ns == 1 ) then
! total layer absorption optical depth fixed at value
! of kalg*0.50m, independent of actual layer thickness
- kabs = kabs + kabs_chl(ns,k)
+ kabs = kabs + kabs_chl(ns,k)
endif
sig = ki_int(ns)*wi_int(ns)
tau(k) = (kabs+sig)*dzk(k)
@@ -2550,16 +2722,14 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
g(k) = gi_int(ns)
! aerosol in sea ice
if (tr_zaero .and. dEdd_algae) then
- do k = kii, klev
- gzaer(ns,k) = gzaer(ns,k)/(wzaer(ns,k)+puny)
- wzaer(ns,k) = wzaer(ns,k)/(tzaer(ns,k)+puny)
- g(k) = (g(k)*w0(k)*tau(k) + gzaer(ns,k)*wzaer(ns,k)*tzaer(ns,k)) / &
- (w0(k)*tau(k) + wzaer(ns,k)*tzaer(ns,k))
- w0(k) = (w0(k)*tau(k) + wzaer(ns,k)*tzaer(ns,k)) / &
+ do k = kii, klev
+ g(k) = (g(k)*w0(k)*tau(k) + gzaer(ns,k))/ &
+ (w0(k)*tau(k) + wzaer(ns,k))
+ w0(k) = (w0(k)*tau(k) + wzaer(ns,k)) / &
(tau(k) + tzaer(ns,k))
tau(k) = tau(k) + tzaer(ns,k)
enddo
- elseif (tr_aero) then
+ elseif (tr_aero) then
k = kii ! sea ice SSL
taer = c0
waer = c0
@@ -2587,7 +2757,7 @@ subroutine compute_dEdd (nilyr, nslyr, klev, klevp, &
waer_bc_tab(ns,k_bcins(k))
gaer = gaer + &
aero_mp(na+2)*kaer_bc_tab(ns,k_bcins(k))* &
- waer_bc_tab(ns,k_bcins(k))*gaer_bc_tab(ns,k_bcins(k))
+ waer_bc_tab(ns,k_bcins(k))*gaer_bc_tab(ns,k_bcins(k))
else
! other species (dust)
taer = taer + &
@@ -3452,7 +3622,8 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, &
aice, vsno, &
Tsfc, fs, &
hs0, hs, &
- rhosnw, rsnw)
+ rhosnw, rsnw, &
+ rsnow, tr_rsnw)
integer (kind=int_kind), intent(in) :: &
nslyr ! number of snow layers
@@ -3472,10 +3643,16 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, &
fs , & ! horizontal coverage of snow
hs ! snow depth
- real (kind=dbl_kind), dimension (:), intent(out) :: &
+ real (kind=dbl_kind), dimension (:), intent(in) :: &
+ rsnow ! snow grain radius tracer (micro-meters)
+
+ real (kind=dbl_kind), dimension (:), intent(inout) :: &
rhosnw , & ! density in snow layer (kg/m3)
rsnw ! grain radius in snow layer (micro-meters)
+ logical(kind=log_kind), intent(in) :: &
+ tr_rsnw ! if true, use rsnow
+
! local variables
integer (kind=int_kind) :: &
@@ -3502,23 +3679,36 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, &
if (hs0 > puny) fs = min(hs/hs0, c1)
endif
- ! bare ice, temperature dependence
- dTs = Timelt - Tsfc
- fT = -min(dTs/dT_mlt-c1,c0)
- ! tune nonmelt snow grain radius if desired: note that
- ! the sign is negative so that if R_snw is 1, then the
- ! snow grain radius is reduced and thus albedo increased.
- rsnw_nm = rsnw_nonmelt - R_snw*rsnw_sig
- rsnw_nm = max(rsnw_nm, rsnw_fresh)
- rsnw_nm = min(rsnw_nm, rsnw_mlt)
- do ks = 1, nslyr
- ! snow density ccsm3 constant value
- rhosnw(ks) = rhos
- ! snow grain radius between rsnw_nonmelt and rsnw_mlt
- rsnw(ks) = rsnw_nm + (rsnw_mlt-rsnw_nm)*fT
- rsnw(ks) = max(rsnw(ks), rsnw_fresh)
- rsnw(ks) = min(rsnw(ks), rsnw_mlt)
- enddo ! ks
+ if (tr_rsnw) then !use snow grain tracer
+
+ do ks = 1, nslyr
+ rsnw(ks) = max(rsnw_fall,rsnow(ks))
+ rsnw(ks) = min(rsnw_tmax,rsnw(ks))
+ rhosnw(ks) = rhos
+ enddo
+
+ else
+
+ ! bare ice, temperature dependence
+ dTs = Timelt - Tsfc
+ fT = -min(dTs/dT_mlt-c1,c0)
+ ! tune nonmelt snow grain radius if desired: note that
+ ! the sign is negative so that if R_snw is 1, then the
+ ! snow grain radius is reduced and thus albedo increased.
+ rsnw_nm = rsnw_nonmelt - R_snw*rsnw_sig
+ rsnw_nm = max(rsnw_nm, rsnw_fresh)
+ rsnw_nm = min(rsnw_nm, rsnw_mlt)
+
+ do ks = 1, nslyr
+ ! snow density ccsm3 constant value
+ rhosnw(ks) = rhos
+ ! snow grain radius between rsnw_nonmelt and rsnw_mlt
+ rsnw(ks) = rsnw_nm + (rsnw_mlt-rsnw_nm)*fT
+ rsnw(ks) = max(rsnw(ks), rsnw_fresh)
+ rsnw(ks) = min(rsnw(ks), rsnw_mlt)
+ enddo ! ks
+
+ endif
end subroutine shortwave_dEdd_set_snow
@@ -3577,23 +3767,23 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
nbtrcr_sw, n_zaero, &
skl_bgc, z_tracers, &
l_stop, stop_label)
-
- use ice_constants_colpkg, only: c0, c1, c2, p5
+
+ use ice_constants_colpkg, only: c0, c1, c2, p5, sk_l
use ice_colpkg_tracers, only: nt_bgc_N, nt_zaero, tr_bgc_N, &
tr_zaero, nlt_chl_sw, nlt_zaero_sw
- use ice_colpkg_shared, only: dEdd_algae, bgc_flux_type, sk_l, &
+ use ice_colpkg_shared, only: dEdd_algae, bgc_flux_type, &
R_chl2N, min_bgc, F_abs_chl, hi_ssl
use ice_zbgc_shared, only: remap_zbgc
integer (kind=int_kind), intent(in) :: &
nslyr, & ! number of snow layers
- n_zaero , & ! number of cells with aicen > puny
+ n_zaero , & ! number of cells with aicen > puny
nbtrcr_sw, n_algae, & ! nilyr+nslyr+2 for chlorophyll
ntrcr
integer (kind=int_kind), intent(in) :: &
nblyr , & ! number of bio layers
- nilyr ! number of ice layers
+ nilyr ! number of ice layers
real (kind=dbl_kind), dimension (ntrcr), intent(in) :: &
trcrn ! aerosol or chlorophyll
@@ -3603,20 +3793,20 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
trcrn_sw ! ice on shortwave grid tracers
real (kind=dbl_kind), dimension (:), intent(in) :: &
- sw_grid , & !
- i_grid ! CICE bio grid
-
+ sw_grid , & !
+ i_grid ! CICE bio grid
+
real(kind=dbl_kind), intent(in) :: &
hin , & ! CICE ice thickness
- hbri ! brine height
+ hbri ! brine height
logical (kind=log_kind), intent(in) :: &
- skl_bgc, & ! skeletal layer bgc
- z_tracers ! zbgc
+ skl_bgc, & ! skeletal layer bgc
+ z_tracers ! zbgc
logical (kind=log_kind), intent(inout) :: &
l_stop ! if true, print diagnostics and abort on return
-
+
character (char_len), intent(inout) :: stop_label
! local variables
@@ -3631,7 +3821,7 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
icegrid ! correct for large ice surface layers
real (kind=dbl_kind):: &
- top_conc ! 1% (min_bgc) of surface concentration
+ top_conc ! 1% (min_bgc) of surface concentration
! when hin > hbri: just used in sw calculation
!-----------------------------------------------------------------
@@ -3644,11 +3834,11 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
do k = 1,nilyr+1
icegrid(k) = sw_grid(k)
- enddo
- if (sw_grid(1)*hin*c2 > hi_ssl) then
+ enddo
+ if (sw_grid(1)*hin*c2 > hi_ssl .and. hin > puny) then
icegrid(1) = hi_ssl/c2/hin
endif
-
+ icegrid(2) = c2*sw_grid(1) + (sw_grid(2) - sw_grid(1))
if (z_tracers) then
if (tr_bgc_N) then
do k = 1, nblyr+1
@@ -3657,7 +3847,7 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
R_chl2N(n)*F_abs_chl(n)*trcrn(nt_bgc_N(n)+k-1)
enddo ! n
enddo ! k
-
+
top_conc = trtmp0(nt_bgc_N(1))*min_bgc
call remap_zbgc (ntrcr, nilyr+1, &
nt_bgc_N(1), &
@@ -3666,8 +3856,8 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
1, nblyr+1, &
hin, hbri, &
icegrid(1:nilyr+1), &
- i_grid(1:nblyr+1), top_conc, &
- l_stop, stop_label)
+ i_grid(1:nblyr+1), top_conc, &
+ l_stop, stop_label)
if (l_stop) return
@@ -3677,11 +3867,11 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
do n = 1, n_algae ! snow contribution
trcrn_sw(nlt_chl_sw)= trcrn_sw(nlt_chl_sw) &
- + R_chl2N(n)*F_abs_chl(n)*trcrn(nt_bgc_N(n)+nblyr+1)
+ + R_chl2N(n)*F_abs_chl(n)*trcrn(nt_bgc_N(n)+nblyr+1)
! snow surface layer
trcrn_sw(nlt_chl_sw+1:nlt_chl_sw+nslyr) = &
trcrn_sw(nlt_chl_sw+1:nlt_chl_sw+nslyr) &
- + R_chl2N(n)*F_abs_chl(n)*trcrn(nt_bgc_N(n)+nblyr+2)
+ + R_chl2N(n)*F_abs_chl(n)*trcrn(nt_bgc_N(n)+nblyr+2)
! only 1 snow layer in zaero
enddo ! n
endif ! tr_bgc_N
@@ -3728,6 +3918,1494 @@ subroutine compute_shortwave_trcr(n_algae, nslyr, &
endif
end subroutine compute_shortwave_trcr
+
+!=======================================================================
+! --- Begin 5 band dEdd subroutine ---
+! Evaluate snow/ice/ponded ice inherent optical properties (IOPs), and
+! then calculate the multiple scattering solution by calling solution_dEdd.
+!
+! author: Bruce P. Briegleb, NCAR
+! 2013: E Hunke merged with NCAR version
+! 2018: Cheng Dang merged with SNICAR 5-band snow and aersols IOPs, UC Irvine
+!
+! Note by Cheng Dang 2018:
+! This subroutine kept the existing delta-eddington adding-doubling
+! method, snow and sea ice layer sturcture, and most of the code structures
+! of subroutine compute_dEdd, with major changeds listed below to merge
+! current snow treatments in SNICAR Model
+! 1. The shortwave radiative transfer properties of snow-covered sea ice are
+! calcualted for 5 bands (1 visible and 4 near-IR) defined in SNICAR
+! 2. The reflection/absorption/transmission of direct and diffuse shortwave
+! incidents are calculated seperately to remove the snow grain adjustment
+! in subroutine compute_dEdd
+! 3. The albedo and absorption of snow-covered sea ice are adjusted when solar
+! zenith angle is above 75 degree
+! 4. Comments given in subroutine compute_dEdd are all kepted in this subroutine
+! with modifications at where above changes applies to.
+! 5. This subroutine can be modified and merged with subroutine compute_dEdd
+! to compute shortwave properties of bare and ponded sea ice if requested.
+! For now, these two subroutines are seperated for testing new features.
+!
+! The justification and explaination for above changes can be find in paper:
+! Dang, C., Zender, C. S., and Flanner, M. G.: Inter-comparison and improvement
+! of 2-stream shortwave radiative transfer models for unified treatment of
+! cryospheric surfaces in ESMs, The Cryosphere Discuss.,
+! https://doi.org/10.5194/tc-2019-22, in review, 2019
+
+ subroutine compute_dEdd_5bd (nilyr, nslyr, klev, klevp, &
+ n_zaero, zbio, dEdd_algae, &
+ nlt_chl_sw,nlt_zaero_sw, tr_bgc_N, &
+ tr_zaero, &
+ heat_capacity, fnidr, coszen, &
+ n_aero, tr_aero, R_ice, R_pnd, &
+ kaer_tab_5bd, waer_tab_5bd, gaer_tab_5bd, &
+ kaer_bc_tab_5bd, waer_bc_tab_5bd, &
+ gaer_bc_tab_5bd, bcenh_5bd, modal_aero, kalg, &
+ swvdr, swvdf, swidr, swidf, srftyp, &
+ hs, rhosnw, rsnw, hi, hp, &
+ fi, aero_mp, alvdr, alvdf, &
+ alidr, alidf, &
+ fswsfc, fswint, &
+ fswthru, Sswabs, &
+ Iswabs, fswpenl, &
+ asm_prm_ice_drc, asm_prm_ice_dfs, &
+ ss_alb_ice_drc, ss_alb_ice_dfs, &
+ ext_cff_mss_ice_drc, ext_cff_mss_ice_dfs)
+
+ integer (kind=int_kind), intent(in) :: &
+ nilyr , & ! number of ice layers
+ nslyr , & ! number of snow layers
+ n_aero , & ! number of aerosol tracers
+ n_zaero , & ! number of zaerosol tracers in use
+ nlt_chl_sw , & ! index for chla
+ klev , & ! number of radiation layers - 1
+ klevp ! number of radiation interfaces - 1
+ ! (0 layer is included also)
+
+ integer (kind=int_kind), dimension(:), intent(in) :: &
+ nlt_zaero_sw ! index for zaerosols
+
+ logical (kind=log_kind), intent(in) :: &
+ heat_capacity , & ! if true, ice has nonzero heat capacity
+ tr_aero , & ! if .true., use aerosol tracers
+ dEdd_algae , & ! .true. use prognostic chla in dEdd
+ tr_bgc_N , & ! .true. active bgc (skl or z)
+ tr_zaero , & ! .true. use zaerosols
+ modal_aero ! .true. use modal aerosol treatment
+
+ ! dEdd tuning parameters, set in namelist
+ real (kind=dbl_kind), intent(in) :: &
+ R_ice , & ! sea ice tuning parameter; +1 > 1sig increase in albedo
+ R_pnd ! ponded ice tuning parameter; +1 > 1sig increase in albedo
+
+ real (kind=dbl_kind), intent(in) :: &
+ kalg , & ! algae absorption coefficient
+ fnidr , & ! fraction of direct to total down flux in nir
+ coszen , & ! cosine solar zenith angle
+ swvdr , & ! shortwave down at surface, visible, direct (W/m^2)
+ swvdf , & ! shortwave down at surface, visible, diffuse (W/m^2)
+ swidr , & ! shortwave down at surface, near IR, direct (W/m^2)
+ swidf ! shortwave down at surface, near IR, diffuse (W/m^2)
+
+ integer (kind=int_kind), intent(in) :: &
+ srftyp ! surface type over ice: (0=air, 1=snow, 2=pond)
+
+ real (kind=dbl_kind), intent(in) :: &
+ hs ! snow thickness (m)
+
+ real (kind=dbl_kind), dimension (:), intent(in) :: &
+ rhosnw , & ! snow density in snow layer (kg/m3)
+ rsnw , & ! snow grain radius in snow layer (m)
+ zbio , & ! zaerosol + chla shortwave tracers kg/m^3
+ aero_mp ! aerosol mass path in kg/m2
+
+ real (kind=dbl_kind), intent(in) :: &
+ hi , & ! ice thickness (m)
+ hp , & ! pond depth (m)
+ fi ! snow/bare ice fractional coverage (0 to 1)
+
+ real (kind=dbl_kind), intent(inout) :: &
+ alvdr , & ! visible, direct, albedo (fraction)
+ alvdf , & ! visible, diffuse, albedo (fraction)
+ alidr , & ! near-ir, direct, albedo (fraction)
+ alidf , & ! near-ir, diffuse, albedo (fraction)
+ fswsfc , & ! SW absorbed at snow/bare ice/pondedi ice surface (W m-2)
+ fswint , & ! SW interior absorption (below surface, above ocean,W m-2)
+ fswthru ! SW through snow/bare ice/ponded ice into ocean (W m-2)
+
+ real (kind=dbl_kind), dimension (:), intent(inout) :: &
+ fswpenl , & ! visible SW entering ice layers (W m-2)
+ Sswabs , & ! SW absorbed in snow layer (W m-2)
+ Iswabs ! SW absorbed in ice layer (W m-2)
+
+
+ ! snow grain single-scattering properties for
+ ! direct (drc) and diffuse (dfs) shortwave incidents
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Model SNICAR snow SSP
+ asm_prm_ice_drc , & ! snow asymmetry factor (cos(theta))
+ asm_prm_ice_dfs , & ! snow asymmetry factor (cos(theta))
+ ss_alb_ice_drc , & ! snow single scatter albedo (fraction)
+ ss_alb_ice_dfs , & ! snow single scatter albedo (fraction)
+ ext_cff_mss_ice_drc , & ! snow mass extinction cross section (m2/kg)
+ ext_cff_mss_ice_dfs ! snow mass extinction cross section (m2/kg)
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: &
+ kaer_tab_5bd , & ! aerosol mass extinction cross section (m2/kg)
+ waer_tab_5bd , & ! aerosol single scatter albedo (fraction)
+ gaer_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:), intent(in) :: & ! Modal aerosol treatment
+ kaer_bc_tab_5bd , & ! aerosol mass extinction cross section (m2/kg)
+ waer_bc_tab_5bd , & ! aerosol single scatter albedo (fraction)
+ gaer_bc_tab_5bd ! aerosol asymmetry parameter (cos(theta))
+
+ real (kind=dbl_kind), dimension(:,:,:), intent(in) :: & ! Modal aerosol treatment
+ bcenh_5bd ! BC absorption enhancement factor
+
+!-----------------------------------------------------------------------
+! Set up optical property profiles, based on snow, sea ice and ponded
+! ice IOPs from:
+!
+! Briegleb, B. P., and B. Light (2007): A Delta-Eddington Multiple
+! Scattering Parameterization for Solar Radiation in the Sea Ice
+! Component of the Community Climate System Model, NCAR Technical
+! Note NCAR/TN-472+STR February 2007
+!
+! Computes column Delta-Eddington radiation solution for specific
+! surface type: either snow over sea ice, bare sea ice, or ponded sea ice.
+!
+! Divides solar spectrum into 3 intervals: 0.2-0.7, 0.7-1.19, and
+! 1.19-5.0 micro-meters. The latter two are added (using an assumed
+! partition of incident shortwave in the 0.7-5.0 micro-meter band between
+! the 0.7-1.19 and 1.19-5.0 micro-meter band) to give the final output
+! of 0.2-0.7 visible and 0.7-5.0 near-infrared albedos and fluxes.
+!
+! Specifies vertical layer optical properties based on input snow depth,
+! density and grain radius, along with ice and pond depths, then computes
+! layer by layer Delta-Eddington reflectivity, transmissivity and combines
+! layers (done by calling routine solution_dEdd). Finally, surface albedos
+! and internal fluxes/flux divergences are evaluated.
+!
+! Description of the level and layer index conventions. This is
+! for the standard case of one snow layer and four sea ice layers.
+!
+! Please read the following; otherwise, there is 99.9% chance you
+! will be confused about indices at some point in time........ :)
+!
+! CICE4.0 snow treatment has one snow layer above the sea ice. This
+! snow layer has finite heat capacity, so that surface absorption must
+! be distinguished from internal. The Delta-Eddington solar radiation
+! thus adds extra surface scattering layers to both snow and sea ice.
+! Note that in the following, we assume a fixed vertical layer structure
+! for the radiation calculation. In other words, we always have the
+! structure shown below for one snow and four sea ice layers, but for
+! ponded ice the pond fills "snow" layer 1 over the sea ice, and for
+! bare sea ice the top layers over sea ice are treated as transparent air.
+!
+! SSL = surface scattering layer for either snow or sea ice
+! DL = drained layer for sea ice immediately under sea ice SSL
+! INT = interior layers for sea ice below the drained layer.
+!
+! Notice that the radiation level starts with 0 at the top. Thus,
+! the total number radiation layers is klev+1, where klev is the
+! sum of nslyr, the number of CCSM snow layers, and nilyr, the
+! number of CCSM sea ice layers, plus the sea ice SSL:
+! klev = 1 + nslyr + nilyr
+!
+! For the standard case illustrated below, nslyr=1, nilyr=4,
+! and klev=6, with the number of layer interfaces klevp=klev+1.
+! Layer interfaces are the surfaces on which reflectivities,
+! transmissivities and fluxes are evaluated.
+!
+! CCSM3 Sea Ice Model Delta-Eddington Solar Radiation
+! Layers and Interfaces
+! Layer Index Interface Index
+! --------------------- --------------------- 0
+! 0 \\\ snow SSL \\\
+! snow layer 1 --------------------- 1
+! 1 rest of snow layer
+! +++++++++++++++++++++ +++++++++++++++++++++ 2
+! 2 \\\ sea ice SSL \\\
+! sea ice layer 1 --------------------- 3
+! 3 sea ice DL
+! --------------------- --------------------- 4
+!
+! sea ice layer 2 4 sea ice INT
+!
+! --------------------- --------------------- 5
+!
+! sea ice layer 3 5 sea ice INT
+!
+! --------------------- --------------------- 6
+!
+! sea ice layer 4 6 sea ice INT
+!
+! --------------------- --------------------- 7
+!
+! When snow lies over sea ice, the radiation absorbed in the
+! snow SSL is used for surface heating, and that in the rest
+! of the snow layer for its internal heating. For sea ice in
+! this case, all of the radiant heat absorbed in both the
+! sea ice SSL and the DL are used for sea ice layer 1 heating.
+!
+! When pond lies over sea ice, and for bare sea ice, all of the
+! radiant heat absorbed within and above the sea ice SSL is used
+! for surface heating, and that absorbed in the sea ice DL is
+! used for sea ice layer 1 heating.
+!
+! Basically, vertical profiles of the layer extinction optical depth (tau),
+! single scattering albedo (w0) and asymmetry parameter (g) are required over
+! the klev+1 layers, where klev+1 = 2 + nslyr + nilyr. All of the surface type
+! information and snow/ice iop properties are evaulated in this routine, so
+! the tau,w0,g profiles can be passed to solution_dEdd for multiple scattering
+! evaluation. Snow, bare ice and ponded ice iops are contained in data arrays
+! in this routine.
+!
+!-----------------------------------------------------------------------
+
+ ! local variables
+
+ integer (kind=int_kind) :: &
+ k , & ! level index
+ ns , & ! spectral index
+ nr , & ! index for grain radius tables
+ ki , & ! index for internal absorption
+ km , & ! k starting index for snow, sea ice internal absorption
+ kp , & ! k+1 or k+2 index for snow, sea ice internal absorption
+ ksrf , & ! level index for surface absorption
+ ksnow , & ! level index for snow density and grain size
+ kii ! level starting index for sea ice (nslyr+1)
+
+ integer (kind=int_kind), parameter :: &
+ nmbrad = 32 ! number of snow grain radii in tables
+
+ real (kind=dbl_kind) :: &
+ avdr , & ! visible albedo, direct (fraction)
+ avdf , & ! visible albedo, diffuse (fraction)
+ aidr , & ! near-ir albedo, direct (fraction)
+ aidf ! near-ir albedo, diffuse (fraction)
+
+ real (kind=dbl_kind) :: &
+ fsfc , & ! shortwave absorbed at snow/bare ice/ponded ice surface (W m-2)
+ fint , & ! shortwave absorbed in interior (W m-2)
+ fthru ! shortwave through snow/bare ice/ponded ice to ocean (W/m^2)
+
+ real (kind=dbl_kind), dimension(nslyr) :: &
+ Sabs ! shortwave absorbed in snow layer (W m-2)
+
+ real (kind=dbl_kind), dimension(nilyr) :: &
+ Iabs ! shortwave absorbed in ice layer (W m-2)
+
+ real (kind=dbl_kind), dimension(nilyr+1) :: &
+ fthrul ! shortwave through to ice layers (W m-2)
+
+ real (kind=dbl_kind), dimension (nspint) :: &
+ wghtns ! spectral weights
+
+ real (kind=dbl_kind), parameter :: &
+ cp67 = 0.67_dbl_kind , & ! nir band weight parameter
+ cp33 = 0.33_dbl_kind , & ! nir band weight parameter
+ cp78 = 0.78_dbl_kind , & ! nir band weight parameter
+ cp22 = 0.22_dbl_kind , & ! nir band weight parameter
+ cp01 = 0.01_dbl_kind ! for ocean visible albedo
+
+ real (kind=dbl_kind), dimension (0:klev) :: &
+ tau , & ! layer extinction optical depth
+ w0 , & ! layer single scattering albedo
+ g ! layer asymmetry parameter
+
+ ! following arrays are defined at model interfaces; 0 is the top of the
+ ! layer above the sea ice; klevp is the sea ice/ocean interface.
+ real (kind=dbl_kind), dimension (0:klevp) :: &
+ trndir , & ! solar beam down transmission from top
+ trntdr , & ! total transmission to direct beam for layers above
+ trndif , & ! diffuse transmission to diffuse beam for layers above
+ rupdir , & ! reflectivity to direct radiation for layers below
+ rupdif , & ! reflectivity to diffuse radiation for layers below
+ rdndif ! reflectivity to diffuse radiation for layers above
+
+ real (kind=dbl_kind), dimension (0:klevp) :: &
+ dfdir , & ! down-up flux at interface due to direct beam at top surface
+ dfdif ! down-up flux at interface due to diffuse beam at top surface
+
+ real (kind=dbl_kind) :: &
+ refk , & ! interface k multiple scattering term
+ delr , & ! snow grain radius interpolation parameter
+ ! inherent optical properties (iop) for snow
+ Qs , & ! Snow extinction efficiency
+ ks , & ! Snow mass extinction coefficient (m^2/kg)
+ ws , & ! Snow single scattering albedo
+ gs ! Snow asymmetry parameter
+
+ real (kind=dbl_kind), dimension(nslyr) :: &
+ frsnw ! snow grain radius in snow layer * adjustment factor (m)
+
+ ! actual used ice and ponded ice IOPs, allowing for tuning
+ ! modifications of the above "_mn" value
+ real (kind=dbl_kind), dimension (nspint) :: &
+ ki_ssl , & ! Surface-scattering-layer ice extinction coefficient (/m)
+ wi_ssl , & ! Surface-scattering-layer ice single scattering albedo
+ gi_ssl , & ! Surface-scattering-layer ice asymmetry parameter
+ ki_dl , & ! Drained-layer ice extinction coefficient (/m)
+ wi_dl , & ! Drained-layer ice single scattering albedo
+ gi_dl , & ! Drained-layer ice asymmetry parameter
+ ki_int , & ! Interior-layer ice extinction coefficient (/m)
+ wi_int , & ! Interior-layer ice single scattering albedo
+ gi_int , & ! Interior-layer ice asymmetry parameter
+ ki_p_ssl , & ! Ice under pond srf scat layer extinction coefficient (/m)
+ wi_p_ssl , & ! Ice under pond srf scat layer single scattering albedo
+ gi_p_ssl , & ! Ice under pond srf scat layer asymmetry parameter
+ ki_p_int , & ! Ice under pond extinction coefficient (/m)
+ wi_p_int , & ! Ice under pond single scattering albedo
+ gi_p_int ! Ice under pond asymmetry parameter
+
+ real (kind=dbl_kind), dimension(0:klev) :: &
+ dzk ! layer thickness
+
+ real (kind=dbl_kind) :: &
+ dz , & ! snow, sea ice or pond water layer thickness
+ dz_ssl , & ! snow or sea ice surface scattering layer thickness
+ fs ! scaling factor to reduce (nilyr<4) or increase (nilyr>4) DL
+ ! extinction coefficient to maintain DL optical depth constant
+ ! with changing number of sea ice layers, to approximately
+ ! conserve computed albedo for constant physical depth of sea
+ ! ice when the number of sea ice layers vary
+ real (kind=dbl_kind) :: &
+ sig , & ! scattering coefficient for tuning
+ kabs , & ! absorption coefficient for tuning
+ sigp ! modified scattering coefficient for tuning
+
+
+ real (kind=dbl_kind) :: &
+ albodr , & ! spectral ocean albedo to direct rad
+ albodf ! spectral ocean albedo to diffuse rad
+
+ ! for melt pond transition to bare sea ice for small pond depths
+ real (kind=dbl_kind) :: &
+ sig_i , & ! ice scattering coefficient (/m)
+ sig_p , & ! pond scattering coefficient (/m)
+ kext ! weighted extinction coefficient (/m)
+
+ ! aerosol optical properties from Mark Flanner, 26 June 2008
+ ! order assumed: hydrophobic black carbon, hydrophilic black carbon,
+ ! four dust aerosols by particle size range:
+ ! dust1(.05-0.5 micron), dust2(0.5-1.25 micron),
+ ! dust3(1.25-2.5 micron), dust4(2.5-5.0 micron)
+ ! spectral bands same as snow/sea ice: (0.3-0.7 micron, 0.7-1.19 micron
+ ! and 1.19-5.0 micron in wavelength)
+
+ integer (kind=int_kind) :: &
+ na , n ! aerosol index
+
+ real (kind=dbl_kind) :: &
+ taer , & ! total aerosol extinction optical depth
+ waer , & ! total aerosol single scatter albedo
+ gaer , & ! total aerosol asymmetry parameter
+ swdr , & ! shortwave down at surface, direct (W/m^2)
+ swdf , & ! shortwave down at surface, diffuse (W/m^2)
+ rnilyr , & ! real(nilyr)
+ rnslyr , & ! real(nslyr)
+ rns , & ! real(ns)
+ tmp_0, tmp_ks, tmp_kl ! temp variables
+
+ integer(kind=int_kind), dimension(0:klev) :: &
+ k_bcini , &
+ k_bcins , &
+ k_bcexs
+
+ real(kind=dbl_kind):: &
+ tmp_gs, tmp1 ! temp variables
+
+ ! inherent optical property (iop) arrays for ice and ponded ice
+ ! mn = specified mean (or base) value
+ ! ki = extinction coefficient (/m)
+ ! wi = single scattering albedo
+ ! gi = asymmetry parameter
+
+ ! ice surface scattering layer (ssl) iops
+ real (kind=dbl_kind), dimension (nspint), parameter :: &
+ ki_ssl_mn = (/ 1000.1_dbl_kind, 1003.7_dbl_kind, 7042._dbl_kind/), &
+ wi_ssl_mn = (/ .9999_dbl_kind, .9963_dbl_kind, .9088_dbl_kind/), &
+ gi_ssl_mn = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind/)
+
+ ! ice drained layer (dl) iops
+ real (kind=dbl_kind), dimension (nspint), parameter :: &
+ ki_dl_mn = (/ 100.2_dbl_kind, 107.7_dbl_kind, 1309._dbl_kind /), &
+ wi_dl_mn = (/ .9980_dbl_kind, .9287_dbl_kind, .0305_dbl_kind /), &
+ gi_dl_mn = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind /)
+
+ ! ice interior layer (int) iops
+ real (kind=dbl_kind), dimension (nspint), parameter :: &
+ ki_int_mn = (/ 20.2_dbl_kind, 27.7_dbl_kind, 1445._dbl_kind /), &
+ wi_int_mn = (/ .9901_dbl_kind, .7223_dbl_kind, .0277_dbl_kind /), &
+ gi_int_mn = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind /)
+
+ ! ponded ice surface scattering layer (ssl) iops
+ real (kind=dbl_kind), dimension (nspint), parameter :: &
+ ki_p_ssl_mn = (/ 70.2_dbl_kind, 77.7_dbl_kind, 1309._dbl_kind/), &
+ wi_p_ssl_mn = (/ .9972_dbl_kind, .9009_dbl_kind, .0305_dbl_kind/), &
+ gi_p_ssl_mn = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind /)
+
+ ! ponded ice interior layer (int) iops
+ real (kind=dbl_kind), dimension (nspint), parameter :: &
+ ki_p_int_mn = (/ 20.2_dbl_kind, 27.7_dbl_kind, 1445._dbl_kind/), &
+ wi_p_int_mn = (/ .9901_dbl_kind, .7223_dbl_kind, .0277_dbl_kind/), &
+ gi_p_int_mn = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind /)
+
+ ! inherent optical property (iop) arrays for pond water and underlying ocean
+ ! kw = Pond water extinction coefficient (/m)
+ ! ww = Pond water single scattering albedo
+ ! gw = Pond water asymmetry parameter
+ real (kind=dbl_kind), dimension (nspint), parameter :: &
+ kw = (/ 0.20_dbl_kind, 12.0_dbl_kind, 729._dbl_kind /), &
+ ww = (/ 0.00_dbl_kind, 0.00_dbl_kind, 0.00_dbl_kind /), &
+ gw = (/ 0.00_dbl_kind, 0.00_dbl_kind, 0.00_dbl_kind /)
+
+ real (kind=dbl_kind), parameter :: &
+ rhoi = 917.0_dbl_kind, & ! pure ice mass density (kg/m3)
+ fr_max = 1.00_dbl_kind, & ! snow grain adjustment factor max
+ fr_min = 0.80_dbl_kind, & ! snow grain adjustment factor min
+ ! tuning parameters
+ ! ice and pond scat coeff fractional change for +- one-sigma in albedo
+ fp_ice = 0.15_dbl_kind, & ! ice fraction of scat coeff for + stn dev in alb
+ fm_ice = 0.15_dbl_kind, & ! ice fraction of scat coeff for - stn dev in alb
+ fp_pnd = 2.00_dbl_kind, & ! ponded ice fraction of scat coeff for + stn dev in alb
+ fm_pnd = 0.50_dbl_kind ! ponded ice fraction of scat coeff for - stn dev in alb
+
+ real (kind=dbl_kind), parameter :: & !chla-specific absorption coefficient
+ kchl_tab = 0.01 !0.0023-0.0029 Perovich 1993, also 0.0067 m^2 (mg Chl)^-1
+ ! found values of 0.006 to 0.023 m^2/ mg (676 nm) Neukermans 2014
+ ! and averages over the 300-700nm of 0.0075 m^2/mg in ice Fritsen (2011)
+ ! at 440nm values as high as 0.2 m^2/mg in under ice bloom (Balch 2014)
+ ! Grenfell 1991 uses 0.004 (m^2/mg) which is (0.0078 * spectral weighting)
+ !chlorophyll mass extinction cross section (m^2/mg chla)
+
+ character(len=char_len_long) :: &
+ warning ! warning message
+
+ ! SNICAR
+ ! new inputs
+ integer (kind=int_kind), parameter :: &
+ nmbrad_snicar = 1471 , &! number of snow grain radii in SNICAR
+ ! snow iops table
+ rsnw_snicar_max = 1500 , &
+ rsnw_snicar_min = 30
+
+ real (kind=dbl_kind), dimension (nspint_5bd) :: &
+ wghtns_5bd_dfs, & ! spectral weights for diffuse incident
+ wghtns_5bd_drc ! spectral weights for direct incident
+
+ ! FUTURE-WORK: update 5-band sea ice iops when avalible
+ real (kind=dbl_kind), dimension (nspint_5bd) :: & ! for ice only
+ ki_ssl_5bd , & ! Surface-scattering-layer ice extinction coefficient (/m)
+ wi_ssl_5bd , & ! Surface-scattering-layer ice single scattering albedo
+ gi_ssl_5bd , & ! Surface-scattering-layer ice asymmetry parameter
+ ki_dl_5bd , & ! Drained-layer ice extinction coefficient (/m)
+ wi_dl_5bd , & ! Drained-layer ice single scattering albedo
+ gi_dl_5bd , & ! Drained-layer ice asymmetry parameter
+ ki_int_5bd , & ! Interior-layer ice extinction coefficient (/m)
+ wi_int_5bd , & ! Interior-layer ice single scattering albedo
+ gi_int_5bd ! Interior-layer ice asymmetry parameter
+
+ ! 5-band aersol data
+ real (kind=dbl_kind), dimension(nspint_5bd, 0:klev) :: &
+ kabs_chl_5bd , & ! absorption coefficient for chlorophyll (/m)
+ tzaer_5bd , & ! total aerosol extinction optical depth
+ wzaer_5bd , & ! total aerosol single scatter albedo
+ gzaer_5bd ! total aerosol asymmetry parameter
+
+ ! index
+ integer (kind=int_kind) :: &
+ nsky !sky = 1 (2) for direct (diffuse) downward SW incident
+
+ ! temporary variables used to assign variables for direct/diffuse incident
+ ! based on snicar 5 band IOPs
+ real (kind=dbl_kind), dimension (0:klevp) :: &
+ dfdir_snicar , & ! down-up flux at interface due to direct beam at top surface
+ dfdif_snicar , & ! down-up flux at interface due to diffuse beam at top surface
+ rupdir_snicar , & ! reflectivity to direct radiation for layers below
+ rupdif_snicar ! reflectivity to diffuse radiation for layers above
+
+ ! solar zenith angle parameterizations
+ real (kind=dbl_kind), parameter :: &
+ sza_a0 = 0.085730_dbl_kind , &
+ sza_a1 = -0.630883_dbl_kind , &
+ sza_a2 = 1.303723_dbl_kind , &
+ sza_b0 = 1.467291_dbl_kind , &
+ sza_b1 = -3.338043_dbl_kind , &
+ sza_b2 = 6.807489_dbl_kind , &
+ mu_75 = 0.2588_dbl_kind ! cosine of 75 degree
+
+ real (kind=dbl_kind) :: &
+ sza_c1 , & ! parameter for high sza adjustment
+ sza_c0 , & ! parameter for high sza adjustment
+ sza_factor , & ! parameter for high sza adjustment
+ mu0
+
+ ! 5-bands ice surface scattering layer (ssl) iops to match SNICAR calculations
+ ! note by Cheng Dang:
+ ! for now these data are not needed since the sea ice layer IOPs can be directly
+ ! assigned based on the 3 bands data after adjustment based on tuning parameter R_ice
+ ! In the future, when 5-band sea ice IOPs are available, these data shall be updated
+ ! and the sea ice layer IOPs shall be calculated based on updated 5band iops*
+ !
+ ! The 5band data given in this section are based on CICE and SNICAR band choice:
+ ! SNICAR band 1 = CICE band 1
+ ! SNICAR band 2 = SNICAR band 3 = CICE band 2
+ ! SNICAR band 4 = SNICAR band 5 = CICE band 3
+
+ ! ice surface scattering layer (ssl) iops
+ real (kind=dbl_kind), dimension (nspint_5bd), parameter :: &
+ ki_ssl_mn_5bd = (/ 1000.1_dbl_kind, 1003.7_dbl_kind, 1003.7_dbl_kind, &
+ 7042._dbl_kind, 7042._dbl_kind /), &
+ wi_ssl_mn_5bd = (/ .9999_dbl_kind, .9963_dbl_kind, .9963_dbl_kind, &
+ .9088_dbl_kind, .9088_dbl_kind /), &
+ gi_ssl_mn_5bd = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind, &
+ .94_dbl_kind, .94_dbl_kind /)
+
+ ! ice drained layer (dl) iops
+ real (kind=dbl_kind), dimension (nspint_5bd), parameter :: &
+ ki_dl_mn_5bd = (/ 100.2_dbl_kind, 107.7_dbl_kind, 107.7_dbl_kind, &
+ 1309._dbl_kind, 1309._dbl_kind /), &
+ wi_dl_mn_5bd = (/ .9980_dbl_kind, .9287_dbl_kind, .9287_dbl_kind, &
+ .0305_dbl_kind, .0305_dbl_kind /), &
+ gi_dl_mn_5bd = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind, &
+ .94_dbl_kind, .94_dbl_kind /)
+
+ ! ice interior layer (int) iops
+ real (kind=dbl_kind), dimension (nspint_5bd), parameter :: &
+ ki_int_mn_5bd = (/ 20.2_dbl_kind, 27.7_dbl_kind, 27.7_dbl_kind, &
+ 1445._dbl_kind, 1445._dbl_kind/), &
+ wi_int_mn_5bd = (/ .9901_dbl_kind, .7223_dbl_kind, .7223_dbl_kind, &
+ .0277_dbl_kind, .0277_dbl_kind /), &
+ gi_int_mn_5bd = (/ .94_dbl_kind, .94_dbl_kind, .94_dbl_kind, &
+ .94_dbl_kind, .94_dbl_kind /)
+
+!-----------------------------------------------------------------------
+! Initialize and tune bare ice/ponded ice iops
+
+ k_bcini(:) = c0
+ k_bcins(:) = c0
+ k_bcexs(:) = c0
+
+ rnilyr = c1/real(nilyr,kind=dbl_kind)
+ rnslyr = c1/real(nslyr,kind=dbl_kind)
+ kii = nslyr + 1
+
+ ! initialize albedos and fluxes to 0
+ fthrul = c0
+ Iabs = c0
+ kabs_chl_5bd(:,:) = c0
+ tzaer_5bd(:,:) = c0
+ wzaer_5bd(:,:) = c0
+ gzaer_5bd(:,:) = c0
+
+ avdr = c0
+ avdf = c0
+ aidr = c0
+ aidf = c0
+ fsfc = c0
+ fint = c0
+ fthru = c0
+
+ ! spectral weights - 3 bands
+ ! this section of code is kept for future mearge between 5band and 3 band
+ ! subroutines
+ ! weights 2 (0.7-1.19 micro-meters) and 3 (1.19-5.0 micro-meters)
+ ! are chosen based on 1D calculations using ratio of direct to total
+ ! near-infrared solar (0.7-5.0 micro-meter) which indicates clear/cloudy
+ ! conditions: more cloud, the less 1.19-5.0 relative to the
+ ! 0.7-1.19 micro-meter due to cloud absorption.
+ !wghtns(1) = c1
+ !wghtns(2) = cp67 + (cp78-cp67)*(c1-fnidr)
+! wghtns(3) = cp33 + (cp22-cp33)*(c1-fnidr)
+ !wghtns(3) = c1 - wghtns(2)
+
+ ! spectral weights - 5 bands
+ ! direct beam incident
+ ! add-local-variable
+ wghtns_5bd_drc(1) = 1._dbl_kind
+ wghtns_5bd_drc(2) = 0.49352158521175_dbl_kind!0.49352_dbl_kind!0.50_dbl_kind
+ wghtns_5bd_drc(3) = 0.18099494230665_dbl_kind!0.18100_dbl_kind!0.18_dbl_kind
+ wghtns_5bd_drc(4) = 0.12094898498813_dbl_kind!0.12095_dbl_kind!0.12_dbl_kind !
+ wghtns_5bd_drc(5) = c1-(wghtns_5bd_drc(2)+wghtns_5bd_drc(3)+wghtns_5bd_drc(4))
+ !wghtns_5bd_drc(5) = 0.20453448749347_dbl_kind!0.20453_dbl_kind!0.20_dbl_kind !
+
+ ! diffuse incident
+ wghtns_5bd_dfs(1) = 1._dbl_kind
+ wghtns_5bd_dfs(2) = 0.58581507618433_dbl_kind!0.58582_dbl_kind!0.59_dbl_kind !
+ wghtns_5bd_dfs(3) = 0.20156903770812_dbl_kind!0.20157_dbl_kind!0.20_dbl_kind !
+ wghtns_5bd_dfs(4) = 0.10917889346386_dbl_kind!0.10918_dbl_kind!0.11_dbl_kind !
+ wghtns_5bd_dfs(5) = c1-(wghtns_5bd_dfs(2)+wghtns_5bd_dfs(3)+wghtns_5bd_dfs(4))
+ !wghtns_5bd_dfs(5) = 0.10343699264369_dbl_kind!0.10343_dbl_kind!0.10_dbl_kind !
+
+
+ do k = 1, nslyr
+ !frsnw(k) = (fr_max*fnidr + fr_min*(c1-fnidr))*rsnw(k)
+ Sabs(k) = c0
+ enddo
+
+ ! layer thicknesses
+ ! snow
+ dz = hs*rnslyr
+ ! for small enough snow thickness, ssl thickness half of top snow layer
+!ech: note this is highly resolution dependent!
+ dzk(0) = min(hs_ssl, dz/c2)
+ dzk(1) = dz - dzk(0)
+ if (nslyr > 1) then
+ do k = 2, nslyr
+ dzk(k) = dz
+ enddo
+ endif
+
+ ! ice
+ dz = hi*rnilyr
+ ! empirical reduction in sea ice ssl thickness for ice thinner than 1.5m;
+ ! factor of 30 gives best albedo comparison with limited observations
+ dz_ssl = hi_ssl
+!ech: note hardwired parameters
+! if( hi < 1.5_dbl_kind ) dz_ssl = hi/30._dbl_kind
+ dz_ssl = min(hi_ssl, hi/30._dbl_kind)
+ ! set sea ice ssl thickness to half top layer if sea ice thin enough
+!ech: note this is highly resolution dependent!
+ dz_ssl = min(dz_ssl, dz/c2)
+
+ dzk(kii) = dz_ssl
+ dzk(kii+1) = dz - dz_ssl
+ if (kii+2 <= klev) then
+ do k = kii+2, klev
+ dzk(k) = dz
+ enddo
+ endif
+
+ ! adjust sea ice iops with tuning parameters; tune only the
+ ! scattering coefficient by factors of R_ice, R_pnd, where
+ ! R values of +1 correspond approximately to +1 sigma changes in albedo, and
+ ! R values of -1 correspond approximately to -1 sigma changes in albedo
+ ! Note: the albedo change becomes non-linear for R values > +1 or < -1
+ if( R_ice >= c0 ) then
+ do ns = 1, nspint_5bd
+ sigp = ki_ssl_mn_5bd(ns)*wi_ssl_mn_5bd(ns)*(c1+fp_ice*R_ice)
+ ki_ssl_5bd(ns) = sigp+ki_ssl_mn_5bd(ns)*(c1-wi_ssl_mn_5bd(ns))
+ wi_ssl_5bd(ns) = sigp/ki_ssl_5bd(ns)
+ gi_ssl_5bd(ns) = gi_ssl_mn_5bd(ns)
+
+ sigp = ki_dl_mn_5bd(ns)*wi_dl_mn_5bd(ns)*(c1+fp_ice*R_ice)
+ ki_dl_5bd(ns) = sigp+ki_dl_mn_5bd(ns)*(c1-wi_dl_mn_5bd(ns))
+ wi_dl_5bd(ns) = sigp/ki_dl_5bd(ns)
+ gi_dl_5bd(ns) = gi_dl_mn_5bd(ns)
+
+ sigp = ki_int_mn_5bd(ns)*wi_int_mn_5bd(ns)*(c1+fp_ice*R_ice)
+ ki_int_5bd(ns) = sigp+ki_int_mn_5bd(ns)*(c1-wi_int_mn_5bd(ns))
+ wi_int_5bd(ns) = sigp/ki_int_5bd(ns)
+ gi_int_5bd(ns) = gi_int_mn_5bd(ns)
+ enddo
+ else !if( R_ice < c0 ) then
+ do ns = 1, nspint_5bd
+ sigp = ki_ssl_mn_5bd(ns)*wi_ssl_mn_5bd(ns)*(c1+fm_ice*R_ice)
+ sigp = max(sigp, c0)
+ ki_ssl_5bd(ns) = sigp+ki_ssl_mn_5bd(ns)*(c1-wi_ssl_mn_5bd(ns))
+ wi_ssl_5bd(ns) = sigp/ki_ssl_5bd(ns)
+ gi_ssl_5bd(ns) = gi_ssl_mn_5bd(ns)
+
+ sigp = ki_dl_mn_5bd(ns)*wi_dl_mn_5bd(ns)*(c1+fm_ice*R_ice)
+ sigp = max(sigp, c0)
+ ki_dl_5bd(ns) = sigp+ki_dl_mn_5bd(ns)*(c1-wi_dl_mn_5bd(ns))
+ wi_dl_5bd(ns) = sigp/ki_dl_5bd(ns)
+ gi_dl_5bd(ns) = gi_dl_mn_5bd(ns)
+
+ sigp = ki_int_mn_5bd(ns)*wi_int_mn_5bd(ns)*(c1+fm_ice*R_ice)
+ sigp = max(sigp, c0)
+ ki_int_5bd(ns) = sigp+ki_int_mn_5bd(ns)*(c1-wi_int_mn_5bd(ns))
+ wi_int_5bd(ns) = sigp/ki_int_5bd(ns)
+ gi_int_5bd(ns) = gi_int_mn_5bd(ns)
+ enddo
+ endif ! adjust ice iops
+
+ ! use srftyp to determine interface index of surface absorption
+ ksrf = 1 ! snow covered sea ice
+
+ if (tr_bgc_N .and. dEdd_algae) then ! compute kabs_chl for chlorophyll
+ do k = 0, klev
+ kabs_chl_5bd(1,k) = kchl_tab*zbio(nlt_chl_sw+k)
+ enddo
+ else
+ k = klev
+ kabs_chl_5bd(1,k) = kalg*(0.50_dbl_kind/dzk(k))
+ !print *, 'aerosol, k, kabs_chl_5bd(1,k)', k, kabs_chl_5bd(1,k)
+ endif
+
+!mgf++
+ if (modal_aero) then
+ do k=0,klev
+ if (k < nslyr+1) then ! define indices for snow layer
+ ! use top rsnw, rhosnw for snow ssl and rest of top layer
+ ! Cheng: note that aerosol IOPs are related to snow grain radius.
+ ! CICE adjusted snow grain radius rsnw to frsnw, while for
+ ! SNICAR there is no need, the tmp_gs is therefore calculated
+ ! differently from code in subroutine compute_dEdd
+ ksnow = k - min(k-1,0)
+ tmp_gs = rsnw(ksnow) ! use rsnw not frsnw
+
+ ! get grain size index:
+ ! works for 25 < snw_rds < 1625 um:
+ if (tmp_gs < 125) then
+ tmp1 = tmp_gs/50
+ k_bcini(k) = nint(tmp1)
+ elseif (tmp_gs < 175) then
+ k_bcini(k) = 2
+ else
+ tmp1 = (tmp_gs/250)+2
+ k_bcini(k) = nint(tmp1)
+ endif
+ else ! use the largest snow grain size for ice
+ k_bcini(k) = 8
+ endif
+ ! Set index corresponding to BC effective radius. Here,
+ ! asssume constant BC effective radius of 100nm
+ ! (corresponding to index 2)
+ k_bcins(k) = 2
+ k_bcexs(k) = 2
+
+ ! check bounds:
+ if (k_bcini(k) < 1) k_bcini(k) = 1
+ if (k_bcini(k) > 8) k_bcini(k) = 8
+ if (k_bcins(k) < 1) k_bcins(k) = 1
+ if (k_bcins(k) > 10) k_bcins(k) = 10
+ if (k_bcexs(k) < 1) k_bcexs(k) = 1
+ if (k_bcexs(k) > 10) k_bcexs(k) = 10
+
+ ! print ice radius index:
+ ! write(warning,*) "MGFICE2:k, ice index= ",k, k_bcini(k)
+ ! call add_warning(warning)
+ enddo ! k
+ ! assign the aerosol index
+
+ if (tr_zaero .and. dEdd_algae) then ! compute kzaero for chlorophyll
+ do n = 1,n_zaero
+ if (n == 1) then ! interstitial BC
+ do k = 0, klev
+ do ns = 1,nspint_5bd ! not weighted by aice
+ tzaer_5bd(ns,k) = tzaer_5bd(ns,k)+kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ wzaer_5bd(ns,k) = wzaer_5bd(ns,k)+kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ gzaer_5bd(ns,k) = gzaer_5bd(ns,k)+kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))* &
+ gaer_bc_tab_5bd(ns,k_bcexs(k))*zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ enddo ! nspint
+ enddo
+ elseif (n==2) then ! within-ice BC
+ do k = 0, klev
+ do ns = 1,nspint_5bd
+ tzaer_5bd(ns,k) = tzaer_5bd(ns,k)+kaer_bc_tab_5bd(ns,k_bcins(k)) * &
+ bcenh_5bd(ns,k_bcins(k),k_bcini(k))* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ wzaer_5bd(ns,k) = wzaer_5bd(ns,k)+kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ gzaer_5bd(ns,k) = gzaer_5bd(ns,k)+kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))* &
+ gaer_bc_tab_5bd(ns,k_bcins(k))*zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ enddo ! nspint
+ enddo
+ else ! dust
+ do k = 0, klev
+ do ns = 1,nspint_5bd ! not weighted by aice
+ tzaer_5bd(ns,k) = tzaer_5bd(ns,k)+kaer_tab_5bd(ns,n)* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ wzaer_5bd(ns,k) = wzaer_5bd(ns,k)+kaer_tab_5bd(ns,n)*waer_tab_5bd(ns,n)* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ gzaer_5bd(ns,k) = gzaer_5bd(ns,k)+kaer_tab_5bd(ns,n)*waer_tab_5bd(ns,n)* &
+ gaer_tab_5bd(ns,n)*zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ enddo ! nspint
+ enddo
+ endif !(n=1)
+ enddo ! n_zaero
+ endif ! tr_zaero and dEdd_algae
+
+ else ! Bulk aerosol treatment
+ if (tr_zaero .and. dEdd_algae) then ! compute kzaero for chlorophyll
+ do n = 1,n_zaero ! multiply by aice?
+ do k = 0, klev
+ do ns = 1,nspint_5bd ! not weighted by aice
+ tzaer_5bd(ns,k) = tzaer_5bd(ns,k)+kaer_tab_5bd(ns,n)* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ wzaer_5bd(ns,k) = wzaer_5bd(ns,k)+kaer_tab_5bd(ns,n)*waer_tab_5bd(ns,n)* &
+ zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ gzaer_5bd(ns,k) = gzaer_5bd(ns,k)+kaer_tab_5bd(ns,n)*waer_tab_5bd(ns,n)* &
+ gaer_tab_5bd(ns,n)*zbio(nlt_zaero_sw(n)+k)*dzk(k)
+ enddo ! nspint
+ enddo
+ enddo
+ endif !tr_zaero
+
+ endif ! modal_aero
+
+
+!-----------------------------------------------------------------------
+ ! begin spectral loop
+ do ns = 1, nspint_5bd
+ ! for snow-covered sea ice, comput 5 bands
+ !if( srftyp == 1 ) then
+ ! SNICAR-AD major changes
+ ! 1. loop through 5bands: do ns = 1, nspint_5bd based on nsky
+ ! 2. use snow grain size rsnow, not scaled frsnw
+ ! 3. replace $IOPs_tab with $IOPs_snicar
+ ! 4. replace wghtns with wghtns_5bd
+ do nsky = 1,2 ! loop for both direct beam and diffuse beam
+ if (nsky == 1) then ! direc incident
+ do k=0,nslyr
+ ! use top rsnw, rhosnw for snow ssl and rest of top layer
+ ksnow = k - min(k-1,0)
+ if (rsnw(ksnow) <= rsnw_snicar_min) then
+ ks = ext_cff_mss_ice_drc(ns,1)
+ ws = ss_alb_ice_drc(ns,1)
+ gs = asm_prm_ice_drc(ns,1)
+ elseif (rsnw(ksnow) >= rsnw_snicar_max) then
+ ks = ext_cff_mss_ice_drc(ns,nmbrad_snicar)
+ ws = ss_alb_ice_drc(ns,nmbrad_snicar)
+ gs = asm_prm_ice_drc(ns,nmbrad_snicar)
+ elseif (ceiling(rsnw(ksnow)) - rsnw(ksnow) < 1.0e-3_dbl_kind) then
+ nr = ceiling(rsnw(ksnow)) - 30 + 1
+ ks = ext_cff_mss_ice_drc(ns,nr)
+ ws = ss_alb_ice_drc(ns,nr)
+ gs = asm_prm_ice_drc(ns,nr)
+ else ! linear interpolation in rsnw
+ ! radius = 30 --> nr = 1 in SNICAR table
+ nr = ceiling(rsnw(ksnow)) - 30 + 1
+ delr = (rsnw(ksnow) - floor(rsnw(ksnow))) / &
+ (ceiling(rsnw(ksnow)) - floor(rsnw(ksnow)))
+ ks = ext_cff_mss_ice_drc(ns,nr-1)*(delr) + &
+ ext_cff_mss_ice_drc(ns,nr)*(c1-delr)
+ ws = ss_alb_ice_drc(ns,nr-1)*(delr) + &
+ ss_alb_ice_drc(ns,nr)*(c1-delr)
+ gs = asm_prm_ice_drc(ns,nr-1)*(delr) + &
+ asm_prm_ice_drc(ns,nr)*(c1-delr)
+ endif
+ ! ks = Qs*((rhosnw(ksnow)/rhoi)*3._dbl_kind / &
+ ! (4._dbl_kind*rsnw(ksnow)*1.0e-6_dbl_kind))
+ tau(k) = (ks*rhosnw(ksnow) + kabs_chl_5bd(ns,k))*dzk(k)
+ !w0(k) = ks/(ks + kabs_chl_5bd(ns,k))*ws
+ w0(k) = (ks*rhosnw(ksnow))/(ks*rhosnw(ksnow) + kabs_chl_5bd(ns,k)) * ws
+ g(k) = gs
+
+ !write(warning, *) "sky, k, tau, w0, g =", nsky, k, tau(k), w0(k), g(k)
+ !write(warning, *) "ns, ks, kabs_chl_5bd(ns,k), ", ns, ks, kabs_chl_5bd(ns,k)
+ !call add_warning(warning)
+ !print *, "rsnw(ksnow)", rsnw(ksnow)
+ !print *, "sky, k, tau, w0, g =", nsky, k, tau(k), w0(k), g(k)
+ !print *, "ns, ks, kabs_chl_5bd(ns,k), ",ns, ks, kabs_chl_5bd(ns,k)
+
+ enddo ! k
+ elseif (nsky == 2) then ! diffuse incident
+ do k=0,nslyr
+ ! use top rsnw, rhosnw for snow ssl and rest of top layer
+ ksnow = k - min(k-1,0)
+ if (rsnw(ksnow) < rsnw_snicar_min) then
+ ks = ext_cff_mss_ice_dfs(ns,1)
+ ws = ss_alb_ice_dfs(ns,1)
+ gs = asm_prm_ice_dfs(ns,1)
+ elseif (rsnw(ksnow) > rsnw_snicar_max) then
+ ks = ext_cff_mss_ice_dfs(ns,nmbrad_snicar)
+ ws = ss_alb_ice_dfs(ns,nmbrad_snicar)
+ gs = asm_prm_ice_dfs(ns,nmbrad_snicar)
+ elseif (ceiling(rsnw(ksnow)) - rsnw(ksnow) < 1.0e-3_dbl_kind) then
+ nr = ceiling(rsnw(ksnow)) - 30 + 1
+ ks = ext_cff_mss_ice_dfs(ns,nr)
+ ws = ss_alb_ice_dfs(ns,nr)
+ gs = asm_prm_ice_dfs(ns,nr)
+ else ! linear interpolation in rsnw
+ ! radius = 30 --> nr = 1 in SNICAR table
+ nr = ceiling(rsnw(ksnow)) - 30 + 1
+ delr = (rsnw(ksnow) - floor(rsnw(ksnow))) / &
+ (ceiling(rsnw(ksnow)) - floor(rsnw(ksnow)))
+ ks = ext_cff_mss_ice_dfs(ns,nr-1)*(c1-delr) + &
+ ext_cff_mss_ice_dfs(ns,nr)*delr
+ ws = ss_alb_ice_dfs(ns,nr-1)*(c1-delr) + &
+ ss_alb_ice_dfs(ns,nr)*delr
+ gs = asm_prm_ice_dfs(ns,nr-1)*(c1-delr) + &
+ asm_prm_ice_dfs(ns,nr)*delr
+ endif
+ ! ks = Qs*((rhosnw(ksnow)/rhoi)*3._dbl_kind / &
+ ! (4._dbl_kind*rsnw(ksnow)*1.0e-6_dbl_kind))
+ tau(k) = (ks*rhosnw(ksnow) + kabs_chl_5bd(ns,k))*dzk(k)
+ !w0(k) = ks/(ks + kabs_chl_5bd(ns,k)) *ws
+ w0(k) = (ks*rhosnw(ksnow))/(ks*rhosnw(ksnow) + kabs_chl_5bd(ns,k)) * ws
+ g(k) = gs
+
+ !write(warning, *) "sky, k, tau, w0, g =", nsky, k, tau(k), w0(k), g(k)
+ !write(warning, *) "ns, ks, kabs_chl_5bd(ns,k), ", ns, ks, kabs_chl_5bd(ns,k)
+ !call add_warning(warning)
+ enddo ! k
+ endif ! end if nsky for snow IOPs assignment
+ !------------------------------------------------------------------------------
+
+ !aerosol in snow
+ if (tr_zaero .and. dEdd_algae) then
+ do k = 0,nslyr
+ g(k) = (g(k)*w0(k)*tau(k) + gzaer_5bd(ns,k)) / &
+ (w0(k)*tau(k) + wzaer_5bd(ns,k))
+ w0(k) = (w0(k)*tau(k) + wzaer_5bd(ns,k)) / &
+ (tau(k) + tzaer_5bd(ns,k))
+ tau(k) = tau(k) + tzaer_5bd(ns,k)
+ enddo
+ elseif (tr_aero) then
+ k = 0 ! snow SSL
+ taer = c0
+ waer = c0
+ gaer = c0
+
+ do na=1,4*n_aero,4
+! mgf++
+ if (modal_aero) then
+ if (na == 1) then
+ !interstitial BC
+ taer = taer + &
+ aero_mp(na)*kaer_bc_tab_5bd(ns,k_bcexs(k))
+ waer = waer + &
+ aero_mp(na)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))
+ gaer = gaer + &
+ aero_mp(na)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))*gaer_bc_tab_5bd(ns,k_bcexs(k))
+ elseif (na == 5)then
+ !within-ice BC
+ taer = taer + &
+ aero_mp(na)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ bcenh_5bd(ns,k_bcins(k),k_bcini(k))
+ waer = waer + &
+ aero_mp(na)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))
+ gaer = gaer + &
+ aero_mp(na)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))*gaer_bc_tab_5bd(ns,k_bcins(k))
+ else
+ ! other species (dust)
+ taer = taer + &
+ aero_mp(na)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ aero_mp(na)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ aero_mp(na)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif
+ else
+ taer = taer + &
+ aero_mp(na)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ aero_mp(na)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ aero_mp(na)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif !modal_aero
+!mgf--
+ enddo ! na
+ gaer = gaer/(waer+puny)
+ waer = waer/(taer+puny)
+
+ do k=1,nslyr
+ taer = c0
+ waer = c0
+ gaer = c0
+ do na=1,4*n_aero,4
+ if (modal_aero) then
+!mgf++
+ if (na==1) then
+ ! interstitial BC
+ taer = taer + &
+ (aero_mp(na+1)/rnslyr)*kaer_bc_tab_5bd(ns,k_bcexs(k))
+ waer = waer + &
+ (aero_mp(na+1)/rnslyr)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))
+ gaer = gaer + &
+ (aero_mp(na+1)/rnslyr)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))*gaer_bc_tab_5bd(ns,k_bcexs(k))
+ elseif (na==5) then
+ ! within-ice BC
+ taer = taer + &
+ (aero_mp(na+1)/rnslyr)*kaer_bc_tab_5bd(ns,k_bcins(k))*&
+ bcenh_5bd(ns,k_bcins(k),k_bcini(k))
+ waer = waer + &
+ (aero_mp(na+1)/rnslyr)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))
+ gaer = gaer + &
+ (aero_mp(na+1)/rnslyr)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))*gaer_bc_tab_5bd(ns,k_bcins(k))
+
+ else
+ ! other species (dust)
+ taer = taer + &
+ (aero_mp(na+1)/rnslyr)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ (aero_mp(na+1)/rnslyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ (aero_mp(na+1)/rnslyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif !(na==1)
+
+ else
+ taer = taer + &
+ (aero_mp(na+1)*rnslyr)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ (aero_mp(na+1)*rnslyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ (aero_mp(na+1)*rnslyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif ! modal_aero
+!mgf--
+ enddo ! na
+ gaer = gaer/(waer+puny)
+ waer = waer/(taer+puny)
+ g(k) = (g(k)*w0(k)*tau(k) + gaer*waer*taer) / &
+ (w0(k)*tau(k) + waer*taer)
+ w0(k) = (w0(k)*tau(k) + waer*taer) / &
+ (tau(k) + taer)
+ tau(k) = tau(k) + taer
+ enddo ! k
+ endif ! tr_aero
+
+ ! set optical properties of sea ice
+
+ ! bare or snow-covered sea ice layers
+ !if( srftyp <= 1 ) then
+ ! ssl
+ k = kii
+ tau(k) = (ki_ssl_5bd(ns)+kabs_chl_5bd(ns,k))*dzk(k)
+ w0(k) = ki_ssl_5bd(ns)/(ki_ssl_5bd(ns) + kabs_chl_5bd(ns,k))*wi_ssl_5bd(ns)
+ g(k) = gi_ssl_5bd(ns)
+ ! dl
+ k = kii + 1
+ ! scale dz for dl relative to 4 even-layer-thickness 1.5m case
+ fs = p25/rnilyr
+ tau(k) = (ki_dl_5bd(ns) + kabs_chl_5bd(ns,k)) *dzk(k)*fs
+ w0(k) = ki_dl_5bd(ns)/(ki_dl_5bd(ns) + kabs_chl_5bd(ns,k)) *wi_dl_5bd(ns)
+ g(k) = gi_dl_5bd(ns)
+ ! int above lowest layer
+ if (kii+2 <= klev-1) then
+ do k = kii+2, klev-1
+ tau(k) = (ki_int_5bd(ns) + kabs_chl_5bd(ns,k))*dzk(k)
+ w0(k) = ki_int_5bd(ns)/(ki_int_5bd(ns) + kabs_chl_5bd(ns,k)) *wi_int_5bd(ns)
+ g(k) = gi_int_5bd(ns)
+ enddo
+ endif
+ ! lowest layer
+ k = klev
+ ! add algae to lowest sea ice layer, visible only:
+ kabs = ki_int_5bd(ns)*(c1-wi_int_5bd(ns))
+ if( ns == 1 ) then
+ ! total layer absorption optical depth fixed at value
+ ! of kalg*0.50m, independent of actual layer thickness
+ kabs = kabs + kabs_chl_5bd(ns,k)
+ endif
+ sig = ki_int_5bd(ns)*wi_int_5bd(ns)
+ tau(k) = (kabs+sig)*dzk(k)
+ w0(k) = (sig/(sig+kabs))
+ g(k) = gi_int_5bd(ns)
+ ! aerosol in sea ice
+ if (tr_zaero .and. dEdd_algae) then
+ do k = kii, klev
+ g(k) = (g(k)*w0(k)*tau(k) + gzaer_5bd(ns,k)) / &
+ (w0(k)*tau(k) + wzaer_5bd(ns,k))
+ w0(k) = (w0(k)*tau(k) + wzaer_5bd(ns,k)) / &
+ (tau(k) + tzaer_5bd(ns,k))
+ tau(k) = tau(k) + tzaer_5bd(ns,k)
+ enddo
+ elseif (tr_aero) then
+ k = kii ! sea ice SSL
+ taer = c0
+ waer = c0
+ gaer = c0
+ do na=1,4*n_aero,4
+ !mgf++
+ if (modal_aero) then
+ if (na==1) then
+ ! interstitial BC
+ taer = taer + &
+ aero_mp(na+2)*kaer_bc_tab_5bd(ns,k_bcexs(k))
+ waer = waer + &
+ aero_mp(na+2)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))
+ gaer = gaer + &
+ aero_mp(na+2)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))*gaer_bc_tab_5bd(ns,k_bcexs(k))
+ elseif (na==5) then
+ ! within-ice BC
+ taer = taer + &
+ aero_mp(na+2)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ bcenh_5bd(ns,k_bcins(k),k_bcini(k))
+ waer = waer + &
+ aero_mp(na+2)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))
+ gaer = gaer + &
+ aero_mp(na+2)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))*gaer_bc_tab_5bd(ns,k_bcins(k))
+ else
+ ! other species (dust)
+ taer = taer + &
+ aero_mp(na+2)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ aero_mp(na+2)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ aero_mp(na+2)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif
+ else !bulk
+ taer = taer + &
+ aero_mp(na+2)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ aero_mp(na+2)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ aero_mp(na+2)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif ! modal_aero
+ !mgf--
+ enddo ! na
+
+ gaer = gaer/(waer+puny)
+ waer = waer/(taer+puny)
+ g(k) = (g(k)*w0(k)*tau(k) + gaer*waer*taer) / &
+ (w0(k)*tau(k) + waer*taer)
+ w0(k) = (w0(k)*tau(k) + waer*taer) / &
+ (tau(k) + taer)
+ tau(k) = tau(k) + taer
+ do k = kii+1, klev
+ taer = c0
+ waer = c0
+ gaer = c0
+ do na=1,4*n_aero,4
+ !mgf++
+ if (modal_aero) then
+ if (na==1) then
+ ! interstitial BC
+ taer = taer + &
+ (aero_mp(na+3)/rnilyr)*kaer_bc_tab_5bd(ns,k_bcexs(k))
+ waer = waer + &
+ (aero_mp(na+3)/rnilyr)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))
+ gaer = gaer + &
+ (aero_mp(na+3)/rnilyr)*kaer_bc_tab_5bd(ns,k_bcexs(k))* &
+ waer_bc_tab_5bd(ns,k_bcexs(k))*gaer_bc_tab_5bd(ns,k_bcexs(k))
+ elseif (na==5) then
+ ! within-ice BC
+ taer = taer + &
+ (aero_mp(na+3)/rnilyr)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ bcenh_5bd(ns,k_bcins(k),k_bcini(k))
+ waer = waer + &
+ (aero_mp(na+3)/rnilyr)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))
+ gaer = gaer + &
+ (aero_mp(na+3)/rnilyr)*kaer_bc_tab_5bd(ns,k_bcins(k))* &
+ waer_bc_tab_5bd(ns,k_bcins(k))*gaer_bc_tab_5bd(ns,k_bcins(k))
+
+ else
+ ! other species (dust)
+ taer = taer + &
+ (aero_mp(na+3)/rnilyr)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ (aero_mp(na+3)/rnilyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ (aero_mp(na+3)/rnilyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif
+ else !bulk
+
+ taer = taer + &
+ (aero_mp(na+3)*rnilyr)*kaer_tab_5bd(ns,(1+(na-1)/4))
+ waer = waer + &
+ (aero_mp(na+3)*rnilyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))
+ gaer = gaer + &
+ (aero_mp(na+3)*rnilyr)*kaer_tab_5bd(ns,(1+(na-1)/4))* &
+ waer_tab_5bd(ns,(1+(na-1)/4))*gaer_tab_5bd(ns,(1+(na-1)/4))
+ endif ! modal_aero
+ !mgf--
+ enddo ! na
+ gaer = gaer/(waer+puny)
+ waer = waer/(taer+puny)
+ g(k) = (g(k)*w0(k)*tau(k) + gaer*waer*taer) / &
+ (w0(k)*tau(k) + waer*taer)
+ w0(k) = (w0(k)*tau(k) + waer*taer) / &
+ (tau(k) + taer)
+ tau(k) = tau(k) + taer
+ enddo ! k
+ endif ! tr_aero
+! ---------------------------------------------------------------------------
+
+ ! set reflectivities for ocean underlying sea ice
+ ! if ns == 1 (visible), albedo is 0.1, else, albedo is zero
+ rns = real(ns-1, kind=dbl_kind)
+ albodr = cp01 * (c1 - min(rns, c1))
+ albodf = cp01 * (c1 - min(rns, c1))
+
+ ! layer input properties now completely specified: tau, w0, g,
+ ! albodr, albodf; now compute the Delta-Eddington solution
+ ! reflectivities and transmissivities for each layer; then,
+ ! combine the layers going downwards accounting for multiple
+ ! scattering between layers, and finally start from the
+ ! underlying ocean and combine successive layers upwards to
+ ! the surface; see comments in solution_dEdd for more details.
+ call solution_dEdd &
+ (coszen, srftyp, klev, klevp, nslyr, &
+ tau, w0, g, albodr, albodf, &
+ trndir, trntdr, trndif, rupdir, rupdif, &
+ rdndif)
+ ! the interface reflectivities and transmissivities required
+ ! to evaluate interface fluxes are returned from solution_dEdd;
+ ! now compute up and down fluxes for each interface, using the
+ ! combined layer properties at each interface:
+ !
+ ! layers interface
+ !
+ ! --------------------- k
+ ! k
+ ! ---------------------
+
+ do k = 0, klevp
+ ! interface scattering
+ refk = c1/(c1 - rdndif(k)*rupdif(k))
+ ! dir tran ref from below times interface scattering, plus diff
+ ! tran and ref from below times interface scattering
+ ! fdirup(k) = (trndir(k)*rupdir(k) + &
+ ! (trntdr(k)-trndir(k)) &
+ ! *rupdif(k))*refk
+ ! dir tran plus total diff trans times interface scattering plus
+ ! dir tran with up dir ref and down dif ref times interface scattering
+ ! fdirdn(k) = trndir(k) + (trntdr(k) &
+ ! - trndir(k) + trndir(k) &
+ ! *rupdir(k)*rdndif(k))*refk
+ ! diffuse tran ref from below times interface scattering
+ ! fdifup(k) = trndif(k)*rupdif(k)*refk
+ ! diffuse tran times interface scattering
+ ! fdifdn(k) = trndif(k)*refk
+
+ ! dfdir = fdirdn - fdirup
+ dfdir(k) = trndir(k) &
+ + (trntdr(k)-trndir(k)) * (c1 - rupdif(k)) * refk &
+ - trndir(k)*rupdir(k) * (c1 - rdndif(k)) * refk
+ if (dfdir(k) < puny) dfdir(k) = c0 !echmod necessary?
+ ! dfdif = fdifdn - fdifup
+ dfdif(k) = trndif(k) * (c1 - rupdif(k)) * refk
+ if (dfdif(k) < puny) dfdif(k) = c0 !echmod necessary?
+ enddo ! k
+
+ ! note that because the snow IOPs for diffuse and direct incidents
+ ! are different, the snow albedo needs to be calculated twice for
+ ! direct incident and diffuse incident respectively
+ if (nsky == 1) then ! direc beam (keep the direct beam results)
+ do k = 0, klevp
+ dfdir_snicar(k) = dfdir(k)
+ rupdir_snicar(k) = rupdir(k)
+ enddo
+ elseif (nsky == 2) then ! diffuse (keep the diffuse incident results)
+ do k = 0, klevp
+ dfdif_snicar(k) = dfdif(k)
+ rupdif_snicar(k) = rupdif(k)
+ enddo
+ endif
+ enddo ! end direct/diffuse incident nsky
+
+ ! calculate final surface albedos and fluxes-
+ ! all absorbed flux above ksrf is included in surface absorption
+ if( ns == 1) then ! visible
+ swdr = swvdr
+ swdf = swvdf
+ avdr = rupdir_snicar(0)
+ avdf = rupdif_snicar(0)
+ tmp_0 = dfdir_snicar(0 )*swdr + dfdif_snicar(0 )*swdf
+ tmp_ks = dfdir_snicar(ksrf )*swdr + dfdif_snicar(ksrf )*swdf
+ tmp_kl = dfdir_snicar(klevp)*swdr + dfdif_snicar(klevp)*swdf
+
+ ! for layer biology: save visible only
+ do k = nslyr+2, klevp ! Start at DL layer of ice after SSL scattering
+ fthrul(k-nslyr-1) = dfdir_snicar(k)*swdr + dfdif_snicar(k)*swdf
+ enddo
+
+ fsfc = fsfc + tmp_0 - tmp_ks
+ fint = fint + tmp_ks - tmp_kl
+ fthru = fthru + tmp_kl
+
+ ! if snow covered ice, set snow internal absorption; else, Sabs=0
+ if( srftyp == 1 ) then
+ ki = 0
+ do k=1,nslyr
+ ! skip snow SSL, since SSL absorption included in the surface
+ ! absorption fsfc above
+ km = k
+ kp = km + 1
+ ki = ki + 1
+ Sabs(ki) = Sabs(ki) &
+ + dfdir_snicar(km)*swdr + dfdif_snicar(km)*swdf &
+ - (dfdir_snicar(kp)*swdr + dfdif_snicar(kp)*swdf)
+ enddo ! k
+ endif
+
+ ! complex indexing to insure proper absorptions for sea ice
+ ki = 0
+ do k=nslyr+2,nslyr+1+nilyr
+ ! for bare ice, DL absorption for sea ice layer 1
+ km = k
+ kp = km + 1
+ ! modify for top sea ice layer for snow over sea ice
+ if( srftyp == 1 ) then
+ ! must add SSL and DL absorption for sea ice layer 1
+ if( k == nslyr+2 ) then
+ km = k - 1
+ kp = km + 2
+ endif
+ endif
+ ki = ki + 1
+ Iabs(ki) = Iabs(ki) &
+ + dfdir_snicar(km)*swdr + dfdif_snicar(km)*swdf &
+ - (dfdir_snicar(kp)*swdr + dfdif_snicar(kp)*swdf)
+ enddo ! k
+
+ else !if(ns > 1) then ! near IR
+
+ swdr = swidr
+ swdf = swidf
+
+ ! let fr2(3,4,5) = alb_2(3,4,5)*swd*wght2(3,4,5)
+ ! the ns=2(3,4,5) reflected fluxes respectively,
+ ! where alb_2(3,4,5) are the band
+ ! albedos, swd = nir incident shortwave flux, and wght2(3,4,5) are
+ ! the 2(3,4,5) band weights. thus, the total reflected flux is:
+ ! fr = fr2 + fr3 + fr4 + fr5
+ ! = alb_2*swd*wght2 + alb_3*swd*wght3 + alb_4*swd*wght4 + alb_5*swd*wght5
+ ! hence, the 2,3,4,5 nir band albedo is
+ ! alb = fr/swd = alb_2*wght2 + alb_3*wght3 + alb_4*wght4 + alb_5*wght5
+
+ aidr = aidr + rupdir_snicar(0)*wghtns_5bd_drc(ns)
+ aidf = aidf + rupdif_snicar(0)*wghtns_5bd_dfs(ns)
+
+ tmp_0 = dfdir_snicar(0 )*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(0 )*swdf*wghtns_5bd_dfs(ns)
+ tmp_ks = dfdir_snicar(ksrf )*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(ksrf )*swdf*wghtns_5bd_dfs(ns)
+ tmp_kl = dfdir_snicar(klevp)*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(klevp)*swdf*wghtns_5bd_dfs(ns)
+
+ fsfc = fsfc + tmp_0 - tmp_ks
+ fint = fint + tmp_ks - tmp_kl
+ fthru = fthru + tmp_kl
+
+ ! if snow covered ice, set snow internal absorption; else, Sabs=0
+ if( srftyp == 1 ) then
+ ki = 0
+ do k=1,nslyr
+ ! skip snow SSL, since SSL absorption included in the surface
+ ! absorption fsfc above
+ km = k
+ kp = km + 1
+ ki = ki + 1
+ Sabs(ki) = Sabs(ki) &
+ + dfdir_snicar(km)*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(km)*swdf*wghtns_5bd_dfs(ns) &
+ -(dfdir_snicar(kp)*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(kp)*swdf*wghtns_5bd_dfs(ns))
+
+ enddo ! k
+ endif
+
+ ! complex indexing to insure proper absorptions for sea ice
+ ki = 0
+ do k=nslyr+2,nslyr+1+nilyr
+ ! for bare ice, DL absorption for sea ice layer 1
+ km = k
+ kp = km + 1
+ ! modify for top sea ice layer for snow over sea ice
+ if( srftyp == 1 ) then
+ ! must add SSL and DL absorption for sea ice layer 1
+ if( k == nslyr+2 ) then
+ km = k - 1
+ kp = km + 2
+ endif
+ endif
+ ki = ki + 1
+ Iabs(ki) = Iabs(ki) &
+ + dfdir_snicar(km)*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(km)*swdf*wghtns_5bd_dfs(ns) &
+ -(dfdir_snicar(kp)*swdr*wghtns_5bd_drc(ns) &
+ + dfdif_snicar(kp)*swdf*wghtns_5bd_dfs(ns))
+ enddo ! k
+ endif ! ns = 1, ns > 1
+ enddo ! end spectral loop ns
+
+
+ ! accumulate fluxes over bare sea ice
+
+ ! solar zenith angle parameterization
+ ! calculate the scaling factor for NIR direct albedo if SZA>75 degree
+ sza_factor = c1
+ if( srftyp == 1 ) then
+ mu0 = max(coszen,p01)
+ if (mu0 < mu_75) then
+ sza_c1 = sza_a0 + sza_a1 * mu0 + sza_a2 * mu0**2
+ sza_c0 = sza_b0 + sza_b1 * mu0 + sza_b2 * mu0**2
+ sza_factor = sza_c1 * (log10(rsnw(1)) - 6.0) + sza_c0
+ endif
+ endif
+
+ alvdr = avdr
+ alvdf = avdf
+ alidr = aidr * sza_factor !sza factor is always larger than or equal to 1
+ alidf = aidf
+
+ ! note that we assume the reduced NIR energy absorption by snow
+ ! due to corrected snow albedo is absorbed by the snow single
+ ! scattering layer only - this is generally true if snow SSL >= 2 cm
+ ! by the default model set up:
+ ! if snow_depth >= 8 cm, SSL = 4 cm, satisfy
+ ! esle if snow_depth >= 4 cm, SSL = snow_depth/2 >= 2 cm, satisfy
+ ! esle snow_depth < 4 cm, SSL = snow_depth/2, may overcool SSL layer
+ fswsfc = fswsfc + (fsfc- (sza_factor-c1)*aidr*swidr)*fi
+ fswint = fswint + fint *fi
+ fswthru = fswthru + fthru*fi
+
+
+ do k = 1, nslyr
+ Sswabs(k) = Sswabs(k) + Sabs(k)*fi
+ enddo ! k
+
+ do k = 1, nilyr
+ Iswabs(k) = Iswabs(k) + Iabs(k)*fi
+
+ ! bgc layer
+ fswpenl(k) = fswpenl(k) + fthrul(k)* fi
+
+ if (k == nilyr) then
+ fswpenl(k+1) = fswpenl(k+1) + fthrul(k+1)*fi
+ endif
+ enddo ! k
+
+ !----------------------------------------------------------------
+ ! if ice has zero heat capacity, no SW can be absorbed
+ ! in the ice/snow interior, so add to surface absorption.
+ ! Note: nilyr = nslyr = 1 for this case
+ !----------------------------------------------------------------
+
+ if (.not. heat_capacity) then
+
+ ! SW absorbed at snow/ice surface
+ fswsfc = fswsfc + Iswabs(1) + Sswabs(1)
+
+ ! SW absorbed in ice interior
+ fswint = c0
+ Iswabs(1) = c0
+ Sswabs(1) = c0
+
+ endif ! heat_capacity
+
+ end subroutine compute_dEdd_5bd
+
!=======================================================================
end module ice_shortwave
diff --git a/src/core_seaice/column/ice_snow.F90 b/src/core_seaice/column/ice_snow.F90
new file mode 100644
index 0000000000..ec437eab9d
--- /dev/null
+++ b/src/core_seaice/column/ice_snow.F90
@@ -0,0 +1,952 @@
+! SVN:$Id: ice_snow.F90 972 2015-04-15 19:44:20Z njeffery $
+!=======================================================================
+!
+! authors Elizabeth Hunke, LANL
+! Nicole Jeffery, LANL
+
+ module ice_snow
+
+ use ice_kinds_mod
+ use ice_constants_colpkg, only: puny, c0, c1, c10, rhos, Lfresh, &
+ rhow, rhoi, rhofresh, snwlvlfac, &
+ rhosmin
+ use ice_warnings, only: add_warning
+
+ implicit none
+ save
+
+ private
+ public :: snow_effective_density, update_snow_radius, snow_redist,&
+ drain_snow
+
+ real (kind=dbl_kind), parameter, public :: &
+ S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976)
+ S_wet= 0.422_dbl_kind ! (um^3/s) wet metamorphism parameters
+
+!=======================================================================
+
+ contains
+
+!=======================================================================
+
+! Compute effective density of snow layers from ice, liquid water mass
+
+ subroutine snow_effective_density(nslyr, ncat, &
+ vsnon, vsno, &
+ smice, smliq, &
+ rhosnew, &
+ rhos_effn, rhos_eff, &
+ rhos_cmpn, rhos_cmp)
+
+ integer (kind=int_kind), intent(in) :: &
+ nslyr, & ! number of snow layers
+ ncat ! number of thickness categories
+
+ real (kind=dbl_kind), dimension(:), intent(in) :: &
+ vsnon ! snow volume (m)
+
+ real (kind=dbl_kind), intent(in) :: &
+ vsno , & ! total snow volume (m)
+ rhosnew ! new snow density (kg/m^3)
+
+ real (kind=dbl_kind), dimension(:,:), &
+ intent(inout) :: &
+ smice , & ! mass of ice in snow (kg/m^3)
+ smliq , & ! mass of liquid in snow (kg/m^3)
+ rhos_effn, & ! effective snow density: content (kg/m^3)
+ rhos_cmpn ! effective snow density: compaction (kg/m^3)
+
+ real (kind=dbl_kind), intent(inout) :: &
+ rhos_eff , & ! mean effective snow density: content (kg/m^3)
+ rhos_cmp ! mean effective snow density: compaction (kg/m^3)
+
+ integer (kind=int_kind) :: &
+ k , & ! snow layer index
+ n , & ! ice thickness category index
+ cnt ! counter for snow presence
+
+ rhos_eff = c0
+ rhos_cmp = c0
+
+ if (vsno > puny) then
+
+ !-----------------------------------------------------------------
+ ! Initialize effective snow density (compaction) for new snow
+ !-----------------------------------------------------------------
+
+ do n = 1, ncat
+ do k = 1, nslyr
+ if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew
+ enddo
+ enddo
+
+ !-----------------------------------------------------------------
+ ! Compute average effective density of snow
+ !-----------------------------------------------------------------
+
+ do n = 1, ncat
+ if (vsnon(n) > c0) then
+ do k = 1, nslyr
+ rhos_effn(k,n) = rhos_effn(k,n) + smice(k,n) + smliq(k,n)
+ rhos_eff = rhos_eff + vsnon(n)*rhos_effn(k,n)
+ rhos_cmp = rhos_cmp + vsnon(n)*rhos_cmpn(k,n)
+ enddo
+ endif
+ enddo
+ rhos_eff = rhos_eff/(vsno*real(nslyr,kind=dbl_kind))
+ rhos_cmp = rhos_cmp/(vsno*real(nslyr,kind=dbl_kind))
+
+ endif ! vsno
+
+ end subroutine snow_effective_density
+
+!=======================================================================
+
+! Snow redistribution by wind, based on O. Lecomte Ph.D. (2014).
+! Namelist option snwredist = 'ITDsd':
+! Snow in suspension depends on wind speed, density and the standard
+! deviation of the ice thickness distribution. Snow is redistributed
+! among ice categories proportionally to the category areas.
+! Namelist option snwredist = 'ITDrdg':
+! As above, but use the standard deviation of the level and ridged
+! ice thickness distribution for snow in suspension, and redistribute
+! based on ridged ice area.
+
+! convention:
+! volume, mass and energy include factor of ain
+! thickness does not
+
+ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, &
+ snwredist, alvl, vlvl, fresh, fhocn, fsloss, rhos_cmpn, &
+ fsnow, rhosmax, windmin, drhosdwind, l_stop, stop_label)
+
+ use ice_therm_vertical, only: adjust_enthalpy
+
+ integer (kind=int_kind), intent(in) :: &
+ nslyr , & ! number of snow layers
+ ncat ! number of thickness categories
+
+ real (kind=dbl_kind), intent(in) :: &
+ dt , & ! time step (s)
+ wind , & ! wind speed (m/s)
+ fsnow , & ! snowfall rate (kg m-2 s-1)
+ rhosmax , & ! maximum snow density (kg/m^3)
+ windmin , & ! minimum wind speed to compact snow (m/s)
+ drhosdwind ! wind compaction factor (kg s/m^4)
+
+ real (kind=dbl_kind), dimension(:), intent(in) :: &
+ ain , & ! ice area fraction
+ vin , & ! ice volume (m)
+ alvl , & ! level ice area tracer
+ vlvl ! level ice volume tracer
+
+ real (kind=dbl_kind), intent(inout) :: &
+ fresh , & ! fresh water flux to ocean (kg/m^2/s)
+ fhocn , & ! net heat flux to ocean (W/m^2)
+ fsloss ! snow loss to leads (kg/m^2/s)
+
+ real (kind=dbl_kind), dimension(:), intent(inout) :: &
+ vsn ! snow volume (m)
+
+ real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
+ zqsn , & ! snow enthalpy (J/m^3)
+ rhos_cmpn ! effective snow density: compaction (kg/m^3)
+
+ character(len=char_len), intent(in) :: &
+ snwredist ! type of snow redistribution
+
+ logical (kind=log_kind), intent(out) :: &
+ l_stop ! if true, print diagnostics and abort on return
+
+ character (len=*), intent(out) :: stop_label
+
+ ! local variables
+
+ integer (kind=int_kind) :: &
+ n , & ! category index
+ k ! layer index
+
+ integer (kind=int_kind), dimension(ncat) :: &
+ klyr ! layer index
+
+ real (kind=dbl_kind), parameter :: &
+ refsd = c1 , & ! standard deviation reference
+ gamma = 1.e-5_dbl_kind ! tuning coefficient
+
+ real (kind=dbl_kind) :: &
+ Vseas , & ! critical seasonal wind speed (m/s)
+ ITDsd , & ! standard deviation of ITD
+ flost , & ! fraction of snow lost in leads
+ alost , & ! effective lead area for snow lost in leads
+ suma , & ! sum of ice area over categories
+ sumv , & ! sum of ice volume over categories (m)
+ summ , & ! sum of snow mass over categories (kg/m^2)
+ sumq , & ! sum of snow enthalpy over categories (kg/m^2)
+ msusp , & ! potential mass of snow in suspension (kg/m^2)
+ msnw_susp , & ! mass of snow in suspension (kg/m^2)
+ esnw_susp , & ! energy of snow in suspension (J/m^2)
+ asnw_lvl , & ! mass of snow redeposited on level ice (kg/m^2)
+ e_redeptmp, & ! redeposited energy (J/m^2)
+ dhsn , & ! change in snow depth (m)
+ dmp , & ! mass difference in previous layer (kg/m^2)
+ hslyr , & ! snow layer thickness (m)
+ hslab , & ! new snow thickness (m)
+ drhos , & ! change in snow density due to compaction (kg/m^3)
+ mlost , & ! mass of suspended snow lost in leads (kg/m^2)
+ elost , & ! energy of suspended snow lost in leads (J/m^2)
+ de , & ! change in energy (J/m^2)
+ al, ar , & ! areas of level and ridged ice
+ hlvl, hrdg, & ! thicknesses of level and ridged ice
+ tmp1, tmp2, & ! temporary values
+ tmp3, tmp4, & ! temporary values
+ tmp5 , & ! temporary values
+ work ! temporary value
+
+ real (kind=dbl_kind), dimension(ncat) :: &
+ sfac , & ! temporary for snwlvlfac
+ ardg , & ! ridged ice area tracer
+ m_erosion , & ! eroded mass (kg/m^2)
+ e_erosion , & ! eroded energy (J/m^2)
+ m_redep , & ! redeposited mass (kg/m^2)
+ e_redep , & ! redeposited energy (J/m^2)
+ vsn_init , & ! initial volume (m)
+ esn_init , & ! initial energy (J/m^2)
+ esn_final , & ! final energy (J/m^2)
+ atmp , & ! temporary variable for ain, for debugging convenience
+ hin , & ! ice thickness (m)
+ hsn , & ! snow depth (m)
+ hsn_new ! new snow depth (m)
+
+ real (kind=dbl_kind), dimension (nslyr) :: &
+ dzs ! snow layer thickness after redistribution (m)
+
+ real (kind=dbl_kind), dimension (nslyr+1) :: &
+ zs1 , & ! depth of snow layer boundaries (m)
+ zs2 ! adjusted depths, with equal hslyr (m)
+
+ character(len=char_len_long) :: &
+ warning
+
+ !-----------------------------------------------------------------
+ ! Conservation checks
+ !-----------------------------------------------------------------
+
+ l_stop = .false.
+ stop_label = ''
+ tmp1 = c0
+ tmp3 = c0
+ do n = 1, ncat
+ ! mass conservation check
+ tmp1 = tmp1 + vsn(n)
+ vsn_init(n) = vsn(n)
+ esn_init(n) = c0
+ ! energy conservation check
+ do k = 1, nslyr
+ tmp3 = tmp3 + vsn(n)*zqsn(k,n)/nslyr
+ esn_init(n) = esn_init(n) + vsn(n)*zqsn(k,n)/nslyr
+ enddo
+ enddo
+
+ !-----------------------------------------------------------------
+ ! category thickness and sums
+ !-----------------------------------------------------------------
+
+ hin(:) = c0
+ hsn(:) = c0
+ suma = c0
+ sumv = c0
+ do n = 1, ncat
+ atmp(n) = ain(n)
+ if (atmp(n) > puny) then
+ hin(n) = vin(n)/atmp(n)
+ hsn(n) = vsn(n)/atmp(n)
+ endif
+ hsn_new(n) = hsn(n)
+ suma = suma + atmp(n)
+ sumv = sumv + vin(n)
+ ! maintain positive definite enthalpy
+ do k = 1, nslyr
+ zqsn(k,n) = min(zqsn(k,n) + Lfresh*rhos, c0)
+ enddo
+ enddo ! ncat
+
+ !-----------------------------------------------------------------
+ ! standard deviation of ice thickness distribution
+ !-----------------------------------------------------------------
+
+ work = c0
+ asnw_lvl = c0
+ if (trim(snwredist) == 'ITDrdg') then ! use level and ridged ice
+ do n = 1, ncat
+ ardg(n) = c1 - alvl(n) ! ridged ice tracer
+ al = alvl(n) * atmp(n) ! level
+ ar = ardg(n) * atmp(n) ! ridged
+ hlvl = c0
+ hrdg = c0
+ if (al > puny) hlvl = vin(n)*vlvl(n)/al
+ if (ar > puny) hrdg = vin(n)*(c1-vlvl(n))/ar
+ work = work + al*(hlvl - sumv)**2 + ar*(hrdg - sumv)**2
+
+ ! for redeposition of snow on level ice
+ sfac(n) = snwlvlfac
+ if (ardg(n) > c0) sfac(n) = min(snwlvlfac, alvl(n)/ardg(n))
+ asnw_lvl = asnw_lvl + al - sfac(n)*ar
+ enddo
+ asnw_lvl = asnw_lvl/suma
+ else ! snwredist = 'ITDsd' ! use standard ITD
+ do n = 1, ncat
+ work = work + atmp(n)*(hin(n) - sumv)**2
+ enddo
+ endif
+ ITDsd = sqrt(work)
+
+ !-----------------------------------------------------------------
+ ! fraction of suspended snow lost in leads
+ !-----------------------------------------------------------------
+
+ flost = (c1 - suma) * exp(-ITDsd/refsd)
+!echmod flost = c0
+ alost = c1 - suma * (c1-flost)
+
+ !-----------------------------------------------------------------
+ ! suspended snow
+ !-----------------------------------------------------------------
+
+ msusp = c0
+ do n = 1, ncat
+ ! critical seasonal wind speed needed to compact snow to density rhos
+ Vseas = (rhos_cmpn(1,n) - 44.6_dbl_kind)/174.0_dbl_kind ! use top layer
+ Vseas = max(Vseas, c0)
+ ! maximum mass per unit area of snow in suspension (kg/m^2)
+ if (ITDsd > puny) &
+ msusp = msusp + atmp(n)*gamma*dt*max(wind-Vseas,c0) &
+ * (rhosmax-rhos_cmpn(1,n))/(rhosmax*ITDsd)
+ enddo
+
+ !-----------------------------------------------------------------
+ ! erosion
+ !-----------------------------------------------------------------
+
+ msnw_susp = c0
+ esnw_susp = c0
+ klyr(:) = 1
+ do n = 1, ncat
+ m_erosion(n) = c0 ! mass
+ e_erosion(n) = c0 ! energy
+ if (atmp(n) > puny) then
+ m_erosion(n) = min(msusp, rhos*vsn(n))
+ if (m_erosion(n) > puny) then
+ summ = c0
+ dmp = m_erosion(n)
+ do k = 1, nslyr
+ if (dmp > c0) then
+ dhsn = min(hsn(n)/nslyr, dmp/(rhos*atmp(n)))
+ msnw_susp = msnw_susp + dhsn*rhos*atmp(n) ! total mass in suspension
+ hsn_new(n) = hsn_new(n) - dhsn
+ e_erosion(n) = e_erosion(n) + dhsn*zqsn(k,n)*atmp(n)
+ klyr(n) = k ! number of affected layers
+ summ = summ + rhos*vsn(n)/nslyr ! mass, partial sum
+ dmp = max(m_erosion(n) - summ, c0)
+ endif ! dmp
+ enddo
+ esnw_susp = esnw_susp + e_erosion(n) ! total energy in suspension
+ endif
+ endif
+ enddo
+
+ !-----------------------------------------------------------------
+ ! redeposition
+ !-----------------------------------------------------------------
+
+ do n = 1, ncat
+ if (trim(snwredist) == 'ITDrdg') then ! use level and ridged ice
+ work = atmp(n)*(c1-flost)*(ardg(n)*(c1+sfac(n)) + asnw_lvl)
+ else ! use standard ITD
+ work = atmp(n)*(c1-flost)
+ endif
+ m_redep(n) = msnw_susp*work ! mass
+ e_redep(n) = c0
+ e_redeptmp = esnw_susp*work ! energy
+
+ ! change in snow depth
+ dhsn = c0
+ if (atmp(n) > puny) then
+ dhsn = m_redep(n) / (rhos*atmp(n))
+
+ if (abs(dhsn) > c0) then
+
+ e_redep(n) = e_redeptmp
+ vsn(n) = (hsn_new(n)+dhsn)*atmp(n)
+
+ ! change in snow energy
+ de = e_redeptmp / klyr(n)
+ ! spread among affected layers
+ sumq = c0
+ do k = 1, klyr(n)
+ zqsn(k,n) = (atmp(n)*hsn_new(n)*zqsn(k,n) + de) &
+ / (vsn(n)) ! factor of nslyr cancels out
+
+ if (zqsn(k,n) > c0) then
+ sumq = sumq + zqsn(k,n)
+ zqsn(k,n) = c0
+ endif
+
+ enddo ! klyr
+ zqsn(klyr(n),n) = min(zqsn(klyr(n),n) + sumq, c0) ! may lose energy here
+
+ !-----------------------------------------------------------------
+ ! Conserving energy, compute the enthalpy of the new equal layers
+ !-----------------------------------------------------------------
+
+ if (nslyr > 1) then
+
+ dzs(:) = hsn(n) / real(nslyr,kind=dbl_kind) ! old layer thickness
+ do k = 1, klyr(n)
+ dzs(k) = dzs(k) + dhsn / klyr(n) ! old layer thickness (updated)
+ enddo
+ hsn_new(n) = hsn_new(n) + dhsn
+ hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind) ! new layer thickness
+
+ zs1(1) = c0
+ zs1(1+nslyr) = hsn_new(n)
+
+ zs2(1) = c0
+ zs2(1+nslyr) = hsn_new(n)
+
+ do k = 1, nslyr-1
+ zs1(k+1) = zs1(k) + dzs(k) ! old layer depths (unequal thickness)
+ zs2(k+1) = zs2(k) + hslyr ! new layer depths (equal thickness)
+ enddo
+
+ call adjust_enthalpy (nslyr, &
+ zs1(:), zs2(:), &
+ hslyr, hsn_new(n), &
+ zqsn(:,n))
+ endif ! nslyr > 1
+ endif ! |dhsn| > puny
+ endif ! ain > puny
+
+ ! maintain positive definite enthalpy
+ do k = 1, nslyr
+ zqsn(k,n) = zqsn(k,n) - Lfresh*rhos
+ enddo
+ enddo ! ncat
+
+ !-----------------------------------------------------------------
+ ! mass of suspended snow lost in leads
+ !-----------------------------------------------------------------
+ mlost = msnw_susp*alost
+ fsloss = fsloss + mlost / dt
+
+ !-----------------------------------------------------------------
+ ! mass conservation check
+ !-----------------------------------------------------------------
+
+ tmp2 = c0
+ do n = 1, ncat
+ tmp2 = tmp2 + vsn(n)
+ enddo
+
+ if (tmp2 > tmp1) then ! correct roundoff error
+ vsn(:) = vsn(:) * tmp1/tmp2
+ tmp2 = c0
+ do n = 1, ncat
+ tmp2 = tmp2 + vsn(n)
+ enddo
+ endif
+
+ if (tmp2 < tmp1) fresh = fresh + rhos*(tmp1-tmp2)/dt
+
+ tmp2 = tmp2 + (mlost/rhos)
+
+ if (abs(tmp1-tmp2) > puny) then
+ write(warning,*)'mass conservation error in snow_redist', tmp1, tmp2
+ call add_warning(warning)
+ write(warning,*)'klyr',klyr
+ call add_warning(warning)
+ write(warning,*)'ain',atmp(:)
+ call add_warning(warning)
+ write(warning,*)'vsn final',vsn(:)
+ call add_warning(warning)
+ write(warning,*)'vsn init',vsn_init(:)
+ call add_warning(warning)
+ write(warning,*)'rhos*vsn init',rhos*vsn_init(:)
+ call add_warning(warning)
+ write(warning,*)'m_erosion',m_erosion(:)
+ call add_warning(warning)
+ write(warning,*)'m_redep',m_redep(:)
+ call add_warning(warning)
+ write(warning,*)'mlost',mlost
+ call add_warning(warning)
+ write(warning,*)'v_erosion',m_erosion(:)/rhos
+ call add_warning(warning)
+ write(warning,*)'v_redep',m_redep(:)/rhos
+ call add_warning(warning)
+ write(warning,*)'v lost',mlost/rhos
+ call add_warning(warning)
+ write(warning,*)'hsn',hsn(:)
+ call add_warning(warning)
+ write(warning,*)'hsn_new',hsn_new(:)
+ call add_warning(warning)
+ write(warning,*)'vsn_new',hsn_new(:)*atmp(:)
+ call add_warning(warning)
+ write(warning,*)'lost',suma,flost,alost,msnw_susp
+ call add_warning(warning)
+ stop_label = 'snow redistribution mass conservation error'
+ l_stop = .true.
+ endif
+
+ !-----------------------------------------------------------------
+ ! energy conservation check
+ !-----------------------------------------------------------------
+
+ tmp4 = c0
+ tmp5 = c0
+ esn_final(:) = c0
+ do n = 1, ncat
+ do k = 1, nslyr
+ tmp4 = tmp4 + vsn(n)*zqsn(k,n)/nslyr
+ esn_final(n) = esn_final(n) + vsn(n)*zqsn(k,n)/nslyr
+ enddo
+ tmp5 = tmp5 - e_erosion(n) + e_redep(n)
+ enddo
+ tmp5 = tmp5 + esnw_susp*alost
+
+ !-----------------------------------------------------------------
+ ! energy of suspended snow lost in leads
+ !-----------------------------------------------------------------
+ elost = tmp3 - tmp4
+ fhocn = fhocn + elost / dt
+
+ if (abs(tmp5) > nslyr*Lfresh*puny) then
+ write(warning,*)'energy conservation error in snow_redist', tmp3, tmp4, tmp5
+ call add_warning(warning)
+ write(warning,*)'klyr',klyr
+ call add_warning(warning)
+ write(warning,*)'ain',atmp(:)
+ call add_warning(warning)
+ write(warning,*)'vsn final',vsn(:)
+ call add_warning(warning)
+ write(warning,*)'vsn init',vsn_init(:)
+ call add_warning(warning)
+ write(warning,*)'rhos*vsn init',rhos*vsn_init(:)
+ call add_warning(warning)
+ write(warning,*)'m_erosion',m_erosion(:)
+ call add_warning(warning)
+ write(warning,*)'m_redep',m_redep(:)
+ call add_warning(warning)
+ write(warning,*)'mlost',mlost
+ call add_warning(warning)
+ write(warning,*)'v_erosion',m_erosion(:)/rhos
+ call add_warning(warning)
+ write(warning,*)'v_redep',m_redep(:)/rhos
+ call add_warning(warning)
+ write(warning,*)'v lost',mlost/rhos
+ call add_warning(warning)
+ write(warning,*)'hsn',hsn(:)
+ call add_warning(warning)
+ write(warning,*)'hsn_new',hsn_new(:)
+ call add_warning(warning)
+ write(warning,*)'vsn_new',hsn_new(:)*atmp(:)
+ call add_warning(warning)
+ write(warning,*)'lost',suma,flost,alost,msnw_susp
+ call add_warning(warning)
+ write(warning,*)'tmp3(1)', (vsn(1)*zqsn(k,1)/nslyr,k=1,nslyr)
+ call add_warning(warning)
+ write(warning,*)'esn init',esn_init(:)
+ call add_warning(warning)
+ write(warning,*)'esn final',esn_final(:)
+ call add_warning(warning)
+ write(warning,*)'e_erosion',e_erosion(:)
+ call add_warning(warning)
+ write(warning,*)'e_redep',e_redep(:)
+ call add_warning(warning)
+ write(warning,*)'elost',elost,esnw_susp*alost,Lfresh*mlost
+ call add_warning(warning)
+ write(warning,*)'esnw_susp',esnw_susp
+ call add_warning(warning)
+ stop_label = 'snow redistribution energy conservation error'
+ l_stop = .true.
+ endif
+
+ !-----------------------------------------------------------------
+ ! wind compaction
+ !-----------------------------------------------------------------
+
+ do n = 1, ncat
+ if (vsn(n) > puny) then
+ ! compact freshly fallen or redistributed snow
+ drhos = drhosdwind * max(wind - windmin, c0)
+ hslab = c0
+ if (fsnow > c0) &
+ hslab = max(min(fsnow*dt/(rhos+drhos), hsn_new(n)-hsn(n)), c0)
+ hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind)
+ do k = 1, nslyr
+ work = hslab - hslyr * real(k-1,kind=dbl_kind)
+ work = max(c0, min(hslyr, work))
+ rhos_cmpn(k,n) = rhos_cmpn(k,n) + drhos*work/hslyr
+ rhos_cmpn(k,n) = min(rhos_cmpn(k,n), rhosmax)
+ enddo
+ endif
+ enddo
+
+ end subroutine snow_redist
+
+!=======================================================================
+
+! Snow grain metamorphism driver
+
+ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, &
+ Tsfc, zTin, &
+ hsn, zqsn, smice, smliq, &
+ rsnw_fall, rsnw_tmax, &
+ snowage_tau, &
+ snowage_kappa, &
+ snowage_drdt0, &
+ idx_T_max, &
+ idx_Tgrd_max, &
+ idx_rhos_max)
+
+ integer (kind=int_kind), intent(in) :: &
+ ncat, & ! number of categories
+ nslyr, & ! number of snow layers
+ nilyr, & ! number of ice layers
+ idx_T_max, & ! dimensions of snow parameter matrix
+ idx_Tgrd_max, &
+ idx_rhos_max
+
+ real (kind=dbl_kind), intent(in) :: &
+ dt ! time step
+
+ real (kind=dbl_kind), dimension(ncat), intent(in) :: &
+ zTin , & ! surface ice temperature (oC)
+ Tsfc , & ! surface temperature (oC)
+ hin , & ! ice thickness (m)
+ hsn ! snow thickness (m)
+
+ real (kind=dbl_kind), dimension(nslyr,ncat), intent(in) :: &
+ zqsn ! enthalpy of snow (J m-3)
+
+ real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: &
+ rsnw
+
+ real (kind=dbl_kind), dimension(nslyr,ncat), &
+ intent(inout) :: &
+ smice, & ! mass of ice in snow (kg/m^2)
+ smliq ! mass of liquid in snow (kg/m^2)
+
+ real (kind=dbl_kind), intent(in) :: &
+ rsnw_fall, & ! radius of newly fallen snow (10^-6 m)
+ rsnw_tmax ! maximum grain radius from dry metamorphism (10^-6 m)
+
+ ! dry snow aging parameters
+ real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: &
+ snowage_tau, & ! (10^-6 m)
+ snowage_kappa, & !
+ snowage_drdt0 ! (10^-6 m/hr)
+
+ ! local temporary variables
+
+ integer (kind=int_kind) :: k, n
+
+ real (kind=dbl_kind), dimension(nslyr) :: &
+ drsnw_wet, & ! wet metamorphism (10^-6 m)
+ drsnw_dry ! dry (temperature gradient) metamorphism (10^-6 m)
+
+ !-----------------------------------------------------------------
+ ! dry metamorphism
+ !-----------------------------------------------------------------
+ do n = 1, ncat
+
+ if (hsn(n) > puny .and. hin(n) > puny) then
+
+ drsnw_dry(:) = c0
+ drsnw_wet(:) = c0
+
+ call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), drsnw_dry, zqsn(:,n), Tsfc(n), &
+ zTin(n), hsn(n), hin(n), smice(:,n),smliq(:,n), rsnw_fall, &
+ snowage_tau, snowage_kappa, snowage_drdt0, &
+ idx_T_max, idx_Tgrd_max, idx_rhos_max)
+
+ !-----------------------------------------------------------------
+ ! wet metamorphism
+ !-----------------------------------------------------------------
+
+
+ do k = 1,nslyr
+ call snow_wet_metamorph (dt, drsnw_wet(k), rsnw(k,n), smice(k,n),smliq(k,n))
+ rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry(k) + drsnw_wet(k))
+ enddo
+ else
+ do k = 1,nslyr
+ rsnw(k,n) = max(rsnw_fall,min(rsnw_tmax, rsnw(k,n)))
+ smice(k,n) = rhos
+ smliq(k,n) = c0
+ enddo
+
+ endif
+ enddo
+
+ end subroutine update_snow_radius
+
+!=======================================================================
+
+! Snow grain metamorphism
+
+ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, &
+ Tsfc, zTin1, hsn, hin, smice, smliq, rsnw_fall, &
+ snowage_tau, snowage_kappa, snowage_drdt0, &
+ idx_T_max, idx_Tgrd_max, idx_rhos_max)
+
+ use ice_constants_colpkg, only: c0, rhos, Tffresh, Lfresh, cp_ice, p5, puny, c10
+ use ice_colpkg_shared, only: idx_T_min, idx_Tgrd_min, idx_rhos_min
+
+ ! Vapor redistribution: Method is to retrieve 3 best-bit parameters that
+ ! depend on snow temperature, temperature gradient, and density,
+ ! that are derived from the microphysical model described in:
+ ! Flanner and Zender (2006), Linking snowpack microphysics and albedo
+ ! evolution, J. Geophys. Res., 111, D12208, doi:10.1029/2005JD006834.
+ ! The parametric equation has the form:
+ ! dr/dt = drdt_0*(tau/(dr_fresh+tau))^(1/kappa), where:
+ ! r is the effective radius,
+ ! tau and kappa are best-fit parameters,
+ ! drdt_0 is the initial rate of change of effective radius, and
+ ! dr_fresh is the difference between the current and fresh snow states
+ ! (r_current - r_fresh).
+
+ integer (kind=int_kind), intent(in) :: &
+ nslyr, & ! number of snow layers
+ nilyr, & ! number of ice layers
+ idx_T_max, & ! dimensions of snow parameter matrix
+ idx_Tgrd_max, &
+ idx_rhos_max
+
+ real (kind=dbl_kind), intent(in) :: &
+ dt ! time step (s)
+
+ real (kind=dbl_kind), dimension(nslyr), &
+ intent(in) :: &
+ smice , & ! mass of ice in snow (kg/m^3)
+ smliq , & ! mass of liquid in snow (kg/m^3)
+ rsnw, & ! snow grain radius (10^-6 m)
+ zqsn ! snow enthalpy (J m-3)
+
+ real (kind=dbl_kind), dimension(nslyr), &
+ intent(inout) :: &
+ drsnw_dry ! change due to snow aging (10^-6 m)
+
+ real (kind=dbl_kind), intent(in) :: &
+ Tsfc, & ! surface temperature (oC)
+ zTin1, & ! top ice layer temperature (oC)
+ hsn, & ! snow thickness (m)
+ hin, & ! ice thickness (m)
+ rsnw_fall
+
+ ! dry snow aging parameters
+ real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: &
+ snowage_tau, & ! (10^-6 m)
+ snowage_kappa, & !
+ snowage_drdt0 ! (10^-6 m/hr)
+
+ ! local temporary variables
+
+ integer (kind=int_kind) :: k
+
+ integer (kind=int_kind) :: &
+ T_idx, & ! temperature index
+ Tgrd_idx, & ! temperature gradient index
+ rhos_idx ! density index
+
+ real (kind=dbl_kind), dimension(nslyr):: &
+ zrhos, & ! snow density (kg/m^3) ! for variable snow density
+ zdTdz, & ! temperature gradient (K/s)
+ zTsn ! snow temperature (oC)
+
+ real (kind=dbl_kind) :: &
+ bst_tau, & ! snow aging parameter retrieved from lookup table [hour]
+ bst_kappa, & ! snow aging parameter retrieved from lookup table [unitless]
+ bst_drdt0, & ! snow aging parameter retrieved from lookup table [um hr-1]
+ dr_fresh, & ! change in snow radius from fresh (10^-6 m)
+ dzs, & ! snow layer thickness (m)
+ dzi ! ice layer thickness (m)
+
+ character(len=char_len_long) :: &
+ warning ! warning message
+
+! Needed for variable snow density not currently modeled
+! calculate density based on liquid and ice content of snow
+
+ drsnw_dry(:) = c0
+ zTsn(:) = c0
+ zdTdz(:) = c0
+ zrhos(:) = rhos
+
+ dzs = hsn/real(nslyr,kind=dbl_kind)
+ dzi = hin/real(nilyr,kind=dbl_kind)
+
+ if (nslyr == 1) then
+ zTsn(1) =(Lfresh + zqsn(1)/rhos)/cp_ice
+ zdTdz(1) = min(c10*idx_Tgrd_max,abs((zTsn(1)*dzi + zTin1*dzs)/(dzs + dzi+puny)- Tsfc)/(hsn+puny))
+ else
+ zTsn(1) =(Lfresh + zqsn(1)/rhos)/cp_ice
+ do k = 2, nslyr
+ zTsn(k) = (Lfresh + zqsn(k)/rhos)/cp_ice
+ if (k == 2) then
+ zdTdz(k-1) = abs((zTsn(k-1)+zTsn(k))*p5 - Tsfc)/(dzs+puny)
+ zdTdz(k-1) = min(c10*idx_Tgrd_max,zdTdz(k-1))
+ else
+ zdTdz(k-1) = abs(zTsn(k-2)-zTsn(k))*p5/(dzs+puny)
+ zdTdz(k-1) = min(c10*idx_Tgrd_max,zdTdz(k-1))
+ endif
+ enddo
+
+ zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny)- &
+ (zTsn(nslyr) + zTsn(nslyr-1))*p5)/(dzs+puny)
+ zdTdz(nslyr) = min(c10*idx_Tgrd_max,zdTdz(nslyr))
+ endif
+
+ ! best-fit parameters are read from a table
+ ! 11 temperatures from 225 to 273 K
+ ! 31 temperature gradients from 0 to 300 K/m
+ ! 8 snow densities from 0 to 350 kg/m3
+ ! pointer snowage_tau, snowage_kappa, snowage_drdt0
+
+ do k = 1, nslyr
+ zrhos(k) = smice(k) + smliq(k)
+
+ ! best-fit table indecies:
+ T_idx = nint(abs(zTsn(k)+ Tffresh - 223.0_dbl_kind) / 5.0_dbl_kind, kind=int_kind)
+ Tgrd_idx = nint(zdTdz(k) / 10.0_dbl_kind, kind=int_kind)
+ !rhos_idx = nint(zrhos(k)-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! variable density
+ rhos_idx = nint((rhos-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! fixed density
+
+ ! boundary check:
+ T_idx = min(idx_T_max, max(1,T_idx+1))!min(idx_T_max, max(idx_T_min,T_idx))
+ Tgrd_idx = min(idx_Tgrd_max, max(1,Tgrd_idx+1))!min(idx_Tgrd_max, max(idx_Tgrd_min,Tgrd_idx))
+ rhos_idx = min(idx_rhos_max, max(1,rhos_idx+1)) !min(idx_rhos_max, max(idx_rhos_min,rhos_idx))
+
+ bst_tau = snowage_tau(rhos_idx,Tgrd_idx,T_idx)
+ bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx)
+ bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx)
+
+ ! change in snow effective radius, using best-fit parameters
+ dr_fresh = max(c0,rsnw(k)-rsnw_fall)
+ drsnw_dry(k) = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa))&
+ * (dt/3600.0_dbl_kind)
+ enddo
+
+ end subroutine snow_dry_metamorph
+
+!=======================================================================
+
+! Snow grain metamorphism
+
+ subroutine snow_wet_metamorph (dt, dr_wet, rsnw, smice, smliq)
+
+ use ice_constants_colpkg, only: c0, c1, c4, pi, p1, c100
+ !
+ ! Liquid water redistribution: Apply the grain growth function from:
+ ! Brun, E. (1989), Investigation of wet-snow metamorphism in respect of
+ ! liquid-water content, Annals of Glaciology, 13, 22-26.
+ ! There are two parameters that describe the grain growth rate as
+ ! a function of snow liquid water content (LWC). The "LWC=0" parameter
+ ! is zeroed here because we are accounting for dry snowing with a
+ ! different representation
+ !
+ real (kind=dbl_kind), intent(in) :: &
+ dt ! time step
+
+ real (kind=dbl_kind), &
+ intent(in) :: &
+ rsnw , & ! snow grain radius (10^-6 m)
+ smice, & ! snow ice density (kg/m^3)
+ smliq ! snow liquid density (kg/m^3)
+
+ real (kind=dbl_kind), &
+ intent(inout) :: &
+ dr_wet
+
+ real (kind=dbl_kind) :: &
+ fliq ! liquid mass fraction
+
+ dr_wet = c0
+ fliq = c1
+ if (smice + smliq > c0 .and. rsnw > c0) then
+ fliq = min(smliq/(smice + smliq),p1)*c100
+ dr_wet = S_wet * fliq**3*dt/(c4*pi*rsnw**2)
+ endif
+
+ end subroutine snow_wet_metamorph
+
+!=======================================================================
+
+! Conversions between ice mass, liquid water mass in snow
+
+ subroutine drain_snow (dt, nslyr, vsnon, aicen, &
+ smice, smliq, meltsliq)
+
+ integer (kind=int_kind), intent(in) :: &
+ nslyr ! number of snow layers
+
+ real (kind=dbl_kind), intent(in) :: &
+ dt, & ! time step
+ vsnon, & ! snow volume (m)
+ aicen ! aice area
+
+ real (kind=dbl_kind), intent(inout) :: &
+ meltsliq ! total liquid content
+
+ real (kind=dbl_kind), dimension(nslyr), &
+ intent(in) :: &
+ smice ! mass of ice in snow (kg/m^2)
+
+ real (kind=dbl_kind), dimension(nslyr), &
+ intent(inout) :: &
+ smliq ! mass of liquid in snow (kg/m^2)
+
+ ! local temporary variables
+
+ integer (kind=int_kind) :: k
+
+ real (kind=dbl_kind) :: &
+ hslyr, & ! snow layer thickness (m)
+ hsn ! snow thickness (m)
+
+ real (kind=dbl_kind), dimension(nslyr) :: &
+ dlin , & ! liquid into the layer from above (kg/m^2)
+ dlout , & ! liquid out of the layer (kg/m^2)
+ phi_liq , & ! volumetric liquid fraction
+ phi_ice , & ! volumetric ice fraction
+ w_drain ! flow between layers
+
+ hsn = c0
+ if (aicen > c0) hsn = vsnon/aicen
+ if (hsn > puny) then
+ dlin(:) = c0
+ dlout(:) = c0
+ hslyr = hsn / real(nslyr,kind=dbl_kind)
+ meltsliq = c0
+ do k = 1,nslyr
+ smliq(k) = smliq(k) + dlin(k) / hslyr ! liquid in from above layer
+ phi_ice(k) = min(c1, smice(k) / rhoi)
+ phi_liq(k) = smliq(k)/rhofresh
+ w_drain(k) = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) / dt * rhofresh * hslyr)
+ dlout(k) = w_drain(k) * dt
+ smliq(k) = smliq(k) - dlout(k)/ hslyr
+ if (k < nslyr) then
+ dlin(k+1) = dlout(k)
+ else
+ meltsliq = dlout(nslyr)
+ endif
+ enddo
+ else
+ meltsliq = meltsliq ! computed in thickness_changes
+ endif
+
+ end subroutine drain_snow
+
+!=======================================================================
+
+ end module ice_snow
+
+!=======================================================================
diff --git a/src/core_seaice/column/ice_therm_0layer.F90 b/src/core_seaice/column/ice_therm_0layer.F90
index 4ebb968c47..0cb42522f2 100644
--- a/src/core_seaice/column/ice_therm_0layer.F90
+++ b/src/core_seaice/column/ice_therm_0layer.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_therm_0layer.F90 1182 2017-03-16 19:29:26Z njeffery $
+! SVN:$Id: ice_therm_0layer.F90 1196 2017-04-18 13:32:23Z eclare $
!=========================================================================
!
! Update ice and snow internal temperatures
diff --git a/src/core_seaice/column/ice_therm_bl99.F90 b/src/core_seaice/column/ice_therm_bl99.F90
index a6dc588dc9..fea2d8494d 100644
--- a/src/core_seaice/column/ice_therm_bl99.F90
+++ b/src/core_seaice/column/ice_therm_bl99.F90
@@ -1,4 +1,4 @@
- ! SVN:$Id: ice_therm_bl99.F90 1182 2017-03-16 19:29:26Z njeffery $
+ ! SVN:$Id: ice_therm_bl99.F90 1196 2017-04-18 13:32:23Z eclare $
!=========================================================================
!
! Update ice and snow internal temperatures
diff --git a/src/core_seaice/column/ice_therm_itd.F90 b/src/core_seaice/column/ice_therm_itd.F90
index d9b617841d..0c8fac0928 100644
--- a/src/core_seaice/column/ice_therm_itd.F90
+++ b/src/core_seaice/column/ice_therm_itd.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_therm_itd.F90 1182 2017-03-16 19:29:26Z njeffery $
+! SVN:$Id: ice_therm_itd.F90 1196 2017-04-18 13:32:23Z eclare $
!=======================================================================
!
! Thermo calculations after call to coupler, related to ITD:
@@ -23,7 +23,7 @@ module ice_therm_itd
use ice_kinds_mod
use ice_constants_colpkg, only: c0, c1, c2, c3, c4, c6, c10, &
p001, p1, p333, p5, p666, puny, bignum, &
- rhos, rhoi, Lfresh, ice_ref_salinity
+ rhos, rhoi, Lfresh, ice_ref_salinity, rhosmin
use ice_warnings, only: add_warning
@@ -66,22 +66,23 @@ module ice_therm_itd
! authors: William H. Lipscomb, LANL
! Elizabeth C. Hunke, LANL
- subroutine linear_itd (ncat, hin_max, &
- nilyr, nslyr, &
- ntrcr, trcr_depend, &
+ subroutine linear_itd (ncat, hin_max, &
+ nilyr, nslyr, &
+ ntrcr, trcr_depend, &
trcr_base, n_trcr_strata,&
- nt_strata, &
- aicen_init, vicen_init, &
- aicen, trcrn, &
- vicen, vsnon, &
- aice, aice0, &
- fpond, l_stop, &
+ nt_strata, Tf, &
+ aicen_init, vicen_init, &
+ aicen, trcrn, &
+ vicen, vsnon, &
+ aice, aice0, &
+ fpond, l_stop, &
stop_label)
use ice_itd, only: aggregate_area, shift_ice, &
column_sum, column_conservation_check
use ice_colpkg_tracers, only: nt_qice, nt_qsno, nt_fbri, nt_sice, &
- tr_pond_topo, nt_apnd, nt_hpnd, tr_brine
+ tr_pond_topo, nt_apnd, nt_hpnd, tr_brine, &
+ nt_rhos, tr_snow
use ice_therm_shared, only: hi_min
integer (kind=int_kind), intent(in) :: &
@@ -90,7 +91,10 @@ subroutine linear_itd (ncat, hin_max, &
nslyr , & ! number of snow layers
ntrcr ! number of tracers in use
- real (kind=dbl_kind), dimension(0:ncat), intent(inout) :: &
+ real (kind=dbl_kind), intent(in) :: &
+ Tf ! ocean freezing temperature (C)
+
+ real (kind=dbl_kind), dimension(0:ncat), intent(in) :: &
hin_max ! category boundaries (m)
integer (kind=int_kind), dimension (:), intent(in) :: &
@@ -197,8 +201,6 @@ subroutine linear_itd (ncat, hin_max, &
l_stop = .false.
- hin_max(ncat) = 999.9_dbl_kind ! arbitrary big number
-
do n = 1, ncat
donor(n) = 0
daice(n) = c0
@@ -230,7 +232,7 @@ subroutine linear_itd (ncat, hin_max, &
if (tr_brine) then
vbrin(n) = vbrin(n) + trcrn(nt_fbri,n) &
- * vicen(n)/real(nilyr,kind=dbl_kind)
+ * vicen(n)
endif
do k = 1, nilyr
@@ -542,12 +544,21 @@ subroutine linear_itd (ncat, hin_max, &
trcrn(k,n) = trcrn(k,n) + rhos*Lfresh
enddo
enddo
-
+ ! maintain rhos_cmp positive definiteness
+ if (tr_snow) then
+ do n = 1, ncat
+ do k = nt_rhos, nt_rhos+nslyr-1
+ trcrn(k,n) = max(trcrn(k,n)-rhosmin, c0)
+! trcrn(k,n) = trcrn(k,n) - rhosmin
+ enddo
+ enddo
+ endif
+
call shift_ice (ntrcr, ncat, &
trcr_depend, &
trcr_base, &
n_trcr_strata, &
- nt_strata, &
+ nt_strata, Tf, &
aicen, trcrn, &
vicen, vsnon, &
hicen, donor, &
@@ -561,6 +572,14 @@ subroutine linear_itd (ncat, hin_max, &
trcrn(k,n) = trcrn(k,n) - rhos*Lfresh
enddo
enddo
+ ! maintain rhos_cmp positive definiteness
+ if (tr_snow) then
+ do n = 1, ncat
+ do k = nt_rhos, nt_rhos+nslyr-1
+ trcrn(k,n) = trcrn(k,n) + rhosmin
+ enddo
+ enddo
+ endif
!-----------------------------------------------------------------
! Make sure hice(1) >= minimum ice thickness hi_min.
@@ -609,7 +628,7 @@ subroutine linear_itd (ncat, hin_max, &
if (tr_brine) then
vbrin(n) = vbrin(n) + trcrn(nt_fbri,n) &
- * vicen(n)/real(nilyr,kind=dbl_kind)
+ * vicen(n)
endif
do k = 1, nilyr
@@ -840,7 +859,7 @@ subroutine lateral_melt (dt, ncat, &
use ice_colpkg_tracers, only: nt_qice, nt_qsno, nt_aero, tr_aero, &
tr_pond_topo, nt_apnd, nt_hpnd, bio_index
use ice_colpkg_shared, only: z_tracers , hs_ssl, solve_zsal
- use ice_zbgc, only: lateral_melt_bgc
+ use ice_zbgc, only: lateral_melt_bgc
real (kind=dbl_kind), intent(in) :: &
dt ! time step (s)
@@ -874,7 +893,7 @@ subroutine lateral_melt (dt, ncat, &
real (kind=dbl_kind), dimension(nbtrcr), &
intent(inout) :: &
- flux_bio ! biology tracer flux from layer bgc (mmol/m^2/s)
+ flux_bio ! biology tracer flux from layer bgc (mmol/m^2/s)
real (kind=dbl_kind), dimension(:), intent(inout) :: &
faero_ocn ! aerosol flux to ocean (kg/m^2/s)
@@ -958,10 +977,10 @@ subroutine lateral_melt (dt, ncat, &
!-----------------------------------------------------------------
! Biogeochemistry
- !-----------------------------------------------------------------
+ !-----------------------------------------------------------------
if (z_tracers) then ! snow tracers
- dvssl = min(p5*vsnon(n), hs_ssl*aicen(n)) !snow surface layer
+ dvssl = min(p5*vsnon(n)/real(nslyr,kind=dbl_kind), hs_ssl*aicen(n)) !snow surface layer
dvint = vsnon(n)- dvssl !snow interior
do k = 1, nbtrcr
flux_bio(k) = flux_bio(k) &
@@ -976,9 +995,10 @@ subroutine lateral_melt (dt, ncat, &
if (solve_zsal .or. z_tracers) &
call lateral_melt_bgc(dt, &
ncat, nblyr, &
- rside, vicen_init, &
+ rside, vicen, &
trcrn, fzsal, &
- flux_bio, nbtrcr)
+ flux_bio, nbtrcr, &
+ vicen_init)
endif ! rside
@@ -1006,7 +1026,7 @@ end subroutine lateral_melt
!
subroutine add_new_ice (ncat, nilyr, nblyr, &
n_aero, dt, &
- ntrcr, nltrcr, &
+ ntrcr, nbtrcr, &
hin_max, ktherm, &
aicen, trcrn, &
vicen, vsnon1, &
@@ -1018,8 +1038,8 @@ subroutine add_new_ice (ncat, nilyr, nblyr, &
Tf, sss, &
salinz, phi_init, &
dSin0_frazil, &
- bgrid, cgrid, igrid, &
- nbtrcr, flux_bio, &
+ bgrid, cgrid, &
+ igrid, flux_bio, &
ocean_bio, fzsal, &
frazil_diag, &
l_stop, stop_label)
@@ -1041,7 +1061,7 @@ subroutine add_new_ice (ncat, nilyr, nblyr, &
nilyr , & ! number of ice layers
nblyr , & ! number of bio layers
ntrcr , & ! number of tracers
- nltrcr, & ! number of zbgc tracers
+ nbtrcr, & ! number of bio tracer types
n_aero, & ! number of aerosol tracers
ktherm ! type of thermodynamics (0 0-layer, 1 BL99, 2 mushy)
@@ -1103,9 +1123,6 @@ subroutine add_new_ice (ncat, nilyr, nblyr, &
real (kind=dbl_kind), dimension (nilyr+1), intent(in) :: &
cgrid ! CICE vertical coordinate
- integer (kind=int_kind), intent(in) :: &
- nbtrcr ! number of biology tracers
-
real (kind=dbl_kind), dimension (:), intent(inout) :: &
flux_bio ! tracer flux to ocean from biology (mmol/m^2/s)
@@ -1165,7 +1182,10 @@ subroutine add_new_ice (ncat, nilyr, nblyr, &
vbri_final ! brine volume summed over categories
real (kind=dbl_kind), dimension (ncat) :: &
- vbrin ! trcrn(nt_fbri,n)*vicen(n)
+ vbrin ! trcrn(nt_fbri,n)*vicen(n)
+
+ character(len=char_len_long) :: &
+ warning ! warning message
!-----------------------------------------------------------------
! initialize
@@ -1490,12 +1510,12 @@ subroutine add_new_ice (ncat, nilyr, nblyr, &
!-----------------------------------------------------------------
if (tr_brine .or. nbtrcr > 0) &
call add_new_ice_bgc(dt, nblyr, &
- ncat, nilyr, nltrcr, &
+ ncat, nilyr, nbtrcr, &
bgrid, cgrid, igrid, &
aicen_init, vicen_init, vi0_init, &
aicen, vicen, vsnon1, &
vi0new, ntrcr, trcrn, &
- nbtrcr, sss, ocean_bio,&
+ sss, ocean_bio, &
flux_bio, hsurp, &
l_stop, stop_label, &
l_conservation_check)
diff --git a/src/core_seaice/column/ice_therm_mushy.F90 b/src/core_seaice/column/ice_therm_mushy.F90
index 78401ca716..769e11c819 100644
--- a/src/core_seaice/column/ice_therm_mushy.F90
+++ b/src/core_seaice/column/ice_therm_mushy.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_therm_mushy.F90 1182 2017-03-16 19:29:26Z njeffery $
+! SVN:$Id: ice_therm_mushy.F90 1196 2017-04-18 13:32:23Z eclare $
!=======================================================================
module ice_therm_mushy
@@ -19,7 +19,8 @@ module ice_therm_mushy
private
public :: &
temperature_changes_salinity, &
- permeability
+ permeability, &
+ update_vertical_tracers_snow
real(kind=dbl_kind), parameter :: &
dTemp_errmax = 5.0e-4_dbl_kind ! max allowed change in temperature
@@ -50,6 +51,8 @@ subroutine temperature_changes_salinity(dt, &
fcondtop, fcondbot, &
fadvheat, snoice, &
einit_old, &
+ smice, smliq, &
+ tr_snow, &
lstop, stop_label)
! solve the enthalpy and bulk salinity of the ice for a single column
@@ -96,7 +99,9 @@ subroutine temperature_changes_salinity(dt, &
real (kind=dbl_kind), dimension (:), intent(inout) :: &
Sswabs , & ! SW radiation absorbed in snow layers (W m-2)
- Iswabs ! SW radiation absorbed in ice layers (W m-2)
+ Iswabs , & ! SW radiation absorbed in ice layers (W m-2)
+ smice , & ! ice mass tracer in snow (kg/m^3)
+ smliq ! liquid water mass tracer in snow (kg/m^3)
real (kind=dbl_kind), intent(inout):: &
fsurfn , & ! net flux to top surface, excluding fcondtopn
@@ -120,6 +125,9 @@ subroutine temperature_changes_salinity(dt, &
zqsn , & ! snow layer enthalpy (J m-3)
zTsn ! internal snow layer temperatures
+ logical (kind=log_kind), intent(in) :: &
+ tr_snow ! if .true., use snow tracers
+
logical (kind=log_kind), intent(inout) :: &
lstop ! solver failure flag
@@ -326,6 +334,8 @@ subroutine temperature_changes_salinity(dt, &
phi, dt, &
zSin, Sbr, &
sss, qocn, &
+ smice, smliq, &
+ tr_snow, &
snoice, fadvheat)
end subroutine temperature_changes_salinity
@@ -523,7 +533,7 @@ subroutine two_stage_solver_snow(nilyr, nslyr, &
! check if solution is consistent
! surface conductive heat flux should be less than
! incoming surface heat flux
- if (fcondtop - fsurfn < ferrmax) then
+ if (fcondtop - fsurfn < 0.9_dbl_kind*ferrmax) then
! solution is consistent - have solution so finish
return
@@ -576,7 +586,7 @@ subroutine two_stage_solver_snow(nilyr, nslyr, &
! check if solution is consistent
! surface conductive heat flux should be less than
! incoming surface heat flux
- if (fcondtop - fsurfn < ferrmax) then
+ if (fcondtop - fsurfn < 0.9_dbl_kind*ferrmax) then
! solution is consistent - have solution so finish
return
@@ -842,7 +852,7 @@ subroutine two_stage_solver_nosnow(nilyr, nslyr, &
! check if solution is consistent
! surface conductive heat flux should be less than
! incoming surface heat flux
- if (fcondtop - fsurfn < ferrmax) then
+ if (fcondtop - fsurfn < 0.9_dbl_kind*ferrmax) then
! solution is consistent - have solution so finish
return
@@ -895,7 +905,7 @@ subroutine two_stage_solver_nosnow(nilyr, nslyr, &
! check if solution is consistent
! surface conductive heat flux should be less than
! incoming surface heat flux
- if (fcondtop - fsurfn < ferrmax) then
+ if (fcondtop - fsurfn < 0.9_dbl_kind*ferrmax) then
! solution is consistent - have solution so finish
return
@@ -1364,13 +1374,30 @@ subroutine picard_solver(nilyr, nslyr, &
! if not converged
if (.not. lconverged) then
- call picard_nonconvergence(nilyr, nslyr,&
- Tsf0, Tsf, &
- zTsn0, zTsn, &
- zTin0, zTin, &
- zSin0, zSin, &
- zqsn0, zqsn, &
- zqin0, phi)
+ call picard_nonconvergence(nilyr, nslyr, &
+ Tsf0, Tsf, &
+ zTsn0, zTsn, &
+ zTin0, zTin, &
+ zSin0, zSin, &
+ zqsn0, zqsn, &
+ zqin0, phi, &
+ dt, &
+ hilyr, hslyr, &
+ km, ks, &
+ Iswabs, Sswabs, &
+ Tbot, &
+ fswint, fswsfc, &
+ rhoa, flw, &
+ potT, Qa, &
+ shcoef, lhcoef, &
+ fcondtop, fcondbot, &
+ fadvheat, &
+ flwoutn, fsensn, &
+ flatn, fsurfn, &
+ qpond, qocn, &
+ Spond, sss, &
+ q, dSdt, &
+ w)
lstop = .true.
stop_label = "picard_solver: Picard solver non-convergence"
@@ -1380,13 +1407,30 @@ end subroutine picard_solver
!=======================================================================
- subroutine picard_nonconvergence(nilyr, nslyr,&
- Tsf0, Tsf, &
- zTsn0, zTsn, &
- zTin0, zTin, &
- zSin0, zSin, &
- zqsn0, zqsn, &
- zqin0, phi)
+ subroutine picard_nonconvergence(nilyr, nslyr, &
+ Tsf0, Tsf, &
+ zTsn0, zTsn, &
+ zTin0, zTin, &
+ zSin0, zSin, &
+ zqsn0, zqsn, &
+ zqin0, phi, &
+ dt, &
+ hilyr, hslyr, &
+ km, ks, &
+ Iswabs, Sswabs, &
+ Tbot, &
+ fswint, fswsfc, &
+ rhoa, flw, &
+ potT, Qa, &
+ shcoef, lhcoef, &
+ fcondtop, fcondbot, &
+ fadvheat, &
+ flwoutn, fsensn, &
+ flatn, fsurfn, &
+ qpond, qocn, &
+ Spond, sss, &
+ q, dSdt, &
+ w)
integer (kind=int_kind), intent(in) :: &
nilyr , & ! number of ice layers
@@ -1408,29 +1452,150 @@ subroutine picard_nonconvergence(nilyr, nslyr,&
phi , & ! ice layer liquid fraction
zqin0
+ real(kind=dbl_kind), intent(in) :: &
+ dt , & ! time step (s)
+ hilyr , & ! ice layer thickness (m)
+ hslyr , & ! snow layer thickness (m)
+ Tbot , & ! ice bottom surfce temperature (deg C)
+ fswint , & ! SW absorbed in ice interior below surface (W m-2)
+ fswsfc , & ! SW absorbed at ice/snow surface (W m-2)
+ rhoa , & ! air density (kg/m^3)
+ flw , & ! incoming longwave radiation (W/m^2)
+ potT , & ! air potential temperature (K)
+ Qa , & ! specific humidity (kg/kg)
+ shcoef , & ! transfer coefficient for sensible heat
+ lhcoef , & ! transfer coefficient for latent heat
+ qpond , & ! melt pond brine enthalpy (J m-3)
+ qocn , & ! ocean brine enthalpy (J m-3)
+ Spond , & ! melt pond salinity (ppt)
+ sss , & ! sea surface salinity (ppt)
+ w ! vertical flushing Darcy velocity (m/s)
+
+ real(kind=dbl_kind), dimension(:), intent(in) :: &
+ km , & ! ice conductivity (W m-1 K-1)
+ Iswabs , & ! SW radiation absorbed in ice layers (W m-2)
+ dSdt ! gravity drainage desalination rate for slow mode (ppt s-1)
+
+ real(kind=dbl_kind), dimension(0:nilyr), intent(in) :: &
+ q ! upward interface vertical Darcy flow (m s-1)
+
+ real(kind=dbl_kind), dimension(:), intent(in) :: &
+ ks , & ! snow conductivity (W m-1 K-1)
+ Sswabs ! SW radiation absorbed in snow layers (W m-2)
+
+ real(kind=dbl_kind), intent(in) :: &
+ flwoutn , & ! upward LW at surface (W m-2)
+ fsensn , & ! surface downward sensible heat (W m-2)
+ flatn , & ! surface downward latent heat (W m-2)
+ fsurfn ! net flux to top surface, excluding fcondtop
+
+ real(kind=dbl_kind), intent(in) :: &
+ fcondtop , & ! downward cond flux at top surface (W m-2)
+ fcondbot , & ! downward cond flux at bottom surface (W m-2)
+ fadvheat ! flow of heat to ocean due to advection (W m-2)
+
integer :: &
k ! vertical layer index
character(len=char_len_long) :: &
warning ! warning message
-
+
write(warning,*) "-------------------------------------"
call add_warning(warning)
+ write(warning,*)
+ call add_warning(warning)
write(warning,*) "picard convergence failed!"
call add_warning(warning)
+ write(warning,*) "=========================="
+ call add_warning(warning)
+ write(warning,*)
+ call add_warning(warning)
+
+ write(warning,*) "Surface: Tsf0, Tsf"
+ call add_warning(warning)
write(warning,*) 0, Tsf0, Tsf
call add_warning(warning)
-
+ write(warning,*)
+ call add_warning(warning)
+
+ write(warning,*) "Snow: zTsn0(k), zTsn(k), zqsn0(k), ks(k), Sswabs(k)"
+ call add_warning(warning)
do k = 1, nslyr
- write(warning,*) k, zTsn0(k), zTsn(k), zqsn0(k)
+ write(warning,*) k, zTsn0(k), zTsn(k), zqsn0(k), ks(k), Sswabs(k)
call add_warning(warning)
- enddo ! k
-
+ enddo ! k
+ write(warning,*)
+ call add_warning(warning)
+
+ write(warning,*) "Ice: zTin0(k), zTin(k), zSin0(k), zSin(k), phi(k), zqin0(k), km(k), Iswabs(k), dSdt(k)"
+ call add_warning(warning)
do k = 1, nilyr
- write(warning,*) k, zTin0(k), zTin(k), zSin0(k), zSin(k), phi(k), zqin0(k)
+ write(warning,*) k, zTin0(k), zTin(k), zSin0(k), zSin(k), phi(k), zqin0(k), km(k), Iswabs(k), dSdt(k)
call add_warning(warning)
enddo ! k
+ write(warning,*)
+ call add_warning(warning)
+
+ write(warning,*) "Ice boundary: q(k)"
+ call add_warning(warning)
+ do k = 0, nilyr
+ write(warning,*) k, q(k)
+ call add_warning(warning)
+ enddo ! k
+ write(warning,*)
+ call add_warning(warning)
+
+ write(warning,*) "dt: ", dt
+ call add_warning(warning)
+ write(warning,*) "hilyr: ", hilyr
+ call add_warning(warning)
+ write(warning,*) "hslyr: ", hslyr
+ call add_warning(warning)
+ write(warning,*) "Tbot: ", Tbot
+ call add_warning(warning)
+ write(warning,*) "fswint: ", fswint
+ call add_warning(warning)
+ write(warning,*) "fswsfc: ", fswsfc
+ call add_warning(warning)
+ write(warning,*) "rhoa: ", rhoa
+ call add_warning(warning)
+ write(warning,*) "flw: ", flw
+ call add_warning(warning)
+ write(warning,*) "potT: ", potT
+ call add_warning(warning)
+ write(warning,*) "Qa: ", Qa
+ call add_warning(warning)
+ write(warning,*) "shcoef: ", shcoef
+ call add_warning(warning)
+ write(warning,*) "lhcoef: ", lhcoef
+ call add_warning(warning)
+ write(warning,*) "qpond: ", qpond
+ call add_warning(warning)
+ write(warning,*) "qocn: ", qocn
+ call add_warning(warning)
+ write(warning,*) "Spond: ", Spond
+ call add_warning(warning)
+ write(warning,*) "sss: ", sss
+ call add_warning(warning)
+ write(warning,*) "w: ", w
+ call add_warning(warning)
+ write(warning,*) "flwoutn: ", flwoutn
+ call add_warning(warning)
+ write(warning,*) "fsensn: ", fsensn
+ call add_warning(warning)
+ write(warning,*) "flatn: ", flatn
+ call add_warning(warning)
+ write(warning,*) "fsurfn: ", fsurfn
+ call add_warning(warning)
+ write(warning,*) "fcondtop: ", fcondtop
+ call add_warning(warning)
+ write(warning,*) "fcondbot: ", fcondbot
+ call add_warning(warning)
+ write(warning,*) "fadvheat: ", fadvheat
+ call add_warning(warning)
+ write(warning,*)
+ call add_warning(warning)
write(warning,*) "-------------------------------------"
call add_warning(warning)
@@ -3181,6 +3346,8 @@ subroutine flood_ice(hsn, hin, &
phi, dt, &
zSin, Sbr, &
sss, qocn, &
+ smice, smliq, &
+ tr_snow, &
snoice, fadvheat)
! given upwards flushing brine flow calculate amount of snow ice and
@@ -3204,7 +3371,9 @@ subroutine flood_ice(hsn, hin, &
zqsn , & ! snow layer enthalpy (J m-2)
zqin , & ! ice layer enthalpy (J m-2)
zSin , & ! ice layer bulk salinity (ppt)
- phi ! ice liquid fraction
+ phi , & ! ice liquid fraction
+ smice , & ! ice mass tracer in snow (kg/m^3)
+ smliq ! liquid water mass tracer in snow (kg/m^3)
real(kind=dbl_kind), dimension(:), intent(in) :: &
Sbr ! ice layer brine salinity (ppt)
@@ -3216,9 +3385,12 @@ subroutine flood_ice(hsn, hin, &
real(kind=dbl_kind), intent(out) :: &
snoice ! snow ice formation
- real(kind=dbl_kind), intent(inout) :: &
+ real(kind=dbl_kind), intent(inout) :: &
fadvheat ! advection heat flux to ocean
+ logical (kind=log_kind), intent(in) :: &
+ tr_snow ! if .true., use snow tracers
+
real(kind=dbl_kind) :: &
hin2 , & ! new ice thickness (m)
hsn2 , & ! new snow thickness (m)
@@ -3232,6 +3404,7 @@ subroutine flood_ice(hsn, hin, &
zqsn_snowice , & ! snow enthalpy of snow thats becoming snowice (J m-2)
freeboard_density , & ! negative of ice surface freeboard times the ocean density (kg m-2)
ice_mass , & ! mass of the ice (kg m-2)
+ snow_mass , & ! mass of the ice (kg m-2)
rho_ocn , & ! density of the ocean (kg m-3)
ice_density , & ! density of ice layer (kg m-3)
hadded , & ! thickness rate of water used from ocean (m/s)
@@ -3257,16 +3430,32 @@ subroutine flood_ice(hsn, hin, &
enddo ! k
ice_mass = ice_mass * hilyr
+! for now, do not use variable snow density
+! snow_mass = c0
+! if (tr_snow) then
+! do k = 1,nslyr
+! snow_mass = snow_mass + (smice(k) + smliq(k)) * hslyr
+! enddo
+! else
+ snow_mass = rhos * hsn
+! endif
+
! negative freeboard times ocean density
- freeboard_density = max(ice_mass + hsn * rhos - hin * rho_ocn, c0)
+ freeboard_density = max(ice_mass + snow_mass - hin * rho_ocn, c0)
! check if have flooded ice
if (freeboard_density > c0) then
! sea ice fraction of newly formed snow ice
- phi_snowice = (c1 - rhos / rhoi)
+! phi_snowice = (c1 - snow_mass / hsn / rhoi) ! non-BFB
+ phi_snowice = (c1 - rhos / rhoi) ! for now, do not use variable snow density
- ! density of newly formed snowice
+! njeffery: changed to rhos instead of (c1-phi_snowice)*rhoi
+! to conserve ice and liquid snow tracers when rhos = smice + smliq
+! eclare: this change seems to be BFB
+
+ ! density of newly formed snowice
+! rho_snowice = phi_snowice * rho_ocn + rhos
rho_snowice = phi_snowice * rho_ocn + (c1 - phi_snowice) * rhoi
! calculate thickness of new ice added
@@ -3290,6 +3479,11 @@ subroutine flood_ice(hsn, hin, &
! change snow properties
call update_vertical_tracers_snow(nslyr, zqsn, hslyr, hslyr2)
+ if (tr_snow .and. hslyr2 > puny) then
+ call update_vertical_tracers_snow(nslyr, smice, hslyr, hslyr2)
+ call update_vertical_tracers_snow(nslyr, smliq, hslyr, hslyr2)
+ endif
+
! change ice properties
call update_vertical_tracers_ice(nilyr, zqin, hilyr, hilyr2, &
hin, hin2, zqin_snowice)
diff --git a/src/core_seaice/column/ice_therm_shared.F90 b/src/core_seaice/column/ice_therm_shared.F90
index 1f59e28b29..09bf6b7593 100644
--- a/src/core_seaice/column/ice_therm_shared.F90
+++ b/src/core_seaice/column/ice_therm_shared.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_therm_shared.F90 1182 2017-03-16 19:29:26Z njeffery $
+! SVN:$Id: ice_therm_shared.F90 1196 2017-04-18 13:32:23Z eclare $
!=========================================================================
!
! Shared thermo variables, subroutines
diff --git a/src/core_seaice/column/ice_therm_vertical.F90 b/src/core_seaice/column/ice_therm_vertical.F90
index f28d24962c..d2ad23be29 100644
--- a/src/core_seaice/column/ice_therm_vertical.F90
+++ b/src/core_seaice/column/ice_therm_vertical.F90
@@ -1,4 +1,4 @@
-! SVN:$Id: ice_therm_vertical.F90 1182 2017-03-16 19:29:26Z njeffery $
+! SVN:$Id: ice_therm_vertical.F90 1196 2017-04-18 13:32:23Z eclare $
!=========================================================================
!
! Update ice and snow internal temperatures and compute
@@ -24,7 +24,8 @@ module ice_therm_vertical
use ice_constants_colpkg, only: c0, c1, c3, p001, p5, puny, &
pi, depressT, Lvap, hs_min, cp_ice, &
cp_ocn, rhow, rhoi, rhos, Lfresh, rhofresh, ice_ref_salinity
- use ice_colpkg_shared, only: ktherm, heat_capacity, calc_Tsfc, min_salin
+ use ice_colpkg_shared, only: ktherm, heat_capacity, calc_Tsfc, &
+ min_salin, rsnw_fall, rsnw_tmax
use ice_therm_shared, only: ferrmax, l_brine, &
calculate_tin_from_qin, Tmin
use ice_therm_bl99, only: temperature_changes
@@ -35,7 +36,7 @@ module ice_therm_vertical
save
private
- public :: frzmlt_bottom_lateral, thermo_vertical
+ public :: frzmlt_bottom_lateral, thermo_vertical, adjust_enthalpy
!=======================================================================
@@ -54,13 +55,15 @@ subroutine thermo_vertical (nilyr, nslyr, &
vicen, vsnon, &
Tsf, zSin, &
zqin, zqsn, &
- apond, hpond, &
- iage, tr_pond_topo,&
+ smice, smliq, &
+ tr_snow, apond, &
+ hpond, iage, &
+ tr_pond_topo, &
flw, potT, &
Qa, rhoa, &
fsnow, fpond, &
fbot, Tbot, &
- sss, &
+ sss, rsnw, &
lhcoef, shcoef, &
fswsfc, fswint, &
Sswabs, Iswabs, &
@@ -68,11 +71,14 @@ subroutine thermo_vertical (nilyr, nslyr, &
fsensn, flatn, &
flwoutn, evapn, &
freshn, fsaltn, &
- fhocnn, meltt, &
+ fhocnn, frain, &
+ meltt, &
melts, meltb, &
+ meltsliq, &
congel, snoice, &
mlt_onset, frz_onset, &
yday, dsnow, &
+ tr_rsnw, &
l_stop, stop_label,&
prescribed_ice)
@@ -83,7 +89,8 @@ subroutine thermo_vertical (nilyr, nslyr, &
nslyr ! number of snow layers
real (kind=dbl_kind), intent(in) :: &
- dt ! time step
+ dt , & ! time step
+ frain ! rainfall rate (kg/m2/s)
! ice state variables
real (kind=dbl_kind), intent(inout) :: &
@@ -107,7 +114,10 @@ subroutine thermo_vertical (nilyr, nslyr, &
real (kind=dbl_kind), dimension (:), intent(inout) :: &
zqsn , & ! snow layer enthalpy, zqsn < 0 (J m-3)
zqin , & ! ice layer enthalpy, zqin < 0 (J m-3)
- zSin ! internal ice layer salinities
+ zSin , & ! internal ice layer salinities
+ rsnw , & ! snow grain radius (10^-6 m)
+ smice , & ! ice mass tracer in snow (kg/m^3)
+ smliq ! liquid water mass tracer in snow (kg/m^3)
! input from atmosphere
real (kind=dbl_kind), &
@@ -159,6 +169,7 @@ subroutine thermo_vertical (nilyr, nslyr, &
intent(inout):: &
meltt , & ! top ice melt (m/step-->cm/day)
melts , & ! snow melt (m/step-->cm/day)
+ meltsliq , & ! snow melt mass (kg/m^2/step-->kg/m^2/day)
meltb , & ! basal ice melt (m/step-->cm/day)
congel , & ! basal ice growth (m/step-->cm/day)
snoice , & ! snow-ice formation (m/step-->cm/day)
@@ -169,6 +180,10 @@ subroutine thermo_vertical (nilyr, nslyr, &
real (kind=dbl_kind), intent(in) :: &
yday ! day of year
+ logical (kind=log_kind), intent(in) :: &
+ tr_snow , & ! if .true., use snow tracers
+ tr_rsnw ! if .true., use dynamic snow grain radius
+
logical (kind=log_kind), intent(out) :: &
l_stop ! if true, print diagnostics and abort on return
@@ -231,6 +246,7 @@ subroutine thermo_vertical (nilyr, nslyr, &
congel = c0
snoice = c0
dsnow = c0
+ meltsliq= c0
if (calc_Tsfc) then
fsensn = c0
@@ -288,6 +304,8 @@ subroutine thermo_vertical (nilyr, nslyr, &
fcondtopn, fcondbot, &
fadvocn, snoice, &
einit, &
+ smice, smliq, &
+ tr_snow, &
l_stop, stop_label)
if (l_stop) return
@@ -372,17 +390,20 @@ subroutine thermo_vertical (nilyr, nslyr, &
hin, hilyr, &
hsn, hslyr, &
zqin, zqsn, &
+ smice, smliq, &
fbot, Tbot, &
flatn, fsurfn, &
fcondtopn, fcondbot, &
fsnow, hsn_new, &
fhocnn, evapn, &
meltt, melts, &
+ meltsliq, frain, &
meltb, iage, &
congel, snoice, &
mlt_onset, frz_onset, &
zSin, sss, &
- dsnow)
+ dsnow, tr_snow, &
+ rsnw, tr_rsnw)
!-----------------------------------------------------------------
! Check for energy conservation by comparing the change in energy
@@ -675,8 +696,11 @@ subroutine init_vertical_profile(nilyr, nslyr, &
real (kind=dbl_kind), dimension (:), &
intent(out) :: &
- zqsn , & ! snow enthalpy
zTsn ! snow temperature
+
+ real (kind=dbl_kind), dimension (:), &
+ intent(inout) :: &
+ zqsn ! snow enthalpy
logical (kind=log_kind), intent(inout) :: &
l_stop ! if true, print diagnostics and abort model
@@ -785,7 +809,7 @@ subroutine init_vertical_profile(nilyr, nslyr, &
if (zTsn(k) > Tmax) then
write(warning,*) ' '
call add_warning(warning)
- write(warning,*) 'Starting thermo, zTsn > Tmax'
+ write(warning,*) 'Starting thermo, zTsn > Tmax, k = ', k
call add_warning(warning)
write(warning,*) 'zTsn=',zTsn(k)
call add_warning(warning)
@@ -807,7 +831,7 @@ subroutine init_vertical_profile(nilyr, nslyr, &
if (zTsn(k) < Tmin) then ! allowing for roundoff error
write(warning,*) ' '
call add_warning(warning)
- write(warning,*) 'Starting thermo, zTsn < Tmin'
+ write(warning,*) 'Starting thermo, zTsn < Tmin, k = ',k
call add_warning(warning)
write(warning,*) 'zTsn=', zTsn(k)
call add_warning(warning)
@@ -815,9 +839,9 @@ subroutine init_vertical_profile(nilyr, nslyr, &
call add_warning(warning)
write(warning,*) 'zqsn', zqsn(k)
call add_warning(warning)
- write(warning,*) hin
+ write(warning,*) 'hin', hin
call add_warning(warning)
- write(warning,*) hsn
+ write(warning,*) 'hsn', hsn
call add_warning(warning)
l_stop = .true.
stop_label = "init_vertical_profile: Starting thermo, zTsn < Tmin"
@@ -904,16 +928,9 @@ subroutine init_vertical_profile(nilyr, nslyr, &
if (tice_high .and. heat_capacity) then
- if (l_brine) then
- Tmax = Tmlts(k)
- else ! fresh ice
- Tmax = -zqin(k)*puny/(rhos*cp_ice*vicen)
- endif
-
- if (zTin(k) > Tmax) then
write(warning,*) ' '
call add_warning(warning)
- write(warning,*) 'Starting thermo, T > Tmax, layer', k
+ write(warning,*) 'Starting thermo, zTin > Tmax, layer', k
call add_warning(warning)
write(warning,*) 'k:', k
call add_warning(warning)
@@ -941,27 +958,30 @@ subroutine init_vertical_profile(nilyr, nslyr, &
call add_warning(warning)
else
l_stop = .true.
- stop_label = "init_vertical_profile: Starting thermo, T > Tmax, layer"
+ stop_label = "init_vertical_profile: Starting thermo, zTin > Tmax, layer"
return
endif
- endif
endif ! tice_high
if (tice_low .and. heat_capacity) then
- if (zTin(k) < Tmin) then
write(warning,*) ' '
call add_warning(warning)
- write(warning,*) 'Starting thermo T < Tmin, layer', k
+ write(warning,*) 'Starting thermo, zTin < Tmin, layer', k
call add_warning(warning)
- write(warning,*) 'zTin =', zTin(k)
+ write(warning,*) 'k:', k
+ call add_warning(warning)
+ write(warning,*) 'zTin =',zTin(k),', Tmin=',Tmin
+ call add_warning(warning)
+ write(warning,*) 'zSin =',zSin(k)
call add_warning(warning)
- write(warning,*) 'Tmin =', Tmin
+ write(warning,*) 'hin =',hin
+ call add_warning(warning)
+ write(warning,*) 'zqin =',zqin(k)
call add_warning(warning)
l_stop = .true.
- stop_label = "init_vertical_profile: Starting thermo, T < Tmin, layer"
+ stop_label = "init_vertical_profile: Starting thermo, zTin < Tmin, layer"
return
- endif
endif ! tice_low
!-----------------------------------------------------------------
@@ -1009,17 +1029,20 @@ subroutine thickness_changes (nilyr, nslyr, &
hin, hilyr, &
hsn, hslyr, &
zqin, zqsn, &
+ smice, smliq, &
fbot, Tbot, &
flatn, fsurfn, &
fcondtopn, fcondbot, &
fsnow, hsn_new, &
fhocnn, evapn, &
meltt, melts, &
+ meltsliq, frain, &
meltb, iage, &
congel, snoice, &
mlt_onset, frz_onset,&
zSin, sss, &
- dsnow)
+ dsnow, tr_snow, &
+ rsnw, tr_rsnw)
use ice_colpkg_shared, only: phi_i_mushy
use ice_mushy_physics, only: enthalpy_mush, enthalpy_of_melting, &
@@ -1040,14 +1063,18 @@ subroutine thickness_changes (nilyr, nslyr, &
fsnow , & ! snowfall rate (kg m-2 s-1)
flatn , & ! surface downward latent heat (W m-2)
fsurfn , & ! net flux to top surface, excluding fcondtopn
- fcondtopn ! downward cond flux at top surface (W m-2)
+ fcondtopn , & ! downward cond flux at top surface (W m-2)
+ frain ! rainfall rate (kg/m2/s)
real (kind=dbl_kind), intent(inout) :: &
fcondbot ! downward cond flux at bottom surface (W m-2)
real (kind=dbl_kind), dimension (:), intent(inout) :: &
zqin , & ! ice layer enthalpy (J m-3)
- zqsn ! snow layer enthalpy (J m-3)
+ zqsn , & ! snow layer enthalpy (J m-3)
+ rsnw , & ! snow grain radius (10^-6 m)
+ smice , & ! ice mass tracer in snow (kg/m^3)
+ smliq ! liquid water mass tracer in snow (kg/m^3)
real (kind=dbl_kind), intent(inout) :: &
hilyr , & ! ice layer thickness (m)
@@ -1056,6 +1083,7 @@ subroutine thickness_changes (nilyr, nslyr, &
real (kind=dbl_kind), intent(inout) :: &
meltt , & ! top ice melt (m/step-->cm/day)
melts , & ! snow melt (m/step-->cm/day)
+ meltsliq , & ! snow melt mass (kg/m^2/step-->kg/m^2/day)
meltb , & ! basal ice melt (m/step-->cm/day)
congel , & ! basal ice growth (m/step-->cm/day)
snoice , & ! snow-ice formation (m/step-->cm/day)
@@ -1086,6 +1114,10 @@ subroutine thickness_changes (nilyr, nslyr, &
real (kind=dbl_kind), intent(in) :: &
sss ! ocean salinity (PSU)
+ logical (kind=log_kind), intent(in) :: &
+ tr_snow , & ! if .true., use snow tracers
+ tr_rsnw ! if .true., use snow dynamic snow grain radius
+
! local variables
real (kind=dbl_kind), parameter :: &
@@ -1114,7 +1146,9 @@ subroutine thickness_changes (nilyr, nslyr, &
wk1 , & ! temporary variable
zqsnew , & ! enthalpy of new snow (J m-3)
hstot , & ! snow thickness including new snow (m)
- Tmlts ! melting temperature
+ Tmlts , & ! melting temperature
+ smtot , & ! total ice + liquid mass of snow
+ smice_precs ! ice mass added to snow due to snowfall (kg/m^2)
real (kind=dbl_kind), dimension (nilyr+1) :: &
zi1 , & ! depth of ice layer boundaries (m)
@@ -1128,7 +1162,9 @@ subroutine thickness_changes (nilyr, nslyr, &
dzi ! ice layer thickness after growth/melting
real (kind=dbl_kind), dimension (nslyr) :: &
- dzs ! snow layer thickness after growth/melting
+ dzs , & ! snow layer thickness after growth/melting
+ smicetot , & ! total ice mass of snow in each layer (kg/m^2)
+ smliqtot ! total liquid mass of snow in each layer (kg/m^2)
real (kind=dbl_kind), dimension (nilyr) :: &
qm , & ! energy of melting (J m-3) = zqin in BL99 formulation
@@ -1151,6 +1187,12 @@ subroutine thickness_changes (nilyr, nslyr, &
do k = 1, nslyr
dzs(k) = hslyr
+ smicetot(k) = c0
+ smliqtot(k) = c0
+ if (tr_snow) then
+ smicetot(k) = dzs(k) * smice(k)
+ smliqtot(k) = dzs(k) * smliq(k)
+ endif
enddo
do k = 1, nilyr
@@ -1175,8 +1217,12 @@ subroutine thickness_changes (nilyr, nslyr, &
do k = 1, nslyr
Ts = (Lfresh + zqsn(k)/rhos) / cp_ice
if (Ts > c0) then
- dhs = cp_ice*Ts*dzs(k) / Lfresh
- dzs(k) = dzs(k) - dhs
+ dhs = cp_ice*Ts*dzs(k) / Lfresh ! melt
+ smice_precs = c0
+ if (abs(dzs(k)) > puny) smice_precs = smicetot(k)/dzs(k) * dhs
+ smicetot(k) = max(c0,smicetot(k) - smice_precs) ! dhs << dzs
+ smliqtot(k) = max(c0,smliqtot(k) + smice_precs)
+ dzs (k) = dzs(k) - dhs
zqsn(k) = -rhos*Lfresh
endif
enddo
@@ -1219,6 +1265,7 @@ subroutine thickness_changes (nilyr, nslyr, &
if (hsn > puny) then ! add snow with enthalpy zqsn(1)
dhs = econ / (zqsn(1) - rhos*Lvap) ! econ < 0, dhs > 0
+ smicetot(1) = dhs*rhos + smicetot(1) ! new snow ice
dzs(1) = dzs(1) + dhs
evapn = evapn + dhs*rhos
else ! add ice with enthalpy zqin(1)
@@ -1299,8 +1346,12 @@ subroutine thickness_changes (nilyr, nslyr, &
if (ktherm == 2 .and. zqsn(k) > -rhos * Lfresh) then
dhs = max(-dzs(k), &
- -((zqsn(k) + rhos*Lfresh) / (rhos*Lfresh)) * dzs(k))
- dzs(k) = dzs(k) + dhs
+ -((zqsn(k) + rhos*Lfresh) / (rhos*Lfresh)) * dzs(k)) ! dhs < 0
+ smice_precs = c0
+ if (abs(dzs(k)) > puny) smice_precs = smicetot(k)/dzs(k) * dhs
+ smicetot(k) = max(c0,smicetot(k) + smice_precs) ! -dhs <= dzs
+ smliqtot(k) = max(c0,smliqtot(k) - smice_precs)
+ dzs (k) = dzs(k) + dhs
zqsn(k) = -rhos * Lfresh
melts = melts - dhs
! delta E = zqsn(k) + rhos * Lfresh
@@ -1313,6 +1364,9 @@ subroutine thickness_changes (nilyr, nslyr, &
qsub = zqsn(k) - rhos*Lvap ! qsub < 0
dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0
+ smice_precs = c0
+ if (abs(dzs(k)) > puny) smice_precs = dhs * smicetot(k)/dzs(k)
+ smicetot(k) = max(c0,smicetot(k) + smice_precs)
dzs(k) = dzs(k) + dhs
esub = esub - dhs*qsub
esub = max(esub, c0) ! in case of roundoff error
@@ -1323,6 +1377,10 @@ subroutine thickness_changes (nilyr, nslyr, &
!--------------------------------------------------------------
dhs = max(-dzs(k), etop_mlt/zqsn(k))
+ smice_precs = c0
+ if (abs(dzs(k)) > puny) smice_precs = smicetot(k)/dzs(k) * dhs
+ smicetot(k) = max(c0,smicetot(k) + smice_precs)
+ smliqtot(k) = max(c0,smliqtot(k) - smice_precs)
dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0
etop_mlt = etop_mlt - dhs*zqsn(k)
etop_mlt = max(etop_mlt, c0) ! in case of roundoff error
@@ -1403,6 +1461,9 @@ subroutine thickness_changes (nilyr, nslyr, &
ebot_mlt = ebot_mlt - dhs*zqsn(k)
ebot_mlt = max(ebot_mlt, c0)
+ ! bug fix added by Andrew Roberts, August 5, 2020
+ melts = melts - dhs
+
enddo ! nslyr
!-----------------------------------------------------------------
@@ -1435,10 +1496,44 @@ subroutine thickness_changes (nilyr, nslyr, &
! avoid roundoff errors
zqsn(1) = min(zqsn(1), -rhos*Lfresh)
+ if (tr_snow) then
+
+ smtot = c0
+ if (abs(dzs(1)) > c0) smtot = smicetot(1)/dzs(1) !smice(1) ! save for now
+
+ ! ice mass in snow due to snowfall (precs)
+ ! new snow density = rhos for now
+ smice_precs = hsn_new * rhos ! kg/m^2
+
+ ! update ice mass tracer due to snowfall
+ smicetot(1) = smicetot(1) + smice_precs
+ ! smice(1) = (dzs(1)*smice(1) + smice_precs) / hstot
+
+ ! mass fraction of ice due to snowfall
+ smtot = c0
+ do k = 1, nslyr
+ ! smtot = smtot + smice(k) + smliq(k)
+ smtot = smtot + smicetot(k) + smliqtot(k)
+ enddo
+ if (smtot > c0) then
+ smice_precs = smice_precs / smtot
+ else
+ smice_precs = c1
+ endif
+
+ endif
+
dzs(1) = hstot
+
endif
endif
+!---!-----------------------------------------------------------------
+!---! Add rain at top surface (only to liquid tracer)
+!---!-----------------------------------------------------------------
+
+ smliqtot(1) = smliqtot(1) + frain*dt
+
!-----------------------------------------------------------------
! Find the new ice and snow thicknesses.
!-----------------------------------------------------------------
@@ -1455,6 +1550,14 @@ subroutine thickness_changes (nilyr, nslyr, &
dsnow = dsnow + dzs(k) - hslyr
enddo ! k
+ !-------------------------------------------------------------------
+ ! Incorporate new snow for snow grain radius
+ !-------------------------------------------------------------------
+ if (tr_rsnw .and. hsn_new > c0) &
+ call add_new_snow_radius (nslyr, dzs(1), &
+ hsn_new, rsnw(1), &
+ rsnw_fall, rsnw_tmax)
+
!-------------------------------------------------------------------
! Convert snow to ice if snow lies below freeboard.
!-------------------------------------------------------------------
@@ -1465,8 +1568,26 @@ subroutine thickness_changes (nilyr, nslyr, &
hin, hsn, &
zqin, zqsn, &
dzi, dzs, &
- dsnow)
+ dsnow, &
+ smicetot(:), &
+ smliqtot(:))
+ !-------------------------------------------------------------------
+ ! Update snow mass tracers, smice and smliq, for uneven layers
+ !-------------------------------------------------------------------
+ if (tr_snow) then
+ do k = 1, nslyr
+ meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted)
+ if (dzs(k) > c0) then
+ smice(k) = smicetot(k) / dzs(k)
+ smliq(k) = smliqtot(k) / dzs(k)
+ else
+ smice(k) = c0
+ smliq(k) = c0
+ endif
+ enddo
+ endif
+
!---!-------------------------------------------------------------------
!---! Repartition the ice and snow into equal-thickness layers,
!---! conserving energy.
@@ -1556,6 +1677,23 @@ subroutine thickness_changes (nilyr, nslyr, &
hslyr, hsn, &
zqsn)
+ if (tr_rsnw) &
+ call adjust_enthalpy (nslyr, &
+ zs1(:), zs2(:), &
+ hslyr, hsn, &
+ rsnw(:))
+
+ if (tr_snow) then
+ call adjust_enthalpy (nslyr, &
+ zs1(:), zs2(:), &
+ hslyr, hsn, &
+ smice(:))
+ call adjust_enthalpy (nslyr, &
+ zs1(:), zs2(:), &
+ hslyr, hsn, &
+ smliq(:))
+ endif
+
endif ! nslyr > 1
!-----------------------------------------------------------------
@@ -1568,6 +1706,11 @@ subroutine thickness_changes (nilyr, nslyr, &
fhocnn = fhocnn &
+ zqsn(k)*hsn/(real(nslyr,kind=dbl_kind)*dt)
zqsn(k) = -rhos*Lfresh
+ if (tr_snow) then
+ meltsliq = meltsliq + smicetot(k) ! add to meltponds
+ smice(k) = c0
+ smliq(k) = c0
+ endif
hslyr = c0
endif
enddo
@@ -1615,7 +1758,8 @@ subroutine freeboard (nslyr, dt, &
hin, hsn, &
zqin, zqsn, &
dzi, dzs, &
- dsnow)
+ dsnow, smicetot, &
+ smliqtot)
integer (kind=int_kind), intent(in) :: &
nslyr ! number of snow layers
@@ -1640,7 +1784,9 @@ subroutine freeboard (nslyr, dt, &
real (kind=dbl_kind), dimension (:), intent(inout) :: &
zqin , & ! ice layer enthalpy (J m-3)
dzi , & ! ice layer thicknesses (m)
- dzs ! snow layer thicknesses (m)
+ dzs , & ! snow layer thicknesses (m)
+ smicetot, & ! snow ice mass per layer (kg/m^2)
+ smliqtot ! snow liquid mass per layer (kg/m^2)
! local variables
@@ -1664,7 +1810,7 @@ subroutine freeboard (nslyr, dt, &
dhsn = c0
hqs = c0
- wk1 = hsn - hin*(rhow-rhoi)/rhos
+ wk1 = hsn - hin*(rhow-rhoi)/rhos ! not yet consistent with smice/smliq
if (wk1 > puny .and. hsn > puny) then ! snow below freeboard
dhsn = min(wk1*rhoi/rhow, hsn) ! snow to remove
@@ -1679,6 +1825,8 @@ subroutine freeboard (nslyr, dt, &
do k = nslyr, 1, -1
if (dhin > puny) then
dhs = min(dhsn, dzs(k)) ! snow to remove from layer
+ smicetot(k) = max(c0,smicetot(k) - dhs * smicetot(k) / dzs(k)) !smice(k)
+ smliqtot(k) = max(c0,smliqtot(k) - dhs * smliqtot(k) / dzs(k)) !smliq(k)
hsn = hsn - dhs
dsnow = dsnow -dhs !new snow addition term
dzs(k) = dzs(k) - dhs
@@ -1837,7 +1985,8 @@ subroutine conservation_check_vthermo(dt, &
real (kind=dbl_kind) :: &
einp , & ! energy input during timestep (J m-2)
- ferr ! energy conservation error (W m-2)
+ ferr , & ! energy conservation error (W m-2)
+ ftop ! surface flux error: fcondtopn-fsurfn
character(len=char_len_long) :: &
warning ! warning message
@@ -1883,6 +2032,10 @@ subroutine conservation_check_vthermo(dt, &
call add_warning(warning)
write(warning,*) fbot,fcondbot
call add_warning(warning)
+ write(warning,*) 'fsurfn,fcondtopn:'
+ call add_warning(warning)
+ write(warning,*) fsurfn,fcondtopn
+ call add_warning(warning)
! if (ktherm == 2) then
write(warning,*) 'Intermediate energy =', einter
@@ -1893,11 +2046,15 @@ subroutine conservation_check_vthermo(dt, &
write(warning,*) 'einter - einit =', &
einter-einit
call add_warning(warning)
+ ftop = c0
+ if (ktherm == 2) then
+ if (fcondtopn > fsurfn) ftop = (fcondtopn-fsurfn)
+ end if
write(warning,*) 'Conduction Error =', (einter-einit) &
- - (fcondtopn*dt - fcondbot*dt + fswint*dt)
+ - (fcondtopn*dt - fcondbot*dt + fswint*dt) + ftop*dt
call add_warning(warning)
write(warning,*) 'Melt/Growth Error =', (einter-einit) &
- + ferr*dt - (fcondtopn*dt - fcondbot*dt + fswint*dt)
+ + ferr*dt - (fcondtopn*dt - fcondbot*dt + fswint*dt)-ftop*dt
call add_warning(warning)
write(warning,*) 'Advection Error =', fadvocn*dt
call add_warning(warning)
@@ -1988,6 +2145,35 @@ subroutine update_state_vthermo(nilyr, nslyr, &
end subroutine update_state_vthermo
+!=======================================================================
+
+! Modify snow grain radius in upper layer due to fallen snow
+
+ subroutine add_new_snow_radius (nslyr, dzs, hsn_new, rsnw, &
+ rsnw_fall, rsnw_tmax)
+
+ use ice_constants_colpkg, only: c0, puny
+
+ integer (kind=int_kind), intent(in) :: &
+ nslyr ! number of snow layers
+
+ real (kind=dbl_kind), intent(in) :: &
+ dzs , & ! upper snow layer thickness (m)
+ hsn_new , & ! new snow fall thickness (m)
+ rsnw_fall , & ! radius of new snow (10^-6 m)
+ rsnw_tmax ! maximum radius (10^-6 m)
+
+ real (kind=dbl_kind), &
+ intent(inout) :: &
+ rsnw ! upper layer snow radius (10^-6 m)
+
+ rsnw = (hsn_new * rsnw_fall + max(c0,dzs-hsn_new) * rsnw)/ &
+ (max(hsn_new + max(c0,dzs-hsn_new),puny))
+
+ rsnw = max(rsnw_fall,min(rsnw_tmax, rsnw))
+
+ end subroutine add_new_snow_radius
+
!=======================================================================
end module ice_therm_vertical
diff --git a/src/core_seaice/column/ice_warnings.F90 b/src/core_seaice/column/ice_warnings.F90
index 15ab61abac..6747269623 100644
--- a/src/core_seaice/column/ice_warnings.F90
+++ b/src/core_seaice/column/ice_warnings.F90
@@ -33,7 +33,7 @@ subroutine add_warning(warning)
! number of array elements to increase size of warnings array if that array has run out of space
integer, parameter :: &
- nWarningsBuffer = 10
+ nWarningsBuffer = 100
! temporary array to store previous warnings while warning array is increased in size
character(len=char_len_long), dimension(:), allocatable :: &
diff --git a/src/core_seaice/column/ice_zbgc.F90 b/src/core_seaice/column/ice_zbgc.F90
index 642ba659b0..bb45c96d1c 100644
--- a/src/core_seaice/column/ice_zbgc.F90
+++ b/src/core_seaice/column/ice_zbgc.F90
@@ -27,20 +27,20 @@ module ice_zbgc
! Adjust biogeochemical tracers when new frazil ice forms
subroutine add_new_ice_bgc (dt, nblyr, &
- ncat, nilyr, nltrcr, &
+ ncat, nilyr, nbtrcr, &
bgrid, cgrid, igrid, &
aicen_init, vicen_init, vi0_init, &
aicen, vicen, vsnon1, &
vi0new, &
- ntrcr, trcrn, nbtrcr, &
+ ntrcr, trcrn, &
sss, ocean_bio, flux_bio, &
- hsurp, l_stop, &
+ hsurp, l_stop, &
stop_label, l_conservation_check)
- use ice_constants_colpkg, only: c0, c1, puny, depressT
+ use ice_constants_colpkg, only: c0, c1, puny, depressT, p5
use ice_itd, only: column_sum, &
column_conservation_check
- use ice_colpkg_tracers, only: tr_brine, nt_fbri, nt_sice, nt_qice, nt_Tsfc
+ use ice_colpkg_tracers, only: tr_brine, nt_fbri, nt_sice, nt_qice, nt_Tsfc, bio_index
use ice_colpkg_shared, only: solve_zsal
use ice_therm_shared, only: calculate_Tin_from_qin
@@ -48,7 +48,6 @@ subroutine add_new_ice_bgc (dt, nblyr, &
nblyr , & ! number of bio layers
ncat , & ! number of thickness categories
nilyr , & ! number of ice layers
- nltrcr, & ! number of zbgc tracers
nbtrcr , & ! number of biology tracers
ntrcr ! number of tracers in use
@@ -91,7 +90,7 @@ subroutine add_new_ice_bgc (dt, nblyr, &
real (kind=dbl_kind), dimension (:), &
intent(inout) :: &
flux_bio ! tracer flux to ocean from biology (mmol/m^2/s)
-
+
real (kind=dbl_kind), dimension (:), &
intent(in) :: &
ocean_bio ! ocean concentration of biological tracer
@@ -109,7 +108,8 @@ subroutine add_new_ice_bgc (dt, nblyr, &
integer (kind=int_kind) :: &
location , & ! 1 (add frazil to bottom), 0 (add frazil throughout)
n , & ! ice category index
- k ! ice layer index
+ k , & ! ice layer index
+ m
real (kind=dbl_kind) :: &
vbri1 , & ! starting volume of existing brine
@@ -121,8 +121,8 @@ subroutine add_new_ice_bgc (dt, nblyr, &
vtmp ! total volume of new and old ice
real (kind=dbl_kind), dimension (ncat) :: &
- vbrin ! trcrn(nt_fbri,n)*vicen(n)
-
+ vbrin ! trcrn(nt_fbri,n)*vicen(n)
+
real (kind=dbl_kind) :: &
vice_new ! vicen_init + vsurp
@@ -132,7 +132,18 @@ subroutine add_new_ice_bgc (dt, nblyr, &
character (len=char_len) :: &
fieldid ! field identifier
- !-----------------------------------------------------------------
+ real (kind=dbl_kind), dimension (nbtrcr) :: &
+ total_bio_initial, & ! Initial column bio concentration (mmol/m2)
+ total_bio_final ! final column bio concentration (mmol/m2)
+
+ real (kind=dbl_kind), dimension (nblyr+1) :: &
+ zspace ! vertical grid spacing
+
+ zspace(:) = c1/real(nblyr,kind=dbl_kind)
+ zspace(1) = p5*zspace(1)
+ zspace(nblyr+1) = p5*zspace(nblyr+1)
+
+ !-----------------------------------------------------------------
! brine
!-----------------------------------------------------------------
vbrin(:) = c0
@@ -140,22 +151,28 @@ subroutine add_new_ice_bgc (dt, nblyr, &
vbrin(n) = vicen_init(n)
if (tr_brine) vbrin(n) = trcrn(nt_fbri,n)*vicen_init(n)
enddo
-
+
+ do m = 1, nbtrcr
+ total_bio_initial(m) = c0
+ do n = 1, ncat
+ do k = 1, nblyr+1
+ total_bio_initial(m) = total_bio_initial(m) + vbrin(n) * zspace(k)*trcrn(bio_index(m)+k-1,n)
+ enddo
+ enddo
+ enddo
+
call column_sum (ncat, vbrin, vbri_init)
vbri_init = vbri_init + vi0_init
- do k = 1, nbtrcr
- flux_bio(k) = flux_bio(k) &
- - vi0_init/dt*ocean_bio(k)*zbgc_init_frac(k)
- enddo
+
!-----------------------------------------------------------------
- ! Distribute bgc in new ice volume among all ice categories by
+ ! Distribute bgc in new ice volume among all ice categories by
! increasing ice thickness, leaving ice area unchanged.
!-----------------------------------------------------------------
! Diffuse_bio handles concentration changes from ice growth/melt
! ice area does not change
- ! add salt to the bottom , location = 1
+ ! add salt to the bottom , location = 1
vsurp = c0
vtmp = c0
@@ -174,7 +191,7 @@ subroutine add_new_ice_bgc (dt, nblyr, &
trcrn(nt_fbri,n) = c1
endif
- if (nltrcr > 0) then
+ if (nbtrcr > 0) then
location = 1
call adjust_tracer_profile(nbtrcr, dt, ntrcr, &
aicen_init(n), &
@@ -190,7 +207,7 @@ subroutine add_new_ice_bgc (dt, nblyr, &
location, &
l_stop, stop_label)
if (l_stop) return
- endif ! nltrcr
+ endif ! nbtrcr
endif ! hsurp > 0
enddo ! n
@@ -212,8 +229,8 @@ subroutine add_new_ice_bgc (dt, nblyr, &
! ice area changes
! add salt throughout, location = 0
- if (nltrcr > 0) then
- location = 0
+ if (nbtrcr > 0) then
+ location = 0
call adjust_tracer_profile(nbtrcr, dt, ntrcr, &
aicen(1), &
vbrin(1), &
@@ -233,9 +250,19 @@ subroutine add_new_ice_bgc (dt, nblyr, &
Tmlts = -trcrn(nt_sice,1)*depressT
trcrn(nt_Tsfc,1) = calculate_Tin_from_qin(trcrn(nt_qice,1),Tmlts)
endif ! solve_zsal
- endif ! nltrcr > 0
+ endif ! nbtrcr > 0
endif ! vi0new > 0
+ do m = 1, nbtrcr
+ total_bio_final(m) = c0
+ do n = 1, ncat
+ do k = 1, nblyr+1
+ total_bio_final(m) = total_bio_final(m) + trcrn(nt_fbri,n) * vicen(n) *zspace(k)*trcrn(bio_index(m)+k-1,n)
+ enddo
+ enddo
+ flux_bio(m) = flux_bio(m) + (total_bio_initial(m) - total_bio_final(m))/dt
+ enddo
+
if (tr_brine .and. l_conservation_check) then
call column_sum (ncat, vbrin, vbri_final)
@@ -260,22 +287,24 @@ subroutine lateral_melt_bgc (dt, &
ncat, nblyr, &
rside, vicen, &
trcrn, fzsal, &
- flux_bio, nbltrcr)
+ flux_bio, nbtrcr, &
+ vicen_init)
use ice_colpkg_tracers, only: nt_fbri, nt_bgc_S, bio_index
use ice_colpkg_shared, only: solve_zsal, rhosi
- use ice_constants_colpkg, only: c1, p001
+ use ice_constants_colpkg, only: c1, p001, p5, c0
integer (kind=int_kind), intent(in) :: &
ncat , & ! number of thickness categories
nblyr , & ! number of bio layers
- nbltrcr ! number of biology tracers
+ nbtrcr ! number of biology tracers
real (kind=dbl_kind), intent(in) :: &
dt ! time step (s)
real (kind=dbl_kind), dimension(:), intent(in) :: &
- vicen ! volume per unit area of ice (m)
+ vicen , & ! volume per unit area of ice (m)
+ vicen_init
real (kind=dbl_kind), dimension (:,:), intent(in) :: &
trcrn ! tracer array
@@ -287,41 +316,49 @@ subroutine lateral_melt_bgc (dt, &
fzsal ! salt flux from layer Salinity (kg/m^2/s)
real (kind=dbl_kind), dimension(:), intent(inout) :: &
- flux_bio ! biology tracer flux from layer bgc (mmol/m^2/s)
+ flux_bio ! biology tracer flux from layer bgc (mmol/m^2/s)
! local variables
+ real (kind=dbl_kind) :: &
+ total_bio_initial, & ! initial column tracer concentration (mmol/m2)
+ total_bio_final ! final column tracer concentration (mmol/m20
+
integer (kind=int_kind) :: &
k , & ! layer index
m , & !
n ! category index
- real (kind=dbl_kind) :: &
- zspace ! bio grid spacing
+ real (kind=dbl_kind), dimension (nblyr+1) :: &
+ zspace ! vertical grid spacing
- zspace = c1/(real(nblyr,kind=dbl_kind))
+ zspace(:) = c1/real(nblyr,kind=dbl_kind)
+ zspace(1) = p5*zspace(1)
+ zspace(nblyr+1) = p5*zspace(nblyr+1)
if (solve_zsal) then
do n = 1, ncat
do k = 1,nblyr
fzsal = fzsal + rhosi*trcrn(nt_fbri,n) &
- * vicen(n)*p001*zspace*trcrn(nt_bgc_S+k-1,n) &
+ * vicen(n)*p001*zspace(2)*trcrn(nt_bgc_S+k-1,n) &
* rside/dt
enddo
enddo
endif
- do m = 1, nbltrcr
+ do m = 1, nbtrcr
+ total_bio_initial = c0
+ total_bio_final = c0
do n = 1, ncat
do k = 1, nblyr+1
- flux_bio(m) = flux_bio(m) + trcrn(nt_fbri,n) &
- * vicen(n)*zspace*trcrn(bio_index(m)+k-1,n) &
- * rside/dt
+ total_bio_initial = total_bio_initial + trcrn(nt_fbri,n) * vicen_init(n) *zspace(k)*trcrn(bio_index(m)+k-1,n)
+ total_bio_final = total_bio_final + trcrn(nt_fbri,n) * vicen(n) *zspace(k)*trcrn(bio_index(m)+k-1,n)
enddo
enddo
+ flux_bio(m) = flux_bio(m) + (total_bio_initial - total_bio_final)/dt
enddo
- end subroutine lateral_melt_bgc
+ end subroutine lateral_melt_bgc
!=======================================================================
!
@@ -538,7 +575,8 @@ subroutine merge_bgc_fluxes (dt, nblyr, &
zbgc_snow, zbgc_atm, &
PP_net, ice_bio_net,&
snow_bio_net, grow_alg, &
- grow_net, totalChla)
+ grow_net, totalChla, &
+ nslyr)
use ice_constants_colpkg, only: c1, c0, p5, secday, puny
use ice_colpkg_shared, only: solve_zbgc, max_nbtrcr, hs_ssl, R_C2N, &
@@ -550,6 +588,7 @@ subroutine merge_bgc_fluxes (dt, nblyr, &
integer (kind=int_kind), intent(in) :: &
nblyr, &
+ nslyr, & ! number of snow layers
n_algae, & !
ntrcr, & ! number of tracers
nbtrcr ! number of biology tracer tracers
@@ -625,7 +664,7 @@ subroutine merge_bgc_fluxes (dt, nblyr, &
!-----------------------------------------------------------------
! Merge fluxes
!-----------------------------------------------------------------
- dvssl = min(p5*vsnon, hs_ssl*aicen) ! snow surface layer
+ dvssl = min(p5*vsnon/real(nslyr,kind=dbl_kind), hs_ssl*aicen) ! snow surface layer
dvint = vsnon - dvssl ! snow interior
snow_bio_net(mm) = snow_bio_net(mm) &
+ trcrn(bio_index(mm)+nblyr+1)*dvssl &
@@ -668,9 +707,9 @@ subroutine merge_bgc_fluxes_skl (ntrcr, &
upNH, grow_net, &
grow_alg, totalChla)
- use ice_constants_colpkg, only: c1, secday, puny
+ use ice_constants_colpkg, only: c1, secday, puny, sk_l
use ice_colpkg_tracers, only: nt_bgc_N
- use ice_colpkg_shared, only: sk_l, R_C2N, fr_resp, R_chl2N
+ use ice_colpkg_shared, only: R_C2N, fr_resp, R_chl2N
integer (kind=int_kind), intent(in) :: &
ntrcr , & ! number of cells with aicen > puny
diff --git a/src/core_seaice/model_forward/mpas_seaice_core.F b/src/core_seaice/model_forward/mpas_seaice_core.F
index 2dceb8a9cb..f703942101 100644
--- a/src/core_seaice/model_forward/mpas_seaice_core.F
+++ b/src/core_seaice/model_forward/mpas_seaice_core.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
module seaice_core
use mpas_framework
@@ -12,6 +5,7 @@ module seaice_core
use seaice_analysis_driver
use seaice_column
use mpas_threading
+ use mpas_timer, only: mpas_timer_start, mpas_timer_stop
use mpas_log, only: mpas_log_write
private
@@ -131,7 +125,10 @@ function seaice_core_init(domain, startTimeStamp) result(iErr)
! bootstrap analysis has used config_do_restart: now modify for rest of code
if (trim(config_initial_condition_type) == "restart") config_do_restart = .true.
+ call mpas_timer_start("seaice_init")
call mpas_init_block(domain, dt)
+ call mpas_timer_stop("seaice_init")
+
end function seaice_core_init
@@ -262,7 +259,6 @@ function seaice_core_run(domain) result(iErr)
use mpas_derived_types
use mpas_kind_types
use mpas_stream_manager
- use mpas_timer
use seaice_time_integration, only: seaice_timestep_finalize
use seaice_forcing, only: &
seaice_forcing_get, &
@@ -391,8 +387,7 @@ end function seaice_core_run
subroutine mpas_timestep(domain, itimestep, timeStamp)
use mpas_derived_types
- use seaice_time_integration
- use seaice_error, only: seaice_check_critical_error
+ use seaice_time_integration, only: seaice_timestep
implicit none
@@ -400,12 +395,7 @@ subroutine mpas_timestep(domain, itimestep, timeStamp)
integer, intent(in) :: itimestep
character(len=*), intent(in) :: timeStamp
- integer :: ierr
-
- ierr = 0
- call seaice_timestep(domain, clock, itimestep, ierr)
-
- call seaice_check_critical_error(domain, ierr)
+ call seaice_timestep(domain, clock, itimestep)
end subroutine mpas_timestep
@@ -427,6 +417,8 @@ function seaice_core_finalize(domain) result(iErr)
use mpas_decomp
use seaice_column, only: &
seaice_column_finalize
+ use seaice_mesh_pool, only: &
+ seaice_mesh_pool_destroy
implicit none
@@ -435,6 +427,9 @@ function seaice_core_finalize(domain) result(iErr)
iErr = 0
+ call mpas_log_write(" Destruct mesh pool...")
+ call seaice_mesh_pool_destroy(iErr)
+
! finalize column
call seaice_column_finalize(domain)
diff --git a/src/core_seaice/model_forward/mpas_seaice_core_interface.F b/src/core_seaice/model_forward/mpas_seaice_core_interface.F
index ef8ade111e..2668263502 100644
--- a/src/core_seaice/model_forward/mpas_seaice_core_interface.F
+++ b/src/core_seaice/model_forward/mpas_seaice_core_interface.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2013, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
module seaice_core_interface
use mpas_derived_types
@@ -111,6 +104,9 @@ function seaice_setup_packages(configPool, packagePool, iocontext) result(ierr)!
! set up analysis member packages
call seaice_analysis_setup_packages(configPool, packagePool, iocontext, ierr)
+ ! icebergs
+ call setup_packages_bergs(configPool, packagePool, ierr)
+
! testing system test
call setup_packages_other(configPool, packagePool, ierr)
@@ -138,69 +134,52 @@ subroutine setup_packages_dynamics(configPool, packagePool, ierr)!{{{
config_use_velocity_solver
character(len=strKIND), pointer :: &
- config_stress_divergence_scheme, &
- config_variational_basis
+ config_strain_scheme, &
+ config_stress_divergence_scheme
logical, pointer :: &
pkgWeakActive, &
pkgVariationalActive, &
- pkgWachspressActive, &
- pkgPieceWiseLinearActive
+ pkgWeakVariationalActive
!pkgWeak
!pkgVariational
- !pkgWachspress
- !pkgPieceWiseLinear
call MPAS_pool_get_config(configPool, "config_use_velocity_solver", config_use_velocity_solver)
+ call MPAS_pool_get_config(configPool, "config_strain_scheme", config_strain_scheme)
call MPAS_pool_get_config(configPool, "config_stress_divergence_scheme", config_stress_divergence_scheme)
- call MPAS_pool_get_config(configPool, "config_variational_basis", config_variational_basis)
call MPAS_pool_get_package(packagePool, "pkgWeakActive", pkgWeakActive)
call MPAS_pool_get_package(packagePool, "pkgVariationalActive", pkgVariationalActive)
- call MPAS_pool_get_package(packagePool, "pkgWachspressActive", pkgWachspressActive)
- call MPAS_pool_get_package(packagePool, "pkgPieceWiseLinearActive", pkgPieceWiseLinearActive)
+ call MPAS_pool_get_package(packagePool, "pkgWeakVariationalActive", pkgWeakVariationalActive)
! is the velocity solver on
if (config_use_velocity_solver) then
! stress divergence scheme
- if (trim(config_stress_divergence_scheme) == "weak") then
+ if (trim(config_strain_scheme) == "weak" .or. &
+ trim(config_stress_divergence_scheme) == "weak") then
! weak stress divergence scheme
pkgWeakActive = .true.
- else if (trim(config_stress_divergence_scheme) == "variational") then
+ endif
+
+ if (trim(config_strain_scheme) == "variational" .or. &
+ trim(config_stress_divergence_scheme) == "variational") then
! variational stress divergence scheme
pkgVariationalActive = .true.
- ! variational basis function scheme
- if (trim(config_variational_basis) == "wachspress") then
-
- ! wachspress basis functions
- pkgWachspressActive = .true.
-
- else if (trim(config_variational_basis) == "pwl") then
-
- ! piecewise linear basis functions
- pkgPieceWiseLinearActive = .true.
+ endif
- else
+ if (trim(config_strain_scheme) == "weak" .and. &
+ trim(config_stress_divergence_scheme) == "variational") then
- ! unknown value of config_variational_basis
- call mpas_log_write("Unknown variational scheme: "//trim(config_variational_basis))
- ierr = 1
+ ! weak strain / variational stress divergence
+ pkgWeakVariationalActive = .true.
- endif ! config_variational_basis
-
- else
-
- ! unknown value of config_stress_divergence_scheme
- call mpas_log_write("Unknown stress divergence scheme: "//trim(config_stress_divergence_scheme))
- ierr = 1
-
- endif ! config_stress_divergence_scheme
+ endif
endif ! config_use_velocity_solver
@@ -257,7 +236,9 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
config_use_humics, &
config_use_DON, &
config_use_iron, &
- config_use_zaerosols
+ config_use_zaerosols, &
+ config_use_snow_grain_radius, &
+ config_use_effective_snow_density
logical, pointer :: &
pkgColumnTracerIceAgeActive, &
@@ -289,7 +270,9 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
pkgTracerVerticalDONActive, &
pkgTracerVerticalIronActive, &
pkgTracerZAerosolsActive, &
- pkgTracerZSalinityActive
+ pkgTracerZSalinityActive, &
+ pkgColumnTracerEffectiveSnowDensityActive, &
+ pkgColumnTracerSnowGrainRadiusActive
! other packages
logical, pointer :: &
@@ -356,6 +339,8 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
!pkgTracerVerticalIron
!pkgTracerZAerosols
!pkgTracerZSalinity
+ !pkgColumnTracerEffectiveSnowDensity
+ !pkgColumnTracerSnowGrainRadius
call MPAS_pool_get_config(configPool, "config_use_ice_age", config_use_ice_age)
call MPAS_pool_get_config(configPool, "config_use_first_year_ice", config_use_first_year_ice)
@@ -380,6 +365,8 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
call MPAS_pool_get_config(configPool, "config_use_DON", config_use_DON)
call MPAS_pool_get_config(configPool, "config_use_iron", config_use_iron)
call MPAS_pool_get_config(configPool, "config_use_zaerosols", config_use_zaerosols)
+ call MPAS_pool_get_config(configPool, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(configPool, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_package(packagePool, "pkgColumnTracerIceAgeActive", pkgColumnTracerIceAgeActive)
call MPAS_pool_get_package(packagePool, "pkgColumnTracerFirstYearIceActive", pkgColumnTracerFirstYearIceActive)
@@ -411,6 +398,8 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
call MPAS_pool_get_package(packagePool, "pkgTracerVerticalIronActive", pkgTracerVerticalIronActive)
call MPAS_pool_get_package(packagePool, "pkgTracerZAerosolsActive", pkgTracerZAerosolsActive)
call MPAS_pool_get_package(packagePool, "pkgTracerZSalinityActive", pkgTracerZSalinityActive)
+ call MPAS_pool_get_package(packagePool, "pkgColumnTracerEffectiveSnowDensityActive", pkgColumnTracerEffectiveSnowDensityActive)
+ call MPAS_pool_get_package(packagePool, "pkgColumnTracerSnowGrainRadiusActive", pkgColumnTracerSnowGrainRadiusActive)
use_meltponds = (config_use_cesm_meltponds .or. config_use_level_meltponds .or. config_use_topo_meltponds)
@@ -446,6 +435,9 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
pkgTracerZAerosolsActive = config_use_zaerosols
pkgTracerZSalinityActive = config_use_vertical_zsalinity
+ pkgColumnTracerEffectiveSnowDensityActive = config_use_effective_snow_density
+ pkgColumnTracerSnowGrainRadiusActive = config_use_snow_grain_radius
+
if (.not. config_use_column_package) then
pkgColumnTracerIceAgeActive = .false.
pkgColumnTracerFirstYearIceActive = .false.
@@ -477,6 +469,8 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
pkgTracerVerticalIronActive = .false.
pkgTracerZAerosolsActive = .false.
pkgTracerZSalinityActive = .false.
+ pkgColumnTracerEffectiveSnowDensityActive = .false.
+ pkgColumnTracerSnowGrainRadiusActive = .false.
endif
if (.not. config_use_column_biogeochemistry .and. config_use_column_package) then
@@ -529,6 +523,43 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{
end subroutine setup_packages_column_physics!}}}
+ !***********************************************************************
+ !
+ ! routine setup_packages_bergs
+ !
+ !> \brief Setup icebergs package
+ !> \author Darin Comeau
+ !> \date 19 May 2017
+ !> \details This routine is intended to set the icebergs package PkgBergs
+ !> as active/deactive based on the namelist option config_use_bergs.
+ !
+ !-----------------------------------------------------------------------
+
+ subroutine setup_packages_bergs(configPool, packagePool, ierr)!{{{
+
+ type (mpas_pool_type), intent(in) :: configPool
+ type (mpas_pool_type), intent(in) :: packagePool
+ integer, intent(out) :: ierr
+
+ ! icebergs package
+ logical, pointer :: &
+ config_use_data_icebergs
+
+ logical, pointer :: &
+ pkgBergsActive
+
+ ierr = 0
+
+ !-----------------------------------------------------------------------
+ ! iceberg routines
+ !-----------------------------------------------------------------------
+
+ call MPAS_pool_get_config(configPool, "config_use_data_icebergs", config_use_data_icebergs)
+ call MPAS_pool_get_package(packagePool, "pkgBergsActive", pkgBergsActive)
+ pkgBergsActive = config_use_data_icebergs
+
+ end subroutine setup_packages_bergs!}}}
+
!***********************************************************************
!
! routine setup_packages_other
@@ -549,22 +580,32 @@ subroutine setup_packages_other(configPool, packagePool, ierr)!{{{
logical, pointer :: &
config_use_forcing, &
- config_testing_system_test
+ config_use_data_icebergs, &
+ config_testing_system_test, &
+ config_use_snicar_ad, &
+ config_use_prescribed_ice, &
+ config_use_special_boundaries_velocity, &
+ config_use_special_boundaries_velocity_masks, &
+ config_use_special_boundaries_zero_tracers
logical, pointer :: &
pkgForcingActive, &
- pkgTestingSystemTestActive
+ pkgTestingSystemTestActive, &
+ pkgSnicarActive, &
+ pkgPrescribedActive, &
+ pkgSpecialBoundariesActive
ierr = 0
! pkgForcing
call MPAS_pool_get_config(configPool, "config_use_forcing", config_use_forcing)
+ call MPAS_pool_get_config(configPool, "config_use_data_icebergs", config_use_data_icebergs)
call MPAS_pool_get_package(packagePool, "pkgForcingActive", pkgForcingActive)
! see if we are using the forcing system
- if (config_use_forcing) then
+ if (config_use_forcing .or. config_use_data_icebergs) then
pkgForcingActive = .true.
@@ -578,9 +619,31 @@ subroutine setup_packages_other(configPool, packagePool, ierr)!{{{
! see if we are testing the testing system
if (config_testing_system_test) then
-
pkgTestingSystemTestActive = .true.
+ endif
+
+ ! pkgSnicar
+ call MPAS_pool_get_config(configPool, "config_use_snicar_ad", config_use_snicar_ad)
+ call MPAS_pool_get_package(packagePool, "pkgSnicarActive", pkgSnicarActive)
+ ! see if we are using the snicar_ad system
+ pkgSnicarActive = .true.
+
+ ! pkgPrescribed
+ call MPAS_pool_get_config(configPool, "config_use_prescribed_ice", config_use_prescribed_ice)
+ call MPAS_pool_get_package(packagePool, "pkgPrescribedActive", pkgPrescribedActive)
+ if (config_use_prescribed_ice) then
+ pkgPrescribedActive = .true.
+ endif
+ ! pkgSpecialBoundaries
+ call MPAS_pool_get_config(configPool, "config_use_special_boundaries_velocity", config_use_special_boundaries_velocity)
+ call MPAS_pool_get_config(configPool, "config_use_special_boundaries_velocity_masks", config_use_special_boundaries_velocity_masks)
+ call MPAS_pool_get_config(configPool, "config_use_special_boundaries_zero_tracers", config_use_special_boundaries_zero_tracers)
+ call MPAS_pool_get_package(packagePool, "pkgSpecialBoundariesActive", pkgSpecialBoundariesActive)
+ if (config_use_special_boundaries_velocity .or. &
+ config_use_special_boundaries_velocity_masks .or. &
+ config_use_special_boundaries_zero_tracers) then
+ pkgSpecialBoundariesActive = .true.
endif
end subroutine setup_packages_other!}}}
diff --git a/src/core_seaice/seaice.cmake b/src/core_seaice/seaice.cmake
index 0ac2b0dd49..9a880f4d9c 100644
--- a/src/core_seaice/seaice.cmake
+++ b/src/core_seaice/seaice.cmake
@@ -53,7 +53,6 @@ list(APPEND RAW_SOURCES
core_seaice/shared/mpas_seaice_advection_incremental_remap.F
core_seaice/shared/mpas_seaice_advection_upwind.F
core_seaice/shared/mpas_seaice_advection.F
- core_seaice/shared/mpas_seaice_velocity_solver_unit_tests.F
core_seaice/shared/mpas_seaice_velocity_solver.F
core_seaice/shared/mpas_seaice_velocity_solver_weak.F
core_seaice/shared/mpas_seaice_velocity_solver_variational.F
@@ -64,7 +63,6 @@ list(APPEND RAW_SOURCES
core_seaice/shared/mpas_seaice_forcing.F
core_seaice/shared/mpas_seaice_initialize.F
core_seaice/shared/mpas_seaice_testing.F
- core_seaice/shared/mpas_seaice_unit_test.F
core_seaice/shared/mpas_seaice_mesh.F
core_seaice/shared/mpas_seaice_diagnostics.F
core_seaice/shared/mpas_seaice_numerics.F
@@ -72,6 +70,9 @@ list(APPEND RAW_SOURCES
core_seaice/shared/mpas_seaice_column.F
core_seaice/shared/mpas_seaice_diagnostics.F
core_seaice/shared/mpas_seaice_error.F
+ core_seaice/shared/mpas_seaice_mesh_pool.F
+ core_seaice/shared/mpas_seaice_prescribed.F
+ core_seaice/shared/mpas_seaice_special_boundaries.F
)
# analysis members
diff --git a/src/core_seaice/shared/Makefile b/src/core_seaice/shared/Makefile
index 0f0cf3827e..52bcb75710 100644
--- a/src/core_seaice/shared/Makefile
+++ b/src/core_seaice/shared/Makefile
@@ -5,7 +5,6 @@ OBJS = mpas_seaice_time_integration.o \
mpas_seaice_advection_incremental_remap.o \
mpas_seaice_advection_upwind.o \
mpas_seaice_advection.o \
- mpas_seaice_velocity_solver_unit_tests.o \
mpas_seaice_velocity_solver.o \
mpas_seaice_velocity_solver_weak.o \
mpas_seaice_velocity_solver_variational.o \
@@ -16,14 +15,16 @@ OBJS = mpas_seaice_time_integration.o \
mpas_seaice_forcing.o \
mpas_seaice_initialize.o \
mpas_seaice_testing.o \
- mpas_seaice_unit_test.o \
mpas_seaice_mesh.o \
mpas_seaice_diagnostics.o \
mpas_seaice_numerics.o \
mpas_seaice_constants.o \
mpas_seaice_column.o \
mpas_seaice_diagnostics.o \
- mpas_seaice_error.o
+ mpas_seaice_error.o \
+ mpas_seaice_mesh_pool.o \
+ mpas_seaice_prescribed.o \
+ mpas_seaice_special_boundaries.o
all: $(OBJS)
@@ -31,6 +32,8 @@ mpas_seaice_constants.o:
mpas_seaice_error.o:
+mpas_seaice_mesh_pool.o:
+
mpas_seaice_column.o: mpas_seaice_error.o
mpas_seaice_diagnostics.o: mpas_seaice_constants.o
@@ -53,11 +56,9 @@ mpas_seaice_velocity_solver_wachspress.o: mpas_seaice_constants.o mpas_seaice_nu
mpas_seaice_velocity_solver_pwl.o: mpas_seaice_constants.o mpas_seaice_numerics.o mpas_seaice_mesh.o mpas_seaice_testing.o mpas_seaice_velocity_solver_variational_shared.o
-mpas_seaice_velocity_solver_variational.o: mpas_seaice_constants.o mpas_seaice_velocity_solver_constitutive_relation.o mpas_seaice_velocity_solver_wachspress.o mpas_seaice_velocity_solver_pwl.o
-
-mpas_seaice_velocity_solver.o: mpas_seaice_constants.o mpas_seaice_mesh.o mpas_seaice_testing.o mpas_seaice_velocity_solver_weak.o mpas_seaice_velocity_solver_constitutive_relation.o mpas_seaice_velocity_solver_variational.o mpas_seaice_diagnostics.o
+mpas_seaice_velocity_solver_variational.o: mpas_seaice_constants.o mpas_seaice_velocity_solver_constitutive_relation.o mpas_seaice_velocity_solver_wachspress.o mpas_seaice_velocity_solver_pwl.o mpas_seaice_mesh_pool.o
-mpas_seaice_velocity_solver_unit_tests.o: mpas_seaice_constants.o mpas_seaice_mesh.o mpas_seaice_velocity_solver_weak.o mpas_seaice_velocity_solver_variational.o
+mpas_seaice_velocity_solver.o: mpas_seaice_constants.o mpas_seaice_mesh.o mpas_seaice_testing.o mpas_seaice_velocity_solver_weak.o mpas_seaice_velocity_solver_constitutive_relation.o mpas_seaice_velocity_solver_variational.o mpas_seaice_diagnostics.o mpas_seaice_mesh_pool.o mpas_seaice_special_boundaries.o
mpas_seaice_advection_upwind.o: mpas_seaice_constants.o mpas_seaice_mesh.o
@@ -67,13 +68,13 @@ mpas_seaice_advection_incremental_remap.o: mpas_seaice_constants.o mpas_seaice_m
mpas_seaice_advection.o: mpas_seaice_advection_upwind.o mpas_seaice_advection_incremental_remap.o
-mpas_seaice_unit_test.o: mpas_seaice_constants.o mpas_seaice_velocity_solver_unit_tests.o
+mpas_seaice_prescribed.o: mpas_seaice_constants.o mpas_seaice_column.o
-mpas_seaice_time_integration.o: mpas_seaice_constants.o mpas_seaice_velocity_solver.o mpas_seaice_forcing.o mpas_seaice_unit_test.o mpas_seaice_advection.o mpas_seaice_diagnostics.o mpas_seaice_column.o
+mpas_seaice_time_integration.o: mpas_seaice_constants.o mpas_seaice_velocity_solver.o mpas_seaice_forcing.o mpas_seaice_advection.o mpas_seaice_diagnostics.o mpas_seaice_column.o mpas_seaice_prescribed.o mpas_seaice_special_boundaries.o
-mpas_seaice_initialize.o: mpas_seaice_constants.o mpas_seaice_mesh.o mpas_seaice_velocity_solver.o mpas_seaice_testing.o mpas_seaice_forcing.o mpas_seaice_advection.o mpas_seaice_column.o mpas_seaice_forcing.o
+mpas_seaice_initialize.o: mpas_seaice_constants.o mpas_seaice_mesh.o mpas_seaice_velocity_solver.o mpas_seaice_testing.o mpas_seaice_forcing.o mpas_seaice_advection.o mpas_seaice_column.o mpas_seaice_forcing.o mpas_seaice_mesh_pool.o mpas_seaice_special_boundaries.o
-mpas_seaice_core.o: mpas_seaice_constants.o mpas_seaice_time_integration.o mpas_seaice_velocity_solver.o mpas_seaice_forcing.o mpas_seaice_initialize.o mpas_seaice_column.o
+mpas_seaice_core.o: mpas_seaice_constants.o mpas_seaice_time_integration.o mpas_seaice_velocity_solver.o mpas_seaice_forcing.o mpas_seaice_initialize.o mpas_seaice_column.o mpas_seaice_mesh_pool.o
mpas_seaice_core_interface.o: mpas_seaice_core.o
diff --git a/src/core_seaice/shared/gpu_macros.inc b/src/core_seaice/shared/gpu_macros.inc
new file mode 100644
index 0000000000..a12feee71c
--- /dev/null
+++ b/src/core_seaice/shared/gpu_macros.inc
@@ -0,0 +1,36 @@
+#ifdef MPAS_OPENACC
+
+#define GPU acc
+#define GPUC acc /* continuation line macro */
+#define GPUF acc ) /* final line of GPU directive */
+#define ENTER_DATA enter data
+#define EXIT_DATA exit data
+#define DATA data
+#define DATA_END end data
+#define COPY_IN_LP copyin( /* for multi-line variable lists */
+#define COPY_OUT_LP copyout( /* for multi-line variable lists */
+#define COPY_DEL_LP delete(
+#define UPDATE_D(v) update device v
+#define UPDATE_D_LP update device(
+#define UPDATE_H(v) update host v /* !$GPU UPDATE_H((stressDivergenceU, stressDivergenceV)) -> !$acc update host (stressDivergenceU, stressDivergenceV) */
+#define UPDATE_H_LP update host( /* for multi-line variable lists */
+
+#else
+
+#define GPU omp
+#define GPUC omp&
+#define GPUF omp& )
+#define ENTER_DATA target enter data
+#define EXIT_DATA target exit data
+#define DATA target data
+#define DATA_END end target data
+#define COPY_IN_LP map(to:
+#define COPY_OUT_LP map(from:
+#define COPY_DEL_LP map(delete:
+#define UPDATE_D(v) target update to v
+#define UPDATE_D_LP target update to(
+#define UPDATE_H(v) target update from v
+#define UPDATE_H_LP target update from(
+
+#endif
+
diff --git a/src/core_seaice/shared/mpas_seaice_advection.F b/src/core_seaice/shared/mpas_seaice_advection.F
index 38452d4c59..20c58c8b43 100644
--- a/src/core_seaice/shared/mpas_seaice_advection.F
+++ b/src/core_seaice/shared/mpas_seaice_advection.F
@@ -87,7 +87,7 @@ end subroutine seaice_init_advection
!
!-----------------------------------------------------------------------
- subroutine seaice_run_advection(domain, clock, ierr)
+ subroutine seaice_run_advection(domain, clock)
use seaice_advection_upwind, only: &
seaice_run_advection_upwind
@@ -101,9 +101,6 @@ subroutine seaice_run_advection(domain, clock, ierr)
type (MPAS_Clock_type), intent(in) :: &
clock !< Input:
- integer, intent(inout) :: &
- ierr !< Input/Output:
-
logical, pointer :: &
config_use_advection
@@ -127,7 +124,7 @@ subroutine seaice_run_advection(domain, clock, ierr)
! (Later, change volume to thickness throughout code?)
call mpas_timer_start("advection incr remap")
- call seaice_run_advection_incremental_remap(domain, clock, ierr)
+ call seaice_run_advection_incremental_remap(domain, clock)
call mpas_timer_stop("advection incr remap")
!TODO WHL - Convert ice/snow thickness to volume here
diff --git a/src/core_seaice/shared/mpas_seaice_advection_incremental_remap.F b/src/core_seaice/shared/mpas_seaice_advection_incremental_remap.F
index f8bbcc391b..f55a43e549 100644
--- a/src/core_seaice/shared/mpas_seaice_advection_incremental_remap.F
+++ b/src/core_seaice/shared/mpas_seaice_advection_incremental_remap.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2015, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! mpas_seaice_advection_incremental_remap
@@ -46,20 +39,20 @@ module seaice_advection_incremental_remap
! variables private to this module
type :: geometric_avg_cell_type
- real(kind=RKIND), dimension(:), pointer :: x => null() ! grid cell average of x
- real(kind=RKIND), dimension(:), pointer :: y => null() ! grid cell average of y
- real(kind=RKIND), dimension(:), pointer :: xx => null() ! grid cell average of x^2
- real(kind=RKIND), dimension(:), pointer :: xy => null() ! grid cell average of x*y
- real(kind=RKIND), dimension(:), pointer :: yy => null() ! grid cell average of y^2
- real(kind=RKIND), dimension(:), pointer :: xxx => null() ! grid cell average of x^3
- real(kind=RKIND), dimension(:), pointer :: xxy => null() ! grid cell average of x^2*y
- real(kind=RKIND), dimension(:), pointer :: xyy => null() ! grid cell average of x*y^2
- real(kind=RKIND), dimension(:), pointer :: yyy => null() ! grid cell average of y^3
- real(kind=RKIND), dimension(:), pointer :: xxxx => null() ! grid cell average of x^4
- real(kind=RKIND), dimension(:), pointer :: xxxy => null() ! grid cell average of x^3*y
- real(kind=RKIND), dimension(:), pointer :: xxyy => null() ! grid cell average of x^2*y^2
- real(kind=RKIND), dimension(:), pointer :: xyyy => null() ! grid cell average of x*y^3
- real(kind=RKIND), dimension(:), pointer :: yyyy => null() ! grid cell average of y^4
+ real(kind=RKIND), dimension(:), contiguous, pointer :: x => null() ! grid cell average of x
+ real(kind=RKIND), dimension(:), contiguous, pointer :: y => null() ! grid cell average of y
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xx => null() ! grid cell average of x^2
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xy => null() ! grid cell average of x*y
+ real(kind=RKIND), dimension(:), contiguous, pointer :: yy => null() ! grid cell average of y^2
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xxx => null() ! grid cell average of x^3
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xxy => null() ! grid cell average of x^2*y
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xyy => null() ! grid cell average of x*y^2
+ real(kind=RKIND), dimension(:), contiguous, pointer :: yyy => null() ! grid cell average of y^3
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xxxx => null() ! grid cell average of x^4
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xxxy => null() ! grid cell average of x^3*y
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xxyy => null() ! grid cell average of x^2*y^2
+ real(kind=RKIND), dimension(:), contiguous, pointer :: xyyy => null() ! grid cell average of x*y^3
+ real(kind=RKIND), dimension(:), contiguous, pointer :: yyyy => null() ! grid cell average of y^4
end type geometric_avg_cell_type
! parameters private to this module
@@ -2345,7 +2338,6 @@ end subroutine compute_geometric_cell_averages
subroutine seaice_run_advection_incremental_remap(&
domain, &
clock, &
- ierr, &
timeLevelIn, &
updateHaloInitIn, &
updateHaloFinalIn)
@@ -2361,9 +2353,6 @@ subroutine seaice_run_advection_incremental_remap(&
type (MPAS_Clock_type), intent(in) :: &
clock !< Input: clock
- integer, intent(inout) :: &
- ierr !< Input/Output: error code
-
integer, intent(in), optional :: &
timeLevelIn !< Input: time level of input fields (1 or 2)
@@ -2405,6 +2394,9 @@ subroutine seaice_run_advection_incremental_remap(&
real(kind=RKIND), pointer :: &
dynamicsTimeStep
+ logical, pointer :: &
+ abortFlag ! abort flag
+
! assign pointers
dminfo => domain % dminfo
@@ -2469,8 +2461,8 @@ subroutine seaice_run_advection_incremental_remap(&
else
! with reuse
- call mpas_dmpar_exch_group_reuse_halo_exch(domain, 'velocityHaloExchangeGroup', iErr=ierr)
- if (ierr /= MPAS_DMPAR_NOERR) then
+ call mpas_dmpar_exch_group_reuse_halo_exch(domain, 'velocityHaloExchangeGroup', iErr=ierrHalo)
+ if (ierrHalo /= MPAS_DMPAR_NOERR) then
call MPAS_log_write("failure to perform reuse halo exchange for velocityHaloExchangeGroup", MPAS_LOG_CRIT)
endif
@@ -2569,15 +2561,12 @@ subroutine seaice_run_advection_incremental_remap(&
domain, &
block, &
dynamicsTimeStep, &
- tracersHead, &
- ierr)
- if (ierr > 0) exit
+ tracersHead)
block => block % next
enddo ! associated(block)
call mpas_timer_stop("incr remap blocks")
- if (ierr > 0) return
! Optional check for conservation of mass and mass*tracer
! Note: This check must be done outside the block loop because it requires global sums
@@ -2588,9 +2577,9 @@ subroutine seaice_run_advection_incremental_remap(&
if (verboseRun) call mpas_log_write('Check conservation')
call mpas_timer_start("incr remap tracer cons check")
- call check_tracer_conservation(dminfo, tracersHead, ierr)
+ call check_tracer_conservation(dminfo, tracersHead, abortFlag)
call mpas_timer_stop("incr remap tracer cons check")
- if (ierr > 0) return
+ call seaice_check_critical_error(domain, abortFlag)
endif
@@ -2604,9 +2593,9 @@ subroutine seaice_run_advection_incremental_remap(&
if (verboseRun) call mpas_log_write('Check monotonicity')
call mpas_timer_start("incr remap tracer mono check")
- call check_tracer_monotonicity(domain, tracersHead, ierr)
+ call check_tracer_monotonicity(domain, tracersHead, abortFlag)
call mpas_timer_stop("incr remap tracer mono check")
- if (ierr > 0) return
+ call seaice_check_critical_error(domain, abortFlag)
endif
@@ -2753,7 +2742,6 @@ subroutine incremental_remap_block(&
block, &
dt, &
tracersHead, &
- ierr, &
timeLevelIn)
! in/out arguments
@@ -2766,9 +2754,6 @@ subroutine incremental_remap_block(&
real(kind=RKIND), intent(in) :: &
dt !< Input: time step
- integer, intent(inout) :: &
- ierr !< Input/Output: error code
-
type(tracer_type), pointer :: &
tracersHead !< Input/output: pointer to first element of linked list of tracers
! The pointer stays attached to the first tracer, but all tracers are updated
@@ -2890,6 +2875,9 @@ subroutine incremental_remap_block(&
integer :: n, m, iEdge, iCat, iLayer, iCell
integer :: nCategories, nLayers, count
+ logical :: &
+ abortFlag ! flag if code aborting
+
logical, pointer :: &
configConservationCheck, & ! namelist configuration whether perform conservation check
configMonotonicityCheck, & ! namelist configuration whether perform monotonicity check
@@ -3176,6 +3164,7 @@ subroutine incremental_remap_block(&
!-------------------------------------------------------------------
call mpas_timer_start("incr remap integrate fluxes")
+ abortFlag = .false.
call integrate_fluxes_over_triangles(&
tracersHead, &
nCells, &
@@ -3188,12 +3177,10 @@ subroutine incremental_remap_block(&
indexToCellID, &
indexToEdgeID, &
block, &
- ierr)
+ abortFlag)
call mpas_timer_stop("incr remap integrate fluxes")
- if (ierr > 0) then
- call seaice_critical_error_write_block(domain, block)
- return
- endif
+ call seaice_critical_error_write_block(domain, block, abortFlag)
+ call seaice_check_critical_error(domain, abortFlag)
if (verboseFluxes .and. etestOnProc .and. block % localBlockID == etestBlockID) then
iEdge = etest
@@ -3288,6 +3275,7 @@ subroutine incremental_remap_block(&
!-------------------------------------------------------------------
call mpas_timer_start("incr remap update tracers")
+ abortFlag = .false.
call update_mass_and_tracers(&
nCellsSolve, &
nEdgesOnCell, &
@@ -3298,12 +3286,10 @@ subroutine incremental_remap_block(&
indexToCellID, &
indexToEdgeID, &
block, &
- ierr)
+ abortFlag)
call mpas_timer_stop("incr remap update tracers")
- if (ierr > 0) then
- call seaice_critical_error_write_block(domain, block)
- return
- endif
+ call seaice_critical_error_write_block(domain, block, abortFlag)
+ call seaice_check_critical_error(domain, abortFlag)
!-------------------------------------------------------------------
! Compute final sums of mass*tracer over the locally owned cells
@@ -4272,7 +4258,7 @@ subroutine compute_gradient_2d(&
mask !< Input: integer mask for parent tracer;
! = 1 where field values for this tracer are physically meaningful, else = 0
- real(kind=RKIND), dimension(:,:), intent(out) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(out) :: &
xGrad, yGrad !< Output: x and y components of the gradient
integer, dimension(:), intent(in) :: &
@@ -4289,29 +4275,30 @@ subroutine compute_gradient_2d(&
integer :: iCell, iEdge, iEdgeOnCell, iCellNeighbor
real(kind=RKIND) :: &
- signGradient ! = 1 or -1, depending on which direction is taken as positive at a given edge
+ signGradient, & ! = 1 or -1, depending on which direction is taken as positive at a given edge
+ tempGrad
real(kind=RKIND), dimension(:,:), allocatable :: &
normalGrad, & ! normal components of the gradient, defined on cell edges
- globalGrad, & ! gradient at cell center, in global x/y/z coordinates
- globalGradRotate ! rotated globalGrad vector
+ globalGrad ! gradient at cell center, in global x/y/z coordinates
- real(kind=RKIND), dimension(:), allocatable :: &
- zGrad ! diagnostic only; should be much smaller than xGrad and yGrad
+ !real(kind=RKIND), dimension(:), allocatable :: &
+ ! zGrad ! diagnostic only; should be much smaller than xGrad and yGrad
! find dimensions and allocate arrays
nCategories = size(field,1)
- allocate(zGrad(nCategories))
+ !allocate(zGrad(nCategories))
allocate(normalGrad(nCategories,maxEdges))
allocate(globalGrad(nCategories,3))
- if (config_rotate_cartesian_grid) allocate(globalGradRotate(nCategories,3))
! initialize the gradient
xGrad(:,:) = 0.0_RKIND
yGrad(:,:) = 0.0_RKIND
- zGrad(:) = 0.0_RKIND ! diagnostic only
+ !zGrad(:) = 0.0_RKIND ! diagnostic only
- ! loop over cells
+#if !defined(__GFORTRAN__) && !defined(CPRGNU)
+ !$omp parallel do default(shared) firstprivate(normalGrad,globalGrad) private(iEdgeOnCell,iCellNeighbor,iEdge,iCat,signGradient,tempGrad)
+#endif
do iCell = 1, nCells
if (maskCell(iCell) == 1) then ! ice is present in the cell
@@ -4343,19 +4330,10 @@ subroutine compute_gradient_2d(&
normalGrad(iCat,iEdgeOnCell) = signGradient * (field(iCat,iCellNeighbor) - field(iCat,iCell)) / dcEdge(iEdge)
- else ! either or both field values do not have physical meaning; set gradient component = 0
-
- normalGrad(iCat,iEdgeOnCell) = 0.0_RKIND
-
endif
enddo ! iCat
- else ! there is no cell neighbor on this edge
-
- ! set gradient component = 0
- normalGrad(:,iEdgeOnCell) = 0.0_RKIND
-
endif
! add the contribution of this normal component to the reconstructed
@@ -4373,10 +4351,11 @@ subroutine compute_gradient_2d(&
!TODO - Rotate the gradient vector if on a plane?
if (config_rotate_cartesian_grid .and. on_a_sphere) then
- globalGradRotate(:,1) = -globalGrad(:,3) ! xR = -z
- globalGradRotate(:,2) = globalGrad(:,2) ! yR = y
- globalGradRotate(:,3) = globalGrad(:,1) ! zR = x
- globalGrad(:,:) = globalGradRotate(:,:)
+ do iCat = 1, nCategories
+ tempGrad = globalGrad(iCat,1)
+ globalGrad(iCat,1) = -globalGrad(iCat,3) ! xR = -z
+ globalGrad(iCat,3) = tempGrad ! zR = x
+ enddo ! iCat
endif
! transform from global x/y/z coordinates to local east/west coordinates
@@ -4392,10 +4371,9 @@ subroutine compute_gradient_2d(&
+ transGlobalToCell(2,3,iCell) * globalGrad(:,3)
! Note: The zGrad component is never used; it is simply computed as a diagnostic
- !TODO - Comment out zGrad computation?
- zGrad(:) = transGlobalToCell(3,1,iCell) * globalGrad(:,1) &
- + transGlobalToCell(3,2,iCell) * globalGrad(:,2) &
- + transGlobalToCell(3,3,iCell) * globalGrad(:,3)
+ !zGrad(:) = transGlobalToCell(3,1,iCell) * globalGrad(:,1) &
+ ! + transGlobalToCell(3,2,iCell) * globalGrad(:,2) &
+ ! + transGlobalToCell(3,3,iCell) * globalGrad(:,3)
else ! on a plane; do a simple copy
@@ -4419,18 +4397,19 @@ subroutine compute_gradient_2d(&
realArgs=(/field(iCatTest,iCellNeighbor), normalGrad(iCatTest,iEdgeOnCell)/))
enddo
call mpas_log_write(' ')
- call mpas_log_write('Unlimited center gradient: $r $r $r', &
- realArgs=(/xGrad(iCatTest,iCell), yGrad(iCatTest,iCell), zGrad(iCatTest)/))
+ call mpas_log_write('Unlimited center gradient: $r $r', &
+ realArgs=(/xGrad(iCatTest,iCell), yGrad(iCatTest,iCell)/))
+ !call mpas_log_write('Unlimited center gradient: $r $r $r', &
+ ! realArgs=(/xGrad(iCatTest,iCell), yGrad(iCatTest,iCell), zGrad(iCatTest)/))
endif
endif
enddo ! iCell
! cleanup
- deallocate(zGrad)
+ !deallocate(zGrad)
deallocate(normalGrad)
deallocate(globalGrad)
- if (config_rotate_cartesian_grid) deallocate(globalGradRotate)
end subroutine compute_gradient_2d
@@ -4504,7 +4483,7 @@ subroutine compute_gradient_3d(&
mask !< Input: integer mask for parent tracer;
! = 1 where field values for this tracer are physically meaningful, else = 0
- real(kind=RKIND), dimension(:,:,:), intent(out) :: &
+ real(kind=RKIND), dimension(:,:,:), contiguous, intent(out) :: &
xGrad, yGrad !< Output: x and y components of the gradient
integer, dimension(:), intent(in) :: &
@@ -4522,29 +4501,29 @@ subroutine compute_gradient_3d(&
real(kind=RKIND), dimension(:,:,:), allocatable :: &
normalGrad, & ! normal components of the gradient, defined on cell edges
- globalGrad, & ! gradient at cell center, in global x/y/z coordinates
- globalGradRotate ! rotated globalGrad vector
+ globalGrad ! gradient at cell center, in global x/y/z coordinates
real(kind=RKIND) :: &
signGradient ! = 1 or -1, depending on which direction is taken as positive at a given edge
- real(kind=RKIND), dimension(:,:), allocatable :: &
- zGrad ! diagnostic only; should be much smaller than xGrad and yGrad
+ !real(kind=RKIND), dimension(:,:), allocatable :: &
+ ! zGrad ! diagnostic only; should be much smaller than xGrad and yGrad
! find dimensions and allocate arrays
nLayers = size(field,1)
nCategories = size(field,2)
- allocate(zGrad(nLayers,nCategories))
+ !allocate(zGrad(nLayers,nCategories))
allocate(normalGrad(nLayers,nCategories,maxEdges))
allocate(globalGrad(nLayers,nCategories,3))
- if (config_rotate_cartesian_grid) allocate(globalGradRotate(nLayers,nCategories,3))
! initialize the gradient
xGrad(:,:,:) = 0.0_RKIND
yGrad(:,:,:) = 0.0_RKIND
- zGrad(:,:) = 0.0_RKIND ! diagnostic only
+ !zGrad(:,:) = 0.0_RKIND ! diagnostic only
- ! loop over cells
+#if !defined(__GFORTRAN__) && !defined(CPRGNU)
+ !$omp parallel do default(shared) firstprivate(normalGrad,globalGrad) private(iEdgeOnCell,iCellNeighbor,iEdge,iCat,iLayer,signGradient)
+#endif
do iCell = 1, nCells
if (maskCell(iCell) == 1) then ! ice is present in the cell
@@ -4579,20 +4558,11 @@ subroutine compute_gradient_3d(&
normalGrad(iLayer,iCat,iEdgeOnCell) = &
signGradient * (field(iLayer,iCat,iCellNeighbor) - field(iLayer,iCat,iCell)) / dcEdge(iEdge)
- else ! either or both field values do not have physical meaning; set gradient component = 0
-
- normalGrad(iLayer,iCat,iEdgeOnCell) = 0.0_RKIND
-
endif
enddo ! iCat
enddo ! iLayer
- else ! there is no cell neighbor on this edge
-
- ! set gradient component = 0
- normalGrad(:,:,iEdgeOnCell) = 0.0_RKIND
-
endif
! add the contribution of this normal component to the reconstructed gradient
@@ -4610,10 +4580,10 @@ subroutine compute_gradient_3d(&
!TODO - Rotate the gradient vector if on a plane?
if (config_rotate_cartesian_grid .and. on_a_sphere) then
- globalGradRotate(:,:,1) = -globalGrad(:,:,3) ! xR = -z
- globalGradRotate(:,:,2) = globalGrad(:,:,2) ! yR = y
- globalGradRotate(:,:,3) = globalGrad(:,:,1) ! zR = x
- globalGrad(:,:,:) = globalGradRotate(:,:,:)
+ ! reusing normalGrad as a temporary variable to rotate globalGrad
+ normalGrad(:,:,1) = globalGrad(:,:,1) ! temp
+ globalGrad(:,:,1) = -globalGrad(:,:,3) ! xR = -z
+ globalGrad(:,:,3) = normalGrad(:,:,1) ! zR = x
endif
! transform from global x/y/z coordinates to local east/west coordinates
@@ -4629,10 +4599,9 @@ subroutine compute_gradient_3d(&
+ transGlobalToCell(2,3,iCell) * globalGrad(:,:,3)
! Note: The zGrad component is never used; it is simply computed as a diagnostic
- !TODO - Comment out zGrad computation?
- zGrad(:,:) = transGlobalToCell(3,1,iCell) * globalGrad(:,:,1) &
- + transGlobalToCell(3,2,iCell) * globalGrad(:,:,2) &
- + transGlobalToCell(3,3,iCell) * globalGrad(:,:,3)
+ !zGrad(:,:) = transGlobalToCell(3,1,iCell) * globalGrad(:,:,1) &
+ ! + transGlobalToCell(3,2,iCell) * globalGrad(:,:,2) &
+ ! + transGlobalToCell(3,3,iCell) * globalGrad(:,:,3)
else ! on a plane; do a simple copy
@@ -4656,18 +4625,19 @@ subroutine compute_gradient_3d(&
realArgs=(/field(iLayerTest,iCatTest,iCellNeighbor), normalGrad(iLayerTest,iCatTest,iEdgeOnCell)/))
enddo
call mpas_log_write(' ')
- call mpas_log_write('Unlimited center gradient: $r $r $r', &
- realArgs=(/xGrad(iLayerTest,iCatTest,iCell), yGrad(iLayerTest,iCatTest,iCell), zGrad(iLayerTest,iCatTest)/))
+ call mpas_log_write('Unlimited center gradient: $r $r', &
+ realArgs=(/xGrad(iLayerTest,iCatTest,iCell), yGrad(iLayerTest,iCatTest,iCell)/))
+ !call mpas_log_write('Unlimited center gradient: $r $r $r', &
+ ! realArgs=(/xGrad(iLayerTest,iCatTest,iCell), yGrad(iLayerTest,iCatTest,iCell), zGrad(iLayerTest,iCatTest)/))
endif
endif
enddo ! iCell
! cleanup
- deallocate(zGrad)
+ !deallocate(zGrad)
deallocate(normalGrad)
deallocate(globalGrad)
- if (config_rotate_cartesian_grid) deallocate(globalGradRotate)
end subroutine compute_gradient_3d
@@ -4684,6 +4654,7 @@ end subroutine compute_gradient_3d
!
!-----------------------------------------------------------------------
+!DIR$ ATTRIBUTES FORCEINLINE :: compute_barycenter_coordinates
subroutine compute_barycenter_coordinates(&
geomAvgCell, &
iCell, &
@@ -4842,30 +4813,30 @@ subroutine limit_tracer_gradient_2d(&
integer, intent(in) :: &
nCells !< Input: number of cells
- integer, dimension(:), intent(in) :: &
+ integer, dimension(:), contiguous, intent(in) :: &
nEdgesOnCell !< Input: number of edges per cell
- integer, dimension(:,:), intent(in) :: &
+ integer, dimension(:,:), contiguous, intent(in) :: &
cellsOnCell !< Input: cell index for each edge neighbor of a given cell
- real(kind=RKIND), dimension(:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
field !< Input: 2d field for which we are limiting the gradient
- integer, dimension(:,:), intent(in) :: &
+ integer, dimension(:,:), contiguous, intent(in) :: &
fieldMask !< Input: mask = 1 where field value is physically meaningful, = 0 elsewhere
- real(kind=RKIND), dimension(:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
xVertexOnCell, & !< Input: x (east) coordinate of vertex relative to cell center in local tangent plane
yVertexOnCell !< Input: y (north) coordinate of vertex relative to cell center in local tangent plane
- integer, dimension(:), intent(in) :: &
+ integer, dimension(:), contiguous, intent(in) :: &
maskCell !< Input: = 1 for cells with ice, else = 0
- real(kind=RKIND), dimension(:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
xBarycenter, & !< Input: x (east) coordinate of barycenter of this tracer's parent
yBarycenter !< Input: y (north) coordinate of barycenter of this tracer's parent
- real(kind=RKIND), dimension(:,:), intent(inout) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(inout) :: &
xGrad, & !< Input/output: x (east) component of gradient vector
yGrad !< Input/output: y (north) coordinate of barycenter of this tracer's parent
! Gradient components are unlimited on input, limited on output
@@ -4901,7 +4872,9 @@ subroutine limit_tracer_gradient_2d(&
allocate(maxLocal(nCategories))
allocate(minLocal(nCategories))
- ! loop over cells
+ !$omp parallel do default(shared) private(iEdgeOnCell,iCellNeighbor,&
+ !$omp& iCat,iVertex,deviationAtVertex,gradFactor,gradFactor1,gradFactor2) &
+ !$omp& firstprivate(maxNeighbor,minNeighbor,maxLocal,minLocal)
do iCell = 1, nCells
if (maskCell(iCell) == 1) then ! ice is present
@@ -5038,35 +5011,35 @@ subroutine limit_tracer_gradient_3d(&
integer, intent(in) :: &
nCells !< Input: number of cells
- integer, dimension(:), intent(in) :: &
+ integer, dimension(:), contiguous, intent(in) :: &
nEdgesOnCell !< Input: number of edges per cell
- integer, dimension(:,:), intent(in) :: &
+ integer, dimension(:,:), contiguous, intent(in) :: &
cellsOnCell !< Input: cell index for each edge neighbor of a given cell
- real(kind=RKIND), dimension(:,:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:,:), contiguous, intent(in) :: &
field !< Input: 3d field for which we are limiting the gradient
- integer, dimension(:,:,:), intent(in) :: &
+ integer, dimension(:,:,:), contiguous, intent(in) :: &
fieldMask !< Input: mask = 1 where field value is physically meaningful, = 0 elsewhere
- real(kind=RKIND), dimension(:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
xVertexOnCell, & !< Input: x (east) coordinate of vertex relative to cell center in local tangent plane
yVertexOnCell !< Input: y (north) coordinate of vertex relative to cell center in local tangent plane
- integer, dimension(:), intent(in) :: &
+ integer, dimension(:), contiguous, intent(in) :: &
maskCell !< Input: = 1 for cells with ice, else = 0
- real(kind=RKIND), dimension(:,:,:), intent(inout) :: &
+ real(kind=RKIND), dimension(:,:,:), contiguous, intent(inout) :: &
xGrad, & !< Input/output: x (east) component of gradient vector
yGrad !< Input/output: y (north) coordinate of barycenter of this tracer's parent
! Gradient components are unlimited on input, limited on output
- real(kind=RKIND), dimension(:,:), intent(in), optional :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in), optional :: &
xBarycenter2D, & !< Input: x (east) coordinate of barycenter of this tracer's 2Dparent
yBarycenter2D !< Input: y (north) coordinate of barycenter of this tracer's 2D parent
- real(kind=RKIND), dimension(:,:,:), intent(in), optional :: &
+ real(kind=RKIND), dimension(:,:,:), contiguous, intent(in), optional :: &
xBarycenter3D, & !< Input: x (east) coordinate of barycenter of this tracer's 3D parent
yBarycenter3D !< Input: y (north) coordinate of barycenter of this tracer's 3D parent
@@ -5113,7 +5086,9 @@ subroutine limit_tracer_gradient_3d(&
allocate(maxLocal(nLayers,nCategories))
allocate(minLocal(nLayers,nCategories))
- ! loop over cells
+ !$omp parallel do default(shared) private(iEdgeOnCell,iCellNeighbor,&
+ !$omp& iCat,iLayer,iVertex,deviationAtVertex,gradFactor,gradFactor1,gradFactor2) &
+ !$omp& firstprivate(maxNeighbor,minNeighbor,maxLocal,minLocal)
do iCell = 1, nCells
if (maskCell(iCell) == 1) then ! ice is present
@@ -6440,8 +6415,11 @@ subroutine shift_vertices_of_departure_triangle(&
crossProduct)
if (abs(crossProduct) < eps11) then ! the two vectors are (nearly) parallel; something is wrong
- call mpas_log_write('IR: basis vectors for IR coordinate transformations must not be parallel: iEdge, iCell =', &
- MPAS_LOG_CRIT, intArgs=(/iEdge, iCell/))
+ call mpas_log_write('IR: basis vectors for IR coordinate transformations must not be parallel: iEdge, iCell = $i, $i', &
+ MPAS_LOG_ERR, intArgs=(/iEdge, iCell/))
+ call mpas_log_write('IR: edgeVector1: $r, $r', MPAS_LOG_ERR, realArgs=edgeVector1)
+ call mpas_log_write('IR: edgeVector2: $r, $r', MPAS_LOG_ERR, realArgs=edgeVector2)
+ call mpas_log_write('IR: Critical error', MPAS_LOG_CRIT)
endif
if (crossProduct > 0.0_RKIND) then
@@ -6698,7 +6676,7 @@ subroutine integrate_fluxes_over_triangles(&
indexToCellID, &
indexToEdgeID, &
block, &
- ierr)
+ abortFlag)
type(tracer_type), pointer :: &
tracersHead !< Input/output: pointer to first element of linked list of tracers
@@ -6731,8 +6709,8 @@ subroutine integrate_fluxes_over_triangles(&
type(block_type), intent(in) :: &
block !< Input: local block (diagnostic only)
- integer, intent(inout) :: &
- ierr !< Input: error code
+ logical, intent(inout) :: &
+ abortFlag !< Input: error code
! local variables
@@ -6742,12 +6720,10 @@ subroutine integrate_fluxes_over_triangles(&
dummyTracer ! dummy tracer with value of 1 everywhere
integer :: &
- iEdge, iCell, iCat, iLayer, iTri, iqp
-
- integer :: &
nTriPerEdgeRemap, & ! number of triangles per edge
nCategories, & ! number of ice thickness categories
- nLayers ! number of layers
+ nLayers, & ! number of layers
+ iEdge, iCell, iCat, iLayer, iTri, iqp
real(kind=RKIND), dimension(:), allocatable :: &
tracerIntegral2D ! integral over a triangle of mass, mass*tracer, etc.
@@ -6815,13 +6791,10 @@ subroutine integrate_fluxes_over_triangles(&
else ! nParents = 1, 2 or 3
parentTracer => thisTracer % parent
-
- endif
-
- if (verboseFluxes) then
- if (thisTracer % nParents > 0) then
+ if (verboseFluxes) then
call mpas_log_write('Parent: '//trim(parentTracer % tracerName))
endif
+
endif
! Integrate the fluxes of this tracer (for each category and layer) over each triangle of each edge.
@@ -6829,6 +6802,7 @@ subroutine integrate_fluxes_over_triangles(&
if (thisTracer % ndims == 2) then
+ !$omp parallel do default(shared) firstprivate(tracerIntegral2D) private(iTri,iCell,iqp,iCat)
do iEdge = 1, nEdges
if (maskEdge(iEdge) == 1) then
@@ -6836,86 +6810,42 @@ subroutine integrate_fluxes_over_triangles(&
if (triangleArea(iTri,iEdge) /= 0.0_RKIND) then
- ! In the following arrays:
- ! 1st index of triangleValue2D = category; 2nd index = QP
- ! 1st index of center/xGrad/yGrad = category
- ! 1st index of xTriangle/yTriangle = QP
- ! 1st index of tracerIntegral2D = category
- ! 1st index of edgeFlux2D = category
-
! identify the cell where the triangle is located
iCell = iCellTriangle(iTri,iEdge)
- ! evaluate the tracer at each quadrature point
- do iqp = 1, nQuadPoints
- thisTracer % triangleValue2D(:,iqp,iTri,iEdge) = &
- thisTracer % center2D(:,iCell) &
- + thisTracer % xGrad2D(:,iCell) * xTriangle(iqp,iTri,iEdge) &
- + thisTracer % yGrad2D(:,iCell) * yTriangle(iqp,iTri,iEdge)
- enddo
-
- ! evaluate the product mass*tracer at each quadrature point (using parent tracer info computed already)
- ! In nParents = 0, this is mass
- ! If nParents = 1, this is mass*tracer1
- ! If nParents = 2, this is mass*tracer1*tracer2
- ! If nParents = 3, this is mass*tracer1*tracer2*tracer3
- ! Note: Parent tracer must have ndims = 2
- thisTracer % triangleValue2D(:,:,iTri,iEdge) = parentTracer % triangleValue2D(:,:,iTri,iEdge) &
- * thisTracer % triangleValue2D(:,:,iTri,iEdge)
-
- ! integrate over the triangle by summing over quadrature points
tracerIntegral2D(:) = 0.0_RKIND
+ ! evaluate the tracer at each quadrature point
do iqp = 1, nQuadPoints
- tracerIntegral2D(:) = tracerIntegral2D(:) &
- + weightQuadPoint(iqp) * thisTracer % triangleValue2D(:,iqp,iTri,iEdge)
- enddo
-
+ do iCat = 1, nCategories
+ ! eval the product mass*tracer at each quadrature point (using parent tracer info computed already)
+ ! In nParents = 0, this is mass
+ ! If nParents = 1, this is mass*tracer1
+ ! If nParents = 2, this is mass*tracer1*tracer2
+ ! If nParents = 3, this is mass*tracer1*tracer2*tracer3
+ ! Note: Parent tracer must have ndims = 2
+ thisTracer % triangleValue2D(iCat,iqp,iTri,iEdge) = &
+ parentTracer % triangleValue2D(iCat,iqp,iTri,iEdge) * &
+ ( thisTracer % center2D(iCat,iCell) &
+ + thisTracer % xGrad2D(iCat,iCell) * xTriangle(iqp,iTri,iEdge) &
+ + thisTracer % yGrad2D(iCat,iCell) * yTriangle(iqp,iTri,iEdge) &
+ )
+ ! integrate over the triangle by summing over quadrature points
+ tracerIntegral2D(iCat) = tracerIntegral2D(iCat) &
+ + weightQuadPoint(iqp) * thisTracer % triangleValue2D(iCat,iqp,iTri,iEdge)
+ enddo ! iCat
+ enddo ! iqp
! increment the area-weighted flux across the edge
thisTracer % edgeFlux2D(:,iEdge) = thisTracer % edgeFlux2D(:,iEdge) &
+ triangleArea(iTri,iEdge) * tracerIntegral2D(:)
-
endif ! triangleArea /= 0
-
enddo ! nTriPerEdgeRemap
-
endif ! maskEdge = 1
enddo ! nEdges
-
- ! Check for negative reconstructed ice area
- if (trim(thisTracer % tracerName) == 'iceAreaCategory') then
- do iEdge = 1, nEdges
- do iTri = 1, nTriPerEdgeRemap
- if (triangleArea(iTri,iEdge) /= 0.0_RKIND) then
- iCell = iCellTriangle(iTri,iEdge)
- do iqp = 1, nQuadPoints
- do iCat = 1, nCategories
- if (thisTracer % triangleValue2D(iCat,iqp,iTri,iEdge) < 0.0_RKIND) then
- call mpas_log_write('Negative reconstructed ice area', MPAS_LOG_ERR)
- call mpas_log_write('nCells = $i', MPAS_LOG_ERR, intArgs=(/nCells/))
- call mpas_log_write('iCat, iCell, global iCell: $i $i $i', MPAS_LOG_ERR, &
- intArgs=(/iCat, iCell, indexToCellID(iCell)/))
- call mpas_log_write('iEdge, global iEdge, iTri, iqp: $i $i $i $i', MPAS_LOG_ERR, &
- intArgs=(/iEdge, indexToEdgeID(iEdge), iTri, iqp/))
- call mpas_log_write('triangle area: $r', MPAS_LOG_ERR, realArgs=(/triangleArea(iTri,iEdge)/))
- call mpas_log_write('tracer val: $r', MPAS_LOG_ERR, realArgs=(/thisTracer % triangleValue2D(iCat,iqp,iTri,iEdge)/))
- call mpas_log_write('center val: $r', MPAS_LOG_ERR, realArgs=(/thisTracer % center2D(iCat,iCell)/))
- call mpas_log_write('x gradient: $r', MPAS_LOG_ERR, realArgs=(/thisTracer % xGrad2D(iCat,iCell)/))
- call mpas_log_write('y gradient: $r', MPAS_LOG_ERR, realArgs=(/thisTracer % yGrad2D(iCat,iCell)/))
- call mpas_log_write('IR negative reconstructed ice area (nDims == 2)', MPAS_LOG_ERR)
- ierr = SEAICE_ERROR_IR_NEG_AREA
- return
- endif ! negative area
- enddo ! iCat
- enddo ! iqp
- endif ! triangleArea > 0
- enddo ! iTri
- enddo ! iEdge
- endif ! iceAreaCategory
-
deallocate(tracerIntegral2D)
elseif (thisTracer % ndims == 3) then
+ !$omp parallel do default(shared) firstprivate(tracerIntegral3D) private(iTri,iCell,iqp,iCat,iLayer)
do iEdge = 1, nEdges
if (maskEdge(iEdge) == 1) then
@@ -6923,106 +6853,104 @@ subroutine integrate_fluxes_over_triangles(&
if (triangleArea(iTri,iEdge) /= 0.0_RKIND) then
- ! In the following arrays:
- ! 1st index of triangleValue3D = layer; 2nd index = category; 3rd index = QP
- ! 1st index of center/xGrad/yGrad = layer; 2nd index = category
- ! 1st index of xTriangle/yTriangle = QP
- ! 1st index of tracerIntegral = layer; 2nd index = category
- ! 1st index of edgeFlux = layer; 2nd index = category
-
! identify the cell where the triangle is located
iCell = iCellTriangle(iTri,iEdge)
- ! evaluate the tracer at each quadrature point
- do iqp = 1, nQuadPoints
- thisTracer % triangleValue3D(:,:,iqp,iTri,iEdge) = &
- thisTracer % center3D(:,:,iCell) &
- + thisTracer % xGrad3D(:,:,iCell) * xTriangle(iqp,iTri,iEdge) &
- + thisTracer % yGrad3D(:,:,iCell) * yTriangle(iqp,iTri,iEdge)
- enddo
-
- ! evaluate the product mass*tracer at each quadrature point (using parent tracer info computed already)
- ! In nParents = 0, this is mass
- ! If nParents = 1, this is mass*tracer1
- ! If nParents = 2, this is mass*tracer1*tracer2
- ! If nParents = 3, this is mass*tracer1*tracer2*tracer3
- ! Note: Parent tracer can have ndims = 2 or 3
- if (parentTracer % ndims == 2) then
- do iLayer = 1, nLayers
- thisTracer % triangleValue3D(iLayer,:,:,iTri,iEdge) = &
- parentTracer % triangleValue2D(:,:,iTri,iEdge) * &
- thisTracer % triangleValue3D(iLayer,:,:,iTri,iEdge)
- enddo
- else ! parents has ndims = 3
- thisTracer % triangleValue3D(:,:,:,iTri,iEdge) = parentTracer % triangleValue3D(:,:,:,iTri,iEdge) &
- * thisTracer % triangleValue3D(:,:,:,iTri,iEdge)
- endif
-
- ! integrate over the triangle by summing over quadrature points
tracerIntegral3D(:,:) = 0.0_RKIND
+ ! evaluate the tracer at each quadrature point
do iqp = 1, nQuadPoints
- tracerIntegral3D(:,:) = tracerIntegral3D(:,:) &
- + weightQuadPoint(iqp) * thisTracer % triangleValue3D(:,:,iqp,iTri,iEdge)
- enddo
-
+ do iCat = 1, nCategories
+ do iLayer = 1, nLayers
+ if (parentTracer % ndims == 2) then
+ ! eval the product mass*tracer at each quadrature point (using parent tracer info
+ ! computed already)
+ ! In nParents = 0, this is mass
+ ! If nParents = 1, this is mass*tracer1
+ ! If nParents = 2, this is mass*tracer1*tracer2
+ ! If nParents = 3, this is mass*tracer1*tracer2*tracer3
+ ! Note: Parent tracer can have ndims = 2 or 3
+ thisTracer % triangleValue3D(iLayer,iCat,iqp,iTri,iEdge) = &
+ parentTracer % triangleValue2D(iCat,iqp,iTri,iEdge) * &
+ ( thisTracer % center3D(iLayer,iCat,iCell) &
+ + thisTracer % xGrad3D(iLayer,iCat,iCell) * xTriangle(iqp,iTri,iEdge) &
+ + thisTracer % yGrad3D(iLayer,iCat,iCell) * yTriangle(iqp,iTri,iEdge) &
+ )
+ else ! parents has ndims = 3
+ thisTracer % triangleValue3D(iLayer,iCat,iqp,iTri,iEdge) = &
+ parentTracer % triangleValue3D(iLayer,iCat,iqp,iTri,iEdge) * &
+ ( thisTracer % center3D(iLayer,iCat,iCell) &
+ + thisTracer % xGrad3D(iLayer,iCat,iCell) * xTriangle(iqp,iTri,iEdge) &
+ + thisTracer % yGrad3D(iLayer,iCat,iCell) * yTriangle(iqp,iTri,iEdge) &
+ )
+ endif
+ ! integrate over the triangle by summing over quadrature points
+ tracerIntegral3D(iLayer,iCat) = tracerIntegral3D(iLayer,iCat) &
+ + weightQuadPoint(iqp) * thisTracer % triangleValue3D(iLayer,iCat,iqp,iTri,iEdge)
+ enddo ! iLayer
+ enddo ! iCat
+ enddo ! iqp
! increment the area-weighted flux across the edge
thisTracer % edgeFlux3D(:,:,iEdge) = thisTracer % edgeFlux3D(:,:,iEdge) &
+ triangleArea(iTri,iEdge) * tracerIntegral3D(:,:)
-
endif ! triangleArea /= 0
-
enddo ! nTriPerEdgeRemap
-
endif ! maskEdge = 1
enddo ! nEdges
+ deallocate(tracerIntegral3D)
- ! Check for negative reconstructed ice area
- if (trim(thisTracer % tracerName) == 'iceAreaCategory') then
- do iEdge = 1, nEdges
- do iTri = 1, nTriPerEdgeRemap
- if (triangleArea(iTri,iEdge) /= 0.0_RKIND) then
- iCell = iCellTriangle(iTri,iEdge)
- do iqp = 1, nQuadPoints
- do iCat = 1, nCategories
+ endif ! ndims
+
+ ! Check for negative reconstructed ice area
+ if (trim(thisTracer % tracerName) == 'iceAreaCategory') then
+ do iEdge = 1, nEdges
+ do iTri = 1, nTriPerEdgeRemap
+ if (triangleArea(iTri,iEdge) /= 0.0_RKIND) then
+ iCell = iCellTriangle(iTri,iEdge)
+ do iqp = 1, nQuadPoints
+ do iCat = 1, nCategories
+ if (thisTracer % ndims == 2) then
+ if (thisTracer % triangleValue2D(iCat,iqp,iTri,iEdge) < 0.0_RKIND) then
+ call mpas_log_write('MPAS-seaice: IR negative reconstructed ice area', messageType=MPAS_LOG_ERR)
+ call mpas_log_write('nCells, iCat, iCell, global iCell: $i $i $i $i', messageType=MPAS_LOG_ERR, &
+ intArgs=(/nCells, iCat, iCell, indexToCellID(iCell)/))
+ call mpas_log_write('iEdge, global iEdge, iTri, iqp: $i $i $i $i', messageType=MPAS_LOG_ERR, &
+ intArgs=(/iEdge, indexToEdgeID(iEdge), iTri, iqp/))
+ call mpas_log_write('triangle area, tracer, center, xGrad2D, yGrad2D: $r $r $r $r $r', &
+ messageType=MPAS_LOG_CRIT, & ! abort
+ realArgs=(/triangleArea(iTri,iEdge), &
+ thisTracer%triangleValue2D(iCat,iqp,iTri,iEdge), &
+ thisTracer%center2D(iCat,iCell), &
+ thisTracer% xGrad2D(iCat,iCell), &
+ thisTracer% yGrad2D(iCat,iCell) /))
+ endif ! negative 2D area
+ elseif (thisTracer % ndims == 3) then
do iLayer = 1, nLayers
if (thisTracer % triangleValue3D(iLayer,iCat,iqp,iTri,iEdge) < 0.0_RKIND) then
- call mpas_log_write('Negative reconstructed ice area', messageType=MPAS_LOG_ERR)
- call mpas_log_write('nCells = $i', messageType=MPAS_LOG_ERR, intArgs=(/nCells/))
- call mpas_log_write('iLayer, iCat, iCell, global iCell: $i $i $i $i', &
+ call mpas_log_write('MPAS-seaice: IR negative reconstructed ice area', messageType=MPAS_LOG_ERR)
+ call mpas_log_write('nCells, iLayer, iCat, iCell, global iCell: $i $i $i $i $i', &
messageType=MPAS_LOG_ERR, &
- intArgs=(/iLayer, iCat, iCell, indexToCellID(iCell)/))
+ intArgs=(/nCells, iLayer, iCat, iCell, indexToCellID(iCell)/))
call mpas_log_write('iEdge, global iEdge, iTri, iqp: $i $i $i $i', &
messageType=MPAS_LOG_ERR, &
intArgs=(/iEdge, indexToEdgeID(iEdge), iTri, iqp/))
- call mpas_log_write('triangle area: $r', messageType=MPAS_LOG_ERR, &
- realArgs=(/triangleArea(iTri,iEdge)/))
- call mpas_log_write('tracer val: $r', messageType=MPAS_LOG_ERR, &
- realArgs=(/thisTracer % triangleValue3D(iLayer,iCat,iqp,iTri,iEdge)/))
- call mpas_log_write('center val: $r', messageType=MPAS_LOG_ERR, &
- realArgs=(/thisTracer % center3D(iLayer,iCat,iCell)/))
- call mpas_log_write('x gradient: $r', messageType=MPAS_LOG_ERR, &
- realArgs=(/thisTracer % xGrad3D(iLayer,iCat,iCell)/))
- call mpas_log_write('y gradient: $r', messageType=MPAS_LOG_ERR, &
- realArgs=(/thisTracer % yGrad3D(iLayer,iCat,iCell)/))
- call mpas_log_write('MPAS-seaice: IR negative reconstructed ice area (nDims == 3)', &
- messageType=MPAS_LOG_ERR)
- ierr = SEAICE_ERROR_IR_NEG_AREA
- return
- endif ! negative area
+ call mpas_log_write('triangle area, tracer, center, xGrad3D, yGrad3D: $r $r $r $r $r', &
+ messageType=MPAS_LOG_CRIT, & ! abort
+ realArgs=(/triangleArea(iTri,iEdge), &
+ thisTracer%triangleValue3D(iLayer,iCat,iqp,iTri,iEdge), &
+ thisTracer%center3D(iLayer,iCat,iCell), &
+ thisTracer% xGrad3D(iLayer,iCat,iCell), &
+ thisTracer% yGrad3D(iLayer,iCat,iCell) /))
+ endif ! negative 3D area
enddo ! iLayer
- enddo ! iCat
- enddo ! iqp
- endif ! triangleArea > 0
- enddo ! iTri
- enddo ! iEdge
- endif ! iceAreaCategory
-
- deallocate(tracerIntegral3D)
-
- endif ! ndims
+ endif ! ndims
+ enddo ! iCat
+ enddo ! iqp
+ endif ! triangleArea > 0
+ enddo ! iTri
+ enddo ! iEdge
+ endif ! iceAreaCategory
! clean up
-
if (associated(dummyTracer)) then
if (dummyTracer % ndims == 2) then
if (associated(dummyTracer % triangleValue2D)) deallocate(dummyTracer % triangleValue2D)
@@ -7204,7 +7132,10 @@ subroutine update_mass_and_tracers(&
indexToCellID, &
indexToEdgeID, &
block, &
- ierr)
+ abortFlag)
+
+ use seaice_constants, only: &
+ seaicePuny
integer, intent(in) :: &
nCellsSolve !< Input: number of locally owned cells to be updated
@@ -7230,8 +7161,8 @@ subroutine update_mass_and_tracers(&
type(block_type), intent(in) :: &
block !< Input: local block (diagnostic only)
- integer, intent(inout) :: &
- ierr !< Input/Output: error code
+ logical, intent(inout) :: &
+ abortFlag !< Input/Output: error flag
! local variables
@@ -7332,6 +7263,7 @@ subroutine update_mass_and_tracers(&
allocate (fluxFromCell2D(nCategories))
+ !$omp parallel do default(shared) firstprivate(fluxFromCell2D) private(iEdgeOnCell,iEdge,edgeSignOnCell,iCat)
do iCell = 1, nCellsSolve
fluxFromCell2D = 0.0_RKIND
@@ -7413,6 +7345,7 @@ subroutine update_mass_and_tracers(&
allocate (fluxFromCell3D(nLayers,nCategories))
+ !$omp parallel do default(shared) firstprivate(fluxFromCell3D) private(iEdgeOnCell,iEdge,edgeSignOnCell,iCat,iLayer)
do iCell = 1, nCellsSolve
fluxFromCell3D = 0.0_RKIND
@@ -7535,13 +7468,16 @@ subroutine update_mass_and_tracers(&
do iCell = 1, nCellsSolve
do iCat = 1, nCategories
- if (thisTracer % array2D(iCat,iCell) < 0.0_RKIND) then
+ if (thisTracer % array2D(iCat,iCell) < -seaicePuny*seaicePuny) then
call mpas_log_write('IR: Negative mass in IR: iCat, iCell, global iCell, value: $i $i $i $r', &
messageType=MPAS_LOG_ERR, &
intArgs=(/iCat, iCell, indexToCellID(iCell)/), &
realArgs=(/thisTracer % array2D(iCat,iCell)/))
- ierr = SEAICE_ERROR_IR_NEG_MASS
+ abortFlag = .true.
return
+ else if (thisTracer % array2D(iCat,iCell) >= -seaicePuny*seaicePuny .and. &
+ thisTracer % array2D(iCat,iCell) < 0.0_RKIND) then
+ thisTracer % array2D(iCat,iCell) = 0.0_RKIND
endif
enddo
enddo
@@ -7551,13 +7487,16 @@ subroutine update_mass_and_tracers(&
do iCell = 1, nCellsSolve
do iCat = 1, nCategories
do iLayer = 1, nLayers
- if (thisTracer % array3D(iLayer,iCat,iCell) < 0.0_RKIND) then
+ if (thisTracer % array3D(iLayer,iCat,iCell) < -seaicePuny*seaicePuny) then
call mpas_log_write('IR: Negative mass in IR: iLayer, iCat, iCell, global iCell, value: $i $i $i $i $r', &
messageType=MPAS_LOG_ERR, &
intArgs=(/iLayer, iCat, iCell, indexToCellID(iCell)/), &
realArgs=(/thisTracer % array3D(iLayer,iCat,iCell)/))
- ierr = SEAICE_ERROR_IR_NEG_MASS
+ abortFlag = .true.
return
+ else if (thisTracer % array3D(iLayer,iCat,iCell) >= -seaicePuny*seaicePuny .and. &
+ thisTracer % array3D(iLayer,iCat,iCell) < 0.0_RKIND) then
+ thisTracer % array3D(iLayer,iCat,iCell) = 0.0_RKIND
endif
enddo
enddo
@@ -8184,7 +8123,7 @@ end subroutine sum_tracers
!
!-----------------------------------------------------------------------
- subroutine check_tracer_conservation(dminfo, tracersHead, ierr)
+ subroutine check_tracer_conservation(dminfo, tracersHead, abortFlag)
type (dm_info), intent(in) :: dminfo !< Input: domain info
@@ -8192,8 +8131,8 @@ subroutine check_tracer_conservation(dminfo, tracersHead, ierr)
tracersHead !< Input/output: pointer to first element of linked list of tracers
! The pointer stays attached to the first tracer, but tracer sums are updated
- integer, intent(inout) :: &
- ierr ! thisTracer % localMax2D(iCat,iCell) + toleranceMax) then
@@ -8650,8 +8589,8 @@ subroutine check_tracer_monotonicity(domain, tracersHead, ierr)
call mpas_log_write('Tolerance, difference: $r $r', MPAS_LOG_ERR, &
realArgs=(/toleranceMax, thisTracer % array2D(iCat,iCell) - thisTracer % localMax2D(iCat,iCell)/))
call mpas_log_write('IR advection, monotonicity violation (max, nDims == 2)', MPAS_LOG_ERR)
- ierr = SEAICE_ERROR_IR_MONO
- call seaice_critical_error_write_block(domain, block)
+ abortFlag = .true.
+ call seaice_critical_error_write_block(domain, block, abortFlag)
return
endif
@@ -8765,8 +8704,8 @@ subroutine check_tracer_monotonicity(domain, tracersHead, ierr)
call mpas_log_write('Tolerance, difference: $r $r', MPAS_LOG_ERR, &
realArgs=(/toleranceMin, thisTracer % localMin3D(iLayer,iCat,iCell) - thisTracer % array3D(iLayer,iCat,iCell)/))
call mpas_log_write('IR advection, monotonicity violation (min, nDims == 3)', MPAS_LOG_ERR)
- ierr = SEAICE_ERROR_IR_MONO
- call seaice_critical_error_write_block(domain, block)
+ abortFlag = .true.
+ call seaice_critical_error_write_block(domain, block, abortFlag)
return
elseif (thisTracer % array3D(iLayer,iCat,iCell) > &
@@ -8784,8 +8723,8 @@ subroutine check_tracer_monotonicity(domain, tracersHead, ierr)
call mpas_log_write('Tolerance, difference: $r $r', MPAS_LOG_ERR, &
realArgs=(/toleranceMax, thisTracer % array3D(iLayer,iCat,iCell) - thisTracer % localMax3D(iLayer,iCat,iCell)/))
call mpas_log_write('IR advection, monotonicity violation (max, nDims == 3)', MPAS_LOG_ERR)
- ierr = SEAICE_ERROR_IR_MONO
- call seaice_critical_error_write_block(domain, block)
+ abortFlag = .true.
+ call seaice_critical_error_write_block(domain, block, abortFlag)
return
endif
diff --git a/src/core_seaice/shared/mpas_seaice_advection_incremental_remap_tracers.F b/src/core_seaice/shared/mpas_seaice_advection_incremental_remap_tracers.F
index b1f30702d1..398338a9a7 100644
--- a/src/core_seaice/shared/mpas_seaice_advection_incremental_remap_tracers.F
+++ b/src/core_seaice/shared/mpas_seaice_advection_incremental_remap_tracers.F
@@ -1,10 +1,3 @@
-! Copyright (c) 2015, Los Alamos National Security, LLC (LANS)
-! and the University Corporation for Atmospheric Research (UCAR).
-!
-! Unless noted otherwise source code is licensed under the BSD license.
-! Additional copyright and license information can be found in the LICENSE file
-! distributed with this code, or at http://mpas-dev.github.com/license.html
-!
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! mpas_seaice_advection_incremental_remap_tracers
@@ -45,16 +38,16 @@ module seaice_advection_incremental_remap_tracers
! (nLayer1, nLayer2, nCategories, nCells) for 3D
! tracer arrays
- real(kind=RKIND), dimension(:,:), pointer :: array2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: array3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: array2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: array3D => null()
! mass*tracer products
! = mass for mass field
! = mass*tracer1 for tracers with one parent
! = mass*tracer1*tracer2 for tracers with two parents
! = mass*tracer1*tracer2*tracer3 for tracers with three parents
- real(kind=RKIND), dimension(:,:), pointer :: massTracerProduct2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: massTracerProduct3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: massTracerProduct2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: massTracerProduct3D => null()
!TODO - Replace with one field, 2 time levels?
! global sums (over all cells)
@@ -77,14 +70,14 @@ module seaice_advection_incremental_remap_tracers
! fluxes across cell edges
! (nCategories, nEdges) for 2D
! (nLayers, nCategories, nEdges) for 3D
- real(kind=RKIND), dimension(:,:), pointer :: edgeFlux2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: edgeFlux3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: edgeFlux2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: edgeFlux3D => null()
! tracer values at each quadrature point of departure triangles
! (nCategories, nQuadPoints, nTriPerEdge, nEdges) for 2D
! (nLayers,nCategories, nQuadPoints, nTriPerEdge, nEdges) for 3D
- real(kind=RKIND), dimension(:,:,:,:), pointer :: triangleValue2D => null()
- real(kind=RKIND), dimension(:,:,:,:,:), pointer :: triangleValue3D => null()
+ real(kind=RKIND), dimension(:,:,:,:), pointer :: triangleValue2D => null()
+ real(kind=RKIND), dimension(:,:,:,:,:), pointer :: triangleValue3D => null()
! coordinates of barycenter associated with this tracer
! The term 'barycenter' refers to a center of mass or related quantity, as distinct from the geometric center.
@@ -95,25 +88,25 @@ module seaice_advection_incremental_remap_tracers
! The barycenter for this tracer is the location where the child tracer value (array2D or array3D) is located.
! Only mass-type fields (nParents = 0) are located at the geometric cell center.
- real(kind=RKIND), dimension(:,:), pointer :: xBarycenter2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: xBarycenter3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: xBarycenter2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: xBarycenter3D => null()
- real(kind=RKIND), dimension(:,:), pointer :: yBarycenter2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: yBarycenter3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: yBarycenter2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: yBarycenter3D => null()
! quantities needed for linear reconstruction (value at cell center plus x and y gradients)
! Note: The center value is the value at the geometric cell center and generally is
! difference from the value at the barycenter.
! xGrad and yGrad are the gradient components defined at the cell center
- real(kind=RKIND), dimension(:,:), pointer :: center2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: center3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: center2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: center3D => null()
- real(kind=RKIND), dimension(:,:), pointer :: xGrad2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: xGrad3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: xGrad2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: xGrad3D => null()
- real(kind=RKIND), dimension(:,:), pointer :: yGrad2D => null()
- real(kind=RKIND), dimension(:,:,:), pointer :: yGrad3D => null()
+ real(kind=RKIND), dimension(:,:), pointer :: yGrad2D => null()
+ real(kind=RKIND), dimension(:,:,:), pointer :: yGrad3D => null()
! pointer to parent tracer
type(tracer_type), pointer :: parent => null()
@@ -173,6 +166,8 @@ subroutine seaice_add_tracers_to_linked_list(domain)
pkgColumnTracerLevelIceActive, &
pkgColumnTracerPondsActive, &
pkgColumnTracerLidThicknessActive, &
+ pkgColumnTracerEffectiveSnowDensityActive, &
+ pkgColumnTracerSnowGrainRadiusActive, &
pkgColumnTracerAerosolsActive, &
pkgColumnBiogeochemistryActive, &
pkgTracerBrineActive, &
@@ -240,6 +235,10 @@ subroutine seaice_add_tracers_to_linked_list(domain)
pkgColumnTracerPondsActive)
call MPAS_pool_get_package(domain % blocklist % packages, 'pkgColumnTracerLidThicknessActive', &
pkgColumnTracerLidThicknessActive)
+ call MPAS_pool_get_package(domain % blocklist % packages, 'pkgColumnTracerEffectiveSnowDensityActive', &
+ pkgColumnTracerEffectiveSnowDensityActive)
+ call MPAS_pool_get_package(domain % blocklist % packages, 'pkgColumnTracerSnowGrainRadiusActive', &
+ pkgColumnTracerSnowGrainRadiusActive)
call MPAS_pool_get_package(domain % blocklist % packages, 'pkgColumnTracerAerosolsActive', &
pkgColumnTracerAerosolsActive)
call MPAS_pool_get_package(domain % blocklist % packages, 'pkgColumnBiogeochemistryActive', &
@@ -322,6 +321,18 @@ subroutine seaice_add_tracers_to_linked_list(domain)
call add_tracer_to_tracer_linked_list(tracersHead, 'pondLidThickness', 'pondArea')
endif
+ ! snow density
+ if (pkgColumnTracerEffectiveSnowDensityActive) then
+ call add_tracer_to_tracer_linked_list(tracersHead, 'snowIceMass', 'snowVolumeCategory')
+ call add_tracer_to_tracer_linked_list(tracersHead, 'snowLiquidMass', 'snowVolumeCategory')
+ call add_tracer_to_tracer_linked_list(tracersHead, 'snowDensity', 'snowVolumeCategory')
+ endif
+
+ ! snow grain radius
+ if (pkgColumnTracerSnowGrainRadiusActive) then
+ call add_tracer_to_tracer_linked_list(tracersHead, 'snowGrainRadius','snowVolumeCategory')
+ endif
+
if (pkgColumnTracerAerosolsActive) then
call add_tracer_to_tracer_linked_list(tracersHead, 'snowScatteringAerosol','snowVolumeCategory')
call add_tracer_to_tracer_linked_list(tracersHead, 'snowBodyAerosol', 'snowVolumeCategory')
diff --git a/src/core_seaice/shared/mpas_seaice_advection_upwind.F b/src/core_seaice/shared/mpas_seaice_advection_upwind.F
index da73a3f230..f64efc6e1d 100644
--- a/src/core_seaice/shared/mpas_seaice_advection_upwind.F
+++ b/src/core_seaice/shared/mpas_seaice_advection_upwind.F
@@ -53,6 +53,11 @@ module seaice_advection_upwind
type(tracerConnectivity), dimension(nTracerVariables), private :: &
tracerConnectivities
+ logical, parameter :: &
+ config_convert_volume_to_thickness = .true., &
+ config_limit_ice_concentration = .false., &
+ config_clean_tracers = .false.
+
contains
!-----------------------------------------------------------------------
@@ -73,12 +78,6 @@ module seaice_advection_upwind
subroutine seaice_init_advection_upwind(domain)!{{{
- !use mpas_tracer_advection_helpers, only: &
- ! mpas_tracer_advection_coefficients
-
- !use mpas_tracer_advection_mono, only: &
- ! mpas_tracer_advection_mono_init
-
use seaice_mesh, only: &
seaice_normal_vectors_polygon
@@ -93,36 +92,13 @@ subroutine seaice_init_advection_upwind(domain)!{{{
configs, &
velocity_solver
- integer, pointer :: &
- config_horiz_tracer_adv_order, &
- config_vert_tracer_adv_order
-
- real(kind=RKIND), pointer :: &
- config_coef_3rd_order
-
logical, pointer :: &
config_rotate_cartesian_grid, &
config_use_velocity_solver
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- derivTwo
-
real(kind=RKIND), dimension(:,:,:), pointer :: &
normalVectorEdge
- real(kind=RKIND), dimension(:,:), pointer :: &
- advCoefs, &
- advCoefs3rd
-
- integer, dimension(:), pointer :: &
- nAdvCellsForEdge, &
- maxLevelCell
-
- integer, dimension(:,:), pointer :: &
- advCellsForEdge, &
- highOrderAdvectionMask, &
- boundaryCell
-
integer :: &
err
@@ -134,44 +110,12 @@ subroutine seaice_init_advection_upwind(domain)!{{{
configs => block % configs
call MPAS_pool_get_config(configs, "config_use_velocity_solver", config_use_velocity_solver)
- call MPAS_pool_get_config(configs, "config_horiz_tracer_adv_order", config_horiz_tracer_adv_order)
- call MPAS_pool_get_config(configs, "config_vert_tracer_adv_order", config_vert_tracer_adv_order)
call MPAS_pool_get_config(configs, "config_rotate_cartesian_grid", config_rotate_cartesian_grid)
- call MPAS_pool_get_config(configs, "config_coef_3rd_order", config_coef_3rd_order)
-
- call MPAS_pool_get_array(mesh, "derivTwo", derivTwo)
- call MPAS_pool_get_array(mesh, "advCoefs", advCoefs)
- call MPAS_pool_get_array(mesh, "advCoefs3rd", advCoefs3rd)
- call MPAS_pool_get_array(mesh, "nAdvCellsForEdge", nAdvCellsForEdge)
- call MPAS_pool_get_array(mesh, "advCellsForEdge", advCellsForEdge)
- call MPAS_pool_get_array(mesh, "maxLevelCell", maxLevelCell)
- call MPAS_pool_get_array(mesh, "highOrderAdvectionMask", highOrderAdvectionMask)
- call MPAS_pool_get_array(mesh, "boundaryCell", boundaryCell)
call MPAS_pool_get_array(velocity_solver, "normalVectorEdge", normalVectorEdge)
err = 0
- !call mpas_tracer_advection_coefficients(&
- ! mesh, &
- ! config_horiz_tracer_adv_order, &
- ! derivTwo, &
- ! advCoefs, &
- ! advCoefs3rd, &
- ! nAdvCellsForEdge, &
- ! advCellsForEdge, &
- ! err, &
- ! maxLevelCell, &
- ! highOrderAdvectionMask, &
- ! boundaryCell)
-
- !call mpas_tracer_advection_mono_init(&
- ! 3, &
- ! config_horiz_tracer_adv_order, &
- ! config_vert_tracer_adv_order, &
- ! config_coef_3rd_order, &
- ! .false., .true., err)
-
call define_tracer_connectivities(&
config_use_velocity_solver)
@@ -1264,6 +1208,12 @@ subroutine run_advection_subvariable(&
childTracerOld(iTracerDimension,iCategory,iCell) * parentTracerOld(1,iCategory,iCell) + &
childTendency(iTracerDimension,iCategory,iCell) * dt
+ !write(*,*) trim(childTracerName), iCell, iCategory, iTracerDimension, &
+ ! childTracerOld(iTracerDimension,iCategory,iCell), &
+ ! parentTracerOld(1,iCategory,iCell), &
+ ! childTendency(iTracerDimension,iCategory,iCell), &
+ ! childTracerNew(iTracerDimension,iCategory,iCell)
+
! store the old child tracer multiplied by the old parent. This will be the parent tracer of the next child
childTracerOld(iTracerDimension,iCategory,iCell) = childTracerOld(iTracerDimension,iCategory,iCell) * &
parentTracerOld(iTracerDimension,iCategory,iCell)
@@ -1975,7 +1925,6 @@ subroutine prepare_tracers(&
iCategory
logical, pointer :: &
- config_convert_volume_to_thickness, &
config_conservation_check
integer, dimension(:), pointer :: &
@@ -1995,7 +1944,6 @@ subroutine prepare_tracers(&
call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
call MPAS_pool_get_array(tracers, "surfaceTemperature", surfaceTemperature, 1)
- call MPAS_pool_get_config(configs, "config_convert_volume_to_thickness", config_convert_volume_to_thickness)
call MPAS_pool_get_config(configs, "config_conservation_check", config_conservation_check)
if (config_convert_volume_to_thickness) then
@@ -2061,6 +2009,7 @@ subroutine finalize_tracers(&
real(kind=RKIND), dimension(:,:,:), pointer :: &
iceAreaCategory, &
+ iceAreaCategory2, &
surfaceTemperature, &
iceVolumeCategory, &
snowVolumeCategory, &
@@ -2075,10 +2024,7 @@ subroutine finalize_tracers(&
iCategory
logical, pointer :: &
- config_convert_volume_to_thickness, &
- config_limit_ice_concentration, &
- config_conservation_check, &
- config_clean_tracers
+ config_conservation_check
integer, dimension(:), pointer :: &
itimestep
@@ -2094,14 +2040,14 @@ subroutine finalize_tracers(&
call MPAS_pool_get_array(mesh, "areaCell", areaCell)
call MPAS_pool_get_array(tracers, "iceAreaCategory", iceAreaCategory, 1)
+ call MPAS_pool_get_array(tracers, "iceAreaCategory", iceAreaCategory2, 2)
call MPAS_pool_get_array(tracers, "surfaceTemperature", surfaceTemperature, 1)
call MPAS_pool_get_array(tracers, "iceVolumeCategory", iceVolumeCategory, 1)
call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
- call MPAS_pool_get_config(configs, "config_convert_volume_to_thickness", config_convert_volume_to_thickness)
- call MPAS_pool_get_config(configs, "config_limit_ice_concentration", config_limit_ice_concentration)
call MPAS_pool_get_config(configs, "config_conservation_check", config_conservation_check)
- call MPAS_pool_get_config(configs, "config_clean_tracers", config_clean_tracers)
+
+ !iceAreaCategory(:,:,:) = iceAreaCategory2(:,:,:)
if (config_conservation_check) &
call final_conservation(&
diff --git a/src/core_seaice/shared/mpas_seaice_column.F b/src/core_seaice/shared/mpas_seaice_column.F
index b96ee96598..b0e3498b7a 100644
--- a/src/core_seaice/shared/mpas_seaice_column.F
+++ b/src/core_seaice/shared/mpas_seaice_column.F
@@ -60,12 +60,6 @@ module seaice_column
! maximum number of ancestor tracers
integer :: nMaxAncestorTracers = 2
- ! category tracer array
- real(kind=RKIND), dimension(:,:), allocatable :: tracerArrayCategory ! trcrn
-
- ! cell tracer array
- real(kind=RKIND), dimension(:), allocatable :: tracerArrayCell ! trcr
-
! index of the parent tracer
integer, dimension(:), allocatable :: parentIndex ! trcr_depend
@@ -95,7 +89,11 @@ module seaice_column
index_pondArea, & ! nt_apnd
index_pondDepth, & ! nt_hpnd
index_pondLidThickness, & ! nt_ipnd
- index_aerosols ! nt_aero
+ index_aerosols, & ! nt_aero
+ index_snowIceMass, & ! nt_smice
+ index_snowLiquidMass, & ! nt_smliq
+ index_snowGrainRadius, & ! nt_rsnw
+ index_snowDensity ! nt_rhos
!-----------------------------------------------------------------------
! biogeochemistry
@@ -176,6 +174,13 @@ module seaice_column
type(ciceTracerObjectType), private :: ciceTracerObject
+ real(kind=RKIND), dimension(:,:), allocatable :: &
+ tracerArrayCategory
+!$omp threadprivate(tracerArrayCategory)
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ tracerArrayCell
+
! warnings string kind
integer, parameter :: strKINDWarnings = char_len_long
@@ -243,7 +248,8 @@ subroutine seaice_init_column_physics_package_variables(domain, clock)
config_use_column_package, &
config_do_restart, &
config_use_column_biogeochemistry, &
- config_use_column_shortwave
+ config_use_column_shortwave, &
+ config_use_column_snow_tracers
call MPAS_pool_get_config(domain % configs, "config_use_column_package", config_use_column_package)
call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
@@ -266,6 +272,11 @@ subroutine seaice_init_column_physics_package_variables(domain, clock)
! history variables
call init_column_history_variables(domain)
+ ! snow
+ call MPAS_pool_get_config(domain % configs, "config_use_column_snow_tracers", config_use_column_snow_tracers)
+ if (config_use_column_snow_tracers) &
+ call init_column_snow_tracers(domain)
+
! shortwave
call MPAS_pool_get_config(domain % configs, "config_do_restart", config_do_restart)
call MPAS_pool_get_config(domain % configs, "config_use_column_shortwave", config_use_column_shortwave)
@@ -420,6 +431,199 @@ subroutine init_column_thermodynamic_profiles(domain)
end subroutine init_column_thermodynamic_profiles
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! init_column_snow_tracers
+!
+!> \brief Initializes snow physics tracers
+!>
+!> \author Nicole Jeffery, LANL
+!> \date 1 April 2017
+!> \details
+!>
+!> The following snow tracers are initialized:
+!> 1) Snow liquid content (used to compute wet metamorphism of snow grain, modifies
+!> liquid content of ponds, used in calculation of effective snow density due to content)
+!> 2) Snow ice content (Used in calculation of effective snow density due to content)
+!> 3) Effective snow density (both content and compaction are included. May be used for snow grain aging)
+!> 4) Snow grain radius (used in radiative transfer calculations)
+!
+!-----------------------------------------------------------------------
+
+ subroutine init_column_snow_tracers(domain)
+
+ use seaice_constants, only: &
+ seaicePuny, &
+ seaiceDensitySnow
+
+ type(domain_type), intent(in) :: &
+ domain
+
+ type(block_type), pointer :: &
+ block
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ tracers, &
+ tracers_aggregate, &
+ snow
+
+ logical, pointer :: &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius, &
+ config_do_restart_snow_density, &
+ config_do_restart_snow_grain_radius
+
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ snowIceMass, &
+ snowLiquidMass, &
+ snowDensity, &
+ snowVolumeCategory, &
+ snowGrainRadius
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ snowMeltMassCategory
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ snowDensityViaContent, &
+ snowDensityViaCompaction, &
+ snowMeltMassCell, &
+ snowVolumeCell
+
+ real(kind=RKIND), pointer :: &
+ config_fallen_snow_radius
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nSnowLayers, &
+ nCategories
+
+ integer :: &
+ iCell, &
+ iSnowLayer, &
+ iCategory
+
+ call MPAS_pool_get_config(domain % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
+ call MPAS_pool_get_config(domain % configs, "config_fallen_snow_radius", config_fallen_snow_radius)
+ call MPAS_pool_get_config(domain % configs, "config_do_restart_snow_density", config_do_restart_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_do_restart_snow_grain_radius", config_do_restart_snow_grain_radius)
+
+ block => domain % blocklist
+ do while (associated(block))
+
+ call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
+ call MPAS_pool_get_subpool(block % structs, "tracers", tracers)
+ call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracers_aggregate)
+ call MPAS_pool_get_subpool(block % structs, "snow", snow)
+
+ call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve)
+ call MPAS_pool_get_dimension(block % dimensions, "nCategories", nCategories)
+ call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers)
+
+ call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
+ call MPAS_pool_get_array(tracers_aggregate, "snowVolumeCell", snowVolumeCell)
+
+ if (config_use_effective_snow_density) then
+
+ call MPAS_pool_get_array(snow, "snowDensityViaContent", snowDensityViaContent)
+ call MPAS_pool_get_array(snow, "snowDensityViaCompaction", snowDensityViaCompaction)
+ call MPAS_pool_get_array(snow, "snowMeltMassCategory", snowMeltMassCategory)
+ call MPAS_pool_get_array(snow, "snowMeltMassCell", snowMeltMassCell)
+
+ call MPAS_pool_get_array(tracers, "snowIceMass", snowIceMass, 1)
+ call MPAS_pool_get_array(tracers, "snowLiquidMass", snowLiquidMass, 1)
+ call MPAS_pool_get_array(tracers, "snowDensity", snowDensity, 1)
+
+ if (.not. config_do_restart_snow_density) then
+
+ snowIceMass(:,:,:) = 0.0_RKIND
+ snowLiquidMass(:,:,:) = 0.0_RKIND
+ snowDensity(:,:,:) = 0.0_RKIND
+ snowDensityViaContent(:) = 0.0_RKIND
+ snowDensityViaCompaction(:) = 0.0_RKIND
+ snowMeltMassCategory(:,:) = 0.0_RKIND
+ snowMeltMassCell(:) = 0.0_RKIND
+
+ do iCell = 1, nCellsSolve
+
+ do iCategory = 1, nCategories
+ if (snowVolumeCategory(1,iCategory,iCell) .gt. 0.0_RKIND) then
+ do iSnowLayer = 1, nSnowLayers
+ snowIceMass(iSnowLayer,iCategory,iCell) = seaiceDensitySnow
+ snowDensity(iSnowLayer,iCategory,iCell) = seaiceDensitySnow
+ snowDensityViaContent(iCell) = snowDensityViaContent(iCell) &
+ + snowVolumeCategory(1,iCategory,iCell) * &
+ (snowIceMass(iSnowLayer,iCategory,iCell) + &
+ snowLiquidMass(iSnowLayer,iCategory,iCell))
+ snowDensityViaCompaction(iCell) = snowDensityViaCompaction(iCell) &
+ + snowVolumeCategory(1,iCategory,iCell) * &
+ snowDensity(iSnowLayer,iCategory,iCell)
+ enddo !iSnowLayer
+ endif !snowVolumeCategory
+ enddo !iCategory
+ if (snowVolumeCell(iCell) .gt. seaicePuny) then
+ snowDensityViaContent(iCell) = snowDensityViaContent(iCell)/ &
+ (snowVolumeCell(iCell) * real(nSnowLayers,kind=RKIND)) !!!CHECK THIS!!!
+ snowDensityViaCompaction(iCell) = snowDensityViaCompaction(iCell)/ &
+ (snowVolumeCell(iCell) * real(nSnowLayers,kind=RKIND))
+ else
+ snowDensityViaContent(iCell) = 0.0_RKIND
+ snowDensityViaCompaction(iCell) = 0.0_RKIND
+ endif !snowVolumeCell
+
+ enddo ! iCell
+ else
+
+ snowDensityViaContent(:) = 0.0_RKIND
+ snowDensityViaCompaction(:) = 0.0_RKIND
+ snowMeltMassCategory(:,:) = 0.0_RKIND
+ snowMeltMassCell(:) = 0.0_RKIND
+
+ do iCell = 1, nCellsSolve
+
+ do iCategory = 1, nCategories
+ if (snowVolumeCategory(1,iCategory,iCell) .gt. 0.0_RKIND) then
+ do iSnowLayer = 1, nSnowLayers
+ snowDensityViaContent(iCell) = snowDensityViaContent(iCell) &
+ + snowVolumeCategory(1,iCategory,iCell) * &
+ (snowIceMass(iSnowLayer,iCategory,iCell) + &
+ snowLiquidMass(iSnowLayer,iCategory,iCell))
+ snowDensityViaCompaction(iCell) = snowDensityViaCompaction(iCell) &
+ + snowVolumeCategory(1,iCategory,iCell) * &
+ snowDensity(iSnowLayer,iCategory,iCell)
+ enddo !iSnowLayer
+ endif !snowVolumeCategory
+ enddo !iCategory
+ if (snowVolumeCell(iCell) .gt. seaicePuny) then
+ snowDensityViaContent(iCell) = snowDensityViaContent(iCell)/ &
+ (snowVolumeCell(iCell) * real(nSnowLayers,kind=RKIND)) !!!CHECK THIS!!!
+ snowDensityViaCompaction(iCell) = snowDensityViaCompaction(iCell)/ &
+ (snowVolumeCell(iCell) * real(nSnowLayers,kind=RKIND))
+ else
+ snowDensityViaContent(iCell) = 0.0_RKIND
+ snowDensityViaCompaction(iCell) = 0.0_RKIND
+ endif !snowVolumeCell
+
+ enddo ! iCell
+ endif ! config_do_restart_snow_density
+ endif !config_use_effective_snow_density
+
+ if (config_use_snow_grain_radius) then
+ if (.not. config_do_restart_snow_grain_radius) then
+
+ call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1)
+
+ snowGrainRadius(:,:,:) = config_fallen_snow_radius
+
+ endif ! config_do_restart_snow_grain_radius
+ endif ! config_use_snow_grain_radius
+
+ block => block % next
+ end do
+
+ end subroutine init_column_snow_tracers
+
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! init_column_shortwave
@@ -436,7 +640,6 @@ subroutine seaice_init_column_shortwave(domain, clock)
use ice_colpkg, only: &
colpkg_init_orbit, &
- colpkg_get_warnings, &
colpkg_clear_warnings
use seaice_constants, only: &
@@ -506,13 +709,12 @@ subroutine seaice_init_column_shortwave(domain, clock)
config_shortwave_type
logical, pointer :: &
- config_do_restart
-
- character(len=strKINDWarnings), dimension(:), allocatable :: &
- warnings
+ config_do_restart, &
+ config_use_snicar_ad
call MPAS_pool_get_config(domain % configs, "config_shortwave_type", config_shortwave_type)
call MPAS_pool_get_config(domain % configs, "config_do_restart", config_do_restart)
+ call MPAS_pool_get_config(domain % configs, "config_use_snicar_ad", config_use_snicar_ad)
if (trim(config_shortwave_type) == "dEdd") then
@@ -523,8 +725,7 @@ subroutine seaice_init_column_shortwave(domain, clock)
call colpkg_init_orbit(&
abortFlag, &
abortMessage)
- call colpkg_get_warnings(warnings)
- call column_write_warnings(warnings)
+ call column_write_warnings(abortFlag)
if (abortFlag) then
call mpas_log_write("colpkg_init_orbit: "//trim(abortMessage), messageType=MPAS_LOG_CRIT)
@@ -834,14 +1035,12 @@ end subroutine seaice_column_finalize
!
!-----------------------------------------------------------------------
- subroutine seaice_column_predynamics_time_integration(domain, clock, ierr)
+ subroutine seaice_column_predynamics_time_integration(domain, clock)
type(domain_type), intent(inout) :: domain
type(MPAS_clock_type), intent(in) :: clock
- integer, intent(inout) :: ierr
-
logical, pointer :: &
config_use_column_package, &
config_use_column_shortwave, &
@@ -883,9 +1082,8 @@ subroutine seaice_column_predynamics_time_integration(domain, clock, ierr)
call mpas_timer_start("Column vertical thermodynamics")
if (config_use_column_vertical_thermodynamics) &
- call column_vertical_thermodynamics(domain, clock, ierr)
+ call column_vertical_thermodynamics(domain, clock)
call mpas_timer_stop("Column vertical thermodynamics")
- if (config_use_column_vertical_thermodynamics .and. ierr > 0) return
!-----------------------------------------------------------------
! Biogeochemistry
@@ -893,9 +1091,8 @@ subroutine seaice_column_predynamics_time_integration(domain, clock, ierr)
call mpas_timer_start("Column biogeochemistry")
if (config_use_column_biogeochemistry) &
- call column_biogeochemistry(domain, ierr)
+ call column_biogeochemistry(domain)
call mpas_timer_stop("Column biogeochemistry")
- if (config_use_column_biogeochemistry .and. ierr > 0) return
!-----------------------------------------------------------------
! ITD thermodynamics
@@ -903,9 +1100,8 @@ subroutine seaice_column_predynamics_time_integration(domain, clock, ierr)
call mpas_timer_start("Column ITD thermodynamics")
if (config_use_column_itd_thermodynamics) &
- call column_itd_thermodynamics(domain, clock, ierr)
+ call column_itd_thermodynamics(domain, clock)
call mpas_timer_stop("Column ITD thermodynamics")
- if (config_use_column_itd_thermodynamics .and. ierr > 0) return
!-----------------------------------------------------------------
! Update the aggregated state variables
@@ -940,14 +1136,12 @@ end subroutine seaice_column_predynamics_time_integration
!
!-----------------------------------------------------------------------
- subroutine seaice_column_dynamics_time_integration(domain, clock, ierr)
+ subroutine seaice_column_dynamics_time_integration(domain, clock)
type(domain_type), intent(inout) :: domain
type(MPAS_clock_type), intent(in) :: clock
- integer, intent(inout) :: ierr
-
logical, pointer :: &
config_use_column_package, &
config_use_column_ridging, &
@@ -984,9 +1178,8 @@ subroutine seaice_column_dynamics_time_integration(domain, clock, ierr)
call mpas_timer_start("Column ridging")
if (config_use_column_ridging) &
- call column_ridging(domain, ierr)
+ call column_ridging(domain)
call mpas_timer_stop("Column ridging")
- if (config_use_column_ridging .and. ierr > 0) return
!-----------------------------------------------------------------
! Update the aggregated state variables
@@ -1020,13 +1213,27 @@ subroutine seaice_column_postdynamics_time_integration(domain, clock)
logical, pointer :: &
config_use_column_package, &
- config_use_column_shortwave
+ config_use_column_shortwave, &
+ config_use_column_snow_tracers
+
+ type(block_type), pointer :: &
+ block
call MPAS_pool_get_config(domain % configs, "config_use_column_package", config_use_column_package)
if (config_use_column_package) then
call MPAS_pool_get_config(domain % configs, "config_use_column_shortwave", config_use_column_shortwave)
+ call MPAS_pool_get_config(domain % configs, "config_use_column_snow_tracers", config_use_column_snow_tracers)
+
+ !-----------------------------------------------------------------
+ ! snow
+ !-----------------------------------------------------------------
+
+ call mpas_timer_start("Column snow")
+ if (config_use_column_snow_tracers) &
+ call column_snow(domain)
+ call mpas_timer_stop("Column snow")
!-----------------------------------------------------------------
! Shortwave radiation
@@ -1061,22 +1268,22 @@ end subroutine seaice_column_postdynamics_time_integration
!
!-----------------------------------------------------------------------
- subroutine column_vertical_thermodynamics(domain, clock, ierr)
+ subroutine column_vertical_thermodynamics(domain, clock)
use ice_colpkg, only: &
colpkg_step_therm1, &
- colpkg_clear_warnings, &
- colpkg_get_warnings
+ colpkg_clear_warnings
use seaice_constants, only: &
seaicePuny
+ use seaice_mesh, only: &
+ seaice_interpolate_vertex_to_cell
+
type(domain_type), intent(inout) :: domain
type(MPAS_clock_type), intent(in) :: clock
- integer, intent(inout) :: ierr
-
type(block_type), pointer :: block
type(MPAS_pool_type), pointer :: &
@@ -1096,14 +1303,19 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
shortwave, &
ponds, &
aerosols, &
- diagnostics
+ diagnostics, &
+ snow, &
+ boundary
! configs
real(kind=RKIND), pointer :: &
config_dt
logical, pointer :: &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_prescribed_ice, &
+ config_use_snow_liquid_ponds, &
+ config_use_high_frequency_coupling
! dimensions
integer, pointer :: &
@@ -1122,6 +1334,8 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
snowVolumeCell, &
uVelocity, &
vvelocity, &
+ uVelocityCell, &
+ vvelocityCell, &
uAirVelocity, &
vAirVelocity, &
windSpeed, &
@@ -1187,7 +1401,10 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
frazilFormation, &
meltOnset, &
freezeOnset, &
- oceanHeatFluxIceBottom
+ oceanHeatFluxIceBottom, &
+ openWaterArea, &
+ snowLossToLeads, &
+ snowMeltMassCell
real(kind=RKIND), dimension(:,:), pointer :: &
iceAreaCategoryInitial, &
@@ -1213,7 +1430,9 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
sensibleHeatFluxCouple, &
surfaceHeatFluxCouple, &
surfaceConductiveFluxCouple, &
- snowThicknessChangeCategory
+ snowThicknessChangeCategory, &
+ snowMeltMassCategory, &
+ snowRadiusInStandardRadiationSchemeCategory
real(kind=RKIND), dimension(:,:,:), pointer :: &
iceAreaCategory, &
@@ -1235,7 +1454,10 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
snowScatteringAerosol, &
snowBodyAerosol, &
iceScatteringAerosol, &
- iceBodyAerosol
+ iceBodyAerosol, &
+ snowIceMass, &
+ snowLiquidMass, &
+ snowGrainRadius
integer, dimension(:), pointer :: &
indexToCellID
@@ -1261,9 +1483,6 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
real(kind=RKIND) :: &
dayOfYear
- character(len=strKINDWarnings), dimension(:), allocatable :: &
- warnings
-
! day of year
call get_day_of_year(clock, dayOfYear)
@@ -1287,9 +1506,14 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
call MPAS_pool_get_subpool(block % structs, "ponds", ponds)
call MPAS_pool_get_subpool(block % structs, "aerosols", aerosols)
call MPAS_pool_get_subpool(block % structs, "diagnostics", diagnostics)
+ call MPAS_pool_get_subpool(block % structs, "snow", snow)
+ call MPAS_pool_get_subpool(block % structs, "boundary", boundary)
call MPAS_pool_get_config(block % configs, "config_dt", config_dt)
call MPAS_pool_get_config(block % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(block % configs, "config_use_prescribed_ice", config_use_prescribed_ice)
+ call MPAS_pool_get_config(block % configs, "config_use_snow_liquid_ponds", config_use_snow_liquid_ponds)
+ call MPAS_pool_get_config(block % configs, "config_use_high_frequency_coupling", config_use_high_frequency_coupling)
call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve)
call MPAS_pool_get_dimension(mesh, "nCategories", nCategories)
@@ -1304,6 +1528,7 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
call MPAS_pool_get_array(icestate, "iceAreaCategoryInitial", iceAreaCategoryInitial)
call MPAS_pool_get_array(icestate, "iceVolumeCategoryInitial", iceVolumeCategoryInitial)
call MPAS_pool_get_array(icestate, "snowVolumeCategoryInitial", snowVolumeCategoryInitial)
+ call MPAS_pool_get_array(icestate, "openWaterArea", openWaterArea)
call MPAS_pool_get_array(tracers_aggregate, "iceAreaCell", iceAreaCell)
call MPAS_pool_get_array(tracers_aggregate, "iceVolumeCell", iceVolumeCell)
@@ -1327,9 +1552,14 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
call MPAS_pool_get_array(tracers, "snowBodyAerosol", snowBodyAerosol, 1)
call MPAS_pool_get_array(tracers, "iceScatteringAerosol", iceScatteringAerosol, 1)
call MPAS_pool_get_array(tracers, "iceBodyAerosol", iceBodyAerosol, 1)
+ call MPAS_pool_get_array(tracers, "snowIceMass", snowIceMass, 1)
+ call MPAS_pool_get_array(tracers, "snowLiquidMass", snowLiquidMass, 1)
+ call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1)
call MPAS_pool_get_array(velocity_solver, "uVelocity", uVelocity)
call MPAS_pool_get_array(velocity_solver, "vVelocity", vVelocity)
+ call MPAS_pool_get_array(velocity_solver, "uVelocityCell", uVelocityCell)
+ call MPAS_pool_get_array(velocity_solver, "vVelocityCell", vVelocityCell)
call MPAS_pool_get_array(velocity_solver, "airStressCellU", airStressCellU)
call MPAS_pool_get_array(velocity_solver, "airStressCellV", airStressCellV)
call MPAS_pool_get_array(velocity_solver, "oceanStressCellU", oceanStressCellU)
@@ -1432,6 +1662,16 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
call MPAS_pool_get_array(diagnostics, "meltOnset", meltOnset)
call MPAS_pool_get_array(diagnostics, "freezeOnset", freezeOnset)
+ call MPAS_pool_get_array(snow, "snowLossToLeads", snowLossToLeads)
+ call MPAS_pool_get_array(snow, "snowMeltMassCell", snowMeltMassCell)
+ call MPAS_pool_get_array(snow, "snowMeltMassCategory", snowMeltMassCategory)
+
+ ! high frequency coupling needs to cell center velocity
+ if (config_use_high_frequency_coupling) then
+ call seaice_interpolate_vertex_to_cell(mesh, boundary, uVelocityCell, uVelocity)
+ call seaice_interpolate_vertex_to_cell(mesh, boundary, vVelocityCell, vVelocity)
+ endif
+
! aerosols
if (config_use_aerosols) then
@@ -1447,7 +1687,13 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
endif
- ! loop over cells
+ ! code abort
+ abortFlag = .false.
+ abortMessage = ""
+
+ !$omp parallel do default(shared) private(iCategory,iAerosol,northernHemisphereMask,&
+ !$omp& abortMessage) firstprivate(specificSnowAerosol,specificIceAerosol) &
+ !$omp& reduction(.or.:abortFlag)
do iCell = 1, nCellsSolve
! initial state values
@@ -1489,9 +1735,6 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
northernHemisphereMask = .false.
endif
- abortFlag = .false.
- abortMessage = ""
-
call colpkg_clear_warnings()
call colpkg_step_therm1(&
config_dt, &
@@ -1499,6 +1742,7 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
nIceLayers, &
nSnowLayers, &
nAerosols, &
+ openWaterArea(iCell), &
iceAreaCategoryInitial(:,iCell), &
iceVolumeCategoryInitial(:,iCell), &
snowVolumeCategoryInitial(:,iCell), &
@@ -1508,12 +1752,14 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
iceVolumeCategory(1,:,iCell), &
snowVolumeCell(iCell), &
snowVolumeCategory(1,:,iCell), &
- uVelocity(iCell), &
- vVelocity(iCell), &
+ uVelocityCell(iCell), &
+ vVelocityCell(iCell), &
surfaceTemperature(1,:,iCell), &
snowEnthalpy(:,:,iCell), &
iceEnthalpy(:,:,iCell), &
iceSalinity(:,:,iCell), &
+ snowIceMass(:,:,iCell), &
+ snowLiquidMass(:,:,iCell), &
levelIceArea(1,:,iCell), &
levelIceVolume(1,:,iCell), &
pondArea(1,:,iCell), &
@@ -1521,6 +1767,8 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
pondLidThickness(1,:,iCell), &
iceAge(1,:,iCell), &
firstYearIceArea(1,:,iCell), &
+ snowGrainRadius(:,:,iCell), &
+ config_use_snow_liquid_ponds, &
specificSnowAerosol(:,:,:), &
specificIceAerosol(:,:,:), &
uAirVelocity(iCell), &
@@ -1567,6 +1815,7 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
snowfallRate(iCell), &
rainfallRate(iCell), &
pondFreshWaterFlux(iCell), &
+ snowLossToLeads(iCell), &
surfaceHeatFlux(iCell), &
surfaceHeatFluxCategory(:,iCell), &
surfaceConductiveFlux(iCell), &
@@ -1604,6 +1853,8 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
lateralIceMelt(iCell), &
snowMelt(iCell), &
snowMeltCategory(:,iCell), &
+ snowMeltMassCell(iCell), &
+ snowMeltMassCategory(:,iCell), &
congelation(iCell), &
congelationCategory(:,iCell), &
snowiceFormation(iCell), &
@@ -1616,17 +1867,168 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
freezeOnset(iCell), &
dayOfYear, &
abortFlag, &
- abortMessage)
- call colpkg_get_warnings(warnings)
- call column_write_warnings(warnings)
+ abortMessage, &
+ config_use_prescribed_ice)
+ call column_write_warnings(abortFlag)
- ! code abort
+ ! cell-specific abort message
if (abortFlag) then
call mpas_log_write("column_vertical_thermodynamics: "//trim(abortMessage) , messageType=MPAS_LOG_ERR)
call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
- ierr = SEAICE_ERROR_COL_VERT_THERM
- call seaice_critical_error_write_block(domain, block)
- return
+
+ call mpas_log_write("config_dt: $r", messageType=MPAS_LOG_ERR, realArgs=(/config_dt/))
+ call mpas_log_write("nCategories: $i", messageType=MPAS_LOG_ERR, intArgs=(/nCategories/))
+ call mpas_log_write("nIceLayers: $i", messageType=MPAS_LOG_ERR, intArgs=(/nIceLayers/))
+ call mpas_log_write("nSnowLayers: $i", messageType=MPAS_LOG_ERR, intArgs=(/nSnowLayers/))
+ call mpas_log_write("nAerosols: $i", messageType=MPAS_LOG_ERR, intArgs=(/nAerosols/))
+ call mpas_log_write("openWaterArea: $r", messageType=MPAS_LOG_ERR, realArgs=(/openWaterArea(iCell)/))
+ call mpas_log_write("iceAreaCategoryInitial: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(:,iCell)/))
+ call mpas_log_write("iceVolumeCategoryInitial: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategoryInitial(:,iCell)/))
+ call mpas_log_write("snowVolumeCategoryInitial: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/snowVolumeCategoryInitial(:,iCell)/))
+ call mpas_log_write("iceAreaCell: $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCell(iCell)/))
+ call mpas_log_write("iceAreaCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,:,iCell)/))
+ call mpas_log_write("iceVolumeCell: $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCell(iCell)/))
+ call mpas_log_write("iceVolumeCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategory(1,:,iCell)/))
+ call mpas_log_write("snowVolumeCell: $r", messageType=MPAS_LOG_ERR, realArgs=(/snowVolumeCell(iCell)/))
+ call mpas_log_write("snowVolumeCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/snowVolumeCategory(1,:,iCell)/))
+ call mpas_log_write("uVelocityCell: $r", messageType=MPAS_LOG_ERR, realArgs=(/uVelocityCell(iCell)/))
+ call mpas_log_write("vVelocityCell: $r", messageType=MPAS_LOG_ERR, realArgs=(/vVelocityCell(iCell)/))
+ call mpas_log_write("surfaceTemperature: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceTemperature(1,:,iCell)/))
+ do iCategory = 1, nCategories
+ call mpas_log_write("snowEnthalpy: $i "//repeat("$r ", nSnowLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/snowEnthalpy(:,iCategory,iCell)/))
+ enddo ! iCategory
+ do iCategory = 1, nCategories
+ call mpas_log_write("iceEnthalpy: $i "//repeat("$r ", nIceLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/iceEnthalpy(:,iCategory,iCell)/))
+ enddo ! iCategory
+ do iCategory = 1, nCategories
+ call mpas_log_write("iceSalinity: $i "//repeat("$r ", nIceLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/iceSalinity(:,iCategory,iCell)/))
+ enddo ! iCategory
+ do iCategory = 1, nCategories
+ call mpas_log_write("snowIceMass: $i "//repeat("$r ", nSnowLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/snowIceMass(:,iCategory,iCell)/))
+ enddo ! iCategory
+ do iCategory = 1, nCategories
+ call mpas_log_write("snowLiquidMass: $i "//repeat("$r ", nSnowLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/snowLiquidMass(:,iCategory,iCell)/))
+ enddo ! iCategory
+ call mpas_log_write("levelIceArea: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/levelIceArea(1,:,iCell)/))
+ call mpas_log_write("levelIceVolume: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/levelIceVolume(1,:,iCell)/))
+ call mpas_log_write("pondArea: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/pondArea(1,:,iCell)/))
+ call mpas_log_write("pondDepth: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/pondDepth(1,:,iCell)/))
+ call mpas_log_write("pondLidThickness: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/pondLidThickness(1,:,iCell)/))
+ call mpas_log_write("iceAge: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/iceAge(1,:,iCell)/))
+ call mpas_log_write("firstYearIceArea: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/firstYearIceArea(1,:,iCell)/))
+ do iCategory = 1, nCategories
+ call mpas_log_write("snowGrainRadius: $i "//repeat("$r ", nSnowLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/snowGrainRadius(:,iCategory,iCell)/))
+ enddo ! iCategory
+ call mpas_log_write("config_use_snow_liquid_ponds: $l", messageType=MPAS_LOG_ERR, logicArgs=(/config_use_snow_liquid_ponds/))
+ if (config_use_aerosols) then
+ do iCategory = 1, nCategories
+ call mpas_log_write("specificSnowAerosol $i 1: "//repeat("$r ", nAerosols), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/specificSnowAerosol(:,1,iCategory)/))
+ call mpas_log_write("specificSnowAerosol $i 2: "//repeat("$r ", nAerosols), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/specificSnowAerosol(:,2,iCategory)/))
+ enddo ! iCategory
+ do iCategory = 1, nCategories
+ call mpas_log_write("specificIceAerosol $i 1: "//repeat("$r ", nAerosols), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/specificIceAerosol(:,1,iCategory)/))
+ call mpas_log_write("specificIceAerosol $i 2: "//repeat("$r ", nAerosols), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/specificIceAerosol(:,2,iCategory)/))
+ enddo ! iCategory
+ endif
+ call mpas_log_write("uAirVelocity: $r", messageType=MPAS_LOG_ERR, realArgs=(/uAirVelocity(iCell)/))
+ call mpas_log_write("vAirVelocity: $r", messageType=MPAS_LOG_ERR, realArgs=(/vAirVelocity(iCell)/))
+ call mpas_log_write("windSpeed: $r", messageType=MPAS_LOG_ERR, realArgs=(/windSpeed(iCell)/))
+ call mpas_log_write("airLevelHeight: $r", messageType=MPAS_LOG_ERR, realArgs=(/airLevelHeight(iCell)/))
+ call mpas_log_write("airSpecificHumidity: $r", messageType=MPAS_LOG_ERR, realArgs=(/airSpecificHumidity(iCell)/))
+ call mpas_log_write("airDensity: $r", messageType=MPAS_LOG_ERR, realArgs=(/airDensity(iCell)/))
+ call mpas_log_write("airTemperature: $r", messageType=MPAS_LOG_ERR, realArgs=(/airTemperature(iCell)/))
+ call mpas_log_write("atmosReferenceTemperature2m: $r", messageType=MPAS_LOG_ERR, realArgs=(/atmosReferenceTemperature2m(iCell)/))
+ call mpas_log_write("atmosReferenceHumidity2m: $r", messageType=MPAS_LOG_ERR, realArgs=(/atmosReferenceHumidity2m(iCell)/))
+ call mpas_log_write("atmosReferenceSpeed10m: $r", messageType=MPAS_LOG_ERR, realArgs=(/atmosReferenceSpeed10m(iCell)/))
+ call mpas_log_write("airOceanDragCoefficientRatio: $r", messageType=MPAS_LOG_ERR, realArgs=(/airOceanDragCoefficientRatio(iCell)/))
+ call mpas_log_write("oceanDragCoefficient: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanDragCoefficient(iCell)/))
+ call mpas_log_write("oceanDragCoefficientSkin: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanDragCoefficientSkin(iCell)/))
+ call mpas_log_write("oceanDragCoefficientFloe: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanDragCoefficientFloe(iCell)/))
+ call mpas_log_write("oceanDragCoefficientKeel: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanDragCoefficientKeel(iCell)/))
+ call mpas_log_write("airDragCoefficient: $r", messageType=MPAS_LOG_ERR, realArgs=(/airDragCoefficient(iCell)/))
+ call mpas_log_write("airDragCoefficientSkin: $r", messageType=MPAS_LOG_ERR, realArgs=(/airDragCoefficientSkin(iCell)/))
+ call mpas_log_write("airDragCoefficientFloe: $r", messageType=MPAS_LOG_ERR, realArgs=(/airDragCoefficientFloe(iCell)/))
+ call mpas_log_write("airDragCoefficientPond: $r", messageType=MPAS_LOG_ERR, realArgs=(/airDragCoefficientPond(iCell)/))
+ call mpas_log_write("airDragCoefficientRidge: $r", messageType=MPAS_LOG_ERR, realArgs=(/airDragCoefficientRidge(iCell)/))
+ call mpas_log_write("dragFreeboard: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragFreeboard(iCell)/))
+ call mpas_log_write("dragIceSnowDraft: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragIceSnowDraft(iCell)/))
+ call mpas_log_write("dragRidgeHeight: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragRidgeHeight(iCell)/))
+ call mpas_log_write("dragRidgeSeparation: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragRidgeSeparation(iCell)/))
+ call mpas_log_write("dragKeelDepth: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragKeelDepth(iCell)/))
+ call mpas_log_write("dragKeelSeparation: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragKeelSeparation(iCell)/))
+ call mpas_log_write("dragFloeLength: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragFloeLength(iCell)/))
+ call mpas_log_write("dragFloeSeparation: $r", messageType=MPAS_LOG_ERR, realArgs=(/dragFloeSeparation(iCell)/))
+ call mpas_log_write("airStressForcingU: $r", messageType=MPAS_LOG_ERR, realArgs=(/airStressForcingU(iCell)/))
+ call mpas_log_write("airStressForcingV: $r", messageType=MPAS_LOG_ERR, realArgs=(/airStressForcingV(iCell)/))
+ call mpas_log_write("airStressCellU: $r", messageType=MPAS_LOG_ERR, realArgs=(/airStressCellU(iCell)/))
+ call mpas_log_write("airStressCellV: $r", messageType=MPAS_LOG_ERR, realArgs=(/airStressCellV(iCell)/))
+ call mpas_log_write("airPotentialTemperature: $r", messageType=MPAS_LOG_ERR, realArgs=(/airPotentialTemperature(iCell)/))
+ call mpas_log_write("seaSurfaceTemperature: $r", messageType=MPAS_LOG_ERR, realArgs=(/seaSurfaceTemperature(iCell)/))
+ call mpas_log_write("seaSurfaceSalinity: $r", messageType=MPAS_LOG_ERR, realArgs=(/seaSurfaceSalinity(iCell)/))
+ call mpas_log_write("seaFreezingTemperature: $r", messageType=MPAS_LOG_ERR, realArgs=(/seaFreezingTemperature(iCell)/))
+ call mpas_log_write("oceanStressCellU: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanStressCellU(iCell)/))
+ call mpas_log_write("oceanStressCellV: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanStressCellV(iCell)/))
+ call mpas_log_write("oceanHeatFluxIceBottom: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanHeatFluxIceBottom(iCell)/))
+ call mpas_log_write("freezingMeltingPotential: $r", messageType=MPAS_LOG_ERR, realArgs=(/freezingMeltingPotential(iCell)/))
+ call mpas_log_write("lateralIceMeltFraction: $r", messageType=MPAS_LOG_ERR, realArgs=(/lateralIceMeltFraction(iCell)/))
+ call mpas_log_write("snowfallRate: $r", messageType=MPAS_LOG_ERR, realArgs=(/snowfallRate(iCell)/))
+ call mpas_log_write("rainfallRate: $r", messageType=MPAS_LOG_ERR, realArgs=(/rainfallRate(iCell)/))
+ call mpas_log_write("pondFreshWaterFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/pondFreshWaterFlux(iCell)/))
+ call mpas_log_write("snowLossToLeads: $r", messageType=MPAS_LOG_ERR, realArgs=(/snowLossToLeads(iCell)/))
+ call mpas_log_write("surfaceHeatFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/surfaceHeatFlux(iCell)/))
+ call mpas_log_write("surfaceHeatFluxCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceHeatFluxCategory(:,iCell)/))
+ call mpas_log_write("surfaceConductiveFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/surfaceConductiveFlux(iCell)/))
+ call mpas_log_write("surfaceConductiveFluxCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceConductiveFluxCategory(:,iCell)/))
+ call mpas_log_write("surfaceShortwaveFlux: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceShortwaveFlux(:,iCell)/))
+ call mpas_log_write("interiorShortwaveFlux: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/interiorShortwaveFlux(:,iCell)/))
+ call mpas_log_write("penetratingShortwaveFlux: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/penetratingShortwaveFlux(:,iCell)/))
+ call mpas_log_write("absorbedShortwaveFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/absorbedShortwaveFlux(iCell)/))
+ call mpas_log_write("longwaveUp: $r", messageType=MPAS_LOG_ERR, realArgs=(/longwaveUp(iCell)/))
+ do iCategory = 1, nCategories
+ call mpas_log_write("absorbedShortwaveSnowLayer: $i "//repeat("$r ", nSnowLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/absorbedShortwaveSnowLayer(:,iCategory,iCell)/))
+ enddo ! iCategory
+ do iCategory = 1, nCategories
+ call mpas_log_write("absorbedShortwaveIceLayer: $i "//repeat("$r ", nIceLayers), messageType=MPAS_LOG_ERR, intArgs=(/iCategory/), realArgs=(/absorbedShortwaveIceLayer(:,iCategory,iCell)/))
+ enddo ! iCategory
+ call mpas_log_write("longwaveDown: $r", messageType=MPAS_LOG_ERR, realArgs=(/longwaveDown(iCell)/))
+ call mpas_log_write("solarZenithAngleCosine: $r", messageType=MPAS_LOG_ERR, realArgs=(/solarZenithAngleCosine(iCell)/))
+ call mpas_log_write("sensibleHeatFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/sensibleHeatFlux(iCell)/))
+ call mpas_log_write("sensibleHeatFluxCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/sensibleHeatFluxCategory(:,iCell)/))
+ call mpas_log_write("latentHeatFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/latentHeatFlux(iCell)/))
+ call mpas_log_write("latentHeatFluxCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/latentHeatFluxCategory(:,iCell)/))
+ call mpas_log_write("evaporativeWaterFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/evaporativeWaterFlux(iCell)/))
+ call mpas_log_write("oceanFreshWaterFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanFreshWaterFlux(iCell)/))
+ call mpas_log_write("oceanSaltFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanSaltFlux(iCell)/))
+ call mpas_log_write("oceanHeatFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanHeatFlux(iCell)/))
+ call mpas_log_write("oceanShortwaveFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanShortwaveFlux(iCell)/))
+ call mpas_log_write("latentHeatFluxCouple: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/latentHeatFluxCouple(:,iCell)/))
+ call mpas_log_write("sensibleHeatFluxCouple: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/sensibleHeatFluxCouple(:,iCell)/))
+ call mpas_log_write("surfaceHeatFluxCouple: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceHeatFluxCouple(:,iCell)/))
+ call mpas_log_write("surfaceConductiveFluxCouple: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceConductiveFluxCouple(:,iCell)/))
+ call mpas_log_write("atmosAerosolFlux: "//repeat("$r ", nAerosols), messageType=MPAS_LOG_ERR, realArgs=(/atmosAerosolFlux(:,iCell)/))
+ call mpas_log_write("oceanAerosolFlux: "//repeat("$r ", nAerosols), messageType=MPAS_LOG_ERR, realArgs=(/oceanAerosolFlux(:,iCell)/))
+ call mpas_log_write("pondSnowDepthDifference: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/pondSnowDepthDifference(:,iCell)/))
+ call mpas_log_write("pondLidMeltFluxFraction: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/pondLidMeltFluxFraction(:,iCell)/))
+ call mpas_log_write("surfaceIceMelt: $r", messageType=MPAS_LOG_ERR, realArgs=(/surfaceIceMelt(iCell)/))
+ call mpas_log_write("surfaceIceMeltCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/surfaceIceMeltCategory(:,iCell)/))
+ call mpas_log_write("basalIceMelt: $r", messageType=MPAS_LOG_ERR, realArgs=(/basalIceMelt(iCell)/))
+ call mpas_log_write("basalIceMeltCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/basalIceMeltCategory(:,iCell)/))
+ call mpas_log_write("lateralIceMelt: $r", messageType=MPAS_LOG_ERR, realArgs=(/lateralIceMelt(iCell)/))
+ call mpas_log_write("snowMelt: $r", messageType=MPAS_LOG_ERR, realArgs=(/snowMelt(iCell)/))
+ call mpas_log_write("snowMeltCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/snowMeltCategory(:,iCell)/))
+ call mpas_log_write("snowMeltMassCell: $r", messageType=MPAS_LOG_ERR, realArgs=(/snowMeltMassCell(iCell)/))
+ call mpas_log_write("snowMeltMassCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/snowMeltMassCategory(:,iCell)/))
+ call mpas_log_write("congelation: $r", messageType=MPAS_LOG_ERR, realArgs=(/congelation(iCell)/))
+ call mpas_log_write("congelationCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/congelationCategory(:,iCell)/))
+ call mpas_log_write("snowiceFormation: $r", messageType=MPAS_LOG_ERR, realArgs=(/snowiceFormation(iCell)/))
+ call mpas_log_write("snowiceFormationCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/snowiceFormationCategory(:,iCell)/))
+ call mpas_log_write("snowThicknessChangeCategory: "//repeat("$r ", nCategories), messageType=MPAS_LOG_ERR, realArgs=(/snowThicknessChangeCategory(:,iCell)/))
+ call mpas_log_write("frazilFormation: $r", messageType=MPAS_LOG_ERR, realArgs=(/frazilFormation(iCell)/))
+ call mpas_log_write("northernHemisphereMask: $l", messageType=MPAS_LOG_ERR, logicArgs=(/northernHemisphereMask/))
+ call mpas_log_write("meltOnset: $r", messageType=MPAS_LOG_ERR, realArgs=(/meltOnset(iCell)/))
+ call mpas_log_write("freezeOnset: $r", messageType=MPAS_LOG_ERR, realArgs=(/freezeOnset(iCell)/))
+ call mpas_log_write("dayOfYear: $r", messageType=MPAS_LOG_ERR, realArgs=(/dayOfYear/))
+ call mpas_log_write("config_use_prescribed_ice: $l", messageType=MPAS_LOG_ERR, logicArgs=(/config_use_prescribed_ice/))
endif
! aerosol
@@ -1656,6 +2058,10 @@ subroutine column_vertical_thermodynamics(domain, clock, ierr)
enddo ! iCell
+ ! error-checking
+ call seaice_critical_error_write_block(domain, block, abortFlag)
+ call seaice_check_critical_error(domain, abortFlag)
+
! aerosols
deallocate(specificSnowAerosol)
deallocate(specificIceAerosol)
@@ -1677,19 +2083,16 @@ end subroutine column_vertical_thermodynamics
!
!-----------------------------------------------------------------------
- subroutine column_itd_thermodynamics(domain, clock, ierr)
+ subroutine column_itd_thermodynamics(domain, clock)
use ice_colpkg, only: &
colpkg_step_therm2, &
- colpkg_get_warnings, &
colpkg_clear_warnings
type(domain_type), intent(inout) :: domain
type(MPAS_clock_type), intent(in) :: clock
- integer, intent(inout) :: ierr
-
type(block_type), pointer :: block
type(MPAS_pool_type), pointer :: &
@@ -1722,7 +2125,8 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
nIceLayers, &
nSnowLayers, &
nAerosols, &
- nBioLayers
+ nBioLayers, &
+ nBioLayersP1
! variables
real(kind=RKIND), dimension(:), pointer :: &
@@ -1758,7 +2162,8 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
real(kind=RKIND), dimension(:,:,:), pointer :: &
iceAreaCategory, &
iceVolumeCategory, &
- snowVolumeCategory
+ snowVolumeCategory, &
+ brineFraction
integer, dimension(:,:), pointer :: &
newlyFormedIce
@@ -1771,18 +2176,33 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
iCell, &
iCategory, &
iBioTracers, &
- iBioData
+ iBioData, &
+ iBioLayers
- logical, dimension(:), allocatable :: &
- newlyFormedIceLogical
+ ! test carbon conservation
+ real(kind=RKIND), dimension(:), allocatable :: &
+ totalCarbonCatFinal, &
+ totalCarbonCatInitial, &
+ oceanBioFluxesTemp, &
+ verticalGridSpace
+
+ real(kind=RKIND) :: &
+ oceanCarbonFlux, &
+ totalCarbonFinal, &
+ totalCarbonInitial, &
+ carbonError
real(kind=RKIND), dimension(:), allocatable :: &
oceanBioConcentrationsUsed
+ logical, dimension(:), allocatable :: &
+ newlyFormedIceLogical
+
logical :: &
abortFlag, &
setGetPhysicsTracers, &
- setGetBGCTracers
+ setGetBGCTracers, &
+ checkCarbon
character(len=strKIND) :: &
abortMessage, &
@@ -1791,12 +2211,11 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
real(kind=RKIND) :: &
dayOfYear
- character(len=strKINDWarnings), dimension(:), allocatable :: &
- warnings
-
! day of year
call get_day_of_year(clock, dayOfYear)
+ checkCarbon = .false.
+
block => domain % blocklist
do while (associated(block))
@@ -1825,6 +2244,7 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
call MPAS_pool_get_dimension(mesh, "nAerosols", nAerosols)
call MPAS_pool_get_dimension(block % dimensions, "nBioLayers", nBioLayers)
+ call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP1", nBioLayersP1)
call MPAS_pool_get_array(mesh, "indexToCellID", indexToCellID)
call MPAS_pool_get_array(icestate, "iceAreaCategoryInitial", iceAreaCategoryInitial)
@@ -1836,6 +2256,7 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
call MPAS_pool_get_array(tracers, "iceAreaCategory", iceAreaCategory, 1)
call MPAS_pool_get_array(tracers, "iceVolumeCategory", iceVolumeCategory, 1)
call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
+ call MPAS_pool_get_array(tracers, "brineFraction", brineFraction, 1)
call MPAS_pool_get_array(atmos_coupling, "rainfallRate", rainfallRate)
@@ -1872,10 +2293,28 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
! newly formed ice
allocate(newlyFormedIceLogical(nCategories))
allocate(oceanBioConcentrationsUsed(ciceTracerObject % nBioTracers))
+ allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers))
+ allocate(verticalGridSpace(nBioLayersP1))
+ if (checkCarbon) then
+ allocate(totalCarbonCatFinal(nCategories))
+ allocate(totalCarbonCatInitial(nCategories))
+ endif
+
+ verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND)
+ verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND
+ verticalGridSpace(nBioLayersP1) = verticalGridSpace(1)
setGetPhysicsTracers = .true.
setGetBGCTracers = config_use_column_biogeochemistry
+ ! code abort
+ abortFlag = .false.
+ abortMessage = ""
+
+ !$omp parallel do default(shared) private(iCategory,iBioTracers,iBioData,&
+ !$omp& totalCarbonInitial,abortMessage,oceanBioFluxesTemp,totalCarbonFinal,&
+ !$omp& carbonError) firstprivate(newlyFormedIceLogical,oceanBioConcentrationsUsed) &
+ !$omp& reduction(.or.:abortFlag)
do iCell = 1, nCellsSolve
! newly formed ice
@@ -1890,33 +2329,41 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
enddo ! iBioTracers
! set the category tracer array
- call set_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call set_cice_tracer_array_category(block, ciceTracerObject,&
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
+
+ if (checkCarbon) then
+ totalCarbonInitial = 0.0_RKIND
+ call seaice_total_carbon_content_category(block,totalCarbonCatInitial,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell)
+ do iCategory = 1,nCategories
+ totalCarbonInitial = totalCarbonInitial + totalCarbonCatInitial(iCategory)*iceAreaCategory(1,iCategory,iCell)
+ enddo
+ endif
- abortFlag = .false.
- abortMessage = ""
+ oceanBioFluxesTemp(:) = 0.0_RKIND
call colpkg_clear_warnings()
call colpkg_step_therm2(&
config_dt, &
nCategories, &
nAerosols, &
- ciceTracerObject % nBioTracersLayer, &
+ ciceTracerObject % nBioTracers, & !nbtrcr, intent(in)
nIcelayers, &
nSnowLayers, &
- categoryThicknessLimits(:), &
+ categoryThicknessLimits(:), & !hin_max, intent(inout), dimension(0:ncat)
nBioLayers, &
iceAreaCategory(1,:,iCell), &
iceVolumeCategory(1,:,iCell), &
snowVolumeCategory(1,:,iCell), &
iceAreaCategoryInitial(:,iCell), &
iceVolumeCategoryInitial(:,iCell), &
- ciceTracerObject % tracerArrayCategory, & !trcrn
+ tracerArrayCategory, & !trcrn, intent(inout)
openWaterArea(iCell), &
iceAreaCell(iCell), &
- ciceTracerObject % parentIndex, & !trcr_depend
- ciceTracerObject % firstAncestorMask, & !trcr_base
- ciceTracerObject % ancestorNumber, & !n_trcr_strata
- ciceTracerObject % ancestorIndices, & !nt_strata
+ ciceTracerObject % parentIndex, & !trcr_depend, intent(in)
+ ciceTracerObject % firstAncestorMask, & !trcr_base, intent(in)
+ ciceTracerObject % ancestorNumber, & !n_trcr_strata,intent(in)
+ ciceTracerObject % ancestorIndices, & !nt_strata, intent(in)
seaFreezingTemperature(iCell), &
seaSurfaceSalinity(iCell), &
initialSalinityProfile(:,iCell), &
@@ -1929,22 +2376,26 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
oceanFreshWaterFlux(iCell), &
oceanSaltFlux(iCell), &
oceanHeatFlux(iCell), &
- config_update_ocean_fluxes, &
- biologyGrid(:), &
- verticalGrid(:), &
- interfaceBiologyGrid(:), &
+ config_update_ocean_fluxes, & !update_ocn_f, intent(in)
+ biologyGrid(:), & !bgrid, intent(in)
+ verticalGrid(:), & !cgrid, intent(in)
+ interfaceBiologyGrid(:), & !igrid, intent(in)
oceanAerosolFlux(:,iCell), &
- newlyFormedIceLogical(:), &
+ newlyFormedIceLogical(:), & !first_ice, intent(inout)
zSalinityFlux(iCell), &
- oceanBioFluxes(:,iCell), &
- oceanBioConcentrationsUsed(:), &
+ oceanBioFluxesTemp(:), &
+ oceanBioConcentrationsUsed(:), & !ocean_bio, intent(in)
abortFlag, &
abortMessage, &
frazilGrowthDiagnostic(iCell), &
freezeOnset(iCell), &
dayOfYear)
- call colpkg_get_warnings(warnings)
- call column_write_warnings(warnings)
+
+ do iBioTracers = 1, ciceTracerObject % nBioTracers
+ oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers)
+ enddo
+
+ call column_write_warnings(abortFlag)
! update
do iCategory = 1, nCategories
@@ -1953,22 +2404,56 @@ subroutine column_itd_thermodynamics(domain, clock, ierr)
enddo ! iCategory
! get category tracer array
- call get_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call get_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
+
+ if (checkCarbon) then
+ totalCarbonFinal = 0.0_RKIND
+ call seaice_total_carbon_content_category(block,totalCarbonCatFinal,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell)
+ call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxesTemp,iCell)
+ do iCategory = 1,nCategories
+ totalCarbonFinal = totalCarbonFinal + totalCarbonCatFinal(iCategory)*iceAreaCategory(1,iCategory,iCell)
+ enddo
+ carbonError = totalCarbonInitial - oceanCarbonFlux*config_dt - totalCarbonFinal
+
+ if (abs(carbonError) > 1.0e-14_RKIND*MAXVAL((/totalCarbonInitial,totalCarbonFinal/))) then
+ call mpas_log_write("column_step_therm2, carbon conservation error", messageType=MPAS_LOG_ERR)
+ call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
+ call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError/))
+ call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial/))
+ call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal/))
+ call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux/))
+
+ do iCategory = 1, nCategories
+ call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/))
+ call mpas_log_write("totalCarbonCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/))
+ call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/))
+ enddo
+ endif
+ endif
- ! code abort
+ ! cell-specific abort message
if (abortFlag) then
call mpas_log_write("column_itd_thermodynamics: "//trim(abortMessage) , messageType=MPAS_LOG_ERR)
call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
- ierr = SEAICE_ERROR_COL_ITD_THERM
- call seaice_critical_error_write_block(domain, block)
- return
endif
enddo ! iCell
+ ! error checking
+ call seaice_critical_error_write_block(domain, block, abortFlag)
+ call seaice_check_critical_error(domain, abortFlag)
+
+ if (checkCarbon) then
+ deallocate(totalCarbonCatFinal)
+ deallocate(totalCarbonCatInitial)
+ endif
+
! newly formed ice
deallocate(newlyFormedIceLogical)
deallocate(oceanBioConcentrationsUsed)
+ deallocate(oceanBioFluxesTemp)
+ deallocate(verticalGridSpace)
block => block % next
end do
@@ -2105,84 +2590,332 @@ end subroutine column_prep_radiation
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
-! column_radiation
+! column_snow
!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 21th January 2015
+!> \brief Enable snow grain aging, effective snow density, wind compaction and redistribution
+!>
+!> \author Nicole Jeffery, LANL
+!> \date 3rd April 2017
!> \details
!>
+!> Snow physics improvements include:
+!> 1) Snow redistribution by wind (multiple options available).
+!> Includes parametrizations for snow compaction, redistribution among categories/level ice
+!> and loss to leads.
+!> 2) Tracking of snow liquid and ice content. Liquid is stored in snow before passing to ponds.
+!> Effective snow density is also tracked.
+!> 3) Snow grain radius aging based on wet (liquid content) and dry (temperature gradient) metamorphism.
+!> 4) Effective snow density (based on snow liquid/ice content and compaction)
!
!-----------------------------------------------------------------------
- subroutine column_radiation(domain, clock, lInitialization)
+ subroutine column_snow(domain)
use ice_colpkg, only: &
- colpkg_step_radiation, &
- colpkg_get_warnings, &
- colpkg_clear_warnings
+ colpkg_step_snow, &
+ colpkg_clear_warnings, &
+ colpkg_get_warnings
use seaice_constants, only: &
- pii
+ seaicePuny
type(domain_type), intent(inout) :: domain
- type(MPAS_clock_type), intent(in) :: clock
-
- logical, intent(in) :: &
- lInitialization
-
type(block_type), pointer :: block
type(MPAS_pool_type), pointer :: &
mesh, &
tracers, &
- atmos_coupling, &
- shortwave, &
- ponds, &
- aerosols, &
- biogeochemistry
-
- ! configs
- real(kind=RKIND), pointer :: &
- config_dt
+ tracers_aggregate, &
+ atmos_forcing, &
+ snow, &
+ ocean_fluxes, &
+ atmos_coupling
logical, pointer :: &
- config_use_shortwave_bioabsorption, &
- config_use_brine, &
- config_use_modal_aerosols, &
- config_use_zaerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius, &
config_use_column_biogeochemistry
- ! dimensions
- integer, pointer :: &
- nCellsSolve, &
- nCategories, &
- nIceLayers, &
- nSnowLayers, &
- nAerosols, &
- nAlgae, &
- nBioLayers, &
- nzAerosols, &
- maxAerosolType
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ snowIceMass, &
+ snowLiquidMass, &
+ snowDensity, &
+ snowVolumeCategory, &
+ iceAreaCategory, &
+ iceVolumeCategory, &
+ levelIceArea, &
+ levelIceVolume, &
+ iceEnthalpy, &
+ snowEnthalpy, &
+ iceSalinity, &
+ surfaceTemperature, &
+ snowGrainRadius, &
+ snowEmpiricalGrowthParameterTau, &
+ snowEmpiricalGrowthParameterKappa, &
+ snowPropertyRate
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ snowMeltMassCategory
- ! variables
real(kind=RKIND), dimension(:), pointer :: &
- latCell, &
- lonCell, &
- shortwaveVisibleDirectDown, &
- shortwaveVisibleDiffuseDown, &
- shortwaveIRDirectDown, &
- shortwaveIRDiffuseDown, &
- solarZenithAngleCosine, &
+ windSpeed, &
+ oceanFreshWaterFlux, &
+ oceanHeatFlux, &
+ snowLossToLeads, &
snowfallRate, &
- verticalShortwaveGrid, &
- verticalGrid
+ iceAreaCell, &
+ iceVolumeCell, &
+ snowVolumeCell, &
+ snowDensityViaContent, &
+ snowDensityViaCompaction, &
+ snowMeltMassCell
- real(kind=RKIND), dimension(:,:), pointer :: &
- surfaceShortwaveFlux, &
- interiorShortwaveFlux, &
- penetratingShortwaveFlux, &
+ real(kind=RKIND), pointer :: &
+ config_dt, &
+ config_new_snow_density, &
+ config_max_snow_density, &
+ config_minimum_wind_compaction, &
+ config_wind_compaction_factor
+
+ integer, pointer :: &
+ nCellsSolve, &
+ nSnowLayers, &
+ nIceLayers, &
+ nCategories, &
+ nGrainAgingTemperature, &
+ nGrainAgingTempGradient, &
+ nGrainAgingSnowDensity
+
+ integer :: &
+ iCell, &
+ iSnowLayer, &
+ iIceLayer, &
+ iCategory
+
+ logical :: &
+ abortFlag, &
+ setGetPhysicsTracers, &
+ setGetBGCTracers
+
+ real(kind=RKIND), dimension(:,:), allocatable :: &
+ effectiveSnowDensityCategory
+
+ character(len=strKIND) :: &
+ abortMessage, &
+ abortLocation
+
+ character(len=strKINDWarnings), dimension(:), allocatable :: &
+ warnings
+
+ block => domain % blocklist
+ do while (associated(block))
+
+ call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
+ call MPAS_pool_get_subpool(block % structs, "tracers", tracers)
+ call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracers_aggregate)
+ call MPAS_pool_get_subpool(block % structs, "snow", snow)
+ call MPAS_pool_get_subpool(block % structs, "atmos_forcing", atmos_forcing)
+ call MPAS_pool_get_subpool(block % structs, "ocean_fluxes", ocean_fluxes)
+ call MPAS_pool_get_subpool(block % structs, "atmos_coupling", atmos_coupling)
+
+ call MPAS_pool_get_config(block % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
+ call MPAS_pool_get_config(block % configs, "config_dt", config_dt)
+ call MPAS_pool_get_config(block % configs, "config_new_snow_density", config_new_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_max_snow_density", config_max_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_minimum_wind_compaction", config_minimum_wind_compaction)
+ call MPAS_pool_get_config(block % configs, "config_wind_compaction_factor", config_wind_compaction_factor)
+ call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+
+ call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve)
+ call MPAS_pool_get_dimension(block % dimensions, "nCategories", nCategories)
+ call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers)
+ call MPAS_pool_get_dimension(block % dimensions, "nIceLayers", nIceLayers)
+ call MPAS_pool_get_dimension(block % dimensions, "nGrainAgingTemperature", nGrainAgingTemperature)
+ call MPAS_pool_get_dimension(block % dimensions, "nGrainAgingTempGradient", nGrainAgingTempGradient)
+ call MPAS_pool_get_dimension(block % dimensions, "nGrainAgingSnowDensity", nGrainAgingSnowDensity)
+
+ call MPAS_pool_get_array(snow, "snowDensityViaContent", snowDensityViaContent)
+ call MPAS_pool_get_array(snow, "snowDensityViaCompaction", snowDensityViaCompaction)
+ call MPAS_pool_get_array(snow, "snowMeltMassCategory", snowMeltMassCategory)
+ call MPAS_pool_get_array(snow, "snowMeltMassCell", snowMeltMassCell)
+ call MPAS_pool_get_array(snow, "snowLossToLeads", snowLossToLeads)
+ call MPAS_pool_get_array(snow, "snowEmpiricalGrowthParameterTau", snowEmpiricalGrowthParameterTau)
+ call MPAS_pool_get_array(snow, "snowEmpiricalGrowthParameterKappa", snowEmpiricalGrowthParameterKappa)
+ call MPAS_pool_get_array(snow, "snowPropertyRate", snowPropertyRate)
+
+ call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
+ call MPAS_pool_get_array(tracers, "iceVolumeCategory", iceVolumeCategory, 1)
+ call MPAS_pool_get_array(tracers, "iceAreaCategory", iceAreaCategory, 1)
+ call MPAS_pool_get_array(tracers, "snowIceMass", snowIceMass, 1)
+ call MPAS_pool_get_array(tracers, "snowLiquidMass", snowLiquidMass, 1)
+ call MPAS_pool_get_array(tracers, "snowDensity", snowDensity, 1)
+ call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1)
+ call MPAS_pool_get_array(tracers, "levelIceArea", levelIceArea, 1)
+ call MPAS_pool_get_array(tracers, "levelIceVolume", levelIceVolume, 1)
+ call MPAS_pool_get_array(tracers, "iceEnthalpy", iceEnthalpy, 1)
+ call MPAS_pool_get_array(tracers, "snowEnthalpy", snowEnthalpy, 1)
+ call MPAS_pool_get_array(tracers, "iceSalinity", iceSalinity, 1)
+ call MPAS_pool_get_array(tracers, "surfaceTemperature", surfaceTemperature, 1)
+
+ call MPAS_pool_get_array(tracers_aggregate, "iceAreaCell", iceAreaCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowVolumeCell", snowVolumeCell)
+
+ call MPAS_pool_get_array(atmos_coupling, "snowfallRate", snowfallRate)
+
+ call MPAS_pool_get_array(atmos_forcing, "windSpeed", windSpeed)
+
+ call MPAS_pool_get_array(ocean_fluxes, "oceanFreshWaterFlux", oceanFreshWaterFlux)
+ call MPAS_pool_get_array(ocean_fluxes, "oceanHeatFlux", oceanHeatFlux)
+
+ setGetPhysicsTracers = .true.
+ setGetBGCTracers = config_use_column_biogeochemistry
+
+ allocate(effectiveSnowDensityCategory(1:nSnowLayers,1:nCategories))
+
+ do iCell = 1, nCellsSolve
+
+ effectiveSnowDensityCategory(:,:) = 0.0_RKIND
+
+ abortFlag = .false.
+ abortMessage = ""
+
+ call colpkg_clear_warnings()
+ call colpkg_step_snow (&
+ config_dt, &
+ windSpeed(iCell), &
+ nIceLayers, &
+ nSnowLayers, &
+ nCategories, &
+ iceAreaCell(iCell), &
+ iceAreaCategory(1,:,iCell), &
+ iceVolumeCategory(1,:,iCell), &
+ snowVolumeCategory(1,:,iCell), &
+ levelIceArea(1,:,iCell), &
+ levelIceVolume(1,:,iCell), &
+ snowIceMass(:,:,iCell), &
+ snowLiquidMass(:,:,iCell), &
+ effectiveSnowDensityCategory(:,:), &
+ snowDensityViaContent(iCell), &
+ snowDensity(:,:,iCell), &
+ snowDensityViaCompaction(iCell), &
+ snowGrainRadius(:,:,iCell), &
+ iceEnthalpy(1,:,iCell), &
+ iceSalinity(1,:,iCell), &
+ surfaceTemperature(1,:,iCell), &
+ snowEnthalpy(:,:,iCell), &
+ oceanFreshWaterFlux(iCell), &
+ oceanHeatFlux(iCell), &
+ snowLossToLeads(iCell), &
+ snowfallRate(iCell), &
+ config_new_snow_density, &
+ config_max_snow_density, &
+ config_minimum_wind_compaction, &
+ config_wind_compaction_factor, &
+ snowEmpiricalGrowthParameterTau(:,:,:), &
+ snowEmpiricalGrowthParameterKappa(:,:,:), &
+ snowPropertyRate(:,:,:), &
+ nGrainAgingTemperature, &
+ nGrainAgingTempGradient, &
+ nGrainAgingSnowDensity, &
+ abortFlag, &
+ abortMessage)
+
+ call column_write_warnings(abortFlag)
+
+ enddo !iCell
+
+ deallocate(effectiveSnowDensityCategory)
+
+ block => block % next
+ end do
+
+ end subroutine column_snow
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! column_radiation
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 21th January 2015
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine column_radiation(domain, clock, lInitialization)
+
+ use ice_colpkg, only: &
+ colpkg_step_radiation, &
+ colpkg_clear_warnings
+
+ use seaice_constants, only: &
+ pii
+
+ type(domain_type), intent(inout) :: domain
+
+ type(MPAS_clock_type), intent(in) :: clock
+
+ logical, intent(in) :: &
+ lInitialization
+
+ type(block_type), pointer :: block
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ tracers, &
+ atmos_coupling, &
+ shortwave, &
+ ponds, &
+ aerosols, &
+ biogeochemistry, &
+ snicar, &
+ snow
+
+ ! configs
+ real(kind=RKIND), pointer :: &
+ config_dt
+
+ logical, pointer :: &
+ config_use_shortwave_bioabsorption, &
+ config_use_brine, &
+ config_use_modal_aerosols, &
+ config_use_column_biogeochemistry
+
+ character(len=strKIND), pointer :: &
+ config_snow_redistribution_scheme
+
+ ! dimensions
+ integer, pointer :: &
+ nCellsSolve, &
+ nCategories, &
+ nIceLayers, &
+ nSnowLayers, &
+ nAerosols, &
+ nAlgae, &
+ nBioLayers, &
+ nzAerosols, &
+ maxAerosolType
+
+ ! variables
+ real(kind=RKIND), dimension(:), pointer :: &
+ latCell, &
+ lonCell, &
+ shortwaveVisibleDirectDown, &
+ shortwaveVisibleDiffuseDown, &
+ shortwaveIRDirectDown, &
+ shortwaveIRDiffuseDown, &
+ solarZenithAngleCosine, &
+ snowfallRate, &
+ verticalShortwaveGrid, &
+ verticalGrid
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ surfaceShortwaveFlux, &
+ interiorShortwaveFlux, &
+ penetratingShortwaveFlux, &
bareIceAlbedoCategory, &
snowAlbedoCategory, &
pondAlbedoCategory, &
@@ -2199,7 +2932,20 @@ subroutine column_radiation(domain, clock, lInitialization)
albedoVisibleDiffuseCategory, &
albedoIRDirectCategory, &
albedoIRDiffuseCategory, &
- snowFractionCategory
+ snowFractionCategory, &
+ iceAsymmetryParameterDirect, &
+ iceAsymmetryParameterDiffuse, &
+ iceSingleScatterAlbedoDirect, &
+ iceSingleScatterAlbedoDiffuse, &
+ iceMassExtinctionCrossSectionDirect, &
+ iceMassExtinctionCrossSectionDiffuse, &
+ aerosolAsymmetryParameter5band, &
+ aerosolMassExtinctionCrossSection5band, &
+ aerosolSingleScatterAlbedo5band, &
+ modalAsymmetryParameter5band, &
+ modalMassExtinctionCrossSection5band, &
+ modalSingleScatterAlbedo5band, &
+ snowRadiusInStandardRadiationSchemeCategory
real(kind=RKIND), dimension(:,:,:), pointer :: &
iceAreaCategory, &
@@ -2219,7 +2965,9 @@ subroutine column_radiation(domain, clock, lInitialization)
iceBodyAerosol, &
brineFraction, &
modalBCabsorptionParameter, &
- bioTracerShortwave
+ bioTracerShortwave, &
+ modalBCabsorptionParameter5band, &
+ snowGrainRadius
real(kind=RKIND), pointer :: &
dayOfNextShortwaveCalculation ! needed for CESM like coupled simulations
@@ -2256,9 +3004,6 @@ subroutine column_radiation(domain, clock, lInitialization)
setGetPhysicsTracers, &
setGetBGCTracers
- character(len=strKINDWarnings), dimension(:), allocatable :: &
- warnings
-
! day of year
call get_day_of_year(clock, dayOfYear)
@@ -2271,7 +3016,6 @@ subroutine column_radiation(domain, clock, lInitialization)
call MPAS_pool_get_config(domain % configs, "config_use_brine", config_use_brine)
call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption)
call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols",config_use_modal_aerosols)
- call MPAS_pool_get_config(domain % configs, "config_use_zaerosols",config_use_zaerosols)
call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry",config_use_column_biogeochemistry)
block => domain % blocklist
@@ -2284,8 +3028,11 @@ subroutine column_radiation(domain, clock, lInitialization)
call MPAS_pool_get_subpool(block % structs, "ponds", ponds)
call MPAS_pool_get_subpool(block % structs, "aerosols", aerosols)
call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry)
+ call MPAS_pool_get_subpool(block % structs, "snicar", snicar)
+ call MPAS_pool_get_subpool(block % structs, "snow", snow)
call MPAS_pool_get_config(block % configs, "config_dt", config_dt)
+ call MPAS_pool_get_config(block % configs, "config_snow_redistribution_scheme", config_snow_redistribution_scheme)
call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve)
call MPAS_pool_get_dimension(mesh, "nCategories", nCategories)
@@ -2313,6 +3060,7 @@ subroutine column_radiation(domain, clock, lInitialization)
call MPAS_pool_get_array(tracers, "iceScatteringAerosol", iceScatteringAerosol, 1)
call MPAS_pool_get_array(tracers, "iceBodyAerosol", iceBodyAerosol, 1)
call MPAS_pool_get_array(tracers, "brineFraction", brineFraction, 1)
+ call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1)
call MPAS_pool_get_array(atmos_coupling, "shortwaveVisibleDirectDown", shortwaveVisibleDirectDown)
call MPAS_pool_get_array(atmos_coupling, "shortwaveVisibleDiffuseDown", shortwaveVisibleDiffuseDown)
@@ -2353,6 +3101,23 @@ subroutine column_radiation(domain, clock, lInitialization)
call MPAS_pool_get_array(biogeochemistry, "verticalShortwaveGrid", verticalShortwaveGrid)
call MPAS_pool_get_array(biogeochemistry, "verticalGrid", verticalGrid)
+ ! snicar 5-band snow IOPs
+ call MPAS_pool_get_array(snicar, "iceAsymmetryParameterDirect", iceAsymmetryParameterDirect)
+ call MPAS_pool_get_array(snicar, "iceAsymmetryParameterDiffuse", iceAsymmetryParameterDiffuse)
+ call MPAS_pool_get_array(snicar, "iceSingleScatterAlbedoDirect", iceSingleScatterAlbedoDirect)
+ call MPAS_pool_get_array(snicar, "iceSingleScatterAlbedoDiffuse", iceSingleScatterAlbedoDiffuse)
+ call MPAS_pool_get_array(snicar, "iceMassExtinctionCrossSectionDirect", iceMassExtinctionCrossSectionDirect)
+ call MPAS_pool_get_array(snicar, "iceMassExtinctionCrossSectionDiffuse", iceMassExtinctionCrossSectionDiffuse)
+ call MPAS_pool_get_array(snicar, "aerosolMassExtinctionCrossSection5band", aerosolMassExtinctionCrossSection5band)
+ call MPAS_pool_get_array(snicar, "aerosolSingleScatterAlbedo5band", aerosolSingleScatterAlbedo5band)
+ call MPAS_pool_get_array(snicar, "aerosolAsymmetryParameter5band", aerosolAsymmetryParameter5band)
+ call MPAS_pool_get_array(snicar, "modalMassExtinctionCrossSection5band", modalMassExtinctionCrossSection5band)
+ call MPAS_pool_get_array(snicar, "modalSingleScatterAlbedo5band", modalSingleScatterAlbedo5band)
+ call MPAS_pool_get_array(snicar, "modalAsymmetryParameter5band", modalAsymmetryParameter5band)
+ call MPAS_pool_get_array(snicar, "modalBCabsorptionParameter5band", modalBCabsorptionParameter5band)
+
+ call MPAS_pool_get_array(snow, "snowRadiusInStandardRadiationSchemeCategory", snowRadiusInStandardRadiationSchemeCategory)
+
! calendar type
call MPAS_pool_get_config(block % configs, "config_calendar_type", config_calendar_type)
if (trim(config_calendar_type) == "gregorian") then
@@ -2364,6 +3129,7 @@ subroutine column_radiation(domain, clock, lInitialization)
! aerosols array
allocate(aerosolsArray(4*nAerosols,nCategories))
allocate(index_shortwaveAerosol(maxAerosolType))
+
if (.not. config_use_column_biogeochemistry) then
index_shortwaveAerosol(1:maxAerosolType) = 1
else
@@ -2375,6 +3141,8 @@ subroutine column_radiation(domain, clock, lInitialization)
setGetPhysicsTracers = .true.
setGetBGCTracers = config_use_column_biogeochemistry
+ !$omp parallel do default(shared) firstprivate(aerosolsArray,index_shortwaveAerosol) &
+ !$omp& private(iCategory,iAerosol,lonCellColumn)
do iCell = 1, nCellsSolve
! set aerosols array
@@ -2393,14 +3161,14 @@ subroutine column_radiation(domain, clock, lInitialization)
if (lonCellColumn > pii) lonCellColumn = lonCellColumn - 2.0_RKIND * pii
! set the category tracer array
- call set_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call set_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
call colpkg_clear_warnings()
call colpkg_step_radiation(&
config_dt, &
nCategories, &
nAlgae, &
- config_use_zaerosols, &
nBioLayers, &
ciceTracerObject % nTracers, &
ciceTracerObject % nBioTracers, &
@@ -2411,9 +3179,9 @@ subroutine column_radiation(domain, clock, lInitialization)
nzAerosols, &
config_use_shortwave_bioabsorption, &
ciceTracerObject % index_chlorophyllShortwave, &
- index_shortwaveAerosol, &
- verticalShortwaveGrid(:), &
- verticalGrid(:), &
+ index_shortwaveAerosol, & ! nlt_zaero_sw, dimension(:), intent(in)
+ verticalShortwaveGrid(:), & ! swgrid, dimension (:), intent(in)
+ verticalGrid(:), & ! igrid, dimension (:), intent(in)
brineFraction(1,:,iCell), &
iceAreaCategory(1,:,iCell), &
iceVolumeCategory(1,:,iCell), &
@@ -2423,9 +3191,11 @@ subroutine column_radiation(domain, clock, lInitialization)
pondArea(1,:,iCell), &
pondDepth(1,:,iCell), &
pondLidThickness(1,:,iCell), &
+ config_snow_redistribution_scheme, &
+ snowGrainRadius(:,:,iCell), &
aerosolsArray, &
bioTracerShortwave(:,:,iCell), &
- ciceTracerObject % tracerArrayCategory(:,:), &
+ tracerArrayCategory, & ! trcrn, dimension(:,:), intent(in)
latCell(iCell), &
lonCellColumn, &
calendarType, &
@@ -2433,13 +3203,13 @@ subroutine column_radiation(domain, clock, lInitialization)
dayOfNextShortwaveCalculation, &
dayOfYear, &
secondsIntoDay, &
- aerosolMassExtinctionCrossSection(:,:), &
- aerosolSingleScatterAlbedo(:,:), &
- aerosolAsymmetryParameter(:,:), &
- modalMassExtinctionCrossSection(:,:), &
- modalSingleScatterAlbedo(:,:), &
- modalAsymmetryParameter(:,:), &
- modalBCabsorptionParameter(:,:,:), &
+ aerosolMassExtinctionCrossSection(:,:), & ! kaer_tab, dimension(:,:), intent(in)
+ aerosolSingleScatterAlbedo(:,:), & ! waer_tab, dimension(:,:), intent(in)
+ aerosolAsymmetryParameter(:,:), & ! gaer_tab, dimension(:,:), intent(in)
+ modalMassExtinctionCrossSection(:,:), & ! kaer_bc_tab, dimension(:,:), intent(in)
+ modalSingleScatterAlbedo(:,:), & ! waer_bc_tab, dimension(:,:), intent(in)
+ modalAsymmetryParameter(:,:), & ! gaer_bc_tab, dimension(:,:), intent(in)
+ modalBCabsorptionParameter(:,:,:), & ! bcenh, dimension(:,:,:), intent(in)
config_use_modal_aerosols, &
shortwaveVisibleDirectDown(iCell), &
shortwaveVisibleDiffuseDown(iCell), &
@@ -2465,12 +3235,27 @@ subroutine column_radiation(domain, clock, lInitialization)
pondSnowDepthDifference(:,iCell), &
pondLidMeltFluxFraction(:,iCell), &
.false., &
- lInitialization)
- call colpkg_get_warnings(warnings)
- call column_write_warnings(warnings)
+ lInitialization, &
+ iceAsymmetryParameterDirect(:,:), &
+ iceAsymmetryParameterDiffuse(:,:), &
+ iceSingleScatterAlbedoDirect(:,:), &
+ iceSingleScatterAlbedoDiffuse(:,:), &
+ iceMassExtinctionCrossSectionDirect(:,:), &
+ iceMassExtinctionCrossSectionDiffuse(:,:), &
+ aerosolMassExtinctionCrossSection5band(:,:), &
+ aerosolSingleScatterAlbedo5band(:,:), &
+ aerosolAsymmetryParameter5band(:,:), &
+ modalMassExtinctionCrossSection5band(:,:), &
+ modalSingleScatterAlbedo5band(:,:), &
+ modalAsymmetryParameter5band(:,:), &
+ modalBCabsorptionParameter5band(:,:,:), &
+ snowRadiusInStandardRadiationSchemeCategory(:,iCell))
+
+ call column_write_warnings(.false.)
! set the category tracer array
- call get_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call get_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
enddo ! iCell
@@ -2495,17 +3280,14 @@ end subroutine column_radiation
!
!-----------------------------------------------------------------------
- subroutine column_ridging(domain, ierr)
+ subroutine column_ridging(domain)
use ice_colpkg, only: &
colpkg_step_ridge, &
- colpkg_get_warnings, &
colpkg_clear_warnings
type(domain_type), intent(inout) :: domain
- integer, intent(inout) :: ierr
-
type(block_type), pointer :: block
type(MPAS_pool_type), pointer :: &
@@ -2515,6 +3297,7 @@ subroutine column_ridging(domain, ierr)
tracers_aggregate, &
ponds, &
ocean_fluxes, &
+ ocean_coupling, &
ridging, &
aerosols, &
biogeochemistry, &
@@ -2546,6 +3329,7 @@ subroutine column_ridging(domain, ierr)
oceanFreshWaterFlux, &
oceanSaltFlux, &
oceanHeatFlux, &
+ seaFreezingTemperature, &
iceAreaCell, &
ridgeConvergence, &
ridgeShear, &
@@ -2601,9 +3385,6 @@ subroutine column_ridging(domain, ierr)
abortMessage, &
abortLocation
- character(len=strKINDWarnings), dimension(:), allocatable :: &
- warnings
-
block => domain % blocklist
do while (associated(block))
@@ -2618,6 +3399,7 @@ subroutine column_ridging(domain, ierr)
call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry)
call MPAS_pool_get_subpool(block % structs, "initial", initial)
call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocity_solver)
+ call MPAS_pool_get_subpool(block % structs, "ocean_coupling", ocean_coupling)
call MPAS_pool_get_config(block % configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number)
call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
@@ -2641,6 +3423,8 @@ subroutine column_ridging(domain, ierr)
call MPAS_pool_get_array(tracers, "iceVolumeCategory", iceVolumeCategory, 1)
call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
+ call MPAS_pool_get_array(ocean_coupling, "seaFreezingTemperature", seaFreezingTemperature)
+
call MPAS_pool_get_array(ocean_fluxes, "oceanFreshWaterFlux", oceanFreshWaterFlux)
call MPAS_pool_get_array(ocean_fluxes, "oceanSaltFlux", oceanSaltFlux)
call MPAS_pool_get_array(ocean_fluxes, "oceanHeatFlux", oceanHeatFlux)
@@ -2677,6 +3461,10 @@ subroutine column_ridging(domain, ierr)
setGetPhysicsTracers = .true.
setGetBGCTracers = config_use_column_biogeochemistry
+ ! code abort
+ abortFlag = .false.
+ abortMessage = ""
+
do iCell = 1, nCellsSolve
! newly formed ice
@@ -2685,10 +3473,8 @@ subroutine column_ridging(domain, ierr)
enddo ! iCategory
! set the category tracer array
- call set_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
-
- abortFlag = .false.
- abortMessage = ""
+ call set_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
call colpkg_clear_warnings()
call colpkg_step_ridge(&
@@ -2698,11 +3484,12 @@ subroutine column_ridging(domain, ierr)
nSnowLayers, &
nBioLayers, &
nCategories, &
- categoryThicknessLimits, &
+ categoryThicknessLimits, & ! hin_max, dimension(0:ncat), intent(inout)
ridgeConvergence(iCell), &
ridgeShear(iCell), &
+ seaFreezingTemperature(iCell), &
iceAreaCategory(1,:,iCell), &
- ciceTracerObject % tracerArrayCategory, & ! trcrn
+ tracerArrayCategory, & ! trcrn, dimension(:,:), intent(inout)
iceVolumeCategory(1,:,iCell), &
snowVolumeCategory(1,:,iCell), &
openWaterArea(iCell), &
@@ -2735,8 +3522,7 @@ subroutine column_ridging(domain, ierr)
oceanBioFluxes(:,iCell), &
abortFlag, &
abortMessage)
- call colpkg_get_warnings(warnings)
- call column_write_warnings(warnings)
+ call column_write_warnings(abortFlag)
! update
do iCategory = 1, nCategories
@@ -2745,19 +3531,22 @@ subroutine column_ridging(domain, ierr)
enddo ! iCategory
! get category tracer array
- call get_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call get_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
! code abort
- if (abortFlag) then
- call mpas_log_write("column_ridging: "//trim(abortMessage) , messageType=MPAS_LOG_ERR)
- call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
- ierr = SEAICE_ERROR_COL_RIDGING
- call seaice_critical_error_write_block(domain, block)
- return
- endif
+ if (abortFlag) exit
enddo ! iCell
+ ! code abort
+ if (abortFlag) then
+ call mpas_log_write("column_ridging: "//trim(abortMessage) , messageType=MPAS_LOG_ERR)
+ call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
+ endif
+ call seaice_critical_error_write_block(domain, block, abortFlag)
+ call seaice_check_critical_error(domain, abortFlag)
+
! newly formed ice
deallocate(newlyFormedIceLogical)
@@ -2778,12 +3567,11 @@ end subroutine column_ridging
!
!-----------------------------------------------------------------------
- subroutine column_biogeochemistry(domain, ierr)
+ subroutine column_biogeochemistry(domain)
use ice_colpkg, only: &
colpkg_biogeochemistry, &
colpkg_init_OceanConcArray, &
- colpkg_get_warnings, &
colpkg_clear_warnings
use seaice_constants, only: &
@@ -2791,8 +3579,6 @@ subroutine column_biogeochemistry(domain, ierr)
type(domain_type), intent(inout) :: domain
- integer, intent(inout) :: ierr
-
type(block_type), pointer :: block
type(MPAS_pool_type), pointer :: &
@@ -2858,6 +3644,7 @@ subroutine column_biogeochemistry(domain, ierr)
verticalGrid, &
seaSurfaceTemperature, &
seaSurfaceSalinity, &
+ seaFreezingTemperature, &
snowfallRate, &
zSalinityFlux, &
zSalinityGDFlux, &
@@ -2917,7 +3704,9 @@ subroutine column_biogeochemistry(domain, ierr)
iceAreaCategory, & ! tracers (1,ncat,ncell)
iceVolumeCategory, & ! tracers (1,ncat,ncell)
snowVolumeCategory, & ! tracers (1,ncat,ncell)
- skeletalAlgaeConc
+ skeletalAlgaeConc, &
+ oceanBioFluxesCategory, &
+ brineFraction
integer, dimension(:,:), pointer :: &
newlyFormedIce
@@ -2939,8 +3728,21 @@ subroutine column_biogeochemistry(domain, ierr)
indexj, &
iBioLayers
+ ! test carbon conservation
real(kind=RKIND), dimension(:), allocatable :: &
- oceanBioConcentrationsUsed
+ totalCarbonCatFinal, &
+ totalCarbonCatInitial, &
+ totalCarbonCatFlux, &
+ brineHeightCatInitial, &
+ brineHeightCatFinal
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ oceanBioConcentrationsUsed, &
+ iceCarbonInitialCategory, &
+ iceCarbonFinalCategory, &
+ iceCarbonFluxCategory, &
+ iceBrineInitialCategory, &
+ iceBrineFinalCategory
logical, dimension(:), allocatable :: &
newlyFormedIceLogical
@@ -2949,14 +3751,22 @@ subroutine column_biogeochemistry(domain, ierr)
abortFlag, &
rayleighCriteria, &
setGetPhysicsTracers, &
- setGetBGCTracers
+ setGetBGCTracers, &
+ checkCarbon
character(len=strKIND) :: &
abortMessage, &
abortLocation
- character(len=strKINDWarnings), dimension(:), allocatable :: &
- warnings
+ real(kind=RKIND) :: &
+ carbonErrorCat, &
+ carbonErrorColumnPackage
+
+ real(kind=RKIND), parameter :: &
+ accuracy = 1.0e-14_RKIND
+
+ ! test carbon conservation
+ checkCarbon = .false.
block => domain % blocklist
do while (associated(block))
@@ -3036,6 +3846,7 @@ subroutine column_biogeochemistry(domain, ierr)
call MPAS_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux)
call MPAS_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux)
call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxes", oceanBioFluxes)
+ call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxesCategory", oceanBioFluxesCategory)
call MPAS_pool_get_array(biogeochemistry, "verticalNitrogenLosses", verticalNitrogenLosses)
call MPAS_pool_get_array(biogeochemistry, "bioTemperature", bioTemperature)
call MPAS_pool_get_array(biogeochemistry, "totalSkeletalAlgae", totalSkeletalAlgae)
@@ -3055,6 +3866,7 @@ subroutine column_biogeochemistry(domain, ierr)
call MPAS_pool_get_array(ocean_coupling, "seaSurfaceTemperature", seaSurfaceTemperature)
call MPAS_pool_get_array(ocean_coupling, "seaSurfaceSalinity", seaSurfaceSalinity)
+ call MPAS_pool_get_array(ocean_coupling, "seaFreezingTemperature", seaFreezingTemperature)
call MPAS_pool_get_array(ocean_coupling, "oceanMixedLayerDepth", oceanMixedLayerDepth)
call MPAS_pool_get_array(atmos_coupling, "snowfallRate", snowfallRate)
@@ -3080,19 +3892,33 @@ subroutine column_biogeochemistry(domain, ierr)
call MPAS_pool_get_array(tracers, "iceVolumeCategory", iceVolumeCategory, 1)
call MPAS_pool_get_array(tracers, "snowVolumeCategory", snowVolumeCategory, 1)
call MPAS_pool_get_array(tracers, "skeletalAlgaeConc", skeletalAlgaeConc, 1)
+ call MPAS_pool_get_array(tracers, "brineFraction", brineFraction, 1)
! newly formed ice
allocate(newlyFormedIceLogical(nCategories))
allocate(oceanBioConcentrationsUsed(ciceTracerObject % nBioTracers))
+ allocate(brineHeightCatInitial(nCategories))
+
+ if (checkCarbon) then
+ allocate(totalCarbonCatFinal(nCategories))
+ allocate(totalCarbonCatInitial(nCategories))
+ allocate(totalCarbonCatFlux(nCategories))
+ allocate(brineHeightCatFinal(nCategories))
+ endif
setGetPhysicsTracers = .true.
setGetBGCTracers = config_use_column_biogeochemistry
- do iCell = 1, nCellsSolve
+ ! code abort
+ abortFlag = .false.
+ abortMessage = ""
+ do iCell = 1, nCellsSolve
! newly formed ice
do iCategory = 1, nCategories
newlyFormedIceLogical(iCategory) = (newlyFormedIce(iCategory,iCell) == 1)
+ brineHeightCatInitial(iCategory) = brineFraction(1,iCategory,iCell) * &
+ iceVolumeCategoryInitial(iCategory,iCell)/(iceAreaCategoryInitial(iCategory,iCell) + seaicePuny)
enddo ! iCategory
rayleighCriteria = (rayleighCriteriaReal(iCell) > 0.5_RKIND)
@@ -3146,7 +3972,11 @@ subroutine column_biogeochemistry(domain, ierr)
abortFlag = .false.
- call set_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call set_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
+
+ if (checkCarbon) call seaice_total_carbon_content_category(block,&
+ totalCarbonCatInitial,iceAreaCategoryInitial,iceVolumeCategoryInitial,iCell)
call colpkg_clear_warnings()
call colpkg_biogeochemistry(&
@@ -3202,6 +4032,7 @@ subroutine column_biogeochemistry(domain, ierr)
snowiceFormationCategory(:,iCell), &
seaSurfaceTemperature(iCell), &
seaSurfaceSalinity(iCell), &
+ seaFreezingTemperature(iCell), &
snowfallRate(iCell), &
snowMeltCategory(:,iCell), &
oceanMixedLayerDepth(iCell), &
@@ -3215,28 +4046,47 @@ subroutine column_biogeochemistry(domain, ierr)
iceVolumeCategory(1,:,iCell), &
snowVolumeCategory(1,:,iCell), &
openWaterArea(iCell), &
- ciceTracerObject % tracerArrayCategory(:,:), &
+ tracerArrayCategory, &
snowVolumeCategoryInitial(:,iCell), &
config_use_skeletal_biochemistry, &
maxAlgaeType, &
nZBGCTracers, &
+ oceanBioFluxesCategory(:,:,iCell), &
abortFlag, &
abortMessage)
- call colpkg_get_warnings(warnings)
- call column_write_warnings(warnings)
-
- ! code abort
- if (abortFlag) then
- call mpas_log_write("column_biogeochemistry: "//trim(abortMessage) , messageType=MPAS_LOG_ERR)
- call mpas_log_write("iCell: $i", messageType=MPAS_LOG_CRIT, intArgs=(/indexToCellID(iCell)/))
- ierr = SEAICE_ERROR_COL_BGC
- call seaice_critical_error_write_block(domain, block)
- return
+ call column_write_warnings(abortFlag)
+
+ call get_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
+
+ if (checkCarbon) then
+ call seaice_total_carbon_content_category(block,totalCarbonCatFinal,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell)
+ call seaice_ocean_carbon_flux(block,totalCarbonCatFlux,oceanBioFluxesCategory(:,:,:),iCell)
+ do iCategory = 1,nCategories
+ brineHeightCatFinal(iCategory) = brineFraction(1,iCategory,iCell) * &
+ iceVolumeCategory(1,iCategory,iCell)/(iceAreaCategory(1,iCategory,iCell) + seaicePuny)
+ carbonErrorCat = totalCarbonCatInitial(iCategory) - totalCarbonCatFlux(iCategory)*config_dt - &
+ totalCarbonCatFinal(iCategory)
+ if (abs(carbonErrorCat) > accuracy*MAXVAL((/totalCarbonCatInitial(iCategory),totalCarbonCatFinal(iCategory)/))) then
+! abortFlag = .true.
+! abortMessage = "carbon conservation errror after column bgc"
+ call mpas_log_write("column_biogeochemistry, carbon conservation error", messageType=MPAS_LOG_ERR)
+ call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
+ call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/))
+ call mpas_log_write("carbonErrorCat: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonErrorCat/))
+ call mpas_log_write("carbonErrorCat*iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonErrorCat*iceAreaCategory(1,iCategory,iCell)/))
+ call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory)/))
+ call mpas_log_write("totalCarbonCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/))
+ call mpas_log_write("totalCarbonCatFlux(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFlux(iCategory)/))
+ call mpas_log_write("brineHeightCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatInitial(iCategory)/))
+ call mpas_log_write("brineHeightCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatFinal(iCategory)/))
+ endif
+ enddo
endif
- call get_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ ! code abort
+ if (abortFlag) exit
- ! update
totalSkeletalAlgae(iCell) = 0.0_RKIND
bioShortwaveFluxCell(:,iCell) = 0.0_RKIND
@@ -3263,6 +4113,22 @@ subroutine column_biogeochemistry(domain, ierr)
enddo ! iCell
+ ! code abort
+ if (abortFlag) then
+ call mpas_log_write("column_biogeochemistry: "//trim(abortMessage) , messageType=MPAS_LOG_ERR)
+ call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/))
+ endif
+ call seaice_critical_error_write_block(domain, block, abortFlag)
+ call seaice_check_critical_error(domain, abortFlag)
+
+ if (checkCarbon) then
+ deallocate(totalCarbonCatFinal)
+ deallocate(totalCarbonCatInitial)
+ deallocate(totalCarbonCatFlux)
+ deallocate(brineHeightCatFinal)
+ endif
+
+ deallocate(brineHeightCatInitial)
deallocate(newlyFormedIceLogical)
deallocate(oceanBioConcentrationsUsed)
@@ -3534,7 +4400,8 @@ subroutine seaice_column_aggregate(domain)
mesh, &
tracers, &
tracers_aggregate, &
- icestate
+ icestate, &
+ ocean_coupling
logical, pointer :: &
config_use_column_biogeochemistry
@@ -3543,7 +4410,8 @@ subroutine seaice_column_aggregate(domain)
iceAreaCell, &
iceVolumeCell, &
snowVolumeCell, &
- openWaterArea
+ openWaterArea, &
+ seaFreezingTemperature
real(kind=RKIND), dimension(:,:,:), pointer :: &
iceAreaCategory, &
@@ -3568,6 +4436,7 @@ subroutine seaice_column_aggregate(domain)
call MPAS_pool_get_subpool(block % structs, "tracers", tracers)
call MPAS_pool_get_subpool(block % structs, "icestate", icestate)
call MPAS_pool_get_subpool(block % structs, "tracers_aggregate", tracers_aggregate)
+ call MPAS_pool_get_subpool(block % structs, "ocean_coupling", ocean_coupling)
call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
@@ -3584,22 +4453,26 @@ subroutine seaice_column_aggregate(domain)
call MPAS_pool_get_array(icestate, "openWaterArea", openWaterArea)
+ call MPAS_pool_get_array(ocean_coupling, "seaFreezingTemperature", seaFreezingTemperature)
+
setGetPhysicsTracers = .true.
setGetBGCTracers = config_use_column_biogeochemistry
do iCell = 1, nCellsSolve
! set the category tracer array
- call set_cice_tracer_array_category(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call set_cice_tracer_array_category(block, ciceTracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
call colpkg_aggregate(&
nCategories, &
+ seaFreezingTemperature(iCell), &
iceAreaCategory(1,:,iCell), &
- ciceTracerObject % tracerArrayCategory, & ! trcrn
+ tracerArrayCategory, & ! trcrn
iceVolumeCategory(1,:,iCell), &
snowVolumeCategory(1,:,iCell), &
iceAreaCell(iCell), &
- ciceTracerObject % tracerArrayCell, & ! trcr
+ tracerArrayCell, & ! trcr
iceVolumeCell(iCell), &
snowVolumeCell(iCell), &
openWaterArea(iCell), &
@@ -3610,7 +4483,8 @@ subroutine seaice_column_aggregate(domain)
ciceTracerObject % ancestorIndices) ! nt_strata
! set the cell tracer array
- call get_cice_tracer_array_cell(block, ciceTracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call get_cice_tracer_array_cell(block, ciceTracerObject, &
+ tracerArrayCell, iCell, setGetPhysicsTracers, setGetBGCTracers)
enddo ! iCell
@@ -3694,7 +4568,8 @@ subroutine seaice_column_coupling_prep(domain)
oceanDMSPpFlux, &
oceanDMSPdFlux, &
oceanHumicsFlux, &
- oceanDustIronFlux
+ oceanDustIronFlux, &
+ totalOceanCarbonFlux
real(kind=RKIND), dimension(:,:), pointer :: &
albedoVisibleDirectCategory, &
@@ -3719,7 +4594,13 @@ subroutine seaice_column_coupling_prep(domain)
real(kind=RKIND), pointer :: &
config_dt
- integer, pointer :: &
+ real(kind=RKIND), pointer :: &
+ config_ratio_C_to_N_diatoms, &
+ config_ratio_C_to_N_small_plankton, &
+ config_ratio_C_to_N_phaeocystis, &
+ config_ratio_C_to_N_proteins
+
+ integer, pointer :: &
nCellsSolve, &
nCategories, &
nZBGCTracers, &
@@ -3738,6 +4619,9 @@ subroutine seaice_column_coupling_prep(domain)
iBioTracers, &
iBioData
+ real(kind=RKIND), dimension(:), allocatable :: &
+ ratio_C_to_N
+
real(kind=RKIND), dimension(:), allocatable :: &
oceanBioFluxesAll
@@ -3745,6 +4629,10 @@ subroutine seaice_column_coupling_prep(domain)
call MPAS_pool_get_config(domain % configs, "config_dt", config_dt)
call MPAS_pool_get_config(domain % configs, "config_include_pond_freshwater_feedback", config_include_pond_freshwater_feedback)
call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+ call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms)
+ call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton)
+ call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis)
+ call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins)
if (config_use_ocean_mixed_layer) &
call seaice_column_ocean_mixed_layer(domain)
@@ -3827,6 +4715,7 @@ subroutine seaice_column_coupling_prep(domain)
call MPAS_pool_get_array(biogeochemistry, "oceanDONFlux", oceanDONFlux)
call MPAS_pool_get_array(biogeochemistry, "oceanParticulateIronFlux", oceanParticulateIronFlux)
call MPAS_pool_get_array(biogeochemistry, "oceanDissolvedIronFlux", oceanDissolvedIronFlux)
+ call MPAS_pool_get_array(biogeochemistry, "totalOceanCarbonFlux", totalOceanCarbonFlux)
call MPAS_pool_get_dimension(mesh, "nZBGCTracers", nZBGCTracers)
call MPAS_pool_get_dimension(mesh, "maxAlgaeType", maxAlgaeType)
@@ -3840,6 +4729,12 @@ subroutine seaice_column_coupling_prep(domain)
allocate(oceanBioFluxesAll(nZBGCTracers))
+ allocate(ratio_C_to_N(3))
+
+ ratio_C_to_N(1) = config_ratio_C_to_N_diatoms
+ ratio_C_to_N(2) = config_ratio_C_to_N_small_plankton
+ ratio_C_to_N(3) = config_ratio_C_to_N_phaeocystis
+
do iCell = 1, nCellsSolve
!-------------------------------------------------------------------
@@ -3928,6 +4823,7 @@ subroutine seaice_column_coupling_prep(domain)
!-----------------------------------------------------------------
if (config_use_column_biogeochemistry) then
+ totalOceanCarbonFlux(iCell) = 0.0_RKIND
oceanBioFluxesAll(:) = 0.0_RKIND
oceanAlgaeFlux(:,iCell) = 0.0_RKIND
oceanDOCFlux(:,iCell) = 0.0_RKIND
@@ -3954,6 +4850,8 @@ subroutine seaice_column_coupling_prep(domain)
do iBioTracers = 1, maxAlgaeType
iBioData = iBioData+1
oceanAlgaeFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData)
+ totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + &
+ oceanAlgaeFlux(iBioTracers,iCell) * ratio_C_to_N(iBioTracers)
enddo
! Nitrate
@@ -3964,12 +4862,16 @@ subroutine seaice_column_coupling_prep(domain)
do iBioTracers = 1, maxDOCType
iBioData = iBioData+1
oceanDOCFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData)
+ totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + &
+ oceanDOCFlux(iBioTracers,iCell)
enddo
! DIC
do iBioTracers = 1, maxDICType
iBioData = iBioData+1
oceanDICFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData)
+ totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + &
+ oceanDICFlux(iBioTracers,iCell)
enddo
! Chlorophyll (not saved)
@@ -3995,11 +4897,15 @@ subroutine seaice_column_coupling_prep(domain)
iBioData = iBioData+1
oceanDMSFlux(iCell) = oceanBioFluxesAll(iBioData)
- ! DON (Proteins)
+ ! PON
iBioData = iBioData+1
+
+ ! DON (Proteins)
do iBioTracers = 1, maxDONType
iBioData = iBioData+1
oceanDONFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData)
+ totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + &
+ oceanDONFlux(iBioTracers,iCell) * config_ratio_C_to_N_proteins
enddo
! Dissolved Iron
@@ -4026,12 +4932,15 @@ subroutine seaice_column_coupling_prep(domain)
! Humics
iBioData = iBioData+1
oceanHumicsFlux(iCell) = oceanBioFluxesAll(iBioData)
+ totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + &
+ oceanHumicsFlux(iCell)
endif ! config_use_column_biogeochemistry
enddo ! iCell
deallocate(oceanBioFluxesAll)
+ deallocate(ratio_C_to_N)
block => block % next
enddo
@@ -4581,12 +5490,6 @@ subroutine init_column_tracer_object(domain, tracerObject)
! get the number of CICE tracers in trcrn
call init_column_tracer_object_tracer_number(domain, tracerObject)
- ! allocate the category tracer array
- allocate(tracerObject % tracerArrayCategory(tracerObject % nTracers,nCategories))
-
- ! allocate the cell tracer array
- allocate(tracerObject % tracerArrayCell(tracerObject % nTracers))
-
! allocate other arrays
allocate(tracerObject % parentIndex(tracerObject % nTracers))
allocate(tracerObject % firstAncestorMask(tracerObject % nTracers, tracerObject % nBaseTracers))
@@ -4614,8 +5517,39 @@ subroutine init_column_tracer_object(domain, tracerObject)
! set all indices for biogeochemistry including parent, ancestor and ancestor mask
call init_column_tracer_object_for_biogeochemistry(domain, tracerObject)
+ else
+ allocate(tracerObject % index_algaeConc(1))
+ allocate(tracerObject % index_algalCarbon(1))
+ allocate(tracerObject % index_algalChlorophyll(1))
+ allocate(tracerObject % index_DOCConc(1))
+ allocate(tracerObject % index_DONConc(1))
+ allocate(tracerObject % index_DICConc(1))
+ allocate(tracerObject % index_dissolvedIronConc(1))
+ allocate(tracerObject % index_particulateIronConc(1))
+ allocate(tracerObject % index_verticalAerosolsConc(1))
+
+ allocate(tracerObject % index_algaeConcLayer(1))
+ allocate(tracerObject % index_algalCarbonLayer(1))
+ allocate(tracerObject % index_algalChlorophyllLayer(1))
+ allocate(tracerObject % index_DOCConcLayer(1))
+ allocate(tracerObject % index_DONConcLayer(1))
+ allocate(tracerObject % index_DICConcLayer(1))
+ allocate(tracerObject % index_dissolvedIronConcLayer(1))
+ allocate(tracerObject % index_particulateIronConcLayer(1))
+ allocate(tracerObject % index_verticalAerosolsConcLayer(1))
+ allocate(tracerObject % index_verticalAerosolsConcShortwave(1))
+
+ allocate(tracerObject % index_LayerIndexToDataArray(1))
+ allocate(tracerObject % index_LayerIndexToBioIndex(1))
endif
+ ! allocate tracer arrays
+ !$omp parallel
+ allocate(tracerArrayCategory(tracerObject % nTracers, nCategories))
+ !$omp end parallel
+
+ allocate(tracerArrayCell(tracerObject % nTracers))
+
end subroutine init_column_tracer_object
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -4662,7 +5596,9 @@ subroutine init_column_tracer_object_tracer_number(domain, tracerObject)
config_use_humics, &
config_use_DON, &
config_use_iron, &
- config_use_zaerosols
+ config_use_zaerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
integer, pointer :: &
nIceLayers, &
@@ -4690,6 +5626,8 @@ subroutine init_column_tracer_object_tracer_number(domain, tracerObject)
call MPAS_pool_get_config(domain % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(domain % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(domain % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(domain % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
call MPAS_pool_get_config(domain % configs, "config_use_brine", config_use_brine)
@@ -4761,6 +5699,16 @@ subroutine init_column_tracer_object_tracer_number(domain, tracerObject)
config_use_topo_meltponds) &
tracerObject % nTracers = tracerObject % nTracers + 1
+ ! snow density (ice mass, liquid mass, density)
+ if (config_use_effective_snow_density) then
+ tracerObject % nTracers = tracerObject % nTracers + nSnowLayers*3
+ endif
+
+ ! snow grain radius
+ if (config_use_snow_grain_radius) then
+ tracerObject % nTracers = tracerObject % nTracers + nSnowLayers
+ endif
+
! aerosols
if (config_use_aerosols) &
tracerObject % nTracers = tracerObject % nTracers + nAerosols*4
@@ -4922,7 +5870,10 @@ subroutine init_column_tracer_object_child_indices(domain, tracerObject)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
+
integer :: &
nTracers
@@ -4939,6 +5890,8 @@ subroutine init_column_tracer_object_child_indices(domain, tracerObject)
call MPAS_pool_get_config(domain % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(domain % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(domain % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(domain % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nSnowLayers", nSnowLayers)
@@ -5005,6 +5958,26 @@ subroutine init_column_tracer_object_child_indices(domain, tracerObject)
tracerObject % index_pondLidThickness = nTracers
endif
+ ! snow density
+ tracerObject % index_snowIceMass = indexMissingValue
+ tracerObject % index_snowLiquidMass = indexMissingValue
+ tracerObject % index_snowDensity = indexMissingValue
+ if (config_use_effective_snow_density) then
+ tracerObject % index_snowIceMass = nTracers + 1
+ nTracers = nTracers + nSnowLayers
+ tracerObject % index_snowLiquidMass = nTracers + 1
+ nTracers = nTracers + nSnowLayers
+ tracerObject % index_snowDensity = nTracers + 1
+ nTracers = nTracers + nSnowLayers
+ endif
+
+ ! snow grain radius
+ tracerObject % index_snowGrainRadius = indexMissingValue
+ if (config_use_snow_grain_radius) then
+ tracerObject % index_snowGrainRadius = nTracers + 1
+ nTracers = nTracers + nSnowLayers
+ endif
+
! aerosols
tracerObject % index_aerosols = indexMissingValue
if (config_use_aerosols) then
@@ -5044,7 +6017,9 @@ subroutine init_column_tracer_object_parent_indices(domain, tracerObject)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
integer :: &
iIceLayer, &
@@ -5063,6 +6038,8 @@ subroutine init_column_tracer_object_parent_indices(domain, tracerObject)
call MPAS_pool_get_config(domain % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(domain % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(domain % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(domain % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nSnowLayers", nSnowLayers)
@@ -5079,7 +6056,7 @@ subroutine init_column_tracer_object_parent_indices(domain, tracerObject)
! snow enthalpy
do iSnowLayer = 1, nSnowLayers
- tracerObject % parentIndex(tracerObject % index_snowEnthalpy) = 2
+ tracerObject % parentIndex(tracerObject % index_snowEnthalpy + iSnowLayer - 1) = 2
enddo ! iSnowLayer
! ice age
@@ -5116,6 +6093,22 @@ subroutine init_column_tracer_object_parent_indices(domain, tracerObject)
tracerObject % parentIndex(tracerObject % index_pondLidThickness) = 2 + tracerObject % index_pondArea
endif
+ ! snow density
+ if (config_use_effective_snow_density) then
+ do iSnowLayer = 1, nSnowLayers
+ tracerObject % parentIndex(tracerObject % index_snowIceMass + iSnowLayer - 1) = 2
+ tracerObject % parentIndex(tracerObject % index_snowLiquidMass + iSnowLayer - 1) = 2
+ tracerObject % parentIndex(tracerObject % index_snowDensity + iSnowLayer - 1) = 2
+ enddo ! iSnowLayer
+ endif
+
+ ! snow grain radius
+ if (config_use_snow_grain_radius) then
+ do iSnowLayer = 1, nSnowLayers
+ tracerObject % parentIndex(tracerObject % index_snowGrainRadius + iSnowLayer - 1) = 2
+ enddo ! iSnowLayer
+ endif
+
! aerosols
if (config_use_aerosols) then
do iAerosol = 1, nAerosols
@@ -5284,14 +6277,17 @@ end subroutine init_column_tracer_object_ancestor_indices
!
!-----------------------------------------------------------------------
- subroutine set_cice_tracer_array_category(block, tracerObject, iCell, setPhysicsTracers, setBGCTracers)
+ subroutine set_cice_tracer_array_category(block, tracerObject, tracerArrayCategory, iCell, setPhysicsTracers, setBGCTracers)
type(block_type), intent(inout) :: &
block
- type(ciceTracerObjectType), intent(inout) :: &
+ type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:,:), intent(inout) :: &
+ tracerArrayCategory
+
integer, intent(in) :: &
iCell
@@ -5301,11 +6297,11 @@ subroutine set_cice_tracer_array_category(block, tracerObject, iCell, setPhysics
! get physics tracers
if (setPhysicsTracers) &
- call set_cice_physics_tracer_array_category(block, tracerObject, iCell)
+ call set_cice_physics_tracer_array_category(block, tracerArrayCategory, iCell)
! get BGC tracers
if (setBGCTracers) &
- call set_cice_biogeochemistry_tracer_array_category(block, tracerObject, iCell)
+ call set_cice_biogeochemistry_tracer_array_category(block, tracerObject, tracerArrayCategory, iCell)
end subroutine set_cice_tracer_array_category
@@ -5321,7 +6317,7 @@ end subroutine set_cice_tracer_array_category
!
!-----------------------------------------------------------------------
- subroutine get_cice_tracer_array_category(block, tracerObject, iCell, getPhysicsTracers, getBGCTracers)
+ subroutine get_cice_tracer_array_category(block, tracerObject, tracerArrayCategory, iCell, getPhysicsTracers, getBGCTracers)
type(block_type), intent(inout) :: &
block
@@ -5329,6 +6325,9 @@ subroutine get_cice_tracer_array_category(block, tracerObject, iCell, getPhysics
type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ tracerArrayCategory
+
integer, intent(in) :: &
iCell
@@ -5338,11 +6337,11 @@ subroutine get_cice_tracer_array_category(block, tracerObject, iCell, getPhysics
! get physics tracers
if (getPhysicsTracers) &
- call get_cice_physics_tracer_array_category(block, tracerObject, iCell)
+ call get_cice_physics_tracer_array_category(block, tracerArrayCategory, iCell)
! get BGC tracers
if (getBGCTracers) &
- call get_cice_biogeochemistry_tracer_array_category(block, tracerObject, iCell)
+ call get_cice_biogeochemistry_tracer_array_category(block, tracerObject, tracerArrayCategory, iCell)
end subroutine get_cice_tracer_array_category
@@ -5358,14 +6357,17 @@ end subroutine get_cice_tracer_array_category
!
!-----------------------------------------------------------------------
- subroutine set_cice_tracer_array_cell(block, tracerObject, iCell, setPhysicsTracers, setBGCTracers)
+ subroutine set_cice_tracer_array_cell(block, tracerObject, tracerArrayCell, iCell, setPhysicsTracers, setBGCTracers)
type(block_type), intent(inout) :: &
block
- type(ciceTracerObjectType), intent(inout) :: &
+ type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:), intent(inout) :: &
+ tracerArrayCell
+
integer, intent(in) :: &
iCell
@@ -5375,11 +6377,11 @@ subroutine set_cice_tracer_array_cell(block, tracerObject, iCell, setPhysicsTrac
! get physics tracers
if (setPhysicsTracers) &
- call set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
+ call set_cice_physics_tracer_array_cell(block, tracerArrayCell, iCell)
! get BGC tracers
if (setBGCTracers) &
- call set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell)
+ call set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, tracerArrayCell, iCell)
end subroutine set_cice_tracer_array_cell
@@ -5395,7 +6397,7 @@ end subroutine set_cice_tracer_array_cell
!
!-----------------------------------------------------------------------
- subroutine get_cice_tracer_array_cell(block, tracerObject, iCell, getPhysicsTracers, getBGCTracers)
+ subroutine get_cice_tracer_array_cell(block, tracerObject, tracerArrayCell, iCell, getPhysicsTracers, getBGCTracers)
type(block_type), intent(inout) :: &
block
@@ -5403,6 +6405,9 @@ subroutine get_cice_tracer_array_cell(block, tracerObject, iCell, getPhysicsTrac
type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ tracerArrayCell
+
integer, intent(in) :: &
iCell
@@ -5412,11 +6417,11 @@ subroutine get_cice_tracer_array_cell(block, tracerObject, iCell, getPhysicsTrac
! get physics tracers
if (getPhysicsTracers) &
- call get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
+ call get_cice_physics_tracer_array_cell(block, tracerArrayCell, iCell)
! get BGC tracers
if (getBGCTracers) &
- call get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell)
+ call get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, tracerArrayCell, iCell)
end subroutine get_cice_tracer_array_cell
@@ -5432,13 +6437,13 @@ end subroutine get_cice_tracer_array_cell
!
!-----------------------------------------------------------------------
- subroutine set_cice_physics_tracer_array_category(block, tracerObject, iCell)
+ subroutine set_cice_physics_tracer_array_category(block, tracerArrayCategory, iCell)
type(block_type), intent(in) :: &
block
- type(ciceTracerObjectType), intent(inout) :: &
- tracerObject
+ real(kind=RKIND), dimension(:,:), intent(inout) :: &
+ tracerArrayCategory
integer, intent(in) :: &
iCell
@@ -5450,7 +6455,9 @@ subroutine set_cice_physics_tracer_array_category(block, tracerObject, iCell)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
integer, pointer :: &
nIceLayers, &
@@ -5475,7 +6482,11 @@ subroutine set_cice_physics_tracer_array_category(block, tracerObject, iCell)
snowScatteringAerosol, &
snowBodyAerosol, &
iceScatteringAerosol, &
- iceBodyAerosol
+ iceBodyAerosol, &
+ snowIceMass, &
+ snowLiquidMass, &
+ snowGrainRadius, &
+ snowDensity
integer :: &
nTracers, &
@@ -5488,6 +6499,8 @@ subroutine set_cice_physics_tracer_array_category(block, tracerObject, iCell)
call MPAS_pool_get_config(block % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(block % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_dimension(block % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers)
@@ -5510,42 +6523,46 @@ subroutine set_cice_physics_tracer_array_category(block, tracerObject, iCell)
call MPAS_pool_get_array(tracers, "snowBodyAerosol", snowBodyAerosol, 1)
call MPAS_pool_get_array(tracers, "iceScatteringAerosol", iceScatteringAerosol, 1)
call MPAS_pool_get_array(tracers, "iceBodyAerosol", iceBodyAerosol, 1)
+ call MPAS_pool_get_array(tracers, "snowIceMass", snowIceMass, 1)
+ call MPAS_pool_get_array(tracers, "snowLiquidMass", snowLiquidMass, 1)
+ call MPAS_pool_get_array(tracers, "snowDensity", snowDensity, 1)
+ call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1)
nTracers = 1
! surfaceTemperature
- tracerObject % tracerArrayCategory(nTracers,:) = surfaceTemperature(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = surfaceTemperature(1,:,iCell)
nTracers = nTracers + 1
! iceEnthalpy
- tracerObject % tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:) = iceEnthalpy(:,:,iCell)
+ tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:) = iceEnthalpy(:,:,iCell)
nTracers = nTracers + nIceLayers
! snowEnthalpy
- tracerObject % tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:) = snowEnthalpy(:,:,iCell)
+ tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:) = snowEnthalpy(:,:,iCell)
nTracers = nTracers + nSnowLayers
! ice Salinity
- tracerObject % tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:) = iceSalinity(:,:,iCell)
+ tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:) = iceSalinity(:,:,iCell)
nTracers = nTracers + nIceLayers
! iceAge
if (config_use_ice_age) then
- tracerObject % tracerArrayCategory(nTracers,:) = iceAge(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = iceAge(1,:,iCell)
nTracers = nTracers + 1
endif
! firstYearIceArea
if (config_use_first_year_ice) then
- tracerObject % tracerArrayCategory(nTracers,:) = firstYearIceArea(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = firstYearIceArea(1,:,iCell)
nTracers = nTracers + 1
endif
! level ice tracers
if (config_use_level_ice) then
- tracerObject % tracerArrayCategory(nTracers,:) = levelIceArea(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = levelIceArea(1,:,iCell)
nTracers = nTracers + 1
- tracerObject % tracerArrayCategory(nTracers,:) = levelIceVolume(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = levelIceVolume(1,:,iCell)
nTracers = nTracers + 1
endif
@@ -5553,27 +6570,43 @@ subroutine set_cice_physics_tracer_array_category(block, tracerObject, iCell)
if (config_use_cesm_meltponds .or. &
config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- tracerObject % tracerArrayCategory(nTracers,:) = pondArea(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = pondArea(1,:,iCell)
nTracers = nTracers + 1
- tracerObject % tracerArrayCategory(nTracers,:) = pondDepth(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = pondDepth(1,:,iCell)
nTracers = nTracers + 1
endif
! level or topo ponds
if (config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- tracerObject % tracerArrayCategory(nTracers,:) = pondLidThickness(1,:,iCell)
+ tracerArrayCategory(nTracers,:) = pondLidThickness(1,:,iCell)
nTracers = nTracers + 1
end if
+ ! snow density (ice mass, liquid mass, density)
+ if (config_use_effective_snow_density) then
+ tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:) = snowIceMass(:,:,iCell)
+ nTracers = nTracers + nSnowLayers
+ tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:) = snowLiquidMass(:,:,iCell)
+ nTracers = nTracers + nSnowLayers
+ tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:) = snowDensity(:,:,iCell)
+ nTracers = nTracers + nSnowLayers
+ endif
+
+ ! snow grain radius
+ if (config_use_snow_grain_radius) then
+ tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:) = snowGrainRadius(:,:,iCell)
+ nTracers = nTracers + nSnowLayers
+ endif
+
! aerosols
if (config_use_aerosols) then
do iAerosol = 1, nAerosols
- tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1) ,:) = snowScatteringAerosol(iAerosol,:,iCell)
- tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1)+1,:) = snowBodyAerosol(iAerosol,:,iCell)
- tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1)+2,:) = iceScatteringAerosol(iAerosol,:,iCell)
- tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1)+3,:) = iceBodyAerosol(iAerosol,:,iCell)
+ tracerArrayCategory(nTracers+4*(iAerosol-1) ,:) = snowScatteringAerosol(iAerosol,:,iCell)
+ tracerArrayCategory(nTracers+4*(iAerosol-1)+1,:) = snowBodyAerosol(iAerosol,:,iCell)
+ tracerArrayCategory(nTracers+4*(iAerosol-1)+2,:) = iceScatteringAerosol(iAerosol,:,iCell)
+ tracerArrayCategory(nTracers+4*(iAerosol-1)+3,:) = iceBodyAerosol(iAerosol,:,iCell)
enddo ! iAerosol
endif
@@ -5592,13 +6625,13 @@ end subroutine set_cice_physics_tracer_array_category
!
!-----------------------------------------------------------------------
- subroutine get_cice_physics_tracer_array_category(block, tracerObject, iCell)
+ subroutine get_cice_physics_tracer_array_category(block, tracerArrayCategory, iCell)
type(block_type), intent(inout) :: &
block
- type(ciceTracerObjectType), intent(in) :: &
- tracerObject
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ tracerArrayCategory
integer, intent(in) :: &
iCell
@@ -5610,7 +6643,10 @@ subroutine get_cice_physics_tracer_array_category(block, tracerObject, iCell)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
+
integer, pointer :: &
nIceLayers, &
@@ -5635,7 +6671,11 @@ subroutine get_cice_physics_tracer_array_category(block, tracerObject, iCell)
snowScatteringAerosol, &
snowBodyAerosol, &
iceScatteringAerosol, &
- iceBodyAerosol
+ iceBodyAerosol, &
+ snowIceMass, &
+ snowLiquidMass, &
+ snowGrainRadius, &
+ snowDensity
integer :: &
nTracers, &
@@ -5648,6 +6688,8 @@ subroutine get_cice_physics_tracer_array_category(block, tracerObject, iCell)
call MPAS_pool_get_config(block % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(block % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_dimension(block % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers)
@@ -5670,42 +6712,46 @@ subroutine get_cice_physics_tracer_array_category(block, tracerObject, iCell)
call MPAS_pool_get_array(tracers, "snowBodyAerosol", snowBodyAerosol, 1)
call MPAS_pool_get_array(tracers, "iceScatteringAerosol", iceScatteringAerosol, 1)
call MPAS_pool_get_array(tracers, "iceBodyAerosol", iceBodyAerosol, 1)
+ call MPAS_pool_get_array(tracers, "snowIceMass", snowIceMass, 1)
+ call MPAS_pool_get_array(tracers, "snowLiquidMass", snowLiquidMass, 1)
+ call MPAS_pool_get_array(tracers, "snowDensity", snowDensity, 1)
+ call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1)
nTracers = 1
! surfaceTemperature
- surfaceTemperature(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ surfaceTemperature(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
! iceEnthalpy
- iceEnthalpy(:,:,iCell) = tracerObject % tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:)
+ iceEnthalpy(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:)
nTracers = nTracers + nIceLayers
! snowEnthalpy
- snowEnthalpy(:,:,iCell) = tracerObject % tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:)
+ snowEnthalpy(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:)
nTracers = nTracers + nSnowLayers
! ice Salinity
- iceSalinity(:,:,iCell) = tracerObject % tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:)
+ iceSalinity(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nIceLayers-1,:)
nTracers = nTracers + nIceLayers
! iceAge
if (config_use_ice_age) then
- iceAge(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ iceAge(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
endif
! firstYearIceArea
if (config_use_first_year_ice) then
- firstYearIceArea(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ firstYearIceArea(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
endif
! level ice tracers
if (config_use_level_ice) then
- levelIceArea(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ levelIceArea(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
- levelIceVolume(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ levelIceVolume(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
endif
@@ -5713,27 +6759,43 @@ subroutine get_cice_physics_tracer_array_category(block, tracerObject, iCell)
if (config_use_cesm_meltponds .or. &
config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- pondArea(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ pondArea(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
- pondDepth(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ pondDepth(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
endif
! level or topo ponds
if (config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- pondLidThickness(1,:,iCell) = tracerObject % tracerArrayCategory(nTracers,:)
+ pondLidThickness(1,:,iCell) = tracerArrayCategory(nTracers,:)
nTracers = nTracers + 1
end if
+ ! snow density (ice mass, liquid mass, density)
+ if (config_use_effective_snow_density) then
+ snowIceMass(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:)
+ nTracers = nTracers + nSnowLayers
+ snowLiquidMass(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:)
+ nTracers = nTracers + nSnowLayers
+ snowDensity(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:)
+ nTracers = nTracers + nSnowLayers
+ endif
+
+ ! snow grain radius
+ if (config_use_snow_grain_radius) then
+ snowGrainRadius(:,:,iCell) = tracerArrayCategory(nTracers:nTracers+nSnowLayers-1,:)
+ nTracers = nTracers + nSnowLayers
+ endif
+
! aerosols
if (config_use_aerosols) then
do iAerosol = 1, nAerosols
- snowScatteringAerosol(iAerosol,:,iCell) = tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1) ,:)
- snowBodyAerosol(iAerosol,:,iCell) = tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1)+1,:)
- iceScatteringAerosol(iAerosol,:,iCell) = tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1)+2,:)
- iceBodyAerosol(iAerosol,:,iCell) = tracerObject % tracerArrayCategory(nTracers+4*(iAerosol-1)+3,:)
+ snowScatteringAerosol(iAerosol,:,iCell) = tracerArrayCategory(nTracers+4*(iAerosol-1) ,:)
+ snowBodyAerosol(iAerosol,:,iCell) = tracerArrayCategory(nTracers+4*(iAerosol-1)+1,:)
+ iceScatteringAerosol(iAerosol,:,iCell) = tracerArrayCategory(nTracers+4*(iAerosol-1)+2,:)
+ iceBodyAerosol(iAerosol,:,iCell) = tracerArrayCategory(nTracers+4*(iAerosol-1)+3,:)
enddo ! iAerosol
endif
@@ -5752,13 +6814,13 @@ end subroutine get_cice_physics_tracer_array_category
!
!-----------------------------------------------------------------------
- subroutine set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
+ subroutine set_cice_physics_tracer_array_cell(block, tracerArrayCell, iCell)
type(block_type), intent(in) :: &
block
- type(ciceTracerObjectType), intent(inout) :: &
- tracerObject
+ real(kind=RKIND), dimension(:), intent(inout) :: &
+ tracerArrayCell
integer, intent(in) :: &
iCell
@@ -5770,7 +6832,9 @@ subroutine set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
integer, pointer :: &
nIceLayers, &
@@ -5797,7 +6861,11 @@ subroutine set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
snowScatteringAerosolCell, &
snowBodyAerosolCell, &
iceScatteringAerosolCell, &
- iceBodyAerosolCell
+ iceBodyAerosolCell, &
+ snowIceMassCell, &
+ snowLiquidMassCell, &
+ snowGrainRadiusCell, &
+ snowDensityCell
integer :: &
nTracers, &
@@ -5810,6 +6878,8 @@ subroutine set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
call MPAS_pool_get_config(block % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(block % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_dimension(block % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers)
@@ -5832,42 +6902,46 @@ subroutine set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
call MPAS_pool_get_array(tracers_aggregate, "snowBodyAerosolCell", snowBodyAerosolCell)
call MPAS_pool_get_array(tracers_aggregate, "iceScatteringAerosolCell", iceScatteringAerosolCell)
call MPAS_pool_get_array(tracers_aggregate, "iceBodyAerosolCell", iceBodyAerosolCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowIceMassCell", snowIceMassCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowLiquidMassCell", snowLiquidMassCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowDensityCell", snowDensityCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowGrainRadiusCell", snowGrainRadiusCell)
nTracers = 1
! surfaceTemperature
- tracerObject % tracerArrayCell(nTracers) = surfaceTemperatureCell(iCell)
+ tracerArrayCell(nTracers) = surfaceTemperatureCell(iCell)
nTracers = nTracers + 1
! iceEnthalpy
- tracerObject % tracerArrayCell(nTracers:nTracers+nIceLayers-1) = iceEnthalpyCell(:,iCell)
+ tracerArrayCell(nTracers:nTracers+nIceLayers-1) = iceEnthalpyCell(:,iCell)
nTracers = nTracers + nIceLayers
! snowEnthalpy
- tracerObject % tracerArrayCell(nTracers:nTracers+nSnowLayers-1) = snowEnthalpyCell(:,iCell)
+ tracerArrayCell(nTracers:nTracers+nSnowLayers-1) = snowEnthalpyCell(:,iCell)
nTracers = nTracers + nSnowLayers
! ice Salinity
- tracerObject % tracerArrayCell(nTracers:nTracers+nIceLayers-1) = iceSalinityCell(:,iCell)
+ tracerArrayCell(nTracers:nTracers+nIceLayers-1) = iceSalinityCell(:,iCell)
nTracers = nTracers + nIceLayers
! iceAge
if (config_use_ice_age) then
- tracerObject % tracerArrayCell(nTracers) = iceAgeCell(iCell)
+ tracerArrayCell(nTracers) = iceAgeCell(iCell)
nTracers = nTracers + 1
endif
! firstYearIceArea
if (config_use_first_year_ice) then
- tracerObject % tracerArrayCell(nTracers) = firstYearIceAreaCell(iCell)
+ tracerArrayCell(nTracers) = firstYearIceAreaCell(iCell)
nTracers = nTracers + 1
endif
! level ice tracers
if (config_use_level_ice) then
- tracerObject % tracerArrayCell(nTracers) = levelIceAreaCell(iCell)
+ tracerArrayCell(nTracers) = levelIceAreaCell(iCell)
nTracers = nTracers + 1
- tracerObject % tracerArrayCell(nTracers) = levelIceVolumeCell(iCell)
+ tracerArrayCell(nTracers) = levelIceVolumeCell(iCell)
nTracers = nTracers + 1
endif
@@ -5875,27 +6949,43 @@ subroutine set_cice_physics_tracer_array_cell(block, tracerObject, iCell)
if (config_use_cesm_meltponds .or. &
config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- tracerObject % tracerArrayCell(nTracers) = pondAreaCell(iCell)
+ tracerArrayCell(nTracers) = pondAreaCell(iCell)
nTracers = nTracers + 1
- tracerObject % tracerArrayCell(nTracers) = pondDepthCell(iCell)
+ tracerArrayCell(nTracers) = pondDepthCell(iCell)
nTracers = nTracers + 1
endif
! level or topo ponds
if (config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- tracerObject % tracerArrayCell(nTracers) = pondLidThicknessCell(iCell)
+ tracerArrayCell(nTracers) = pondLidThicknessCell(iCell)
nTracers = nTracers + 1
end if
+ ! snow density (ice mass, liquid mass, density)
+ if (config_use_effective_snow_density) then
+ tracerArrayCell(nTracers:nTracers+nSnowLayers-1) = snowIceMassCell(:,iCell)
+ nTracers = nTracers + nSnowLayers
+ tracerArrayCell(nTracers:nTracers+nSnowLayers-1) = snowLiquidMassCell(:,iCell)
+ nTracers = nTracers + nSnowLayers
+ tracerArrayCell(nTracers:nTracers+nSnowLayers-1) = snowDensityCell(:,iCell)
+ nTracers = nTracers + nSnowLayers
+ endif
+
+ ! snow grain radius
+ if (config_use_snow_grain_radius) then
+ tracerArrayCell(nTracers:nTracers+nSnowLayers-1) = snowGrainRadiusCell(:,iCell)
+ nTracers = nTracers + nSnowLayers
+ endif
+
! aerosols
if (config_use_aerosols) then
do iAerosol = 1, nAerosols
- tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1) ) = snowScatteringAerosolCell(iAerosol,iCell)
- tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1)+1) = snowBodyAerosolCell(iAerosol,iCell)
- tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1)+2) = iceScatteringAerosolCell(iAerosol,iCell)
- tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1)+3) = iceBodyAerosolCell(iAerosol,iCell)
+ tracerArrayCell(nTracers+4*(iAerosol-1) ) = snowScatteringAerosolCell(iAerosol,iCell)
+ tracerArrayCell(nTracers+4*(iAerosol-1)+1) = snowBodyAerosolCell(iAerosol,iCell)
+ tracerArrayCell(nTracers+4*(iAerosol-1)+2) = iceScatteringAerosolCell(iAerosol,iCell)
+ tracerArrayCell(nTracers+4*(iAerosol-1)+3) = iceBodyAerosolCell(iAerosol,iCell)
enddo ! iAerosol
endif
@@ -5914,13 +7004,13 @@ end subroutine set_cice_physics_tracer_array_cell
!
!-----------------------------------------------------------------------
- subroutine get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
+ subroutine get_cice_physics_tracer_array_cell(block, tracerArrayCell, iCell)
type(block_type), intent(inout) :: &
block
- type(ciceTracerObjectType), intent(in) :: &
- tracerObject
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ tracerArrayCell
integer, intent(in) :: &
iCell
@@ -5932,7 +7022,9 @@ subroutine get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
- config_use_aerosols
+ config_use_aerosols, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
integer, pointer :: &
nIceLayers, &
@@ -5959,7 +7051,11 @@ subroutine get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
snowScatteringAerosolCell, &
snowBodyAerosolCell, &
iceScatteringAerosolCell, &
- iceBodyAerosolCell
+ iceBodyAerosolCell, &
+ snowIceMassCell, &
+ snowLiquidMassCell, &
+ snowGrainRadiusCell, &
+ snowDensityCell
integer :: &
nTracers, &
@@ -5972,6 +7068,8 @@ subroutine get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
call MPAS_pool_get_config(block % configs, "config_use_level_meltponds", config_use_level_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_topo_meltponds", config_use_topo_meltponds)
call MPAS_pool_get_config(block % configs, "config_use_aerosols", config_use_aerosols)
+ call MPAS_pool_get_config(block % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(block % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
call MPAS_pool_get_dimension(block % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers)
@@ -5994,42 +7092,46 @@ subroutine get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
call MPAS_pool_get_array(tracers_aggregate, "snowBodyAerosolCell", snowBodyAerosolCell)
call MPAS_pool_get_array(tracers_aggregate, "iceScatteringAerosolCell", iceScatteringAerosolCell)
call MPAS_pool_get_array(tracers_aggregate, "iceBodyAerosolCell", iceBodyAerosolCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowIceMassCell", snowIceMassCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowLiquidMassCell", snowLiquidMassCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowDensityCell", snowDensityCell)
+ call MPAS_pool_get_array(tracers_aggregate, "snowGrainRadiusCell", snowGrainRadiusCell)
nTracers = 1
! surfaceTemperature
- surfaceTemperatureCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ surfaceTemperatureCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
! iceEnthalpy
- iceEnthalpyCell(:,iCell) = tracerObject % tracerArrayCell(nTracers:nTracers+nIceLayers-1)
+ iceEnthalpyCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nIceLayers-1)
nTracers = nTracers + nIceLayers
! snowEnthalpy
- snowEnthalpyCell(:,iCell) = tracerObject % tracerArrayCell(nTracers:nTracers+nSnowLayers-1)
+ snowEnthalpyCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nSnowLayers-1)
nTracers = nTracers + nSnowLayers
! ice Salinity
- iceSalinityCell(:,iCell) = tracerObject % tracerArrayCell(nTracers:nTracers+nIceLayers-1)
+ iceSalinityCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nIceLayers-1)
nTracers = nTracers + nIceLayers
! iceAge
if (config_use_ice_age) then
- iceAgeCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ iceAgeCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
endif
! firstYearIceArea
if (config_use_first_year_ice) then
- firstYearIceAreaCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ firstYearIceAreaCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
endif
! level ice tracers
if (config_use_level_ice) then
- levelIceAreaCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ levelIceAreaCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
- levelIceVolumeCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ levelIceVolumeCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
endif
@@ -6037,27 +7139,43 @@ subroutine get_cice_physics_tracer_array_cell(block, tracerObject, iCell)
if (config_use_cesm_meltponds .or. &
config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- pondAreaCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ pondAreaCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
- pondDepthCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ pondDepthCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
endif
! level or topo ponds
if (config_use_level_meltponds .or. &
config_use_topo_meltponds) then
- pondLidThicknessCell(iCell) = tracerObject % tracerArrayCell(nTracers)
+ pondLidThicknessCell(iCell) = tracerArrayCell(nTracers)
nTracers = nTracers + 1
end if
+ ! snow density (ice mass, liquid mass, density)
+ if (config_use_effective_snow_density) then
+ snowIceMassCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nSnowLayers-1)
+ nTracers = nTracers + nSnowLayers
+ snowLiquidMassCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nSnowLayers-1)
+ nTracers = nTracers + nSnowLayers
+ snowDensityCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nSnowLayers-1)
+ nTracers = nTracers + nSnowLayers
+ endif
+
+ ! snow grain radius
+ if (config_use_snow_grain_radius) then
+ snowGrainRadiusCell(:,iCell) = tracerArrayCell(nTracers:nTracers+nSnowLayers-1)
+ nTracers = nTracers + nSnowLayers
+ endif
+
! aerosols
if (config_use_aerosols) then
do iAerosol = 1, nAerosols
- snowScatteringAerosolCell(iAerosol,iCell) = tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1) )
- snowBodyAerosolCell(iAerosol,iCell) = tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1)+1)
- iceScatteringAerosolCell(iAerosol,iCell) = tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1)+2)
- iceBodyAerosolCell(iAerosol,iCell) = tracerObject % tracerArrayCell(nTracers+4*(iAerosol-1)+3)
+ snowScatteringAerosolCell(iAerosol,iCell) = tracerArrayCell(nTracers+4*(iAerosol-1) )
+ snowBodyAerosolCell(iAerosol,iCell) = tracerArrayCell(nTracers+4*(iAerosol-1)+1)
+ iceScatteringAerosolCell(iAerosol,iCell) = tracerArrayCell(nTracers+4*(iAerosol-1)+2)
+ iceBodyAerosolCell(iAerosol,iCell) = tracerArrayCell(nTracers+4*(iAerosol-1)+3)
enddo ! iAerosol
endif
@@ -6076,14 +7194,17 @@ end subroutine get_cice_physics_tracer_array_cell
!
!-----------------------------------------------------------------------
- subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, iCell)
+ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, tracerArrayCategory, iCell)
type(block_type), intent(in) :: &
block
- type(ciceTracerObjectType), intent(inout) :: &
+ type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:,:), intent(inout) :: &
+ tracerArrayCategory
+
integer, intent(in) :: &
iCell
@@ -6222,69 +7343,69 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! brine height fraction
if (config_use_brine) &
- tracerObject % tracerArrayCategory(tracerObject % index_brineFraction,:) = brineFraction(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_brineFraction,:) = brineFraction(1,:,iCell)
if (config_use_skeletal_biochemistry) then
! algal nitrogen
do iBioTracers = 1, nAlgae
- tracerObject % tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers),:) = &
+ tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers),:) = &
skeletalAlgaeConc(iBioTracers,:,iCell)
enddo
! nitrate
if (config_use_nitrate) &
- tracerObject % tracerArrayCategory(tracerObject % index_nitrateConc,:) = skeletalNitrateConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_nitrateConc,:) = skeletalNitrateConc(1,:,iCell)
! DOC
if (config_use_carbon) then
do iBioTracers = 1, nDOC
- tracerObject % tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers),:) = skeletalDOCConc(iBioTracers,:,iCell)
+ tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers),:) = skeletalDOCConc(iBioTracers,:,iCell)
enddo
! DIC
do iBioTracers = 1, nDIC
- tracerObject % tracerArrayCategory(tracerObject % index_DICConc(iBioTracers),:) = skeletalDICConc(iBioTracers,:,iCell)
+ tracerArrayCategory(tracerObject % index_DICConc(iBioTracers),:) = skeletalDICConc(iBioTracers,:,iCell)
enddo
endif
! DON
if (config_use_DON) then
do iBioTracers = 1, nDON
- tracerObject % tracerArrayCategory(tracerObject % index_DONConc(iBioTracers),:) = skeletalDONConc(iBioTracers,:,iCell)
+ tracerArrayCategory(tracerObject % index_DONConc(iBioTracers),:) = skeletalDONConc(iBioTracers,:,iCell)
enddo
endif
! ammonium
if (config_use_ammonium) &
- tracerObject % tracerArrayCategory(tracerObject % index_ammoniumConc,:) = skeletalAmmoniumConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_ammoniumConc,:) = skeletalAmmoniumConc(1,:,iCell)
! silicate
if (config_use_silicate) &
- tracerObject % tracerArrayCategory(tracerObject % index_silicateConc,:) = skeletalSilicateConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_silicateConc,:) = skeletalSilicateConc(1,:,iCell)
! DMS, DMSPp, DMSPd
if (config_use_DMS) then
- tracerObject % tracerArrayCategory(tracerObject % index_DMSConc,:) = skeletalDMSConc(1,:,iCell)
- tracerObject % tracerArrayCategory(tracerObject % index_DMSPpConc,:) = skeletalDMSPpConc(1,:,iCell)
- tracerObject % tracerArrayCategory(tracerObject % index_DMSPdConc,:) = skeletalDMSPdConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_DMSConc,:) = skeletalDMSConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_DMSPpConc,:) = skeletalDMSPpConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_DMSPdConc,:) = skeletalDMSPdConc(1,:,iCell)
endif
! nonreactive mobile tracer
if (config_use_nonreactive) &
- tracerObject % tracerArrayCategory(tracerObject % index_nonreactiveConc,:) = skeletalNonreactiveConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_nonreactiveConc,:) = skeletalNonreactiveConc(1,:,iCell)
! humic material
if (config_use_humics) &
- tracerObject % tracerArrayCategory(tracerObject % index_humicsConc,:) = skeletalHumicsConc(1,:,iCell)
+ tracerArrayCategory(tracerObject % index_humicsConc,:) = skeletalHumicsConc(1,:,iCell)
! Particulate and dissovled Iron
if (config_use_iron) then
do iBioTracers = 1, nParticulateIron
- tracerObject % tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers),:) = &
+ tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers),:) = &
skeletalParticulateIronConc(iBioTracers,:,iCell)
enddo
do iBioTracers = 1, nDissolvedIron
- tracerObject % tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers),:) = &
+ tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers),:) = &
skeletalDissolvedIronConc(iBioTracers,:,iCell)
enddo
endif
@@ -6293,7 +7414,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! Fraction of biogeochemical tracer in the mobile phase
do iLayers = 1, tracerObject % nBioTracers
- tracerObject % tracerArrayCategory(tracerObject % index_mobileFraction+iLayers-1,:) = mobileFraction(iLayers,:,iCell)
+ tracerArrayCategory(tracerObject % index_mobileFraction+iLayers-1,:) = mobileFraction(iLayers,:,iCell)
enddo
! algal nitrogen
@@ -6302,7 +7423,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nAlgae
do iLayers = 1,nBioLayersP3
iBiocount = iBiocount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers)+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers)+iLayers-1,:) = &
verticalAlgaeConc(iBioCount,:,iCell)
enddo
enddo
@@ -6311,7 +7432,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! nitrate
if (config_use_nitrate) then
do iLayers = 1, nBioLayersP3
- tracerObject % tracerArrayCategory(tracerObject % index_nitrateConc + iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_nitrateConc + iLayers-1,:) = &
verticalNitrateConc(iLayers,:,iCell)
enddo
endif
@@ -6322,7 +7443,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nDOC
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers) + iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers) + iLayers-1,:) = &
verticalDOCConc(iBioCount,:,iCell)
enddo
enddo
@@ -6332,7 +7453,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nDIC
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_DICConc(iBioTracers) + iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_DICConc(iBioTracers) + iLayers-1,:) = &
verticalDICConc(iBioCount,:,iCell)
enddo
enddo
@@ -6344,7 +7465,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nDON
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_DONConc(iBioTracers) + iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_DONConc(iBioTracers) + iLayers-1,:) = &
verticalDONConc(iBioCount,:,iCell)
enddo
enddo
@@ -6353,7 +7474,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! ammonium
if (config_use_ammonium) then
do iLayers = 1, nBioLayersP3
- tracerObject % tracerArrayCategory(tracerObject % index_ammoniumConc + iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_ammoniumConc + iLayers-1,:) = &
verticalAmmoniumConc(iLayers,:,iCell)
enddo
endif
@@ -6361,7 +7482,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! silicate
if (config_use_silicate) then
do iLayers = 1, nBioLayersP3
- tracerObject % tracerArrayCategory(tracerObject % index_silicateConc+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_silicateConc+iLayers-1,:) = &
verticalSilicateConc(iLayers,:,iCell)
enddo
endif
@@ -6369,16 +7490,16 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! DMS, DMSPp, DMSPd
if (config_use_DMS) then
do iLayers = 1, nBioLayersP3
- tracerObject % tracerArrayCategory(tracerObject % index_DMSConc+iLayers-1,:) = verticalDMSConc(iLayers,:,iCell)
- tracerObject % tracerArrayCategory(tracerObject % index_DMSPpConc+iLayers-1,:) = verticalDMSPpConc(iLayers,:,iCell)
- tracerObject % tracerArrayCategory(tracerObject % index_DMSPdConc+iLayers-1,:) = verticalDMSPdConc(iLayers,:,iCell)
+ tracerArrayCategory(tracerObject % index_DMSConc+iLayers-1,:) = verticalDMSConc(iLayers,:,iCell)
+ tracerArrayCategory(tracerObject % index_DMSPpConc+iLayers-1,:) = verticalDMSPpConc(iLayers,:,iCell)
+ tracerArrayCategory(tracerObject % index_DMSPdConc+iLayers-1,:) = verticalDMSPdConc(iLayers,:,iCell)
enddo
endif
! nonreactive purely mobile tracers
if (config_use_nonreactive) then
do iLayers = 1, nBioLayersP3
- tracerObject % tracerArrayCategory(tracerObject % index_nonreactiveConc+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_nonreactiveConc+iLayers-1,:) = &
verticalNonreactiveConc(iLayers,:,iCell)
enddo
endif
@@ -6386,7 +7507,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! humic material
if (config_use_humics) then
do iLayers = 1, nBioLayersP3
- tracerObject % tracerArrayCategory(tracerObject % index_humicsConc+iLayers-1,:) = verticalHumicsConc(iLayers,:,iCell)
+ tracerArrayCategory(tracerObject % index_humicsConc+iLayers-1,:) = verticalHumicsConc(iLayers,:,iCell)
enddo
endif
@@ -6396,7 +7517,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nParticulateIron
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1,:) = &
verticalParticulateIronConc(iBioCount,:,iCell)
enddo
enddo
@@ -6404,7 +7525,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nDissolvedIron
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1,:) = &
verticalDissolvedIronConc(iBioCount,:,iCell)
enddo
enddo
@@ -6416,7 +7537,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iBioTracers = 1, nzAerosols
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCategory(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1,:) = &
verticalAerosolsConc(iBioCount,:,iCell)
enddo
enddo
@@ -6425,7 +7546,7 @@ subroutine set_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! salinity used with BL99 thermodynamics
if (config_use_vertical_zsalinity) then
do iLayers = 1, nBioLayers
- tracerObject % tracerArrayCategory(tracerObject % index_verticalSalinity+iLayers-1,:) = &
+ tracerArrayCategory(tracerObject % index_verticalSalinity+iLayers-1,:) = &
verticalSalinity(iLayers,:,iCell)
enddo
endif
@@ -6445,7 +7566,7 @@ end subroutine set_cice_biogeochemistry_tracer_array_category
!
!-----------------------------------------------------------------------
- subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, iCell)
+ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, tracerArrayCategory, iCell)
type(block_type), intent(inout) :: &
block
@@ -6453,6 +7574,9 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ tracerArrayCategory
+
integer, intent(in) :: &
iCell
@@ -6590,74 +7714,74 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! biogeochemistry
! brine height fraction
if (config_use_brine) &
- brineFraction(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_brineFraction,:)
+ brineFraction(1,:,iCell) = tracerArrayCategory(tracerObject % index_brineFraction,:)
if (config_use_skeletal_biochemistry) then
! algal nitrogen
do iBioTracers = 1, nAlgae
skeletalAlgaeConc(iBioTracers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers),:)
+ tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers),:)
enddo
! nitrate
if (config_use_nitrate) &
- skeletalNitrateConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_nitrateConc,:)
+ skeletalNitrateConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_nitrateConc,:)
if (config_use_carbon) then
! DOC
do iBioTracers = 1, nDOC
skeletalDOCConc(iBioTracers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers),:)
+ tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers),:)
enddo
! DIC
do iBioTracers = 1, nDIC
skeletalDICConc(iBioTracers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_DICConc(iBioTracers),:)
+ tracerArrayCategory(tracerObject % index_DICConc(iBioTracers),:)
enddo
endif
! DON
if (config_use_DON) then
do iBioTracers = 1, nDON
- skeletalDONConc(iBioTracers,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DONConc(iBioTracers),:)
+ skeletalDONConc(iBioTracers,:,iCell) = tracerArrayCategory(tracerObject % index_DONConc(iBioTracers),:)
enddo
endif
! ammonium
if (config_use_ammonium) &
- skeletalAmmoniumConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_ammoniumConc,:)
+ skeletalAmmoniumConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_ammoniumConc,:)
! silicate
if (config_use_silicate) &
- skeletalSilicateConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_silicateConc,:)
+ skeletalSilicateConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_silicateConc,:)
! DNS, DMSPp, DMSPd
if (config_use_DMS) then
- skeletalDMSConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DMSConc,:)
- skeletalDMSPpConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DMSPpConc,:)
- skeletalDMSPdConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DMSPdConc,:)
+ skeletalDMSConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_DMSConc,:)
+ skeletalDMSPpConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_DMSPpConc,:)
+ skeletalDMSPdConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_DMSPdConc,:)
endif
! nonreactive tracer
if (config_use_nonreactive) &
- skeletalNonreactiveConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_nonreactiveConc,:)
+ skeletalNonreactiveConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_nonreactiveConc,:)
! humic material
if (config_use_humics) &
- skeletalHumicsConc(1,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_humicsConc,:)
+ skeletalHumicsConc(1,:,iCell) = tracerArrayCategory(tracerObject % index_humicsConc,:)
if (config_use_iron) then
! Particulate Iron
do iBioTracers = 1, nParticulateIron
skeletalParticulateIronConc(iBioTracers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers),:)
+ tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers),:)
enddo
! Dissolved Iron
do iBioTracers = 1, nDissolvedIron
skeletalDissolvedIronConc(iBioTracers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers),:)
+ tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers),:)
enddo
endif
@@ -6665,7 +7789,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
! fraction of biogeochemical tracer in the mobile phase
do iLayers = 1, tracerObject % nBioTracers
- mobileFraction(iLayers,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_mobileFraction+iLayers-1,:)
+ mobileFraction(iLayers,:,iCell) = tracerArrayCategory(tracerObject % index_mobileFraction+iLayers-1,:)
enddo
if (config_use_vertical_biochemistry) then
@@ -6676,7 +7800,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBiocount = iBiocount + 1
verticalAlgaeConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers)+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_algaeConc(iBioTracers)+iLayers-1,:)
enddo
enddo
endif
@@ -6685,7 +7809,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
if (config_use_nitrate) then
do iLayers = 1, nBioLayersP3
verticalNitrateConc(iLayers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_nitrateConc + iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_nitrateConc + iLayers-1,:)
enddo
endif
@@ -6697,7 +7821,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDOCConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers) + iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_DOCConc(iBioTracers) + iLayers-1,:)
enddo
enddo
iBioCount = 0
@@ -6707,7 +7831,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDICConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_DICConc(iBioTracers) + iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_DICConc(iBioTracers) + iLayers-1,:)
enddo
enddo
endif
@@ -6719,7 +7843,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDONConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_DONConc(iBioTracers) + iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_DONConc(iBioTracers) + iLayers-1,:)
enddo
enddo
endif
@@ -6728,7 +7852,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
if (config_use_ammonium) then
do iLayers = 1, nBioLayersP3
verticalAmmoniumConc(iLayers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_ammoniumConc + iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_ammoniumConc + iLayers-1,:)
enddo
endif
@@ -6736,16 +7860,16 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
if (config_use_silicate) then
do iLayers = 1, nBioLayersP3
verticalSilicateConc(iLayers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_silicateConc+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_silicateConc+iLayers-1,:)
enddo
endif
! DMS, DMSPp, DMSPd
if (config_use_DMS) then
do iLayers = 1, nBioLayersP3
- verticalDMSConc(iLayers,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DMSConc+iLayers-1,:)
- verticalDMSPpConc(iLayers,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DMSPpConc+iLayers-1,:)
- verticalDMSPdConc(iLayers,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_DMSPdConc+iLayers-1,:)
+ verticalDMSConc(iLayers,:,iCell) = tracerArrayCategory(tracerObject % index_DMSConc+iLayers-1,:)
+ verticalDMSPpConc(iLayers,:,iCell) = tracerArrayCategory(tracerObject % index_DMSPpConc+iLayers-1,:)
+ verticalDMSPdConc(iLayers,:,iCell) = tracerArrayCategory(tracerObject % index_DMSPdConc+iLayers-1,:)
enddo
endif
@@ -6753,14 +7877,14 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
if (config_use_nonreactive) then
do iLayers = 1, nBioLayersP3
verticalNonreactiveConc(iLayers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_nonreactiveConc+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_nonreactiveConc+iLayers-1,:)
enddo
endif
! humic material
if (config_use_humics) then
do iLayers = 1, nBioLayersP3
- verticalHumicsConc(iLayers,:,iCell) = tracerObject % tracerArrayCategory(tracerObject % index_humicsConc+iLayers-1,:)
+ verticalHumicsConc(iLayers,:,iCell) = tracerArrayCategory(tracerObject % index_humicsConc+iLayers-1,:)
enddo
endif
@@ -6772,7 +7896,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
verticalParticulateIronConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1,:)
enddo
enddo
iBioCount = 0
@@ -6782,7 +7906,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDissolvedIronConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1,:)
enddo
enddo
endif
@@ -6794,7 +7918,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
do iLayers = 1,nBioLayersP3
iBioCount = iBioCount + 1
verticalAerosolsConc(iBioCount,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1,:)
enddo
enddo
endif
@@ -6803,7 +7927,7 @@ subroutine get_cice_biogeochemistry_tracer_array_category(block, tracerObject, i
if (config_use_vertical_zsalinity) then
do iLayers = 1, nBioLayers
verticalSalinity(iLayers,:,iCell) = &
- tracerObject % tracerArrayCategory(tracerObject % index_verticalSalinity+iLayers-1,:)
+ tracerArrayCategory(tracerObject % index_verticalSalinity+iLayers-1,:)
enddo
endif
endif
@@ -6822,14 +7946,17 @@ end subroutine get_cice_biogeochemistry_tracer_array_category
!
!-----------------------------------------------------------------------
- subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell)
+ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, tracerArrayCell, iCell)
type(block_type), intent(in) :: &
block
- type(ciceTracerObjectType), intent(inout) :: &
+ type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:), intent(inout) :: &
+ tracerArrayCell
+
integer, intent(in) :: &
iCell
@@ -7002,72 +8129,72 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! biogeochemistry
! brine height fraction
if (config_use_brine) &
- tracerObject % tracerArrayCell(tracerObject % index_brineFraction) = brineFractionCell(iCell)
+ tracerArrayCell(tracerObject % index_brineFraction) = brineFractionCell(iCell)
if (config_use_skeletal_biochemistry) then
! algal nitrogen
do iBioTracers = 1, nAlgae
- tracerObject % tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)) = skeletalAlgaeConcCell(iBioTracers,iCell)
+ tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)) = skeletalAlgaeConcCell(iBioTracers,iCell)
enddo
! nitrate
if (config_use_nitrate) &
- tracerObject % tracerArrayCell(tracerObject % index_nitrateConc) = skeletalNitrateConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_nitrateConc) = skeletalNitrateConcCell(1,iCell)
if (config_use_carbon) then
! DOC
do iBioTracers = 1, nDOC
- tracerObject % tracerArrayCell(tracerObject % index_DOCConc(iBioTracers)) = skeletalDOCConcCell(iBioTracers,iCell)
+ tracerArrayCell(tracerObject % index_DOCConc(iBioTracers)) = skeletalDOCConcCell(iBioTracers,iCell)
enddo
! DIC
do iBioTracers = 1, nDIC
- tracerObject % tracerArrayCell(tracerObject % index_DICConc(iBioTracers)) = skeletalDICConcCell(iBioTracers,iCell)
+ tracerArrayCell(tracerObject % index_DICConc(iBioTracers)) = skeletalDICConcCell(iBioTracers,iCell)
enddo
endif
! DON
if (config_use_DON) then
do iBioTracers = 1, nDON
- tracerObject % tracerArrayCell(tracerObject % index_DONConc(iBioTracers)) = skeletalDONConcCell(iBioTracers,iCell)
+ tracerArrayCell(tracerObject % index_DONConc(iBioTracers)) = skeletalDONConcCell(iBioTracers,iCell)
enddo
endif
! ammonium
if (config_use_ammonium) &
- tracerObject % tracerArrayCell(tracerObject % index_ammoniumConc) = skeletalAmmoniumConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_ammoniumConc) = skeletalAmmoniumConcCell(1,iCell)
! silicate
if (config_use_silicate) &
- tracerObject % tracerArrayCell(tracerObject % index_silicateConc) = skeletalSilicateConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_silicateConc) = skeletalSilicateConcCell(1,iCell)
! DMS, DMSPp, DMSPd
if (config_use_DMS) then
- tracerObject % tracerArrayCell(tracerObject % index_DMSConc) = skeletalDMSConcCell(1,iCell)
- tracerObject % tracerArrayCell(tracerObject % index_DMSPpConc) = skeletalDMSPpConcCell(1,iCell)
- tracerObject % tracerArrayCell(tracerObject % index_DMSPdConc) = skeletalDMSPdConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_DMSConc) = skeletalDMSConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_DMSPpConc) = skeletalDMSPpConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_DMSPdConc) = skeletalDMSPdConcCell(1,iCell)
endif
! nonreactive tracer
if (config_use_nonreactive) &
- tracerObject % tracerArrayCell(tracerObject % index_nonreactiveConc) = skeletalNonreactiveConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_nonreactiveConc) = skeletalNonreactiveConcCell(1,iCell)
! humic material
if (config_use_humics) &
- tracerObject % tracerArrayCell(tracerObject % index_humicsConc) = skeletalHumicsConcCell(1,iCell)
+ tracerArrayCell(tracerObject % index_humicsConc) = skeletalHumicsConcCell(1,iCell)
if (config_use_iron) then
! particulate iron
do iBioTracers = 1, nParticulateIron
- tracerObject % tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)) = &
+ tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)) = &
skeletalParticulateIronConcCell(iBioTracers,iCell)
enddo
! dissolved iron
do iBioTracers = 1, nDissolvedIron
- tracerObject % tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)) = &
+ tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)) = &
skeletalDissolvedIronConcCell(iBioTracers,iCell)
enddo
endif
@@ -7083,13 +8210,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBiocount = iBiocount + 1
- tracerObject % tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1) = &
verticalAlgaeConcCell(iBioCount,iCell)
verticalAlgaeIceCell(iLayers+iIceCount,iCell) = verticalAlgaeConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBiocount = iBiocount + 1
- tracerObject % tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1) = &
verticalAlgaeConcCell(iBioCount,iCell)
enddo
enddo
@@ -7098,11 +8225,11 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! nitrate
if (config_use_nitrate) then
do iLayers = 1, nBioLayersP1
- tracerObject % tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1) = verticalNitrateConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1) = verticalNitrateConcCell(iLayers,iCell)
verticalNitrateIceCell(iLayers,iCell) = verticalNitrateConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- tracerObject % tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1) = verticalNitrateConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1) = verticalNitrateConcCell(iLayers,iCell)
enddo
endif
@@ -7115,13 +8242,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1) = &
verticalDOCConcCell(iBioCount,iCell)
verticalDOCIceCell(iLayers+iIceCount,iCell) = verticalDOCConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1) = &
verticalDOCConcCell(iBioCount,iCell)
enddo
enddo
@@ -7133,13 +8260,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1) = &
verticalDICConcCell(iBioCount,iCell)
verticalDICIceCell(iLayers+iIceCount,iCell) = verticalDICConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1) = &
verticalDICConcCell(iBioCount,iCell)
enddo
enddo
@@ -7153,13 +8280,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1) = &
verticalDONConcCell(iBioCount,iCell)
verticalDONIceCell(iLayers+iIceCount,iCell) = verticalDONConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1) = &
verticalDONConcCell(iBioCount,iCell)
enddo
enddo
@@ -7168,12 +8295,12 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! ammonium
if (config_use_ammonium) then
do iLayers = 1, nBioLayersP1
- tracerObject % tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1) = &
verticalAmmoniumConcCell(iLayers,iCell)
verticalAmmoniumIceCell(iLayers,iCell) = verticalAmmoniumConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- tracerObject % tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1) = &
+ tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1) = &
verticalAmmoniumConcCell(iLayers,iCell)
enddo
endif
@@ -7181,40 +8308,40 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! silicate
if (config_use_silicate) then
do iLayers = 1, nBioLayersP1
- tracerObject % tracerArrayCell(tracerObject % index_silicateConc+iLayers-1) = verticalSilicateConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_silicateConc+iLayers-1) = verticalSilicateConcCell(iLayers,iCell)
verticalSilicateIceCell(iLayers,iCell) = verticalSilicateConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- tracerObject % tracerArrayCell(tracerObject % index_silicateConc+iLayers-1) = verticalSilicateConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_silicateConc+iLayers-1) = verticalSilicateConcCell(iLayers,iCell)
enddo
endif
! DMS, DMSPp, DMSPd
if (config_use_DMS) then
do iLayers = 1, nBioLayersP1
- tracerObject % tracerArrayCell(tracerObject % index_DMSConc+iLayers-1) = verticalDMSConcCell(iLayers,iCell)
- tracerObject % tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1) = verticalDMSPpConcCell(iLayers,iCell)
- tracerObject % tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1) = verticalDMSPdConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_DMSConc+iLayers-1) = verticalDMSConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1) = verticalDMSPpConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1) = verticalDMSPdConcCell(iLayers,iCell)
verticalDMSIceCell(iLayers,iCell) = verticalDMSConcCell(iLayers,iCell)
verticalDMSPpIceCell(iLayers,iCell) = verticalDMSPpConcCell(iLayers,iCell)
verticalDMSPdIceCell(iLayers,iCell) = verticalDMSPdConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- tracerObject % tracerArrayCell(tracerObject % index_DMSConc+iLayers-1) = verticalDMSConcCell(iLayers,iCell)
- tracerObject % tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1) = verticalDMSPpConcCell(iLayers,iCell)
- tracerObject % tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1) = verticalDMSPdConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_DMSConc+iLayers-1) = verticalDMSConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1) = verticalDMSPpConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1) = verticalDMSPdConcCell(iLayers,iCell)
enddo
endif
! nonreactive
if (config_use_nonreactive) then
do iLayers = 1, nBioLayersP1
- tracerObject % tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1) = &
verticalNonreactiveConcCell(iLayers,iCell)
verticalNonreactiveIceCell(iLayers,iCell) = verticalNonreactiveConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- tracerObject % tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1) = &
verticalNonreactiveConcCell(iLayers,iCell)
enddo
endif
@@ -7222,11 +8349,11 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! humic material
if (config_use_humics) then
do iLayers = 1, nBioLayersP1
- tracerObject % tracerArrayCell(tracerObject % index_humicsConc+iLayers-1) = verticalHumicsConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_humicsConc+iLayers-1) = verticalHumicsConcCell(iLayers,iCell)
verticalHumicsIceCell(iLayers,iCell) = verticalHumicsConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- tracerObject % tracerArrayCell(tracerObject % index_humicsConc+iLayers-1) = verticalHumicsConcCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_humicsConc+iLayers-1) = verticalHumicsConcCell(iLayers,iCell)
enddo
endif
@@ -7239,13 +8366,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1) = &
verticalParticulateIronConcCell(iBioCount,iCell)
verticalParticulateIronIceCell(iLayers+iIceCount,iCell) = verticalParticulateIronConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1) = &
verticalParticulateIronConcCell(iBioCount,iCell)
enddo
enddo
@@ -7257,13 +8384,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1) = &
verticalDissolvedIronConcCell(iBioCount,iCell)
verticalDissolvedIronIceCell(iLayers+iIceCount,iCell) = verticalDissolvedIronConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1) = &
verticalDissolvedIronConcCell(iBioCount,iCell)
enddo
enddo
@@ -7277,13 +8404,13 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1) = &
verticalAerosolsConcCell(iBioCount,iCell)
verticalAerosolsIceCell(iLayers+iIceCount,iCell) = verticalAerosolsConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
- tracerObject % tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1) = &
+ tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1) = &
verticalAerosolsConcCell(iBioCount,iCell)
enddo
enddo
@@ -7292,7 +8419,7 @@ subroutine set_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! salinity for use with BL99 thermodynamics
if (config_use_vertical_zsalinity) then
do iLayers = 1, nBioLayers
- tracerObject % tracerArrayCell(tracerObject % index_verticalSalinity+iLayers-1) = verticalSalinityCell(iLayers,iCell)
+ tracerArrayCell(tracerObject % index_verticalSalinity+iLayers-1) = verticalSalinityCell(iLayers,iCell)
enddo
endif
endif
@@ -7311,7 +8438,7 @@ end subroutine set_cice_biogeochemistry_tracer_array_cell
!
!-----------------------------------------------------------------------
- subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell)
+ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, tracerArrayCell, iCell)
type(block_type), intent(inout) :: &
block
@@ -7319,6 +8446,9 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
type(ciceTracerObjectType), intent(in) :: &
tracerObject
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ tracerArrayCell
+
integer, intent(in) :: &
iCell
@@ -7402,13 +8532,15 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
verticalHumicsIceCell, &
verticalParticulateIronIceCell, &
verticalDissolvedIronIceCell, &
- verticalAerosolsIceCell
+ verticalAerosolsIceCell, &
+ verticalAerosolsSnowCell
integer :: &
iBioTracers, &
iBioCount, &
iLayers, &
- iIceCount
+ iIceCount, &
+ iSnowCount
call MPAS_pool_get_config(block % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry)
call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
@@ -7483,79 +8615,80 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
call MPAS_pool_get_array(tracers_aggregate, "verticalParticulateIronIceCell", verticalParticulateIronIceCell)
call MPAS_pool_get_array(tracers_aggregate, "verticalDissolvedIronIceCell", verticalDissolvedIronIceCell)
call MPAS_pool_get_array(tracers_aggregate, "verticalAerosolsIceCell", verticalAerosolsIceCell)
+ call MPAS_pool_get_array(tracers_aggregate, "verticalAerosolsSnowCell", verticalAerosolsSnowCell)
call MPAS_pool_get_array(tracers_aggregate, "verticalSalinityCell", verticalSalinityCell)
call MPAS_pool_get_array(tracers_aggregate, "brineFractionCell", brineFractionCell)
! biogeochemistry
! brine height fraction
if (config_use_brine) &
- brineFractionCell(iCell) = tracerObject % tracerArrayCell(tracerObject % index_brineFraction)
+ brineFractionCell(iCell) = tracerArrayCell(tracerObject % index_brineFraction)
if (config_use_skeletal_biochemistry) then
! algal nitrogen
do iBioTracers = 1, nAlgae
- skeletalAlgaeConcCell(iBioTracers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_algaeConc(iBioTracers))
+ skeletalAlgaeConcCell(iBioTracers,iCell) = tracerArrayCell(tracerObject % index_algaeConc(iBioTracers))
enddo
! nitrate
if (config_use_nitrate) &
- skeletalNitrateConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_nitrateConc)
+ skeletalNitrateConcCell(1,iCell) = tracerArrayCell(tracerObject % index_nitrateConc)
if (config_use_carbon) then
! DOC
do iBioTracers = 1, nDOC
- skeletalDOCConcCell(iBioTracers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DOCConc(iBioTracers))
+ skeletalDOCConcCell(iBioTracers,iCell) = tracerArrayCell(tracerObject % index_DOCConc(iBioTracers))
enddo
! DIC
do iBioTracers = 1, nDIC
- skeletalDICConcCell(iBioTracers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DICConc(iBioTracers))
+ skeletalDICConcCell(iBioTracers,iCell) = tracerArrayCell(tracerObject % index_DICConc(iBioTracers))
enddo
endif
! DON
if (config_use_DON) then
do iBioTracers = 1, nDON
- skeletalDONConcCell(iBioTracers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DONConc(iBioTracers))
+ skeletalDONConcCell(iBioTracers,iCell) = tracerArrayCell(tracerObject % index_DONConc(iBioTracers))
enddo
endif
! ammonium
if (config_use_ammonium) &
- skeletalAmmoniumConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_ammoniumConc)
+ skeletalAmmoniumConcCell(1,iCell) = tracerArrayCell(tracerObject % index_ammoniumConc)
! silicate
if (config_use_silicate) &
- skeletalSilicateConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_silicateConc)
+ skeletalSilicateConcCell(1,iCell) = tracerArrayCell(tracerObject % index_silicateConc)
! DMS
if (config_use_DMS) then
- skeletalDMSConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSConc)
- skeletalDMSPpConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSPpConc)
- skeletalDMSPdConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSPdConc)
+ skeletalDMSConcCell(1,iCell) = tracerArrayCell(tracerObject % index_DMSConc)
+ skeletalDMSPpConcCell(1,iCell) = tracerArrayCell(tracerObject % index_DMSPpConc)
+ skeletalDMSPdConcCell(1,iCell) = tracerArrayCell(tracerObject % index_DMSPdConc)
endif
! nonreactive tracer
if (config_use_nonreactive) &
- skeletalNonreactiveConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_nonreactiveConc)
+ skeletalNonreactiveConcCell(1,iCell) = tracerArrayCell(tracerObject % index_nonreactiveConc)
! humic material
if (config_use_humics) &
- skeletalHumicsConcCell(1,iCell) = tracerObject % tracerArrayCell(tracerObject % index_humicsConc)
+ skeletalHumicsConcCell(1,iCell) = tracerArrayCell(tracerObject % index_humicsConc)
if (config_use_iron) then
! particulate iron
do iBioTracers = 1, nParticulateIron
skeletalParticulateIronConcCell(iBioTracers,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers))
+ tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers))
enddo
! dissolved iron
do iBioTracers = 1, nDissolvedIron
skeletalDissolvedIronConcCell(iBioTracers,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers))
+ tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers))
enddo
endif
@@ -7571,13 +8704,13 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBiocount = iBiocount + 1
verticalAlgaeConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1)
verticalAlgaeIceCell(iLayers+iIceCount,iCell) = verticalAlgaeConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBiocount = iBiocount + 1
verticalAlgaeConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_algaeConc(iBioTracers)+iLayers-1)
enddo
enddo
endif
@@ -7585,11 +8718,11 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! nitrate
if (config_use_nitrate) then
do iLayers = 1, nBioLayersP1
- verticalNitrateConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1)
+ verticalNitrateConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1)
verticalNitrateIceCell(iLayers,iCell) = verticalNitrateConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- verticalNitrateConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1)
+ verticalNitrateConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_nitrateConc + iLayers-1)
enddo
endif
@@ -7603,13 +8736,13 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
verticalDOCConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1)
+ tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1)
verticalDOCIceCell(iLayers+iIceCount,iCell) = verticalDOCConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDOCConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1)
+ tracerArrayCell(tracerObject % index_DOCConc(iBioTracers) + iLayers-1)
enddo
enddo
iBioCount = 0
@@ -7621,13 +8754,13 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
verticalDICConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1)
+ tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1)
verticalDICIceCell(iLayers+iIceCount,iCell) = verticalDICConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDICConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1)
+ tracerArrayCell(tracerObject % index_DICConc(iBioTracers) + iLayers-1)
enddo
enddo
endif
@@ -7641,13 +8774,13 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
verticalDONConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1)
+ tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1)
verticalDONIceCell(iLayers+iIceCount,iCell) = verticalDONConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDONConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1)
+ tracerArrayCell(tracerObject % index_DONConc(iBioTracers) + iLayers-1)
enddo
enddo
endif
@@ -7656,40 +8789,40 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
if (config_use_ammonium) then
do iLayers = 1, nBioLayersP1
verticalAmmoniumConcCell(iLayers,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1)
+ tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1)
verticalAmmoniumIceCell(iLayers,iCell) = verticalAmmoniumConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
verticalAmmoniumConcCell(iLayers,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1)
+ tracerArrayCell(tracerObject % index_ammoniumConc + iLayers-1)
enddo
endif
! silicate
if (config_use_silicate) then
do iLayers = 1, nBioLayersP1
- verticalSilicateConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_silicateConc+iLayers-1)
+ verticalSilicateConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_silicateConc+iLayers-1)
verticalSilicateIceCell(iLayers,iCell) = verticalSilicateConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- verticalSilicateConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_silicateConc+iLayers-1)
+ verticalSilicateConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_silicateConc+iLayers-1)
enddo
endif
! DMS, DMSPp, DMSPd
if (config_use_DMS) then
do iLayers = 1, nBioLayersP1
- verticalDMSConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSConc+iLayers-1)
- verticalDMSPpConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1)
- verticalDMSPdConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1)
+ verticalDMSConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_DMSConc+iLayers-1)
+ verticalDMSPpConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1)
+ verticalDMSPdConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1)
verticalDMSIceCell(iLayers,iCell) = verticalDMSConcCell(iLayers,iCell)
verticalDMSPpIceCell(iLayers,iCell) = verticalDMSPpConcCell(iLayers,iCell)
verticalDMSPdIceCell(iLayers,iCell) = verticalDMSPdConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- verticalDMSConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSConc+iLayers-1)
- verticalDMSPpConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1)
- verticalDMSPdConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1)
+ verticalDMSConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_DMSConc+iLayers-1)
+ verticalDMSPpConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_DMSPpConc+iLayers-1)
+ verticalDMSPdConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_DMSPdConc+iLayers-1)
enddo
endif
@@ -7697,23 +8830,23 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
if (config_use_nonreactive) then
do iLayers = 1, nBioLayersP1
verticalNonreactiveConcCell(iLayers,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1)
+ tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1)
verticalNonreactiveIceCell(iLayers,iCell) = verticalNonreactiveConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
verticalNonreactiveConcCell(iLayers,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1)
+ tracerArrayCell(tracerObject % index_nonreactiveConc+iLayers-1)
enddo
endif
! humic material
if (config_use_humics) then
do iLayers = 1, nBioLayersP1
- verticalHumicsConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_humicsConc+iLayers-1)
+ verticalHumicsConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_humicsConc+iLayers-1)
verticalHumicsIceCell(iLayers,iCell) = verticalHumicsConcCell(iLayers,iCell)
enddo
do iLayers = nBioLayersP1+1, nBioLayersP3
- verticalHumicsConcCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_humicsConc+iLayers-1)
+ verticalHumicsConcCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_humicsConc+iLayers-1)
enddo
endif
@@ -7727,13 +8860,13 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
verticalParticulateIronConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1)
verticalDissolvedIronIceCell(iLayers+iIceCount,iCell) = verticalDissolvedIronConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
verticalParticulateIronConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_particulateIronConc(iBioTracers)+iLayers-1)
enddo
enddo
iBioCount = 0
@@ -7745,13 +8878,13 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
verticalDissolvedIronConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1)
verticalDissolvedIronIceCell(iLayers+iIceCount,iCell) = verticalDissolvedIronConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
verticalDissolvedIronConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_dissolvedIronConc(iBioTracers)+iLayers-1)
enddo
enddo
endif
@@ -7761,17 +8894,20 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
iBioCount = 0
do iBioTracers = 1, nzAerosols
iIceCount = (iBioTracers-1)*nBioLayersP1
+ iSnowCount = (iBioTracers-1)*2
do iLayers = 1,nBioLayersP1
iBioCount = iBioCount + 1
verticalAerosolsConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1)
verticalAerosolsIceCell(iLayers+iIceCount,iCell) = verticalAerosolsConcCell(iBioCount,iCell)
enddo
do iLayers = nBioLayersP1+1,nBioLayersP3
iBioCount = iBioCount + 1
verticalAerosolsConcCell(iBioCount,iCell) = &
- tracerObject % tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1)
+ tracerArrayCell(tracerObject % index_verticalAerosolsConc(iBioTracers)+iLayers-1)
+ verticalAerosolsSnowCell(iLayers-nBioLayersP1+iSnowCount,iCell) = &
+ verticalAerosolsConcCell(iBioCount,iCell)
enddo
enddo
endif
@@ -7779,7 +8915,7 @@ subroutine get_cice_biogeochemistry_tracer_array_cell(block, tracerObject, iCell
! salinity for use with BL99 thermodynamics
if (config_use_vertical_zsalinity) then
do iLayers = 1, nBioLayers
- verticalSalinityCell(iLayers,iCell) = tracerObject % tracerArrayCell(tracerObject % index_verticalSalinity+iLayers-1)
+ verticalSalinityCell(iLayers,iCell) = tracerArrayCell(tracerObject % index_verticalSalinity+iLayers-1)
enddo
endif
endif
@@ -7847,7 +8983,11 @@ subroutine check_column_package_configs(domain)
domain
integer, pointer :: &
- nCategories
+ nCategories, &
+ nSnowLayers, &
+ nIceLayers, &
+ config_nSnowLayers, &
+ config_nIceLayers
character(len=strKIND), pointer :: &
config_thermodynamics_type, &
@@ -7904,6 +9044,8 @@ subroutine check_column_package_configs(domain)
config_snow_to_ice_transition_depth
call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nCategories", nCategories)
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nSnowLayers", nSnowLayers)
+ call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nIceLayers", nIceLayers)
call MPAS_pool_get_config(domain % configs, "config_thermodynamics_type", config_thermodynamics_type)
call MPAS_pool_get_config(domain % configs, "config_heat_conductivity_type", config_heat_conductivity_type)
@@ -7947,6 +9089,8 @@ subroutine check_column_package_configs(domain)
call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols", config_use_modal_aerosols)
call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols)
call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+ call MPAS_pool_get_config(domain % configs, "config_nSnowLayers", config_nSnowLayers)
+ call MPAS_pool_get_config(domain % configs, "config_nIceLayers", config_nIceLayers)
!-----------------------------------------------------------------------
! Check values
@@ -8025,6 +9169,18 @@ subroutine check_column_package_configs(domain)
call config_error("config_pond_refreezing_type", config_pond_refreezing_type, "'cesm' or 'hlid'")
endif
+ ! check for consistency in snow vertical dimension
+ if (config_nSnowLayers /= nSnowlayers) &
+ call mpas_log_write(&
+ 'Check for inconsistencies in restart file: config_nSnowLayers /= nSnowLayers', &
+ messageType=MPAS_LOG_CRIT)
+
+ ! check for consistency in ice vertical dimension
+ if (config_nIceLayers /= nIcelayers) &
+ call mpas_log_write(&
+ 'Check for inconsistencies in restart file: config_nIceLayers /= nIceLayers', &
+ messageType=MPAS_LOG_CRIT)
+
!-----------------------------------------------------------------------
! Check combinations
!-----------------------------------------------------------------------
@@ -8259,7 +9415,9 @@ subroutine init_column_package_tracer_flags(domain)
config_use_humics, &
config_use_nonreactive, &
config_use_vertical_biochemistry, &
- config_use_skeletal_biochemistry
+ config_use_skeletal_biochemistry, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius
logical :: &
use_meltponds, &
@@ -8287,6 +9445,8 @@ subroutine init_column_package_tracer_flags(domain)
call MPAS_pool_get_config(domain % configs, "config_use_nonreactive", config_use_nonreactive)
call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry)
call MPAS_pool_get_config(domain % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
+ call MPAS_pool_get_config(domain % configs, "config_use_effective_snow_density", config_use_effective_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius)
use_nitrogen = .false.
if (config_use_skeletal_biochemistry .or. config_use_vertical_biochemistry) &
@@ -8302,6 +9462,8 @@ subroutine init_column_package_tracer_flags(domain)
config_use_cesm_meltponds, &
config_use_level_meltponds, &
config_use_topo_meltponds, &
+ config_use_effective_snow_density, &
+ config_use_snow_grain_radius, &
config_use_aerosols, &
config_use_brine, &
config_use_vertical_zsalinity, &
@@ -8325,6 +9487,8 @@ subroutine init_column_package_tracer_flags(domain)
!tr_pond_cesm = config_use_cesm_meltponds
!tr_pond_lvl = config_use_level_meltponds
!tr_pond_topo = config_use_topo_meltponds
+ !tr_snow = config_use_effective_snow_density
+ !tr_rsnw = config_use_snow_grain_radius
!tr_aero = config_use_aerosols
!tr_brine = config_use_brine
!tr_bgc_S = config_use_vertical_zsalinity
@@ -8407,6 +9571,10 @@ subroutine init_column_package_tracer_indices(tracerObject)
! nt_hpnd, & ! melt pond depth
! nt_ipnd, & ! melt pond refrozen lid thickness
! nt_aero, & ! starting index for aerosols in ice
+ ! nt_smice, & ! snow ice mass
+ ! nt_smliq, & ! snow liquid mass
+ ! nt_rsnw, & ! snow grain radius
+ ! nt_rhos, & ! snow density tracer
! nt_fbri, & ! volume fraction of ice with dynamic salt (hinS/vicen*aicen)
! nt_bgc_Nit, & ! nutrients
! nt_bgc_Am, & !
@@ -8468,6 +9636,10 @@ subroutine init_column_package_tracer_indices(tracerObject)
tracerObject % index_pondDepth, &
tracerObject % index_pondLidThickness, &
tracerObject % index_aerosols, &
+ tracerObject % index_snowIceMass, &
+ tracerObject % index_snowLiquidMass, &
+ tracerObject % index_snowGrainRadius, &
+ tracerObject % index_snowDensity, &
tracerObject % index_verticalAerosolsConc, &
tracerObject % index_algaeConc, &
tracerObject % index_algalCarbon, &
@@ -8531,6 +9703,10 @@ subroutine init_column_package_tracer_indices(tracerObject)
!nt_hpnd = tracerObject % index_pondDepth
!nt_ipnd = tracerObject % index_pondLidThickness
!nt_aero = tracerObject % index_aerosols
+ !nt_smice = tracerObject % index_snowIceMass
+ !nt_rsnw = tracerObject % index_snowGrainRadius
+ !nt_rhos = tracerObject % index_snowDensity
+ !nt_smliq = tracerObject % index_snowLiquidMass
!nt_fbri = tracerObject % index_brineFraction
!nt_zaeros = tracerObject % index_verticalAerosolsConc
!nt_bgc_N = tracerObject % index_algaeConc
@@ -8776,7 +9952,7 @@ subroutine init_column_package_configs(domain)
! F_abs_chl_diatoms , &
! F_abs_chl_sp , &
! F_abs_chl_phaeo , &
- ! ratio_C2N_proteins
+ ! ratio_C2N_proteins
use ice_colpkg, only: &
colpkg_init_parameters
@@ -8798,7 +9974,8 @@ subroutine init_column_package_configs(domain)
config_pond_refreezing_type, &
config_ocean_heat_transfer_type, &
config_sea_freezing_temperature_type, &
- config_skeletal_bgc_flux_type
+ config_skeletal_bgc_flux_type, &
+ config_snow_redistribution_scheme
logical, pointer :: &
config_calc_surface_temperature, &
@@ -8812,7 +9989,9 @@ subroutine init_column_package_configs(domain)
config_use_shortwave_bioabsorption, &
config_use_skeletal_biochemistry, &
config_use_vertical_zsalinity, &
- config_use_modal_aerosols
+ config_use_modal_aerosols, &
+ config_use_snicar_ad, &
+ config_use_snow_liquid_ponds
real(kind=RKIND), pointer :: &
config_min_friction_velocity, &
@@ -8945,6 +10124,7 @@ subroutine init_column_package_configs(domain)
config_mobility_type_humics, &
config_mobility_type_saccharids, &
config_mobility_type_lipids, &
+ config_mobility_type_inorganic_carbon, &
config_mobility_type_proteins, &
config_mobility_type_dissolved_iron, &
config_mobility_type_particulate_iron, &
@@ -8963,7 +10143,13 @@ subroutine init_column_package_configs(domain)
config_scales_absorption_diatoms, &
config_scales_absorption_small_plankton, &
config_scales_absorption_phaeocystis, &
- config_ratio_C_to_N_proteins
+ config_ratio_C_to_N_proteins, &
+ config_fallen_snow_radius, &
+ config_new_snow_density, &
+ config_max_snow_density, &
+ config_minimum_wind_compaction, &
+ config_wind_compaction_factor, &
+ config_max_dry_snow_radius
integer, pointer :: &
config_boundary_layer_iteration_number
@@ -8980,6 +10166,7 @@ subroutine init_column_package_configs(domain)
call MPAS_pool_get_config(domain % configs, "config_slow_mode_critical_porosity", config_slow_mode_critical_porosity)
call MPAS_pool_get_config(domain % configs, "config_congelation_ice_porosity", config_congelation_ice_porosity)
call MPAS_pool_get_config(domain % configs, "config_shortwave_type", config_shortwave_type)
+ call MPAS_pool_get_config(domain % configs, "config_use_snicar_ad", config_use_snicar_ad)
call MPAS_pool_get_config(domain % configs, "config_albedo_type", config_albedo_type)
call MPAS_pool_get_config(domain % configs, "config_visible_ice_albedo", config_visible_ice_albedo)
call MPAS_pool_get_config(domain % configs, "config_infrared_ice_albedo", config_infrared_ice_albedo)
@@ -9138,6 +10325,7 @@ subroutine init_column_package_configs(domain)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_humics", config_mobility_type_humics)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_saccharids", config_mobility_type_saccharids)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_lipids", config_mobility_type_lipids)
+ call MPAS_pool_get_config(domain % configs, "config_mobility_type_inorganic_carbon", config_mobility_type_inorganic_carbon)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_proteins", config_mobility_type_proteins)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_dissolved_iron", config_mobility_type_dissolved_iron)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_particulate_iron", config_mobility_type_particulate_iron)
@@ -9157,6 +10345,14 @@ subroutine init_column_package_configs(domain)
call MPAS_pool_get_config(domain % configs, "config_scales_absorption_small_plankton", config_scales_absorption_small_plankton)
call MPAS_pool_get_config(domain % configs, "config_scales_absorption_phaeocystis", config_scales_absorption_phaeocystis)
call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins)
+ call MPAS_pool_get_config(domain % configs, "config_snow_redistribution_scheme", config_snow_redistribution_scheme)
+ call MPAS_pool_get_config(domain % configs, "config_fallen_snow_radius", config_fallen_snow_radius)
+ call MPAS_pool_get_config(domain % configs, "config_use_snow_liquid_ponds", config_use_snow_liquid_ponds)
+ call MPAS_pool_get_config(domain % configs, "config_new_snow_density", config_new_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_max_snow_density", config_max_snow_density)
+ call MPAS_pool_get_config(domain % configs, "config_minimum_wind_compaction", config_minimum_wind_compaction)
+ call MPAS_pool_get_config(domain % configs, "config_wind_compaction_factor", config_wind_compaction_factor)
+ call MPAS_pool_get_config(domain % configs, "config_max_dry_snow_radius", config_max_dry_snow_radius)
call colpkg_init_parameters(&
config_cice_int("config_thermodynamics_type", config_thermodynamics_type), &
@@ -9171,6 +10367,7 @@ subroutine init_column_package_configs(domain)
config_slow_mode_critical_porosity, &
config_congelation_ice_porosity, &
config_shortwave_type, &
+ config_use_snicar_ad, &
config_albedo_type, &
config_visible_ice_albedo, &
config_infrared_ice_albedo, &
@@ -9316,6 +10513,7 @@ subroutine init_column_package_configs(domain)
config_mobility_type_humics, &
config_mobility_type_saccharids, &
config_mobility_type_lipids, &
+ config_mobility_type_inorganic_carbon, &
config_mobility_type_proteins, &
config_mobility_type_dissolved_iron, &
config_mobility_type_particulate_iron, &
@@ -9334,7 +10532,15 @@ subroutine init_column_package_configs(domain)
config_scales_absorption_diatoms, &
config_scales_absorption_small_plankton, &
config_scales_absorption_phaeocystis, &
- config_ratio_C_to_N_proteins)
+ config_ratio_C_to_N_proteins, &
+ config_snow_redistribution_scheme, &
+ config_use_snow_liquid_ponds, &
+ config_fallen_snow_radius, &
+ config_max_dry_snow_radius, &
+ config_new_snow_density, &
+ config_max_snow_density, &
+ config_minimum_wind_compaction, &
+ config_wind_compaction_factor)
!-----------------------------------------------------------------------
! Parameters for thermodynamics
@@ -10012,6 +11218,10 @@ subroutine init_column_package_configs(domain)
! mobility type lipids
! doctype_l = config_mobility_type_lipids
+ ! dictype_1:
+ ! mobility type dissolved inorganic carbon
+ ! dictype_1 = config_mobility_type_inorganic_carbon
+
! dontype_protein:
! mobility type proteins
! dontype_protein = config_mobility_type_proteins
@@ -10096,6 +11306,42 @@ subroutine init_column_package_configs(domain)
! 0.02 characteristic skeletal layer thickness (m) (zsalinity)
!l_skS = config_zsalinity_gravity_drainage_scale
+ !-----------------------------------------------------------------------
+ ! Parameters for snow
+ !-----------------------------------------------------------------------
+
+ ! snwredist:
+ ! snow redistribution type
+ ! snwredist = config_snow_redistribution_scheme
+
+ ! use_smliq_pnd:
+ ! convert excess snow liquid to ponds
+ ! use_smliq_pnd = config_use_snow_liquid_ponds
+
+ ! rsnw_fall:
+ ! fallen snow grain radius (um)
+ ! rsnw_fall = config_fallen_snow_radius
+
+ ! rsnw_tmax:
+ ! maximum dry metamorphism snow grain radius (um)
+ ! rsnw_tmax = config_max_dry_snow_radius
+
+ ! rhosnew:
+ ! new snow density (kg/m^3)
+ ! rhosnew = config_new_snow_density
+
+ ! rhosmax:
+ ! maximum snow density (kg/m^3)
+ ! rhosmax = config_max_snow_density
+
+ ! windmin:
+ ! minimum wind speed to compact snow (m/s)
+ ! windmin = config_minimum_wind_compaction
+
+ ! drhosdwind:
+ ! wind compaction factor (kg s/m^4)
+ ! drhosdwind = config_wind_compaction_factor
+
end subroutine init_column_package_configs
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -10273,7 +11519,9 @@ subroutine init_column_non_activated_pointers(domain)
pkgTracerVerticalDONActive, &
pkgTracerVerticalIronActive, &
pkgTracerZAerosolsActive, &
- pkgTracerZSalinityActive
+ pkgTracerZSalinityActive, &
+ pkgColumnTracerEffectiveSnowDensityActive, &
+ pkgColumnTracerSnowGrainRadiusActive
! mesh stand-ins
@@ -10339,6 +11587,8 @@ subroutine init_column_non_activated_pointers(domain)
call MPAS_pool_get_package(block % packages, "pkgTracerVerticalIronActive", pkgTracerVerticalIronActive)
call MPAS_pool_get_package(block % packages, "pkgTracerZAerosolsActive", pkgTracerZAerosolsActive)
call MPAS_pool_get_package(block % packages, "pkgTracerZSalinityActive", pkgTracerZSalinityActive)
+ call MPAS_pool_get_package(block % packages, "pkgColumnTracerEffectiveSnowDensityActive", pkgColumnTracerEffectiveSnowDensityActive)
+ call MPAS_pool_get_package(block % packages, "pkgColumnTracerSnowGrainRadiusActive", pkgColumnTracerSnowGrainRadiusActive)
! ice age
@@ -10488,6 +11738,17 @@ subroutine init_column_non_activated_pointers(domain)
call set_stand_in_tracer_array(block, "verticalSalinity")
endif
+ ! snow density tracers
+ if (.not. pkgColumnTracerEffectiveSnowDensityActive) then
+ call set_stand_in_tracer_array(block, "snowDensity")
+ call set_stand_in_tracer_array(block, "snowLiquidMass")
+ call set_stand_in_tracer_array(block, "snowIceMass")
+ endif
+
+ ! snow grain radius
+ if (.not. pkgColumnTracerSnowGrainRadiusActive) then
+ call set_stand_in_tracer_array(block, "snowGrainRadius")
+ endif
!-----------------------------------------------------------------------
! other column packages
!-----------------------------------------------------------------------
@@ -10597,7 +11858,9 @@ subroutine finalize_column_non_activated_pointers(domain)
pkgTracerVerticalDONActive, &
pkgTracerVerticalIronActive, &
pkgTracerZAerosolsActive, &
- pkgTracerZSalinityActive
+ pkgTracerZSalinityActive, &
+ pkgColumnTracerEffectiveSnowDensityActive, &
+ pkgColumnTracerSnowGrainRadiusActive
! drag variables
type(field1DReal), pointer :: &
@@ -10655,6 +11918,8 @@ subroutine finalize_column_non_activated_pointers(domain)
call MPAS_pool_get_package(block % packages, "pkgTracerVerticalIronActive", pkgTracerVerticalIronActive)
call MPAS_pool_get_package(block % packages, "pkgTracerZAerosolsActive", pkgTracerZAerosolsActive)
call MPAS_pool_get_package(block % packages, "pkgTracerZSalinityActive", pkgTracerZSalinityActive)
+ call MPAS_pool_get_package(block % packages, "pkgColumnTracerEffectiveSnowDensityActive", pkgColumnTracerEffectiveSnowDensityActive)
+ call MPAS_pool_get_package(block % packages, "pkgColumnTracerSnowGrainRadiusActive", pkgColumnTracerSnowGrainRadiusActive)
! ice age
if (.not. pkgColumnTracerIceAgeActive) then
@@ -10803,6 +12068,17 @@ subroutine finalize_column_non_activated_pointers(domain)
call finalize_stand_in_tracer_array(block, "verticalSalinity")
endif
+ ! snow density tracers
+ if (.not. pkgColumnTracerEffectiveSnowDensityActive) then
+ call finalize_stand_in_tracer_array(block, "snowDensity")
+ call finalize_stand_in_tracer_array(block, "snowLiquidMass")
+ call finalize_stand_in_tracer_array(block, "snowIceMass")
+ endif
+
+ ! snow grain radius
+ if (.not. pkgColumnTracerSnowGrainRadiusActive) then
+ call finalize_stand_in_tracer_array(block, "snowGrainRadius")
+ endif
!-----------------------------------------------------------------------
! other column packages
!-----------------------------------------------------------------------
@@ -11119,21 +12395,26 @@ subroutine seaice_column_reinitialize_oceanic_fluxes(domain)
type(block_type), pointer :: block
type(MPAS_pool_type), pointer :: &
- oceanFluxesPool
+ oceanFluxesPool, &
+ snowPool
real(kind=RKIND), dimension(:), pointer :: &
oceanFreshWaterFlux, &
oceanSaltFlux, &
oceanHeatFlux, &
- oceanShortwaveFlux
+ oceanShortwaveFlux, &
+ snowLossToLeads, &
+ snowMeltMassCell
logical, pointer :: &
- config_use_column_package
+ config_use_column_package, &
+ config_use_column_snow_tracers
block => domain % blocklist
do while (associated(block))
call MPAS_pool_get_config(block % configs, "config_use_column_package", config_use_column_package)
+ call MPAS_pool_get_config(block % configs, "config_use_column_snow_tracers", config_use_column_snow_tracers)
if (config_use_column_package) then
@@ -11149,6 +12430,17 @@ subroutine seaice_column_reinitialize_oceanic_fluxes(domain)
oceanHeatFlux(:) = 0.0_RKIND
oceanShortwaveFlux(:) = 0.0_RKIND
+ if (config_use_column_snow_tracers) then
+ call MPAS_pool_get_subpool(block % structs, "snow", snowPool)
+
+ call MPAS_pool_get_array(snowPool, "snowLossToLeads", snowLossToLeads)
+ call MPAS_pool_get_array(snowPool, "snowMeltMassCell", snowMeltMassCell)
+
+ snowLossToLeads(:) = 0.0_RKIND
+ snowMeltMassCell(:) = 0.0_RKIND
+
+ endif ! config_use_column_snow_tracers
+
endif ! config_use_column_package
block => block % next
@@ -11268,6 +12560,7 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject)
config_mobility_type_phaeocystis, &
config_mobility_type_saccharids, &
config_mobility_type_lipids, &
+ config_mobility_type_inorganic_carbon, &
config_mobility_type_proteins, &
config_mobility_type_dissolved_iron, &
config_mobility_type_particulate_iron, &
@@ -11429,6 +12722,7 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_humics", config_mobility_type_humics)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_saccharids", config_mobility_type_saccharids)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_lipids", config_mobility_type_lipids)
+ call MPAS_pool_get_config(domain % configs, "config_mobility_type_inorganic_carbon", config_mobility_type_inorganic_carbon)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_proteins", config_mobility_type_proteins)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_dissolved_iron", config_mobility_type_dissolved_iron)
call MPAS_pool_get_config(domain % configs, "config_mobility_type_particulate_iron", config_mobility_type_particulate_iron)
@@ -11662,6 +12956,7 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject)
config_mobility_type_phaeocystis, &
config_mobility_type_saccharids, &
config_mobility_type_lipids, &
+ config_mobility_type_inorganic_carbon, &
config_mobility_type_proteins, &
config_mobility_type_dissolved_iron, &
config_mobility_type_particulate_iron, &
@@ -11905,7 +13200,8 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject)
endif
! set the category tracer array
- call set_cice_tracer_array_category(block, tracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call set_cice_tracer_array_category(block, tracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
if (config_use_vertical_zsalinity) then
call colpkg_init_zsalinity(&
@@ -11914,7 +13210,7 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject)
config_do_restart_zsalinity, &
rayleighCriteria, &
rayleighCriteriaReal(iCell), &
- tracerObject % tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), &
+ tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), &
tracerObject % index_verticalSalinity, &
nCategories, &
seaSurfaceSalinity(iCell))
@@ -11933,7 +13229,7 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject)
tracerObject % nTracers, &
tracerObject % nBiotracers, &
iceSalinity(:,:,iCell), &
- tracerObject % tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), &
+ tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), &
seaSurfaceSalinity(iCell), &
oceanNitrateConc(iCell), &
oceanAmmoniumConc(iCell), &
@@ -11967,7 +13263,8 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject)
endif ! biogeochemistry
! get the category tracer array
- call get_cice_tracer_array_category(block, tracerObject, iCell, setGetPhysicsTracers, setGetBGCTracers)
+ call get_cice_tracer_array_category(block, tracerObject, &
+ tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers)
enddo ! iCell
@@ -12004,7 +13301,8 @@ subroutine seaice_column_reinitialize_diagnostics_thermodynamics(domain)
tracersAggregatePool, &
pondsPool, &
shortwavePool, &
- dragPool
+ dragPool, &
+ snowPool
! atmospheric fluxes
real(kind=RKIND), dimension(:), pointer :: &
@@ -12028,6 +13326,18 @@ subroutine seaice_column_reinitialize_diagnostics_thermodynamics(domain)
basalIceMelt, &
lateralIceMelt
+ ! snow model
+ real(kind=RKIND), dimension(:), pointer :: &
+ snowLossToLeads, &
+ snowMeltMassCell, &
+ snowDensityViaContent, &
+ snowDensityViaCompaction, &
+ snowRadiusInStandardRadiationScheme
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ snowMeltMassCategory, &
+ snowRadiusInStandardRadiationSchemeCategory
+
! diagnostic tendencies
real(kind=RKIND), dimension(:), pointer :: &
iceAreaTendencyThermodynamics, &
@@ -12071,7 +13381,8 @@ subroutine seaice_column_reinitialize_diagnostics_thermodynamics(domain)
logical, pointer :: &
config_use_ice_age, &
config_use_form_drag, &
- config_use_column_package
+ config_use_column_package, &
+ config_use_column_snow_tracers
call MPAS_pool_get_config(domain % blocklist % configs, "config_use_column_package", config_use_column_package)
@@ -12213,6 +13524,29 @@ subroutine seaice_column_reinitialize_diagnostics_thermodynamics(domain)
endif ! config_use_form_drag
+ ! snow
+ call MPAS_pool_get_config(block % configs, "config_use_column_snow_tracers", config_use_column_snow_tracers)
+ if (config_use_column_snow_tracers) then
+
+ call MPAS_pool_get_subpool(block % structs, "snow", snowPool)
+ call MPAS_pool_get_array(snowPool, "snowLossToLeads", snowLossToLeads)
+ call MPAS_pool_get_array(snowPool, "snowMeltMassCell", snowMeltMassCell)
+ call MPAS_pool_get_array(snowPool, "snowMeltMassCategory", snowMeltMassCategory)
+ call MPAS_pool_get_array(snowPool, "snowDensityViaContent", snowDensityViaContent)
+ call MPAS_pool_get_array(snowPool, "snowDensityViaCompaction", snowDensityViaCompaction)
+ call MPAS_pool_get_array(snowPool, "snowRadiusInStandardRadiationScheme", snowRadiusInStandardRadiationScheme)
+ call MPAS_pool_get_array(snowPool, "snowRadiusInStandardRadiationSchemeCategory", snowRadiusInStandardRadiationSchemeCategory)
+
+ snowLossToLeads = 0.0_RKIND
+ snowMeltMassCell = 0.0_RKIND
+ snowMeltMassCategory = 0.0_RKIND
+ snowDensityViaContent = 0.0_RKIND
+ snowDensityViaCompaction = 0.0_RKIND
+ snowRadiusInStandardRadiationScheme = 0.0_RKIND
+ snowRadiusInStandardRadiationSchemeCategory = 0.0_RKIND
+
+ end if ! config_use_column_snow_tracers
+
block => block % next
end do
@@ -12416,7 +13750,8 @@ subroutine seaice_column_reinitialize_diagnostics_bgc(domain)
netBrineHeight, &
zSalinityFlux, &
zSalinityGDFlux, &
- totalChlorophyll
+ totalChlorophyll, &
+ totalCarbonContentCell
real(kind=RKIND), dimension(:,:), pointer :: &
oceanBioFluxes, &
@@ -12431,45 +13766,61 @@ subroutine seaice_column_reinitialize_diagnostics_bgc(domain)
logical, pointer :: &
config_use_column_biogeochemistry, &
config_use_column_shortwave, &
- config_use_column_package
+ config_use_column_package, &
+ config_use_vertical_biochemistry, &
+ config_use_vertical_zsalinity
call MPAS_pool_get_config(domain % blocklist % configs, "config_use_column_package", config_use_column_package)
- if (config_use_column_package) then
+ if (config_use_column_package) then
block => domain % blocklist
do while (associated(block))
! biogeochemistry
call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity)
if (config_use_column_biogeochemistry) then
call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistryPool)
- call MPAS_pool_get_array(biogeochemistryPool, "primaryProduction", primaryProduction)
- call MPAS_pool_get_array(biogeochemistryPool, "totalChlorophyll", totalChlorophyll)
- call MPAS_pool_get_array(biogeochemistryPool, "netSpecificAlgalGrowthRate", netSpecificAlgalGrowthRate)
+ if (config_use_vertical_biochemistry) then
+ call MPAS_pool_get_array(biogeochemistryPool, "primaryProduction", primaryProduction)
+ call MPAS_pool_get_array(biogeochemistryPool, "totalChlorophyll", totalChlorophyll)
+ call MPAS_pool_get_array(biogeochemistryPool, "netSpecificAlgalGrowthRate", netSpecificAlgalGrowthRate)
+
+ primaryProduction = 0.0_RKIND
+ totalChlorophyll = 0.0_RKIND
+ netSpecificAlgalGrowthRate = 0.0_RKIND
+
+ end if
+
+ if (config_use_vertical_zsalinity) then
+ call MPAS_pool_get_array(biogeochemistryPool, "zSalinityFlux", zSalinityFlux)
+ call MPAS_pool_get_array(biogeochemistryPool, "zSalinityGDFlux", zSalinityGDFlux)
+
+ zSalinityFlux = 0.0_RKIND
+ zSalinityGDFlux = 0.0_RKIND
+
+ end if
+
call MPAS_pool_get_array(biogeochemistryPool, "netBrineHeight", netBrineHeight)
- call MPAS_pool_get_array(biogeochemistryPool, "zSalinityFlux", zSalinityFlux)
- call MPAS_pool_get_array(biogeochemistryPool, "zSalinityGDFlux", zSalinityGDFlux)
call MPAS_pool_get_array(biogeochemistryPool, "oceanBioFluxes", oceanBioFluxes)
call MPAS_pool_get_array(biogeochemistryPool, "atmosIceBioFluxes", atmosIceBioFluxes)
call MPAS_pool_get_array(biogeochemistryPool, "snowIceBioFluxes", snowIceBioFluxes)
call MPAS_pool_get_array(biogeochemistryPool, "totalVerticalBiologyIce", totalVerticalBiologyIce)
call MPAS_pool_get_array(biogeochemistryPool, "totalVerticalBiologySnow", totalVerticalBiologySnow)
+ call MPAS_pool_get_array(biogeochemistryPool, "totalCarbonContentCell", totalCarbonContentCell)
- primaryProduction = 0.0_RKIND
- totalChlorophyll = 0.0_RKIND
- netSpecificAlgalGrowthRate = 0.0_RKIND
netBrineHeight = 0.0_RKIND
- zSalinityFlux = 0.0_RKIND
- zSalinityGDFlux = 0.0_RKIND
oceanBioFluxes = 0.0_RKIND
atmosIceBioFluxes = 0.0_RKIND
snowIceBioFluxes = 0.0_RKIND
totalVerticalBiologyIce = 0.0_RKIND
totalVerticalBiologySnow = 0.0_RKIND
+ totalCarbonContentCell = 0.0_RKIND
endif
@@ -13265,23 +14616,642 @@ subroutine column_combine_snow_ice_tracers(domain)
end subroutine column_combine_snow_ice_tracers
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_ocean_carbon_flux
+!
+!> \brief
+!> \author Nicole Jeffery, LANL
+!> \date 26 May 2020
+!> \details Calculate the ocean carbon flux
+!> by summing the appropriate biogeochemical tracer fluxes in units of mmol C/m2/s
+!>
+!> ocean carbon flux = algal nitrogen group fluxes * (C to N ratios)
+!> + dissolved carbon group fluxes
+!> + dissolved organic nitrogen * (C to N ratio)
+!> + dissolved inorganic carbon fluxes + humic fluxes
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_ocean_carbon_flux(block,oceanCarbonFlux,oceanBioFluxes,iCell)
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ oceanCarbonFlux
+
+ real(kind=RKIND), dimension(:,:,:), intent(in) :: &
+ oceanBioFluxes
+
+ integer, intent(in) :: &
+ iCell
+
+ type(block_type), intent(in) :: &
+ block
+
+ logical, pointer :: &
+ config_use_column_biogeochemistry, &
+ config_use_vertical_biochemistry, &
+ config_use_carbon, &
+ config_use_DON, &
+ config_use_humics
+
+ integer, pointer :: &
+ nAlgae, &
+ nDOC, &
+ nDON, &
+ nDIC
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ biogeochemistry
+
+ real(kind=RKIND), pointer :: &
+ config_ratio_C_to_N_diatoms, &
+ config_ratio_C_to_N_small_plankton, &
+ config_ratio_C_to_N_phaeocystis, &
+ config_ratio_C_to_N_proteins
+
+ integer, pointer :: &
+ nCategories, &
+ nZBGCTracers, &
+ maxAlgaeType, &
+ maxDOCType, &
+ maxDICType, &
+ maxDONType, &
+ maxIronType, &
+ maxBCType, &
+ maxDustType, &
+ maxAerosolType
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ ratio_C_to_N
+
+ real(kind=RKIND), dimension(:,:), allocatable :: &
+ oceanBioFluxesAll
+
+ integer :: &
+ iBioTracers, &
+ iBioData, &
+ iCategory
+
+ call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_carbon", config_use_carbon)
+ call MPAS_pool_get_config(block % configs, "config_use_DON", config_use_DON)
+ call MPAS_pool_get_config(block % configs, "config_use_humics",config_use_humics)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins)
+
+ call MPAS_pool_get_dimension(block % dimensions, "nAlgae", nAlgae)
+ call MPAS_pool_get_dimension(block % dimensions, "nDOC", nDOC)
+ call MPAS_pool_get_dimension(block % dimensions, "nDIC", nDIC)
+ call MPAS_pool_get_dimension(block % dimensions, "nDON", nDON)
+
+ call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
+ call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry)
+
+ call MPAS_pool_get_dimension(mesh, "nCategories", nCategories)
+ call MPAS_pool_get_dimension(mesh, "nZBGCTracers", nZBGCTracers)
+ call MPAS_pool_get_dimension(mesh, "maxAlgaeType", maxAlgaeType)
+ call MPAS_pool_get_dimension(mesh, "maxDOCType", maxDOCType)
+ call MPAS_pool_get_dimension(mesh, "maxDICType", maxDICType)
+ call MPAS_pool_get_dimension(mesh, "maxDONType", maxDONType)
+ call MPAS_pool_get_dimension(mesh, "maxAerosolType", maxAerosolType)
+ call MPAS_pool_get_dimension(mesh, "maxIronType", maxIronType)
+ call MPAS_pool_get_dimension(mesh, "maxBCType", maxBCType)
+ call MPAS_pool_get_dimension(mesh, "maxDustType", maxDustType)
+
+
+ allocate(oceanBioFluxesAll(nZBGCTracers,nCategories))
+ allocate(ratio_C_to_N(3))
+
+ ratio_C_to_N(1) = config_ratio_C_to_N_diatoms
+ ratio_C_to_N(2) = config_ratio_C_to_N_small_plankton
+ ratio_C_to_N(3) = config_ratio_C_to_N_phaeocystis
+
+ if (config_use_column_biogeochemistry) then
+
+ do iCategory = 1, nCategories
+
+ oceanCarbonFlux(iCategory) = 0.0_RKIND
+ oceanBioFluxesAll(:,iCategory) = 0.0_RKIND
+
+ do iBioTracers = 1, ciceTracerObject % nBioTracers
+ iBioData = ciceTracerObject % index_LayerIndexToDataArray(iBioTracers)
+ oceanBioFluxesAll(iBioData,iCategory) = oceanBioFluxes(iBioTracers,iCategory,iCell)
+ enddo
+ iBioData = 0
+
+ ! Algae
+ do iBioTracers = 1, maxAlgaeType
+ iBioData = iBioData+1
+ oceanCarbonFlux(iCategory) = oceanCarbonFlux(iCategory) + &
+ oceanBioFluxesAll(iBioData,iCategory) * ratio_C_to_N(iBioTracers)
+ enddo
+
+ ! Nitrate
+ iBioData = iBioData+1
+
+ ! Polysaccharids and Lipids
+ do iBioTracers = 1, maxDOCType
+ iBioData = iBioData+1
+ oceanCarbonFlux(iCategory) = oceanCarbonFlux(iCategory) + &
+ oceanBioFluxesAll(iBioData,iCategory)
+ enddo
+
+ ! DIC
+ do iBioTracers = 1, maxDICType
+ iBioData = iBioData+1
+ oceanCarbonFlux(iCategory) = oceanCarbonFlux(iCategory) + &
+ oceanBioFluxesAll(iBioData,iCategory)
+ enddo
+
+ ! + Chlorophyll (maxAlgaeType) + Ammonium (1) + Silicate (1) + DMSPp (1) + DMSPd (1)
+ ! + DMS (1) + PON (1)
+
+ iBioData = iBioData+maxAlgaeType + 6
+
+ ! DON
+ do iBioTracers = 1, maxDONType
+ iBioData = iBioData+1
+ oceanCarbonFlux(iCategory) = oceanCarbonFlux(iCategory) + &
+ oceanBioFluxesAll(iBioData,iCategory) * config_ratio_C_to_N_proteins
+ enddo
+
+ ! + dFe (maxIronType) + pFe (maxIronType)
+ ! + Black Carbon (maxBCType) + Dust (maxDustType)
+
+ iBioData = iBioData + 2*maxIronType + maxBCType + maxDustType
+
+ ! Humics
+ iBioData = iBioData+1
+ oceanCarbonFlux(iCategory) = oceanCarbonFlux(iCategory) + &
+ oceanBioFluxesAll(iBioData,iCategory)
+
+ enddo ! nCategories
+ endif
+
+ deallocate(oceanBioFluxesAll)
+ deallocate(ratio_C_to_N)
+
+ end subroutine seaice_ocean_carbon_flux
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_ocean_carbon_flux_cell
+!
+!> \brief
+!> \author Nicole Jeffery, LANL
+!> \date 26 May 2020
+!> \details Calculate the ocean carbon flux
+!> by summing the appropriate biogeochemical tracer fluxes in units of mmol C/m2/s
+!>
+!> ocean carbon flux = algal nitrogen group fluxes * (C to N ratios)
+!> + dissolved carbon group fluxes
+!> + dissolved organic nitrogen * (C to N ratio)
+!> + dissolved inorganic carbon fluxes + humic fluxes
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxes,iCell)
+
+ real(kind=RKIND), intent(out) :: &
+ oceanCarbonFlux
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ oceanBioFluxes
+
+ integer, intent(in) :: &
+ iCell
+
+ type(block_type), intent(in) :: &
+ block
+
+ logical, pointer :: &
+ config_use_column_biogeochemistry, &
+ config_use_vertical_biochemistry, &
+ config_use_carbon, &
+ config_use_DON, &
+ config_use_humics
+
+ integer, pointer :: &
+ nAlgae, &
+ nDOC, &
+ nDON, &
+ nDIC
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ biogeochemistry
+
+ real(kind=RKIND), pointer :: &
+ config_ratio_C_to_N_diatoms, &
+ config_ratio_C_to_N_small_plankton, &
+ config_ratio_C_to_N_phaeocystis, &
+ config_ratio_C_to_N_proteins
+
+ integer, pointer :: &
+ nZBGCTracers, &
+ maxAlgaeType, &
+ maxDOCType, &
+ maxDICType, &
+ maxDONType, &
+ maxIronType, &
+ maxBCType, &
+ maxDustType, &
+ maxAerosolType
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ ratio_C_to_N
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ oceanBioFluxesAll
+
+ integer :: &
+ iBioTracers, &
+ iBioData
+
+ call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_carbon", config_use_carbon)
+ call MPAS_pool_get_config(block % configs, "config_use_DON", config_use_DON)
+ call MPAS_pool_get_config(block % configs, "config_use_humics",config_use_humics)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins)
+
+ call MPAS_pool_get_dimension(block % dimensions, "nAlgae", nAlgae)
+ call MPAS_pool_get_dimension(block % dimensions, "nDOC", nDOC)
+ call MPAS_pool_get_dimension(block % dimensions, "nDIC", nDIC)
+ call MPAS_pool_get_dimension(block % dimensions, "nDON", nDON)
+
+ call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
+ call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry)
+
+ call MPAS_pool_get_dimension(mesh, "nZBGCTracers", nZBGCTracers)
+ call MPAS_pool_get_dimension(mesh, "maxAlgaeType", maxAlgaeType)
+ call MPAS_pool_get_dimension(mesh, "maxDOCType", maxDOCType)
+ call MPAS_pool_get_dimension(mesh, "maxDICType", maxDICType)
+ call MPAS_pool_get_dimension(mesh, "maxDONType", maxDONType)
+ call MPAS_pool_get_dimension(mesh, "maxAerosolType", maxAerosolType)
+ call MPAS_pool_get_dimension(mesh, "maxIronType", maxIronType)
+ call MPAS_pool_get_dimension(mesh, "maxBCType", maxBCType)
+ call MPAS_pool_get_dimension(mesh, "maxDustType", maxDustType)
+
+ allocate(oceanBioFluxesAll(nZBGCTracers))
+ allocate(ratio_C_to_N(3))
+
+ ratio_C_to_N(1) = config_ratio_C_to_N_diatoms
+ ratio_C_to_N(2) = config_ratio_C_to_N_small_plankton
+ ratio_C_to_N(3) = config_ratio_C_to_N_phaeocystis
+
+ if (config_use_column_biogeochemistry) then
+
+ oceanCarbonFlux = 0.0_RKIND
+ oceanBioFluxesAll(:) = 0.0_RKIND
+
+ do iBioTracers = 1, ciceTracerObject % nBioTracers
+ iBioData = ciceTracerObject % index_LayerIndexToDataArray(iBioTracers)
+ oceanBioFluxesAll(iBioData) = oceanBioFluxes(iBioTracers)
+ enddo
+ iBioData = 0
+
+ ! Algae
+ do iBioTracers = 1, maxAlgaeType
+ iBioData = iBioData+1
+ oceanCarbonFlux = oceanCarbonFlux + &
+ oceanBioFluxesAll(iBioData) * ratio_C_to_N(iBioTracers)
+ enddo
+
+ ! Nitrate
+ iBioData = iBioData+1
+
+ ! Polysaccharids and Lipids
+ do iBioTracers = 1, maxDOCType
+ iBioData = iBioData+1
+ oceanCarbonFlux = oceanCarbonFlux + &
+ oceanBioFluxesAll(iBioData)
+ enddo
+
+ ! DIC
+ do iBioTracers = 1, maxDICType
+ iBioData = iBioData+1
+ oceanCarbonFlux = oceanCarbonFlux + &
+ oceanBioFluxesAll(iBioData)
+ enddo
+
+ ! + Chlorophyll (maxAlgaeType) + Ammonium (1) + Silicate (1) + DMSPp (1) + DMSPd (1)
+ ! + DMS (1) + PON (1)
+
+ iBioData = iBioData+maxAlgaeType + 6
+
+ ! DON
+ do iBioTracers = 1, maxDONType
+ iBioData = iBioData+1
+ oceanCarbonFlux = oceanCarbonFlux + &
+ oceanBioFluxesAll(iBioData) * config_ratio_C_to_N_proteins
+ enddo
+
+ ! + dFe (maxIronType) + pFe (maxIronType)
+ ! + Black Carbon (maxBCType) + Dust (maxDustType)
+
+ iBioData = iBioData + 2*maxIronType + maxBCType + maxDustType
+
+ ! Humics
+ iBioData = iBioData+1
+ oceanCarbonFlux = oceanCarbonFlux + &
+ oceanBioFluxesAll(iBioData)
+
+ endif
+
+ deallocate(oceanBioFluxesAll)
+ deallocate(ratio_C_to_N)
+
+ end subroutine seaice_ocean_carbon_flux_cell
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_total_carbon_content_category
+!
+!> \brief
+!> \author Nicole Jeffery, LANL
+!> \date 26 May 2020
+!> \details Calculate the total carbon concentration in the sea ice category
+!> by summing the appropriate biogeochemical tracers in units of mmol C
+!>
+!> Total carbon = algal nitrogen groups * (C to N ratios) + dissolved carbon groups
+!> + dissolved inorganic carbon + humic material
+!> + dissolved organic nitrogen * (C to N ratio)
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_total_carbon_content_category(block,totalCarbonContentCategory,iceAreaCategory,iceVolumeCategory,iCell)
+
+ use seaice_constants, only: &
+ skeletalLayerThickness, &
+ seaicePuny
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ totalCarbonContentCategory
+
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ iceAreaCategory, &
+ iceVolumeCategory
+
+ integer, intent(in) :: &
+ iCell
+
+ type(block_type), intent(in) :: &
+ block
+
+ logical, pointer :: &
+ config_use_skeletal_biochemistry, &
+ config_use_vertical_biochemistry, &
+ config_use_vertical_tracers, &
+ config_use_carbon, &
+ config_use_DON, &
+ config_use_humics
+
+ integer, pointer :: &
+ nCategories, &
+ nBioLayersP1, &
+ nBioLayers, &
+ nAlgae, &
+ nDOC, &
+ nDIC, &
+ nDON
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ biogeochemistry, &
+ tracers
+
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ skeletalAlgaeConc, &
+ skeletalDOCConc, &
+ skeletalDICConc, &
+ skeletalDONConc, &
+ skeletalHumicsConc, &
+ verticalAlgaeConc, &
+ verticalDOCConc, &
+ verticalDICConc, &
+ verticalDONConc, &
+ verticalHumicsConc, &
+ brineFraction
+
+ real(kind=RKIND), pointer :: &
+ config_ratio_C_to_N_diatoms, &
+ config_ratio_C_to_N_small_plankton, &
+ config_ratio_C_to_N_phaeocystis, &
+ config_ratio_C_to_N_proteins
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ ratio_C_to_N, &
+ verticalGridSpace
+
+ real(kind=RKIND) :: &
+ brineHeight
+
+ integer :: &
+ iBioTracers, &
+ iBioCount, &
+ iLayers, &
+ iCategory
+
+ call MPAS_pool_get_config(block % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry)
+ call MPAS_pool_get_config(block % configs, "config_use_vertical_tracers", config_use_vertical_tracers)
+ call MPAS_pool_get_config(block % configs, "config_use_carbon", config_use_carbon)
+ call MPAS_pool_get_config(block % configs, "config_use_DON", config_use_DON)
+ call MPAS_pool_get_config(block % configs, "config_use_humics",config_use_humics)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis)
+ call MPAS_pool_get_config(block % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins)
+
+ call MPAS_pool_get_dimension(block % dimensions, "nBioLayers", nBioLayers)
+ call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP1", nBioLayersP1)
+ call MPAS_pool_get_dimension(block % dimensions, "nAlgae", nAlgae)
+ call MPAS_pool_get_dimension(block % dimensions, "nDOC", nDOC)
+ call MPAS_pool_get_dimension(block % dimensions, "nDIC", nDIC)
+ call MPAS_pool_get_dimension(block % dimensions, "nDON", nDON)
+
+ call MPAS_pool_get_subpool(block % structs, "tracers", tracers)
+ call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry)
+ call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
+
+ call MPAS_pool_get_dimension(mesh, "nCategories", nCategories)
+
+ call MPAS_pool_get_array(tracers, "skeletalAlgaeConc", skeletalAlgaeConc, 1)
+ call MPAS_pool_get_array(tracers, "skeletalDOCConc", skeletalDOCConc, 1)
+ call MPAS_pool_get_array(tracers, "skeletalDICConc", skeletalDICConc, 1)
+ call MPAS_pool_get_array(tracers, "skeletalDONConc", skeletalDONConc, 1)
+ call MPAS_pool_get_array(tracers, "skeletalHumicsConc", skeletalHumicsConc, 1)
+ call MPAS_pool_get_array(tracers, "verticalAlgaeConc", verticalAlgaeConc, 1)
+ call MPAS_pool_get_array(tracers, "verticalDOCConc", verticalDOCConc, 1)
+ call MPAS_pool_get_array(tracers, "verticalDICConc", verticalDICConc, 1)
+ call MPAS_pool_get_array(tracers, "verticalDONConc", verticalDONConc, 1)
+ call MPAS_pool_get_array(tracers, "verticalHumicsConc", verticalHumicsConc, 1)
+ call MPAS_pool_get_array(tracers, "brineFraction", brineFraction, 1)
+
+ allocate(ratio_C_to_N(3))
+ allocate(verticalGridSpace(nBioLayersP1))
+
+ ratio_C_to_N(1) = config_ratio_C_to_N_diatoms
+ ratio_C_to_N(2) = config_ratio_C_to_N_small_plankton
+ ratio_C_to_N(3) = config_ratio_C_to_N_phaeocystis
+
+
+ verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND)
+ verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND
+ verticalGridSpace(nBioLayersP1) = verticalGridSpace(1)
+ totalCarbonContentCategory(:) = 0.0_RKIND
+
+
+ if (config_use_skeletal_biochemistry) then
+
+ do iCategory = 1, nCategories
+ ! algal nitrogen
+ do iBioTracers = 1, nAlgae
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + skeletalAlgaeConc(iBioTracers,iCategory,iCell)* &
+ skeletalLayerThickness * ratio_C_to_N(iBioTracers)
+ enddo
+
+ if (config_use_carbon) then
+ ! DOC
+ do iBioTracers = 1, nDOC
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + skeletalDOCConc(iBioTracers,iCategory,iCell)* &
+ skeletalLayerThickness
+ enddo
+
+ ! DIC
+ do iBioTracers = 1, nDIC
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + skeletalDICConc(iBioTracers,iCategory,iCell)* &
+ skeletalLayerThickness
+ enddo
+ endif
+
+ if (config_use_DON) then
+ ! DON
+ do iBioTracers = 1, nDON
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + skeletalDONConc(iBioTracers,iCategory,iCell)* &
+ config_ratio_C_to_N_proteins * skeletalLayerThickness
+ enddo
+ endif
+
+ ! humic material
+ if (config_use_humics) &
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + skeletalHumicsConc(1,iCategory,iCell)* &
+ skeletalLayerThickness
+ enddo
+ elseif (config_use_vertical_tracers) then
+
+ do iCategory = 1, nCategories
+ brineHeight = 0.0_RKIND
+ if (iceAreaCategory(iCategory,iCell) > seaicePuny) then
+ brineHeight = iceVolumeCategory(iCategory,iCell)/iceAreaCategory(iCategory,iCell) * brineFraction(1,iCategory,iCell)
+ endif
+
+ if (config_use_vertical_biochemistry) then
+ iBioCount = 0
+ ! algal nitrogen
+ do iBioTracers = 1, nAlgae
+ do iLayers = 1,nBioLayersP1
+ iBiocount = iBiocount + 1
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + &
+ verticalAlgaeConc(iBioCount,iCategory,iCell) * ratio_C_to_N(iBioTracers) * &
+ verticalGridSpace(iLayers) * brineHeight
+ enddo
+ iBioCount = iBioCount+2 ! snow layers
+ enddo
+ endif
+
+ if (config_use_carbon) then
+ iBioCount = 0
+ ! DOC
+ do iBioTracers = 1, nDOC
+ do iLayers = 1,nBioLayersP1
+ iBioCount = iBioCount + 1
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + &
+ verticalDOCConc(iBioCount,iCategory,iCell) * verticalGridSpace(iLayers) * brineHeight
+ enddo
+ iBioCount = iBioCount+2 ! snow layers
+ enddo
+ iBioCount = 0
+ ! DIC
+ do iBioTracers = 1, nDIC
+
+ do iLayers = 1,nBioLayersP1
+ iBioCount = iBioCount + 1
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + &
+ verticalDICConc(iBioCount,iCategory,iCell) * verticalGridSpace(iLayers) * brineHeight
+ enddo
+ iBioCount = iBioCount + 2 ! snow layers
+ enddo
+ endif
+
+ if (config_use_DON) then
+ iBioCount = 0
+ ! dissolved organic nitrogen
+ do iBioTracers = 1, nDON
+ do iLayers = 1,nBioLayersP1
+ iBiocount = iBiocount + 1
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + &
+ verticalDONConc(iBioCount,iCategory,iCell) * config_ratio_C_to_N_proteins * &
+ verticalGridSpace(iLayers) * brineHeight
+ enddo
+ iBioCount = iBioCount+2 ! snow layers
+ enddo
+ endif
+
+ ! humic material
+ if (config_use_humics) then
+ do iLayers = 1, nBioLayersP1
+ totalCarbonContentCategory(iCategory) = totalCarbonContentCategory(iCategory) + &
+ verticalHumicsConc(iLayers,iCategory,iCell) * verticalGridSpace(iLayers) * brineHeight
+ enddo
+ endif
+ enddo
+ endif
+
+ deallocate(ratio_C_to_N)
+ deallocate(verticalGridSpace)
+
+ end subroutine seaice_total_carbon_content_category
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!-----------------------------------------------------------------------
! Warning messages
!-----------------------------------------------------------------------
- subroutine column_write_warnings(warnings)
+ subroutine column_write_warnings(logAsErrors)
+
+ use ice_colpkg, only: colpkg_get_warnings
- character(len=strKINDWarnings), dimension(:), intent(in) :: &
+ character(len=strKINDWarnings), dimension(:), allocatable :: &
warnings
+ logical, intent(in) :: &
+ logAsErrors
+
integer :: &
iWarning
- do iWarning = 1, size(warnings)
-
- call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_WARN)
+ call colpkg_get_warnings(warnings)
- enddo ! iWarning
+ if (logAsErrors) then
+ do iWarning = 1, size(warnings)
+ call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_ERR)
+ enddo ! iWarning
+ else
+ do iWarning = 1, size(warnings)
+ call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_WARN)
+ enddo ! iWarning
+ endif
end subroutine column_write_warnings
diff --git a/src/core_seaice/shared/mpas_seaice_constants.F b/src/core_seaice/shared/mpas_seaice_constants.F
index e722807e7f..dcc6ec76b6 100644
--- a/src/core_seaice/shared/mpas_seaice_constants.F
+++ b/src/core_seaice/shared/mpas_seaice_constants.F
@@ -33,7 +33,8 @@ module seaice_constants
rhofresh, &
vonkar, &
iceruf, &
- zref
+ zref, &
+ sk_l
private
save
@@ -50,8 +51,7 @@ module seaice_constants
! Earth constants
real (kind=RKIND), parameter, public :: &
seaiceGravity = gravit, & ! gravitational acceleration (m/s^2)
- earthRadius = 6371229.0_RKIND, & ! radius of Earth in [m]
- omega = 7.29212e-5_RKIND ! angular rotation rate of the Earth [s-1]
+ omega = 7.29212e-5_RKIND ! angular rotation rate of the Earth [s-1]
character (len=*), public, parameter :: &
coupleAlarmID = 'coupling'
@@ -91,5 +91,9 @@ module seaice_constants
iceThicknessMinimum = seaicePuny, &
snowThicknessMinimum = seaicePuny
+ ! biogeochemistry constants
+ real(kind=RKIND), parameter, public :: &
+ skeletalLayerThickness = sk_l
+
end module seaice_constants
diff --git a/src/core_seaice/shared/mpas_seaice_error.F b/src/core_seaice/shared/mpas_seaice_error.F
index ea61e7ed3b..1a21bfde52 100644
--- a/src/core_seaice/shared/mpas_seaice_error.F
+++ b/src/core_seaice/shared/mpas_seaice_error.F
@@ -22,20 +22,6 @@ module seaice_error
private
save
- ! column critical error codes
- integer, parameter, public :: &
- SEAICE_ERROR_COL_VERT_THERM = 10, &
- SEAICE_ERROR_COL_ITD_THERM = 11, &
- SEAICE_ERROR_COL_RIDGING = 12, &
- SEAICE_ERROR_COL_BGC = 13
-
- ! incremental remap critical error codes
- integer, parameter, public :: &
- SEAICE_ERROR_IR_NEG_AREA = 20, &
- SEAICE_ERROR_IR_NEG_MASS = 21, &
- SEAICE_ERROR_IR_MONO = 22, &
- SEAICE_ERROR_IR_CONS = 23
-
! public routines
public :: &
seaice_critical_error_write_block, &
@@ -55,7 +41,7 @@ module seaice_error
!
!-----------------------------------------------------------------------
- subroutine seaice_critical_error_write_block(domain, block)
+ subroutine seaice_critical_error_write_block(domain, block, abortFlag)
type(domain_type), intent(in) :: &
domain
@@ -63,12 +49,19 @@ subroutine seaice_critical_error_write_block(domain, block)
type(block_type), intent(in) :: &
block
- ! write out block streams
- call mpas_stream_mgr_block_write(&
- domain % streamManager, &
- writeBlock=block, &
- streamID='abort_block', &
- forceWriteNow=.true.)
+ logical, intent(in) :: &
+ abortFlag
+
+ if (abortFlag) then
+
+ ! write out block streams
+ call mpas_stream_mgr_block_write(&
+ domain % streamManager, &
+ writeBlock=block, &
+ streamID='abort_block', &
+ forceWriteNow=.true.)
+
+ endif ! abortFlag
end subroutine seaice_critical_error_write_block
@@ -84,27 +77,29 @@ end subroutine seaice_critical_error_write_block
!
!-----------------------------------------------------------------------
- subroutine seaice_check_critical_error(domain, ierr)
+ subroutine seaice_check_critical_error(domain, abortFlag)
use mpas_dmpar, only: mpas_dmpar_max_int
- type(domain_type), intent(inout) :: &
+ type(domain_type), intent(in) :: &
domain !< Input/Output:
- integer, intent(in) :: &
- ierr
+ logical, intent(in) :: &
+ abortFlag
logical, pointer :: &
config_full_abort_write
integer :: &
+ ierr, &
ierrmax
call MPAS_pool_get_config(domain % configs, "config_full_abort_write", config_full_abort_write)
-
if (config_full_abort_write) then
! find if anyone failed
+ ierr = 0
+ if (abortFlag) ierr = 1
call mpas_dmpar_max_int(domain % dminfo, ierr, ierrmax)
if (ierrmax > 0) then
@@ -115,47 +110,10 @@ subroutine seaice_check_critical_error(domain, ierr)
endif
! check if a critical error occured
- if (ierr > 0) then
-
- ! kill the model
- call mpas_log_write("Runtime error $i: "//trim(error_string(ierr)), &
- messageType=MPAS_LOG_CRIT, intArgs=(/ierr/))
-
- endif
+ if (abortFlag) call mpas_log_write("Runtime error", messageType=MPAS_LOG_CRIT)
end subroutine seaice_check_critical_error
!-----------------------------------------------------------------------
- function error_string(ierr) result(errorStr)
-
- character(len=strKIND) :: errorStr
-
- integer, intent(in) :: ierr
-
- select case(ierr)
- case(SEAICE_ERROR_COL_VERT_THERM)
- errorStr = "Column: Vertical Thermodynamics"
- case(SEAICE_ERROR_COL_ITD_THERM)
- errorStr = "Column: ITD thermodynamics"
- case(SEAICE_ERROR_COL_RIDGING)
- errorStr = "Column: Ridging"
- case(SEAICE_ERROR_COL_BGC)
- errorStr = "Column: BGC"
- case(SEAICE_ERROR_IR_NEG_AREA)
- errorStr = "IR: Negative area"
- case(SEAICE_ERROR_IR_NEG_MASS)
- errorStr = "IR: Negative mass"
- case(SEAICE_ERROR_IR_MONO)
- errorStr = "IR: Monotonicity violation"
- case(SEAICE_ERROR_IR_CONS)
- errorStr = "IR: Conservation violation"
- case default
- errorStr = "Unknown error code"
- end select
-
- end function error_string
-
- !-----------------------------------------------------------------------
-
end module seaice_error
diff --git a/src/core_seaice/shared/mpas_seaice_forcing.F b/src/core_seaice/shared/mpas_seaice_forcing.F
index 1f95cbfc1c..e6a2a243a3 100644
--- a/src/core_seaice/shared/mpas_seaice_forcing.F
+++ b/src/core_seaice/shared/mpas_seaice_forcing.F
@@ -13,6 +13,8 @@
module seaice_forcing
+ use mpas_kind_types
+ use mpas_timer
use mpas_derived_types
use mpas_pool_routines
use mpas_timekeeping
@@ -32,7 +34,7 @@ module seaice_forcing
post_atmospheric_forcing, &
post_oceanic_coupling
- type (MPAS_forcing_group_type), pointer :: seaiceForcingGroups
+ type (MPAS_forcing_group_type), pointer, public :: seaiceForcingGroups
! forcing parameters
real (kind=RKIND), parameter :: &
@@ -63,14 +65,18 @@ module seaice_forcing
!
!-----------------------------------------------------------------------
- subroutine seaice_forcing_init(domain)
+ subroutine seaice_forcing_init(domain, clock)
type (domain_type) :: domain
+ type (MPAS_Clock_type) :: clock
+
logical, pointer :: &
- config_use_forcing
+ config_use_forcing, &
+ config_use_data_icebergs
call MPAS_pool_get_config(domain % configs, "config_use_forcing", config_use_forcing)
+ call MPAS_pool_get_config(domain % configs, "config_use_data_icebergs", config_use_data_icebergs)
if (config_use_forcing) then
@@ -82,6 +88,9 @@ subroutine seaice_forcing_init(domain)
endif
+ ! init the data iceberg forcing
+ if (config_use_data_icebergs) call init_data_iceberg_forcing(domain, clock)
+
end subroutine seaice_forcing_init
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -310,9 +319,11 @@ subroutine seaice_forcing_get(&
firstTimeStep
logical, pointer :: &
- config_use_forcing
+ config_use_forcing, &
+ config_use_data_icebergs
call MPAS_pool_get_config(domain % configs, "config_use_forcing", config_use_forcing)
+ call MPAS_pool_get_config(domain % configs, "config_use_data_icebergs", config_use_data_icebergs)
if (config_use_forcing) then
@@ -329,6 +340,15 @@ subroutine seaice_forcing_get(&
endif
+ ! data iceberg forcing
+ if (config_use_data_icebergs) then
+
+ call data_iceberg_forcing(&
+ streamManager, &
+ domain)
+
+ endif
+
end subroutine seaice_forcing_get
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -1590,6 +1610,203 @@ subroutine post_oceanic_coupling(block)
end subroutine post_oceanic_coupling
+!-----------------------------------------------------------------------
+! data iceberg forcing
+!-----------------------------------------------------------------------
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! init_data_iceberg_forcing
+!
+!> \brief
+!> \author Darin Comeau, LANL
+!> \date 27th August 2018
+!> \details This initializes the data iceberg forcing group.
+!>
+!-----------------------------------------------------------------------
+
+ subroutine init_data_iceberg_forcing(domain, clock)
+
+ type (domain_type) :: domain
+
+ type (MPAS_Clock_type) :: clock
+
+ logical, pointer :: &
+ config_do_restart
+
+ character(len=strKIND) :: &
+ forcingIntervalMonthly, &
+ forcingReferenceTimeMonthly
+
+ type (MPAS_Time_Type) :: currTime
+ character(len=strKIND) :: timeStamp
+ integer :: ierr
+
+ ! get configuration options
+ call MPAS_pool_get_config(domain % configs, "config_do_restart", config_do_restart)
+
+ forcingIntervalMonthly = "00-01-00_00:00:00"
+ forcingReferenceTimeMonthly = "0001-01-15_00:00:00"
+
+ currTime = mpas_get_clock_time(clock, MPAS_NOW, ierr)
+ call mpas_get_time(curr_time=currTime, dateTimeString=timeStamp, ierr=ierr)
+ timeStamp = '0000'//trim(timeStamp(5:))
+
+ ! create own data iceberg forcing group
+ call MPAS_forcing_init_group(&
+ seaiceForcingGroups, &
+ "seaice_data_iceberg_forcing_monthly", &
+ domain, &
+ timeStamp, &
+ '0000-01-01_00:00:00', &
+ '0001-00-00_00:00:00', &
+ config_do_restart)
+
+ ! iceberg freshwater fluxes
+ call MPAS_forcing_init_field(&
+ domain % streamManager, &
+ seaiceForcingGroups, &
+ "seaice_data_iceberg_forcing_monthly", &
+ "bergFreshwaterFluxData", &
+ "dataIcebergForcing", &
+ "berg_forcing", &
+ "bergFreshwaterFluxData", &
+ "linear", &
+ forcingReferenceTimeMonthly, &
+ forcingIntervalMonthly)
+
+ call MPAS_forcing_init_field_data(&
+ seaiceForcingGroups, &
+ "seaice_data_iceberg_forcing_monthly", &
+ domain % streamManager, &
+ config_do_restart, &
+ .false.)
+
+ end subroutine init_data_iceberg_forcing
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! data_iceberg_forcing
+!
+!> \brief
+!> \author Darin Comeau, LANL
+!> \date 27th Aug 2018
+!> \details This routine is the timestep for getting and setting fluxes
+!> from data icebergs.
+!
+!-----------------------------------------------------------------------
+
+ subroutine data_iceberg_forcing(&
+ streamManager, &
+ domain)
+
+ type (MPAS_streamManager_type), intent(inout) :: streamManager
+
+ type (domain_type) :: domain
+
+ ! Arguments for verbose debugging
+ ! type (MPAS_time_type) :: currentForcingTime
+ ! character(len=strKIND) :: currentForcingTimeStr
+
+ real(kind=RKIND), pointer :: &
+ config_dt
+
+ call mpas_pool_get_config(domain % configs, 'config_dt', config_dt)
+
+ ! For verbose debugging.
+ ! Uncomment the lines below and the arguments above to print the forcing time
+ ! to the log file, to ensure the forcing times match the simulation times.
+
+ ! call MPAS_forcing_get_forcing_time(&
+ ! seaiceForcingGroups, &
+ ! "seaice_data_iceberg_forcing_monthly", &
+ ! currentForcingTime)
+
+ ! call MPAS_get_time(currentForcingTime, dateTimeString=currentForcingTimeStr)
+ ! call MPAS_log_write('Get Data icebergs at: '//trim(currentForcingTimeStr))
+
+ ! use the forcing layer to get
+ call MPAS_forcing_get_forcing(&
+ seaiceForcingGroups, &
+ "seaice_data_iceberg_forcing_monthly", &
+ streamManager, &
+ config_dt)
+
+ call get_data_iceberg_fluxes(domain)
+
+ end subroutine data_iceberg_forcing
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! get_data_iceberg_fluxes
+!
+!> \brief Initialize with icebergs calving mass
+!> \author Darin Comeau, LANL
+!> \date 20 Aug 2018
+!> \details This routine is intended to initialize the set data iceberg
+!> meltwater and latent heat fluxes from a forcing file of monthly
+!> climatologies.
+!
+!-----------------------------------------------------------------------
+
+ subroutine get_data_iceberg_fluxes(domain)
+
+ use seaice_constants, only: &
+ seaiceLatentHeatMelting ! latent heat of melting of fresh ice (J/kg)
+
+ type(domain_type), intent(inout) :: &
+ domain
+
+ type(block_type), pointer :: &
+ block
+
+ type(MPAS_pool_type), pointer :: &
+ mesh, &
+ berg_forcing, &
+ berg_fluxes
+
+ integer, pointer :: &
+ nCellsSolve
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ bergFreshwaterFluxData, & ! iceberg freshwater flux read in from file (kg/m^2/s)
+ bergFreshwaterFlux, & ! iceberg freshwater flux for ocean (kg/m^2/s)
+ bergLatentHeatFlux ! iceberg latent heat flux for ocean (J/m^2/s)
+
+ integer :: &
+ iCell
+
+ ! dc including as parameters here so as not to create new namelist options
+ real(kind=RKIND), parameter :: &
+ specificHeatFreshIce = 2106.0_RKIND, & ! specific heat of fresh ice J * kg^-1 * K^-1
+ bergTemperature = -4.0_RKIND ! iceberg temperature, assumed constant
+
+ block => domain % blocklist
+ do while (associated(block))
+
+ call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
+ call MPAS_pool_get_subpool(block % structs, "berg_forcing", berg_forcing)
+ call MPAS_pool_get_subpool(block % structs, "berg_fluxes", berg_fluxes)
+
+ call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve)
+
+ call MPAS_pool_get_array(berg_forcing, "bergFreshwaterFluxData", bergFreshwaterFluxData)
+ call MPAS_pool_get_array(berg_fluxes, "bergFreshwaterFlux", bergFreshwaterFlux)
+ call MPAS_pool_get_array(berg_fluxes, "bergLatentHeatFlux", bergLatentHeatFlux)
+
+ do iCell = 1, nCellsSolve
+
+ bergFreshwaterFlux(iCell) = bergFreshwaterFluxData(iCell)
+ bergLatentHeatFlux(iCell) = bergFreshwaterFluxData(iCell) * &
+ (seaiceLatentHeatMelting - specificHeatFreshIce*bergTemperature)
+
+ enddo
+
+ block => block % next
+ enddo
+
+ end subroutine get_data_iceberg_fluxes
+
!-----------------------------------------------------------------------
! coupler fluxes initialization
!-----------------------------------------------------------------------
@@ -1748,6 +1965,7 @@ subroutine reset_ocean_coupler_fluxes(domain)
type(MPAS_pool_type), pointer :: &
oceanFluxes, &
+ icebergFluxes, &
biogeochemistry
real(kind=RKIND), dimension(:), pointer :: &
@@ -1756,6 +1974,10 @@ subroutine reset_ocean_coupler_fluxes(domain)
oceanHeatFlux, &
oceanShortwaveFlux
+ real(kind=RKIND), dimension(:), pointer :: &
+ bergFreshwaterFlux, &
+ bergLatentHeatFlux
+
real(kind=RKIND), dimension(:), pointer :: &
oceanNitrateFlux, &
oceanSilicateFlux, &
@@ -1776,7 +1998,8 @@ subroutine reset_ocean_coupler_fluxes(domain)
oceanDissolvedIronFlux
logical, pointer :: &
- config_use_column_biogeochemistry
+ config_use_column_biogeochemistry, &
+ config_use_data_icebergs
block => domain % blocklist
do while (associated(block))
@@ -1834,6 +2057,21 @@ subroutine reset_ocean_coupler_fluxes(domain)
endif
+ ! data icebergs
+ call MPAS_pool_get_config(block % configs, "config_use_data_icebergs", config_use_data_icebergs)
+
+ if (config_use_data_icebergs) then
+
+ call MPAS_pool_get_subpool(block % structs, "berg_fluxes", icebergFluxes)
+
+ call MPAS_pool_get_array(icebergFluxes, "bergFreshwaterFlux", bergFreshwaterFlux)
+ call MPAS_pool_get_array(icebergFluxes, "bergLatentHeatFlux", bergLatentHeatFlux)
+
+ bergFreshwaterFlux = 0.0_RKIND
+ bergLatentHeatFlux = 0.0_RKIND
+
+ endif
+
block => block % next
end do
@@ -1859,11 +2097,19 @@ subroutine seaice_forcing_write_restart_times(domain)
type(domain_type) :: domain
logical, pointer :: &
- config_use_forcing
+ config_use_forcing, &
+ config_use_prescribed_ice, &
+ config_use_prescribed_ice_forcing, &
+ config_use_data_icebergs
call MPAS_pool_get_config(domain % configs, "config_use_forcing", config_use_forcing)
+ call MPAS_pool_get_config(domain % configs, "config_use_prescribed_ice", config_use_prescribed_ice)
+ call MPAS_pool_get_config(domain % configs, "config_use_prescribed_ice_forcing", config_use_prescribed_ice_forcing)
+ call MPAS_pool_get_config(domain % configs, "config_use_data_icebergs", config_use_data_icebergs)
- if (config_use_forcing) then
+ if (config_use_forcing .or. &
+ (config_use_prescribed_ice .and. config_use_prescribed_ice_forcing) .or. &
+ config_use_data_icebergs) then
call MPAS_forcing_write_restart_times(seaiceForcingGroups)
diff --git a/src/core_seaice/shared/mpas_seaice_initialize.F b/src/core_seaice/shared/mpas_seaice_initialize.F
index ab437c38c8..2f7247ff0c 100644
--- a/src/core_seaice/shared/mpas_seaice_initialize.F
+++ b/src/core_seaice/shared/mpas_seaice_initialize.F
@@ -20,6 +20,7 @@ module seaice_initialize
use mpas_io_units
use mpas_abort
use mpas_log, only: mpas_log_write
+ use mpas_timer, only: mpas_timer_start, mpas_timer_stop
implicit none
@@ -58,6 +59,13 @@ subroutine seaice_init(&
use seaice_forcing, only: seaice_forcing_init, seaice_reset_coupler_fluxes
use seaice_diagnostics, only: &
seaice_set_testing_system_test_arrays
+ use seaice_mesh_pool, only: &
+ seaice_mesh_pool_create
+ use seaice_prescribed, only: &
+ seaice_init_prescribed_ice
+ use seaice_special_boundaries, only: &
+ seaice_init_special_boundaries, &
+ seaice_set_special_boundaries_zero_tracers
type(domain_type), intent(inout) :: &
domain !< Input/Output:
@@ -79,6 +87,12 @@ subroutine seaice_init(&
! initialize junk values
call init_junk_values(domain)
+ ! initialize special boundaries
+ call seaice_init_special_boundaries(domain)
+
+ ! initialize prescribed ice
+ call seaice_init_prescribed_ice(domain)
+
! initialize landice mask if needed for testing
call init_test_ice_shelf_mask(domain)
@@ -86,6 +100,9 @@ subroutine seaice_init(&
call mpas_log_write(" Initialize mesh...")
call seaice_init_mesh(domain)
+ call mpas_log_write(" Initialize mesh pool...")
+ call seaice_mesh_pool_create(domain)
+
! init the basic column physics package
call mpas_log_write(" Initialize column parameters...")
call seaice_init_column_physics_package_parameters(domain)
@@ -96,11 +113,13 @@ subroutine seaice_init(&
! initialize forcing
call mpas_log_write(" Initialize forcing...")
- call seaice_forcing_init(domain)
+ call seaice_forcing_init(domain, clock)
! init dynamics
call mpas_log_write(" Initialize velocity solver...")
+ call mpas_timer_start("Velocity solver init")
call seaice_init_velocity_solver(domain)
+ call mpas_timer_stop("Velocity solver init")
! init advection
call mpas_log_write(" Initialize advection...")
@@ -122,6 +141,9 @@ subroutine seaice_init(&
call mpas_log_write(" Initialize coupler fluxes...")
call seaice_reset_coupler_fluxes(domain)
+ ! special boundaries tracers
+ call seaice_set_special_boundaries_zero_tracers(domain)
+
end subroutine seaice_init!}}}
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -605,7 +627,8 @@ subroutine init_ice_cice_default(&
integer :: &
iCell, &
iCategory, &
- iIceLayer
+ iIceLayer, &
+ iSnowLayer
real(kind=RKIND), parameter :: &
initialCategorySnowThickness = 0.2_RKIND
@@ -688,8 +711,9 @@ subroutine init_ice_cice_default(&
snowVolumeCategory(1,:,iCell) = 0.0_RKIND
surfaceTemperature(1,:,iCell) = seaFreezingTemperature(iCell)
-
- snowEnthalpy(1,:,iCell) = colpkg_enthalpy_snow(0.0_RKIND)
+ do iSnowLayer = 1, nSnowLayers
+ snowEnthalpy(iSnowLayer,:,iCell) = colpkg_enthalpy_snow(0.0_RKIND)
+ end do
endif
@@ -958,9 +982,6 @@ subroutine init_ice_state_circle_of_ice(&
block, &
configs)!{{{
- use seaice_constants, only: &
- earthRadius
-
type(block_type), intent(inout) :: &
block !< Input/Output:
@@ -986,6 +1007,7 @@ subroutine init_ice_state_circle_of_ice(&
surfaceTemperature
real(kind=RKIND), pointer :: &
+ earthRadius, &
config_initial_ice_area, &
config_initial_ice_volume, &
config_initial_snow_volume
@@ -996,8 +1018,12 @@ subroutine init_ice_state_circle_of_ice(&
integer :: &
iCell
- real(kind=RKIND), parameter :: &
- circle_radius = 0.1_RKIND*earthRadius
+ real(kind=RKIND) :: &
+ circle_radius
+
+ call MPAS_pool_get_config(configs, "config_earth_radius", earthRadius)
+
+ circle_radius = 0.1_RKIND*earthRadius
call MPAS_pool_get_config(configs, "config_initial_ice_area", config_initial_ice_area)
call MPAS_pool_get_config(configs, "config_initial_ice_volume", config_initial_ice_volume)
diff --git a/src/core_seaice/shared/mpas_seaice_mesh.F b/src/core_seaice/shared/mpas_seaice_mesh.F
index 9ba4e64bfb..5ca85939ac 100644
--- a/src/core_seaice/shared/mpas_seaice_mesh.F
+++ b/src/core_seaice/shared/mpas_seaice_mesh.F
@@ -84,9 +84,6 @@ subroutine rescale_mesh(&
use mpas_stream_manager
- use seaice_constants, only: &
- earthRadius
-
type (domain_type), intent(inout) :: &
domain !< Input/Output:
@@ -96,7 +93,8 @@ subroutine rescale_mesh(&
real(kind=RKIND), pointer :: &
oldRadius, &
- sphere_radius
+ sphere_radius, &
+ earthRadius
real(kind=RKIND) :: &
newRadius
@@ -154,6 +152,7 @@ subroutine rescale_mesh(&
directionProperty
call MPAS_pool_get_config(domain % blocklist % configs, "config_do_restart", config_do_restart)
+ call MPAS_pool_get_config(domain % blocklist % configs, "config_earth_radius", earthRadius)
if (.not. config_do_restart) then
@@ -631,25 +630,26 @@ end subroutine interior_edges
!-----------------------------------------------------------------------
subroutine seaice_cell_vertices_at_vertex(&
- mesh, &
- cellVerticesAtVertex)!{{{
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
+ cellVerticesAtVertex, &
+ nVertices, &
+ vertexDegree, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ cellsOnVertex)!{{{
integer, dimension(:,:), intent(out) :: &
cellVerticesAtVertex !< Output:
- integer, pointer :: &
- nVertices, &
- vertexDegree
+ integer, intent(in) :: &
+ nVertices, & !< Input:
+ vertexDegree !< Input:
- integer, dimension(:,:), pointer :: &
- cellsOnVertex, &
- verticesOnCell
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
- integer, dimension(:), pointer :: &
- nEdgesOnCell
+ integer, dimension(:,:), intent(in) :: &
+ cellsOnVertex, & !< Input:
+ verticesOnCell !< Input:
integer :: &
iVertex, &
@@ -658,14 +658,6 @@ subroutine seaice_cell_vertices_at_vertex(&
iVertexOnCell, &
jVertex
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
- call MPAS_pool_get_dimension(mesh, "vertexDegree", vertexDegree)
-
- call MPAS_pool_get_array(mesh, "cellsOnVertex", cellsOnVertex)
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
-
do iVertex = 1, nVertices
do iVertexDegree = 1, vertexDegree
@@ -880,31 +872,43 @@ subroutine normal_vectors_planar_polygon(&
nEdgesOnCell
integer, dimension(:,:), pointer :: &
- edgesOnCell
+ edgesOnCell, &
+ verticesOnEdge
real(kind=RKIND), dimension(:), pointer :: &
- xEdge, &
- yEdge, &
+ xVertex, &
+ yVertex, &
xCell, &
- yCell
+ yCell, &
+ xEdge, &
+ yEdge
integer :: &
iCell, &
iEdgeOnCell, &
- iEdge
+ iEdge, &
+ iVertex1, &
+ iVertex2
real(kind=RKIND) :: &
- dx, dy
+ tx, &
+ ty, &
+ tmag, &
+ nx, &
+ ny
! init variables
call MPAS_pool_get_dimension(mesh, "nCells", nCells)
call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
call MPAS_pool_get_array(mesh, "edgesOnCell", edgesOnCell)
- call MPAS_pool_get_array(mesh, "xEdge", xEdge)
- call MPAS_pool_get_array(mesh, "yEdge", yEdge)
+ call MPAS_pool_get_array(mesh, "verticesOnEdge", verticesOnEdge)
+ call MPAS_pool_get_array(mesh, "xVertex", xVertex)
+ call MPAS_pool_get_array(mesh, "yVertex", yVertex)
call MPAS_pool_get_array(mesh, "xCell", xCell)
call MPAS_pool_get_array(mesh, "yCell", yCell)
+ call MPAS_pool_get_array(mesh, "xEdge", xEdge)
+ call MPAS_pool_get_array(mesh, "yEdge", yEdge)
do iCell = 1, nCells
@@ -912,11 +916,25 @@ subroutine normal_vectors_planar_polygon(&
iEdge = edgesOnCell(iEdgeOnCell,iCell)
- dx = xEdge(iEdge) - xCell(iCell)
- dy = yEdge(iEdge) - yCell(iCell)
+ iVertex1 = verticesOnEdge(1,iEdge)
+ iVertex2 = verticesOnEdge(2,iEdge)
+
+ tx = xVertex(iVertex2) - xVertex(iVertex1)
+ ty = yVertex(iVertex2) - yVertex(iVertex1)
+ tmag = sqrt(tx**2 + ty**2)
+ tx = tx / tmag
+ ty = ty / tmag
+
+ nx = xEdge(iEdge) - xCell(iCell)
+ ny = yEdge(iEdge) - yCell(iCell)
+
+ if ((nx * ty - ny * tx) < 0.0_RKIND) then
+ tx = -tx
+ ty = -ty
+ endif
- normalVectorPolygon(1,iEdgeOnCell,iCell) = dx / sqrt(dx**2 + dy**2)
- normalVectorPolygon(2,iEdgeOnCell,iCell) = dy / sqrt(dx**2 + dy**2)
+ normalVectorPolygon(1,iEdgeOnCell,iCell) = ty
+ normalVectorPolygon(2,iEdgeOnCell,iCell) = -tx
enddo ! iEdgeOnCell
diff --git a/src/core_seaice/shared/mpas_seaice_mesh_pool.F b/src/core_seaice/shared/mpas_seaice_mesh_pool.F
new file mode 100644
index 0000000000..4594a89e36
--- /dev/null
+++ b/src/core_seaice/shared/mpas_seaice_mesh_pool.F
@@ -0,0 +1,286 @@
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_mesh_pool
+!
+!> \brief
+!> \date 2020
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+module seaice_mesh_pool
+
+#include "gpu_macros.inc"
+
+ use mpas_derived_types
+ use mpas_pool_routines
+ use mpas_log
+
+ implicit none
+ private
+
+ integer, public :: &
+ nCells, &
+ nVerticesSolve, &
+ vertexDegree
+
+ integer, public, dimension(:), pointer :: &
+ nEdgesOnCell, &
+ solveStress, &
+ solveVelocity
+
+ integer, public, dimension(:,:), pointer :: &
+ verticesOnCell, &
+ cellsOnVertex, &
+ cellVerticesAtVertex
+
+ real(kind=RKIND), public, dimension(:), pointer :: &
+ areaTriangle, &
+ tanLatVertexRotatedOverRadius, &
+ icePressure, &
+ uVelocity, &
+ vVelocity, &
+ stressDivergenceU, &
+ stressDivergenceV
+
+ real(kind=RKIND), public, dimension(:,:), pointer :: &
+ stress11, &
+ stress12, &
+ stress22
+
+ real(kind=RKIND), public, dimension(:,:,:), pointer :: &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsU,&
+ basisIntegralsV,&
+ basisIntegralsMetric
+
+ public :: &
+ seaice_mesh_pool_create, &
+ seaice_mesh_pool_update, &
+ seaice_mesh_pool_destroy
+
+!-----------------------------------------------------------------------
+
+contains
+
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_mesh_pool_create
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_mesh_pool_create(&
+ domain)!{{{
+
+ type(domain_type) :: &
+ domain
+
+ integer :: &
+ blockCount
+
+ type(block_type), pointer :: &
+ block
+
+ type (mpas_pool_type), pointer :: &
+ meshPool, &
+ velocitySolverPool, &
+ velocityVariationalPool
+
+ integer, pointer :: &
+ nCellsTmp, &
+ nVerticesSolveTmp, &
+ vertexDegreeTmp
+
+ blockCount = 0
+ block => domain % blocklist
+ do while ( associated(block) )
+
+ blockCount = blockCount + 1
+ if (blockCount > 1) then
+ call mpas_log_write('seaice_mesh_pool_create: more than one block is no longer supported', MPAS_LOG_CRIT)
+ endif
+
+ call mpas_pool_get_subpool(block % structs, 'mesh', meshPool)
+ call mpas_pool_get_subpool(block % structs, 'velocity_solver', velocitySolverPool)
+ call MPAS_pool_get_subpool(block % structs, "velocity_variational", velocityVariationalPool)
+
+ ! convert mesh dimensions from pointers to scalars
+ call mpas_pool_get_dimension(meshPool, 'nCells', nCellsTmp)
+ call MPAS_pool_get_dimension(meshPool, "nVerticesSolve", nVerticesSolveTmp)
+ call MPAS_pool_get_dimension(meshPool, "vertexDegree", vertexDegreeTmp)
+
+ nCells = nCellsTmp
+ nVerticesSolve = nVerticesSolveTmp
+ vertexDegree = vertexDegreeTmp
+
+ ! point to existing arrays
+ call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell)
+ call mpas_pool_get_array(meshPool, 'verticesOnCell', verticesOnCell)
+ call mpas_pool_get_array(meshPool, 'cellsOnVertex', cellsOnVertex)
+ call mpas_pool_get_array(meshPool, 'areaTriangle', areaTriangle)
+
+ call MPAS_pool_get_array(velocitySolverPool, "solveStress", solveStress)
+ call MPAS_pool_get_array(velocitySolverPool, "solveVelocity", solveVelocity)
+ call MPAS_pool_get_array(velocitySolverPool, "icePressure", icePressure)
+ call MPAS_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
+ call MPAS_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
+ call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceU", stressDivergenceU)
+ call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceV", stressDivergenceV)
+
+ call MPAS_pool_get_array(velocityVariationalPool, "basisGradientU", basisGradientU)
+ call MPAS_pool_get_array(velocityVariationalPool, "basisGradientV", basisGradientV)
+ call MPAS_pool_get_array(velocityVariationalPool, "basisIntegralsU", basisIntegralsU)
+ call MPAS_pool_get_array(velocityVariationalPool, "basisIntegralsV", basisIntegralsV)
+ call MPAS_pool_get_array(velocityVariationalPool, "basisIntegralsMetric", basisIntegralsMetric)
+ call MPAS_pool_get_array(velocityVariationalPool, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
+ call MPAS_pool_get_array(velocityVariationalPool, "cellVerticesAtVertex", cellVerticesAtVertex)
+ call MPAS_pool_get_array(velocityVariationalPool, "stress11", stress11)
+ call MPAS_pool_get_array(velocityVariationalPool, "stress22", stress22)
+ call MPAS_pool_get_array(velocityVariationalPool, "stress12", stress12)
+
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+!$GPU ENTER_DATA COPY_IN_LP &
+!$GPUC nCells, &
+!$GPUC nVerticesSolve, &
+!$GPUC vertexDegree, &
+!$GPUC nEdgesOnCell, &
+!$GPUC verticesOnCell, &
+!$GPUC cellsOnVertex, &
+!$GPUC areaTriangle, &
+!$GPUC solveStress, &
+!$GPUC solveVelocity, &
+!$GPUC icePressure, &
+!$GPUC uVelocity, &
+!$GPUC vVelocity, &
+!$GPUC stressDivergenceU, &
+!$GPUC stressDivergenceV, &
+!$GPUC basisGradientU, &
+!$GPUC basisGradientV, &
+!$GPUC basisIntegralsU, &
+!$GPUC basisIntegralsV, &
+!$GPUC basisIntegralsMetric, &
+!$GPUC tanLatVertexRotatedOverRadius, &
+!$GPUC cellVerticesAtVertex, &
+!$GPUC stress11, &
+!$GPUC stress12, &
+!$GPUC stress22 &
+!$GPUF
+#endif
+
+ block => block % next
+ end do
+
+ end subroutine seaice_mesh_pool_create!}}}
+!-----------------------------------------------------------------------
+
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_mesh_pool_destroy
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_mesh_pool_destroy(&
+ err)!{{{
+
+ integer, intent(out) :: &
+ err ! returned error flag
+
+ err = 0
+
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+ ! first delete on device
+!$GPU EXIT_DATA COPY_DEL_LP &
+!$GPUC nCells, &
+!$GPUC nVerticesSolve, &
+!$GPUC vertexDegree, &
+!$GPUC nEdgesOnCell, &
+!$GPUC verticesOnCell, &
+!$GPUC cellsOnVertex, &
+!$GPUC areaTriangle, &
+!$GPUC solveStress, &
+!$GPUC solveVelocity, &
+!$GPUC icePressure, &
+!$GPUC uVelocity, &
+!$GPUC vVelocity, &
+!$GPUC stressDivergenceU, &
+!$GPUC stressDivergenceV, &
+!$GPUC basisGradientU, &
+!$GPUC basisGradientV, &
+!$GPUC basisIntegralsU, &
+!$GPUC basisIntegralsV, &
+!$GPUC basisIntegralsMetric, &
+!$GPUC tanLatVertexRotatedOverRadius, &
+!$GPUC cellVerticesAtVertex, &
+!$GPUC stress11, &
+!$GPUC stress12, &
+!$GPUC stress22 &
+!$GPUF
+#endif
+
+ ! then nullify on host
+ nullify(nEdgesOnCell, &
+ verticesOnCell, &
+ cellsOnVertex, &
+ areaTriangle, &
+ solveStress, &
+ solveVelocity, &
+ icePressure, &
+ uVelocity, &
+ vVelocity, &
+ stressDivergenceU, &
+ stressDivergenceV, &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsU, &
+ basisIntegralsV, &
+ basisIntegralsMetric, &
+ tanLatVertexRotatedOverRadius, &
+ cellVerticesAtVertex, &
+ stress11, &
+ stress12, &
+ stress22 &
+ )
+
+ end subroutine seaice_mesh_pool_destroy!}}}
+!-----------------------------------------------------------------------
+
+
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_mesh_pool_update
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_mesh_pool_update(&
+ domain)!{{{
+
+ type(domain_type) :: &
+ domain
+
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+ ! update arrays on device
+!$GPU UPDATE_D_LP &
+!$GPUC solveStress, &
+!$GPUC solveVelocity, &
+!$GPUC icePressure, &
+!$GPUC uVelocity, &
+!$GPUC vVelocity, &
+!$GPUC stress11, &
+!$GPUC stress12, &
+!$GPUC stress22 &
+!$GPUF
+#endif
+
+ end subroutine seaice_mesh_pool_update!}}}
+!-----------------------------------------------------------------------
+
+
+
+end module seaice_mesh_pool
diff --git a/src/core_seaice/shared/mpas_seaice_prescribed.F b/src/core_seaice/shared/mpas_seaice_prescribed.F
new file mode 100644
index 0000000000..fe6c16dca6
--- /dev/null
+++ b/src/core_seaice/shared/mpas_seaice_prescribed.F
@@ -0,0 +1,374 @@
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_prescribed
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 7th November 2018
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+module seaice_prescribed
+
+ use mpas_derived_types
+ use mpas_pool_routines
+ use mpas_forcing
+ use seaice_forcing, only: seaiceForcingGroups
+
+ implicit none
+
+ private
+ save
+
+ public :: &
+ seaice_init_prescribed_ice, &
+ seaice_run_prescribed_ice
+
+contains
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_init_prescribed_ice
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 7th November 2018
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_init_prescribed_ice(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ logical, pointer :: &
+ config_use_prescribed_ice, &
+ config_use_prescribed_ice_forcing, &
+ config_use_dynamics, &
+ config_use_column_itd_thermodynamics, &
+ config_do_restart
+
+ character(len=strKIND) :: &
+ forcingIntervalMonthly, &
+ forcingReferenceTimeMonthly
+
+ call mpas_pool_get_config(domain % configs, "config_use_prescribed_ice", config_use_prescribed_ice)
+ if (config_use_prescribed_ice) then
+
+ ! check for compatable options
+ call mpas_pool_get_config(domain % configs, "config_use_dynamics", config_use_dynamics)
+ if (config_use_dynamics) then
+ call mpas_log_write("Prescribed ice mode: Dynamics must be off (config_use_dynamics = false)", MPAS_LOG_CRIT)
+ endif
+
+ call mpas_pool_get_config(domain % configs, "config_use_column_itd_thermodynamics", config_use_column_itd_thermodynamics)
+ if (config_use_column_itd_thermodynamics) then
+ call mpas_log_write("Prescribed ice mode: ITD thermodynamics must be off (config_use_column_itd_thermodynamics = false)", MPAS_LOG_CRIT)
+ endif
+
+ call mpas_pool_get_config(domain % configs, "config_use_prescribed_ice_forcing", config_use_prescribed_ice_forcing)
+ if (config_use_prescribed_ice_forcing) then
+
+ call MPAS_pool_get_config(domain % configs, "config_do_restart", config_do_restart)
+
+ ! create the monthly forcing group
+ call MPAS_forcing_init_group(&
+ seaiceForcingGroups, &
+ "seaice_prescribed_ice_coverage", &
+ domain, &
+ '0000-01-01_00:00:00', &
+ '0000-01-01_00:00:00', &
+ '0001-00-00_00:00:00', &
+ config_do_restart)
+
+ forcingIntervalMonthly = "00-01-00_00:00:00"
+ forcingReferenceTimeMonthly = "0001-01-15_00:00:00"
+
+ call MPAS_forcing_init_field(&
+ domain % streamManager, &
+ seaiceForcingGroups, &
+ "seaice_prescribed_ice_coverage", &
+ "iceCoverage", &
+ "prescribedIceForcing", &
+ "prescribed_ice", &
+ "iceCoverage", &
+ "linear", &
+ forcingReferenceTimeMonthly, &
+ forcingIntervalMonthly)
+
+ call MPAS_forcing_init_field_data(&
+ seaiceForcingGroups, &
+ "seaice_prescribed_ice_coverage", &
+ domain % streamManager, &
+ config_do_restart, &
+ .false.)
+
+ endif ! config_use_prescribed_ice_forcing
+
+ endif ! config_use_prescribed_ice
+
+ end subroutine seaice_init_prescribed_ice
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_run_prescribed_ice
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 7th November 2018
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_run_prescribed_ice(domain)
+
+ use seaice_constants, only: &
+ seaicePuny
+
+ use ice_colpkg, only: &
+ colpkg_enthalpy_snow, &
+ colpkg_enthalpy_ice, &
+ colpkg_salinity_profile
+
+ use seaice_column, only: &
+ seaice_column_reinitialize_fluxes, &
+ seaice_column_aggregate
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ logical, pointer :: &
+ config_use_prescribed_ice, &
+ config_use_prescribed_ice_forcing
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(mpas_pool_type), pointer :: &
+ prescribedIcePool, &
+ tracersPool, &
+ initialPool, &
+ oceanCouplingPool, &
+ meshPool, &
+ velocitySolverPool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ iceCoverage, &
+ categoryThicknessLimits, &
+ seaFreezingTemperature, &
+ latCell, &
+ freezingMeltingPotential, &
+ uVelocity, &
+ vVelocity, &
+ oceanStressCellU, &
+ oceanStressCellV
+
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ iceAreaCategory, &
+ iceVolumeCategory, &
+ snowVolumeCategory, &
+ surfaceTemperature, &
+ iceEnthalpy, &
+ iceSalinity, &
+ snowEnthalpy
+
+ real(kind=RKIND) :: &
+ iceThickness, &
+ snowThickness, &
+ depth, &
+ iceTemperature, &
+ temperatureGradient
+
+ real(kind=RKIND), pointer :: &
+ config_dt
+
+ integer, pointer :: &
+ nCells, &
+ nCategories, &
+ nIceLayers, &
+ nSnowLayers
+
+ integer :: &
+ iCell, &
+ iCategory, &
+ iIceLayer, &
+ iSnowLayer
+
+ call mpas_pool_get_config(domain % configs, "config_use_prescribed_ice", config_use_prescribed_ice)
+ if (config_use_prescribed_ice) then
+
+ ! get ice coverage
+ call mpas_pool_get_config(domain % configs, "config_use_prescribed_ice_forcing", config_use_prescribed_ice_forcing)
+ if (config_use_prescribed_ice_forcing) then
+
+ call mpas_pool_get_config(domain % configs, 'config_dt', config_dt)
+
+ call MPAS_forcing_get_forcing(&
+ seaiceForcingGroups, &
+ "seaice_prescribed_ice_coverage", &
+ domain % streamManager, &
+ config_dt)
+
+ endif ! config_use_prescribed_ice_forcing
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call mpas_pool_get_subpool(blockPtr % structs, "prescribed_ice", prescribedIcePool)
+ call mpas_pool_get_subpool(blockPtr % structs, "tracers", tracersPool)
+ call mpas_pool_get_subpool(blockPtr % structs, "initial", initialPool)
+ call mpas_pool_get_subpool(blockPtr % structs, "ocean_coupling", oceanCouplingPool)
+ call mpas_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+
+ call mpas_pool_get_array(prescribedIcePool, "iceCoverage", iceCoverage)
+
+ call mpas_pool_get_array(tracersPool, "iceAreaCategory", iceAreaCategory, 1)
+ call mpas_pool_get_array(tracersPool, "iceVolumeCategory", iceVolumeCategory, 1)
+ call mpas_pool_get_array(tracersPool, "snowVolumeCategory", snowVolumeCategory, 1)
+ call mpas_pool_get_array(tracersPool, "surfaceTemperature", surfaceTemperature, 1)
+ call mpas_pool_get_array(tracersPool, "iceEnthalpy", iceEnthalpy, 1)
+ call mpas_pool_get_array(tracersPool, "iceSalinity", iceSalinity, 1)
+ call mpas_pool_get_array(tracersPool, "snowEnthalpy", snowEnthalpy, 1)
+
+ call mpas_pool_get_array(initialPool, "categoryThicknessLimits", categoryThicknessLimits)
+
+ call mpas_pool_get_array(oceanCouplingPool, "seaFreezingTemperature", seaFreezingTemperature)
+
+ call mpas_pool_get_array(meshPool, "latCell", latCell)
+
+ call mpas_pool_get_dimension(blockPtr % dimensions, "nCells", nCells)
+ call mpas_pool_get_dimension(blockPtr % dimensions, "nCategories", nCategories)
+ call mpas_pool_get_dimension(blockPtr % dimensions, "nIceLayers", nIceLayers)
+ call mpas_pool_get_dimension(blockPtr % dimensions, "nSnowLayers", nSnowLayers)
+
+ do iCell = 1, nCells
+
+ ! limit ice coverage
+ if (iceCoverage(iCell) < 1e-4_RKIND) iceCoverage(iCell) = 0.0_RKIND
+ if (iceCoverage(iCell) > 1.0_RKIND) iceCoverage(iCell) = 1.0_RKIND
+
+ if (iceCoverage(iCell) >= 1e-4_RKIND) then
+
+ ! set thickness based on hemisphere
+ if (latCell(iCell) >= 0.0) then
+ iceThickness = 2.0_RKIND
+ else if (latCell(iCell) < 0.0) then
+ iceThickness = 1.0_RKIND
+ endif
+
+ ! loop over categories
+ do iCategory = 1, nCategories
+
+ ! find relevant thickness category
+ if (iceThickness >= categoryThicknessLimits(iCategory) .and. & !!!! index limits
+ iceThickness < categoryThicknessLimits(iCategory+1)) then
+
+ if (iceAreaCategory(1,iCategory,iCell) > 0.0_RKIND) then
+ snowThickness = snowVolumeCategory(1,iCategory,iCell) / iceAreaCategory(1,iCategory,iCell)
+ else
+ snowThickness = 0.0_RKIND
+ endif ! prognostic ice present
+
+ ! reset ice state
+ iceAreaCategory(1,iCategory,iCell) = iceCoverage(iCell)
+ iceVolumeCategory(1,iCategory,iCell) = iceThickness * iceAreaCategory(1,iCategory,iCell)
+ snowVolumeCategory(1,iCategory,iCell) = snowThickness * iceAreaCategory(1,iCategory,iCell)
+
+ ! set thermodynamic tracers
+ if (abs(iceEnthalpy(1,iCategory,iCell)) < seaicePuny) then !!!!! check indices
+
+ if (iceAreaCategory(1,iCategory,iCell) < seaicePuny) then
+ surfaceTemperature(1,iCategory,iCell) = seaFreezingTemperature(iCell)
+ endif
+
+ temperatureGradient = seaFreezingTemperature(iCell) - surfaceTemperature(1,iCategory,iCell)
+
+ ! ice quantities
+ do iIceLayer = 1, nIceLayers
+
+ depth = (real(iIceLayer,kind=RKIND) - 0.5_RKIND) / real(nIceLayers,kind=RKIND)
+ iceTemperature = surfaceTemperature(1,iCategory,iCell) + temperatureGradient * depth
+ iceSalinity(iIceLayer,iCategory,iCell) = colpkg_salinity_profile(depth)
+ iceEnthalpy(iIceLayer,iCategory,iCell) = colpkg_enthalpy_ice(iceTemperature,iceSalinity(iIceLayer,iCategory,iCell))
+
+ enddo ! iIceLayer
+
+ ! snow quantities
+ do iSnowLayer = 1, nSnowLayers
+ snowEnthalpy(iSnowLayer,iCategory,iCell) = colpkg_enthalpy_snow(surfaceTemperature(1,iCategory,iCell))
+ enddo ! iSnowLayer
+
+ endif
+
+ else
+
+ surfaceTemperature(1,iCategory,iCell) = seaFreezingTemperature(iCell)
+ iceAreaCategory(1,iCategory,iCell) = 0.0_RKIND
+ iceVolumeCategory(1,iCategory,iCell) = 0.0_RKIND
+ snowVolumeCategory(1,iCategory,iCell) = 0.0_RKIND
+ iceSalinity(:,iCategory,iCell) = 0.0_RKIND
+ iceEnthalpy(:,iCategory,iCell) = 0.0_RKIND
+ snowEnthalpy(:,iCategory,iCell) = 0.0_RKIND
+
+ endif ! in category
+
+ enddo ! iCategory
+
+ else
+
+ ! low ice coverage
+ surfaceTemperature(1,:,iCell) = seaFreezingTemperature(iCell)
+ iceAreaCategory(1,:,iCell) = 0.0_RKIND
+ iceVolumeCategory(1,:,iCell) = 0.0_RKIND
+ snowVolumeCategory(1,:,iCell) = 0.0_RKIND
+ iceSalinity(:,:,iCell) = 0.0_RKIND
+ iceEnthalpy(:,:,iCell) = 0.0_RKIND
+ snowEnthalpy(:,:,iCell) = 0.0_RKIND
+
+ endif ! ice coverage
+
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ ! aggregate tracers
+ call seaice_column_aggregate(domain)
+
+ ! set non-computed fluxes, ice velocities, ice-ocn stresses to zero
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call mpas_pool_get_subpool(blockPtr % structs, "velocity_solver", velocitySolverPool)
+ call mpas_pool_get_subpool(blockPtr % structs, "ocean_coupling", oceanCouplingPool)
+
+ call mpas_pool_get_array(oceanCouplingPool, "freezingMeltingPotential", freezingMeltingPotential)
+ call mpas_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
+ call mpas_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
+ call mpas_pool_get_array(velocitySolverPool, "oceanStressCellU", oceanStressCellU)
+ call mpas_pool_get_array(velocitySolverPool, "oceanStressCellV", oceanStressCellV)
+
+ freezingMeltingPotential(:) = 0.0_RKIND
+ uVelocity(:) = 0.0_RKIND
+ vVelocity(:) = 0.0_RKIND
+ oceanStressCellU(:) = 0.0_RKIND
+ oceanStressCellV(:) = 0.0_RKIND
+
+ blockPtr => blockPtr % next
+ enddo
+
+ ! reinitialize fluxes
+ call seaice_column_reinitialize_fluxes(domain)
+
+ endif ! prescribed ice mode
+
+ end subroutine seaice_run_prescribed_ice
+
+ !-----------------------------------------------------------------------
+
+end module seaice_prescribed
diff --git a/src/core_seaice/shared/mpas_seaice_special_boundaries.F b/src/core_seaice/shared/mpas_seaice_special_boundaries.F
new file mode 100644
index 0000000000..8af16514df
--- /dev/null
+++ b/src/core_seaice/shared/mpas_seaice_special_boundaries.F
@@ -0,0 +1,414 @@
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_special_boundaries
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 23rd December 2020
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+module seaice_special_boundaries
+
+ use mpas_derived_types
+ use mpas_pool_routines
+
+ implicit none
+
+ private
+ save
+
+ public :: &
+ seaice_init_special_boundaries, &
+ seaice_set_special_boundaries_velocity, &
+ seaice_set_special_boundaries_velocity_masks, &
+ seaice_set_special_boundaries_zero_tracers
+
+ logical, pointer :: &
+ useSpecialBoundariesVelocity, &
+ useSpecialBoundariesVelocityMasks, &
+ useSpecialBoundariesZeroTracers
+
+ ! vertex flags
+ integer, parameter :: &
+ VELOCITY_BOUNDARY_NONE = 0, &
+ VELOCITY_BOUNDARY_PERIODIC = 1, &
+ VELOCITY_BOUNDARY_REVERSE = 2, &
+ VELOCITY_BOUNDARY_ZERO = 3
+
+ ! cell flags
+ integer, parameter :: &
+ TRACER_BOUNDARY_NONE = 0, &
+ TRACER_BOUNDARY_ZERO = 1
+
+contains
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_init_special_boundaries
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 23rd December 2020
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_init_special_boundaries(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ call init_special_boundaries_velocity(domain)
+
+ call init_special_boundaries_tracers(domain)
+
+ end subroutine seaice_init_special_boundaries
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! init_special_boundaries_velocity
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 23rd December 2020
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine init_special_boundaries_velocity(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(mpas_pool_type), pointer :: &
+ specialBoundariesPool, &
+ meshPool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ xVertex, &
+ yVertex
+
+ integer, dimension(:), pointer :: &
+ vertexBoundaryType, &
+ vertexBoundarySource, &
+ vertexBoundarySourceLocal, &
+ indexToVertexID
+
+ integer, dimension(:), allocatable :: &
+ globalToLocalID
+
+ integer, pointer :: &
+ nVertices
+
+ integer :: &
+ iVertex
+
+ call MPAS_pool_get_config(domain % configs, "config_use_special_boundaries_velocity", useSpecialBoundariesVelocity)
+ call MPAS_pool_get_config(domain % configs, "config_use_special_boundaries_velocity_masks", useSpecialBoundariesVelocityMasks)
+
+ if (useSpecialBoundariesVelocity) then
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nVertices", nVertices)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "special_boundaries", specialBoundariesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+
+ call MPAS_pool_get_array(specialBoundariesPool, "vertexBoundaryType", vertexBoundaryType)
+ call MPAS_pool_get_array(specialBoundariesPool, "vertexBoundarySource", vertexBoundarySource)
+ call MPAS_pool_get_array(specialBoundariesPool, "vertexBoundarySourceLocal", vertexBoundarySourceLocal)
+
+ call MPAS_pool_get_array(meshPool, "xVertex", xVertex)
+ call MPAS_pool_get_array(meshPool, "yVertex", yVertex)
+ call MPAS_pool_get_array(meshPool, "indexToVertexID", indexToVertexID)
+
+ allocate(globalToLocalID(nVertices))
+
+ do iVertex = 1, nVertices
+
+ globalToLocalID(indexToVertexID(iVertex)) = iVertex
+
+ enddo ! iVertex
+
+ do iVertex = 1, nVertices
+
+ vertexBoundarySourceLocal(iVertex) = globalToLocalID(vertexBoundarySource(iVertex))
+
+ enddo ! iVertex
+
+ deallocate(globalToLocalID)
+
+ blockPtr => blockPtr % next
+ enddo
+
+ endif
+
+ end subroutine init_special_boundaries_velocity
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! init_special_boundaries_tracers
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 16th January 2021
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine init_special_boundaries_tracers(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ call MPAS_pool_get_config(domain % configs, "config_use_special_boundaries_zero_tracers", useSpecialBoundariesZeroTracers)
+
+ end subroutine init_special_boundaries_tracers
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_set_special_boundaries_velocity
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 23rd December 2020
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_set_special_boundaries_velocity(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(mpas_pool_type), pointer :: &
+ velocitySolverPool, &
+ specialBoundariesPool, &
+ meshPool
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ uVelocity, &
+ vVelocity, &
+ xVertex, &
+ yVertex
+
+ integer, dimension(:), pointer :: &
+ vertexBoundaryType, &
+ vertexBoundarySource, &
+ indexToVertexID
+
+ integer, pointer :: &
+ nVertices
+
+ integer :: &
+ iVertex, &
+ iVertexSource
+
+ if (useSpecialBoundariesVelocity) then
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nVertices", nVertices)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "special_boundaries", specialBoundariesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "velocity_solver", velocitySolverPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+
+ call MPAS_pool_get_array(specialBoundariesPool, "vertexBoundaryType", vertexBoundaryType)
+ call MPAS_pool_get_array(specialBoundariesPool, "vertexBoundarySourceLocal", vertexBoundarySource)
+
+ call MPAS_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
+ call MPAS_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
+
+ do iVertex = 1, nVertices
+
+ if (vertexBoundaryType(iVertex) == VELOCITY_BOUNDARY_PERIODIC) then
+
+ iVertexSource = vertexBoundarySource(iVertex)
+
+ uVelocity(iVertex) = uVelocity(iVertexSource)
+ vVelocity(iVertex) = vVelocity(iVertexSource)
+
+ else if (vertexBoundaryType(iVertex) == VELOCITY_BOUNDARY_REVERSE) then
+
+ iVertexSource = vertexBoundarySource(iVertex)
+
+ uVelocity(iVertex) = -uVelocity(iVertexSource)
+ vVelocity(iVertex) = -vVelocity(iVertexSource)
+
+ else if (vertexBoundaryType(iVertex) == VELOCITY_BOUNDARY_ZERO) then
+
+ uVelocity(iVertex) = 0.0
+ vVelocity(iVertex) = 0.0
+
+ endif
+
+ enddo ! iVertex
+
+ blockPtr => blockPtr % next
+ enddo
+
+ endif
+
+ end subroutine seaice_set_special_boundaries_velocity
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_set_special_boundaries_velocity_masks
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 23rd December 2020
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_set_special_boundaries_velocity_masks(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(mpas_pool_type), pointer :: &
+ velocitySolverPool, &
+ specialBoundariesPool
+
+ integer, dimension(:), pointer :: &
+ solveVelocity, &
+ solveStress, &
+ solveVelocitySpecialBoundaries, &
+ solveStressSpecialBoundaries
+
+ integer, pointer :: &
+ nCells, &
+ nVertices
+
+ integer :: &
+ iCell, &
+ iVertex
+
+ if (useSpecialBoundariesVelocityMasks) then
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCells", nCells)
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nVertices", nVertices)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "special_boundaries", specialBoundariesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "velocity_solver", velocitySolverPool)
+
+ call MPAS_pool_get_array(specialBoundariesPool, "solveVelocitySpecialBoundaries", solveVelocitySpecialBoundaries)
+ call MPAS_pool_get_array(specialBoundariesPool, "solveStressSpecialBoundaries", solveStressSpecialBoundaries)
+
+ call MPAS_pool_get_array(velocitySolverPool, "solveVelocity", solveVelocity)
+ call MPAS_pool_get_array(velocitySolverPool, "solveStress", solveStress)
+
+ do iVertex = 1, nVertices
+ solveVelocity(iVertex) = solveVelocitySpecialBoundaries(iVertex)
+ enddo ! iVertex
+
+ do iCell = 1, nCells
+ solveStress(iCell) = solveStressSpecialBoundaries(iCell)
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ endif
+
+ end subroutine seaice_set_special_boundaries_velocity_masks
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_set_special_boundaries_zero_tracers
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 16th January 2021
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_set_special_boundaries_zero_tracers(domain)
+
+ type (domain_type), intent(inout) :: &
+ domain !< Input/Output:
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type(mpas_pool_type), pointer :: &
+ specialBoundariesPool, &
+ tracersPool
+
+ integer, dimension(:), pointer :: &
+ tracerBoundaryType
+
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ iceAreaCategory, &
+ iceVolumeCategory, &
+ snowVolumeCategory
+
+ integer, pointer :: &
+ nCells
+
+ integer :: &
+ iCell
+
+ if (useSpecialBoundariesZeroTracers) then
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_dimension(blockPtr % dimensions, "nCells", nCells)
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "special_boundaries", specialBoundariesPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "tracers", tracersPool)
+
+ call MPAS_pool_get_array(specialBoundariesPool, "tracerBoundaryType", tracerBoundaryType)
+
+ call MPAS_pool_get_array(tracersPool, "iceAreaCategory", iceAreaCategory, 1)
+ call MPAS_pool_get_array(tracersPool, "iceVolumeCategory", iceVolumeCategory, 1)
+ call MPAS_pool_get_array(tracersPool, "snowVolumeCategory", snowVolumeCategory, 1)
+
+ do iCell = 1, nCells
+
+ if (tracerBoundaryType(iCell) == TRACER_BOUNDARY_ZERO) then
+ iceAreaCategory(:,:,iCell) = 0.0_RKIND
+ iceVolumeCategory(:,:,iCell) = 0.0_RKIND
+ snowVolumeCategory(:,:,iCell) = 0.0_RKIND
+ endif
+
+ enddo ! iCell
+
+ blockPtr => blockPtr % next
+ enddo
+
+ endif
+
+ end subroutine seaice_set_special_boundaries_zero_tracers
+
+ !-----------------------------------------------------------------------
+
+end module seaice_special_boundaries
diff --git a/src/core_seaice/shared/mpas_seaice_time_integration.F b/src/core_seaice/shared/mpas_seaice_time_integration.F
index 331c8c6be9..348bcf2190 100644
--- a/src/core_seaice/shared/mpas_seaice_time_integration.F
+++ b/src/core_seaice/shared/mpas_seaice_time_integration.F
@@ -42,8 +42,7 @@ module seaice_time_integration
subroutine seaice_timestep(&
domain, &
clock, &
- itimestep, &
- ierr)!{{{
+ itimestep)!{{{
use mpas_timer
@@ -52,9 +51,6 @@ subroutine seaice_timestep(&
seaice_check_state, &
seaice_load_balance_timers
- use seaice_unit_test, only: &
- seaice_perform_unit_test
-
use seaice_velocity_solver, only: &
seaice_run_velocity_solver
@@ -70,6 +66,12 @@ subroutine seaice_timestep(&
seaice_column_reinitialize_diagnostics_bgc, &
seaice_column_reinitialize_diagnostics_dynamics
+ use seaice_prescribed, only: &
+ seaice_run_prescribed_ice
+
+ use seaice_special_boundaries, only: &
+ seaice_set_special_boundaries_zero_tracers
+
type(domain_type), intent(inout) :: &
domain !< Input/Output:
@@ -79,9 +81,6 @@ subroutine seaice_timestep(&
integer, intent(in) :: &
itimestep !< Input:
- integer, intent(inout) :: &
- ierr !< Input
-
type(block_type), pointer :: &
block
@@ -89,7 +88,7 @@ subroutine seaice_timestep(&
configs
logical, pointer :: &
- config_perform_unit_test, &
+ config_use_dynamics, &
config_use_advection
integer, pointer :: &
@@ -121,47 +120,46 @@ subroutine seaice_timestep(&
configs => domain % configs
call MPAS_pool_get_config(configs, "config_use_advection", config_use_advection)
- call MPAS_pool_get_config(configs, "config_perform_unit_test", config_perform_unit_test)
- if (config_perform_unit_test) then
- call seaice_perform_unit_test(domain)
- return
- endif
+ ! prescribed ice mode
+ call seaice_run_prescribed_ice(domain)
! pre dynamics column physics
call mpas_timer_start("Column pre-dynamics")
- call seaice_column_predynamics_time_integration(domain, clock, ierr)
- if (ierr > 0) return
+ call seaice_column_predynamics_time_integration(domain, clock)
call mpas_timer_stop("Column pre-dynamics")
- ! loop of dynamcis subcycle
- call MPAS_pool_get_config(configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number)
- do iDynamicsSubcycle = 1, config_dynamics_subcycle_number
+ ! dynamics
+ call MPAS_pool_get_config(configs, "config_use_dynamics", config_use_dynamics)
+ if (config_use_dynamics) then
+
+ ! loop of dynamcis subcycle
+ call MPAS_pool_get_config(configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number)
+ do iDynamicsSubcycle = 1, config_dynamics_subcycle_number
- ! reinitialize dynamics diagnostics
- call mpas_timer_start("Reinitialize diagnostics dynamics")
- call seaice_column_reinitialize_diagnostics_dynamics(domain)
- call mpas_timer_stop("Reinitialize diagnostics dynamics")
+ ! reinitialize dynamics diagnostics
+ call mpas_timer_start("Reinitialize diagnostics dynamics")
+ call seaice_column_reinitialize_diagnostics_dynamics(domain)
+ call mpas_timer_stop("Reinitialize diagnostics dynamics")
- ! velocity solve
- call mpas_timer_start("Velocity solver")
- call seaice_run_velocity_solver(domain, clock)
- call mpas_timer_stop("Velocity solver")
+ ! velocity solve
+ call mpas_timer_start("Velocity solver")
+ call seaice_run_velocity_solver(domain, clock)
+ call mpas_timer_stop("Velocity solver")
- ! advection
- call mpas_timer_start("Advection")
- if (config_use_advection) &
- call seaice_run_advection(domain, clock, ierr)
- call mpas_timer_stop("Advection")
- if (ierr > 0) return
+ ! advection
+ call mpas_timer_start("Advection")
+ if (config_use_advection) &
+ call seaice_run_advection(domain, clock)
+ call mpas_timer_stop("Advection")
- ! ridging
- call mpas_timer_start("Column")
- call seaice_column_dynamics_time_integration(domain, clock, ierr)
- call mpas_timer_stop("Column")
- if (ierr > 0) return
+ ! ridging
+ call mpas_timer_start("Column")
+ call seaice_column_dynamics_time_integration(domain, clock)
+ call mpas_timer_stop("Column")
- enddo ! iDynamicsSubcycle
+ enddo ! iDynamicsSubcycle
+ endif ! config_use_dynamics
! shortwave
call mpas_timer_start("Column post-dynamics")
@@ -171,6 +169,9 @@ subroutine seaice_timestep(&
! check the physical state of the model
call seaice_check_state(domain)
+ ! tracer special boundaries
+ call seaice_set_special_boundaries_zero_tracers(domain)
+
end subroutine seaice_timestep!}}}
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
diff --git a/src/core_seaice/shared/mpas_seaice_unit_test.F b/src/core_seaice/shared/mpas_seaice_unit_test.F
deleted file mode 100644
index db9ff7a3ac..0000000000
--- a/src/core_seaice/shared/mpas_seaice_unit_test.F
+++ /dev/null
@@ -1,74 +0,0 @@
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_unit_test
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
-module seaice_unit_test
-
- use mpas_derived_types
- use mpas_pool_routines
- use mpas_log, only: mpas_log_write
-
- private
- save
-
- public :: &
- seaice_perform_unit_test
-
-contains
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_perform_unit_test
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_perform_unit_test(&
- domain)!{{{
-
- use seaice_velocity_solver_unit_tests, only: &
- seaice_strain_rate_operator_unit_test, &
- seaice_stress_divergence_operator_unit_test, &
- seaice_constitutive_relationship_unit_test
-
- type(domain_type), intent(inout) :: &
- domain !< Input/Output:
-
- character(len=strKIND), pointer :: &
- config_unit_test_type, &
- config_unit_test_subtype
-
- call MPAS_pool_get_config(domain % configs, "config_unit_test_type", config_unit_test_type)
- call MPAS_pool_get_config(domain % configs, "config_unit_test_subtype", config_unit_test_subtype)
-
- call mpas_log_write("Unit test: "//trim(config_unit_test_type)//" "//trim(config_unit_test_subtype))
-
- select case (trim(config_unit_test_type))
- case ("strain rate operator")
- call seaice_strain_rate_operator_unit_test(domain, trim(config_unit_test_subtype))
- case ("stress divergence operator")
- call seaice_stress_divergence_operator_unit_test(domain, trim(config_unit_test_subtype))
- case ("constitutive relationship")
- call seaice_constitutive_relationship_unit_test(domain)
- case default
- call mpas_log_write("seaice_perform_unit_test: config_unit_test_type unknown: "//trim(config_unit_test_type))
- end select
-
- end subroutine seaice_perform_unit_test!}}}
-
-!-----------------------------------------------------------------------
-
-end module seaice_unit_test
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver.F b/src/core_seaice/shared/mpas_seaice_velocity_solver.F
index e960bc82e7..2f4fdae5c2 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver.F
@@ -12,12 +12,14 @@
module seaice_velocity_solver
+#include "gpu_macros.inc"
+
use mpas_derived_types
use mpas_pool_routines
use mpas_timekeeping
use mpas_dmpar
use mpas_timer
- use mpas_log, only: mpas_log_write
+ use mpas_log, only: mpas_log_write, mpas_log_info
implicit none
@@ -28,6 +30,33 @@ module seaice_velocity_solver
seaice_init_velocity_solver, &
seaice_run_velocity_solver
+ ! strain scheme type
+ integer :: &
+ strainSchemeType
+
+ integer, parameter :: &
+ WEAK_STRAIN_SCHEME = 1, &
+ VARIATIONAL_STRAIN_SCHEME = 2
+
+ logical :: &
+ averageVariationalStrains
+
+ ! stress divergence scheme type
+ integer :: &
+ stressDivergenceSchemeType
+
+ integer, parameter :: &
+ WEAK_STRESS_DIVERGENCE_SCHEME = 1, &
+ VARIATIONAL_STRESS_DIVERGENCE_SCHEME = 2
+
+ ! ocean stress type
+ integer :: &
+ oceanStressType
+
+ integer, parameter :: &
+ QUADRATIC_OCEAN_STRESS = 1, &
+ LINEAR_OCEAN_STRESS = 2
+
! velocity solver constants
real(kind=RKIND), parameter, private :: &
sinOceanTurningAngle = 0.0_RKIND, & ! northern hemisphere
@@ -72,12 +101,16 @@ subroutine seaice_init_velocity_solver(&
block
character(len=strKIND), pointer :: &
+ config_strain_scheme, &
config_stress_divergence_scheme, &
config_variational_basis, &
- config_wachspress_integration_type
+ config_variational_denominator_type, &
+ config_wachspress_integration_type, &
+ config_ocean_stress_type
logical, pointer :: &
config_use_velocity_solver, &
+ config_average_variational_strain, &
config_rotate_cartesian_grid, &
config_include_metric_terms, &
config_aggregate_halo_exch, &
@@ -131,6 +164,42 @@ subroutine seaice_init_velocity_solver(&
if (config_use_velocity_solver) then
+ ! options
+ call MPAS_pool_get_config(domain % configs, "config_strain_scheme", config_strain_scheme)
+ if (trim(config_strain_scheme) == "weak") then
+ strainSchemeType = WEAK_STRAIN_SCHEME
+ else if (trim(config_strain_scheme) == "variational") then
+ strainSchemeType = VARIATIONAL_STRAIN_SCHEME
+ else
+ call MPAS_log_write("config_strain_scheme unknown: "//trim(config_strain_scheme), MPAS_LOG_CRIT)
+ endif
+
+ call MPAS_pool_get_config(domain % configs, "config_stress_divergence_scheme", config_stress_divergence_scheme)
+ if (trim(config_stress_divergence_scheme) == "weak") then
+ stressDivergenceSchemeType = WEAK_STRESS_DIVERGENCE_SCHEME
+ else if (trim(config_stress_divergence_scheme) == "variational") then
+ stressDivergenceSchemeType = VARIATIONAL_STRESS_DIVERGENCE_SCHEME
+ else
+ call MPAS_log_write("config_stress_divergence_scheme unknown: "//trim(config_stress_divergence_scheme), MPAS_LOG_CRIT)
+ endif
+
+ call MPAS_pool_get_config(domain % configs, "config_ocean_stress_type", config_ocean_stress_type)
+ if (trim(config_ocean_stress_type) == "quadratic") then
+ oceanStressType = QUADRATIC_OCEAN_STRESS
+ else if (trim(config_ocean_stress_type) == "linear") then
+ oceanStressType = LINEAR_OCEAN_STRESS
+ else
+ call MPAS_log_write("config_ocean_stress_type unknown: "//trim(config_ocean_stress_type), MPAS_LOG_CRIT)
+ endif
+
+ if (strainSchemeType == VARIATIONAL_STRAIN_SCHEME .and. &
+ stressDivergenceSchemeType == WEAK_STRESS_DIVERGENCE_SCHEME) then
+ call MPAS_log_write("Cannot have variational strain scheme with variational stress divergence scheme", MPAS_LOG_CRIT)
+ endif
+
+ call MPAS_pool_get_config(domain % configs, "config_average_variational_strain", config_average_variational_strain)
+ averageVariationalStrains = config_average_variational_strain
+
! initialize the evp solver
call seaice_init_evp(domain)
@@ -142,14 +211,16 @@ subroutine seaice_init_velocity_solver(&
call MPAS_pool_get_subpool(block % structs, "velocity_weak", velocity_weak)
call MPAS_pool_get_subpool(block % structs, "velocity_variational", velocity_variational)
- call MPAS_pool_get_config(block % configs, "config_stress_divergence_scheme", config_stress_divergence_scheme)
call MPAS_pool_get_config(block % configs, "config_variational_basis", config_variational_basis)
+ call MPAS_pool_get_config(block % configs, "config_variational_denominator_type", config_variational_denominator_type)
call MPAS_pool_get_config(block % configs, "config_rotate_cartesian_grid", config_rotate_cartesian_grid)
call MPAS_pool_get_config(block % configs, "config_include_metric_terms", config_include_metric_terms)
call MPAS_pool_get_config(block % configs, "config_wachspress_integration_type", config_wachspress_integration_type)
call MPAS_pool_get_config(block % configs, "config_wachspress_integration_order", config_wachspress_integration_order)
- if (trim(config_stress_divergence_scheme) == "weak") then
+ ! init solvers
+ if (strainSchemeType == WEAK_STRAIN_SCHEME .or. &
+ stressDivergenceSchemeType == WEAK_STRESS_DIVERGENCE_SCHEME) then
call seaice_init_velocity_solver_weak(&
mesh, &
@@ -157,7 +228,10 @@ subroutine seaice_init_velocity_solver(&
velocity_weak, &
config_rotate_cartesian_grid)
- else if (trim(config_stress_divergence_scheme) == "variational") then
+ endif
+
+ if (strainSchemeType == VARIATIONAL_STRAIN_SCHEME .or. &
+ stressDivergenceSchemeType == VARIATIONAL_STRESS_DIVERGENCE_SCHEME) then
call seaice_init_velocity_solver_variational(&
mesh, &
@@ -166,17 +240,10 @@ subroutine seaice_init_velocity_solver(&
config_rotate_cartesian_grid, &
config_include_metric_terms, &
config_variational_basis, &
+ config_variational_denominator_type, &
config_wachspress_integration_type, &
config_wachspress_integration_order)
- else if (trim(config_stress_divergence_scheme) == "none") then
-
- continue
-
- else
-
- call MPAS_log_write("config_stress_divergence_scheme unknown: "//trim(config_stress_divergence_scheme), MPAS_LOG_CRIT)
-
endif
block => block % next
@@ -545,6 +612,9 @@ end subroutine seaice_run_velocity_solver!}}}
subroutine velocity_solver_pre_subcycle(domain)
+ use seaice_mesh_pool, only: &
+ seaice_mesh_pool_update
+
type(domain_type), intent(inout) :: &
domain
@@ -593,6 +663,11 @@ subroutine velocity_solver_pre_subcycle(domain)
call init_subcycle_variables(domain)
call mpas_timer_stop("init subcycle var")
+ ! update mesh pool variables
+ call mpas_timer_start("update mesh pool")
+ call seaice_mesh_pool_update(domain)
+ call mpas_timer_stop("update mesh pool")
+
end subroutine velocity_solver_pre_subcycle
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -719,7 +794,8 @@ subroutine calculation_masks(domain)
config_use_column_vertical_thermodynamics, &
config_use_halo_exch, &
config_aggregate_halo_exch, &
- config_reuse_halo_exch
+ config_reuse_halo_exch, &
+ config_calc_velocity_masks
integer :: &
ierr
@@ -818,9 +894,11 @@ subroutine calculation_masks(domain)
end do
! calculate computational masks
- call stress_calculation_mask(domain)
-
- call velocity_calculation_mask(domain)
+ call MPAS_pool_get_config(domain % configs, "config_calc_velocity_masks", config_calc_velocity_masks)
+ if (config_calc_velocity_masks) then
+ call stress_calculation_mask(domain)
+ call velocity_calculation_mask(domain)
+ endif
! halo exchange velocity mask
call seaice_load_balance_timers(domain, "vel prep before")
@@ -2327,6 +2405,10 @@ subroutine subcycle_velocity_solver(&
domain, &
clock)!{{{
+ use seaice_special_boundaries, only: &
+ seaice_set_special_boundaries_velocity, &
+ seaice_set_special_boundaries_velocity_masks
+
type(domain_type), intent(inout) :: &
domain !< Input/Output:
@@ -2339,6 +2421,27 @@ subroutine subcycle_velocity_solver(&
integer :: &
iElasticSubcycle
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+ type (MPAS_pool_type), pointer :: &
+ velocityVariationalPool
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ replacementPressure
+
+ call MPAS_pool_get_subpool(domain % blocklist % structs, "velocity_variational", velocityVariationalPool)
+ call MPAS_pool_get_array(velocityVariationalPool, "replacementPressure", replacementPressure)
+
+ call mpas_timer_start("Velocity solver memcpy HtoD")
+!$GPU DATA COPY_OUT_LP &
+!$GPUC replacementPressure &
+!$GPUF
+ call mpas_timer_stop("Velocity solver memcpy HtoD")
+#endif
+
+ ! special boundaries
+ call seaice_set_special_boundaries_velocity(domain)
+ call seaice_set_special_boundaries_velocity_masks(domain)
+
call MPAS_pool_get_config(domain % configs, "config_elastic_subcycle_number", config_elastic_subcycle_number)
do iElasticSubcycle = 1, config_elastic_subcycle_number
@@ -2348,8 +2451,16 @@ subroutine subcycle_velocity_solver(&
clock, &
iElasticSubcycle)
+ ! special boundaries
+ call seaice_set_special_boundaries_velocity(domain)
+ call seaice_set_special_boundaries_velocity_masks(domain)
+
enddo
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+!$GPU DATA_END
+#endif
+
end subroutine subcycle_velocity_solver!}}}
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -2369,15 +2480,20 @@ subroutine single_subcycle_velocity_solver(&
clock, &
iElasticSubcycle)!{{{
- use seaice_velocity_solver_weak, only: &
- seaice_internal_stress_weak
-
- use seaice_velocity_solver_variational, only: &
- seaice_internal_stress_variational
+ use seaice_velocity_solver_constitutive_relation, only: &
+ constitutiveRelationType, &
+ EVP_CONSTITUTIVE_RELATION, &
+ REVISED_EVP_CONSTITUTIVE_RELATION
use seaice_diagnostics, only: &
seaice_load_balance_timers
+ use seaice_mesh_pool, only: &
+ stressDivergenceU, &
+ stressDivergenceV, &
+ uVelocity, &
+ vVelocity
+
type(domain_type), intent(inout) :: &
domain !< Input/Output:
@@ -2387,11 +2503,7 @@ subroutine single_subcycle_velocity_solver(&
integer, intent(in) :: &
iElasticSubcycle !< Input: !! testing
- character(len=strKIND), pointer :: &
- config_stress_divergence_scheme
-
logical, pointer :: &
- config_revised_evp, &
config_use_halo_exch, &
config_aggregate_halo_exch, &
config_reuse_halo_exch
@@ -2399,23 +2511,14 @@ subroutine single_subcycle_velocity_solver(&
integer :: &
ierr
- call MPAS_pool_get_config(domain % configs, "config_stress_divergence_scheme", config_stress_divergence_scheme)
- call MPAS_pool_get_config(domain % configs, "config_revised_evp", config_revised_evp)
-
! calculate internal stresses
- if (trim(config_stress_divergence_scheme) == "weak") then
-
- call mpas_timer_start("Velocity solver internal stress")
- call seaice_internal_stress_weak(domain)
- call mpas_timer_stop("Velocity solver internal stress")
+ call mpas_timer_start("Velocity solver internal stress")
+ call seaice_internal_stress(domain)
+ call mpas_timer_stop("Velocity solver internal stress")
- else if (trim(config_stress_divergence_scheme) == "variational") then
-
- call mpas_timer_start("Velocity solver internal stress")
- call seaice_internal_stress_variational(domain)
- call mpas_timer_stop("Velocity solver internal stress")
-
- endif
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+!$GPU UPDATE_H((stressDivergenceU, stressDivergenceV))
+#endif
! ocean stress coefficient
call mpas_timer_start("ocn stress coef")
@@ -2423,13 +2526,13 @@ subroutine single_subcycle_velocity_solver(&
call mpas_timer_stop("ocn stress coef")
! solve for velocity
- if (.not. config_revised_evp) then
+ if (constitutiveRelationType == EVP_CONSTITUTIVE_RELATION) then
call mpas_timer_start("Velocity solver compute")
call solve_velocity(domain)
call mpas_timer_stop("Velocity solver compute")
- else
+ else if (constitutiveRelationType == REVISED_EVP_CONSTITUTIVE_RELATION) then
call mpas_timer_start("Velocity solver compute")
call solve_velocity_revised(domain)
@@ -2482,8 +2585,392 @@ subroutine single_subcycle_velocity_solver(&
call seaice_load_balance_timers(domain, "vel after")
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+!$GPU UPDATE_D((uVelocity, vVelocity))
+#endif
+
end subroutine single_subcycle_velocity_solver!}}}
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_internal_stress
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 28th January 2021
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_internal_stress(domain)
+
+ use seaice_mesh_pool, only: &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsMetric, &
+ basisIntegralsU, &
+ basisIntegralsV, &
+ cellVerticesAtVertex, &
+ icePressure, &
+ solveStress, &
+ solveVelocity, &
+ stress11var => stress11, &
+ stress22var => stress22, &
+ stress12var => stress12, &
+ tanLatVertexRotatedOverRadius, &
+ uVelocity, &
+ vVelocity
+
+ use seaice_velocity_solver_weak, only: &
+ seaice_strain_tensor_weak, &
+ seaice_stress_tensor_weak, &
+ seaice_stress_divergence_weak
+
+ use seaice_velocity_solver_variational, only: &
+ seaice_strain_tensor_variational, &
+ seaice_stress_tensor_variational, &
+ seaice_stress_divergence_variational, &
+ seaice_average_strains_on_vertex
+
+ type(domain_type), intent(inout) :: &
+ domain
+
+ type(block_type), pointer :: &
+ blockPtr
+
+ type (MPAS_pool_type), pointer :: &
+ meshPool, &
+ velocityWeakPool, &
+ velocityVariationalPool, &
+ velocityWeakVariationalPool, &
+ velocitySolverPool
+
+ real(kind=RKIND), pointer :: &
+ elasticTimeStep
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ stressDivergenceU, &
+ stressDivergenceV
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ replacementPressureWeak, &
+ strain11weak, &
+ strain22weak, &
+ strain12weak, &
+ stress11weak, &
+ stress22weak, &
+ stress12weak, &
+ latCellRotated, &
+ latVertexRotated, &
+ areaCell
+
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ normalVectorPolygon, &
+ normalVectorTriangle
+
+ real(kind=RKIND), dimension(:,:), pointer :: &
+ replacementPressureVar, &
+ strain11var, &
+ strain22var, &
+ strain12var
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ variationalDenominator
+
+ blockPtr => domain % blocklist
+ do while (associated(blockPtr))
+
+ call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "velocity_weak", velocityWeakPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "velocity_variational", velocityVariationalPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "velocity_weak_variational", velocityWeakVariationalPool)
+ call MPAS_pool_get_subpool(blockPtr % structs, "velocity_solver", velocitySolverPool)
+
+ call MPAS_pool_get_array(velocitySolverPool, "elasticTimeStep", elasticTimeStep)
+ call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceU", stressDivergenceU)
+ call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceV", stressDivergenceV)
+
+ if (strainSchemeType == WEAK_STRAIN_SCHEME .or. &
+ stressDivergenceSchemeType == WEAK_STRESS_DIVERGENCE_SCHEME) then
+
+ call MPAS_pool_get_array(velocityWeakPool, "normalVectorPolygon", normalVectorPolygon)
+ call MPAS_pool_get_array(velocityWeakPool, "normalVectorTriangle", normalVectorTriangle)
+ call MPAS_pool_get_array(velocityWeakPool, "latCellRotated", latCellRotated)
+ call MPAS_pool_get_array(velocityWeakPool, "latVertexRotated", latVertexRotated)
+ call MPAS_pool_get_array(velocityWeakPool, "strain11", strain11weak)
+ call MPAS_pool_get_array(velocityWeakPool, "strain22", strain22weak)
+ call MPAS_pool_get_array(velocityWeakPool, "strain12", strain12weak)
+ call MPAS_pool_get_array(velocityWeakPool, "stress11", stress11weak)
+ call MPAS_pool_get_array(velocityWeakPool, "stress22", stress22weak)
+ call MPAS_pool_get_array(velocityWeakPool, "stress12", stress12weak)
+ call MPAS_pool_get_array(velocityWeakPool, "replacementPressure", replacementPressureWeak)
+
+ endif
+
+ if (strainSchemeType == VARIATIONAL_STRAIN_SCHEME .or. &
+ stressDivergenceSchemeType == VARIATIONAL_STRESS_DIVERGENCE_SCHEME) then
+
+ call MPAS_pool_get_array(velocityVariationalPool, "strain11", strain11var)
+ call MPAS_pool_get_array(velocityVariationalPool, "strain22", strain22var)
+ call MPAS_pool_get_array(velocityVariationalPool, "strain12", strain12var)
+ call MPAS_pool_get_array(velocityVariationalPool, "replacementPressure", replacementPressureVar)
+ call MPAS_pool_get_array(velocityVariationalPool, "variationalDenominator", variationalDenominator)
+
+ endif
+
+ ! strain
+ if (strainSchemeType == WEAK_STRAIN_SCHEME) then
+
+ call mpas_timer_start("Velocity solver strain tensor")
+ call seaice_strain_tensor_weak(&
+ meshPool, &
+ strain11weak, &
+ strain22weak, &
+ strain12weak, &
+ uVelocity, &
+ vVelocity, &
+ normalVectorPolygon, &
+ latCellRotated, &
+ solveStress)
+ call mpas_timer_stop("Velocity solver strain tensor")
+
+ else if (strainSchemeType == VARIATIONAL_STRAIN_SCHEME) then
+
+ call mpas_timer_start("Velocity solver strain tensor")
+ call seaice_strain_tensor_variational(&
+ meshPool, &
+ strain11var, &
+ strain22var, &
+ strain12var, &
+ uVelocity, &
+ vVelocity, &
+ basisGradientU, &
+ basisGradientV, &
+ tanLatVertexRotatedOverRadius, &
+ solveStress)
+ call mpas_timer_stop("Velocity solver strain tensor")
+
+ endif
+
+ ! average variational strains around vertex
+ if (strainSchemeType == VARIATIONAL_STRAIN_SCHEME .and. &
+ averageVariationalStrains) then
+
+ call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
+ call seaice_average_strains_on_vertex(&
+ areaCell, &
+ strain11var, &
+ strain22var, &
+ strain12var)
+ endif
+
+ ! weak strain / variational stress divergence
+ if (strainSchemeType == WEAK_STRAIN_SCHEME .and. &
+ stressDivergenceSchemeType == VARIATIONAL_STRESS_DIVERGENCE_SCHEME) then
+
+ call mpas_timer_start("Velocity solver interpolate strain")
+ call interpolate_strains_weak_to_variational(&
+ meshPool, &
+ velocityWeakVariationalPool, &
+ strain11weak, &
+ strain22weak, &
+ strain12weak, &
+ strain11var, &
+ strain22var, &
+ strain12var)
+ call mpas_timer_stop("Velocity solver interpolate strain")
+
+ endif
+
+ ! consitutive relation
+ if (stressDivergenceSchemeType == WEAK_STRESS_DIVERGENCE_SCHEME) then
+
+ call mpas_timer_start("Velocity solver stress tensor")
+ call seaice_stress_tensor_weak(&
+ meshPool, &
+ stress11weak, &
+ stress22weak, &
+ stress12weak, &
+ strain11weak, &
+ strain22weak, &
+ strain12weak, &
+ icePressure, &
+ replacementPressureWeak, &
+ solveStress, &
+ elasticTimeStep)
+ call mpas_timer_stop("Velocity solver stress tensor")
+
+ else if (stressDivergenceSchemeType == VARIATIONAL_STRESS_DIVERGENCE_SCHEME) then
+
+ call mpas_timer_start("Velocity solver stress tensor")
+ call seaice_stress_tensor_variational(&
+ meshPool, &
+ stress11var, &
+ stress22var, &
+ stress12var, &
+ strain11var, &
+ strain22var, &
+ strain12var, &
+ icePressure, &
+ replacementPressureVar, &
+ solveStress, &
+ elasticTimeStep)
+ call mpas_timer_stop("Velocity solver stress tensor")
+
+ endif
+
+ ! stress divergence
+ if (stressDivergenceSchemeType == WEAK_STRESS_DIVERGENCE_SCHEME) then
+
+ call mpas_timer_start("Velocity solver stress divergence")
+ call seaice_stress_divergence_weak(&
+ meshPool, &
+ stressDivergenceU, &
+ stressDivergenceV, &
+ stress11weak, &
+ stress22weak, &
+ stress12weak, &
+ normalVectorTriangle, &
+ latVertexRotated, &
+ solveVelocity)
+ call mpas_timer_stop("Velocity solver stress divergence")
+
+ else if (stressDivergenceSchemeType == VARIATIONAL_STRESS_DIVERGENCE_SCHEME) then
+
+ call mpas_timer_start("Velocity solver stress divergence")
+ call seaice_stress_divergence_variational(&
+ meshPool, &
+ stressDivergenceU, &
+ stressDivergenceV, &
+ stress11var, &
+ stress22var, &
+ stress12var, &
+ basisIntegralsU, &
+ basisIntegralsV, &
+ basisIntegralsMetric, &
+ variationalDenominator, &
+ tanLatVertexRotatedOverRadius, &
+ cellVerticesAtVertex, &
+ solveVelocity)
+ call mpas_timer_stop("Velocity solver stress divergence")
+
+ endif
+
+ blockPtr => blockPtr % next
+ end do
+
+ end subroutine seaice_internal_stress
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! interpolate_strains_weak_to_variational
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 29th January 2021
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine interpolate_strains_weak_to_variational(&
+ meshPool, &
+ velocityWeakVariationalPool, &
+ strain11weak, &
+ strain22weak, &
+ strain12weak, &
+ strain11var, &
+ strain22var, &
+ strain12var)
+
+ use seaice_mesh_pool, only: &
+ nCells, &
+ nVerticesSolve, &
+ vertexDegree, &
+ cellsOnVertex, &
+ nEdgesOnCell, &
+ verticesOnCell
+
+ type (MPAS_pool_type), pointer :: &
+ meshPool, &
+ velocityWeakVariationalPool
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ strain11weak, & !< Input/Output:
+ strain22weak, & !< Input/Output:
+ strain12weak !< Input/Output:
+
+ real(kind=RKIND), dimension(:,:), intent(out) :: &
+ strain11var, & !< Input/Output:
+ strain22var, & !< Input/Output:
+ strain12var !< Input/Output:
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ strain11Vertex, &
+ strain22Vertex, &
+ strain12Vertex
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ areaCell
+
+ real(kind=RKIND) :: &
+ denom
+
+ integer :: &
+ iVertex, &
+ iCellOnVertex, &
+ iCell, &
+ iVertexOnCell
+
+ call MPAS_pool_get_array(meshPool, "areaCell", areaCell)
+
+ call MPAS_pool_get_array(velocityWeakVariationalPool, "strain11Vertex", strain11Vertex)
+ call MPAS_pool_get_array(velocityWeakVariationalPool, "strain22Vertex", strain22Vertex)
+ call MPAS_pool_get_array(velocityWeakVariationalPool, "strain12Vertex", strain12Vertex)
+
+ do iVertex = 1, nVerticesSolve
+
+ strain11Vertex(iVertex) = 0.0_RKIND
+ strain22Vertex(iVertex) = 0.0_RKIND
+ strain12Vertex(iVertex) = 0.0_RKIND
+ denom = 0.0_RKIND
+
+ do iCellOnVertex = 1, vertexDegree
+
+ iCell = cellsOnVertex(iCellOnVertex,iVertex)
+
+ if (iCell >= 1 .and. iCell <= nCells) then
+ strain11Vertex(iVertex) = strain11Vertex(iVertex) + areaCell(iCell) * strain11weak(iCell)
+ strain22Vertex(iVertex) = strain22Vertex(iVertex) + areaCell(iCell) * strain22weak(iCell)
+ strain12Vertex(iVertex) = strain12Vertex(iVertex) + areaCell(iCell) * strain12weak(iCell)
+ denom = denom + areaCell(iCell)
+ endif
+
+ enddo ! iCellOnVertex
+
+ strain11Vertex(iVertex) = strain11Vertex(iVertex) / denom
+ strain22Vertex(iVertex) = strain22Vertex(iVertex) / denom
+ strain12Vertex(iVertex) = strain12Vertex(iVertex) / denom
+
+ enddo ! iVertex
+
+ do iCell = 1, nCells
+
+ do iVertexOnCell = 1, nEdgesOnCell(iCell)
+
+ iVertex = verticesOnCell(iVertexOnCell,iCell)
+
+ strain11var(iVertexOnCell,iCell) = strain11Vertex(iVertex)
+ strain22var(iVertexOnCell,iCell) = strain22Vertex(iVertex)
+ strain12var(iVertexOnCell,iCell) = strain12Vertex(iVertex)
+
+ enddo ! iVertexOnCell
+
+ enddo ! iCell
+
+ end subroutine interpolate_strains_weak_to_variational
+
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! ocean_stress_coefficient
@@ -2554,24 +3041,40 @@ subroutine ocean_stress_coefficient(domain)
call MPAS_pool_get_array(icestatePool, "iceAreaVertex", iceAreaVertex)
- do iVertex = 1, nVerticesSolve
+ if (oceanStressType == QUADRATIC_OCEAN_STRESS) then
- if (solveVelocity(iVertex) == 1) then
+ do iVertex = 1, nVerticesSolve
- oceanStressCoeff(iVertex) = seaiceIceOceanDragCoefficient * seaiceDensitySeaWater * iceAreaVertex(iVertex) * &
- sqrt((uOceanVelocityVertex(iVertex) - uVelocity(iVertex))**2 + &
- (vOceanVelocityVertex(iVertex) - vVelocity(iVertex))**2)
+ if (solveVelocity(iVertex) == 1) then
- endif
+ oceanStressCoeff(iVertex) = seaiceIceOceanDragCoefficient * seaiceDensitySeaWater * iceAreaVertex(iVertex) * &
+ sqrt((uOceanVelocityVertex(iVertex) - uVelocity(iVertex))**2 + &
+ (vOceanVelocityVertex(iVertex) - vVelocity(iVertex))**2)
- enddo ! iVertex
+ endif
- else
+ enddo ! iVertex
+
+ else if (oceanStressType == LINEAR_OCEAN_STRESS) then
+
+ do iVertex = 1, nVerticesSolve
+
+ if (solveVelocity(iVertex) == 1) then
+
+ oceanStressCoeff(iVertex) = seaiceIceOceanDragCoefficient * seaiceDensitySeaWater * iceAreaVertex(iVertex)
+
+ endif
+
+ enddo ! iVertex
+
+ end if ! oceanStressType
+
+ else ! configUseOceanStress
! no ocean stress
oceanStressCoeff = 0.0_RKIND
- endif
+ endif ! configUseOceanStress
block => block % next
end do
@@ -2608,8 +3111,6 @@ subroutine solve_velocity(domain)
real(kind=RKIND), dimension(:), pointer :: &
uVelocity, &
vVelocity, &
- uVelocityInitial, &
- vVelocityInitial, &
totalMassVertex, &
totalMassVertexfVertex, &
stressDivergenceU, &
@@ -2654,8 +3155,6 @@ subroutine solve_velocity(domain)
call MPAS_pool_get_array(velocitySolverPool, "solveVelocity", solveVelocity)
call MPAS_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
call MPAS_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "uVelocityInitial", uVelocityInitial)
- call MPAS_pool_get_array(velocitySolverPool, "vVelocityInitial", vVelocityInitial)
call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceU", stressDivergenceU)
call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceV", stressDivergenceV)
call MPAS_pool_get_array(velocitySolverPool, "airStressVertexU", airStressVertexU)
@@ -2667,7 +3166,9 @@ subroutine solve_velocity(domain)
call MPAS_pool_get_array(velocitySolverPool, "oceanStressV", oceanStressV)
call MPAS_pool_get_array(velocitySolverPool, "oceanStressCoeff", oceanStressCoeff)
- !$omp parallel do default(shared) private(iVertex, leftMatrix, rightHandSide, solutionDenominator)
+#ifdef MPAS_OPENMP
+!$omp parallel do default(shared) private(iVertex, leftMatrix, rightHandSide, solutionDenominator)
+#endif
do iVertex = 1, nVerticesSolve
if (solveVelocity(iVertex) == 1) then
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_constitutive_relation.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_constitutive_relation.F
index 27c04b5506..324187c1f4 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_constitutive_relation.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver_constitutive_relation.F
@@ -24,19 +24,29 @@ module seaice_velocity_solver_constitutive_relation
public :: &
seaice_init_evp, &
seaice_evp_constitutive_relation, &
- seaice_evp_constitutive_relation_revised
+ seaice_evp_constitutive_relation_revised, &
+ seaice_linear_constitutive_relation
+
+ ! constitutive relation options
+ integer, public :: &
+ constitutiveRelationType
+
+ integer, public :: &
+ EVP_CONSTITUTIVE_RELATION = 1, &
+ REVISED_EVP_CONSTITUTIVE_RELATION = 2, &
+ LINEAR_CONSTITUTIVE_RELATION = 3, &
+ NONE_CONSTITUTIVE_RELATION = 4
! general EVP parameters
real(kind=RKIND), parameter, private :: &
eccentricity = 2.0_RKIND, &
- dampingTimescaleParameter = 0.36_RKIND, &
- puny = 1.0e-11_RKIND
+ dampingTimescaleParameter = 0.36_RKIND
real(kind=RKIND), parameter, public :: &
- eccentricitySquared = eccentricity**2
+ eccentricitySquared = eccentricity**2, &
+ puny = 1.0e-11_RKIND
real(kind=RKIND), private :: &
- dampingTimescale, &
evpDampingCriterion
! Bouillon et al. 2013 parameters
@@ -45,6 +55,7 @@ module seaice_velocity_solver_constitutive_relation
dampingRatio = 5.5e-3_RKIND ! xi = Sv/Sc < 1
real(kind=RKIND), public :: &
+ dampingTimescale, &
numericalInertiaCoefficient ! brlx
contains
@@ -67,6 +78,9 @@ subroutine seaice_init_evp(domain)
type(block_type), pointer :: block
+ character(len=strKIND), pointer :: &
+ config_constitutive_relation_type
+
type(MPAS_pool_type), pointer :: &
velocitySolver, &
mesh
@@ -86,6 +100,20 @@ subroutine seaice_init_evp(domain)
dvEdgeMin, &
dvEdgeMinGlobal
+ ! constitutive relation type
+ call MPAS_pool_get_config(domain % configs, "config_constitutive_relation_type", config_constitutive_relation_type)
+ if (trim(config_constitutive_relation_type) == 'evp') then
+ constitutiveRelationType = EVP_CONSTITUTIVE_RELATION
+ else if (trim(config_constitutive_relation_type) == 'evp_revised') then
+ constitutiveRelationType = REVISED_EVP_CONSTITUTIVE_RELATION
+ else if (trim(config_constitutive_relation_type) == 'linear') then
+ constitutiveRelationType = LINEAR_CONSTITUTIVE_RELATION
+ else if (trim(config_constitutive_relation_type) == 'none') then
+ constitutiveRelationType = NONE_CONSTITUTIVE_RELATION
+ else
+ call MPAS_log_write("config_constitutive_relation_type unknown: "//trim(config_constitutive_relation_type), MPAS_LOG_CRIT)
+ endif
+
! general EVP
block => domain % blocklist
do while (associated(block))
@@ -158,6 +186,10 @@ subroutine seaice_evp_constitutive_relation(&
replacementPressure, &
areaCell, &
dtElastic)
+#ifdef CPRINTEL
+!$omp declare simd(seaice_evp_constitutive_relation) uniform(dtElastic), notinbranch &
+!$omp& linear(ref(stress11,stress22,stress12,strain11,strain22,strain12,replacementPressure,icePressure,areaCell))
+#endif
real(kind=RKIND), intent(inout) :: &
stress11, & !< Input/Output:
@@ -237,6 +269,10 @@ subroutine seaice_evp_constitutive_relation_revised(&
icePressure, &
replacementPressure, &
areaCell)
+#ifdef CPRINTEL
+!$omp declare simd(seaice_evp_constitutive_relation_revised) uniform(icePressure,areaCell), notinbranch &
+!$omp& linear(ref(stress11,stress22,stress12,strain11,strain22,strain12,replacementPressure))
+#endif
real(kind=RKIND), intent(inout) :: &
stress11, & !< Input/Output:
@@ -312,6 +348,10 @@ subroutine seaice_linear_constitutive_relation(&
strain11, &
strain22, &
strain12)
+#ifdef CPRINTEL
+!$omp declare simd(seaice_linear_constitutive_relation) notinbranch &
+!$omp& linear(ref(stress11,stress22,stress12,strain11,strain22,strain12))
+#endif
real(kind=RKIND), intent(out) :: &
stress11, & !< Output:
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_pwl.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_pwl.F
index a9c3b48a0e..09da732bcd 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_pwl.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver_pwl.F
@@ -42,119 +42,20 @@ module seaice_velocity_solver_pwl
!-----------------------------------------------------------------------
subroutine seaice_init_velocity_solver_pwl(&
- mesh, &
- velocity_variational, &
- boundary, &
- rotateCartesianGrid, &
- includeMetricTerms)!{{{
-
- use seaice_mesh, only: &
- seaice_cell_vertices_at_vertex
-
- use seaice_velocity_solver_variational_shared, only: &
- seaice_calc_local_coords, &
- seaice_calc_variational_metric_terms
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
- type(MPAS_pool_type), pointer :: &
- velocity_variational, & !< Input/Output:
- boundary !< Input/Output:
-
- logical, intent(in) :: &
- rotateCartesianGrid, & !< Input:
- includeMetricTerms !< Input:
-
- integer, dimension(:,:), pointer :: &
- cellVerticesAtVertex
-
- integer, pointer :: &
- nCells, &
- maxEdges
-
- real(kind=RKIND), dimension(:), pointer :: &
- tanLatVertexRotatedOverRadius
-
- real(kind=RKIND), dimension(:,:), allocatable :: &
- xLocal, &
- yLocal
-
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- basisGradientU, &
- basisGradientV, &
- basisIntegralsMetric, &
- basisIntegralsU, &
- basisIntegralsV
-
- integer :: iCell, i1, i2
-
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "maxEdges", maxEdges)
-
- call MPAS_pool_get_array(velocity_variational, "cellVerticesAtVertex", cellVerticesAtVertex)
- call MPAS_pool_get_array(velocity_variational, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
- call MPAS_pool_get_array(velocity_variational, "basisGradientU", basisGradientU)
- call MPAS_pool_get_array(velocity_variational, "basisGradientV", basisGradientV)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsMetric", basisIntegralsMetric)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsU", basisIntegralsU)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsV", basisIntegralsV)
-
- allocate(xLocal(maxEdges,nCells))
- allocate(yLocal(maxEdges,nCells))
-
- call seaice_calc_local_coords(&
- mesh, &
- xLocal, &
- yLocal, &
- rotateCartesianGrid)
-
- call seaice_calc_variational_metric_terms(&
- mesh, &
- tanLatVertexRotatedOverRadius, &
- rotateCartesianGrid, &
- includeMetricTerms)
-
- call seaice_cell_vertices_at_vertex(&
- mesh, &
- cellVerticesAtVertex)
-
- call init_velocity_solver_pwl_basis(&
- mesh, &
- basisGradientU, &
- basisGradientV, &
- basisIntegralsMetric, &
- basisIntegralsU, &
- basisIntegralsV, &
- xLocal, &
- yLocal)
-
- deallocate(xLocal)
- deallocate(yLocal)
-
- end subroutine seaice_init_velocity_solver_pwl!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! init_velocity_solver_pwl_basis
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine init_velocity_solver_pwl_basis(&
- mesh, &
+ nCells, &
+ maxEdges, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ edgesOnCell, &
+ dvEdge, &
+ areaCell, &
+ xLocal, &
+ yLocal, &
basisGradientU, &
basisGradientV, &
basisIntegralsMetric, &
basisIntegralsU, &
- basisIntegralsV, &
- xLocal, &
- yLocal)!{{{
+ basisIntegralsV)!{{{
use seaice_numerics, only: &
seaice_solve_linear_basis_system
@@ -162,8 +63,24 @@ subroutine init_velocity_solver_pwl_basis(&
use seaice_velocity_solver_variational_shared, only: &
seaice_wrapped_index
- type(MPAS_pool_type), pointer :: &
- mesh !< Input:
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ xLocal, & !< Input:
+ yLocal !< Input:
+
+ integer, intent(in) :: &
+ nCells, & !< Input:
+ maxEdges !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
+
+ integer, dimension(:,:), intent(in) :: &
+ verticesOnCell, & !< Input:
+ edgesOnCell !< Input:
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ dvEdge, & !< Input:
+ areaCell !< Input:
real(kind=RKIND), dimension(:,:,:), intent(out) :: &
basisGradientU, & !< Output:
@@ -172,10 +89,6 @@ subroutine init_velocity_solver_pwl_basis(&
basisIntegralsU, & !< Output:
basisIntegralsV !< Output:
- real(kind=RKIND), dimension(:,:), intent(in) :: &
- xLocal, & !< Input:
- yLocal !< Input:
-
real(kind=RKIND) :: &
xPWLCentre, &
yPWLCentre, &
@@ -209,21 +122,6 @@ subroutine init_velocity_solver_pwl_basis(&
rightHandSide, &
solutionVector
- integer, pointer :: &
- nCells, &
- maxEdges
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- verticesOnCell, &
- edgesOnCell
-
- real(kind=RKIND), dimension(:), pointer :: &
- dvEdge, &
- areaCell
-
real(kind=RKIND), dimension(:,:), allocatable :: &
subBasisGradientU, &
subBasisGradientV, &
@@ -234,16 +132,6 @@ subroutine init_velocity_solver_pwl_basis(&
real(kind=RKIND), dimension(:), allocatable :: &
basisSubArea
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "maxEdges", maxEdges)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
- call MPAS_pool_get_array(mesh, "edgesOnCell", edgesOnCell)
- call MPAS_pool_get_array(mesh, "dvEdge", dvEdge)
- call MPAS_pool_get_array(mesh, "areaCell", areaCell)
-
allocate(subBasisGradientU(maxEdges,3))
allocate(subBasisGradientV(maxEdges,3))
allocate(subBasisConstant(maxEdges,3))
@@ -482,7 +370,7 @@ subroutine init_velocity_solver_pwl_basis(&
deallocate(subCellgradientV)
deallocate(basisSubArea)
- end subroutine init_velocity_solver_pwl_basis!}}}
+ end subroutine seaice_init_velocity_solver_pwl!}}}
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_unit_tests.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_unit_tests.F
deleted file mode 100644
index 7b273f5fbc..0000000000
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_unit_tests.F
+++ /dev/null
@@ -1,2414 +0,0 @@
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_velocity_solver_unit_tests
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
-module seaice_velocity_solver_unit_tests
-
- use mpas_derived_types
- use mpas_pool_routines
- use mpas_log, only: mpas_log_write
-
- implicit none
-
- private
- save
-
- public :: &
- seaice_strain_rate_operator_unit_test, &
- seaice_stress_divergence_operator_unit_test, &
- seaice_constitutive_relationship_unit_test
-
- integer, private :: &
- iObject = 2
-
-contains
-
-!-----------------------------------------------------------------------
-! Spherical strain rate unit test
-!-----------------------------------------------------------------------
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_strain_rate_operator_unit_test
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_strain_rate_operator_unit_test(&
- domain, &
- unit_test_subtype)!{{{
-
- type(domain_type), intent(inout) :: &
- domain !< Input/Output:
-
- character(len=*), intent(in) :: &
- unit_test_subtype !< Input:
-
- integer, parameter :: ntests = 6
- character(len=200), dimension(ntests), parameter :: &
- test_names = (/"zero ", &
- "zonal ", &
- "meridonal ", &
- "solid_body ", &
- "sinusoidal1", &
- "sinusoidal2"/)
-
- integer :: &
- itest
-
- if (trim(unit_test_subtype) == "all") then
-
- do itest = 1, ntests
-
- call seaice_strain_rate_operator_unit_test_individual(&
- domain, &
- trim(test_names(itest)))
-
- enddo ! itest
-
- else
-
- call seaice_strain_rate_operator_unit_test_individual(&
- domain, &
- unit_test_subtype)
-
- endif
-
- end subroutine seaice_strain_rate_operator_unit_test
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_strain_rate_operator_unit_test
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_strain_rate_operator_unit_test_individual(&
- domain, &
- unit_test_subtype)!{{{
-
- use seaice_velocity_solver_weak, only: &
- seaice_strain_tensor_weak
-
- use seaice_velocity_solver_variational, only: &
- seaice_strain_tensor_variational
-
- use seaice_mesh, only: &
- seaice_latlon_from_xyz, &
- seaice_grid_rotation_forward
-
- use seaice_constants, only: &
- seaiceRadiansToDegrees, &
- pii
-
- type(domain_type) :: &
- domain !< Input/Output:
-
- character(len=*), intent(in) :: &
- unit_test_subtype !< Input:
-
- type(block_type), pointer :: &
- block
-
- type (MPAS_pool_type), pointer :: &
- mesh, &
- boundary, &
- velocity_solver, &
- velocity_weak, &
- velocity_variational
-
- real(kind=RKIND), dimension(:), allocatable :: &
- strain11, &
- strain22, &
- strain12, &
- strain11_test, &
- strain22_test, &
- strain12_test, &
- strain11_diff, &
- strain22_diff, &
- strain12_diff, &
- latVertexRotated0, &
- lonVertexRotated0, &
- latCellRotated0, &
- lonCellRotated0
-
- integer :: &
- iCell, &
- iCellOnCell, &
- iVertex
-
- real(kind=RKIND) :: &
- up, vp, ut, vt, &
- xp, yp, zp, &
- rms_strain11, &
- rms_strain22, &
- rms_strain12
-
- integer, pointer :: &
- nCells, &
- nVertices
-
- integer, dimension(:), pointer :: &
- solveStress, &
- interiorCell
-
- real(kind=RKIND), pointer :: &
- sphere_radius
-
- real(kind=RKIND), dimension(:), pointer :: &
- xVertex, &
- yVertex, &
- zVertex, &
- xCell, &
- yCell, &
- zCell, &
- latCell, &
- lonCell, &
- uVelocity, &
- vVelocity, &
- latCellRotated, &
- strain11_weak, &
- strain22_weak, &
- strain12_weak, &
- tanLatVertexRotatedOverRadius
-
- real(kind=RKIND), dimension(:,:), pointer :: &
- strain11_variational, &
- strain22_variational, &
- strain12_variational
-
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- basisGradientU, &
- basisGradientV
-
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- normalVectorPolygon
-
- logical, pointer :: &
- config_rotate_cartesian_grid
-
- character(len=strKIND), pointer :: &
- config_stress_divergence_scheme
-
- real(kind=RKIND), parameter :: &
- polarAngleLimit = 0.95_RKIND * 0.5_RKIND * pii
-
- call MPAS_pool_get_config(domain % configs, "config_rotate_cartesian_grid", config_rotate_cartesian_grid)
- call MPAS_pool_get_config(domain % configs, "config_stress_divergence_scheme", config_stress_divergence_scheme)
-
- block => domain % blocklist
- do while (associated(block))
-
- call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
- call MPAS_pool_get_subpool(block % structs, "boundary", boundary)
- call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocity_solver)
- call MPAS_pool_get_subpool(block % structs, "velocity_weak", velocity_weak)
- call MPAS_pool_get_subpool(block % structs, "velocity_variational", velocity_variational)
-
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
- call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
- sphere_radius = 6371220.0_RKIND
-
- call MPAS_pool_get_array(mesh, "xVertex", xVertex)
- call MPAS_pool_get_array(mesh, "yVertex", yVertex)
- call MPAS_pool_get_array(mesh, "zVertex", zVertex)
- call MPAS_pool_get_array(mesh, "xCell", xCell)
- call MPAS_pool_get_array(mesh, "yCell", yCell)
- call MPAS_pool_get_array(mesh, "zCell", zCell)
- call MPAS_pool_get_array(mesh, "latCell", latCell)
- call MPAS_pool_get_array(mesh, "lonCell", lonCell)
-
- call MPAS_pool_get_array(velocity_solver, "solveStress", solveStress)
- call MPAS_pool_get_array(velocity_solver, "uVelocity", uVelocity)
- call MPAS_pool_get_array(velocity_solver, "vVelocity", vVelocity)
-
- call MPAS_pool_get_array(boundary, "interiorCell", interiorCell)
-
- if (trim(config_stress_divergence_scheme) == "weak") then
- call MPAS_pool_get_array(velocity_weak, "latCellRotated", latCellRotated)
- call MPAS_pool_get_array(velocity_weak, "normalVectorPolygon", normalVectorPolygon)
- call MPAS_pool_get_array(velocity_weak, "strain11", strain11_weak)
- call MPAS_pool_get_array(velocity_weak, "strain22", strain22_weak)
- call MPAS_pool_get_array(velocity_weak, "strain12", strain12_weak)
- else if (trim(config_stress_divergence_scheme) == "variational") then
- call MPAS_pool_get_array(velocity_variational, "strain11", strain11_variational)
- call MPAS_pool_get_array(velocity_variational, "strain22", strain22_variational)
- call MPAS_pool_get_array(velocity_variational, "strain12", strain12_variational)
- call MPAS_pool_get_array(velocity_variational, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
- call MPAS_pool_get_array(velocity_variational, "basisGradientU", basisGradientU)
- call MPAS_pool_get_array(velocity_variational, "basisGradientV", basisGradientV)
- endif
-
- open(54,file="strain_rate_test_"//trim(unit_test_subtype)//".txt",position="append")
-
- write(54,*) "-----------------------------------------------------------"
- write(54,*)
- write(54,*) "Test type: ", trim(unit_test_subtype)
- write(54,*)
-
- allocate(strain11(nCells))
- allocate(strain22(nCells))
- allocate(strain12(nCells))
- allocate(strain11_test(nCells))
- allocate(strain22_test(nCells))
- allocate(strain12_test(nCells))
- allocate(strain11_diff(nCells))
- allocate(strain22_diff(nCells))
- allocate(strain12_diff(nCells))
-
- allocate(lonVertexRotated0(nVertices))
- allocate(latVertexRotated0(nVertices))
- allocate(lonCellRotated0(nCells))
- allocate(latCellRotated0(nCells))
-
- do iVertex = 1, nVertices
-
- call seaice_grid_rotation_forward(&
- xp, yp, zp, &
- xVertex(iVertex), yVertex(iVertex), zVertex(iVertex), &
- config_rotate_cartesian_grid)
-
- call seaice_latlon_from_xyz(&
- latVertexRotated0(iVertex), lonVertexRotated0(iVertex), &
- xp, yp, zp, sphere_radius)
-
- enddo ! iVertex
-
- do iCell = 1, nCells
-
- call seaice_grid_rotation_forward(&
- xp, yp, zp, &
- xCell(iCell), yCell(iCell), zCell(iCell), &
- config_rotate_cartesian_grid)
-
- call seaice_latlon_from_xyz(&
- latCellRotated0(iCell), lonCellRotated0(iCell), &
- xp, yp, zp, sphere_radius)
-
- enddo ! iCell
-
- ! set solveStrain away from rotated pole
- do iCell = 1, nCells
-
- solveStress(iCell) = interiorCell(iCell)
-
- if (abs(latCellRotated0(iCell)) > 0.8_RKIND * pii * 0.5_RKIND) then
- solveStress(iCell) = 0
- endif
-
- enddo ! iCell
-
- ! set test velocities and expected outputs
- call spherical_test_strain(&
- mesh, &
- uVelocity, &
- vVelocity, &
- lonVertexRotated0, &
- latVertexRotated0, &
- strain11_test, &
- strain22_test, &
- strain12_test, &
- lonCellRotated0, &
- latCellRotated0, &
- nVertices, &
- nCells, &
- trim(unit_test_subtype))
-
- write(54,*)
- write(54,*) "Analytic solution:"
- write(54,*) "strain11 (min/max):", minval(strain11_test,mask=(solveStress(1:nCells)==1)), &
- maxval(strain11_test,mask=(solveStress(1:nCells)==1))
- write(54,*) "strain22 (min/max):", minval(strain22_test,mask=(solveStress(1:nCells)==1)), &
- maxval(strain22_test,mask=(solveStress(1:nCells)==1))
- write(54,*) "strain12 (min/max):", minval(strain12_test,mask=(solveStress(1:nCells)==1)), &
- maxval(strain12_test,mask=(solveStress(1:nCells)==1))
-
- ! calculate strain
- if (trim(config_stress_divergence_scheme) == "weak") then
-
- call seaice_strain_tensor_weak(&
- mesh, &
- strain11_weak, &
- strain22_weak, &
- strain12_weak, &
- uVelocity, &
- vVelocity, &
- normalVectorPolygon, &
- latCellRotated, &
- solveStress)
-
- strain11(1:nCells) = strain11_weak(1:nCells)
- strain22(1:nCells) = strain22_weak(1:nCells)
- strain12(1:nCells) = strain12_weak(1:nCells)
-
- else if (trim(config_stress_divergence_scheme) == "variational") then
-
- call seaice_strain_tensor_variational(&
- mesh, &
- strain11_variational, &
- strain22_variational, &
- strain12_variational, &
- uVelocity, &
- vVelocity, &
- basisGradientU, &
- basisGradientV, &
- tanLatVertexRotatedOverRadius, &
- solveStress)
-
- call average_variational_stress(&
- mesh, &
- strain11_variational, &
- strain22_variational, &
- strain12_variational, &
- strain11, &
- strain22, &
- strain12)
-
- endif
-
- write(54,*)
- write(54,*) "Numerical solution:"
- write(54,*) "strain11 (min/max):", minval(strain11(1:nCells),mask=(solveStress(1:nCells)==1)), &
- maxval(strain11(1:nCells),mask=(solveStress(1:nCells)==1))
- write(54,*) "strain22 (min/max):", minval(strain22(1:nCells),mask=(solveStress(1:nCells)==1)), &
- maxval(strain22(1:nCells),mask=(solveStress(1:nCells)==1))
- write(54,*) "strain12 (min/max):", minval(strain12(1:nCells),mask=(solveStress(1:nCells)==1)), &
- maxval(strain12(1:nCells),mask=(solveStress(1:nCells)==1))
-
- ! calculate difference
- strain11_diff = strain11(1:nCells) - strain11_test
- strain22_diff = strain22(1:nCells) - strain22_test
- strain12_diff = strain12(1:nCells) - strain12_test
-
- write(54,*)
- write(54,*) "Difference:"
- write(54,*) "strain11 (min/max):", minval(strain11_diff,mask=(solveStress(1:nCells)==1)), &
- maxval(strain11_diff,mask=(solveStress(1:nCells)==1))
- write(54,*) "strain22 (min/max):", minval(strain22_diff,mask=(solveStress(1:nCells)==1)), &
- maxval(strain22_diff,mask=(solveStress(1:nCells)==1))
- write(54,*) "strain12 (min/max):", minval(strain12_diff,mask=(solveStress(1:nCells)==1)), &
- maxval(strain12_diff,mask=(solveStress(1:nCells)==1))
-
- open(55,file="strains_"//trim(unit_test_subtype)//".txt")
- do iCell = 1, nCells
-
- write(55,*) iCell, solveStress(iCell), &
- strain11(iCell), strain11_test(iCell), &
- strain22(iCell), strain22_test(iCell), &
- strain12(iCell), strain12_test(iCell), &
- strain12(iCell) - strain12_test(iCell)
-
- enddo ! iCell
- close(55)
-
- open(55,file="strain11_"//trim(unit_test_subtype)//".txt")
- open(56,file="strain22_"//trim(unit_test_subtype)//".txt")
- open(57,file="strain12_"//trim(unit_test_subtype)//".txt")
- do iCell = 1, nCells
- write(55,*) iCell, lonCell(iCell) * seaiceRadiansToDegrees, latCell(iCell) * seaiceRadiansToDegrees, &
- strain11(iCell), strain11_test(iCell), strain11_diff(iCell), &
- strain11_diff(iCell) * real(solveStress(iCell),RKIND)
- write(56,*) iCell, lonCell(iCell) * seaiceRadiansToDegrees, latCell(iCell) * seaiceRadiansToDegrees, &
- strain22(iCell), strain22_test(iCell), strain22_diff(iCell), &
- strain22_diff(iCell) * real(solveStress(iCell),RKIND)
- write(57,*) iCell, lonCell(iCell) * seaiceRadiansToDegrees, latCell(iCell) * seaiceRadiansToDegrees, &
- strain12(iCell), strain12_test(iCell), strain12_diff(iCell), &
- strain12_diff(iCell) * real(solveStress(iCell),RKIND)
- enddo ! iCell
- close(55)
- close(56)
- close(57)
-
- ! rms difference
- call rms_difference( &
- strain11(1:nCells), &
- strain11_test, &
- solveStress(1:nCells), &
- nCells, &
- rms_strain11)
-
- call rms_difference( &
- strain22(1:nCells), &
- strain22_test, &
- solveStress(1:nCells), &
- nCells, &
- rms_strain22)
-
- call rms_difference( &
- strain12(1:nCells), &
- strain12_test, &
- solveStress(1:nCells), &
- nCells, &
- rms_strain12)
-
- write(54,*)
- write(54,*) "RMS:"
- write(54,*) "strain11:", rms_strain11
- write(54,*) "strain22:", rms_strain22
- write(54,*) "strain12:", rms_strain12
-
- do iCell = 1, nCells
-
- if (solveStress(iCell) == 0) then
- strain11_test(iCell) = 0.0_RKIND
- strain22_test(iCell) = 0.0_RKIND
- strain12_test(iCell) = 0.0_RKIND
- strain11_diff(iCell) = 0.0_RKIND
- strain22_diff(iCell) = 0.0_RKIND
- strain12_diff(iCell) = 0.0_RKIND
- endif
-
- enddo ! iCell
-
- ! plot spatial distribution
- call plot_spherical_latlon(mesh, real(interiorCell,RKIND), "interiorCell_"//trim(unit_test_subtype)//".txt")
- call plot_spherical_latlon(mesh, real(solveStress,RKIND), "solveStress_"//trim(unit_test_subtype)//".txt")
- call plot_spherical_latlon(mesh, latCellRotated0, "latCellRotated0_"//trim(unit_test_subtype)//".txt")
-
- call plot_spherical_latlon(mesh, strain11, "strain11_plot_"//trim(unit_test_subtype)//"_model.txt")
- call plot_spherical_latlon(mesh, strain11_test, "strain11_plot_"//trim(unit_test_subtype)//"_analytical.txt")
- call plot_spherical_latlon(mesh, strain11_diff, "strain11_plot_"//trim(unit_test_subtype)//"_diff.txt")
-
- call plot_spherical_latlon(mesh, strain22, "strain22_plot_"//trim(unit_test_subtype)//"_model.txt")
- call plot_spherical_latlon(mesh, strain22_test, "strain22_plot_"//trim(unit_test_subtype)//"_analytical.txt")
- call plot_spherical_latlon(mesh, strain22_diff, "strain22_plot_"//trim(unit_test_subtype)//"_diff.txt")
-
- call plot_spherical_latlon(mesh, strain12, "strain12_plot_"//trim(unit_test_subtype)//"_model.txt")
- call plot_spherical_latlon(mesh, strain12_test, "strain12_plot_"//trim(unit_test_subtype)//"_analytical.txt")
- call plot_spherical_latlon(mesh, strain12_diff, "strain12_plot_"//trim(unit_test_subtype)//"_diff.txt")
-
- deallocate(strain11)
- deallocate(strain22)
- deallocate(strain12)
- deallocate(strain11_test)
- deallocate(strain22_test)
- deallocate(strain12_test)
- deallocate(strain11_diff)
- deallocate(strain22_diff)
- deallocate(strain12_diff)
-
- deallocate(lonVertexRotated0)
- deallocate(latVertexRotated0)
- deallocate(lonCellRotated0)
- deallocate(latCellRotated0)
-
- write(54,*)
-
- close(54)
-
- block => block % next
- enddo
-
- end subroutine seaice_strain_rate_operator_unit_test_individual!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! average_variational_stress
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date December 12th 2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine average_variational_stress(&
- mesh, &
- strain11_variational, &
- strain22_variational, &
- strain12_variational, &
- strain11, &
- strain22, &
- strain12)
-
- type(mpas_pool_type), intent(in) :: &
- mesh
-
- real(kind=RKIND), dimension(:,:), intent(in) :: &
- strain11_variational, &
- strain22_variational, &
- strain12_variational
-
- real(kind=RKIND), dimension(:), intent(out) :: &
- strain11, &
- strain22, &
- strain12
-
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer :: &
- iCell, &
- iVertexOnCell
-
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
-
- do iCell = 1, nCells
-
- strain11(iCell) = 0.0_RKIND
- strain22(iCell) = 0.0_RKIND
- strain12(iCell) = 0.0_RKIND
-
- do iVertexOnCell = 1, nEdgesOnCell(iCell)
-
- strain11(iCell) = strain11(iCell) + strain11_variational(iVertexOnCell,iCell)
- strain22(iCell) = strain22(iCell) + strain22_variational(iVertexOnCell,iCell)
- strain12(iCell) = strain12(iCell) + strain12_variational(iVertexOnCell,iCell)
-
- enddo ! iVertexOnCell
-
- strain11(iCell) = strain11(iCell) / real(nEdgesOnCell(iCell), RKIND)
- strain22(iCell) = strain22(iCell) / real(nEdgesOnCell(iCell), RKIND)
- strain12(iCell) = strain12(iCell) / real(nEdgesOnCell(iCell), RKIND)
-
- enddo ! iCell
-
- end subroutine average_variational_stress
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! spherical_test_strain
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine spherical_test_strain(mesh, &
- uVelocity, &
- vVelocity, &
- longitudeVelocity, &
- latitudeVelocity, &
- strain11, &
- strain22, &
- strain12, &
- longitudeStrain, &
- latitudeStrain, &
- nPointsVelocity, &
- nPointsStrain, &
- test_type)!{{{
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
- real(kind=RKIND), dimension(:), intent(out) :: &
- uVelocity, & !< Output:
- vVelocity, & !< Output:
- strain11, & !< Output:
- strain22, & !< Output:
- strain12 !< Output:
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- longitudeVelocity, & !< Input:
- latitudeVelocity, & !< Input:
- longitudeStrain, & !< Input:
- latitudeStrain !< Input:
-
- integer, intent(in) :: &
- nPointsVelocity, & !< Input:
- nPointsStrain !< Input:
-
- character(len=*), intent(in) :: &
- test_type !< Input:
-
- real(kind=RKIND) :: &
- uVelocity_test, &
- vVelocity_test, &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat
-
- integer :: &
- iPoint
-
- real(kind=RKIND), pointer :: &
- sphere_radius
-
- call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
-
- ! set velocity points
- do iPoint = 1, nPointsVelocity
-
- call spherical_test_strain_velocities( &
- uVelocity(iPoint), &
- vVelocity(iPoint), &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat, &
- longitudeVelocity(iPoint), &
- latitudeVelocity(iPoint), &
- test_type)
-
- enddo ! iPoint
-
- ! set strain points
- do iPoint = 1, nPointsStrain
-
- call spherical_test_strain_velocities( &
- uVelocity_test, &
- vVelocity_test, &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat, &
- longitudeStrain(iPoint), &
- latitudeStrain(iPoint), &
- test_type)
-
- strain11(iPoint) = strain11_component(uVelocity_test, vVelocity_test, &
- du_dlon, du_dlat, dv_dlon, dv_dlat, &
- sphere_radius, longitudeStrain(iPoint), latitudeStrain(iPoint))
- strain22(iPoint) = strain22_component(uVelocity_test, vVelocity_test, &
- du_dlon, du_dlat, dv_dlon, dv_dlat, &
- sphere_radius, longitudeStrain(iPoint), latitudeStrain(iPoint))
- strain12(iPoint) = strain12_component(uVelocity_test, vVelocity_test, &
- du_dlon, du_dlat, dv_dlon, dv_dlat, &
- sphere_radius, longitudeStrain(iPoint), latitudeStrain(iPoint))
-
- enddo ! iPoint
-
- end subroutine spherical_test_strain!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! spherical_test_strain_velocities
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine spherical_test_strain_velocities( &
- u, &
- v, &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat, &
- lon, &
- lat, &
- test_type)!{{{
-
- real(kind=RKIND), intent(out) :: &
- u, & !< Output:
- v, & !< Output:
- du_dlon, & !< Output:
- du_dlat, & !< Output:
- dv_dlon, & !< Output:
- dv_dlat !< Output:
-
- real(kind=RKIND), intent(in) :: &
- lon, & !< Input:
- lat !< Input:
-
- character(len=*), intent(in) :: &
- test_type !< Input:
-
- if (trim(test_type) == "zero") then
-
- u = 0.0_RKIND
- v = 0.0_RKIND
-
- du_dlon = 0.0_RKIND
- du_dlat = 0.0_RKIND
- dv_dlon = 0.0_RKIND
- dv_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "zonal") then
-
- u = 1.0_RKIND
- v = 0.0_RKIND
-
- du_dlon = 0.0_RKIND
- du_dlat = 0.0_RKIND
- dv_dlon = 0.0_RKIND
- dv_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "meridonal") then
-
- u = 0.0_RKIND
- v = 1.0_RKIND
-
- du_dlon = 0.0_RKIND
- du_dlat = 0.0_RKIND
- dv_dlon = 0.0_RKIND
- dv_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "solid_body") then
-
- u = cos(lat)
- v = 0.0_RKIND
-
- du_dlon = 0.0_RKIND
- du_dlat = -sin(lat)
- dv_dlon = 0.0_RKIND
- dv_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "sinusoidal1") then
-
- u = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- v = 0.0_RKIND
-
- du_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- du_dlat = -2.0_RKIND * cos(lon) * sin(2.0_RKIND * lat)
- dv_dlon = 0.0_RKIND
- dv_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "sinusoidal2") then
-
- u = 0.0_RKIND
- v = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
-
- du_dlon = 0.0_RKIND
- du_dlat = 0.0_RKIND
- dv_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dv_dlat = -2.0_RKIND * cos(lon) * sin(2.0_RKIND * lat)
-
- else
-
- call mpas_log_write("spherical_test_strain_velocities: Unknown test case: "//trim(test_type), MPAS_LOG_CRIT)
-
- endif
-
- end subroutine spherical_test_strain_velocities!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! strain11_component
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- function strain11_component(&
- u, &
- v, &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat, &
- r, &
- lon, &
- lat) &
- result(e11)!{{{
-
- real(kind=RKIND), intent(in) :: &
- u, & !< Input:
- v, & !< Input:
- du_dlon, & !< Input:
- du_dlat, & !< Input:
- dv_dlon, & !< Input:
- dv_dlat, & !< Input:
- r, & !< Input:
- lon, & !< Input:
- lat !< Input:
-
- real(kind=RKIND) :: e11
-
- e11 = (1.0_RKIND / (r * cos(lat))) * (du_dlon - v * sin(lat))
-
- end function strain11_component!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! strain22_component
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- function strain22_component(&
- u, &
- v, &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat, &
- r, &
- lon, &
- lat) &
- result(e22)!{{{
-
- real(kind=RKIND), intent(in) :: &
- u, & !< Input:
- v, & !< Input:
- du_dlon, & !< Input:
- du_dlat, & !< Input:
- dv_dlon, & !< Input:
- dv_dlat, & !< Input:
- r, & !< Input:
- lon, & !< Input:
- lat !< Input:
-
- real(kind=RKIND) :: e22
-
- e22 = dv_dlat / r
-
- end function strain22_component!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! strain12_component
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- function strain12_component(&
- u, &
- v, &
- du_dlon, &
- du_dlat, &
- dv_dlon, &
- dv_dlat, &
- r, &
- lon, &
- lat) &
- result(e12)!{{{
-
- real(kind=RKIND), intent(in) :: &
- u, & !< Input:
- v, & !< Input:
- du_dlon, & !< Input:
- du_dlat, & !< Input:
- dv_dlon, & !< Input:
- dv_dlat, & !< Input:
- r, & !< Input:
- lon, & !< Input:
- lat !< Input:
-
- real(kind=RKIND) :: e12
-
- e12 = (0.5_RKIND / r) * (du_dlat + u * tan(lat) + dv_dlon / cos(lat))
-
- end function strain12_component!}}}
-
-!-----------------------------------------------------------------------
-! Spherical stress divergence unit test
-!-----------------------------------------------------------------------
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_stress_divergence_operator_unit_test
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_stress_divergence_operator_unit_test(&
- domain, &
- unit_test_subtype)!{{{
-
- type(domain_type) :: &
- domain !< Input/Output:
-
- character(len=*), intent(in) :: &
- unit_test_subtype !< Input:
-
- integer, parameter :: ntests = 8
- character(len=200), dimension(ntests), parameter :: &
- test_names = (/"zero ", &
- "const11", &
- "const22", &
- "const12", &
- "test1 ", &
- "test2 ", &
- "test3 ", &
- "test4 "/)
-
- integer :: &
- itest
-
- if (trim(unit_test_subtype) == "all") then
-
- do itest = 1, ntests
-
- call seaice_stress_divergence_operator_unit_test_individual(&
- domain, &
- trim(test_names(itest)))
-
- enddo ! itest
-
- else
-
- call seaice_stress_divergence_operator_unit_test_individual(&
- domain, &
- unit_test_subtype)
-
- endif
-
- end subroutine seaice_stress_divergence_operator_unit_test
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_stress_divergence_operator_unit_test_individual
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_stress_divergence_operator_unit_test_individual(&
- domain, &
- unit_test_subtype)!{{{
-
- use seaice_velocity_solver_weak, only: &
- seaice_stress_divergence_weak
-
- use seaice_velocity_solver_variational, only: &
- seaice_stress_divergence_variational
-
- use seaice_mesh, only: &
- seaice_grid_rotation_forward, &
- seaice_latlon_from_xyz
-
- use seaice_constants, only: &
- seaiceRadiansToDegrees, &
- pii
-
- type(domain_type), intent(inout) :: &
- domain !< Input/Output:
-
- character(len=*), intent(in) :: &
- unit_test_subtype !< Input:
-
- type(block_type), pointer :: &
- block
-
- type (MPAS_pool_type), pointer :: &
- mesh, &
- boundary, &
- velocity_solver, &
- velocity_weak, &
- velocity_variational
-
- real(kind=RKIND), dimension(:), allocatable :: &
- stressDivergenceU_test, &
- stressDivergenceV_test, &
- stressDivergenceU_diff, &
- stressDivergenceV_diff, &
- latVertexRotated0, &
- lonVertexRotated0, &
- latCellRotated0, &
- lonCellRotated0
-
- real(kind=RKIND) :: &
- xp, yp, zp, &
- rms_divergenceU, &
- rms_divergenceV
-
- integer :: &
- iCell, &
- iVertex
-
- integer, pointer :: &
- nCells, &
- nVertices
-
- integer, dimension(:), pointer :: &
- solveVelocity, &
- interiorVertex
-
- real(kind=RKIND), pointer :: &
- sphere_radius
-
- real(kind=RKIND), dimension(:), pointer :: &
- xVertex, &
- yVertex, &
- zVertex, &
- xCell, &
- yCell, &
- zCell, &
- latVertex, &
- lonVertex, &
- latVertexRotated, &
- stress11_weak, &
- stress22_weak, &
- stress12_weak, &
- stressDivergenceU, &
- stressDivergenceV
-
- integer, dimension(:,:), pointer :: &
- cellVerticesAtVertex
-
- real(kind=RKIND), dimension(:), pointer :: &
- tanLatVertexRotatedOverRadius
-
- real(kind=RKIND), dimension(:,:), pointer :: &
- stress11_variational, &
- stress22_variational, &
- stress12_variational
-
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- basisGradientU, &
- basisGradientV, &
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric
-
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- normalVectorTriangle
-
- logical, pointer :: &
- config_rotate_cartesian_grid
-
- character(len=strKIND), pointer :: &
- config_stress_divergence_scheme
-
- call MPAS_pool_get_config(domain % configs, "config_rotate_cartesian_grid", config_rotate_cartesian_grid)
- call MPAS_pool_get_config(domain % configs, "config_stress_divergence_scheme", config_stress_divergence_scheme)
-
- block => domain % blocklist
- do while (associated(block))
-
- call MPAS_pool_get_subpool(block % structs, "mesh", mesh)
- call MPAS_pool_get_subpool(block % structs, "boundary", boundary)
- call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocity_solver)
- call MPAS_pool_get_subpool(block % structs, "velocity_weak", velocity_weak)
- call MPAS_pool_get_subpool(block % structs, "velocity_variational", velocity_variational)
-
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
- call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
-
- call MPAS_pool_get_array(mesh, "xVertex", xVertex)
- call MPAS_pool_get_array(mesh, "yVertex", yVertex)
- call MPAS_pool_get_array(mesh, "zVertex", zVertex)
- call MPAS_pool_get_array(mesh, "xCell", xCell)
- call MPAS_pool_get_array(mesh, "yCell", yCell)
- call MPAS_pool_get_array(mesh, "zCell", zCell)
- call MPAS_pool_get_array(mesh, "latVertex", latVertex)
- call MPAS_pool_get_array(mesh, "lonVertex", lonVertex)
-
- call MPAS_pool_get_array(boundary, "interiorVertex", interiorVertex)
-
- call MPAS_pool_get_array(velocity_solver, "solveVelocity", solveVelocity)
- call MPAS_pool_get_array(velocity_solver, "stressDivergenceU", stressDivergenceU)
- call MPAS_pool_get_array(velocity_solver, "stressDivergenceV", stressDivergenceV)
-
- if (trim(config_stress_divergence_scheme) == "weak") then
- call MPAS_pool_get_array(velocity_weak, "normalVectorTriangle", normalVectorTriangle)
- call MPAS_pool_get_array(velocity_weak, "latVertexRotated", latVertexRotated)
- call MPAS_pool_get_array(velocity_weak, "stress11", stress11_weak)
- call MPAS_pool_get_array(velocity_weak, "stress22", stress22_weak)
- call MPAS_pool_get_array(velocity_weak, "stress12", stress12_weak)
- else if (trim(config_stress_divergence_scheme) == "variational") then
- call MPAS_pool_get_array(velocity_variational, "stress11", stress11_variational)
- call MPAS_pool_get_array(velocity_variational, "stress22", stress22_variational)
- call MPAS_pool_get_array(velocity_variational, "stress12", stress12_variational)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsU", basisIntegralsU)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsV", basisIntegralsV)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsMetric", basisIntegralsMetric)
- call MPAS_pool_get_array(velocity_variational, "cellVerticesAtVertex", cellVerticesAtVertex)
- call MPAS_pool_get_array(velocity_variational, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
- endif
-
- open(54,file="stress_divergence_test_"//trim(unit_test_subtype)//".txt")
-
- write(54,*) "-----------------------------------------------------------"
- write(54,*)
- write(54,*) "Test type: ", trim(unit_test_subtype)
- write(54,*)
-
- allocate(stressDivergenceU_test(nVertices))
- allocate(stressDivergenceV_test(nVertices))
- allocate(stressDivergenceU_diff(nVertices))
- allocate(stressDivergenceV_diff(nVertices))
-
- allocate(lonVertexRotated0(nVertices))
- allocate(latVertexRotated0(nVertices))
- allocate(lonCellRotated0(nCells))
- allocate(latCellRotated0(nCells))
-
- do iVertex = 1, nVertices
-
- call seaice_grid_rotation_forward(&
- xp, yp, zp, &
- xVertex(iVertex), yVertex(iVertex), zVertex(iVertex), &
- config_rotate_cartesian_grid)
-
- call seaice_latlon_from_xyz(&
- latVertexRotated0(iVertex), lonVertexRotated0(iVertex), &
- xp, yp, zp, sphere_radius)
-
- enddo ! iVertex
-
- do iCell = 1, nCells
-
- call seaice_grid_rotation_forward(&
- xp, yp, zp, &
- xCell(iCell), yCell(iCell), zCell(iCell), &
- config_rotate_cartesian_grid)
-
- call seaice_latlon_from_xyz(&
- latCellRotated0(iCell), lonCellRotated0(iCell), &
- xp, yp, zp, sphere_radius)
-
- enddo ! iCell
-
- ! set solveStrain away from rotated pole
- do iVertex = 1, nVertices
-
- solveVelocity(iVertex) = interiorVertex(iVertex)
-
- if (abs(latVertexRotated0(iVertex)) > 0.8_RKIND * pii * 0.5_RKIND) then
- solveVelocity(iVertex) = 0
- endif
-
- enddo ! iCell
-
- ! set test velocities and expected outputs
- if (trim(config_stress_divergence_scheme) == "weak") then
- call spherical_test_divergence_stress_weak(mesh, &
- stress11_weak, &
- stress22_weak, &
- stress12_weak, &
- lonCellRotated0, &
- latCellRotated0, &
- stressDivergenceU_test, &
- stressDivergenceV_test, &
- lonVertexRotated0, &
- latVertexRotated0, &
- trim(unit_test_subtype))
- else if (trim(config_stress_divergence_scheme) == "variational") then
- call spherical_test_divergence_stress_variational(mesh, &
- stress11_variational, &
- stress22_variational, &
- stress12_variational, &
- lonVertexRotated0, &
- latVertexRotated0, &
- stressDivergenceU_test, &
- stressDivergenceV_test, &
- lonVertexRotated0, &
- latVertexRotated0, &
- trim(unit_test_subtype))
- endif
-
- write(54,*)
- write(54,*) "Analytic solution:"
- write(54,*) "stressDivergenceU:", minval(stressDivergenceU_test,mask=(solveVelocity(1:nVertices)==1)), &
- maxval(stressDivergenceU_test,mask=(solveVelocity(1:nVertices)==1))
- write(54,*) "stressDivergenceV:", minval(stressDivergenceV_test,mask=(solveVelocity(1:nVertices)==1)), &
- maxval(stressDivergenceV_test,mask=(solveVelocity(1:nVertices)==1))
-
- ! calculate divergence of stress
- if (trim(config_stress_divergence_scheme) == "weak") then
-
- call seaice_stress_divergence_weak(&
- mesh, &
- stressDivergenceU, &
- stressDivergenceV, &
- stress11_weak, &
- stress22_weak, &
- stress12_weak, &
- normalVectorTriangle, &
- latVertexRotated, &
- solveVelocity)
-
- else if (trim(config_stress_divergence_scheme) == "variational") then
-
- call seaice_stress_divergence_variational(&
- mesh, &
- stressDivergenceU, &
- stressDivergenceV, &
- stress11_variational, &
- stress22_variational, &
- stress12_variational, &
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric, &
- tanLatVertexRotatedOverRadius, &
- cellVerticesAtVertex, &
- solveVelocity)
-
- endif
-
- write(54,*)
- write(54,*) "Numerical solution:"
- write(54,*) "stressDivergenceU:", minval(stressDivergenceU(1:nVertices),mask=(solveVelocity(1:nVertices)==1)), &
- maxval(stressDivergenceU(1:nVertices),mask=(solveVelocity(1:nVertices)==1))
- write(54,*) "stressDivergenceV:", minval(stressDivergenceV(1:nVertices),mask=(solveVelocity(1:nVertices)==1)), &
- maxval(stressDivergenceV(1:nVertices),mask=(solveVelocity(1:nVertices)==1))
-
- ! calculate difference
- stressDivergenceU_diff = stressDivergenceU(1:nVertices) - &
- stressDivergenceU_test
- stressDivergenceV_diff = stressDivergenceV(1:nVertices) - &
- stressDivergenceV_test
-
- write(54,*)
- write(54,*) "Difference:"
- write(54,*) "stressDivergenceU:", minval(stressDivergenceU_diff,mask=(solveVelocity(1:nVertices)==1)), &
- maxval(stressDivergenceU_diff,mask=(solveVelocity(1:nVertices)==1))
- write(54,*) "stressDivergenceV:", minval(stressDivergenceV_diff,mask=(solveVelocity(1:nVertices)==1)), &
- maxval(stressDivergenceV_diff,mask=(solveVelocity(1:nVertices)==1))
-
- open(55, file="divergences_"//trim(unit_test_subtype)//".txt")
- do iVertex = 1, nVertices
-
- write(55,*) iVertex, solveVelocity(iVertex), &
- stressDivergenceU(iVertex), stressDivergenceU_test(iVertex), &
- stressDivergenceV(iVertex), stressDivergenceV_test(iVertex), &
- stressDivergenceU(iVertex) - stressDivergenceU_test(iVertex), &
- stressDivergenceV(iVertex) - stressDivergenceV_test(iVertex)
-
- enddo ! iVertex
- close(55)
-
- open(55,file="divergenceu_"//trim(unit_test_subtype)//".txt")
- open(56,file="divergencev_"//trim(unit_test_subtype)//".txt")
- do iVertex = 1, nVertices
- write(55,*) iVertex, lonVertex(iVertex) * seaiceRadiansToDegrees, latVertex(iVertex) * seaiceRadiansToDegrees, &
- stressDivergenceU(iVertex), stressDivergenceU_test(iVertex), stressDivergenceU_diff(iVertex), &
- stressDivergenceU_diff(iVertex) * real(solveVelocity(iVertex),RKIND)
- write(56,*) iVertex, lonVertex(iVertex) * seaiceRadiansToDegrees, latVertex(iVertex) * seaiceRadiansToDegrees, &
- stressDivergenceV(iVertex), stressDivergenceV_test(iVertex), stressDivergenceV_diff(iVertex), &
- stressDivergenceV_diff(iVertex) * real(solveVelocity(iVertex),RKIND)
- enddo ! iVertex
- close(55)
- close(56)
-
- ! rms difference
- call rms_difference( &
- stressDivergenceU(1:nVertices), &
- stressDivergenceU_test, &
- solveVelocity(1:nVertices), &
- nVertices, &
- rms_divergenceU)
-
- call rms_difference( &
- stressDivergenceV(1:nVertices), &
- stressDivergenceV_test, &
- solveVelocity(1:nVertices), &
- nVertices, &
- rms_divergenceV)
-
- write(54,*)
- write(54,*) "RMS:"
- write(54,*) "rms_divergenceU:", rms_divergenceU
- write(54,*) "rms_divergenceV:", rms_divergenceV
-
- do iVertex = 1, nVertices
-
- if (solveVelocity(iVertex) == 0) then
- stressDivergenceU_test(iVertex) = 0.0_RKIND
- stressDivergenceU_test(iVertex) = 0.0_RKIND
- stressDivergenceU_diff(iVertex) = 0.0_RKIND
- stressDivergenceU_diff(iVertex) = 0.0_RKIND
- endif
-
- enddo ! iCell
-
- ! plot spatial distribution
- call plot_spherical_latlon(mesh, real(interiorVertex,RKIND), "interiorVertex_"//trim(unit_test_subtype)//".txt")
- call plot_spherical_latlon(mesh, real(solveVelocity,RKIND), "solveVelocity_"//trim(unit_test_subtype)//".txt")
- call plot_spherical_latlon(mesh, latVertexRotated0, "latVertexRotated0_"//trim(unit_test_subtype)//".txt")
-
- call plot_spherical_latlon(&
- mesh, stressDivergenceU, "stressDivergenceU_plot_"//trim(unit_test_subtype)//"_model.txt")
- call plot_spherical_latlon(&
- mesh, stressDivergenceU_test, "stressDivergenceU_plot_"//trim(unit_test_subtype)//"_analytical.txt")
- call plot_spherical_latlon(&
- mesh, stressDivergenceU_diff, "stressDivergenceU_plot_"//trim(unit_test_subtype)//"_diff.txt")
-
- call plot_spherical_latlon(&
- mesh, stressDivergenceV, "stressDivergenceV_plot_"//trim(unit_test_subtype)//"_model.txt")
- call plot_spherical_latlon(&
- mesh, stressDivergenceV_test, "stressDivergenceV_plot_"//trim(unit_test_subtype)//"_analytical.txt")
- call plot_spherical_latlon(&
- mesh, stressDivergenceV_diff, "stressDivergenceV_plot_"//trim(unit_test_subtype)//"_diff.txt")
-
- ! cleanup
- deallocate(stressDivergenceU_test)
- deallocate(stressDivergenceV_test)
- deallocate(stressDivergenceU_diff)
- deallocate(stressDivergenceV_diff)
-
- deallocate(lonVertexRotated0)
- deallocate(latVertexRotated0)
- deallocate(lonCellRotated0)
- deallocate(latCellRotated0)
-
- close(54)
-
- block => block % next
- enddo
-
- end subroutine seaice_stress_divergence_operator_unit_test_individual!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! spherical_test_divergence_stress_weak
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine spherical_test_divergence_stress_weak(mesh, &
- stress11, &
- stress22, &
- stress12, &
- longitudeStress, &
- latitudeStress, &
- stressDivergenceU, &
- stressDivergenceV, &
- longitudeDivergence, &
- latitudeDivergence, &
- test_type)!{{{
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
- real(kind=RKIND), dimension(:), intent(out) :: &
- stressDivergenceU, & !< Output:
- stressDivergenceV, & !< Output:
- stress11, & !< Output:
- stress22, & !< Output:
- stress12 !< Output:
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- longitudeStress, & !< Input:
- latitudeStress, & !< Input:
- longitudeDivergence, & !< Input:
- latitudeDivergence !< Input:
-
- character(len=*), intent(in) :: &
- test_type !< Input:
-
- real(kind=RKIND) :: &
- stress11_test, &
- stress22_test, &
- stress12_test, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat
-
- integer :: &
- nPointsStress, &
- nPointsDivergence, &
- iPoint
-
- real(kind=RKIND), pointer :: &
- sphere_radius
-
- call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
-
- nPointsStress = size(stress11)-1
- nPointsDivergence = size(stressDivergenceU)-1
-
- ! set stress points
- do iPoint = 1, nPointsStress
-
- call spherical_test_divergence_stress_stresses( &
- stress11(iPoint), &
- stress22(iPoint), &
- stress12(iPoint), &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- longitudeStress(iPoint), &
- latitudeStress(iPoint), &
- test_type)
-
- enddo ! iPoint
-
- ! set divergence poinys
- do iPoint = 1, nPointsDivergence
-
- call spherical_test_divergence_stress_stresses( &
- stress11_test, &
- stress22_test, &
- stress12_test, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- longitudeDivergence(iPoint), &
- latitudeDivergence(iPoint), &
- test_type)
-
- stressDivergenceU(iPoint) = &
- divergenceStressU(stress11_test, stress22_test, stress12_test, &
- dstress11_dlon, dstress11_dlat, dstress22_dlon, dstress22_dlat, dstress12_dlon, dstress12_dlat, &
- sphere_radius, longitudeDivergence(iPoint), latitudeDivergence(iPoint))
- stressDivergenceV(iPoint) = &
- divergenceStressV(stress11_test, stress22_test, stress12_test, &
- dstress11_dlon, dstress11_dlat, dstress22_dlon, dstress22_dlat, dstress12_dlon, dstress12_dlat, &
- sphere_radius, longitudeDivergence(iPoint), latitudeDivergence(iPoint))
-
- enddo ! iPoint
-
- end subroutine spherical_test_divergence_stress_weak!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! spherical_test_divergence_stress_variational
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine spherical_test_divergence_stress_variational(mesh, &
- stress11, &
- stress22, &
- stress12, &
- longitudeStress, &
- latitudeStress, &
- stressDivergenceU, &
- stressDivergenceV, &
- longitudeDivergence, &
- latitudeDivergence, &
- test_type)!{{{
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
- real(kind=RKIND), dimension(:), intent(out) :: &
- stressDivergenceU, & !< Output:
- stressDivergenceV !< Output:
-
- real(kind=RKIND), dimension(:,:), intent(out) :: &
- stress11, & !< Output:
- stress22, & !< Output:
- stress12 !< Output:
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- longitudeStress, & !< Input:
- latitudeStress, & !< Input:
- longitudeDivergence, & !< Input:
- latitudeDivergence !< Input:
-
- character(len=*), intent(in) :: &
- test_type !< Input:
-
- real(kind=RKIND) :: &
- stress11_test, &
- stress22_test, &
- stress12_test, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat
-
- integer, pointer :: &
- nCells, &
- nVertices
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- verticesOnCell
-
- integer :: &
- iVertex, &
- iCell, &
- iVertexOnCell
-
- real(kind=RKIND), pointer :: &
- sphere_radius
-
- call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
-
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
-
- ! set stress points
- do iCell = 1, nCells
-
- do iVertexOnCell = 1, nEdgesOnCell(iCell)
-
- iVertex = verticesOnCell(iVertexOnCell,iCell)
-
- call spherical_test_divergence_stress_stresses( &
- stress11(iVertexOnCell,iCell), &
- stress22(iVertexOnCell,iCell), &
- stress12(iVertexOnCell,iCell), &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- longitudeStress(iVertex), &
- latitudeStress(iVertex), &
- test_type)
-
- enddo ! iVertexOnCell
-
- enddo ! iCell
-
- ! set divergence points
- do iVertex = 1, nVertices
-
- call spherical_test_divergence_stress_stresses( &
- stress11_test, &
- stress22_test, &
- stress12_test, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- longitudeDivergence(iVertex), &
- latitudeDivergence(iVertex), &
- test_type)
-
- stressDivergenceU(iVertex) = &
- divergenceStressU(stress11_test, stress22_test, stress12_test, &
- dstress11_dlon, dstress11_dlat, dstress22_dlon, dstress22_dlat, dstress12_dlon, dstress12_dlat, &
- sphere_radius, longitudeDivergence(iVertex), latitudeDivergence(iVertex))
- stressDivergenceV(iVertex) = &
- divergenceStressV(stress11_test, stress22_test, stress12_test, &
- dstress11_dlon, dstress11_dlat, dstress22_dlon, dstress22_dlat, dstress12_dlon, dstress12_dlat, &
- sphere_radius, longitudeDivergence(iVertex), latitudeDivergence(iVertex))
-
- enddo ! iVertex
-
- end subroutine spherical_test_divergence_stress_variational!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! spherical_test_divergence_stress_stresses
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine spherical_test_divergence_stress_stresses( &
- stress11, &
- stress22, &
- stress12, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- lon, &
- lat, &
- test_type)!{{{
-
- real(kind=RKIND), intent(out) :: &
- stress11, &
- stress22, &
- stress12, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat
-
- real(kind=RKIND), intent(in) :: &
- lon, & !< Input:
- lat !< Input:
-
- character(len=*), intent(in) :: &
- test_type !< Input:
-
- if (trim(test_type) == "zero") then
-
- stress11 = 0.0_RKIND
- stress22 = 0.0_RKIND
- stress12 = 0.0_RKIND
-
- dstress11_dlon = 0.0_RKIND
- dstress11_dlat = 0.0_RKIND
- dstress22_dlon = 0.0_RKIND
- dstress22_dlat = 0.0_RKIND
- dstress12_dlon = 0.0_RKIND
- dstress12_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "const11") then
-
- stress11 = 1.0_RKIND
- stress22 = 0.0_RKIND
- stress12 = 0.0_RKIND
-
- dstress11_dlon = 0.0_RKIND
- dstress11_dlat = 0.0_RKIND
- dstress22_dlon = 0.0_RKIND
- dstress22_dlat = 0.0_RKIND
- dstress12_dlon = 0.0_RKIND
- dstress12_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "const22") then
-
- stress11 = 0.0_RKIND
- stress22 = 1.0_RKIND
- stress12 = 0.0_RKIND
-
- dstress11_dlon = 0.0_RKIND
- dstress11_dlat = 0.0_RKIND
- dstress22_dlon = 0.0_RKIND
- dstress22_dlat = 0.0_RKIND
- dstress12_dlon = 0.0_RKIND
- dstress12_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "const12") then
-
- stress11 = 0.0_RKIND
- stress22 = 0.0_RKIND
- stress12 = 1.0_RKIND
-
- dstress11_dlon = 0.0_RKIND
- dstress11_dlat = 0.0_RKIND
- dstress22_dlon = 0.0_RKIND
- dstress22_dlat = 0.0_RKIND
- dstress12_dlon = 0.0_RKIND
- dstress12_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "test1") then
-
- stress11 = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- stress22 = 0.0_RKIND
- stress12 = 0.0_RKIND
-
- dstress11_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dstress11_dlat = -cos(lon) * 2.0_RKIND * sin(2.0_RKIND * lat)
- dstress22_dlon = 0.0_RKIND
- dstress22_dlat = 0.0_RKIND
- dstress12_dlon = 0.0_RKIND
- dstress12_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "test2") then
-
- stress11 = 0.0_RKIND
- stress22 = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- stress12 = 0.0_RKIND
-
- dstress11_dlon = 0.0_RKIND
- dstress11_dlat = 0.0_RKIND
- dstress22_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dstress22_dlat = -cos(lon) * 2.0_RKIND * sin(2.0_RKIND * lat)
- dstress12_dlon = 0.0_RKIND
- dstress12_dlat = 0.0_RKIND
-
- else if (trim(test_type) == "test3") then
-
- stress11 = 0.0_RKIND
- stress22 = 0.0_RKIND
- stress12 = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
-
- dstress11_dlon = 0.0_RKIND
- dstress11_dlat = 0.0_RKIND
- dstress22_dlon = 0.0_RKIND
- dstress22_dlat = 0.0_RKIND
- dstress12_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dstress12_dlat = -cos(lon) * 2.0_RKIND * sin(2.0_RKIND * lat)
-
- else if (trim(test_type) == "test4") then
-
- stress11 = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- stress22 = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- stress12 = cos(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
-
- dstress11_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dstress11_dlat = -cos(lon) * 2.0_RKIND * sin(2.0_RKIND * lat)
- dstress22_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dstress22_dlat = -cos(lon) * 2.0_RKIND * sin(2.0_RKIND * lat)
- dstress12_dlon = -sin(lon) * (1.0_RKIND + cos(2.0_RKIND * lat))
- dstress12_dlat = -cos(lon) * 2.0_RKIND * sin(2.0_RKIND * lat)
-
- else
-
- call mpas_log_write("spherical_test_divergence_stress_stresses: Unknown test case: "//trim(test_type), &
- MPAS_LOG_CRIT)
-
- endif
-
- end subroutine spherical_test_divergence_stress_stresses!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! divergenceStressU
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- function divergenceStressU(&
- stress11, &
- stress22, &
- stress12, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- r, &
- lon, &
- lat) &
- result(divu)!{{{
-
- real(kind=RKIND), intent(in) :: &
- stress11, & !< Input:
- stress22, & !< Input:
- stress12, & !< Input:
- dstress11_dlon, & !< Input:
- dstress11_dlat, & !< Input:
- dstress22_dlon, & !< Input:
- dstress22_dlat, & !< Input:
- dstress12_dlon, & !< Input:
- dstress12_dlat, & !< Input:
- r, & !< Input:
- lon, & !< Input:
- lat !< Input:
-
- real(kind=RKIND) :: divu
-
- divu = (1.0_RKIND / (r * cos(lat))) * dstress11_dlon + &
- (1.0_RKIND / r) * dstress12_dlat - &
- (2.0_RKIND / r) * tan(lat) * stress12
-
- end function divergenceStressU!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! divergenceStressV
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- function divergenceStressV(&
- stress11, &
- stress22, &
- stress12, &
- dstress11_dlon, &
- dstress11_dlat, &
- dstress22_dlon, &
- dstress22_dlat, &
- dstress12_dlon, &
- dstress12_dlat, &
- r, &
- lon, &
- lat) &
- result(divv)!{{{
-
- real(kind=RKIND), intent(in) :: &
- stress11, & !< Input:
- stress22, & !< Input:
- stress12, & !< Input:
- dstress11_dlon, & !< Input:
- dstress11_dlat, & !< Input:
- dstress22_dlon, & !< Input:
- dstress22_dlat, & !< Input:
- dstress12_dlon, & !< Input:
- dstress12_dlat, & !< Input:
- r, & !< Input:
- lon, & !< Input:
- lat !< Input:
-
- real(kind=RKIND) :: divv
-
- divv = (1.0_RKIND / (r * cos(lat))) * dstress12_dlon + &
- (1.0_RKIND / r) * dstress22_dlat + &
- (1.0_RKIND / r) * tan(lat) * stress11 - &
- (1.0_RKIND / r) * tan(lat) * stress22
-
- end function divergenceStressV!}}}
-
-!-----------------------------------------------------------------------
-! EVP Constitutive relationship unit test
-!-----------------------------------------------------------------------
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_constitutive_relationship_unit_test
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_constitutive_relationship_unit_test(&
- domain)!{{{
-
- use seaice_velocity_solver_constitutive_relation, only: &
- seaice_evp_constitutive_relation, &
- seaice_evp_constitutive_relation_revised, &
- seaice_init_evp
-
- type(domain_type), intent(inout) :: &
- domain !< Input/Output:
-
- type(block_type), pointer :: &
- block
-
- integer, parameter :: &
- nTests = 2
-
- real(kind=RKIND), dimension(nTests) :: &
- icePressure, &
- stress11, &
- stress22, &
- stress12, &
- strain11, &
- strain22, &
- strain12
-
- real(kind=RKIND) :: &
- replacementPressure, &
- areaCell
-
- logical, pointer :: &
- config_revised_evp
-
- type(MPAS_pool_type), pointer :: &
- velocitySolver
-
- real(kind=RKIND), pointer :: &
- elasticTimeStep
-
- integer :: &
- iTest
-
- call MPAS_pool_get_config(domain % configs, "config_revised_evp", config_revised_evp)
-
- call seaice_init_evp(domain)
-
- block => domain % blocklist
- do while (associated(block))
-
- call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocitySolver)
- call MPAS_pool_get_array(velocitySolver, "elasticTimeStep", elasticTimeStep)
-
- call constitutive_relationship_set_strains(&
- stress11, &
- stress22, &
- stress12, &
- icePressure, &
- strain11, &
- strain22, &
- strain12)
-
- areaCell = 1.0_RKIND
-
- do iTest = 1, nTests
-
- if (.not. config_revised_evp) then
-
- call seaice_evp_constitutive_relation(&
- stress11(iTest), &
- stress22(iTest), &
- stress12(iTest), &
- strain11(iTest), &
- strain22(iTest), &
- strain12(iTest), &
- icePressure(iTest), &
- replacementPressure, &
- areaCell, &
- elasticTimeStep)
-
- else
-
- call seaice_evp_constitutive_relation_revised(&
- stress11(iTest), &
- stress22(iTest), &
- stress12(iTest), &
- strain11(iTest), &
- strain22(iTest), &
- strain12(iTest), &
- icePressure(iTest), &
- replacementPressure, &
- areaCell)
-
- endif
-
- enddo ! iTest
-
- call constitutive_relationship_writeout(&
- icePressure, &
- strain11, &
- strain22, &
- strain12, &
- stress11, &
- stress22, &
- stress12)
-
- block => block % next
- enddo
-
- end subroutine seaice_constitutive_relationship_unit_test!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! constitutive_relationship_set_strains
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine constitutive_relationship_set_strains(&
- stress11, &
- stress22, &
- stress12, &
- icePressure, &
- strain11, &
- strain22, &
- strain12)!{{{
-
- real(kind=RKIND), dimension(:), intent(out) :: &
- stress11, & !< Output:
- stress22, & !< Output:
- stress12, & !< Output:
- icePressure, & !< Output:
- strain11, & !< Output:
- strain22, & !< Output:
- strain12 !< Output:
-
- integer :: &
- iTest
-
- ! test 1
- iTest = 1
- stress11(iTest) = 0.0_RKIND
- stress22(iTest) = 0.0_RKIND
- stress12(iTest) = 0.0_RKIND
- icePressure(iTest) = 0.0_RKIND
- strain11(iTest) = 0.0_RKIND
- strain22(iTest) = 0.0_RKIND
- strain12(iTest) = 0.0_RKIND
-
- ! test 2
- iTest = 2
- stress11(iTest) = 0.0_RKIND
- stress22(iTest) = 0.0_RKIND
- stress12(iTest) = 0.0_RKIND
- icePressure(iTest) = 1000000000.0_RKIND
- strain11(iTest) = 1.0_RKIND
- strain22(iTest) = 1.0_RKIND
- strain12(iTest) = 1.0_RKIND
-
- end subroutine constitutive_relationship_set_strains!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! constitutive_relationship_writeout
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine constitutive_relationship_writeout(&
- icePressure, &
- strain11, &
- strain22, &
- strain12, &
- stress11, &
- stress22, &
- stress12)!{{{
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- icePressure, & !< Input:
- strain11, & !< Input:
- strain22, & !< Input:
- strain12, & !< Input:
- stress11, & !< Input:
- stress22, & !< Input:
- stress12 !< Input:
-
- integer :: &
- iTest
-
- write(*,*) "Constitutive tests"
- write(*,*)
-
- do iTest = 1, size(icePressure)
-
- write(*,*) "Constitutive test ", iTest
-
- write(*,*) "strength: ", icePressure(iTest)
- write(*,*) "strain11: ", strain11(iTest)
- write(*,*) "strain22: ", strain22(iTest)
- write(*,*) "strain12: ", strain12(iTest)
- write(*,*) "stress11: ", stress11(iTest)
- write(*,*) "stress22: ", stress22(iTest)
- write(*,*) "stress12: ", stress12(iTest)
-
- enddo ! iTest
-
- end subroutine constitutive_relationship_writeout!}}}
-
-!-----------------------------------------------------------------------
-! Utils
-!-----------------------------------------------------------------------
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! rms_difference
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine rms_difference(array1, array2, mask, n, rms)!{{{
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- array1, & !< Input:
- array2 !< Input:
-
- integer, dimension(:), intent(in) :: &
- mask !< Input:
-
- integer, intent(in) :: &
- n !< Input:
-
- real(kind=RKIND), intent(out) :: &
- rms !< Output:
-
- integer :: &
- i, &
- num
-
- rms = 0.0_RKIND
- num = 0
-
- do i = 1, n
-
- if (mask(i) == 1) then
-
- rms = rms + (array1(i) - array2(i))**2
- num = num + 1
-
- endif
-
- enddo ! i
-
- rms = sqrt(rms / real(num, RKIND))
-
- end subroutine rms_difference!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! plot_spherical_latlon
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine plot_spherical_latlon(mesh, array, filename, tag)!{{{
-
- use seaice_constants, only: &
- pii
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- array !< Input:
-
- character(len=*), intent(in) :: &
- filename !< Input:
-
- integer, optional, intent(in) :: &
- tag !< Input:
-
- integer, pointer :: &
- nCells, &
- nVertices, &
- vertexDegree
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- pointVertexOnPoint
-
- real(kind=RKIND), dimension(:), pointer :: &
- lonPointVertex, &
- latPointVertex, &
- lonPoint, &
- latPoint
-
- integer, dimension(:), allocatable :: &
- nPointVerticesOnPoint, &
- plotPoint
-
- integer :: &
- iPoint, &
- iPointVertexOnPoint, &
- iPointVertex, &
- nPoints, &
- array_size
-
- real(kind=RKIND) :: &
- plotLonPointVertex, &
- plotLatPointVertex, &
- plotLonPointVertex0, &
- plotLatPointVertex0
-
- character(len=2000) :: &
- strout, &
- stroutvertex
-
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
-
- if (size(array) == nCells+1 .or. size(array) == nCells) then
-
- array_size = nCells
-
- nPoints = nCells
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- allocate(nPointVerticesOnPoint(nCells))
- nPointVerticesOnPoint(:) = nEdgesOnCell(1:nCells)
- call MPAS_pool_get_array(mesh, "verticesOnCell", pointVertexOnPoint)
- call MPAS_pool_get_array(mesh, "lonVertex", lonPointVertex)
- call MPAS_pool_get_array(mesh, "latVertex", latPointVertex)
- call MPAS_pool_get_array(mesh, "lonCell", lonPoint)
- call MPAS_pool_get_array(mesh, "latCell", latPoint)
- allocate(plotPoint(nCells))
- plotPoint = 1
-
- else if (size(array) == nVertices+1 .or. size(array) == nVertices) then
-
- array_size = nVertices
-
- nPoints = nVertices
- call MPAS_pool_get_dimension(mesh, "vertexDegree", vertexDegree)
- allocate(nPointVerticesOnPoint(nVertices))
- nPointVerticesOnPoint(:) = vertexDegree
- call MPAS_pool_get_array(mesh, "cellsOnVertex", pointVertexOnPoint)
- call MPAS_pool_get_array(mesh, "lonCell", lonPointVertex)
- call MPAS_pool_get_array(mesh, "latCell", latPointVertex)
- call MPAS_pool_get_array(mesh, "lonVertex", lonPoint)
- call MPAS_pool_get_array(mesh, "latVertex", latPoint)
- allocate(plotPoint(nVertices))
- do iPoint = 1, nVertices
- plotPoint(iPoint) = 1
- do iPointVertexOnPoint = 1, vertexDegree
- if (pointVertexOnPoint(iPointVertexOnPoint,iPoint) > nCells) then
- plotPoint(iPoint) = 0
- endif
- enddo ! iPointVertexOnPoint
- enddo ! iPoint
-
- else
- write(*,*) "plot_spherical_latlon: size not supported: ", size(array)
- endif
-
- call open_filename_tag(55, filename, tag)
-
- write(55,*) "set xrange [0:6.283]"
- write(55,*) "set yrange [-1.571:1.571]"
- write(55,*) "set cbrange [",minval(array(1:array_size)),":",maxval(array(1:array_size)),"]"
-
- write(55,*) "set pm3d"
- write(55,*) "set size square"
- write(55,*) "unset key"
- write(55,*) "set palette defined (0 0.0 0.0 0.5, 1 0.0 0.0 1.0, 2 0.0 0.5 1.0, 3 0.0 1.0 1.0, "//&
- "4 0.5 1.0 0.5, 5 1.0 1.0 0.0, 6 1.0 0.5 0.0, 7 1.0 0.0 0.0, 8 0.5 0.0 0.0 )"
-
- iObject = 1
-
- do iPoint = 1, nPoints
-
- if (plotPoint(iPoint) == 1) then
-
- write(strout,fmt='(a,i5,a)') "set object ",iObject," polygon from "
-
- do iPointVertexOnPoint = 1, nPointVerticesOnPoint(iPoint)
-
- iPointVertex = pointVertexOnPoint(iPointVertexOnPoint,iPoint)
-
- plotLonPointVertex = lonPointVertex(iPointVertex)
- plotLatPointVertex = latPointVertex(iPointVertex)
-
- if (lonPoint(iPoint) <= pii) then
-
- if (plotLonPointVertex >= 0.9_RKIND * 2.0_RKIND * pii) then
- plotLonPointVertex = plotLonPointVertex - 2.0_RKIND * pii
- endif
-
- endif
-
- if (lonPoint(iPoint) > pii) then
-
- if (plotLonPointVertex <= 0.1_RKIND * 2.0_RKIND * pii) then
- plotLonPointVertex = plotLonPointVertex + 2.0_RKIND * pii
- endif
-
- endif
-
- if (iPointVertexOnPoint == 1) then
-
- plotLonPointVertex0 = plotLonPointVertex
- plotLatPointVertex0 = plotLatPointVertex
-
- endif
-
- write(stroutvertex,fmt='(f14.2,a,f14.2,a)') plotLonPointVertex, ",", plotLatPointVertex, " to "
- strout = trim(strout)//trim(stroutvertex)
-
- enddo ! iPointVertexOnPoint
-
- write(stroutvertex,fmt='(f14.2,a,f14.2)') plotLonPointVertex0, ",", plotLatPointVertex0
- strout = trim(strout)//trim(stroutvertex)
- write(55,*) trim(strout)
-
- write(strout,fmt='(a,i5,a,e14.6,a)') "set object ",iObject,' fc palette cb ', array(iPoint), ' fillstyle solid'
- write(55,*) trim(strout)
-
- iObject = iObject + 1
-
- endif ! plotPoint
-
- enddo ! iPoint
-
- deallocate(nPointVerticesOnPoint)
- deallocate(plotPoint)
-
- write(55,*) "plot -10"
-
- close(55)
-
- end subroutine plot_spherical_latlon!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! open_filename_tag
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine open_filename_tag(unit, filename, tag)!{{{
-
- integer, intent(in) :: &
- unit !< Input:
-
- character(len=*), intent(in) :: &
- filename !< Input:
-
- integer, optional, intent(in) :: &
- tag !< Input:
-
- character(len=2000) :: &
- strtag, &
- filename_use
-
- if (present(tag)) then
- write(strtag,fmt='(i5.5)') tag
- filename_use = filename(1:len(trim(filename))-4)//"_"//trim(strtag)//filename(len(trim(filename))-3:)
- open(unit,file=trim(filename_use),action='write')
- else
- open(unit,file=trim(filename),action='write')
- endif
-
- end subroutine open_filename_tag!}}}
-
- !--------------------------------------------------------------------------
-
-end module seaice_velocity_solver_unit_tests
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_variational.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_variational.F
index f090cb73b5..92eed849db 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_variational.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver_variational.F
@@ -12,9 +12,12 @@
module seaice_velocity_solver_variational
+#include "gpu_macros.inc"
+
use mpas_derived_types
use mpas_pool_routines
use mpas_timer
+ use mpas_log, only: mpas_log_write
implicit none
@@ -24,8 +27,9 @@ module seaice_velocity_solver_variational
public :: &
seaice_init_velocity_solver_variational, &
seaice_strain_tensor_variational, &
+ seaice_average_strains_on_vertex, &
+ seaice_stress_tensor_variational, &
seaice_stress_divergence_variational, &
- seaice_internal_stress_variational, &
seaice_final_divergence_shear_variational
contains
@@ -53,9 +57,72 @@ subroutine seaice_init_velocity_solver_variational(&
rotateCartesianGrid, &
includeMetricTerms, &
variationalBasisType, &
+ variationalDenominatorType, &
+ integrationType, &
+ integrationOrder)!{{{
+
+ type(MPAS_pool_type), pointer, intent(in) :: &
+ mesh !< Input:
+
+ type(MPAS_pool_type), pointer :: &
+ velocity_variational, & !< Input/Output:
+ boundary !< Input/Output:
+
+ logical, intent(in) :: &
+ rotateCartesianGrid, & !< Input:
+ includeMetricTerms !< Input:
+
+ character(len=*), intent(in) :: &
+ variationalBasisType, & !< Input:
+ variationalDenominatorType, & !< Input:
+ integrationType !< Input:
+
+ integer, intent(in) :: &
+ integrationOrder !< Input:
+
+ call init_velocity_solver_variational_primary_mesh(&
+ mesh, &
+ velocity_variational, &
+ boundary, &
+ rotateCartesianGrid, &
+ includeMetricTerms, &
+ variationalBasisType, &
+ variationalDenominatorType, &
+ integrationType, &
+ integrationOrder)
+
+ end subroutine seaice_init_velocity_solver_variational
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! init_velocity_solver_variational_primary_mesh
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 24 October 2014
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine init_velocity_solver_variational_primary_mesh(&
+ mesh, &
+ velocity_variational, &
+ boundary, &
+ rotateCartesianGrid, &
+ includeMetricTerms, &
+ variationalBasisType, &
+ variationalDenominatorType, &
integrationType, &
integrationOrder)!{{{
+ use seaice_mesh, only: &
+ seaice_cell_vertices_at_vertex
+
+ use seaice_velocity_solver_variational_shared, only: &
+ seaice_calc_local_coords, &
+ seaice_calc_variational_metric_terms
+
use seaice_velocity_solver_wachspress, only: &
seaice_init_velocity_solver_wachspress
@@ -74,187 +141,424 @@ subroutine seaice_init_velocity_solver_variational(&
includeMetricTerms !< Input:
character(len=*), intent(in) :: &
- variationalBasisType, & !< Input:
- integrationType !< Input:
+ variationalBasisType, & !< Input:
+ variationalDenominatorType, & !< Input:
+ integrationType !< Input:
integer, intent(in) :: &
integrationOrder !< Input:
+ integer, dimension(:,:), pointer :: &
+ cellVerticesAtVertex
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ tanLatVertexRotatedOverRadius, &
+ variationalDenominator
+
+ real(kind=RKIND), dimension(:,:,:), pointer :: &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsMetric, &
+ basisIntegralsU, &
+ basisIntegralsV
+
+ integer, pointer :: &
+ nCells, &
+ nVertices, &
+ vertexDegree, &
+ maxEdges
+
+ integer, dimension(:), pointer :: &
+ nEdgesOnCell, &
+ interiorVertex
+
+ integer, dimension(:,:), pointer :: &
+ verticesOnCell, &
+ cellsOnVertex, &
+ edgesOnCell
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell, &
+ areaCell, &
+ areaTriangle, &
+ dvEdge
+
+ logical, pointer :: &
+ on_a_sphere
+
+ real(kind=RKIND), pointer :: &
+ sphere_radius
+
+ real(kind=RKIND), dimension(:,:), allocatable :: &
+ xLocal, &
+ yLocal
+
+ call MPAS_pool_get_config(mesh, "on_a_sphere", on_a_sphere)
+ call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
+
+ call MPAS_pool_get_dimension(mesh, "nCells", nCells)
+ call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
+ call MPAS_pool_get_dimension(mesh, "vertexDegree", vertexDegree)
+ call MPAS_pool_get_dimension(mesh, "maxEdges", maxEdges)
+
+ call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
+ call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
+ call MPAS_pool_get_array(mesh, "cellsOnVertex", cellsOnVertex)
+ call MPAS_pool_get_array(mesh, "edgesOnCell", edgesOnCell)
+ call MPAS_pool_get_array(mesh, "xVertex", xVertex)
+ call MPAS_pool_get_array(mesh, "yVertex", yVertex)
+ call MPAS_pool_get_array(mesh, "zVertex", zVertex)
+ call MPAS_pool_get_array(mesh, "xCell", xCell)
+ call MPAS_pool_get_array(mesh, "yCell", yCell)
+ call MPAS_pool_get_array(mesh, "zCell", zCell)
+ call MPAS_pool_get_array(mesh, "areaCell", areaCell)
+ call MPAS_pool_get_array(mesh, "areaTriangle", areaTriangle)
+ call MPAS_pool_get_array(mesh, "dvEdge", dvEdge)
+
+ call MPAS_pool_get_array(boundary, "interiorVertex", interiorVertex)
+
+ call MPAS_pool_get_array(velocity_variational, "cellVerticesAtVertex", cellVerticesAtVertex)
+ call MPAS_pool_get_array(velocity_variational, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
+ call MPAS_pool_get_array(velocity_variational, "basisGradientU", basisGradientU)
+ call MPAS_pool_get_array(velocity_variational, "basisGradientV", basisGradientV)
+ call MPAS_pool_get_array(velocity_variational, "basisIntegralsU", basisIntegralsU)
+ call MPAS_pool_get_array(velocity_variational, "basisIntegralsV", basisIntegralsV)
+ call MPAS_pool_get_array(velocity_variational, "basisIntegralsMetric", basisIntegralsMetric)
+ call MPAS_pool_get_array(velocity_variational, "variationalDenominator", variationalDenominator)
+
+ call mpas_timer_start("variational calc_metric_terms")
+ call seaice_calc_variational_metric_terms(&
+ tanLatVertexRotatedOverRadius, &
+ nVertices, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ sphere_radius, &
+ rotateCartesianGrid, &
+ includeMetricTerms)
+ call mpas_timer_stop("variational calc_metric_terms")
+
+ call mpas_timer_start("variational vertices_at_vertex")
+ call seaice_cell_vertices_at_vertex(&
+ cellVerticesAtVertex, &
+ nVertices, &
+ vertexDegree, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ cellsOnVertex)
+ call mpas_timer_stop("variational vertices_at_vertex")
+
+ call mpas_timer_start("variational calc_local_coords")
+ allocate(xLocal(maxEdges,nCells))
+ allocate(yLocal(maxEdges,nCells))
+
+ call seaice_calc_local_coords(&
+ xLocal, &
+ yLocal, &
+ nCells, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell, &
+ rotateCartesianGrid, &
+ on_a_sphere)
+ call mpas_timer_stop("variational calc_local_coords")
+
if (trim(variationalBasisType) == "wachspress") then
call seaice_init_velocity_solver_wachspress(&
- mesh, &
- velocity_variational, &
- boundary, &
+ nCells, &
+ maxEdges, &
+ nEdgesOnCell, &
+ xLocal, &
+ yLocal, &
rotateCartesianGrid, &
includeMetricTerms, &
+ on_a_sphere, &
integrationType, &
- integrationOrder)
+ integrationOrder, &
+ sphere_radius, &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsU, &
+ basisIntegralsV, &
+ basisIntegralsMetric)
else if (trim(variationalBasisType) == "pwl") then
call seaice_init_velocity_solver_pwl(&
- mesh, &
- velocity_variational, &
- boundary, &
- rotateCartesianGrid, &
- includeMetricTerms)
+ nCells, &
+ maxEdges, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ edgesOnCell, &
+ dvEdge, &
+ areaCell, &
+ xLocal, &
+ yLocal, &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsMetric, &
+ basisIntegralsU, &
+ basisIntegralsV)
+
+ else if (trim(variationalBasisType) == "none") then
+
+ continue
+
+ else
+
+ call MPAS_log_write("Unknown variational basis type: "//trim(variationalBasisType), MPAS_LOG_CRIT)
endif
- end subroutine seaice_init_velocity_solver_variational
+ call mpas_timer_start("variational denominator")
+ call variational_denominator(&
+ nVertices, &
+ vertexDegree, &
+ nEdgesOnCell, &
+ interiorVertex, &
+ areaTriangle, &
+ cellsOnVertex, &
+ cellVerticesAtVertex, &
+ basisIntegralsMetric, &
+ variationalDenominatorType, &
+ variationalDenominator)
+ call mpas_timer_stop("variational denominator")
-!-----------------------------------------------------------------------
-! time step
-!-----------------------------------------------------------------------
+ ! clean up
+ deallocate(xLocal)
+ deallocate(yLocal)
+
+ !call homogenize_variational_basis_field()
+
+ end subroutine init_velocity_solver_variational_primary_mesh
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
-! seaice_internal_stress_variational
+! variational_denominator
!
!> \brief
!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
+!> \date 30th January 2021
!> \details
!>
!
!-----------------------------------------------------------------------
- subroutine seaice_internal_stress_variational(domain)!{{{
+ subroutine variational_denominator(&
+ nVertices, &
+ vertexDegree, &
+ nEdgesOnCell, &
+ interiorVertex, &
+ areaTriangle, &
+ cellsOnVertex, &
+ cellVerticesAtVertex, &
+ basisIntegralsMetric, &
+ variationalDenominatorType, &
+ variationalDenominator)
+
+ integer, intent(in) :: &
+ nVertices, & !< Input:
+ vertexDegree !< Input:
- type(domain_type), intent(inout) :: &
- domain
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell, & !< Input:
+ interiorVertex !< Input:
- type(block_type), pointer :: &
- block
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ areaTriangle !< Input:
- type (MPAS_pool_type), pointer :: &
- meshPool, &
- velocityVariationalPool, &
- velocitySolverPool
+ integer, dimension(:,:), intent(in) :: &
+ cellsOnVertex !< Input:
- real(kind=RKIND), dimension(:), pointer :: &
- uVelocity, &
- vVelocity, &
- icePressure, &
- stressDivergenceU, &
- stressDivergenceV
+ integer, dimension(:,:), intent(in) :: &
+ cellVerticesAtVertex !< Input:
- real(kind=RKIND), pointer :: &
- elasticTimeStep
+ real(kind=RKIND), dimension(:,:,:), intent(in) :: &
+ basisIntegralsMetric !< Input:
- logical, pointer :: &
- revisedEVP
+ character(len=*), intent(in) :: &
+ variationalDenominatorType !< Input:
- integer, dimension(:), pointer :: &
- solveStress, &
- solveVelocity
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ variationalDenominator
- integer, dimension(:,:), pointer :: &
- cellVerticesAtVertex
+ integer :: &
+ iVertex, &
+ iSurroundingCell, &
+ iStressVertex, &
+ iCell, &
+ iVelocityVertex
- real(kind=RKIND), dimension(:), pointer :: &
- tanLatVertexRotatedOverRadius
+ if (trim(variationalDenominatorType) == "alternate") then
- real(kind=RKIND), dimension(:,:), pointer :: &
- replacementPressure, &
- strain11, &
- strain22, &
- strain12, &
- stress11, &
- stress22, &
- stress12
+ do iVertex = 1, nVertices
- real(kind=RKIND), dimension(:,:,:), pointer :: &
+ variationalDenominator(iVertex) = 0.0_RKIND
+
+ ! loop over surrounding cells
+ do iSurroundingCell = 1, vertexDegree
+
+ ! get the cell number of this cell
+ iCell = cellsOnVertex(iSurroundingCell, iVertex)
+
+ ! get the vertexOnCell number of the iVertex velocity point from cell iCell
+ iVelocityVertex = cellVerticesAtVertex(iSurroundingCell,iVertex)
+
+ ! loop over the vertices of the surrounding cell
+ do iStressVertex = 1, nEdgesOnCell(iCell)
+
+ variationalDenominator(iVertex) = variationalDenominator(iVertex) + &
+ basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell)
+
+ enddo ! iStressVertex
+
+ enddo ! iSurroundingCell
+
+ ! inverse
+ variationalDenominator(iVertex) = variationalDenominator(iVertex)
+
+ enddo ! iVertex
+
+ else if (trim(variationalDenominatorType) == "original") then
+
+ do iVertex = 1, nVertices
+ variationalDenominator(iVertex) = areaTriangle(iVertex)
+ enddo ! iVertex
+
+ else
+
+ call MPAS_log_write("Unknown variational denominator type: "//trim(variationalDenominatorType), MPAS_LOG_CRIT)
+
+ endif
+
+ end subroutine variational_denominator
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! homogenize_variational_basis_field
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 9th January 2021
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine homogenize_variational_basis_field()
+
+ use seaice_mesh_pool, only: &
basisGradientU, &
basisGradientV, &
+ basisIntegralsMetric, &
basisIntegralsU, &
basisIntegralsV, &
- basisIntegralsMetric
-
- block => domain % blocklist
- do while (associated(block))
-
- call MPAS_pool_get_config(block % configs, "config_revised_evp", revisedEVP)
-
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "velocity_variational", velocityVariationalPool)
- call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocitySolverPool)
-
- call MPAS_pool_get_array(velocitySolverPool, "solveStress", solveStress)
- call MPAS_pool_get_array(velocitySolverPool, "solveVelocity", solveVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "icePressure", icePressure)
- call MPAS_pool_get_array(velocitySolverPool, "elasticTimeStep", elasticTimeStep)
- call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceU", stressDivergenceU)
- call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceV", stressDivergenceV)
-
- call MPAS_pool_get_array(velocityVariationalPool, "strain11", strain11)
- call MPAS_pool_get_array(velocityVariationalPool, "strain22", strain22)
- call MPAS_pool_get_array(velocityVariationalPool, "strain12", strain12)
- call MPAS_pool_get_array(velocityVariationalPool, "stress11", stress11)
- call MPAS_pool_get_array(velocityVariationalPool, "stress22", stress22)
- call MPAS_pool_get_array(velocityVariationalPool, "stress12", stress12)
- call MPAS_pool_get_array(velocityVariationalPool, "cellVerticesAtVertex", cellVerticesAtVertex)
- call MPAS_pool_get_array(velocityVariationalPool, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
- call MPAS_pool_get_array(velocityVariationalPool, "basisGradientU", basisGradientU)
- call MPAS_pool_get_array(velocityVariationalPool, "basisGradientV", basisGradientV)
- call MPAS_pool_get_array(velocityVariationalPool, "basisIntegralsU", basisIntegralsU)
- call MPAS_pool_get_array(velocityVariationalPool, "basisIntegralsV", basisIntegralsV)
- call MPAS_pool_get_array(velocityVariationalPool, "basisIntegralsMetric", basisIntegralsMetric)
- call MPAS_pool_get_array(velocityVariationalPool, "replacementPressure", replacementPressure)
-
- call mpas_timer_start("Velocity solver strain tensor")
- call seaice_strain_tensor_variational(&
- meshPool, &
- strain11, &
- strain22, &
- strain12, &
- uVelocity, &
- vVelocity, &
- basisGradientU, &
- basisGradientV, &
- tanLatVertexRotatedOverRadius, &
- solveStress)
- call mpas_timer_stop("Velocity solver strain tensor")
-
- call mpas_timer_start("Velocity solver stress tensor")
- call seaice_stress_tensor_variational(&
- meshPool, &
- stress11, &
- stress22, &
- stress12, &
- strain11, &
- strain22, &
- strain12, &
- icePressure, &
- replacementPressure, &
- solveStress, &
- elasticTimeStep, &
- revisedEVP)
- call mpas_timer_stop("Velocity solver stress tensor")
-
- call mpas_timer_start("Velocity solver stress divergence")
- call seaice_stress_divergence_variational(&
- meshPool, &
- stressDivergenceU, &
- stressDivergenceV, &
- stress11, &
- stress22, &
- stress12, &
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric, &
- tanLatVertexRotatedOverRadius, &
- cellVerticesAtVertex, &
- solveVelocity)
- call mpas_timer_stop("Velocity solver stress divergence")
+ nCells
+
+ integer :: &
+ iCell
+
+ integer, parameter :: &
+ iCellHomogenize = 1111
+
+ !call homogenize_cell(basisGradientU, iCellHomogenize)
+ !call homogenize_cell(basisGradientV, iCellHomogenize)
+ !call homogenize_cell(basisIntegralsMetric, iCellHomogenize)
+ !call homogenize_cell(basisIntegralsU, iCellHomogenize)
+ !call homogenize_cell(basisIntegralsV, iCellHomogenize)
- block => block % next
- end do
+ do iCell = 1, nCells
+
+ basisGradientU(:,:,iCell) = basisGradientU(:,:,iCellHomogenize)
+ basisGradientV(:,:,iCell) = basisGradientV(:,:,iCellHomogenize)
+ basisIntegralsMetric(:,:,iCell) = basisIntegralsMetric(:,:,iCellHomogenize)
+ basisIntegralsU(:,:,iCell) = basisIntegralsU(:,:,iCellHomogenize)
+ basisIntegralsV(:,:,iCell) = basisIntegralsV(:,:,iCellHomogenize)
+
+ enddo ! iCell
- end subroutine seaice_internal_stress_variational!}}}
+ end subroutine homogenize_variational_basis_field
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! homogenize_variational_basis_field
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 9th January 2021
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine homogenize_cell(&
+ field, &
+ iCell)
+
+ real(kind=RKIND), dimension(:,:,:), intent(inout) :: &
+ field
+
+ integer, intent(in) :: &
+ iCell
+
+ integer :: &
+ iVertexOnCell1, &
+ iVertexOnCell2, &
+ nCanonicalValues, &
+ iCV
+
+ real(kind=RKIND), dimension(100) :: &
+ canonicalValues
+
+ logical :: &
+ lFound
+
+ nCanonicalValues = 0
+
+ do iVertexOnCell1 = 1, 6
+ do iVertexOnCell2 = 1, 6
+
+ lFound = .false.
+ do iCV = 1, nCanonicalValues
+
+ if (abs(abs(canonicalValues(iCV) - abs(field(iVertexOnCell1,iVertexOnCell2,iCell)))) < 1e-12) then
+ lFound = .true.
+ field(iVertexOnCell1,iVertexOnCell2,iCell) = canonicalValues(iCV) * sign(1.0_RKIND, field(iVertexOnCell1,iVertexOnCell2,iCell))
+ exit
+ endif
+
+ enddo ! iCV
+
+ if (.not. lFound) then
+ nCanonicalValues = nCanonicalValues + 1
+ canonicalValues(nCanonicalValues) = abs(field(iVertexOnCell1,iVertexOnCell2,iCell))
+ endif
+
+ enddo ! iVertexOnCell2
+ enddo ! iVertexOnCell1
+
+ !do iVertexOnCell1 = 1, 6
+ ! do iVertexOnCell2 = 1, 6
+ ! write(*,*) iVertexOnCell1, iVertexOnCell2, field(iVertexOnCell1,iVertexOnCell2,iCell)
+ ! enddo ! iVertexOnCell2
+ !enddo ! iVertexOnCell1
+
+ end subroutine homogenize_cell
+
+!-----------------------------------------------------------------------
+! time step
+!-----------------------------------------------------------------------
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
@@ -280,6 +584,11 @@ subroutine seaice_strain_tensor_variational(&
tanLatVertexRotatedOverRadius, &
solveStress)!{{{
+ use seaice_mesh_pool, only: &
+ nCells, &
+ verticesOnCell, &
+ nEdgesOnCell
+
type(MPAS_pool_type), pointer, intent(in) :: &
mesh !< Input:
@@ -293,7 +602,7 @@ subroutine seaice_strain_tensor_variational(&
vVelocity, & !< Input:
tanLatVertexRotatedOverRadius !< Input:
- real(kind=RKIND), dimension(:,:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:,:), contiguous, intent(in) :: &
basisGradientU, & !< Input:
basisGradientV !< Input:
@@ -307,59 +616,50 @@ subroutine seaice_strain_tensor_variational(&
iVertex, &
jVertex
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- verticesOnCell
-
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
+ real(kind=RKIND) :: &
+ strain11Tmp, &
+ strain22Tmp, &
+ strain12Tmp
! loop over cells
- !$omp parallel do default(shared) private(iCell, iGradientVertex, iBasisVertex, iVertex, jVertex)
+#ifdef MPAS_OPENMP_OFFLOAD
+!$omp target teams distribute parallel do
+#elif MPAS_OPENACC
+!$acc parallel loop gang worker
+#else
+!$omp parallel do default(shared) private(iGradientVertex, iBasisVertex, iVertex, jVertex, &
+!$omp& strain11Tmp, strain22Tmp, strain12Tmp)
+#endif
do iCell = 1, nCells
if (solveStress(iCell) == 1) then
- strain11(:,iCell) = 0.0_RKIND
- strain22(:,iCell) = 0.0_RKIND
- strain12(:,iCell) = 0.0_RKIND
-
! loop over velocity points surrounding cell - location of stress and derivative
do iGradientVertex = 1, nEdgesOnCell(iCell)
+ strain11Tmp = 0.0_RKIND
+ strain22Tmp = 0.0_RKIND
+ strain12Tmp = 0.0_RKIND
+
! loop over basis functions
do iBasisVertex = 1, nEdgesOnCell(iCell)
iVertex = verticesOnCell(iBasisVertex,iCell)
- strain11(iGradientVertex,iCell) = strain11(iGradientVertex,iCell) + &
- uVelocity(iVertex) * basisGradientU(iBasisVertex,iGradientVertex,iCell)
-
- strain22(iGradientVertex,iCell) = strain22(iGradientVertex,iCell) + &
- vVelocity(iVertex) * basisGradientV(iBasisVertex,iGradientVertex,iCell)
-
- strain12(iGradientVertex,iCell) = strain12(iGradientVertex,iCell) + 0.5_RKIND * (&
- uVelocity(iVertex) * basisGradientV(iBasisVertex,iGradientVertex,iCell) + &
- vVelocity(iVertex) * basisGradientU(iBasisVertex,iGradientVertex,iCell))
+ strain11Tmp = strain11Tmp + uVelocity(iVertex) * basisGradientU(iBasisVertex,iGradientVertex,iCell)
+ strain22Tmp = strain22Tmp + vVelocity(iVertex) * basisGradientV(iBasisVertex,iGradientVertex,iCell)
+ strain12Tmp = strain12Tmp + 0.5_RKIND * (&
+ uVelocity(iVertex) * basisGradientV(iBasisVertex,iGradientVertex,iCell) + &
+ vVelocity(iVertex) * basisGradientU(iBasisVertex,iGradientVertex,iCell))
enddo ! iVertexOnCell
! metric terms
jVertex = verticesOnCell(iGradientVertex,iCell)
- strain11(iGradientVertex,iCell) = strain11(iGradientVertex,iCell) - &
- vVelocity(jVertex) * tanLatVertexRotatedOverRadius(jVertex)
-
- strain12(iGradientVertex,iCell) = strain12(iGradientVertex,iCell) + &
- uVelocity(jVertex) * tanLatVertexRotatedOverRadius(jVertex) * 0.5_RKIND
+ strain11(iGradientVertex,iCell) = strain11Tmp - vVelocity(jVertex) * tanLatVertexRotatedOverRadius(jVertex)
+ strain12(iGradientVertex,iCell) = strain12Tmp + uVelocity(jVertex) * tanLatVertexRotatedOverRadius(jVertex) * 0.5_RKIND
+ strain22(iGradientVertex,iCell) = strain22Tmp
enddo ! jVertexOnCell
@@ -369,6 +669,99 @@ subroutine seaice_strain_tensor_variational(&
end subroutine seaice_strain_tensor_variational!}}}
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_average_strains_on_vertex
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 2013-2014
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_average_strains_on_vertex(&
+ areaCell, &
+ strain11, &
+ strain22, &
+ strain12)
+
+ use seaice_mesh_pool, only: &
+ nCells, &
+ nVerticesSolve, &
+ cellVerticesAtVertex, &
+ cellsOnVertex, &
+ vertexDegree
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ areaCell !< Input
+
+ real(kind=RKIND), dimension(:,:), intent(inout) :: &
+ strain11, & !< Input/Output:
+ strain22, & !< Input/Output:
+ strain12 !< Input/Output:
+
+ real(kind=RKIND) :: &
+ strain11avg, &
+ strain22avg, &
+ strain12avg, &
+ denominator
+
+ integer :: &
+ iVertex, &
+ iVertexDegree, &
+ iCell, &
+ iVertexOnCell
+
+ do iVertex = 1, nVerticesSolve
+
+ strain11avg = 0.0_RKIND
+ strain22avg = 0.0_RKIND
+ strain12avg = 0.0_RKIND
+ denominator = 0.0_RKIND
+
+ do iVertexDegree = 1, vertexDegree
+
+ iCell = cellsOnVertex(iVertexDegree,iVertex)
+
+ if (iCell <= nCells) then
+
+ iVertexOnCell = cellVerticesAtVertex(iVertexDegree,iVertex)
+
+ strain11avg = strain11avg + strain11(iVertexOnCell,iCell) * areaCell(iCell)
+ strain22avg = strain22avg + strain22(iVertexOnCell,iCell) * areaCell(iCell)
+ strain12avg = strain12avg + strain12(iVertexOnCell,iCell) * areaCell(iCell)
+ denominator = denominator + areaCell(iCell)
+
+ endif
+
+ enddo ! iVertexDegree
+
+ strain11avg = strain11avg / denominator
+ strain22avg = strain22avg / denominator
+ strain12avg = strain12avg / denominator
+
+ do iVertexDegree = 1, vertexDegree
+
+ iCell = cellsOnVertex(iVertexDegree,iVertex)
+
+ if (iCell <= nCells) then
+
+ iVertexOnCell = cellVerticesAtVertex(iVertexDegree,iVertex)
+
+ strain11(iVertexOnCell,iCell) = strain11avg
+ strain22(iVertexOnCell,iCell) = strain22avg
+ strain12(iVertexOnCell,iCell) = strain12avg
+
+ endif
+
+ enddo ! iCellOnVertex
+
+ enddo ! iVertex
+
+ end subroutine seaice_average_strains_on_vertex
+
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_stress_tensor_variational
@@ -392,25 +785,34 @@ subroutine seaice_stress_tensor_variational(&
icePressure, &
replacementPressure, &
solveStress, &
- dtElastic, &
- revisedEVP)!{{{
+ dtElastic)!{{{
use seaice_velocity_solver_constitutive_relation, only: &
+ constitutiveRelationType, &
+ EVP_CONSTITUTIVE_RELATION, &
+ REVISED_EVP_CONSTITUTIVE_RELATION, &
+ LINEAR_CONSTITUTIVE_RELATION, &
seaice_evp_constitutive_relation, &
- seaice_evp_constitutive_relation_revised
+ seaice_evp_constitutive_relation_revised, &
+ seaice_linear_constitutive_relation, &
+ eccentricitySquared, puny, dampingTimescale
+
+ use seaice_mesh_pool, only: &
+ nCells, &
+ nEdgesOnCell
type(MPAS_pool_type), pointer, intent(in) :: &
mesh !< Input:
- real(kind=RKIND), dimension(:,:), intent(inout) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(inout) :: &
stress11, & !< Input/Output:
stress22, & !< Input/Output:
stress12 !< Input/Output:
- real(kind=RKIND), dimension(:,:), intent(out) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(out) :: &
replacementPressure !< Output:
- real(kind=RKIND), dimension(:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
strain11, & !< Input:
strain22, & !< Input:
strain12 !< Input:
@@ -424,39 +826,75 @@ subroutine seaice_stress_tensor_variational(&
real(kind=RKIND), intent(in) :: &
dtElastic !< Input:
- logical, intent(in) :: &
- revisedEVP !< Input:
-
integer :: &
iCell, &
iVertexOnCell
- integer, pointer :: &
- nCells, &
- maxEdges
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
real(kind=RKIND), dimension(:), pointer :: &
areaCell
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "maxEdges", maxEdges)
+ real(kind=RKIND) :: &
+ strainDivergence, &
+ strainTension, &
+ strainShearing, &
+ stress1, &
+ stress2, &
+ Delta, &
+ pressureCoefficient, &
+ denominator
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
+ ! init variables
call MPAS_pool_get_array(mesh, "areaCell", areaCell)
- if (.not. revisedEVP) then
+ if (constitutiveRelationType == EVP_CONSTITUTIVE_RELATION) then
+
+ denominator = 1.0_RKIND + (0.5_RKIND * dtElastic) / dampingTimescale
- !$omp parallel do default(shared) private(iCell, iVertexOnCell)
+#ifdef MPAS_OPENMP_OFFLOAD
+!$omp target teams distribute parallel do
+#elif MPAS_OPENACC
+!$acc parallel loop gang worker
+#else
+!$omp parallel do default(shared) private(iVertexOnCell)
+#endif
do iCell = 1, nCells
replacementPressure(:,iCell) = 0.0_RKIND
if (solveStress(iCell) == 1) then
+#if defined(MPAS_OPENMP_OFFLOAD) || defined(MPAS_OPENACC)
+ ! inline call to seaice_evp_constitutive_relation for GPUs
+ do iVertexOnCell = 1, nEdgesOnCell(iCell)
+
+ ! convert from stress11 to stress1 etc
+ strainDivergence = strain11(iVertexOnCell,iCell) + strain22(iVertexOnCell,iCell)
+ strainTension = strain11(iVertexOnCell,iCell) - strain22(iVertexOnCell,iCell)
+ strainShearing = strain12(iVertexOnCell,iCell) * 2.0_RKIND
+
+ stress1 = stress11(iVertexOnCell,iCell) + stress22(iVertexOnCell,iCell)
+ stress2 = stress11(iVertexOnCell,iCell) - stress22(iVertexOnCell,iCell)
+
+ ! perform the constituitive relation
+ Delta = sqrt(strainDivergence*strainDivergence + &
+ (strainTension*strainTension + strainShearing*strainShearing) / eccentricitySquared)
+
+ pressureCoefficient = icePressure(iCell) / max(Delta,puny)
+ replacementPressure(iVertexOnCell,iCell) = pressureCoefficient * Delta
+
+ pressureCoefficient = (pressureCoefficient * dtElastic) / (2.0_RKIND * dampingTimescale)
+
+ stress1 = (stress1 + pressureCoefficient * (strainDivergence - Delta)) / denominator
+ stress2 = (stress2 + (pressureCoefficient / eccentricitySquared) * strainTension ) / denominator
+ stress12(iVertexOnCell,iCell) = (stress12(iVertexOnCell,iCell) &
+ + (pressureCoefficient / eccentricitysquared) * strainShearing * 0.5_RKIND) / denominator
+
+ ! convert back
+ stress11(iVertexOnCell,iCell) = 0.5_RKIND * (stress1 + stress2)
+ stress22(iVertexOnCell,iCell) = 0.5_RKIND * (stress1 - stress2)
+
+#else
+ !$omp simd
do iVertexOnCell = 1, nEdgesOnCell(iCell)
call seaice_evp_constitutive_relation(&
@@ -470,19 +908,23 @@ subroutine seaice_stress_tensor_variational(&
replacementPressure(iVertexOnCell,iCell), &
areaCell(iCell), &
dtElastic)
-
+#endif
enddo ! iVertexOnCell
endif ! solveStress
enddo ! iCell
- else
+ else if (constitutiveRelationType == REVISED_EVP_CONSTITUTIVE_RELATION) then
+#ifdef MPAS_OPENMP
+!$omp parallel do default(shared) private(iVertexOnCell)
+#endif
do iCell = 1, nCells
if (solveStress(iCell) == 1) then
+ !$omp simd
do iVertexOnCell = 1, nEdgesOnCell(iCell)
call seaice_evp_constitutive_relation_revised(&
@@ -502,10 +944,111 @@ subroutine seaice_stress_tensor_variational(&
enddo ! iCell
- endif
+ else if (constitutiveRelationType == LINEAR_CONSTITUTIVE_RELATION) then
+
+#ifdef MPAS_OPENMP
+!$omp parallel do default(shared) private(iCell, iVertexOnCell)
+#endif
+ do iCell = 1, nCells
+
+ if (solveStress(iCell) == 1) then
+
+ !$omp simd
+ do iVertexOnCell = 1, nEdgesOnCell(iCell)
+
+ call seaice_linear_constitutive_relation(&
+ stress11(iVertexOnCell,iCell), &
+ stress22(iVertexOnCell,iCell), &
+ stress12(iVertexOnCell,iCell), &
+ strain11(iVertexOnCell,iCell), &
+ strain22(iVertexOnCell,iCell), &
+ strain12(iVertexOnCell,iCell))
+
+ enddo ! iVertexOnCell
+
+ endif ! solveStress
+
+ enddo ! iCell
+
+ endif ! constitutiveRelationType
end subroutine seaice_stress_tensor_variational!}}}
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_stress_tensor_variational_linear
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 3rd October 2019
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_stress_tensor_variational_linear(&
+ mesh, &
+ stress11, &
+ stress22, &
+ stress12, &
+ strain11, &
+ strain22, &
+ strain12, &
+ solveStress)!{{{
+
+ use seaice_velocity_solver_constitutive_relation, only: &
+ seaice_linear_constitutive_relation
+
+ use seaice_mesh_pool, only: &
+ nCells, &
+ nEdgesOnCell
+
+ type(MPAS_pool_type), pointer, intent(in) :: &
+ mesh !< Input:
+
+ real(kind=RKIND), dimension(:,:), contiguous, intent(out) :: &
+ stress11, & !< Input/Output:
+ stress22, & !< Input/Output:
+ stress12 !< Input/Output:
+
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
+ strain11, & !< Input:
+ strain22, & !< Input:
+ strain12 !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ solveStress !< Input:
+
+ integer :: &
+ iCell, &
+ iVertexOnCell
+
+#ifdef MPAS_OPENMP
+!$omp parallel do default(shared) private(iCell, iVertexOnCell)
+#endif
+ do iCell = 1, nCells
+
+ if (solveStress(iCell) == 1) then
+
+ !$omp simd
+ do iVertexOnCell = 1, nEdgesOnCell(iCell)
+
+ call seaice_linear_constitutive_relation(&
+ stress11(iVertexOnCell,iCell), &
+ stress22(iVertexOnCell,iCell), &
+ stress12(iVertexOnCell,iCell), &
+ strain11(iVertexOnCell,iCell), &
+ strain22(iVertexOnCell,iCell), &
+ strain12(iVertexOnCell,iCell))
+
+ enddo ! iVertexOnCell
+
+ endif ! solveStress
+
+ enddo ! iCell
+
+ end subroutine seaice_stress_tensor_variational_linear!}}}
+
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_stress_divergence_variational
@@ -528,10 +1071,18 @@ subroutine seaice_stress_divergence_variational(&
basisIntegralsU, &
basisIntegralsV, &
basisIntegralsMetric, &
+ variationalDenominator, &
tanLatVertexRotatedOverRadius, &
cellVerticesAtVertex, &
solveVelocity)!{{{
+ use seaice_mesh_pool, only: &
+ nVerticesSolve, &
+ cellsOnVertex, &
+ nEdgesOnCell, &
+ areaTriangle, &
+ vertexDegree
+
type(MPAS_pool_type), pointer, intent(in) :: &
mesh !< Input:
@@ -539,18 +1090,19 @@ subroutine seaice_stress_divergence_variational(&
stressDivergenceU, & !< Output:
stressDivergenceV !< Output:
- real(kind=RKIND), dimension(:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:), contiguous, intent(in) :: &
stress11, & !< Input:
stress22, & !< Input:
stress12 !< Input:
- real(kind=RKIND), dimension(:,:,:), intent(in) :: &
+ real(kind=RKIND), dimension(:,:,:), contiguous, intent(in) :: &
basisIntegralsU, & !< Input:
basisIntegralsV, & !< Input:
basisIntegralsMetric !< Input:
real(kind=RKIND), dimension(:), intent(in) :: &
- tanLatVertexRotatedOverRadius !< Input:
+ tanLatVertexRotatedOverRadius, & !< Input:
+ variationalDenominator !< Input:
integer, dimension(:,:), intent(in) :: &
cellVerticesAtVertex !< Input:
@@ -559,6 +1111,8 @@ subroutine seaice_stress_divergence_variational(&
solveVelocity !< Input:
real(kind=RKIND) :: &
+ stressDivergenceUVertex, &
+ stressDivergenceVVertex, &
stressDivergenceUCell, &
stressDivergenceVCell
@@ -569,37 +1123,21 @@ subroutine seaice_stress_divergence_variational(&
iStressVertex, &
iVelocityVertex
- integer, pointer :: &
- nVertices, &
- vertexDegree
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- cellsOnVertex, &
- verticesOnCell
-
- real(kind=RKIND), dimension(:), pointer :: &
- areaTriangle
-
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
- call MPAS_pool_get_dimension(mesh, "vertexDegree", vertexDegree)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "cellsOnVertex", cellsOnVertex)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
- call MPAS_pool_get_array(mesh, "areaTriangle", areaTriangle)
-
! loop over velocity positions
- !$omp parallel do default(shared) private(iVertex, iSurroundingCell, iCell, iVelocityVertex, stressDivergenceUCell, stressDivergenceVCell, iStressVertex)
- do iVertex = 1, nVertices
+#ifdef MPAS_OPENMP_OFFLOAD
+!$omp target teams distribute parallel do
+#elif MPAS_OPENACC
+!$acc parallel loop gang worker
+#else
+!$omp parallel do default(shared) private(stressDivergenceUVertex, stressDivergenceVVertex, &
+!$omp& iSurroundingCell, iCell, iVelocityVertex, stressDivergenceUCell, stressDivergenceVCell, iStressVertex)
+#endif
+ do iVertex = 1, nVerticesSolve
if (solveVelocity(iVertex) == 1) then
- stressDivergenceU(iVertex) = 0.0_RKIND
- stressDivergenceV(iVertex) = 0.0_RKIND
+ stressDivergenceUVertex = 0.0_RKIND
+ stressDivergenceVVertex = 0.0_RKIND
! loop over surrounding cells
do iSurroundingCell = 1, vertexDegree
@@ -616,33 +1154,28 @@ subroutine seaice_stress_divergence_variational(&
! loop over the vertices of the surrounding cell
do iStressVertex = 1, nEdgesOnCell(iCell)
- ! normal terms
+ ! normal & metric terms
stressDivergenceUCell = stressDivergenceUCell - &
stress11(iStressVertex,iCell) * basisIntegralsU(iStressVertex,iVelocityVertex,iCell) - &
- stress12(iStressVertex,iCell) * basisIntegralsV(iStressVertex,iVelocityVertex,iCell)
-
- stressDivergenceVCell = stressDivergenceVCell - &
- stress22(iStressVertex,iCell) * basisIntegralsV(iStressVertex,iVelocityVertex,iCell) - &
- stress12(iStressVertex,iCell) * basisIntegralsU(iStressVertex,iVelocityVertex,iCell)
-
- ! metric terms
- stressDivergenceUCell = stressDivergenceUCell - &
+ stress12(iStressVertex,iCell) * basisIntegralsV(iStressVertex,iVelocityVertex,iCell) - &
stress12(iStressVertex,iCell) * basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell) * &
tanLatVertexRotatedOverRadius(iVertex)
- stressDivergenceVCell = stressDivergenceVCell + &
+ stressDivergenceVCell = stressDivergenceVCell - &
+ stress22(iStressVertex,iCell) * basisIntegralsV(iStressVertex,iVelocityVertex,iCell) - &
+ stress12(iStressVertex,iCell) * basisIntegralsU(iStressVertex,iVelocityVertex,iCell) + &
stress11(iStressVertex,iCell) * basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell) * &
tanLatVertexRotatedOverRadius(iVertex)
enddo ! iStressVertex
- stressDivergenceU(iVertex) = stressDivergenceU(iVertex) + stressDivergenceUCell
- stressDivergenceV(iVertex) = stressDivergenceV(iVertex) + stressDivergenceVCell
+ stressDivergenceUVertex = stressDivergenceUVertex + stressDivergenceUCell
+ stressDivergenceVVertex = stressDivergenceVVertex + stressDivergenceVCell
enddo ! iSurroundingCell
- stressDivergenceU(iVertex) = stressDivergenceU(iVertex) / areaTriangle(iVertex)
- stressDivergenceV(iVertex) = stressDivergenceV(iVertex) / areaTriangle(iVertex)
+ stressDivergenceU(iVertex) = stressDivergenceUVertex / variationalDenominator(iVertex)
+ stressDivergenceV(iVertex) = stressDivergenceVVertex / variationalDenominator(iVertex)
endif ! solveVelocity
@@ -667,22 +1200,19 @@ subroutine seaice_final_divergence_shear_variational(block)
use seaice_velocity_solver_constitutive_relation, only: &
eccentricitySquared
+ use seaice_mesh_pool, only: &
+ nCells, &
+ solveStress, &
+ nEdgesOnCell
+
type(block_type), intent(inout) :: &
block
type(MPAS_pool_type), pointer :: &
- meshPool, &
velocityVariationalPool, &
velocitySolverPool, &
ridgingPool
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell, &
- solveStress
-
real(kind=RKIND), dimension(:,:), pointer :: &
strain11, &
strain22, &
@@ -713,21 +1243,15 @@ subroutine seaice_final_divergence_shear_variational(block)
iCell, &
iVertexOnCell
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
call MPAS_pool_get_subpool(block % structs, "velocity_variational", velocityVariationalPool)
call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocitySolverPool)
- call MPAS_pool_get_dimension(meshPool, "nCells", nCells)
-
- call MPAS_pool_get_array(meshPool, "nEdgesOnCell", nEdgesOnCell)
-
call MPAS_pool_get_array(velocityVariationalPool, "strain11", strain11)
call MPAS_pool_get_array(velocityVariationalPool, "strain22", strain22)
call MPAS_pool_get_array(velocityVariationalPool, "strain12", strain12)
call MPAS_pool_get_array(velocitySolverPool, "divergence", divergence)
call MPAS_pool_get_array(velocitySolverPool, "shear", shear)
- call MPAS_pool_get_array(velocitySolverPool, "solveStress", solveStress)
allocate(DeltaAverage(nCells))
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_variational_shared.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_variational_shared.F
index 3a0e79a107..92165961ca 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_variational_shared.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver_variational_shared.F
@@ -40,37 +40,72 @@ module seaice_velocity_solver_variational_shared
!-----------------------------------------------------------------------
subroutine seaice_calc_local_coords(&
- mesh, &
xLocal, &
yLocal, &
- rotateCartesianGrid)!{{{
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
+ nCells, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell, &
+ rotateCartesianGrid, &
+ onASphere)!{{{
real(kind=RKIND), dimension(:,:), intent(out) :: &
xLocal, & !< Output:
yLocal !< Output:
- logical, intent(in) :: &
- rotateCartesianGrid !< Input:
+ integer, intent(in) :: &
+ nCells !< Input:
- logical, pointer :: &
- on_a_sphere
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
- call MPAS_pool_get_config(mesh, "on_a_sphere", on_a_sphere)
+ integer, dimension(:,:), intent(in) :: &
+ verticesOnCell !< Input:
- if (on_a_sphere) then
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ xVertex, & !< Input:
+ yVertex, & !< Input:
+ zVertex, & !< Input:
+ xCell, & !< Input:
+ yCell, & !< Input:
+ zCell !< Input:
+
+ logical, intent(in) :: &
+ rotateCartesianGrid, & !< Input:
+ onASphere !< Input:
+
+ if (onASphere) then
call calc_local_coords_spherical(&
- mesh, &
xLocal, &
yLocal, &
+ nCells, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell, &
rotateCartesianGrid)
else
call calc_local_coords_planar(&
- mesh, &
xLocal, &
- yLocal)
+ yLocal, &
+ nCells, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell)
endif
end subroutine seaice_calc_local_coords!}}}
@@ -88,45 +123,43 @@ end subroutine seaice_calc_local_coords!}}}
!-----------------------------------------------------------------------
subroutine calc_local_coords_planar(&
- mesh, &
xLocal, &
- yLocal)!{{{
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
+ yLocal, &
+ nCells, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell)!{{{
real(kind=RKIND), dimension(:,:), intent(out) :: &
xLocal, & !< Output:
yLocal !< Output:
- integer :: &
- iCell, &
- iVertex, &
- iVertexOnCell
-
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
+ integer, intent(in) :: &
+ nCells !< Input:
- integer, dimension(:,:), pointer :: &
- verticesOnCell
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
- real(kind=RKIND), dimension(:), pointer :: &
- xVertex, &
- yVertex, &
- xCell, &
- yCell
+ integer, dimension(:,:), intent(in) :: &
+ verticesOnCell !< Input:
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ xVertex, & !< Input:
+ yVertex, & !< Input:
+ zVertex, & !< Input:
+ xCell, & !< Input:
+ yCell, & !< Input:
+ zCell !< Input:
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
- call MPAS_pool_get_array(mesh, "xVertex", xVertex)
- call MPAS_pool_get_array(mesh, "yVertex", yVertex)
- call MPAS_pool_get_array(mesh, "xCell", xCell)
- call MPAS_pool_get_array(mesh, "yCell", yCell)
+ integer :: &
+ iCell, &
+ iVertex, &
+ iVertexOnCell
do iCell = 1, nCells
@@ -156,22 +189,44 @@ end subroutine calc_local_coords_planar!}}}
!-----------------------------------------------------------------------
subroutine calc_local_coords_spherical(&
- mesh, &
xLocal, &
yLocal, &
+ nCells, &
+ nEdgesOnCell, &
+ verticesOnCell, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ xCell, &
+ yCell, &
+ zCell, &
rotateCartesianGrid)!{{{
use seaice_mesh, only: &
seaice_project_3D_vector_onto_local_2D, &
seaice_grid_rotation_forward
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
real(kind=RKIND), dimension(:,:), intent(out) :: &
xLocal, & !< Output:
yLocal !< Output:
+ integer, intent(in) :: &
+ nCells !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
+
+ integer, dimension(:,:), intent(in) :: &
+ verticesOnCell !< Input:
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ xVertex, & !< Input:
+ yVertex, & !< Input:
+ zVertex, & !< Input:
+ xCell, & !< Input:
+ yCell, & !< Input:
+ zCell !< Input:
+
logical, intent(in) :: &
rotateCartesianGrid !< Input:
@@ -186,41 +241,18 @@ subroutine calc_local_coords_spherical(&
iVertex, &
iVertexOnCell
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- verticesOnCell
-
- real(kind=RKIND), dimension(:), pointer :: &
- xVertex, &
- yVertex, &
- zVertex, &
- xCell, &
- yCell, &
- zCell
-
real(kind=RKIND) :: &
xCellRotated, &
yCellRotated, &
zCellRotated
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
- call MPAS_pool_get_array(mesh, "xVertex", xVertex)
- call MPAS_pool_get_array(mesh, "yVertex", yVertex)
- call MPAS_pool_get_array(mesh, "zVertex", zVertex)
- call MPAS_pool_get_array(mesh, "xCell", xCell)
- call MPAS_pool_get_array(mesh, "yCell", yCell)
- call MPAS_pool_get_array(mesh, "zCell", zCell)
-
do iCell = 1, nCells
+ call seaice_grid_rotation_forward(&
+ xCellRotated, yCellRotated, zCellRotated, &
+ xCell(iCell), yCell(iCell), zCell(iCell), &
+ rotateCartesianGrid)
+
do iVertexOnCell = 1, nEdgesOnCell(iCell)
iVertex = verticesOnCell(iVertexOnCell, iCell)
@@ -230,11 +262,6 @@ subroutine calc_local_coords_spherical(&
xVertex(iVertex), yVertex(iVertex), zVertex(iVertex), &
rotateCartesianGrid)
- call seaice_grid_rotation_forward(&
- xCellRotated, yCellRotated, zCellRotated, &
- xCell(iCell), yCell(iCell), zCell(iCell), &
- rotateCartesianGrid)
-
call seaice_project_3D_vector_onto_local_2D(&
normalVector2D, &
normalVector3D, &
@@ -264,51 +291,45 @@ end subroutine calc_local_coords_spherical!}}}
!-----------------------------------------------------------------------
subroutine seaice_calc_variational_metric_terms(&
- mesh, &
tanLatVertexRotatedOverRadius, &
+ nVertices, &
+ xVertex, &
+ yVertex, &
+ zVertex, &
+ sphereRadius, &
rotateCartesianGrid, &
includeMetricTerms)
use seaice_mesh, only: &
seaice_grid_rotation_forward
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
real(kind=RKIND), dimension(:), intent(out) :: &
tanLatVertexRotatedOverRadius !< Output:
+ integer, intent(in) :: &
+ nVertices !< Input:
+
+ real(kind=RKIND), dimension(:), pointer :: &
+ xVertex, & !< Input:
+ yVertex, & !< Input:
+ zVertex !< Input:
+
+ real(kind=RKIND), pointer :: &
+ sphereRadius !< Input:
+
logical, intent(in) :: &
rotateCartesianGrid, & !< Input:
includeMetricTerms !< Input:
- integer, pointer :: &
- nVertices
-
integer :: &
iVertex
- real(kind=RKIND), dimension(:), pointer :: &
- xVertex, &
- yVertex, &
- zVertex
-
- real(kind=RKIND), pointer :: &
- sphere_radius
-
real(kind=RKIND) :: &
xVertexRotated, &
yVertexRotated, &
zVertexRotated, &
latVertexRotated
- call MPAS_pool_get_dimension(mesh, "nVertices", nVertices)
- call MPAS_pool_get_config(mesh, "sphere_radius", sphere_radius)
-
- call MPAS_pool_get_array(mesh, "xVertex", xVertex)
- call MPAS_pool_get_array(mesh, "yVertex", yVertex)
- call MPAS_pool_get_array(mesh, "zVertex", zVertex)
-
if (includeMetricTerms) then
do iVertex = 1, nVertices
@@ -318,9 +339,9 @@ subroutine seaice_calc_variational_metric_terms(&
xVertex(iVertex), yVertex(iVertex), zVertex(iVertex), &
rotateCartesianGrid)
- latVertexRotated = asin(zVertexRotated / sphere_radius)
+ latVertexRotated = asin(zVertexRotated / sphereRadius)
- tanLatVertexRotatedOverRadius(iVertex) = tan(latVertexRotated) / sphere_radius
+ tanLatVertexRotatedOverRadius(iVertex) = tan(latVertexRotated) / sphereRadius
enddo ! iVertex
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_wachspress.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_wachspress.F
index 0e63e9c991..1e46eea0bd 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_wachspress.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver_wachspress.F
@@ -44,33 +44,43 @@ module seaice_velocity_solver_wachspress
!-----------------------------------------------------------------------
subroutine seaice_init_velocity_solver_wachspress(&
- mesh, &
- velocity_variational, &
- boundary, &
+ nCells, &
+ maxEdges, &
+ nEdgesOnCell, &
+ xLocal, &
+ yLocal, &
rotateCartesianGrid, &
includeMetricTerms, &
+ onASphere, &
integrationType, &
- integrationOrder)!{{{
+ integrationOrder, &
+ sphereRadius, &
+ basisGradientU, &
+ basisGradientV, &
+ basisIntegralsU, &
+ basisIntegralsV, &
+ basisIntegralsMetric)!{{{
use mpas_timer
- use seaice_mesh, only: &
- seaice_cell_vertices_at_vertex
-
use seaice_velocity_solver_variational_shared, only: &
- seaice_calc_local_coords, &
- seaice_calc_variational_metric_terms
+ seaice_calc_local_coords
+
+ integer, intent(in) :: &
+ nCells, & !< Input:
+ maxEdges !< Input:
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
- type(MPAS_pool_type), pointer :: &
- velocity_variational, & !< Input/Output:
- boundary !< Input/Output:
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ xLocal, & !< Input:
+ yLocal !< Input:
logical, intent(in) :: &
rotateCartesianGrid, & !< Input:
- includeMetricTerms !< Input:
+ includeMetricTerms, & !< Input:
+ onASphere !< Input:
character(len=strKIND), intent(in) :: &
integrationType !< Input:
@@ -78,26 +88,15 @@ subroutine seaice_init_velocity_solver_wachspress(&
integer, intent(in) :: &
integrationOrder !< Input:
- integer :: &
- iCell, &
- iVertex
-
- integer, pointer :: &
- nCells, &
- maxEdges, i1, i2
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- cellVerticesAtVertex
-
- real(kind=RKIND), dimension(:), pointer :: &
- tanLatVertexRotatedOverRadius
+ real(kind=RKIND), intent(in) :: &
+ sphereRadius !< Input:
- real(kind=RKIND), dimension(:,:), allocatable :: &
- xLocal, &
- yLocal
+ real(kind=RKIND), dimension(:,:,:), intent(out) :: &
+ basisGradientU, & !< Output:
+ basisGradientV, & !< Output:
+ basisIntegralsU, & !< Output:
+ basisIntegralsV, & !< Output:
+ basisIntegralsMetric !< Output:
real(kind=RKIND), dimension(:,:), allocatable :: &
wachspressA, &
@@ -106,69 +105,44 @@ subroutine seaice_init_velocity_solver_wachspress(&
real(kind=RKIND), dimension(:,:,:), allocatable :: &
wachspressKappa
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- basisGradientU, &
- basisGradientV, &
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric
-
call mpas_timer_start("Velocity solver Wachpress init")
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "maxEdges", maxEdges)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
-
- call MPAS_pool_get_array(velocity_variational, "cellVerticesAtVertex", cellVerticesAtVertex)
- call MPAS_pool_get_array(velocity_variational, "tanLatVertexRotatedOverRadius", tanLatVertexRotatedOverRadius)
- call MPAS_pool_get_array(velocity_variational, "basisGradientU", basisGradientU)
- call MPAS_pool_get_array(velocity_variational, "basisGradientV", basisGradientV)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsU", basisIntegralsU)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsV", basisIntegralsV)
- call MPAS_pool_get_array(velocity_variational, "basisIntegralsMetric", basisIntegralsMetric)
-
- allocate(xLocal(maxEdges,nCells))
- allocate(yLocal(maxEdges,nCells))
allocate(wachspressKappa(maxEdges,maxEdges,nCells))
allocate(wachspressA(maxEdges,nCells))
allocate(wachspressB(maxEdges,nCells))
- call seaice_calc_local_coords(&
- mesh, &
- xLocal, &
- yLocal, &
- rotateCartesianGrid)
-
- call seaice_calc_variational_metric_terms(&
- mesh, &
- tanLatVertexRotatedOverRadius, &
- rotateCartesianGrid, &
- includeMetricTerms)
-
+ call mpas_timer_start("wachpress calc_coefficients")
call calc_wachspress_coefficients(&
- mesh, &
wachspressKappa, &
wachspressA, &
wachspressB, &
+ nCells, &
+ nEdgesOnCell, &
xLocal, &
yLocal)
+ call mpas_timer_stop("wachpress calc_coefficients")
+ call mpas_timer_start("wachpress calc_derivatives")
call calculate_wachspress_derivatives(&
- mesh, &
basisGradientU, &
basisGradientV, &
+ nCells, &
+ maxEdges, &
+ nEdgesOnCell, &
xLocal, &
yLocal, &
wachspressA, &
wachspressB, &
wachspressKappa)
+ call mpas_timer_stop("wachpress calc_derivatives")
+ call mpas_timer_start("wachpress integrate")
call integrate_wachspress(&
- mesh, &
basisIntegralsU, &
basisIntegralsV, &
basisIntegralsMetric, &
+ nCells, &
+ nEdgesOnCell, &
xLocal, &
yLocal, &
wachspressA, &
@@ -176,20 +150,375 @@ subroutine seaice_init_velocity_solver_wachspress(&
wachspressKappa, &
integrationType, &
integrationOrder)
+ call mpas_timer_stop("wachpress integrate")
+
+ deallocate(wachspressKappa)
+ deallocate(wachspressA)
+ deallocate(wachspressB)
+
+ call mpas_timer_stop("Velocity solver Wachpress init")
+
+ end subroutine seaice_init_velocity_solver_wachspress!}}}
+
+!-----------------------------------------------------------------------
+! Integration
+!-----------------------------------------------------------------------
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! integrate_wachspress
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 2013-2014
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine integrate_wachspress(&
+ basisIntegralsU, &
+ basisIntegralsV, &
+ basisIntegralsMetric, &
+ nCells, &
+ nEdgesOnCell, &
+ xLocal, &
+ yLocal, &
+ wachspressA, &
+ wachspressB, &
+ wachspressKappa, &
+ integrationType, &
+ integrationOrder)!{{{
+
+ ! basisIntegralsUV (iStressVertex,iVelocityVertex,iCell)
+ ! iCell : cell integrals are performed on
+ ! iStressVertex : vertex number of Wachspress function
+ ! iVelocityVertex : vertex number of Wachspress derivative function
+ ! Sij
+
+ real(kind=RKIND), dimension(:,:,:), intent(out) :: &
+ basisIntegralsU, & !< Output:
+ basisIntegralsV, & !< Output:
+ basisIntegralsMetric !< Output:
+
+ integer, intent(in) :: &
+ nCells !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
+
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ xLocal, & !< Input:
+ yLocal, & !< Input:
+ wachspressA, & !< Input:
+ wachspressB !< Input:
+
+ real(kind=RKIND), dimension(:,:,:), intent(in) :: &
+ wachspressKappa !< Input:
+
+ character(len=strKIND), intent(in) :: &
+ integrationType !< Input:
+
+ integer, intent(in) :: &
+ integrationOrder !< Input:
+
+ integer :: &
+ iCell, &
+ iStressVertex, &
+ iVelocityVertex
+
+ integer :: &
+ nIntegrationPoints
+
+ real(kind=RKIND), dimension(:), allocatable :: &
+ integrationU, &
+ integrationV, &
+ integrationWeights
+
+ real(kind=RKIND) :: &
+ normalizationFactor
+
+ ! Quadrature rules
+ call get_integration_factors(&
+ integrationType, &
+ integrationOrder, &
+ nIntegrationPoints, &
+ integrationU, &
+ integrationV, &
+ integrationWeights, &
+ normalizationFactor)
+
+ !$omp parallel do default(shared) private(iStressVertex, iVelocityVertex)
+ do iCell = 1, nCells
+
+ do iVelocityVertex = 1, nEdgesOnCell(iCell)
+
+ do iStressVertex = 1, nEdgesOnCell(iCell)
+
+ basisIntegralsU(iStressVertex,iVelocityVertex,iCell) = 0.0_RKIND
+ basisIntegralsV(iStressVertex,iVelocityVertex,iCell) = 0.0_RKIND
+ basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell) = 0.0_RKIND
+
+ call integrate_wachspress_polygon(&
+ basisIntegralsU(iStressVertex,iVelocityVertex,iCell), &
+ basisIntegralsV(iStressVertex,iVelocityVertex,iCell), &
+ basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell), &
+ nEdgesOnCell(iCell), &
+ iStressVertex, &
+ iVelocityVertex, &
+ xLocal(:,iCell), &
+ yLocal(:,iCell), &
+ wachspressA(:,iCell), &
+ wachspressB(:,iCell), &
+ wachspressKappa(:,:,iCell), &
+ nIntegrationPoints, &
+ integrationU, &
+ integrationV, &
+ integrationWeights, &
+ normalizationFactor)
+
+ enddo ! jVertex
+
+ enddo ! iVertex
+
+ enddo ! iCell
+
+ deallocate(integrationU)
+ deallocate(integrationV)
+ deallocate(integrationWeights)
+
+ end subroutine integrate_wachspress!}}}
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! integrate_wachspress_polygon
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 2013-2014
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine integrate_wachspress_polygon(&
+ basisIntegralsU, &
+ basisIntegralsV, &
+ basisIntegralsMetric, &
+ nEdgesOnCell, &
+ iStressVertex, &
+ iVelocityVertex, &
+ xLocal, &
+ yLocal, &
+ wachspressA, &
+ wachspressB, &
+ wachspressKappa, &
+ nIntegrationPoints, &
+ integrationU, &
+ integrationV, &
+ integrationWeights, &
+ normalizationFactor)!{{{
+
+ use seaice_velocity_solver_variational_shared, only: &
+ seaice_wrapped_index
+
+ real(kind=RKIND), intent(inout) :: &
+ basisIntegralsU, & !< Input/Output:
+ basisIntegralsV, & !< Input/Output:
+ basisIntegralsMetric !< Input/Output:
+
+ integer, intent(in) :: &
+ nEdgesOnCell, & !< Input:
+ iStressVertex, & !< Input:
+ iVelocityVertex !< Input:
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ xLocal, & !< Input:
+ yLocal !< Input:
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ wachspressA, & !< Input:
+ wachspressB !< Input:
+
+ real(kind=RKIND), dimension(:,:), intent(in) :: &
+ wachspressKappa !< Input:
+
+ integer, intent(in) :: &
+ nIntegrationPoints !< Input:
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ integrationU, & !< Input:
+ integrationV, & !< Input:
+ integrationWeights !< Input:
+
+ real(kind=RKIND), intent(in) :: &
+ normalizationFactor !< Input:
+
+ integer, dimension(nEdgesOnCell) :: &
+ nEdgesOnCellSubset
+
+ integer, dimension(nEdgesOnCell,nEdgesOnCell) :: &
+ vertexIndexSubset
+
+ real(kind=RKIND) :: &
+ basisIntegralsSubTriangleTmp, &
+ basisIntegralsUSubTriangle, &
+ basisIntegralsVSubTriangle, &
+ basisIntegralsMetricSubTriangle
+
+ real(kind=RKIND), dimension(nIntegrationPoints) :: &
+ x, &
+ y, &
+ stressBasisFunction, &
+ velocityBasisFunction, &
+ velocityBasisDerivativeU, &
+ velocityBasisDerivativeV
+
+ real(kind=RKIND), dimension(2,2) :: &
+ mapping
+
+ real(kind=RKIND), dimension(nEdgesOnCell) :: &
+ jacobian
+
+ integer :: &
+ iIntegrationPoint, &
+ iSubTriangle, &
+ i1, &
+ i2
+
+ call wachspress_indexes(&
+ nEdgesOnCell, &
+ nEdgesOnCellSubset, &
+ vertexIndexSubset)
+
+ do iSubTriangle = 1, nEdgesOnCell
+
+ i1 = iSubTriangle
+ i2 = seaice_wrapped_index(iSubTriangle + 1, nEdgesOnCell)
+
+ call get_triangle_mapping(&
+ mapping, &
+ jacobian(iSubTriangle), &
+ 1.0_RKIND, 0.0_RKIND, &
+ 0.0_RKIND, 1.0_RKIND, &
+ xLocal(i1), yLocal(i1), &
+ xLocal(i2), yLocal(i2))
+
+ !in-lined use_triangle_mapping
+ do iIntegrationPoint = 1, nIntegrationPoints
+
+ x(iIntegrationPoint) = mapping(1,1) * integrationU(iIntegrationPoint) + &
+ mapping(1,2) * integrationV(iIntegrationPoint)
+ y(iIntegrationPoint) = mapping(2,1) * integrationU(iIntegrationPoint) + &
+ mapping(2,2) * integrationV(iIntegrationPoint)
+
+ enddo ! iIntegrationPoint
+
+ call wachspress_basis_function(&
+ nEdgesOnCell, iStressVertex, x, y, &
+ wachspressKappa, wachspressA, wachspressB, &
+ nEdgesOnCellSubset, vertexIndexSubset, &
+ stressBasisFunction)
+
+ call wachspress_basis_function(&
+ nEdgesOnCell, iVelocityVertex, x, y, &
+ wachspressKappa, wachspressA, wachspressB, &
+ nEdgesOnCellSubset, vertexIndexSubset, &
+ velocityBasisFunction)
+
+ call wachspress_basis_derivative(&
+ nEdgesOnCell, iVelocityVertex, x, y, &
+ wachspressKappa, wachspressA, wachspressB, &
+ nEdgesOnCellSubset, vertexIndexSubset, &
+ velocityBasisDerivativeU, &
+ velocityBasisDerivativeV)
+
+ basisIntegralsUSubTriangle = 0.0_RKIND
+ basisIntegralsVSubTriangle = 0.0_RKIND
+ basisIntegralsMetricSubTriangle = 0.0_RKIND
+
+ do iIntegrationPoint = 1, nIntegrationPoints
+
+ basisIntegralsSubTriangleTmp = &
+ jacobian(iSubTriangle) * &
+ integrationWeights(iIntegrationPoint) * &
+ stressBasisFunction(iIntegrationPoint)
+
+ basisIntegralsUSubTriangle = basisIntegralsUSubTriangle + &
+ basisIntegralsSubTriangleTmp * &
+ velocityBasisDerivativeU(iIntegrationPoint)
+
+ basisIntegralsVSubTriangle = basisIntegralsVSubTriangle + &
+ basisIntegralsSubTriangleTmp * &
+ velocityBasisDerivativeV(iIntegrationPoint)
+
+ basisIntegralsMetricSubTriangle = basisIntegralsMetricSubTriangle + &
+ basisIntegralsSubTriangleTmp * &
+ velocityBasisFunction(iIntegrationPoint)
+
+ enddo ! iIntegrationPoint
+
+ basisIntegralsU = basisIntegralsU + basisIntegralsUSubTriangle / normalizationFactor
+ basisIntegralsV = basisIntegralsV + basisIntegralsVSubTriangle / normalizationFactor
+ basisIntegralsMetric = basisIntegralsMetric + basisIntegralsMetricSubTriangle / normalizationFactor
+
+ enddo ! iSubTriangle
+
+ end subroutine integrate_wachspress_polygon!}}}
+
+!-----------------------------------------------------------------------
+! Remapping
+!-----------------------------------------------------------------------
+
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! get_triangle_mapping
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 2013-2014
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine get_triangle_mapping(&
+ mapping, &
+ jacobian, &
+ x1, y1, &
+ x2, y2, &
+ u1, v1, &
+ u2, v2)!{{{
+
+ real(kind=RKIND), dimension(2,2), intent(out) :: &
+ mapping !< Output:
+
+ real(kind=RKIND), intent(out) :: &
+ jacobian !< Output:
+
+ real(kind=RKIND), intent(in) :: &
+ x1, & !< Input:
+ y1, & !< Input:
+ x2, & !< Input:
+ y2, & !< Input:
+ u1, & !< Input:
+ v1, & !< Input:
+ u2, & !< Input:
+ v2 !< Input:
+
+ mapping(1,1) = (u2*y1 - u1*y2) / (x2*y1 - x1*y2)
+ mapping(1,2) = (u1*x2 - u2*x1) / (y1*x2 - y2*x1)
- call seaice_cell_vertices_at_vertex(&
- mesh, &
- cellVerticesAtVertex)
+ mapping(2,1) = (v2*y1 - v1*y2) / (x2*y1 - x1*y2)
+ mapping(2,2) = (v1*x2 - v2*x1) / (y1*x2 - y2*x1)
- deallocate(xLocal)
- deallocate(yLocal)
- deallocate(wachspressKappa)
- deallocate(wachspressA)
- deallocate(wachspressB)
+ jacobian = mapping(1,1) * mapping(2,2) - mapping(1,2) * mapping(2,1)
- call mpas_timer_stop("Velocity solver Wachpress init")
+ end subroutine get_triangle_mapping!}}}
- end subroutine seaice_init_velocity_solver_wachspress!}}}
+!-----------------------------------------------------------------------
+! Wachspress function
+!-----------------------------------------------------------------------
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
@@ -204,16 +533,14 @@ end subroutine seaice_init_velocity_solver_wachspress!}}}
!-----------------------------------------------------------------------
subroutine calc_wachspress_coefficients(&
- mesh, &
wachspressKappa, &
wachspressA, &
wachspressB, &
+ nCells, &
+ nEdgesOnCell, &
xLocal, &
yLocal)!{{{
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
real(kind=RKIND), dimension(:,:,:), intent(out) :: &
wachspressKappa !< Output:
@@ -221,6 +548,12 @@ subroutine calc_wachspress_coefficients(&
wachspressA, & !< Output:
wachspressB !< Output:
+ integer, intent(in) :: &
+ nCells !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
+
real(kind=RKIND), dimension(:,:), intent(in) :: &
xLocal, & !< Input:
yLocal !< Input:
@@ -233,17 +566,6 @@ subroutine calc_wachspress_coefficients(&
i2, &
jVertex
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
-
! loop over cells
do iCell = 1, nCells
@@ -312,13 +634,13 @@ subroutine wachspress_indexes(&
seaice_wrapped_index
integer, intent(in) :: &
- nEdgesOnCell
+ nEdgesOnCell !< Input:
integer, dimension(:), intent(out) :: &
- nEdgesOnCellSubset
+ nEdgesOnCellSubset !< Output:
integer, dimension(:,:), intent(out) :: &
- vertexIndexSubset
+ vertexIndexSubset !< Output:
integer :: &
jVertex, &
@@ -388,28 +710,24 @@ subroutine wachspress_basis_function(&
wachspressB !< Input:
integer, dimension(:), intent(in) :: &
- nEdgesOnCellSubset
+ nEdgesOnCellSubset !< Input:
integer, dimension(:,:), intent(in) :: &
- vertexIndexSubset
+ vertexIndexSubset !< Input:
real(kind=RKIND), dimension(:), intent(out) :: &
wachpress !< Output:
- real(kind=RKIND), dimension(:,:), allocatable :: &
+ real(kind=RKIND), dimension(size(x),nEdgesOnCell) :: &
numerator
- real(kind=RKIND), dimension(:), allocatable :: &
+ real(kind=RKIND), dimension(size(x)) :: &
denominator, &
edgeEquation
integer :: &
jVertex
- allocate(denominator(size(x)))
- allocate(numerator(size(x),nEdgesOnCell))
- allocate(edgeEquation(size(x)))
-
! sum over numerators to get denominator
denominator(:) = 0.0_RKIND
@@ -428,10 +746,6 @@ subroutine wachspress_basis_function(&
wachpress(:) = numerator(:,iVertex) / denominator(:)
- deallocate(denominator)
- deallocate(numerator)
- deallocate(edgeEquation)
-
end subroutine wachspress_basis_function!}}}
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -475,39 +789,33 @@ subroutine wachspress_basis_derivative(&
wachspressB !< Input:
integer, dimension(:), intent(in) :: &
- nEdgesOnCellSubset
+ nEdgesOnCellSubset !< Input:
integer, dimension(:,:), intent(in) :: &
- vertexIndexSubset
+ vertexIndexSubset !< Input:
real(kind=RKIND), dimension(:), intent(out) :: &
wachspressU, & !< Output:
wachspressV !< Output:
- real(kind=RKIND), dimension(:,:,:), allocatable :: &
+ real(kind=RKIND), dimension(size(x),2,nEdgesOnCell) :: &
derivative
- real(kind=RKIND), dimension(:,:), allocatable :: &
- numerator, &
+ real(kind=RKIND), dimension(size(x),nEdgesOnCell) :: &
+ numerator
+
+ real(kind=RKIND), dimension(size(x),2) :: &
sum_of_derivatives, &
sum_of_products, &
product
- real(kind=RKIND), dimension(:), allocatable :: &
+ real(kind=RKIND), dimension(size(x)) :: &
denominator, &
edgeEquation
integer :: &
jVertex
- allocate(denominator(size(x)))
- allocate(sum_of_derivatives(size(x),2))
- allocate(numerator(size(x),nEdgesOnCell))
- allocate(derivative(size(x),2,nEdgesOnCell))
- allocate(sum_of_products(size(x),2))
- allocate(product(size(x),2))
- allocate(edgeEquation(size(x)))
-
! sum over numerators to get denominator
denominator(:) = 0.0_RKIND
sum_of_derivatives(:,:) = 0.0_RKIND
@@ -539,14 +847,6 @@ subroutine wachspress_basis_derivative(&
wachspressV(:) = derivative(:,2,iVertex) / denominator(:) - &
(numerator(:,iVertex) / denominator(:)**2) * sum_of_derivatives(:,2)
- deallocate(denominator)
- deallocate(sum_of_derivatives)
- deallocate(numerator)
- deallocate(derivative)
- deallocate(sum_of_products)
- deallocate(product)
- deallocate(edgeEquation)
-
end subroutine wachspress_basis_derivative!}}}
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@@ -592,10 +892,10 @@ subroutine wachspress_numerator(&
wachspressB !< Input:
integer, dimension(:), intent(in) :: &
- nEdgesOnCellSubset
+ nEdgesOnCellSubset !< Input:
integer, dimension(:,:), intent(in) :: &
- vertexIndexSubset
+ vertexIndexSubset !< Input:
real(kind=RKIND), dimension(:), intent(inout) :: &
edgeEquation
@@ -669,20 +969,20 @@ subroutine wachspress_numerator_derivative(&
wachspressB !< Input:
integer, dimension(:), intent(in) :: &
- nEdgesOnCellSubset
+ nEdgesOnCellSubset !< Input:
integer, dimension(:,:), intent(in) :: &
- vertexIndexSubset
+ vertexIndexSubset !< Input:
real(kind=RKIND), dimension(:,:), intent(out) :: &
derivative !< Output:
real(kind=RKIND), dimension(:,:), intent(inout) :: &
- sum_of_products, &
- product
+ sum_of_products, & !< Input/Output:
+ product !< Input/Output:
real(kind=RKIND), dimension(:), intent(inout) :: &
- edgeEquation
+ edgeEquation !< Input/Output:
integer :: &
kVertex, &
@@ -781,17 +1081,17 @@ end subroutine wachspress_edge_equation!}}}
!-----------------------------------------------------------------------
subroutine calculate_wachspress_derivatives(&
- mesh, &
basisGradientU, &
basisGradientV, &
+ nCells, &
+ maxEdges, &
+ nEdgesOnCell, &
xLocal, &
yLocal, &
wachspressA, &
wachspressB, &
wachspressKappa)!{{{
- use mpas_timer
-
use seaice_velocity_solver_variational_shared, only: &
seaice_wrapped_index
@@ -800,13 +1100,17 @@ subroutine calculate_wachspress_derivatives(&
! iVertexOnCell : The vertex basis function the gradient is calculated from
! jVertexOnCell : The vertex location the gradients are calculated at
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
real(kind=RKIND), dimension(:,:,:), intent(out) :: &
basisGradientU, & !< Output:
basisGradientV !< Output:
+ integer, intent(in) :: &
+ nCells, & !< Input:
+ maxEdges !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ nEdgesOnCell !< Input:
+
real(kind=RKIND), dimension(:,:), intent(in) :: &
wachspressA, & !< Input:
wachspressB, & !< Input:
@@ -821,16 +1125,6 @@ subroutine calculate_wachspress_derivatives(&
iBasisVertex, &
iGradientVertex
- integer, pointer :: &
- nCells, &
- maxEdges
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer, dimension(:,:), pointer :: &
- verticesOnCell
-
integer, dimension(:), allocatable :: &
nEdgesOnCellSubset
@@ -840,13 +1134,6 @@ subroutine calculate_wachspress_derivatives(&
real(kind=RKIND), dimension(:), allocatable :: &
x, y, derivativeU, derivativeV
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_dimension(mesh, "maxEdges", maxEdges)
-
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
- call MPAS_pool_get_array(mesh, "verticesOnCell", verticesOnCell)
-
allocate(x(maxEdges))
allocate(y(maxEdges))
@@ -870,264 +1157,57 @@ subroutine calculate_wachspress_derivatives(&
x(iGradientVertex) = xLocal(iGradientVertex,iCell)
y(iGradientVertex) = yLocal(iGradientVertex,iCell)
- enddo ! iGradientVertex
-
- ! loop over vertices - basis function
- do iBasisVertex = 1, nEdgesOnCell(iCell)
-
- call wachspress_basis_derivative(&
- nEdgesOnCell(iCell), &
- iBasisVertex, &
- x(1:nEdgesOnCell(iCell)), &
- y(1:nEdgesOnCell(iCell)), &
- wachspressKappa(:,:,iCell), &
- wachspressA(:,iCell), &
- wachspressB(:,iCell), &
- nEdgesOnCellSubset(1:nEdgesOnCell(iCell)), &
- vertexIndexSubset(1:nEdgesOnCell(iCell),1:nEdgesOnCell(iCell)), &
- derivativeU(1:nEdgesOnCell(iCell)), &
- derivativeV(1:nEdgesOnCell(iCell)))
-
- basisGradientU(iBasisVertex,:,iCell) = 0.0_RKIND
- basisGradientV(iBasisVertex,:,iCell) = 0.0_RKIND
-
- iGradientVertex = iBasisVertex
- basisGradientU(iBasisVertex,iGradientVertex,iCell) = derivativeU(iGradientVertex)
- basisGradientV(iBasisVertex,iGradientVertex,iCell) = derivativeV(iGradientVertex)
-
- iGradientVertex = seaice_wrapped_index(iBasisVertex - 1, nEdgesOnCell(iCell))
- basisGradientU(iBasisVertex,iGradientVertex,iCell) = derivativeU(iGradientVertex)
- basisGradientV(iBasisVertex,iGradientVertex,iCell) = derivativeV(iGradientVertex)
-
- iGradientVertex = seaice_wrapped_index(iBasisVertex + 1, nEdgesOnCell(iCell))
- basisGradientU(iBasisVertex,iGradientVertex,iCell) = derivativeU(iGradientVertex)
- basisGradientV(iBasisVertex,iGradientVertex,iCell) = derivativeV(iGradientVertex)
-
- enddo ! iBasisVertex
-
- enddo ! iCell
-
- deallocate(nEdgesOnCellSubset)
- deallocate(vertexIndexSubset)
-
- deallocate(x)
- deallocate(y)
-
- deallocate(derivativeU)
- deallocate(derivativeV)
-
- end subroutine calculate_wachspress_derivatives!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! get_triangle_mapping
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine get_triangle_mapping(&
- mapping, &
- jacobian, &
- x1, y1, &
- x2, y2, &
- u1, v1, &
- u2, v2)!{{{
-
- real(kind=RKIND), dimension(2,2), intent(out) :: &
- mapping !< Output:
-
- real(kind=RKIND), intent(out) :: &
- jacobian !< Output:
-
- real(kind=RKIND), intent(in) :: &
- x1, & !< Input:
- y1, & !< Input:
- x2, & !< Input:
- y2, & !< Input:
- u1, & !< Input:
- v1, & !< Input:
- u2, & !< Input:
- v2 !< Input:
-
- mapping(1,1) = (u2*y1 - u1*y2) / (x2*y1 - x1*y2)
- mapping(1,2) = (u1*x2 - u2*x1) / (y1*x2 - y2*x1)
-
- mapping(2,1) = (v2*y1 - v1*y2) / (x2*y1 - x1*y2)
- mapping(2,2) = (v1*x2 - v2*x1) / (y1*x2 - y2*x1)
-
- jacobian = mapping(1,1) * mapping(2,2) - mapping(1,2) * mapping(2,1)
-
- end subroutine get_triangle_mapping!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! use_triangle_mapping
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine use_triangle_mapping(&
- u, v, &
- x, y, &
- mapping)!{{{
-
- real(kind=RKIND), intent(out) :: &
- u, v !< Output:
-
- real(kind=RKIND), intent(in) :: &
- x, y !< Input:
-
- real(kind=RKIND), dimension(2,2), intent(in) :: &
- mapping !< Input:
-
- u = mapping(1,1) * x + mapping(1,2) * y
- v = mapping(2,1) * x + mapping(2,2) * y
-
- end subroutine use_triangle_mapping!}}}
-
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! integrate_wachspress
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine integrate_wachspress(&
- mesh, &
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric, &
- xLocal, &
- yLocal, &
- wachspressA, &
- wachspressB, &
- wachspressKappa, &
- integrationType, &
- integrationOrder)!{{{
-
- use mpas_timer
-
- ! basisIntegralsUV (iStressVertex,iVelocityVertex,iCell)
- ! iCell : cell integrals are performed on
- ! iStressVertex : vertex number of Wachspress function
- ! iVelocityVertex : vertex number of Wachspress derivative function
- ! Sij
-
- type(MPAS_pool_type), pointer, intent(in) :: &
- mesh !< Input:
-
- real(kind=RKIND), dimension(:,:,:), intent(out) :: &
- basisIntegralsU, & !< Output:
- basisIntegralsV, & !< Output:
- basisIntegralsMetric !< Output:
-
- real(kind=RKIND), dimension(:,:), intent(in) :: &
- xLocal, & !< Input:
- yLocal, & !< Input:
- wachspressA, & !< Input:
- wachspressB !< Input:
-
- real(kind=RKIND), dimension(:,:,:), intent(in) :: &
- wachspressKappa !< Input:
-
- character(len=strKIND), intent(in) :: &
- integrationType !< Input:
-
- integer, intent(in) :: &
- integrationOrder !< Input:
-
- real(kind=RKIND) :: &
- integration
-
- integer :: &
- iCell, &
- iStressVertex, &
- iVelocityVertex
-
- integer, pointer :: &
- nCells
-
- integer, dimension(:), pointer :: &
- nEdgesOnCell
-
- integer :: &
- nIntegrationPoints
-
- real(kind=RKIND), dimension(:), allocatable :: &
- integrationU, &
- integrationV, &
- integrationWeights
-
- real(kind=RKIND) :: &
- normalizationFactor
-
- ! init variables
- call MPAS_pool_get_dimension(mesh, "nCells", nCells)
- call MPAS_pool_get_array(mesh, "nEdgesOnCell", nEdgesOnCell)
-
- call get_integration_factors(&
- integrationType, &
- integrationOrder, &
- nIntegrationPoints, &
- integrationU, &
- integrationV, &
- integrationWeights, &
- normalizationFactor)
+ enddo ! iGradientVertex
- do iCell = 1, nCells
+ ! loop over vertices - basis function
+ do iBasisVertex = 1, nEdgesOnCell(iCell)
- do iStressVertex = 1, nEdgesOnCell(iCell)
+ call wachspress_basis_derivative(&
+ nEdgesOnCell(iCell), &
+ iBasisVertex, &
+ x(1:nEdgesOnCell(iCell)), &
+ y(1:nEdgesOnCell(iCell)), &
+ wachspressKappa(:,:,iCell), &
+ wachspressA(:,iCell), &
+ wachspressB(:,iCell), &
+ nEdgesOnCellSubset(1:nEdgesOnCell(iCell)), &
+ vertexIndexSubset(1:nEdgesOnCell(iCell),1:nEdgesOnCell(iCell)), &
+ derivativeU(1:nEdgesOnCell(iCell)), &
+ derivativeV(1:nEdgesOnCell(iCell)))
- do iVelocityVertex = 1, nEdgesOnCell(iCell)
+ basisGradientU(iBasisVertex,:,iCell) = 0.0_RKIND
+ basisGradientV(iBasisVertex,:,iCell) = 0.0_RKIND
- basisIntegralsU(iStressVertex,iVelocityVertex,iCell) = 0.0_RKIND
- basisIntegralsV(iStressVertex,iVelocityVertex,iCell) = 0.0_RKIND
- basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell) = 0.0_RKIND
+ iGradientVertex = iBasisVertex
+ basisGradientU(iBasisVertex,iGradientVertex,iCell) = derivativeU(iGradientVertex)
+ basisGradientV(iBasisVertex,iGradientVertex,iCell) = derivativeV(iGradientVertex)
- call integrate_wachspress_polygon(&
- basisIntegralsU(iStressVertex,iVelocityVertex,iCell), &
- basisIntegralsV(iStressVertex,iVelocityVertex,iCell), &
- basisIntegralsMetric(iStressVertex,iVelocityVertex,iCell), &
- nEdgesOnCell(iCell), &
- iStressVertex, &
- iVelocityVertex, &
- xLocal(:,iCell), &
- yLocal(:,iCell), &
- wachspressA(:,iCell), &
- wachspressB(:,iCell), &
- wachspressKappa(:,:,iCell), &
- nIntegrationPoints, &
- integrationU, &
- integrationV, &
- integrationWeights, &
- normalizationFactor)
+ iGradientVertex = seaice_wrapped_index(iBasisVertex - 1, nEdgesOnCell(iCell))
+ basisGradientU(iBasisVertex,iGradientVertex,iCell) = derivativeU(iGradientVertex)
+ basisGradientV(iBasisVertex,iGradientVertex,iCell) = derivativeV(iGradientVertex)
- enddo ! jVertex
+ iGradientVertex = seaice_wrapped_index(iBasisVertex + 1, nEdgesOnCell(iCell))
+ basisGradientU(iBasisVertex,iGradientVertex,iCell) = derivativeU(iGradientVertex)
+ basisGradientV(iBasisVertex,iGradientVertex,iCell) = derivativeV(iGradientVertex)
- enddo ! iVertex
+ enddo ! iBasisVertex
enddo ! iCell
- deallocate(integrationU)
- deallocate(integrationV)
- deallocate(integrationWeights)
+ deallocate(nEdgesOnCellSubset)
+ deallocate(vertexIndexSubset)
- end subroutine integrate_wachspress!}}}
+ deallocate(x)
+ deallocate(y)
+
+ deallocate(derivativeU)
+ deallocate(derivativeV)
+
+ end subroutine calculate_wachspress_derivatives!}}}
+
+!-----------------------------------------------------------------------
+! Integration factors
+!-----------------------------------------------------------------------
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
@@ -1141,7 +1221,14 @@ end subroutine integrate_wachspress!}}}
!
!-----------------------------------------------------------------------
- subroutine get_integration_factors(integrationType, integrationOrder, nIntegrationPoints, u, v, weights, normalizationFactor)
+ subroutine get_integration_factors(&
+ integrationType, &
+ integrationOrder, &
+ nIntegrationPoints, &
+ u, &
+ v, &
+ weights, &
+ normalizationFactor)
character(len=strKIND), intent(in) :: &
integrationType
@@ -1853,218 +1940,6 @@ subroutine get_integration_factors_fekete(&
end subroutine get_integration_factors_fekete
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! integrate_wachspress_polygon
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine integrate_wachspress_polygon(&
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric, &
- nEdgesOnCell, &
- iStressVertex, &
- iVelocityVertex, &
- xLocal, &
- yLocal, &
- wachspressA, &
- wachspressB, &
- wachspressKappa, &
- nIntegrationPoints, &
- integrationU, &
- integrationV, &
- integrationWeights, &
- normalizationFactor)!{{{
-
- use seaice_constants, only: pii
-
- use seaice_velocity_solver_variational_shared, only: &
- seaice_wrapped_index
-
- real(kind=RKIND), intent(inout) :: &
- basisIntegralsU, &
- basisIntegralsV, &
- basisIntegralsMetric
-
- integer, intent(in) :: &
- nEdgesOnCell, & !< Input:
- iStressVertex, & !< Input:
- iVelocityVertex !< Input:
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- xLocal, & !< Input:
- yLocal !< Input:
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- wachspressA, & !< Input:
- wachspressB !< Input:
-
- real(kind=RKIND), dimension(:,:), intent(in) :: &
- wachspressKappa !< Input:
-
- integer, intent(in) :: & !< Input:
- nIntegrationPoints
-
- real(kind=RKIND), dimension(:), intent(in) :: &
- integrationU, & !< Input:
- integrationV, & !< Input:
- integrationWeights !< Input:
-
- real(kind=RKIND), intent(in) :: &
- normalizationFactor !< Input:
-
- integer, dimension(:), allocatable :: &
- nEdgesOnCellSubset
-
- integer, dimension(:,:), allocatable :: &
- vertexIndexSubset
-
- real(kind=RKIND) :: &
- basisIntegralsUSubTriangle, &
- basisIntegralsVSubTriangle, &
- basisIntegralsMetricSubTriangle
-
- real(kind=RKIND), dimension(:), allocatable :: &
- x, &
- y, &
- stressBasisFunction, &
- velocityBasisFunction, &
- velocityBasisDerivativeU, &
- velocityBasisDerivativeV
-
- real(kind=RKIND) :: &
- u, &
- v
-
- integer :: &
- iIntegrationPoint
-
- real(kind=RKIND), dimension(2,2) :: &
- mapping
-
- real(kind=RKIND), dimension(:), allocatable :: &
- jacobian
-
- integer :: &
- iSubTriangle, &
- i1, &
- i2
-
- character(len=strKIND) :: filename
-
- allocate(nEdgesOnCellSubset(nEdgesOnCell))
- allocate(vertexIndexSubset(nEdgesOnCell,nEdgesOnCell))
-
- call wachspress_indexes(&
- nEdgesOnCell, &
- nEdgesOnCellSubset, &
- vertexIndexSubset)
-
- allocate(jacobian(nEdgesOnCell))
-
- do iSubTriangle = 1, nEdgesOnCell
-
- i1 = iSubTriangle
- i2 = seaice_wrapped_index(iSubTriangle + 1, nEdgesOnCell)
-
- call get_triangle_mapping(&
- mapping, &
- jacobian(iSubTriangle), &
- 1.0_RKIND, 0.0_RKIND, &
- 0.0_RKIND, 1.0_RKIND, &
- xLocal(i1), yLocal(i1), &
- xLocal(i2), yLocal(i2))
-
- allocate(x(nIntegrationPoints))
- allocate(y(nIntegrationPoints))
-
- do iIntegrationPoint = 1, nIntegrationPoints
-
- call use_triangle_mapping(&
- x(iIntegrationPoint), y(iIntegrationPoint), &
- integrationU(iIntegrationPoint), integrationV(iIntegrationPoint), &
- mapping)
-
- enddo ! iIntegrationPoint
-
- allocate(stressBasisFunction(nIntegrationPoints))
- allocate(velocityBasisFunction(nIntegrationPoints))
- allocate(velocityBasisDerivativeU(nIntegrationPoints))
- allocate(velocityBasisDerivativeV(nIntegrationPoints))
-
- call wachspress_basis_function(&
- nEdgesOnCell, iStressVertex, x, y, &
- wachspressKappa, wachspressA, wachspressB, &
- nEdgesOnCellSubset, vertexIndexSubset, &
- stressBasisFunction)
-
- call wachspress_basis_function(&
- nEdgesOnCell, iVelocityVertex, x, y, &
- wachspressKappa, wachspressA, wachspressB, &
- nEdgesOnCellSubset, vertexIndexSubset, &
- velocityBasisFunction)
-
- call wachspress_basis_derivative(&
- nEdgesOnCell, iVelocityVertex, x, y, &
- wachspressKappa, wachspressA, wachspressB, &
- nEdgesOnCellSubset, vertexIndexSubset, &
- velocityBasisDerivativeU, &
- velocityBasisDerivativeV)
-
- basisIntegralsUSubTriangle = 0.0_RKIND
- basisIntegralsVSubTriangle = 0.0_RKIND
- basisIntegralsMetricSubTriangle = 0.0_RKIND
-
- do iIntegrationPoint = 1, nIntegrationPoints
-
- basisIntegralsUSubTriangle = basisIntegralsUSubTriangle + &
- jacobian(iSubTriangle) * &
- integrationWeights(iIntegrationPoint) * &
- stressBasisFunction(iIntegrationPoint) * &
- velocityBasisDerivativeU(iIntegrationPoint)
-
- basisIntegralsVSubTriangle = basisIntegralsVSubTriangle + &
- jacobian(iSubTriangle) * &
- integrationWeights(iIntegrationPoint) * &
- stressBasisFunction(iIntegrationPoint) * &
- velocityBasisDerivativeV(iIntegrationPoint)
-
- basisIntegralsMetricSubTriangle = basisIntegralsMetricSubTriangle + &
- jacobian(iSubTriangle) * &
- integrationWeights(iIntegrationPoint) * &
- stressBasisFunction(iIntegrationPoint) * &
- velocityBasisFunction(iIntegrationPoint)
-
- enddo ! iIntegrationPoint
-
- basisIntegralsU = basisIntegralsU + basisIntegralsUSubTriangle / normalizationFactor
- basisIntegralsV = basisIntegralsV + basisIntegralsVSubTriangle / normalizationFactor
- basisIntegralsMetric = basisIntegralsMetric + basisIntegralsMetricSubTriangle / normalizationFactor
-
- deallocate(stressBasisFunction)
- deallocate(velocityBasisFunction)
- deallocate(velocityBasisDerivativeU)
- deallocate(velocityBasisDerivativeV)
-
- deallocate(x)
- deallocate(y)
-
- enddo ! iSubTriangle
-
- deallocate(nEdgesOnCellSubset)
- deallocate(vertexIndexSubset)
-
- deallocate(jacobian)
-
- end subroutine integrate_wachspress_polygon!}}}
-
!-----------------------------------------------------------------------
end module seaice_velocity_solver_wachspress
diff --git a/src/core_seaice/shared/mpas_seaice_velocity_solver_weak.F b/src/core_seaice/shared/mpas_seaice_velocity_solver_weak.F
index db39daf7ba..1e79492f89 100644
--- a/src/core_seaice/shared/mpas_seaice_velocity_solver_weak.F
+++ b/src/core_seaice/shared/mpas_seaice_velocity_solver_weak.F
@@ -22,7 +22,6 @@ module seaice_velocity_solver_weak
public :: &
seaice_init_velocity_solver_weak, &
- seaice_internal_stress_weak, &
seaice_strain_tensor_weak, &
seaice_stress_tensor_weak, &
seaice_stress_divergence_weak, &
@@ -98,132 +97,6 @@ end subroutine seaice_init_velocity_solver_weak!}}}
! Time step
!-----------------------------------------------------------------------
-!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-!
-! seaice_internal_stress_weak
-!
-!> \brief
-!> \author Adrian K. Turner, LANL
-!> \date 2013-2014
-!> \details
-!>
-!
-!-----------------------------------------------------------------------
-
- subroutine seaice_internal_stress_weak(domain)!{{{
-
- type(domain_type), intent(inout) :: &
- domain
-
- type(block_type), pointer :: &
- block
-
- type(MPAS_pool_type), pointer :: &
- meshPool, &
- velocityWeakPool, &
- velocitySolverPool
-
- real(kind=RKIND), dimension(:), pointer :: &
- uVelocity, &
- vVelocity, &
- icePressure, &
- replacementPressure, &
- stressDivergenceU, &
- stressDivergenceV, &
- strain11, &
- strain22, &
- strain12, &
- stress11, &
- stress22, &
- stress12, &
- latCellRotated, &
- latVertexRotated
-
- real(kind=RKIND), pointer :: &
- elasticTimeStep
-
- logical, pointer :: &
- revisedEVP
-
- integer, dimension(:), pointer :: &
- solveStress, &
- solveVelocity
-
- real(kind=RKIND), dimension(:,:,:), pointer :: &
- normalVectorPolygon, &
- normalVectorTriangle
-
- block => domain % blocklist
- do while (associated(block))
-
- call MPAS_pool_get_config(block % configs, "config_revised_evp", revisedEVP)
-
- call MPAS_pool_get_subpool(block % structs, "mesh", meshPool)
- call MPAS_pool_get_subpool(block % structs, "velocity_weak", velocityWeakPool)
- call MPAS_pool_get_subpool(block % structs, "velocity_solver", velocitySolverPool)
-
- call MPAS_pool_get_array(velocitySolverPool, "solveStress", solveStress)
- call MPAS_pool_get_array(velocitySolverPool, "solveVelocity", solveVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "uVelocity", uVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "vVelocity", vVelocity)
- call MPAS_pool_get_array(velocitySolverPool, "icePressure", icePressure)
- call MPAS_pool_get_array(velocitySolverPool, "elasticTimeStep", elasticTimeStep)
- call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceU", stressDivergenceU)
- call MPAS_pool_get_array(velocitySolverPool, "stressDivergenceV", stressDivergenceV)
-
- call MPAS_pool_get_array(velocityWeakPool, "normalVectorPolygon", normalVectorPolygon)
- call MPAS_pool_get_array(velocityWeakPool, "normalVectorTriangle", normalVectorTriangle)
- call MPAS_pool_get_array(velocityWeakPool, "latCellRotated", latCellRotated)
- call MPAS_pool_get_array(velocityWeakPool, "latVertexRotated", latVertexRotated)
- call MPAS_pool_get_array(velocityWeakPool, "strain11", strain11)
- call MPAS_pool_get_array(velocityWeakPool, "strain22", strain22)
- call MPAS_pool_get_array(velocityWeakPool, "strain12", strain12)
- call MPAS_pool_get_array(velocityWeakPool, "stress11", stress11)
- call MPAS_pool_get_array(velocityWeakPool, "stress22", stress22)
- call MPAS_pool_get_array(velocityWeakPool, "stress12", stress12)
- call MPAS_pool_get_array(velocityWeakPool, "replacementPressure", replacementPressure)
-
- call seaice_strain_tensor_weak(&
- meshPool, &
- strain11, &
- strain22, &
- strain12, &
- uVelocity, &
- vVelocity, &
- normalVectorPolygon, &
- latCellRotated, &
- solveStress)
-
- call seaice_stress_tensor_weak(&
- meshPool, &
- stress11, &
- stress22, &
- stress12, &
- strain11, &
- strain22, &
- strain12, &
- icePressure, &
- replacementPressure, &
- solveStress, &
- elasticTimeStep, &
- revisedEVP)
-
- call seaice_stress_divergence_weak(&
- meshPool, &
- stressDivergenceU, &
- stressDivergenceV, &
- stress11, &
- stress22, &
- stress12, &
- normalVectorTriangle, &
- latVertexRotated, &
- solveVelocity)
-
- block => block % next
- end do
-
- end subroutine seaice_internal_stress_weak!}}}
-
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_strain_tensor_weak
@@ -402,12 +275,16 @@ subroutine seaice_stress_tensor_weak(&
icePressure, &
replacementPressure, &
solveStress, &
- dtElastic, &
- revisedEVP)!{{{
+ dtElastic)!{{{
use seaice_velocity_solver_constitutive_relation, only: &
+ constitutiveRelationType, &
+ EVP_CONSTITUTIVE_RELATION, &
+ REVISED_EVP_CONSTITUTIVE_RELATION, &
+ LINEAR_CONSTITUTIVE_RELATION, &
seaice_evp_constitutive_relation, &
- seaice_evp_constitutive_relation_revised
+ seaice_evp_constitutive_relation_revised, &
+ seaice_linear_constitutive_relation
type(MPAS_pool_type), pointer, intent(in) :: &
mesh !< Input:
@@ -430,9 +307,6 @@ subroutine seaice_stress_tensor_weak(&
real(kind=RKIND), intent(in) :: &
dtElastic !< Input:
- logical, intent(in) :: &
- revisedEVP !< Input:
-
integer :: &
iCell
@@ -447,7 +321,7 @@ subroutine seaice_stress_tensor_weak(&
call MPAS_pool_get_array(mesh, "areaCell", areaCell)
- if (.not. revisedEVP) then
+ if (constitutiveRelationType == EVP_CONSTITUTIVE_RELATION) then
do iCell = 1, nCells
@@ -475,7 +349,7 @@ subroutine seaice_stress_tensor_weak(&
end do ! iCell
- else
+ else if (constitutiveRelationType == REVISED_EVP_CONSTITUTIVE_RELATION) then
do iCell = 1, nCells
@@ -502,10 +376,108 @@ subroutine seaice_stress_tensor_weak(&
end do ! iCell
- endif
+ else if (constitutiveRelationType == LINEAR_CONSTITUTIVE_RELATION) then
+
+ do iCell = 1, nCells
+
+ if (solveStress(iCell) == 1) then
+
+ call seaice_linear_constitutive_relation(&
+ stress11(iCell), &
+ stress22(iCell), &
+ stress12(iCell), &
+ strain11(iCell), &
+ strain22(iCell), &
+ strain12(iCell))
+
+ else
+
+ stress11(iCell) = 0.0_RKIND
+ stress22(iCell) = 0.0_RKIND
+ stress12(iCell) = 0.0_RKIND
+
+ endif ! solveStress
+
+ enddo ! iCell
+
+ endif ! constitutiveRelationType
end subroutine seaice_stress_tensor_weak!}}}
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! seaice_stress_tensor_weak_linear
+!
+!> \brief
+!> \author Adrian K. Turner, LANL
+!> \date 2013-2014
+!> \details
+!>
+!
+!-----------------------------------------------------------------------
+
+ subroutine seaice_stress_tensor_weak_linear(&
+ mesh, &
+ stress11, &
+ stress22, &
+ stress12, &
+ strain11, &
+ strain22, &
+ strain12, &
+ solveStress)!{{{
+
+ use seaice_velocity_solver_constitutive_relation, only: &
+ seaice_linear_constitutive_relation
+
+ type(MPAS_pool_type), pointer, intent(in) :: &
+ mesh !< Input:
+
+ real(kind=RKIND), dimension(:), intent(out) :: &
+ stress11, & !< Output:
+ stress22, & !< Output:
+ stress12 !< Output:
+
+ real(kind=RKIND), dimension(:), intent(in) :: &
+ strain11, & !< Input:
+ strain22, & !< Input:
+ strain12 !< Input:
+
+ integer, dimension(:), intent(in) :: &
+ solveStress !< Input:
+
+ integer :: &
+ iCell
+
+ integer, pointer :: &
+ nCells
+
+ ! init variables
+ call MPAS_pool_get_dimension(mesh, "nCells", nCells)
+
+ do iCell = 1, nCells
+
+ if (solveStress(iCell) == 1) then
+
+ call seaice_linear_constitutive_relation(&
+ stress11(iCell), &
+ stress22(iCell), &
+ stress12(iCell), &
+ strain11(iCell), &
+ strain22(iCell), &
+ strain12(iCell))
+
+ else
+
+ stress11(iCell) = 0.0_RKIND
+ stress22(iCell) = 0.0_RKIND
+ stress12(iCell) = 0.0_RKIND
+
+ endif ! solveStress
+
+ enddo ! iCell
+
+ end subroutine seaice_stress_tensor_weak_linear!}}}
+
!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!
! seaice_stress_divergence_weak
diff --git a/testing_and_setup/compass/README_landice.md b/testing_and_setup/compass/README_landice.md
new file mode 100644
index 0000000000..191e53a07c
--- /dev/null
+++ b/testing_and_setup/compass/README_landice.md
@@ -0,0 +1,53 @@
+# Setting up COMPASS for landice test cases
+
+## COMPASS conda environment
+
+To set up and run landice test cases from COMPASS, you will need a conda
+environment. First, install Miniconda3 (if miniconda is not already
+installed), then create a new conda environment as follows:
+``` bash
+conda create -n compass_py3.7 -c conda-forge -c xylar python=3.7 geometric_features mpas_tools jigsaw jigsawpy metis pyflann scikit-image basemap pyamg ffmpeg pyqt
+```
+Each time you want to work with COMPASS, you will need to run:
+```
+conda activate compass_py3.7
+```
+
+## Setting config options
+
+The file `general.config.landice` is a template containing a set of config
+options that the COMPASS user must set in order to set up landice test cases.
+Make a copy of this file (e.g. `general.config.landice.myEdits`) and set the options as follows.
+* Set the appropriate paths in the `[namelists]` and `[streams]` sections
+* Set the appropriate paths in the `[executables]` section. The `model` path should be to the compiled `landice_model` file. The other executables can currently be found in the `MPAS-Tools` repository at https://github.com/MPAS-Dev/MPAS-Tools. Eventually they will be moved into the conda package, at which point they will no longer be required here.
+* The [paths] section is currently not required.
+
+## Setting up and running a specific test
+
+* To see a list of available tests: `./list_testcases.py -o landice`
+* To set up a single test case, e.g.: `./setup_testcase.py -n 102 --work_dir ~/Documents/mpas-git/TESTS/ -f general.config.landice.myEdits`
+ In this example test number 102 will be set up within the `~/Documents/mpas-git/TESTS/` directory using the information you have set up in the `general.config.landice.myEdits` file. Note that within the `--work_dir` directory, a directory tree corresponding to the test will be created (e.g. `dome/2000m/halfar_analytic_test/`), even if a only a single test was requested. See `/setup_testcase.py -h` for detailed usage options.
+* Change directory to where the test was created. Run the test with python driver script located there. Note that individual steps can be run manually by cd'ing into the step directory and running the auto-generated python script for that step.
+
+## Running a regression suite
+Regression suites are defined that run a set of tests. Regression suite are defined in the directory `landice/regression_suites/`.
+* See `./manage_regression_suite.py -h` for detailed usage options
+* A common usage is like: `./manage_regression_suite.py -t landice/regression_suites/combined_integration_test_suite.xml -f general.config.landice.myEdits -c --work_dir ~/Documents/mpas-git/TESTS/TRUSTED`
+ This will run the regression suite without comparison to an older version of the code.
+* To run the regression suite and compare to a previous run of the regression suite, the command can be called with the `-b` baseline option like: `./manage_regression_suite.py -t landice/regression_suites/combined_integration_test_suite.xml -f general.config.landice.myEdits -c -b ~/Documents/mpas-git/TESTS/TRUSTED --work_dir ~/Documents/mpas-git/TESTS/TESTING`
+
+## Adding a new test
+See `testing_and_setup/compass/README` and `testing_and_setup/compass/docs/*` for detailed information about the COMPASS system.
+In general, COMPASS is organized like: `testing_and_setup/compass////`
+* `` is `landice`.
+* `` is the parent directory for a test case configuration, such as the Halfar dome or Antarctica. This directory level holds general purpose files for this configuration, such as initial condition setup scripts, pre/post-processing analysis scripts, namelist/streams template files, `albany_input.yaml` files, etc.
+* `` is the grid resolution for a given configuration. Note that in some cases this directory level is used for other purposes than resolution.
+* `` is the specific type of test for a given configuration and resolution, e.g., a smoke test, a restart test, an analytic-solution test. Note that in some cases this directory level is used for other purposes than a specific type of test.
+
+To add a new test:
+1. Create a new test `` directory and corresponding `` and `` levels in the `compass/landice` directory.
+2. Add a namelist/streams template file, `albany_input.yaml` file, and any required pre/post-processing scripts (e.g. initial conditions, comparison to analytic solution) to the `` directory.
+3. Add `config_*_step.xml` files in the `` for each step of the test required. Each step is run in a separate directory. A common layout is to create the mesh in one direcory with a `config_setup_mesh_step.xml` file and for the test to be run in a second directory with a `config_run_model_step.xml` file.
+4. Add a `config_driver.xml` file to the ``. This xml file references the individual step files.
+5. Try out and debug your new test using the `setup_testcase.py` command described above.
+6. A good example to use for setting up a new test is `testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test`.
diff --git a/testing_and_setup/compass/general.config.landice b/testing_and_setup/compass/general.config.landice
index 9c53cdca7e..a07da3100e 100644
--- a/testing_and_setup/compass/general.config.landice
+++ b/testing_and_setup/compass/general.config.landice
@@ -25,11 +25,9 @@ forward = FULL_PATH_TO_FORWARD_TEMPLATE_STREAMS
# anywhere on the machine.
[executables]
model = FULL_PATH_TO_MODEL
-mesh_converter = FULL_PATH_TO_MESH_CONVERTER
-cell_culler = FULL_PATH_TO_CELL_CULLER
-metis = FULL_PATH_TO_METIS
-grid_to_li_grid = FULL_PATH_TO_create_landice_grid_from_generic_MPAS_grid.py
-periodic_hex = FULL_PATH_TO_PERIODIC_HEX
+grid_to_li_grid = FULL_PATH_TO/MPAS-Tools/landice/mesh_tools_li/create_landice_grid_from_generic_MPAS_grid.py
+define_cull_mask = FULL_PATH_TO/MPAS-Tools/landice/mesh_tools_li/define_cullMask.py
+interpolate_to_mpasli_grid = FULL_PATH_TO/MPAS-Tools/landice/mesh_tools_li/interpolate_to_mpasli_grid.py
# The paths section describes paths that are used within the landice core test
diff --git a/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_run_model_step.xml b/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_run_model_step.xml
index eb4d2c0773..a1504c8953 100644
--- a/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -21,7 +20,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_setup_mesh_step.xml
index cf6f4554cd..15aaec9de3 100644
--- a/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/EISMINT1/50000m/MovingMargin1/config_setup_mesh_step.xml
@@ -2,39 +2,35 @@
-
-
-
-
-
-
-
+
+ 32
+ 38
+ 50000.0
+
+
-
-
+
grid.nc
- mpas_grid.nc
-
-
-
- mpas_grid.nc
+ culled.nc
-
- mpas_grid.nc
+
+
culled.nc
+ mpas_grid.nc
+
-
- culled.nc
+
+ mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/EISMINT1/check_output_eismint-mm1.py b/testing_and_setup/compass/landice/EISMINT1/check_output_eismint-mm1.py
index 131b5b187c..5bc995b1c1 100755
--- a/testing_and_setup/compass/landice/EISMINT1/check_output_eismint-mm1.py
+++ b/testing_and_setup/compass/landice/EISMINT1/check_output_eismint-mm1.py
@@ -1,14 +1,14 @@
#!/usr/bin/env python
-# A script to compare MPAS model output to the EISMINT Moving Margin 1 test case.
-# Matt Hoffman, LANL, September 2013
+"""
+A script to compare MPAS model output to the EISMINT Moving Margin 1 test case.
+Matt Hoffman, LANL, September 2013
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys
import datetime
-try:
- import netCDF4
-except ImportError:
- print 'Unable to import netCDF4 python modules:'
- sys.exit
+import netCDF4
from optparse import OptionParser
import numpy as np
import matplotlib.pyplot as plt
@@ -22,12 +22,12 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'output.nc'
- print 'No file specified. Attempting to use output.nc'
+ print('No file specified. Attempting to use output.nc')
if options.t:
timelev = int(options.t)
else:
timelev = -1
- print 'No time level specified. Attempting to use final time.'
+ print('No time level specified. Attempting to use final time.')
################### DEFINE FUNCTIONS ######################
@@ -63,36 +63,36 @@ def xtime2numtime(xtime):
#numtime = xtime2numtime(xtime)
# Find out what the ice density and flowA values for this run were.
-print '\nCollecting parameter values from the output file.'
+print('\nCollecting parameter values from the output file.')
flowA = filein.config_default_flowParamA
-print 'Using a flowParamA value of: ' + str(flowA)
+print('Using a flowParamA value of: ' + str(flowA))
flow_n = filein.config_flowLawExponent
-print 'Using a flowLawExponent value of: ' + str(flow_n)
+print('Using a flowLawExponent value of: ' + str(flow_n))
rhoi = filein.config_ice_density
-print 'Using an ice density value of: ' + str(rhoi)
+print('Using an ice density value of: ' + str(rhoi))
dynamicThickness = filein.config_dynamic_thickness
-print 'Dynamic thickness for this run = ' + str(dynamicThickness)
+print('Dynamic thickness for this run = ' + str(dynamicThickness))
-print 'Using model time of ' + xtime[timelev,:].tostring().strip() + '\n'
+print('Using model time of ' + xtime[timelev,:].tostring().strip() + '\n')
# find divide
ind = np.where(thk == thk.max())
# Print some stats about the error
-print '===================================='
-print 'Max modeled thickness (m) = ' + str( thk.max() )
-print 'EISMINT models ice thickness at divide (m):'
-print ' 3d models (10 of them): 2978.0 +/- 19.3'
-print ' 2d models (3 of them): 2982.2 +/- 26.4'
-print '===================================='
-print ''
-print '===================================='
-print 'Basal homologous temperature at divide (deg C) = {}'.format(basalTemp[ind][0]-basalPmpTemp[ind][0])
-print 'EISMINT models basal temperature at divide (m):'
-print ' 3d models (6 of them): -13.34 +/- 0.56'
-print '===================================='
-print ''
+print('====================================')
+print('Max modeled thickness (m) = ' + str( thk.max() ))
+print('EISMINT models ice thickness at divide (m):')
+print(' 3d models (10 of them): 2978.0 +/- 19.3')
+print(' 2d models (3 of them): 2982.2 +/- 26.4')
+print('====================================')
+print('')
+print('====================================')
+print('Basal homologous temperature at divide (deg C) = {}'.format(basalTemp[ind][0]-basalPmpTemp[ind][0]))
+print('EISMINT models basal temperature at divide (m):')
+print(' 3d models (6 of them): -13.34 +/- 0.56')
+print('====================================')
+print('')
# Plot the results
@@ -103,7 +103,7 @@ def xtime2numtime(xtime):
plt.scatter(xCell,yCell,markersize,thk[:], marker='h', edgecolors='none')
plt.colorbar()
plt.axis('equal')
-plt.title('Modeled thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
+plt.title('Modeled thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
plt.draw()
@@ -111,12 +111,12 @@ def xtime2numtime(xtime):
if options.saveimage:
plotname = 'halfar-results.png'
plt.savefig(plotname, dpi=150)
- print 'Saved plot as ' + plotname
+ print('Saved plot as ' + plotname)
if options.hidefigs:
- print "Plot display disabled with -n argument."
+ print("Plot display disabled with -n argument.")
else:
- print 'Showing plot... Close plot window to exit.'
+ print('Showing plot... Close plot window to exit.')
plt.show()
diff --git a/testing_and_setup/compass/landice/EISMINT1/setup_initial_conditions_EISMINT1-MovingMargin-1.py b/testing_and_setup/compass/landice/EISMINT1/setup_initial_conditions_EISMINT1-MovingMargin-1.py
index 46ec12f35a..1d1147cd72 100755
--- a/testing_and_setup/compass/landice/EISMINT1/setup_initial_conditions_EISMINT1-MovingMargin-1.py
+++ b/testing_and_setup/compass/landice/EISMINT1/setup_initial_conditions_EISMINT1-MovingMargin-1.py
@@ -1,5 +1,9 @@
#!/usr/bin/env python
-# Generate initial conditions for EISMINT-1 moving margin land ice test case
+"""
+Generate initial conditions for EISMINT-1 moving margin land ice test case
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys, numpy
from netCDF4 import Dataset as NetCDFFile
@@ -14,7 +18,7 @@
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
# Open the file, get needed dimensions
@@ -90,5 +94,5 @@
gridfile.close()
-print 'Successfully added initial conditions for EISMINT1-Moving Margin, experiment 1 to the file: ', options.filename
+print('Successfully added initial conditions for EISMINT1-Moving Margin, experiment 1 to the file: '+options.filename)
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/EISMINT2_25000m_template.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/EISMINT2_25000m_template.xml
index f47c9c5ba9..3dd8d21a9e 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/EISMINT2_25000m_template.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/EISMINT2_25000m_template.xml
@@ -12,12 +12,18 @@
+
+
+
+
+
+
@@ -53,6 +59,23 @@
+
+ output
+ globalStats.nc
+ 0000-00-01_00:00:00
+ 0000-01-01_00:00:00
+ overwrite
+
+
+
+
+
+
+
+
+
+
+
input;output
restart.$Y.nc
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_1p.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_1p.xml
index c3766d6825..3c392081b7 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_1p.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_1p.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_4p.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_4p.xml
index 9569b87e6c..0a2fdbaff3 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_4p.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/decomposition_test/config_experiment_F_4p.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_driver.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_driver.xml
new file mode 100644
index 0000000000..571b0e4223
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_driver.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_experiment_F_1p.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_experiment_F_1p.xml
new file mode 100644
index 0000000000..b2746cfb34
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_experiment_F_1p.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0000-00-01_00:00:00
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_experiment_F_4p.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_experiment_F_4p.xml
new file mode 100644
index 0000000000..0134fb25c3
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_experiment_F_4p.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0000-00-01_00:00:00
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_setup_mesh_step.xml
new file mode 120000
index 0000000000..4e4ca628b5
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/config_setup_mesh_step.xml
@@ -0,0 +1 @@
+../standard_experiments/config_setup_mesh_step.xml
\ No newline at end of file
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/output_comparison.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/output_comparison.xml
new file mode 100644
index 0000000000..37dfae6532
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_decomposition_test/output_comparison.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_driver.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_driver.xml
new file mode 100644
index 0000000000..2450de0a19
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_driver.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_full_run_step.xml
new file mode 100644
index 0000000000..9a2757712d
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_full_run_step.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0100-00-00_00:00:00
+
+
+ rst.$Y.nc
+ output_interval
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_restart_run_step.xml
new file mode 100644
index 0000000000..f7c6b9878a
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_restart_run_step.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0100-00-00_00:00:00
+ truncate
+
+
+ rst.$Y.nc
+ output_interval
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+ 0100-00-00_00:00:00
+ overwrite
+
+
+ rst.$Y.nc
+ output_interval
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_setup_mesh_step.xml
new file mode 120000
index 0000000000..4e4ca628b5
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/config_setup_mesh_step.xml
@@ -0,0 +1 @@
+../standard_experiments/config_setup_mesh_step.xml
\ No newline at end of file
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/output_comparison.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/output_comparison.xml
new file mode 100644
index 0000000000..37dfae6532
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/enthalpy_restart_test/output_comparison.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/periodic_hex.namelist.input b/testing_and_setup/compass/landice/EISMINT2/25000m/periodic_hex.namelist.input
deleted file mode 100644
index b1ee7be3c8..0000000000
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/periodic_hex.namelist.input
+++ /dev/null
@@ -1,8 +0,0 @@
-&periodic_grid
- nx = 64,
- ny = 74,
- dc = 25000.,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1,
-/
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_driver.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_driver.xml
new file mode 100644
index 0000000000..453e680b51
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_driver.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_full_run_step.xml
new file mode 100644
index 0000000000..3c9217f958
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_full_run_step.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0100-00-00_00:00:00
+
+
+ rst.$Y.nc
+ output_interval
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_restart_run_step.xml
new file mode 100644
index 0000000000..01dbb91cff
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_restart_run_step.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0100-00-00_00:00:00
+ truncate
+
+
+ rst.$Y.nc
+ output_interval
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+ 0100-00-00_00:00:00
+ overwrite
+
+
+ rst.$Y.nc
+ output_interval
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_setup_mesh_step.xml
new file mode 120000
index 0000000000..4e4ca628b5
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/config_setup_mesh_step.xml
@@ -0,0 +1 @@
+../standard_experiments/config_setup_mesh_step.xml
\ No newline at end of file
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/output_comparison.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/output_comparison.xml
new file mode 100644
index 0000000000..37dfae6532
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/restart_test/output_comparison.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_A.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_A.xml
index 1025b017b4..c90d0a21bf 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_A.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_A.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_B.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_B.xml
index 24bfd1c6f2..10a66f139b 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_B.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_B.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_C.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_C.xml
index e15bafbc87..6fbf1838c5 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_C.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_C.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_D.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_D.xml
index f74ffbeb63..629f5c650a 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_D.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_D.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_E.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_E.xml
index 9709f2c5d6..a2fe1f4503 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_E.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_E.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_F.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_F.xml
index 4f81cc883d..80a365e012 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_F.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_F.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_G.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_G.xml
index 2b0ef5b5fe..cd2ca5a251 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_G.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_experiment_G.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_setup_mesh_step.xml
index f3be897079..f7bc6c1656 100644
--- a/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/EISMINT2/25000m/standard_experiments/config_setup_mesh_step.xml
@@ -1,29 +1,43 @@
-
-
-
-
-
-
-
-
-
+
+ 64
+ 74
+ 25000.0
-
+
grid.nc
mpas_grid.nc
+
+
+ mpas_grid.nc
+ radius
+ 750.0
+
+
+
+
+ mpas_grid.nc
+ culled_grid.nc
+
+
+
+
+ culled_grid.nc
+ mpas_grid2.nc
+
+
-
- mpas_grid.nc
+
+ mpas_grid2.nc
landice_grid.nc
10
@@ -31,7 +45,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/EISMINT2/README b/testing_and_setup/compass/landice/EISMINT2/README
new file mode 100644
index 0000000000..19d1488ab7
--- /dev/null
+++ b/testing_and_setup/compass/landice/EISMINT2/README
@@ -0,0 +1,7 @@
+To run EISMINT2 experiments, first set up the test case like usual,
+including running the auto-generated python script in the work directory.
+
+Then in each experiment directory, first run the setup_initial_conditions_EISMINT2.py.
+Then manually run landice_model on the number of processors you wish.
+
+To view the results, run visualize_output_EISMINT2.py.
diff --git a/testing_and_setup/compass/landice/EISMINT2/setup_initial_conditions_EISMINT2.py b/testing_and_setup/compass/landice/EISMINT2/setup_initial_conditions_EISMINT2.py
index c9a8c603fd..376c7ff37b 100755
--- a/testing_and_setup/compass/landice/EISMINT2/setup_initial_conditions_EISMINT2.py
+++ b/testing_and_setup/compass/landice/EISMINT2/setup_initial_conditions_EISMINT2.py
@@ -3,6 +3,8 @@
# Test case is described in:
# Payne, A. J., Huybrechts, P., Calov, R., Fastook, J. L., Greve, R., Marshall, S. J., Marsiat, I., Ritz, C., Tarasov, L. and Thomassen, M. P. A.: Results from the EISMINT model intercomparison: the effects of thermomechanical coupling, J. Glaciol., 46(153), 227-238, 2000.
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import sys, os
from netCDF4 import Dataset as NetCDFFile
from math import sqrt
@@ -19,7 +21,7 @@
sys.exit('Error: No experiment specified. Please specify an experiment to setup with the -e option')
experiment = options.exp.lower() # allow lower or upper case to be input, but use lower case in the script logic
if experiment in ('a','b','c','d','f','g'):
- print 'Setting up EISMINT2 Experiment ' + experiment
+ print('Setting up EISMINT2 Experiment ' + experiment)
else:
sys.exit("Error: Invalid experiment specified. Please specify an experiment between 'a' and 'g', excluding 'e'")
@@ -125,7 +127,7 @@
# Define values prescribed by Payne et al. 2000 paper.
params = exp_params[experiment]
-print "Parameters for this experiment:", params
+print("Parameters for this experiment:", params)
# SMB field specified by EISMINT, constant in time for EISMINT2
# It is a function of geographical position (not elevation)
@@ -163,5 +165,5 @@
betaVar[0,:] = beta
gridfile.close()
-print 'Successfully added initial conditions for EISMINT2, experiment '+experiment+' to the file: ', filename
+print('Successfully added initial conditions for EISMINT2, experiment '+experiment+' to the file: ', filename)
diff --git a/testing_and_setup/compass/landice/EISMINT2/visualize_output_EISMINT2.py b/testing_and_setup/compass/landice/EISMINT2/visualize_output_EISMINT2.py
index 5d7958525f..49f56a7c27 100755
--- a/testing_and_setup/compass/landice/EISMINT2/visualize_output_EISMINT2.py
+++ b/testing_and_setup/compass/landice/EISMINT2/visualize_output_EISMINT2.py
@@ -2,17 +2,16 @@
# A script to compare MPAS model output to the EISMINT2 test cases.
# Matt Hoffman, LANL, December 2014
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import sys, os
import datetime
-try:
- import netCDF4
-except ImportError:
- print 'Unable to import netCDF4 python modules:'
- sys.exit
+import netCDF4
from optparse import OptionParser
import numpy as np
import matplotlib.pyplot as plt
-from matplotlib.mlab import griddata
+#from matplotlib.mlab import griddata
+from scipy.interpolate import griddata
# Parse options
from optparse import OptionParser
@@ -26,7 +25,7 @@
sys.exit('Error: No experiment specified. Please specify an experiment to visualize with the -e option')
experiment = options.exp.lower() # allow lower or upper case to be input, but use lower case in the script logic
if experiment in ('a','b','c','d','f', 'g'):
- print 'Visualizing EISMINT2 Experiment ' + experiment
+ print('Visualizing EISMINT2 Experiment ' + experiment)
else:
sys.exit("Error: Invalid experiment specified. Please specify an experiment between 'a' and 'g', excluding 'e'")
@@ -61,7 +60,7 @@ def xtimeGetYear(xtime):
-def contourMPAS(field, contour_levs=None):
+def contourMPAS(field, contour_levs=np.array([0])):
"""Contours irregular MPAS data on cells"""
#-- Now let's grid your data.
# First we'll make a regular grid to interpolate onto.
@@ -71,12 +70,12 @@ def contourMPAS(field, contour_levs=None):
yc = np.linspace(yCell.min(), yCell.max(), numrows)
xi, yi = np.meshgrid(xc, yc)
#-- Interpolate at the points in xi, yi
- zi = griddata(xCell, yCell, field, xi, yi)
+ zi = griddata((xCell, yCell), field, (xi, yi))
#-- Display the results
- if contour_levs == None:
+ if len(contour_levs)==1:
im = plt.contour(xi, yi, zi)
else:
- im = plt.contour(xi, yi, zi, contour_levs)
+ im = plt.contour(xi, yi, zi, contour_levs, cmap=plt.cm.jet)
#plt.scatter(xCell, yCell, c=temperature[timelev,:,-1], s=100, vmin=zi.min(), vmax=zi.max()) # to see the raw data on top
plt.colorbar(im)
@@ -111,7 +110,7 @@ def contourMPAS(field, contour_levs=None):
secInYr = 365.0*24.0*3600.0
timelev = -1 # Use final time
-print 'Using final model time of ' + xtime[timelev,:].tostring().strip() + '\n'
+print('Using final model time of ' + xtime[timelev,:].tostring().strip().decode('utf-8') + '\n')
##### Print some stats about the error
@@ -140,7 +139,7 @@ def contourMPAS(field, contour_levs=None):
else:
markersize= max( int(round( 1800.0/(nCells**0.5) )), 1)
markershape = '.'
-print 'Using a markersize of ', markersize
+print('Using a markersize of ', markersize)
fig = plt.figure(1, facecolor='w')
@@ -149,11 +148,15 @@ def contourMPAS(field, contour_levs=None):
#markershape='h'
# print ice locations with gray hexagons
-iceIndices = np.where(thickness[timelev,:]>0.0)[0]
-plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, (0.8, 0.8, 0.8), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
+iceIndices = np.where(thickness[timelev,:]>10.0)[0]
+plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, c=np.array([[0.8, 0.8, 0.8],]), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
# add contours of ice temperature over the top
-contourMPAS(basalTemperature[timelev,:], np.linspace(240.0, 275.0, 8))
+basalTemp = basalTemperature[timelev,:]
+# fill places below dynamic limit with non-ice value of 273.15
+basalTemp[np.where(thickness[timelev,:]<10.0)] = 273.15
+#plt.scatter(xCell, yCell, markersize, basalTemp[:], marker=markershape, edgecolors='none') # print ice locations with gray hexagons; plt.plot()
+contourMPAS(basalTemp, contour_levs=np.linspace(240.0, 275.0, 8))
plt.axis('equal')
plt.title('Modeled basal temperature (K) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
@@ -175,7 +178,7 @@ def contourMPAS(field, contour_levs=None):
ax1 = fig.add_subplot(131)
# print ice locations with gray hexagons
-plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, (0.8, 0.8, 0.8), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
+plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, c=np.array([[0.8, 0.8, 0.8],]), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
# add contours of ice thickness over the top
contour_intervals = np.linspace(0.0, 5000.0, 5000.0/250.0+1)
@@ -183,7 +186,7 @@ def contourMPAS(field, contour_levs=None):
#contourMPAS(thickness[timelev,:])
plt.title('Final thickness (m)' )
-plt.axis('equal')
+ax1.set_aspect('equal')
#plt.xlim( (0.0, 750.0) ); plt.ylim( (0.0, 750.0) )
plt.xlabel('X position (km)'); plt.ylabel('Y position (km)')
@@ -198,14 +201,14 @@ def contourMPAS(field, contour_levs=None):
flux += speedLevel * thickness[timelev,:] * layerThicknessFractions[k]
# print ice locations with gray hexagons
-plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, (0.8, 0.8, 0.8), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
+plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, c=np.array([[0.8, 0.8, 0.8],]), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
# add contours over the top
#contour_intervals = np.linspace(0.0, 10.0, 10.0/0.5+1)
contour_intervals = np.linspace(0.0, 20.0, 11)
contourMPAS(flux * 3600.0*24.0*365.0 / 10000.0, contour_levs=contour_intervals)
#contourMPAS(flux * 3600.0*24.0*365.0 / 10000.0)
-plt.axis('equal')
+ax.set_aspect('equal')
plt.title('Final flux (m$^2$ a$^{-1}$ / 10000)' )
#plt.xlim( (0.0, 750.0) ); plt.ylim( (0.0, 750.0) )
plt.xlabel('X position (km)'); plt.ylabel('Y position (km)')
@@ -215,14 +218,15 @@ def contourMPAS(field, contour_levs=None):
ax = fig.add_subplot(132, sharex=ax1, sharey=ax1)
# print ice locations with gray hexagons
-plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, (0.8, 0.8, 0.8), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
+plt.scatter(xCell[iceIndices], yCell[iceIndices], markersize, c=np.array([[0.8, 0.8, 0.8],]), marker=markershape, edgecolors='none') # print ice locations with gray hexagons
# add contours over the top
#contour_intervals = np.linspace(0.0, 20.0, 20.0/2.0+1)
contour_intervals = np.linspace(0.0, 16.0, 16.0/0.5+1)
#contourMPAS(flwa[timelev,:,:].mean(axis=1) *3600.0*24.0*365.0 / 1.0e-17, contour_levs=contour_intervals) # NOT SURE WHICH LEVEL FLWA SHOULD COME FROM - so taking column average
-contourMPAS(flwa[timelev,:,:].mean(axis=1) * 3600.0*24.0*365.0 / 1.0e-17) # NOT SURE WHICH LEVEL FLWA SHOULD COME FROM - so taking column average
-plt.axis('equal')
+if flwa[timelev,:,:].max()>0.0: # this is not used if FO velo solver is used
+ contourMPAS(flwa[timelev,:,:].mean(axis=1) * 3600.0*24.0*365.0 / 1.0e-17) # NOT SURE WHICH LEVEL FLWA SHOULD COME FROM - so taking column average
+ax.set_aspect('equal')
plt.title('Final flow factor (10$^{-17}$ Pa$^{-3}$ a$^{-1}$)' ) # Note: the paper's figure claims units of 10$^{-25}$ Pa$^{-3}$ a$^{-1}$ but the time unit appears to be 10^-17
#plt.xlim( (0.0, 750.0) ); plt.ylim( (0.0, 750.0) )
plt.xlabel('X position (km)'); plt.ylabel('Y position (km)')
@@ -292,6 +296,7 @@ def contourMPAS(field, contour_levs=None):
plt.ylabel('Volume (10$^6$ km$^3$)')
plt.plot( (0.0,), volume, 'ro') # MPAS results
plt.xticks(())
+print("MALI volume = {}".format(volume))
fig.add_subplot(152)
area = (areaCell[iceIndices]).sum() / 1000.0**2 / 10.0**6
@@ -305,6 +310,7 @@ def contourMPAS(field, contour_levs=None):
plt.ylabel('Area (10$^6$ km$^2$)')
plt.plot( (0.0,), area, 'ro') # MPAS results
plt.xticks(())
+print("MALI area = {}".format(area))
fig.add_subplot(153)
warmBedIndices = np.where(np.logical_and(thickness[timelev,:] > 0.0, basalTemperature[timelev,:] >= (basalPmpTemperature[timelev,:] - 0.01) ) )[0] # using threshold here to identify melted locations
@@ -323,6 +329,7 @@ def contourMPAS(field, contour_levs=None):
plt.ylabel('Melt fraction')
plt.plot( (0.0,), meltfraction, 'ro') # MPAS results
plt.xticks(())
+print("MALI melt fraction = {}".format(meltfraction))
fig.add_subplot(154)
dividethickness = thickness[timelev, divideIndex]
@@ -334,6 +341,7 @@ def contourMPAS(field, contour_levs=None):
plt.ylabel('Divide thickness (m)')
plt.plot( (0.0,), dividethickness, 'ro') # MPAS results
plt.xticks(())
+print("MALI divide thickness = {}".format(dividethickness[0]))
fig.add_subplot(155)
dividebasaltemp = basalTemperature[timelev, divideIndex]
@@ -346,6 +354,7 @@ def contourMPAS(field, contour_levs=None):
plt.ylabel('Divide basal temp. (K)')
plt.plot( (0.0,), dividebasaltemp, 'ro') # MPAS results
plt.xticks(())
+print("MALI divide basal temperature = {}".format(dividebasaltemp[0]))
plt.tight_layout()
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/README_forcings b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/README_forcings
new file mode 100644
index 0000000000..641d399a7a
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/README_forcings
@@ -0,0 +1,47 @@
+Processing steps for ISMIP6 forcing
+
+MJH 9/23/2019
+
+Regridding from native ISMIP6 grid to MPAS grid needs to happen for all
+forcings.
+
+
+BMB
+---
+
+1. copy 1995-2010 remapped data from Tong's directory, naming it appropriately
+here: TF___1995-2010.nc
+2. run add_xtime.py script on file
+
+3. Create gamma0/basin/Toffset file:
+ a. Do some renames from ISMIP6-provided files, e.g.:
+ ncrename -v x,x1 -v y,y1 -v deltaT_basin,ismip6shelfMelt_deltaT -v gamma0,ismip6shelfMelt_gamma0 coeff_gamma0_DeltaT_quadratic_non_local_median_PIGL_gamma_calibration.renames.nc
+ b. regrid basin number, Toffset using interpolate_to_mpasli_grid.py using nearest neighbor method, e.g.:
+ ./interpolate_to_mpasli_grid.py -s coeff_gamma0_DeltaT_quadratic_non_local_median_PIGL_gamma_calibration.renames.nc -d ismip6_basins_gamma0_deltaT_nonlocal_median_PIGL.nc -m n
+ (Note will need to add xCell,yCell to destination file for interpolation to work.)
+ c. Apply gamma0 value:
+ ncks -A -v ismip6shelfMelt_gamma0 coeff_gamma0_DeltaT_quadratic_non_local_median_PIGL_gamma_calibration.renames.nc ismip6_basins_gamma0_deltaT_nonlocal_median_PIGL.nc
+
+3. Create offset file:
+ a. run model for one time step at 2015 to get param. base melt rate
+ b. Pull out melt rate (make sure it was from the param and not the original
+ Rignot data):
+ ncks -d Time,0 -v floatingBasalMassBal output.2015.nc mt0.nc
+ c. Difference with Rignot melt rate:
+ ncdiff m0.nc mt0.nc ismip6shelfMelt_offset___2015.nc
+ d. Rename melt field:
+ ncrename -v floatingBasalMassBal,ismip6shelfMelt_offset ismip6shelfMelt_offset___2015.nc
+
+
+
+SMB
+---
+
+1. copy 1995-2010 remapped data from Tong's directory, naming it appropriately
+here: SMB___1995-2010.anomaly.nc
+1a. Rename smb field: ncrename -v smb,sfcMassBal FILE.nc
+2. run add_xtime.py script on file
+3. cp to non-anomaly file name: SMB___1995-2010.nc
+4. run apply_base_to_anomaly.py on file
+5. run zero_smb_on_icefree_areas.py on file
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/add_xtime.py b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/add_xtime.py
new file mode 100644
index 0000000000..6f4a446e1c
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/add_xtime.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+from __future__ import absolute_import, division, print_function, unicode_literals
+import netCDF4
+import numpy as np
+
+f = netCDF4.Dataset('SMB_NorESM_2.6_1995-2100.anomaly.nc','r+')
+
+nt = len(f.dimensions['Time'])
+
+# It seems much faster for large files to use NCO to add xtime, like:
+# ncap2 -s 'defdim("StrLen",64); xtime[$Time,$StrLen]=" "' TF_NorESM_2.6_1995-2100.nc temp.nc
+StrLen=64
+if 'xtime' in f.variables:
+ xtime = f.variables['xtime']
+else:
+ if not 'StrLen' in f.dimensions:
+ print("adding StrLen")
+ f.createDimension('StrLen', StrLen)
+ print("adding xtime")
+ xtime = f.createVariable('xtime','c', ('Time', 'StrLen'))
+
+
+startYear = 1995
+for i in range(nt):
+
+ time_string = f.variables['xtime'][i,:]
+
+ time_string = "{:04}-01-01_00:00:00".format(i+startYear)
+
+ print(time_string)
+
+ f.variables['xtime'][i,:] = list(time_string.ljust(StrLen))
+
+
+f.close()
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/apply_base_to_anomaly.py b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/apply_base_to_anomaly.py
new file mode 100644
index 0000000000..f789d27b78
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/apply_base_to_anomaly.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# script to apply anomaly SMB field to our base SMB
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+import netCDF4
+import numpy as np
+
+f = netCDF4.Dataset('SMB_NorESM_2.6_1995-2100.nc','r+')
+nt = len(f.dimensions['Time'])
+smb = f.variables['sfcMassBal']
+
+fbase = netCDF4.Dataset('../test/ais2km_100yr_spinup.nc','r')
+smbBase = fbase.variables['sfcMassBal'][0,:]
+
+for i in range(nt):
+ print(i)
+
+ smb[i,:] = smb[i,:] + smbBase
+
+f.close()
+fbase.close()
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt10/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt10/namelist.landice
new file mode 100644
index 0000000000..1dd2920926
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt10/namelist.landice
@@ -0,0 +1,105 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'none'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+ config_do_restart = .false.
+ config_start_time = '2015-01-01_00:00:00'
+! config_do_restart = .true.
+! config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ !config_stop_time = '2100-01-01_00:00:00'
+ config_run_duration = '0005-00-00_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 34
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt10/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt10/streams.landice
new file mode 100644
index 0000000000..ff5e4bd679
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt10/streams.landice
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt12/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt12/namelist.landice
new file mode 100644
index 0000000000..a5002b1a17
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt12/namelist.landice
@@ -0,0 +1,105 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'mask'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+ config_do_restart = .false.
+ config_start_time = '2015-01-01_00:00:00'
+! config_do_restart = .true.
+! config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ !config_stop_time = '2100-01-01_00:00:00'
+ config_run_duration = '0005-00-00_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 34
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt12/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt12/streams.landice
new file mode 100644
index 0000000000..d50e0989ee
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt12/streams.landice
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt5/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt5/namelist.landice
new file mode 100644
index 0000000000..3698ba0a4c
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt5/namelist.landice
@@ -0,0 +1,104 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'none'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+! config_do_restart = .false.
+! config_start_time = '2015-01-01_00:00:00'
+ config_do_restart = .true.
+ config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ config_stop_time = '2100-01-01_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 32
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt5/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt5/streams.landice
new file mode 100644
index 0000000000..5b650ceff9
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt5/streams.landice
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt6/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt6/namelist.landice
new file mode 100644
index 0000000000..1dd2920926
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt6/namelist.landice
@@ -0,0 +1,105 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'none'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+ config_do_restart = .false.
+ config_start_time = '2015-01-01_00:00:00'
+! config_do_restart = .true.
+! config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ !config_stop_time = '2100-01-01_00:00:00'
+ config_run_duration = '0005-00-00_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 34
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt6/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt6/streams.landice
new file mode 100644
index 0000000000..1e835f87f6
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt6/streams.landice
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt7/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt7/namelist.landice
new file mode 100644
index 0000000000..1dd2920926
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt7/namelist.landice
@@ -0,0 +1,105 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'none'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+ config_do_restart = .false.
+ config_start_time = '2015-01-01_00:00:00'
+! config_do_restart = .true.
+! config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ !config_stop_time = '2100-01-01_00:00:00'
+ config_run_duration = '0005-00-00_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 34
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt7/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt7/streams.landice
new file mode 100644
index 0000000000..502218e121
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt7/streams.landice
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt8/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt8/namelist.landice
new file mode 100644
index 0000000000..1dd2920926
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt8/namelist.landice
@@ -0,0 +1,105 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'none'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+ config_do_restart = .false.
+ config_start_time = '2015-01-01_00:00:00'
+! config_do_restart = .true.
+! config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ !config_stop_time = '2100-01-01_00:00:00'
+ config_run_duration = '0005-00-00_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 34
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt8/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt8/streams.landice
new file mode 100644
index 0000000000..6182231a37
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt8/streams.landice
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt9/namelist.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt9/namelist.landice
new file mode 100644
index 0000000000..1dd2920926
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt9/namelist.landice
@@ -0,0 +1,105 @@
+&velocity_solver
+ config_velocity_solver = 'FO'
+ config_unrealistic_velocity = 0.01592356685
+/
+
+&advection
+ config_thickness_advection = 'fo'
+ config_tracer_advection = 'none'
+/
+
+&thermal_solver
+ config_thermal_solver = 'none'
+ config_thermal_calculate_bmb = .true.
+ config_temperature_init = 'file'
+ config_surface_air_temperature_source = 'file'
+ config_basal_heat_flux_source = 'file'
+/
+
+&iceshelf_melt
+ config_basal_mass_bal_float = 'ismip6'
+/
+
+&calving
+ config_calving = 'none'
+ config_calving_topography = -500.0
+ config_calving_thickness = 100.0
+ config_calving_eigencalving_parameter_source = 'data'
+ config_calving_eigencalving_parameter_scalar_value = 3.5e16
+ config_data_calving = .false.
+ config_calving_timescale = 0.0
+ config_restore_calving_front = .true.
+ config_remove_icebergs = .true.
+ config_remove_small_islands = .true.
+/
+
+&physical_parameters
+ config_ice_density = 910.0
+ config_default_flowParamA = 3.1709792e-24
+ config_flowLawExponent = 3.0
+ !config_dynamic_thickness = 10.0
+ config_dynamic_thickness = 11.0
+ config_flowLawExponent = 3.0
+/
+
+&time_integration
+ config_dt = '0001-00-00_00:00:00'
+ config_time_integration = 'forward_euler'
+ config_adaptive_timestep = .true.
+ config_min_adaptive_timestep = 60.0
+ config_max_adaptive_timestep = 1.575e10
+ config_adaptive_timestep_CFL_fraction = 0.8
+ config_adaptive_timestep_include_DCFL = .false.
+ config_adaptive_timestep_force_interval = '0001-00-00_00:00:00'
+/
+
+&time_management
+ config_do_restart = .false.
+ config_start_time = '2015-01-01_00:00:00'
+! config_do_restart = .true.
+! config_start_time = 'file'
+ config_restart_timestamp_name = 'restart_timestamp'
+ !config_stop_time = '2100-01-01_00:00:00'
+ config_run_duration = '0005-00-00_00:00:00'
+ config_calendar_type = 'gregorian_noleap'
+/
+
+&io
+ config_write_output_on_startup = .true.
+ config_pio_num_iotasks = 200
+ config_pio_stride = 34
+ config_year_digits = 4
+/
+
+&decomposition
+ config_num_halos = 2
+ config_number_of_blocks = 0
+ config_explicit_proc_decomp = .false.
+ !config_block_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ !config_proc_decomp_file_prefix = 'weighted.graph.info.100to1.part.'
+ config_block_decomp_file_prefix = 'graph.info.part.'
+ config_proc_decomp_file_prefix = 'graph.info.part.'
+/
+
+&debug
+ config_print_thickness_advection_info = .true.
+ config_print_calving_info = .true.
+ config_print_thermal_info = .false.
+ config_always_compute_fem_grid = .false.
+ config_print_velocity_cleanup_details = .false.
+/
+
+&AM_globalStats
+ config_AM_globalStats_enable = .true.
+ config_AM_globalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_globalStats_compute_on_startup = .true.
+ config_AM_globalStats_write_on_startup = .true.
+/
+
+&AM_regionalStats
+ config_AM_regionalStats_enable = .true.
+ config_AM_regionalStats_compute_interval = '0000-00-00_01:00:00'
+ config_AM_regionalStats_compute_on_startup = .true.
+ config_AM_regionalStats_write_on_startup = .true.
+/
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt9/streams.landice b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt9/streams.landice
new file mode 100644
index 0000000000..2312210e21
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/expt9/streams.landice
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/interpolate_collapse_mask.py b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/interpolate_collapse_mask.py
new file mode 100755
index 0000000000..9818475afd
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/interpolate_collapse_mask.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+'''
+Interpolate fields from an input file to a pre-existing MPAS-LI grid.
+
+The input file can either be CISM format or MPASLI format.
+
+For CISM input files, three interpolation methods are supported:
+* a built-in bilinear interpolation method
+* a built-in barycentric interpolation method (nearest neighbor is used for extrapolation regions)
+* using weights generated by ESMF
+
+For MPAS input files only barycentric interpolation is supported.
+'''
+
+from __future__ import absolute_import, division, print_function, \
+ unicode_literals
+
+import sys
+import numpy as np
+import netCDF4
+from optparse import OptionParser
+import math
+from collections import OrderedDict
+import scipy.spatial
+import time
+from datetime import datetime
+
+
+print("== Gathering information. (Invoke with --help for more details. All arguments are optional)\n")
+parser = OptionParser()
+parser.description = __doc__
+parser.add_option("-s", "--source", dest="inputFile", help="name of source (input) file. NOTE: 8km and higher resolution fields are very blocky and unrealistic looking. It is better to use 16 or 32 km resolution where the fractional mask value is rounded to 0 or 1. This results in a smoother, more realistic-looking maski. 16km resolution appears to be the best compromise between fidelity to the original (pixely) data and smoothness.", metavar="FILENAME")
+parser.add_option("-d", "--destination", dest="mpasFile", help="name of destination file on which to interpolate fields.", metavar="FILENAME")
+parser.add_option("-i", "--initial", dest="icFile", help="initial condition file", metavar="FILENAME")
+for option in parser.option_list:
+ if option.default != ("NO", "DEFAULT"):
+ option.help += (" " if option.help else "") + "[default: %default]"
+options, args = parser.parse_args()
+
+print(" Source file: {}".format(options.inputFile))
+print(" Destination MPASLI file to be modified: {}".format(options.mpasFile))
+
+print('') # make a space in stdout before further output
+
+
+#----------------------------
+#----------------------------
+# Define needed functions
+#----------------------------
+#----------------------------
+
+#----------------------------
+
+def delaunay_interp_weights(xy, uv, d=2):
+ '''
+ xy = input x,y coords
+ uv = output (MPSALI) x,y coords
+ '''
+
+ #print("scipy version=", scipy.version.full_version)
+ if xy.shape[0] > 2**24-1:
+ print("WARNING: The source file contains more than 2^24-1 (16,777,215) points due to a limitation in older versions of Qhull (see: https://mail.scipy.org/pipermail/scipy-user/2015-June/036598.html). Delaunay creation may fail if Qhull being linked by scipy.spatial is older than v2015.0.1 2015/8/31.")
+
+ tri = scipy.spatial.Delaunay(xy)
+ print(" Delaunay triangulation complete.", flush=True)
+ simplex = tri.find_simplex(uv)
+ print(" find_simplex complete.", flush=True)
+ vertices = np.take(tri.simplices, simplex, axis=0)
+ print(" identified vertices.", flush=True)
+ temp = np.take(tri.transform, simplex, axis=0)
+ print(" np.take complete.", flush=True)
+ delta = uv - temp[:, d]
+ bary = np.einsum('njk,nk->nj', temp[:, :d, :], delta)
+ print(" calculating bary complete.", flush=True)
+ wts = np.hstack((bary, 1 - bary.sum(axis=1, keepdims=True)))
+
+ return vertices, wts
+
+#----------------------------
+
+def delaunay_interpolate(values):
+ vtx = vtx1; wts = wts1
+
+ outfield = np.einsum('nj,nj->n', np.take(values, vtx), wts)
+
+ return outfield
+
+
+#----------------------------
+#----------------------------
+
+
+
+
+print("==================")
+print('Gathering coordinate information from input and output files.')
+
+
+# Open the output file, get needed dimensions & variables
+try:
+ MPASfile = netCDF4.Dataset(options.mpasFile,'r+')
+ MPASfile.set_auto_mask(False)
+
+ # '2d' spatial fields on cell centers
+ xCell = MPASfile.variables['xCell'][:]
+ #print('xCell min/max:', xCell.min(), xCell.max()
+ yCell = MPASfile.variables['yCell'][:]
+ #print('yCell min/max:', yCell.min(), yCell.max()
+ nCells = len(MPASfile.dimensions['nCells'])
+
+except:
+ sys.exit('Error: The output grid file specified is either missing or lacking needed dimensions/variables.')
+print("==================\n")
+
+
+
+# Open the input file, get needed dimensions
+inputFile = netCDF4.Dataset(options.inputFile,'r')
+inputFile.set_auto_mask(False)
+
+# Figure out if this is CISM or MPAS
+if 'x1' in inputFile.variables:
+ filetype='cism'
+else:
+ sys.exit("ERROR: Unknown file type. ")
+
+if filetype=='cism':
+ # Get CISM location variables if they exist
+ try:
+ x1 = inputFile.variables['x1'][:]
+ dx1 = x1[1] - x1[0]
+ #print('x1 min/max/dx:', x1.min(), x1.max(), dx1
+ y1 = inputFile.variables['y1'][:]
+ dy1 = y1[1] - y1[0]
+ #print('y1 min/max/dx:', y1.min(), y1.max(), dy1
+
+ except:
+ print(' Input file is missing x1 and/or y1. Might not be a problem.')
+
+ # Check the overlap of the grids
+ print('==================')
+ print('Input File extents:')
+ print(' x1 min, max: {} {}'.format(x1.min(), x1.max()))
+ print(' y1 min, max: {} {}'.format(y1.min(), y1.max()))
+ print('MPAS File extents:')
+ print(' xCell min, max: {} {}'.format(xCell.min(), xCell.max()))
+ print(' yCell min, max: {} {}'.format(yCell.min(), yCell.max()))
+ print('==================')
+
+
+#----------------------------
+# Setup Delaunay/barycentric interpolation weights if needed
+mpasXY = np.vstack((xCell[:], yCell[:])).transpose()
+
+[Yi,Xi] = np.meshgrid(x1[:], y1[:])
+cismXY1 = np.zeros([Xi.shape[0]*Xi.shape[1],2])
+cismXY1[:,0] = Yi.flatten()
+cismXY1[:,1] = Xi.flatten()
+
+print('\nBuilding interpolation weights: CISM x1/y1 -> MPAS', flush=True)
+start = time.clock()
+vtx1, wts1 = delaunay_interp_weights(cismXY1, mpasXY)
+end = time.clock(); print('done in {}'.format(end-start), flush=True)
+
+
+# ------- get/create out field ---
+if 'calvingMask' in MPASfile.variables:
+ outMask = MPASfile.variables['calvingMask']
+else:
+ outMask = MPASfile.createVariable('calvingMask','i',('Time','nCells'))
+
+StrLen=64
+if 'xtime' in MPASfile.variables:
+ xtime = MPASfile.variables['xtime']
+else:
+ if not 'StrLen' in MPASfile.dimensions:
+ print("adding StrLen")
+ MPASfile.createDimension('StrLen', StrLen)
+ print("adding xtime")
+ xtime = MPASfile.createVariable('xtime','c', ('Time', 'StrLen'))
+
+
+# create initial extent mask
+fic = netCDF4.Dataset(options.icFile,'r')
+thk = fic.variables['thickness'][0,:]
+bed = fic.variables['bedTopography'][0,:]
+icMask = (thk==0.0) * (bed<0.0) # locate places where there is no ice and is ocean. Calving will be forced here.
+
+
+#----------------------------
+nt = len(inputFile.dimensions['time'])
+inMask = inputFile.variables['mask']
+
+startYear=1995
+for t in range(nt):
+ print('time={}'.format(t), flush=True)
+
+ start = time.clock()
+ interpMask = np.round(delaunay_interpolate(inMask[t,:,:]))
+ outMask[t,:] = np.maximum(interpMask, icMask)
+ end = time.clock(); print(' interpolation done in {}'.format(end-start))
+
+ time_string = "{:04}-01-01_00:00:00".format(t+startYear)
+ print(time_string)
+ MPASfile.variables['xtime'][t,:] = list(time_string.ljust(StrLen))
+
+ MPASfile.sync() # update the file now in case we get an error later
+
+
+# Update history attribute of netCDF file
+thiscommand = datetime.now().strftime("%a %b %d %H:%M:%S %Y") + ": " + " ".join(sys.argv[:])
+if hasattr(MPASfile, 'history'):
+ newhist = '\n'.join([thiscommand, getattr(MPASfile, 'history')])
+else:
+ newhist = thiscommand
+setattr(MPASfile, 'history', newhist )
+
+inputFile.close()
+MPASfile.close()
+
+print('\nInterpolation completed.')
diff --git a/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/zero_smb_on_icefree_areas.py b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/zero_smb_on_icefree_areas.py
new file mode 100644
index 0000000000..f43ea67798
--- /dev/null
+++ b/testing_and_setup/compass/landice/ISMIP6-AIS-Projections/zero_smb_on_icefree_areas.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# script to apply anomaly SMB field to our base SMB
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+import netCDF4
+import numpy as np
+
+fic = netCDF4.Dataset('/global/cscratch1/sd/hoffman2/ISMIP6/expt5-pio1/ais2km_100yr_spinup.nc','r')
+thk0 = fic.variables['thickness'][0,:]
+bed = fic.variables['bedTopography'][0,:]
+mask = (thk0>0) # only keep SMB where ice was originally
+fic.close()
+
+f = netCDF4.Dataset('SMB_NorESM_2.6_1995-2100.nc','r+')
+nt = len(f.dimensions['Time'])
+smb = f.variables['sfcMassBal']
+
+for i in range(nt):
+ print(i)
+
+ smb[i,:] = smb[i,:] * mask
+
+f.close()
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/README.mismip+ b/testing_and_setup/compass/landice/MISMIP+/README.mismip+
index 64c0a3c3f4..b4d5001bda 100644
--- a/testing_and_setup/compass/landice/MISMIP+/README.mismip+
+++ b/testing_and_setup/compass/landice/MISMIP+/README.mismip+
@@ -33,7 +33,7 @@ Go to your MPAS-Code directory. You should see a directory structure like this:
|–– [dome, EISMINT2, greenland, MISMIP3d, etc.]
|–– MISMIP+
|–– README.mismip+
- |–– albany_input.xml
+ |–– albany_input.yaml
|–– cull_cells_for_MISMIP.py
|–– mismip+PlotGL.py
|–– mismip+WriteGL.py
@@ -150,7 +150,7 @@ Note 2: Each subdirectory will have links to the graph.info.part files in the pa
Note 3: There is a namelist parameter called config_default_flowParamA.
However, this parameter does *not* determine the flow parameter for the higher-order model.
- To change this parameter, open the file .../MPAS-Code/test_cases/ocean/landice/MISMIP+/albany_input.xml
+ To change this parameter, open the file .../MPAS-Code/test_cases/ocean/landice/MISMIP+/albany_input.yaml
Scroll down to these lines:
@@ -161,7 +161,7 @@ Note 3: There is a namelist parameter called config_default_flowParamA.
Note 4: The MISMIP+ protocols allow one of three kinds of basal sliding law.
MPAS LI uses a Weertman-type power law (Eq. 6 of Asay-Davis et al.).
- This basal sliding law is set in albany_input.xml:
+ This basal sliding law is set in albany_input.yaml:
diff --git a/testing_and_setup/compass/landice/MISMIP+/albany_input.xml b/testing_and_setup/compass/landice/MISMIP+/albany_input.xml
deleted file mode 100644
index 3dcb722cdc..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/albany_input.xml
+++ /dev/null
@@ -1,241 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/MISMIP+/albany_input.yaml b/testing_and_setup/compass/landice/MISMIP+/albany_input.yaml
new file mode 100644
index 0000000000..5fcc329399
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP+/albany_input.yaml
@@ -0,0 +1,292 @@
+%YAML 1.1
+---
+ANONYMOUS:
+# In order to use ML, change Tpetra to Epetra in the following line,
+# and "Preconditioner Type: MueLu" to " Preconditioner Type: ML" several lines below
+ Build Type: Tpetra
+
+ Problem:
+ Dirichlet BCs:
+ SDBC on NS dirichlet for DOF U1 prescribe Field: dirichlet_field
+ LandIce BCs:
+ Number: 2
+ BC 0:
+ Cubature Degree: 5
+ Side Set Name: basalside
+ Type: Basal Friction
+ Basal Friction Coefficient:
+ Type: Power Law
+ Zero Beta On Floating Ice: true
+ Power Law Coefficient: 1.0
+ Power Exponent: 0.3333333333
+ Bed Roughness: 1.0
+ BC 1:
+ Cubature Degree: 5
+ Side Set Name: ice_margin_side
+ Type: Lateral
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+ 'Glen''s Law A': 2.0e-05
+ 'Glen''s Law n': 3.0
+
+# Discretization Description
+ Discretization:
+ Exodus Output File Name: albany_output.exo
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: MueLu
+ Preconditioner Types:
+
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
+
+ MueLu:
+ Matrix:
+ PDE equations: 2
+ Factories:
+ myLineDetectionFact:
+ factory: LineDetectionFactory
+ 'linedetection: orientation': coordinates
+ mySemiCoarsenPFact1:
+ factory: SemiCoarsenPFactory
+ 'semicoarsen: coarsen rate': 14
+ UncoupledAggregationFact2:
+ factory: UncoupledAggregationFactory
+ 'aggregation: ordering': graph
+ 'aggregation: max selected neighbors': 0
+ 'aggregation: min agg size': 3
+ 'aggregation: phase3 avoid singletons': true
+ MyCoarseMap2:
+ factory: CoarseMapFactory
+ Aggregates: UncoupledAggregationFact2
+ myTentativePFact2:
+ 'tentative: calculate qr': true
+ factory: TentativePFactory
+ Aggregates: UncoupledAggregationFact2
+ CoarseMap: MyCoarseMap2
+ mySaPFact2:
+ 'sa: eigenvalue estimate num iterations': 10
+ 'sa: damping factor': 1.33333e+00
+ factory: SaPFactory
+ P: myTentativePFact2
+ myTransferCoordinatesFact:
+ factory: CoordinatesTransferFactory
+ CoarseMap: MyCoarseMap2
+ Aggregates: UncoupledAggregationFact2
+ myTogglePFact:
+ factory: TogglePFactory
+ 'semicoarsen: number of levels': 2
+ TransferFactories:
+ P1: mySemiCoarsenPFact1
+ P2: mySaPFact2
+ Ptent1: mySemiCoarsenPFact1
+ Ptent2: myTentativePFact2
+ Nullspace1: mySemiCoarsenPFact1
+ Nullspace2: myTentativePFact2
+ myRestrictorFact:
+ factory: TransPFactory
+ P: myTogglePFact
+ myToggleTransferCoordinatesFact:
+ factory: ToggleCoordinatesTransferFactory
+ Chosen P: myTogglePFact
+ TransferFactories:
+ Coordinates1: mySemiCoarsenPFact1
+ Coordinates2: myTransferCoordinatesFact
+ myRAPFact:
+ factory: RAPFactory
+ P: myTogglePFact
+ R: myRestrictorFact
+ TransferFactories:
+ For Coordinates: myToggleTransferCoordinatesFact
+ myRepartitionHeuristicFact:
+ factory: RepartitionHeuristicFactory
+ A: myRAPFact
+ 'repartition: min rows per proc': 3000
+ 'repartition: max imbalance': 1.327e+00
+ 'repartition: start level': 1
+ myZoltanInterface:
+ factory: ZoltanInterface
+ A: myRAPFact
+ Coordinates: myToggleTransferCoordinatesFact
+ number of partitions: myRepartitionHeuristicFact
+ myRepartitionFact:
+ factory: RepartitionFactory
+ A: myRAPFact
+ Partition: myZoltanInterface
+ 'repartition: remap parts': true
+ number of partitions: myRepartitionHeuristicFact
+ myRebalanceProlongatorFact:
+ factory: RebalanceTransferFactory
+ type: Interpolation
+ P: myTogglePFact
+ Coordinates: myToggleTransferCoordinatesFact
+ Nullspace: myTogglePFact
+ myRebalanceRestrictionFact:
+ factory: RebalanceTransferFactory
+ type: Restriction
+ R: myRestrictorFact
+ myRebalanceAFact:
+ factory: RebalanceAcFactory
+ A: myRAPFact
+ TransferFactories: { }
+ mySmoother1:
+ factory: TrilinosSmoother
+ type: LINESMOOTHING_BANDEDRELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother3:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother4:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': pre
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 4
+ 'relaxation: damping factor': 1.0
+ Hierarchy:
+ max levels: 7
+ 'coarse: max size': 2000
+ verbosity: None
+ Finest:
+ Smoother: mySmoother1
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+ All:
+ startLevel: 1
+ Smoother: mySmoother4
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+
+ ML:
+ Base Method Defaults: none
+ ML Settings:
+ default values: SA
+ ML output: 0
+ 'repartition: enable': 1
+ 'repartition: max min ratio': 1.327e+00
+ 'repartition: min per proc': 600
+ 'repartition: Zoltan dimensions': 2
+ 'repartition: start level': 4
+ 'semicoarsen: number of levels': 2
+ 'semicoarsen: coarsen rate': 14
+ 'smoother: sweeps': 4
+ 'smoother: type': Gauss-Seidel
+ 'smoother: Chebyshev eig boost': 1.2e+00
+ 'smoother: sweeps (level 0)': 1
+ 'smoother: type (level 0)': line Gauss-Seidel
+ 'smoother: line GS Type': standard
+ 'smoother: damping factor': 1.0e+00
+ 'smoother: pre or post': both
+ 'coarse: type': Gauss-Seidel
+ 'coarse: sweeps': 4
+ 'coarse: max size': 2000
+ 'coarse: pre or post': pre
+ max levels: 7
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/cull_cells_for_MISMIP.py b/testing_and_setup/compass/landice/MISMIP+/cull_cells_for_MISMIP.py
index 082a1dd5cc..9804b0d14f 100755
--- a/testing_and_setup/compass/landice/MISMIP+/cull_cells_for_MISMIP.py
+++ b/testing_and_setup/compass/landice/MISMIP+/cull_cells_for_MISMIP.py
@@ -16,6 +16,8 @@
distances greater than, say, half of the range in x/y values of the entire mesh.
"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import sys
import netCDF4
import numpy as np
@@ -23,7 +25,7 @@
from optparse import OptionParser
-print "== Gathering information. (Invoke with --help for more details. All arguments are optional)"
+print("== Gathering information. (Invoke with --help for more details. All arguments are optional)")
parser = OptionParser()
parser.description = "This script takes an MPAS grid file and marks the edge rows and columns for culling, e.g., to remove periodicity."
parser.add_option("-f", "--file", dest="inFile", help="MPAS grid file name used as input.", default="grid.nc", metavar="FILENAME")
@@ -32,7 +34,7 @@
option.help += (" " if option.help else "") + "[default: %default]"
options, args = parser.parse_args()
-print '' # make a space in stdout before further output
+print('') # make a space in stdout before further output
# ===============================================
@@ -54,14 +56,14 @@
# For a periodic hex, the upper and lower rows need to be marked
# Plus an extra row along the top
unique_ys=np.array(sorted(list(set(yCell[:]))))
-print "Found ", len(unique_ys), " unique y values"
+print("Found {} unique y values".format(len(unique_ys)))
cullCell_local[np.nonzero(yCell == unique_ys[0])] = 1
cullCell_local[np.nonzero(yCell == unique_ys[1])] = 1
cullCell_local[np.nonzero(yCell == unique_ys[-1])] = 1
# For a periodidic hex the leftmost and rightmost *TWO* columns need to be marked
unique_Xs=np.array(sorted(list(set(xCell[:]))))
-print "Found ", len(unique_Xs), " unique x values"
+print("Found {} unique x values".format(len(unique_Xs)))
cullCell_local[np.nonzero(xCell == unique_Xs[0])] = 1
cullCell_local[np.nonzero(xCell == unique_Xs[1])] = 1
cullCell_local[np.nonzero(xCell == unique_Xs[-1])] = 1
@@ -71,4 +73,4 @@
fin.close()
-print "Marked cells for culling. Use MpasCellCuller.x to cull the cells."
+print("Marked cells for culling. Use MpasCellCuller.x to cull the cells.")
diff --git a/testing_and_setup/compass/landice/MISMIP+/mismip+PlotGL.py b/testing_and_setup/compass/landice/MISMIP+/mismip+PlotGL.py
index 5c8733e560..8101367e89 100755
--- a/testing_and_setup/compass/landice/MISMIP+/mismip+PlotGL.py
+++ b/testing_and_setup/compass/landice/MISMIP+/mismip+PlotGL.py
@@ -11,6 +11,8 @@
Modified by William Lipscomb
"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
@@ -36,7 +38,7 @@ def garplot(ncfile, label, color, marker):
try:
ncid = Dataset(ncfile, 'r')
except:
- print "Failed to open file: {}. Skipping.".format(ncfile)
+ print("Failed to open file: {}. Skipping.".format(ncfile))
return 0
gar = ncid.variables["groundedArea"][:]*1e-6*1e-3
time = ncid.variables["time"][:]
@@ -57,7 +59,7 @@ def glplot(ncfile, times, colora, label):
try:
ncid = Dataset(ncfile, 'r')
except:
- print "Failed to open file: {}. Skipping.".format(ncfile)
+ print("Failed to open file: {}. Skipping.".format(ncfile))
return 350.0, 500.0
time = ncid.variables["time"][:]
@@ -126,4 +128,4 @@ def glplot(ncfile, times, colora, label):
plt.savefig(plotname)
plt.close()
-print 'Created test plot', plotname
+print('Created test plot', plotname)
diff --git a/testing_and_setup/compass/landice/MISMIP+/mismip+ResolutionAnalysis.py b/testing_and_setup/compass/landice/MISMIP+/mismip+ResolutionAnalysis.py
index 4c84d564da..298938e169 100755
--- a/testing_and_setup/compass/landice/MISMIP+/mismip+ResolutionAnalysis.py
+++ b/testing_and_setup/compass/landice/MISMIP+/mismip+ResolutionAnalysis.py
@@ -8,6 +8,8 @@
by Matt Hoffman, modified from mismip+PlotGL.py script.
"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
@@ -27,10 +29,10 @@ def vafplot(resolution, color, marker):
time1r = ncid.variables["time"][:]
ncid.close()
except:
- print "Failed to open file: {}. Skipping.".format(fname)
+ print"Failed to open file: {}. Skipping.".format(fname))
vaf1r = []
time1r = []
-
+
# repeat for 1ra
fname = '{}/Ice1ra/Ice1ra{}.nc'.format(resolution, model)
label = "{}".format(resolution)
@@ -40,7 +42,7 @@ def vafplot(resolution, color, marker):
time1ra = ncid.variables["time"][:]
ncid.close()
except:
- print "Failed to open file: {}. Skipping.".format(fname)
+ print("Failed to open file: {}. Skipping.".format(fname))
vaf1ra = []
time1ra = []
@@ -53,7 +55,7 @@ def vafplot(resolution, color, marker):
time1rax = ncid.variables["time"][:]
ncid.close()
except:
- print "Failed to open file: {}. Skipping.".format(fname)
+ print("Failed to open file: {}. Skipping.".format(fname))
vaf1rax = []
time1rax = []
@@ -74,7 +76,7 @@ def glplot(ncfile, times, colora, label):
try:
ncid = Dataset(ncfile, 'r')
except:
- print "Failed to open file: {}. Skipping.".format(ncfile)
+ print("Failed to open file: {}. Skipping.".format(ncfile))
return 350.0, 500.0
time = ncid.variables["time"][:]
@@ -136,4 +138,4 @@ def glplot(ncfile, times, colora, label):
plt.show()
plt.close()
-print 'Created test plot', plotname
+print('Created test plot'+plotname)
diff --git a/testing_and_setup/compass/landice/MISMIP+/mismip+WriteGL.py b/testing_and_setup/compass/landice/MISMIP+/mismip+WriteGL.py
index b049461c7f..0f8f98ba40 100755
--- a/testing_and_setup/compass/landice/MISMIP+/mismip+WriteGL.py
+++ b/testing_and_setup/compass/landice/MISMIP+/mismip+WriteGL.py
@@ -7,7 +7,7 @@
The following input fields are needed to create the grounding-line file
(assuming GL points are tracked at cell edges)::
- Dimensions:
+ Dimensions:
nCells
nEdges
nVertLevels
@@ -18,7 +18,7 @@
cellsOnEdge
areaCell
layerThicknessFractions
-
+
Prognostic quantities:
edgeMask
cellMask
@@ -31,6 +31,8 @@
"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import os, sys
import numpy as np
import netCDF4
@@ -70,7 +72,7 @@
def xtime2numtime(xtime):
"""Define a function to convert xtime character array to numeric time values using datetime objects"""
- # First parse the xtime character array into a string
+ # First parse the xtime character array into a string
xtimestr = netCDF4.chartostring(xtime) # convert from the character array to an array of strings using the netCDF4 module's function
dt = []
@@ -82,14 +84,14 @@ def xtime2numtime(xtime):
dt.append( datetime.datetime(*results) ) # * notation passes in the array as arguments
# use the netCDF4 module's function for converting a datetime to a time number
- numtime = netCDF4.date2num(dt, units='seconds since '+str(dt[0]))
+ numtime = netCDF4.date2num(dt, units='seconds since '+str(dt[0]))
numtime /= (3600.0 * 24.0 * 365.0)
numtime -= numtime[0] # return years from start
return numtime
def xtimeGetYear(xtime):
"""Get an array of years from an xtime array, ignoring any partial year information"""
- # First parse the xtime character array into a string
+ # First parse the xtime character array into a string
xtimestr = netCDF4.chartostring(xtime) # convert from the character array to an array of strings using the netCDF4 module's function
years = np.zeros( (len(xtimestr),) )
for i in range(len(xtimestr)):
@@ -105,7 +107,7 @@ def glplot(ncfile, times, colora, label):
ncid = netCDF4.Dataset(ncfile, 'r')
ltime = ncid.variables["time"][:]
- print 'ltime:', ltime[:]
+ print('ltime: {}'.format(ltime[:]))
lxmax = 0.0
lxmin = 800.0
@@ -125,18 +127,18 @@ def glplot(ncfile, times, colora, label):
for expt in experiments:
- print '\n Looking for output file', outputFile, 'in directory', expt
+ print('\n Looking for output file {} in directory {}'.format(outputFile, expt))
try:
os.chdir(expt)
except:
- print 'Could not find a directory for this experiment. Skipping.'
+ print('Could not find a directory for this experiment. Skipping.')
continue
try:
ncfile = netCDF4.Dataset(outputFile, 'r')
except:
- print 'Could not find the output file in this directory. Skipping.'
+ print('Could not find the output file in this directory. Skipping.')
continue
# Get dimensions
@@ -162,7 +164,7 @@ def glplot(ncfile, times, colora, label):
bedTopography = ncfile.variables['bedTopography'][:,:]
uReconstructZonal = ncfile.variables['uReconstructZonal'][:,:,:]
uReconstructMeridional = ncfile.variables['uReconstructMeridional'][:,:,:]
-
+
# Get prognostic fields on edges
edgeMask = ncfile.variables['edgeMask'][:,:]
@@ -174,13 +176,13 @@ def glplot(ncfile, times, colora, label):
uMeanZonal[:,:] += layerThicknessFractions[k] * 0.5 * (uReconstructZonal[:,:,k] + uReconstructZonal[:,:,k+1])
uMeanMeridional[:,:] += layerThicknessFractions[k] * 0.5 * (uReconstructMeridional[:,:,k] + uReconstructMeridional[:,:,k+1])
- # Create GL file
+ # Create GL file
GLfile = expt + model + '.nc'
ncfile = netCDF4.Dataset(GLfile, 'w')
- print 'Creating output GL file', GLfile
+ print('Creating output GL file {}'.format(GLfile))
- # Set dimensions
+ # Set dimensions
glptdim = ncfile.createDimension('nPointGL', size = None)
timedim = ncfile.createDimension('nTime', size = nTime)
@@ -201,17 +203,17 @@ def glplot(ncfile, times, colora, label):
iceVAF = ncfile.createVariable('iceVAF', 'f4', ('nTime'))
groundedArea = ncfile.createVariable('groundedArea', 'f4', ('nTime'))
- iceVolume = np.zeros((nTime,))
- iceVAF = np.zeros((nTime,))
- groundedArea = np.zeros((nTime,))
+ iceVolume = np.zeros((nTime,))
+ iceVAF = np.zeros((nTime,))
+ groundedArea = np.zeros((nTime,))
- print 'Created output variables'
+ print('Created output variables')
# Loop over time slices
for iTime in range(nTime):
time[iTime] = years[iTime]
- print 'iTime, time =', iTime, time[iTime]
+ print('iTime={}, time={}'.format(iTime, time[iTime]))
# Loop over edges to gather GL info
nGL = 0
@@ -229,7 +231,7 @@ def glplot(ncfile, times, colora, label):
# find indices of adjacent cells
# subtract 1 from cellsOnEdge because indexing of cell-centered fields starts at 0
- iCell1 = cellsOnEdge[iEdge,0] - 1
+ iCell1 = cellsOnEdge[iEdge,0] - 1
iCell2 = cellsOnEdge[iEdge,1] - 1
xGL[m,iTime] = xEdge[iEdge]
@@ -264,13 +266,13 @@ def glplot(ncfile, times, colora, label):
else:
iceVAF[iTime] += areaCell[iCell] * thickness[iTime,iCell]
- if np.logical_and( (cellMask[iTime,iCell] & Icebit),
+ if np.logical_and( (cellMask[iTime,iCell] & Icebit),
( (cellMask[iTime,iCell] & Floatbit) != Floatbit) ): # ice is present and not floating
groundedArea[iTime] += areaCell[iCell]
- print 'ice volume (m^3) =', iceVolume[iTime]
- print 'ice VAF (m^3) =', iceVAF[iTime]
- print 'grounded area (m^2) =', groundedArea[iTime]
+ print('ice volume (m^3) = {}'.format(iceVolume[iTime]))
+ print('ice VAF (m^3) = {}'.format(iceVAF[iTime]))
+ print('grounded area (m^2) = {}'.format(roundedArea[iTime]))
ncfile.variables['iceVolume'][:] = iceVolume[:]
ncfile.variables['iceVAF'][:] = iceVAF[:]
@@ -282,11 +284,11 @@ def glplot(ncfile, times, colora, label):
# Make sure the grounded area is reasonable
ncfile = netCDF4.Dataset(GLfile, 'r')
groundedArea = ncfile.variables['groundedArea'][:]
- print 'groundedArea =', groundedArea[:]
+ print('groundedArea = {}'.format(groundedArea[:]))
ncfile.close()
# Create a test plot from the data in this file
- print 'Making plot from file', GLfile
+ print('Making plot from file' + GLfile)
if expt == 'Ice0' or expt == 'Ice1r' or expt == 'Ice2r':
timeList = [0, 20, 40, 60, 80, 100]
@@ -312,7 +314,7 @@ def glplot(ncfile, times, colora, label):
plt.savefig(plotname)
plt.clf()
- print 'Created test plot', plotname
+ print('Created test plot' + plotname)
# Change to parent directory to process the next experiment
os.chdir('..')
diff --git a/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_initial_conditions.py b/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_initial_conditions.py
index a9a7ccb2e5..6fcc63f52f 100755
--- a/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_initial_conditions.py
+++ b/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_initial_conditions.py
@@ -1,14 +1,18 @@
#!/usr/bin/env python
-#WHL - Based on MISMIP3D setup script by Matt Hoffman, modified for MISMIP+.
+"""
+This script sets up initial conditions for the MISMIP+ experiment.
+See this paper for details:
+ X. Asay-Davis et al. (2015), Experimental design for three interrelated
+ Marine Ice-Sheet and Ocean Model Intercomparison Projects, Geosci. Model Devel. Discuss.,
+ 8, 9859-9924.
+Following grid setup and initialization, the code should be spun up for ~10-20 ka
+ without basal melting, which should result in a stable grounding line
+ crossing the center of the channel around x = 450 km.
-# This script sets up initial conditions for the MISMIP+ experiment.
-# See this paper for details:
-# X. Asay-Davis et al. (2015), Experimental design for three interrelated
-# Marine Ice-Sheet and Ocean Model Intercomparison Projects, Geosci. Model Devel. Discuss.,
-# 8, 9859-9924.
-# Following grid setup and initialization, the code should be spun up for ~10-20 ka
-# without basal melting, which should result in a stable grounding line
-# crossing the center of the channel around x = 450 km.
+WHL - Based on MISMIP3D setup script by Matt Hoffman, modified for MISMIP+.
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys
from netCDF4 import Dataset
@@ -23,7 +27,7 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
# Open the file, get needed dimensions
@@ -35,7 +39,7 @@
maxEdges = len(gridfile.dimensions['maxEdges'])
#WHL- Maybe do production runs with fewer than 10 levels?
if nVertLevels != 10:
- print 'nVertLevels in the supplied file was ', nVertLevels, '. 10 levels is a preliminary value to be used with this test case.'
+ print('nVertLevels in the supplied file was {}. 10 levels is a preliminary value to be used with this test case.'.format(nVertLevels))
except:
sys.exit('Error: The grid file specified is missing needed dimensions.')
@@ -48,14 +52,14 @@
yCell = gridfile.variables['yCell'][:]
if yCell.min() > 0.0:
- print 'Shifting domain origin, because it appears that this has not yet been done.'
+ print('Shifting domain origin, because it appears that this has not yet been done.')
unique_xs = np.array(sorted(list(set(xCell[:]))))
unique_ys = np.array(sorted(list(set(yCell[:]))))
- print 'unique_ys.min:', unique_ys.min()
- print 'unique_ys.max:', unique_ys.max()
- print 'unique_xs.min:', unique_xs.min()
- print 'unique_xs.max:', unique_xs.max()
+ print('unique_ys.min: {}'.format(unique_ys.min()))
+ print('unique_ys.max: {}'.format(unique_ys.max()))
+ print('unique_xs.min: {}'.format(unique_xs.min()))
+ print('unique_xs.max: {}'.format(unique_xs.max()))
xShift = -1.0 * unique_xs.min()
yShift = -1.0 * unique_ys.min()
@@ -72,7 +76,7 @@
# Essentially, we only want to model the interior half of those cells.
# Adding this here because we only want to do this if it hasn't been done before.
# This method is assuming a periodic_hex mesh!
- print "Adjusting areaCell and dvEdge for cells along north and south boundaries"
+ print("Adjusting areaCell and dvEdge for cells along north and south boundaries")
# Adjust area in half for N/S boundary cells
unique_ys = np.array(sorted(list(set(yCell[:])))) # recalculate after above adjustment
@@ -111,11 +115,11 @@ def computeBed(x,y):
Bsum = B_x + B_y
B = np.maximum(Bsum, Bmax) # B >= Bmax
return B
-
+
# Create the required variables in the netCDF file.
# Set bedTopography (this variable should always be present in the input file)
-print "Defining bedTopography"
+print("Defining bedTopography")
# Compute the bed topography
bedTopography = np.zeros((nCells,))
@@ -132,7 +136,7 @@ def computeBed(x,y):
# Set the initial thickness
# Initial condition is uniform 100 m (except where x > xcalve)
-print "Defining thickness"
+print("Defining thickness")
xcalve = 640000.0 # m
init_thickness = 100.0 # m
thickness = np.zeros((nCells,))
@@ -147,7 +151,7 @@ def computeBed(x,y):
# Convert from m/yr to kg/m2/s using appropriate ice density.
# Assign a large negative SMB where x > xcalve, to prevent ice advancing.
-print "Defining SMB"
+print("Defining SMB")
SMB = np.zeros((nCells,))
rhoi = 918.0 # from Asay-Davis et al. (2016)
seconds_per_year = 3600.0 * 24.0 * 365.0
@@ -165,14 +169,14 @@ def computeBed(x,y):
# supporting a no-slip boundary condition.
if 'dirichletVelocityMask' in gridfile.variables:
- print 'dirichletVelocityMask already in gridfile'
+ print('dirichletVelocityMask already in gridfile')
kinbcmask = gridfile.variables['dirichletVelocityMask']
else:
- print 'dirichletVelocityMask not in gridfile; create new variable'
+ print('dirichletVelocityMask not in gridfile; create new variable')
datatype = gridfile.variables['xCell'].dtype # Get the datatype for double precision float
dirichletVelocityMask = gridfile.createVariable('dirichletVelocityMask', datatype, ('Time','nCells','nVertInterfaces'))
-print "Defining velocity boundary conditions"
+print("Defining velocity boundary conditions")
kinbcmask = np.zeros((nCells, nVertInterfaces))
kinbcmask[np.nonzero(yCell == yCell.min()), : ] = 1 # south row
kinbcmask[np.nonzero(yCell == yCell.max()), : ] = 1 # north row
@@ -182,16 +186,16 @@ def computeBed(x,y):
# Set the initial velocities to zero to enforce Dirichlet BC..
# May not be necessary, but doing this to be on the safe side.
if 'uReconstructX' in gridfile.variables:
- print 'uReconstructX already in gridfile'
+ print('uReconstructX already in gridfile')
else:
- print 'uReconstructX not in gridfile; create new variable'
+ print('uReconstructX not in gridfile; create new variable')
datatype = gridfile.variables['xCell'].dtype # Get the datatype for double precision float
uReconstructX = gridfile.createVariable('uReconstructX', datatype, ('Time','nCells'))
if 'uReconstructY' in gridfile.variables:
- print 'uReconstructY already in gridfile'
+ print('uReconstructY already in gridfile')
else:
- print 'uReconstructY not in gridfile; create new variable'
+ print('uReconstructY not in gridfile; create new variable')
datatype = gridfile.variables['xCell'].dtype # Get the datatype for double precision float
uReconstructY = gridfile.createVariable('uReconstructY', datatype, ('Time','nCells'))
@@ -199,28 +203,28 @@ def computeBed(x,y):
gridfile.variables['uReconstructY'][0,:] = 0.0
-# Set basal traction coefficient, beta.
-# For now, assume a Weertman-type power law, tau_b = C * u^(1/m), where C = beta.
+# Set basal traction coefficient. Now goes into field effectivePressure
+# For now, assume a Weertman-type power law, tau_b = C * u^(1/m), where C = effectivePressure.
# Asay-Davis et al. (2016) specify C = 3.160 x 10^6 Pa m^{-1/3} s^{1/3} for power-law friction,
# with friction-law exponent m = 3.
# Later, we could support a Tsai friction law.
-if 'beta' in gridfile.variables:
- print 'beta already in gridfile'
- kinbcmask = gridfile.variables['beta']
+if 'effectivePressure' in gridfile.variables:
+ print('effectivePressure already in gridfile')
+ effectivePressure = gridfile.variables['effectivePressure']
else:
- print 'beta not in gridfile; create new variable'
+ print('effectivePressure not in gridfile; create new variable')
datatype = gridfile.variables['xCell'].dtype # Get the datatype for double precision float
- beta = gridfile.createVariable('beta', datatype, ('Time','nCells'))
+ effectivePressure = gridfile.createVariable('effectivePressure', datatype, ('Time','nCells'))
+
+print("Defining effectivePressure")
+# For the Weertman power law, effectivePressure holds the 'C' coefficient. The effectivePressure units in MPAS are a bit confusing.
+# In the MISMIP3D setup script, C = 10^7 Pa m^-1/3 s^1/3 translates to effectivePressure = 31880. (actually, 31651.755)
+# For MISMIP+, C = 3.160 x 10^6 Pa m^-1/3 s^1/3 translates to effectivePressure = 10002.
-print "Defining beta"
-# For the Weertman power law, beta holds the 'C' coefficient. The beta units in MPAS are a mess right now.
-# In the MISMIP3D setup script, C = 10^7 Pa m^-1/3 s^1/3 translates to beta = 31880.
-# For MISMIP+, C = 3.160 x 10^6 Pa m^-1/3 s^1/3 translates to beta = 10002.
-
C = 3.160e6 # Pa m^{-1/3} s^{1/3}
C = C / seconds_per_year**(1.0/3.0) # convert to MPAS units
-gridfile.variables['beta'][0,:] = C
+gridfile.variables['effectivePressure'][0,:] = C
# Set up layerThicknessFractions
@@ -230,4 +234,4 @@ def computeBed(x,y):
gridfile.sync()
gridfile.close()
-print 'Successfully added MISMIP+ initial conditions to: ', options.filename
+print('Successfully added MISMIP+ initial conditions to: ' + options.filename)
diff --git a/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_subdirectories.py b/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_subdirectories.py
index 03a68182bb..154e96dd3d 100755
--- a/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_subdirectories.py
+++ b/testing_and_setup/compass/landice/MISMIP+/setup_mismip+_subdirectories.py
@@ -1,13 +1,16 @@
#!/usr/bin/env python
+"""
+Set up subdirectories for the various MISMIP+ experiments:
+Ice0, Ice1r, Ice1ra, Ice1rr, Ice1rax, Ice1rrx, Ice2r, Ice2ra, Ice2r, Ice2rax, Ice2rrx
+Note: Ice1rax is the optional extension of Ice1ra from year 200 to 1000,
+ and similarly for the other Ice*x experiments.
-# Set up subdirectories for the various MISMIP+ experiments:
-# Ice0, Ice1r, Ice1ra, Ice1rr, Ice1rax, Ice1rrx, Ice2r, Ice2ra, Ice2r, Ice2rax, Ice2rrx
-# Note: Ice1rax is the optional extension of Ice1ra from year 200 to 1000,
-# and similarly for the other Ice*x experiments.
+The namelist and streams files for each experiment should already
+have been created in the directory from which this script is launched;
+the script simply moves them to the subdirectories.
+"""
-# The namelist and streams files for each experiment should already
-# have been created in the directory from which this script is launched;
-# the script simply moves them to the subdirectories.
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys, os
import shutil
@@ -28,14 +31,14 @@
sys.exit('Error: No experiment specified. Please specify experiment(s) with the -x option')
-print 'Experiments:', experiments
+print('Experiments: {}'.format(experiments))
# Loop through experiments
for expt in experiments:
- print 'Setting up directory for experiment', expt
+ print('Setting up directory for experiment'+expt)
# Make the subdirectory if it does not exist already
- try:
+ try:
os.mkdir(expt)
except:
pass
@@ -71,7 +74,7 @@
os.symlink('../' + file, file)
# Link to the albany input file in the parent directory
- os.symlink('../' + 'albany_input.xml', 'albany_input.xml')
+ os.symlink('../' + 'albany_input.yaml', 'albany_input.yaml')
# Link to the appropriate restart file and timestamp
# No restart file needed for the Spinup experiment
@@ -92,7 +95,7 @@
# while removing the xtime variable
gridfile = 'landice_grid.nc'
griddir = '../Spinup/'
- os.symlink(griddir + gridfile, gridfile)
+ os.symlink(griddir + gridfile, gridfile)
else:
# Start from the appropriate restart file
if expt=='Ice1ra' or expt=='Ice1rr':
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_driver.xml b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_driver.xml
new file mode 100644
index 0000000000..7c73d964e5
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_driver.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_full_run_step.xml
new file mode 100644
index 0000000000..f328ee6d66
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_full_run_step.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0001-00-00_00:00:00
+ 0000-01-01_00:00:00
+
+
+ rst.$Y.$M.$D.nc
+ output_interval
+ 0001-00-00_00:00:00
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_restart_run_step.xml
new file mode 100644
index 0000000000..33a85c48ae
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_restart_run_step.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0001-00-00_00:00:00
+ truncate
+ 0000-01-01_00:00:00
+
+
+ rst.$Y.$M.$D.nc
+ output_interval
+ 0001-00-00_00:00:00
+
+
+
+
+
+
+ 0001-00-00_00:00:00
+ overwrite
+ 0000-01-01_00:00:00
+
+
+ rst.$Y.$M.$D.nc
+ output_interval
+ 0001-00-00_00:00:00
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_setup_mesh_step.xml
new file mode 100644
index 0000000000..48c7fdfc7f
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/config_setup_mesh_step.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+ -->
+ -->
+
+
+
+
+
+
+
+
+
+
+
+ 144
+ 24
+ 4618.802154
+
+
+
+
+ grid.nc
+
+
+
+
+ grid.nc
+ culled_grid.nc
+
+
+
+
+ culled_grid.nc
+ landice_grid.nc
+ 10
+
+
+
+
+
+
+
+ landice_grid.nc
+
+
+
+
+ 16
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/output_comparison.xml b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/output_comparison.xml
new file mode 100644
index 0000000000..6810dbc93a
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/restart_test/output_comparison.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/config_setup_experiments.xml b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/config_setup_experiments.xml
index 4c1e6aa4f6..69a351fa7a 100644
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/config_setup_experiments.xml
+++ b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/config_setup_experiments.xml
@@ -2,19 +2,13 @@
-
-
-
-
-
-->
-->
-
-
+
@@ -231,10 +225,38 @@
+
+
+
-
+
+ 284
+ 44
+ 2309.401077
@@ -243,18 +265,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -264,7 +286,7 @@
-
+
16
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input
deleted file mode 100644
index 7958e75213..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input
+++ /dev/null
@@ -1,21 +0,0 @@
-&periodic_grid
-! Notes for MISMIP+:
-! (1) We want ymax - ymin = 80 km for MISMIP+, where ymax and ymin are cell center coordinates.
-! Let dy be the spacing between cell centers in the y direction.
-! Then let ny = 80/dy + 4. For example, dy = 8 km => ny = 10 + 4 = 14.
-! The reason for the addition of 4 is that 3 horizontal rows will later be culled, and we will ignore
-! the two half-rows where y < ymin or y > ymax.
-! (2) To choose dc = the x distance between cell centers: Divide dy by sqrt(3)/2.
-! For example, dy = 8000 m ==> dc = 8000 m / (sqrt(3)/2) = 9237.604307 m.
-! (3) For MISMIP+, the cells should extend past x = 640 km.
-! Let nx = int(650/dc) + 3 where dc is in km. The extra 10 km gives some leeway,
-! and the addition of 3 accounts for the culling of 4 vertical rows.
-! (4) nVertLevels does not matter, since it will be redefined later.
-! (5) can set nproc = 1, since the mesh will need culling later to remove periodicity.
- dc = 2309.401077,
- nx = 284,
- ny = 44,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.1000m b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.1000m
deleted file mode 100644
index 3f906d3db2..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.1000m
+++ /dev/null
@@ -1,21 +0,0 @@
-&periodic_grid
-! Notes for MISMIP+:
-! (1) We want ymax - ymin = 80 km for MISMIP+, where ymax and ymin are cell center coordinates.
-! Let dy be the spacing between cell centers in the y direction.
-! Then let ny = 80/dy + 4. For example, dy = 8 km => ny = 10 + 4 = 14.
-! The reason for the addition of 4 is that 3 horizontal rows will later be culled, and we will ignore
-! the two half-rows where y < ymin or y > ymax.
-! (2) To choose dc = the x distance between cell centers: Divide dy by sqrt(3)/2.
-! For example, dy = 8000 m ==> dc = 8000 m / (sqrt(3)/2) = 9237.604307 m.
-! (3) For MISMIP+, the cells should extend past x = 640 km.
-! Let nx = int(650/dc) + 3 where dc is in km. The extra 10 km gives some leeway,
-! and the addition of 3 accounts for the culling of 4 vertical rows.
-! (4) nVertLevels does not matter, since it will be redefined later.
-! (5) can set nproc = 1, since the mesh will need culling later to remove periodicity.
- dc = 1154.700538,
- nx = 566,
- ny = 84,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.2000m b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.2000m
deleted file mode 100644
index 7958e75213..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.2000m
+++ /dev/null
@@ -1,21 +0,0 @@
-&periodic_grid
-! Notes for MISMIP+:
-! (1) We want ymax - ymin = 80 km for MISMIP+, where ymax and ymin are cell center coordinates.
-! Let dy be the spacing between cell centers in the y direction.
-! Then let ny = 80/dy + 4. For example, dy = 8 km => ny = 10 + 4 = 14.
-! The reason for the addition of 4 is that 3 horizontal rows will later be culled, and we will ignore
-! the two half-rows where y < ymin or y > ymax.
-! (2) To choose dc = the x distance between cell centers: Divide dy by sqrt(3)/2.
-! For example, dy = 8000 m ==> dc = 8000 m / (sqrt(3)/2) = 9237.604307 m.
-! (3) For MISMIP+, the cells should extend past x = 640 km.
-! Let nx = int(650/dc) + 3 where dc is in km. The extra 10 km gives some leeway,
-! and the addition of 3 accounts for the culling of 4 vertical rows.
-! (4) nVertLevels does not matter, since it will be redefined later.
-! (5) can set nproc = 1, since the mesh will need culling later to remove periodicity.
- dc = 2309.401077,
- nx = 284,
- ny = 44,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.4000m b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.4000m
deleted file mode 100644
index 13580cdc1a..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.4000m
+++ /dev/null
@@ -1,21 +0,0 @@
-&periodic_grid
-! Notes for MISMIP+:
-! (1) We want ymax - ymin = 80 km for MISMIP+, where ymax and ymin are cell center coordinates.
-! Let dy be the spacing between cell centers in the y direction.
-! Then let ny = 80/dy + 4. For example, dy = 8 km => ny = 10 + 4 = 14.
-! The reason for the addition of 4 is that 3 horizontal rows will later be culled, and we will ignore
-! the two half-rows where y < ymin or y > ymax.
-! (2) To choose dc = the x distance between cell centers: Divide dy by sqrt(3)/2.
-! For example, dy = 8000 m ==> dc = 8000 m / (sqrt(3)/2) = 9237.604307 m.
-! (3) For MISMIP+, the cells should extend past x = 640 km.
-! Let nx = int(650/dc) + 3 where dc is in km. The extra 10 km gives some leeway,
-! and the addition of 3 accounts for the culling of 4 vertical rows.
-! (4) nVertLevels does not matter, since it will be redefined later.
-! (5) can set nproc = 1, since the mesh will need culling later to remove periodicity.
- dc = 4618.802154,
- nx = 144,
- ny = 24,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.500m b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.500m
deleted file mode 100644
index a14a0e229e..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.500m
+++ /dev/null
@@ -1,21 +0,0 @@
-&periodic_grid
-! Notes for MISMIP+:
-! (1) We want ymax - ymin = 80 km for MISMIP+, where ymax and ymin are cell center coordinates.
-! Let dy be the spacing between cell centers in the y direction.
-! Then let ny = 80/dy + 4. For example, dy = 8 km => ny = 10 + 4 = 14.
-! The reason for the addition of 4 is that 3 horizontal rows will later be culled, and we will ignore
-! the two half-rows where y < ymin or y > ymax.
-! (2) To choose dc = the x distance between cell centers: Divide dy by sqrt(3)/2.
-! For example, dy = 8000 m ==> dc = 8000 m / (sqrt(3)/2) = 9237.604307 m.
-! (3) For MISMIP+, the cells should extend past x = 640 km.
-! Let nx = int(650/dc) + 3 where dc is in km. The extra 10 km gives some leeway,
-! and the addition of 3 accounts for the culling of 4 vertical rows.
-! (4) nVertLevels does not matter, since it will be redefined later.
-! (5) can set nproc = 1, since the mesh will need culling later to remove periodicity.
- dc = 577.350269,
- nx = 1129,
- ny = 164,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.8000m b/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.8000m
deleted file mode 100644
index 4caefdd19e..0000000000
--- a/testing_and_setup/compass/landice/MISMIP+/standard_resolution/standard_test/namelist.input.8000m
+++ /dev/null
@@ -1,21 +0,0 @@
-&periodic_grid
-! Notes for MISMIP+:
-! (1) We want ymax - ymin = 80 km for MISMIP+, where ymax and ymin are cell center coordinates.
-! Let dy be the spacing between cell centers in the y direction.
-! Then let ny = 80/dy + 4. For example, dy = 8 km => ny = 10 + 4 = 14.
-! The reason for the addition of 4 is that 3 horizontal rows will later be culled, and we will ignore
-! the two half-rows where y < ymin or y > ymax.
-! (2) To choose dc = the x distance between cell centers: Divide dy by sqrt(3)/2.
-! For example, dy = 8000 m ==> dc = 8000 m / (sqrt(3)/2) = 9237.604307 m.
-! (3) For MISMIP+, the cells should extend past x = 640 km.
-! Let nx = int(650/dc) + 3 where dc is in km. The extra 10 km gives some leeway,
-! and the addition of 3 accounts for the culling of 4 vertical rows.
-! (4) nVertLevels does not matter, since it will be redefined later.
-! (5) can set nproc = 1, since the mesh will need culling later to remove periodicity.
- dc = 9237.604307,
- nx = 73,
- ny = 14,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/albany_input.xml b/testing_and_setup/compass/landice/MISMIP3D/albany_input.xml
deleted file mode 100644
index cab6151f86..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/albany_input.xml
+++ /dev/null
@@ -1,236 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/MISMIP3D/albany_input.yaml b/testing_and_setup/compass/landice/MISMIP3D/albany_input.yaml
new file mode 100644
index 0000000000..2586b0e020
--- /dev/null
+++ b/testing_and_setup/compass/landice/MISMIP3D/albany_input.yaml
@@ -0,0 +1,292 @@
+%YAML 1.1
+---
+ANONYMOUS:
+# In order to use ML, change Tpetra to Epetra in the following line,
+# and "Preconditioner Type: MueLu" to " Preconditioner Type: ML" several lines below
+ Build Type: Tpetra
+
+ Problem:
+ Dirichlet BCs:
+ SDBC on NS dirichlet for DOF U1 prescribe Field: dirichlet_field
+ LandIce BCs:
+ Number: 2
+ BC 0:
+ Cubature Degree: 9
+ Side Set Name: basalside
+ Type: Basal Friction
+ Basal Friction Coefficient:
+ Type: Power Law
+ Zero Beta On Floating Ice: true
+ Power Law Coefficient: 1.0
+ Power Exponent: 0.3333333333
+ Bed Roughness: 1.0
+ BC 1:
+ Cubature Degree: 5
+ Side Set Name: ice_margin_side
+ Type: Lateral
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+ 'Glen''s Law A': 3.1536e-06
+ 'Glen''s Law n': 3.0
+
+# Discretization Description
+ Discretization:
+ Exodus Output File Name: albany_output.exo
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: MueLu
+ Preconditioner Types:
+
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
+
+ MueLu:
+ Matrix:
+ PDE equations: 2
+ Factories:
+ myLineDetectionFact:
+ factory: LineDetectionFactory
+ 'linedetection: orientation': coordinates
+ mySemiCoarsenPFact1:
+ factory: SemiCoarsenPFactory
+ 'semicoarsen: coarsen rate': 14
+ UncoupledAggregationFact2:
+ factory: UncoupledAggregationFactory
+ 'aggregation: ordering': graph
+ 'aggregation: max selected neighbors': 0
+ 'aggregation: min agg size': 3
+ 'aggregation: phase3 avoid singletons': true
+ MyCoarseMap2:
+ factory: CoarseMapFactory
+ Aggregates: UncoupledAggregationFact2
+ myTentativePFact2:
+ 'tentative: calculate qr': true
+ factory: TentativePFactory
+ Aggregates: UncoupledAggregationFact2
+ CoarseMap: MyCoarseMap2
+ mySaPFact2:
+ 'sa: eigenvalue estimate num iterations': 10
+ 'sa: damping factor': 1.33333e+00
+ factory: SaPFactory
+ P: myTentativePFact2
+ myTransferCoordinatesFact:
+ factory: CoordinatesTransferFactory
+ CoarseMap: MyCoarseMap2
+ Aggregates: UncoupledAggregationFact2
+ myTogglePFact:
+ factory: TogglePFactory
+ 'semicoarsen: number of levels': 2
+ TransferFactories:
+ P1: mySemiCoarsenPFact1
+ P2: mySaPFact2
+ Ptent1: mySemiCoarsenPFact1
+ Ptent2: myTentativePFact2
+ Nullspace1: mySemiCoarsenPFact1
+ Nullspace2: myTentativePFact2
+ myRestrictorFact:
+ factory: TransPFactory
+ P: myTogglePFact
+ myToggleTransferCoordinatesFact:
+ factory: ToggleCoordinatesTransferFactory
+ Chosen P: myTogglePFact
+ TransferFactories:
+ Coordinates1: mySemiCoarsenPFact1
+ Coordinates2: myTransferCoordinatesFact
+ myRAPFact:
+ factory: RAPFactory
+ P: myTogglePFact
+ R: myRestrictorFact
+ TransferFactories:
+ For Coordinates: myToggleTransferCoordinatesFact
+ myRepartitionHeuristicFact:
+ factory: RepartitionHeuristicFactory
+ A: myRAPFact
+ 'repartition: min rows per proc': 3000
+ 'repartition: max imbalance': 1.327e+00
+ 'repartition: start level': 1
+ myZoltanInterface:
+ factory: ZoltanInterface
+ A: myRAPFact
+ Coordinates: myToggleTransferCoordinatesFact
+ number of partitions: myRepartitionHeuristicFact
+ myRepartitionFact:
+ factory: RepartitionFactory
+ A: myRAPFact
+ Partition: myZoltanInterface
+ 'repartition: remap parts': true
+ number of partitions: myRepartitionHeuristicFact
+ myRebalanceProlongatorFact:
+ factory: RebalanceTransferFactory
+ type: Interpolation
+ P: myTogglePFact
+ Coordinates: myToggleTransferCoordinatesFact
+ Nullspace: myTogglePFact
+ myRebalanceRestrictionFact:
+ factory: RebalanceTransferFactory
+ type: Restriction
+ R: myRestrictorFact
+ myRebalanceAFact:
+ factory: RebalanceAcFactory
+ A: myRAPFact
+ TransferFactories: { }
+ mySmoother1:
+ factory: TrilinosSmoother
+ type: LINESMOOTHING_BANDEDRELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother3:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother4:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': pre
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 4
+ 'relaxation: damping factor': 1.0
+ Hierarchy:
+ max levels: 7
+ 'coarse: max size': 2000
+ verbosity: None
+ Finest:
+ Smoother: mySmoother1
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+ All:
+ startLevel: 1
+ Smoother: mySmoother4
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+
+ ML:
+ Base Method Defaults: none
+ ML Settings:
+ default values: SA
+ ML output: 0
+ 'repartition: enable': 1
+ 'repartition: max min ratio': 1.327e+00
+ 'repartition: min per proc': 600
+ 'repartition: Zoltan dimensions': 2
+ 'repartition: start level': 4
+ 'semicoarsen: number of levels': 2
+ 'semicoarsen: coarsen rate': 14
+ 'smoother: sweeps': 4
+ 'smoother: type': Gauss-Seidel
+ 'smoother: Chebyshev eig boost': 1.2e+00
+ 'smoother: sweeps (level 0)': 1
+ 'smoother: type (level 0)': line Gauss-Seidel
+ 'smoother: line GS Type': standard
+ 'smoother: damping factor': 1.0e+00
+ 'smoother: pre or post': both
+ 'coarse: type': Gauss-Seidel
+ 'coarse: sweeps': 4
+ 'coarse: max size': 2000
+ 'coarse: pre or post': pre
+ max levels: 7
+
diff --git a/testing_and_setup/compass/landice/MISMIP3D/cull_cells_for_MISMIP.py b/testing_and_setup/compass/landice/MISMIP3D/cull_cells_for_MISMIP.py
index 082a1dd5cc..76ec7c9d03 100755
--- a/testing_and_setup/compass/landice/MISMIP3D/cull_cells_for_MISMIP.py
+++ b/testing_and_setup/compass/landice/MISMIP3D/cull_cells_for_MISMIP.py
@@ -16,6 +16,8 @@
distances greater than, say, half of the range in x/y values of the entire mesh.
"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import sys
import netCDF4
import numpy as np
@@ -23,7 +25,7 @@
from optparse import OptionParser
-print "== Gathering information. (Invoke with --help for more details. All arguments are optional)"
+print("== Gathering information. (Invoke with --help for more details. All arguments are optional)")
parser = OptionParser()
parser.description = "This script takes an MPAS grid file and marks the edge rows and columns for culling, e.g., to remove periodicity."
parser.add_option("-f", "--file", dest="inFile", help="MPAS grid file name used as input.", default="grid.nc", metavar="FILENAME")
@@ -32,7 +34,7 @@
option.help += (" " if option.help else "") + "[default: %default]"
options, args = parser.parse_args()
-print '' # make a space in stdout before further output
+print('') # make a space in stdout before further output
# ===============================================
@@ -54,14 +56,14 @@
# For a periodic hex, the upper and lower rows need to be marked
# Plus an extra row along the top
unique_ys=np.array(sorted(list(set(yCell[:]))))
-print "Found ", len(unique_ys), " unique y values"
+print("Found "+str( len(unique_ys)) + " unique y values")
cullCell_local[np.nonzero(yCell == unique_ys[0])] = 1
cullCell_local[np.nonzero(yCell == unique_ys[1])] = 1
cullCell_local[np.nonzero(yCell == unique_ys[-1])] = 1
# For a periodidic hex the leftmost and rightmost *TWO* columns need to be marked
unique_Xs=np.array(sorted(list(set(xCell[:]))))
-print "Found ", len(unique_Xs), " unique x values"
+print("Found "+str(len(unique_Xs))+ " unique x values")
cullCell_local[np.nonzero(xCell == unique_Xs[0])] = 1
cullCell_local[np.nonzero(xCell == unique_Xs[1])] = 1
cullCell_local[np.nonzero(xCell == unique_Xs[-1])] = 1
@@ -71,4 +73,4 @@
fin.close()
-print "Marked cells for culling. Use MpasCellCuller.x to cull the cells."
+print("Marked cells for culling. Use MpasCellCuller.x to cull the cells.")
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_10000m.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_10000m.xml
index d9179f31f8..6784b573ac 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_10000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_10000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -27,8 +21,18 @@
+
-
+
+ 169
+ 14
+ 10000.0
@@ -37,18 +41,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -57,7 +61,7 @@
-
+
24
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_1000m.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_1000m.xml
index dcbb117107..99473dccfb 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_1000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_1000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -37,9 +31,19 @@
+
-
+
+ 1612
+ 120
+ 1000.0
@@ -48,18 +52,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +72,7 @@
-
+
48
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_2000m.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_2000m.xml
index 890e66f0bb..963a511e95 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_2000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_2000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -38,8 +32,18 @@
+
-
+
+ 812
+ 60
+ 2000.0
@@ -48,18 +52,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +72,7 @@
-
+
48
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_250m.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_250m.xml
index 8711e7bdcb..108b2d7fe6 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_250m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_250m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -38,8 +32,18 @@
+
-
+
+ 6420
+ 466
+ 250.0
@@ -48,18 +52,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +72,7 @@
-
+
48
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_5000m.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_5000m.xml
index 2a81958aec..794cf4769d 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_5000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_5000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -34,9 +28,19 @@
-
+
-
+
+ 328
+ 26
+ 5000.0
@@ -45,18 +49,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -65,7 +69,7 @@
-
+
48
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_500m.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_500m.xml
index d2da20fba4..52e8c4314b 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_500m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_500m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -38,8 +32,18 @@
+
-
+
+ 3216
+ 234
+ 500.0
@@ -48,18 +52,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +72,7 @@
-
+
48
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_P75.xml b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_P75.xml
index e5c104dd77..09449ef7b9 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_P75.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/config_P75.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.10000m b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.10000m
deleted file mode 100644
index d467253feb..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.10000m
+++ /dev/null
@@ -1,11 +0,0 @@
-&periodic_grid
-! MISMIP3D Elmer output uses 2.5 km spacing.
- dc = 10000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=81. Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 169,
-! Half domain is 50 km tall but we are not dealing with reflective boundaries, so our domain is 100 km tall. standard hex mesh has dy=0.866*dc. So ny=11.547. We want odd number for symmetry in N-S direction, so use 11. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 14,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.1000m b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.1000m
deleted file mode 100644
index 0cd68657e8..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.1000m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 1000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=800 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 1612,
-! Half domain is 50 km tall but we are not dealing with reflective boundaries, so our domain is 100 km tall. standard hex mesh has dy=0.866*dc. So ny=115.473. But we lose one cell height since the half of the north and south rows are oustide the domain. Need this number to be odd. Use 117 + 2 for stripping off periodicity +1 for culling to get symmetric mesh.
- ny = 120,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.2000m b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.2000m
deleted file mode 100644
index 033be9232b..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.2000m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 2000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=400 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 812,
-! Half domain is 50 km tall but we are not dealing with reflective boundaries, so our domain is 100 km tall. standard hex mesh has dy=0.866*dc. So ny=57.737. But need this number to be odd, so use 57 + 2 for stripping off periodicity +1 for culling to get symmetric mesh.
- ny = 60,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.250m b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.250m
deleted file mode 100644
index 6a58232749..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.250m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 250.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=3200 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 6420,
-! Half domain is 50 km tall but we are not dealing with reflective boundaries, so our domain is 100 km tall. standard hex mesh has dy=0.866*dc. So ny=461.89. But need this number to be odd, and one cell (two half cells) is effectively outside of the domain. So use 463 + 2 for stripping off periodicity +1 for culling to get symmetric mesh. To give effective domain width of 100023m.
- ny = 466,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.5000m b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.5000m
deleted file mode 100644
index a497208aa9..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.5000m
+++ /dev/null
@@ -1,11 +0,0 @@
-&periodic_grid
-! MISMIP3D Elmer output uses 2.5 km spacing.
- dc = 5000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=161 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 328,
-! Half domain is 50 km tall but we are not dealing with reflective boundaries, so our domain is 100 km tall. standard hex mesh has dy=0.866*dc. So ny=23.09. We want odd number for symmetry in N-S direction, so use 23. Use 23 + 2 for stripping off periodicity + 1 for removal to get symmetric mesh.
- ny = 26,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.500m b/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.500m
deleted file mode 100644
index b9b49eb9b7..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/full_width/Stnd/namelist.input.500m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 500.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=3200 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 3216,
-! Half domain is 50 km tall but we are not dealing with reflective boundaries, so our domain is 100 km tall. standard hex mesh has dy=0.866*dc. So ny=230.9. But need this number to be odd, so use 231 + 2 for stripping off periodicity +1 for culling to get symmetric mesh.
- ny = 234,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_10000m.xml b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_10000m.xml
index 7335b7af9a..129f1ae0a7 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_10000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_10000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -28,7 +22,10 @@
-
+
+ 169
+ 6
+ 10000.0
@@ -37,18 +34,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -57,7 +54,7 @@
-
+
8
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_1000m.xml b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_1000m.xml
index 3b7d901806..0785e4801f 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_1000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_1000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -39,7 +33,10 @@
-
+
+ 1612
+ 6
+ 1000.0
@@ -48,18 +45,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +65,7 @@
-
+
96
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_2000m.xml b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_2000m.xml
index 890e66f0bb..52fa4ff048 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_2000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_2000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -39,7 +33,10 @@
-
+
+ 812
+ 6
+ 2000.0
@@ -48,18 +45,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +65,7 @@
-
+
48
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_250m.xml b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_250m.xml
index 6166596b45..5920a99cf8 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_250m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_250m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -39,7 +33,10 @@
-
+
+ 6420
+ 6
+ 250.0
@@ -48,18 +45,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +65,7 @@
-
+
392
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_5000m.xml b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_5000m.xml
index 7013c56ae3..e6b7ac05bc 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_5000m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_5000m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -39,7 +33,10 @@
-
+
+ 328
+ 6
+ 5000.0
@@ -48,18 +45,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +65,7 @@
-
+
16
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_500m.xml b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_500m.xml
index eb8ee2bc9e..8f62961273 100644
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_500m.xml
+++ b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/config_500m.xml
@@ -2,17 +2,11 @@
-
-
-
-
-
-
-
+
@@ -39,7 +33,10 @@
-
+
+ 3216
+ 6
+ 500.0
@@ -48,18 +45,18 @@
-
+
grid.nc
culled_grid.nc
-
+
culled_grid.nc
landice_grid.nc
10
-
+
@@ -68,7 +65,7 @@
-
+
160
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.10000m b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.10000m
deleted file mode 100644
index fac6770334..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.10000m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 10000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=81. Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 169,
-! Want an odd number of cells, minimal = 3. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 6,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.1000m b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.1000m
deleted file mode 100644
index 8f65a2a36a..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.1000m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 1000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=800 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 1612,
-! Want an odd number of cells, minimal = 3. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 6,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.2000m b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.2000m
deleted file mode 100644
index 86fa4c4d03..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.2000m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 2000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=400 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 812,
-! Want an odd number of cells, minimal = 3. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 6,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.250m b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.250m
deleted file mode 100644
index 25942110aa..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.250m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 250.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=3200 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 6420,
-! Want an odd number of cells, minimal = 3. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 6,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.5000m b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.5000m
deleted file mode 100644
index 349467acb7..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.5000m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 5000.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=161 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 328,
-! Want an odd number of cells, minimal = 3. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 6,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.500m b/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.500m
deleted file mode 100644
index 352ef1c814..0000000000
--- a/testing_and_setup/compass/landice/MISMIP3D/minimal_width/Stnd/namelist.input.500m
+++ /dev/null
@@ -1,10 +0,0 @@
-&periodic_grid
- dc = 500.,
-! Domain is 800 km wide, standard hex mesh has dx=dc. so nx=3200 Double to get both halves. +2 for stripping off periodicity. Add a few more to be sure we go past 800 km.
- nx = 3216,
-! Want an odd number of cells, minimal = 3. + 2 for stripping off periodicity + 1 for stripping off a non-symmetric cell.
- ny = 6,
- nVertLevels = 1,
-! The mesh will need culling to remove periodicity, so no need to build decomps now.
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/MISMIP3D/plot_GL_Stnd_MISMIP3D.py b/testing_and_setup/compass/landice/MISMIP3D/plot_GL_Stnd_MISMIP3D.py
index 59947c29d2..9176416006 100755
--- a/testing_and_setup/compass/landice/MISMIP3D/plot_GL_Stnd_MISMIP3D.py
+++ b/testing_and_setup/compass/landice/MISMIP3D/plot_GL_Stnd_MISMIP3D.py
@@ -1,14 +1,13 @@
#!/usr/bin/env python
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import numpy as np
import netCDF4
import datetime
-# import math
-# from pylab import *
from optparse import OptionParser
import matplotlib.pyplot as plt
import fnmatch, os
-# from matplotlib.contour import QuadContourSet
-# import time
template = "output-mask*.nc"
GLbit = 256
@@ -25,13 +24,13 @@
options, args = parser.parse_args()
if options.filename:
- print "Using single file:", options.filename
+ print("Using single file:"+options.filename)
filelist = (options.filename,)
else:
- print "No filename provided. Using template."
+ print("No filename provided. Using template.")
filelist = fnmatch.filter(os.listdir('.'), template)
filelist.sort() # sort this cause the list will be in arbitrary order
-print "List of files to process:", filelist
+print("List of files to process: {}".format(filelist))
#if not options.variable:
# parser.error("Variable is a required input.")
@@ -83,10 +82,10 @@ def xtimeGetYear(xtime):
GLposAll = np.zeros((1,4))
for filename in filelist:
- print "Processing file:", filename
+ print("Processing file:"+filename)
f = netCDF4.Dataset(filename,'r')
-
+
xtime = f.variables['xtime'][:]
#years = xtime2numtime(xtime)
years = xtimeGetYear(xtime)
@@ -102,23 +101,22 @@ def xtimeGetYear(xtime):
#upperSurface = f.variables['upperSurface'][time_slice,:]
#surfaceSpeed = f.variables['surfaceSpeed'][time_slice,:]
#basalSpeed = f.variables['basalSpeed'][time_slice,:]
- #floatingEdges = f.variables['floatingEdges'][time_slice,:]
edgeMask = f.variables['edgeMask'] # just get the object
#normalVelocity = f.variables['normalVelocity']
#uReconstructX = f.variables['uReconstructX']
#uReconstructX = f.variables['uReconstructX']
#uReconstructY = f.variables['uReconstructY']
-
+
vert_levs = len(f.dimensions['nVertLevels'])
nt = len(f.dimensions['Time'])
-
+
# print "nx = ", nx, " ny = ", ny
- print "vert_levs = ", vert_levs, " time_length = ", nt
-
+ print("vert_levs = {}, time_length = {}".format(vert_levs, nt))
+
GLpos = np.zeros((nt,4)) # time, min, mean, max. This array is just this file.
for t in range(nt):
GLpos[t,0] = years[t]
- GLind = np.nonzero( np.logical_and( ( (edgeMask[t,:] & GLbit) / GLbit == 1), (xEdge > 0.0) ) )
+ GLind = np.nonzero( np.logical_and( ( (edgeMask[t,:] & GLbit) // GLbit == 1), (xEdge > 0.0) ) )
#print 'Time, GL position values', years[t], xEdge[GLind]
if len(GLind[0]) > 0:
GLpos[t,1] = xEdge[GLind].min() / 1000.0
@@ -133,7 +131,7 @@ def xtimeGetYear(xtime):
fig = plt.figure(1, facecolor='w')
ax = fig.add_subplot(111)
# Calculate GL position
-print "Final GL position (time, min, mean, max):", GLpos[-1,:]
+print("Final GL position (time, min, mean, max): {}".format( GLpos[-1,:]))
plt.plot(GLposAll[:,0], GLposAll[:,1], ':b')
plt.plot(GLposAll[:,0], GLposAll[:,2], '-bo')
@@ -152,14 +150,14 @@ def xtimeGetYear(xtime):
plt.draw()
if options.saveimages:
- print "Saving figures to files."
+ print("Saving figures to files.")
plt.savefig('GL-position.png')
if options.hidefigs:
- print "Plot display disabled with -n argument."
+ print("Plot display disabled with -n argument.")
else:
plt.show()
diff --git a/testing_and_setup/compass/landice/MISMIP3D/plot_Perturbation_MISMIP3d.py b/testing_and_setup/compass/landice/MISMIP3D/plot_Perturbation_MISMIP3d.py
index 5e97b73200..30eb45be3b 100755
--- a/testing_and_setup/compass/landice/MISMIP3D/plot_Perturbation_MISMIP3d.py
+++ b/testing_and_setup/compass/landice/MISMIP3D/plot_Perturbation_MISMIP3d.py
@@ -4,6 +4,8 @@
'''
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import numpy as np
import netCDF4
from optparse import OptionParser
@@ -25,7 +27,7 @@
# =====================
# First plot: GL in plan view
-print "=== Beginning plan view GL plot ==="
+print("=== Beginning plan view GL plot ===")
ax1 = fig.add_subplot(211)
# dictionary describing what's what for each run
@@ -49,10 +51,10 @@
edgeMask = f.variables['edgeMask'][t,:]
xtime = f.variables['xtime'][:]
- print "For run ", run, " using file ", results[run]['fname'], " and time=", "".join(xtime[t,:])
+ print("For run " + run + " using file " + results[run]['fname'] + " and time=" + "".join(xtime[t,:]))
GLindEast = np.nonzero( np.logical_and(
- (edgeMask[:] & GLbit) / GLbit == 1,
+ (edgeMask[:] & GLbit) // GLbit == 1,
xEdge > 0.0 ) )[0]
#plt.plot(xEdge[GLindEast] / 1000.0, yEdge[GLindEast] / 1000.0, '*', color=color) # to just plot the edge locations
for i in range(len(GLindEast)):
@@ -74,7 +76,7 @@
# =====================
# Second plot: GL position time series at two points
-print "=== Beginning GL time series plot ==="
+print("=== Beginning GL time series plot ===")
ax2 = fig.add_subplot(212)
# Find the y-position at the wall - assume it is the same for S and R files
@@ -82,7 +84,7 @@
yEdge = f.variables['yEdge'][:]
unique_yEdge = np.array(sorted(list(set(yEdge[:]))))
wallY = unique_yEdge[-2] # get the second to last location. Last one will be 'outside' the domain
-print "For wall yEdge using value:", wallY
+print("For wall yEdge using value: {}".format(wallY))
f.close()
# Build dictionary
@@ -108,13 +110,13 @@
year = 100.0 - year
nt = len(f.dimensions['Time'])
- print "For run ", run, " using file ", results[run]['fname'], " and yEdge value ", yValue
+ print("For run " + run + " using file " + results[run]['fname'] + " and yEdge value " + str( yValue))
GLx = np.zeros( (nt,) )
for t in range(nt):
edgeMask = f.variables['edgeMask'][t,:]
GLindEast = np.nonzero( np.logical_and( np.logical_and(
- (edgeMask[:] & GLbit) / GLbit == 1,
+ (edgeMask[:] & GLbit) // GLbit == 1,
xEdge > 0.0 ),
yEdge == yValue) )[0] # should only be 1 index
GLx[t] = xEdge[GLindEast]
diff --git a/testing_and_setup/compass/landice/MISMIP3D/plot_speed_profiles.py b/testing_and_setup/compass/landice/MISMIP3D/plot_speed_profiles.py
index c80394afc3..f89ab5b2fd 100755
--- a/testing_and_setup/compass/landice/MISMIP3D/plot_speed_profiles.py
+++ b/testing_and_setup/compass/landice/MISMIP3D/plot_speed_profiles.py
@@ -2,19 +2,16 @@
'''
Plots velocity profiles for a diagnostic solve for a range of resolutions, with and without GLP.
'''
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import numpy as np
import netCDF4
-#import datetime
-# import math
-# from pylab import *
from optparse import OptionParser
import matplotlib.pyplot as plt
from matplotlib import cm
-# from matplotlib.contour import QuadContourSet
-# import time
reslist = (10000, 5000, 2000, 1000, 500, 250)
-GLbit = 256
secInYr = 3600.0 * 24.0 * 365.0 # Note: this may be slightly wrong for some calendar types!
parser = OptionParser()
@@ -26,11 +23,11 @@
options, args = parser.parse_args()
if not options.filename:
- print "No filename provided. Using output.nc."
+ print("No filename provided. Using output.nc.")
options.filename = "output.nc"
if not options.time:
- print "No time provided. Using time 0."
+ print("No time provided. Using time 0.")
time_slice = 0
else:
time_slice = int(options.time)
@@ -66,12 +63,12 @@ def get_data(filename):
res = reslist[i]
# no glp first
fname = "{}m.nc".format(res)
- print "Processing file", fname
+ print("Processing file"+fname)
x, u = get_data(fname)
plt.plot(x, u, '.-', color=colors[i], label="{}m, no GLP".format(res))
# glp next
fname = "{}m-glp.nc".format(res)
- print "Processing file", fname
+ print("Processing file"+fname)
x, u = get_data(fname)
plt.plot(x, u, '.--', color=colors[i], label="{}m, GLP".format(res))
@@ -82,14 +79,14 @@ def get_data(filename):
plt.legend()
plt.draw()
if options.saveimages:
- print "Saving figures to files."
+ print("Saving figures to files.")
plt.savefig('GL-position.png')
if options.hidefigs:
- print "Plot display disabled with -n argument."
+ print("Plot display disabled with -n argument.")
else:
plt.show()
diff --git a/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_initial_conditions.py b/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_initial_conditions.py
index 2cdfa4749e..7d17099f01 100755
--- a/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_initial_conditions.py
+++ b/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_initial_conditions.py
@@ -1,6 +1,10 @@
#!/usr/bin/env python
-# This script sets up MISMIP3D Stnd experiment.
-# see http://homepages.ulb.ac.be/~fpattyn/mismip3d/Mismip3Dv12.pdf
+"""
+This script sets up MISMIP3D Stnd experiment.
+see http://homepages.ulb.ac.be/~fpattyn/mismip3d/Mismip3Dv12.pdf
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys
from netCDF4 import Dataset
@@ -15,7 +19,7 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
# Open the file, get needed dimensions
@@ -26,7 +30,7 @@
nVertInterfaces = nVertLevels + 1
maxEdges = len(gridfile.dimensions['maxEdges'])
if nVertLevels != 10:
- print 'nVerLevels in the supplied file was ', nVertLevels, '. 10 levels is a preliminary value to be used with this test case.'
+ print('nVerLevels in the supplied file was {}. 10 levels is a preliminary value to be used with this test case.'.format(nVertLevels))
except:
sys.exit('Error: The grid file specified is missing needed dimensions.')
@@ -37,17 +41,17 @@
xCell = gridfile.variables['xCell'][:]
yCell = gridfile.variables['yCell'][:]
if yCell.min() > 0.0:
- print 'Shifting domain origin, because it appears that this has not yet been done.'
+ print('Shifting domain origin, because it appears that this has not yet been done.')
unique_ys=np.array(sorted(list(set(yCell[:]))))
targety = (unique_ys.max() - unique_ys.min()) / 2.0 + unique_ys.min() # center of domain range
best_y=unique_ys[ np.absolute((unique_ys - targety)) == np.min(np.absolute(unique_ys - (targety))) ][0]
- print 'Found a best y value to use of:' + str(best_y)
-
+ print( 'Found a best y value to use of:' + str(best_y))
+
unique_xs=np.array(sorted(list(set(xCell[:]))))
targetx = (unique_xs.max() - unique_xs.min()) / 2.0 + unique_xs.min() # center of domain range
best_x=unique_xs[ np.absolute((unique_xs - targetx)) == np.min(np.absolute(unique_xs - (targetx))) ][0]
- print 'Found a best x value to use of:' + str(best_x)
-
+ print('Found a best x value to use of:' + str(best_x))
+
xShift = -1.0 * best_x
yShift = -1.0 * best_y
gridfile.variables['xCell'][:] = xCell + xShift
@@ -62,7 +66,7 @@
# Need to adjust geometry along top and bottom boundaries to get flux correct there
# Essentially, we only want to model the interior half of those cells
# Adding this here because we only want to do this if it hasn't been done before.
- print "Adjusting areaCell and dvEdge for cells along north and south boundaries"
+ print("Adjusting areaCell and dvEdge for cells along north and south boundaries")
# This method is assuming a periodic_hex mesh!
@@ -85,14 +89,14 @@
# print np.array(sorted(list(set(yCell[:]))))
# bed slope defined by b(m)=-100km-x(km)
-print "Defining bed topography."
+print("Defining bed topography.")
topg = np.zeros((1,nCells,))
topg[0,np.nonzero(xCell>=0.0)]= -100.0 - xCell[np.nonzero(xCell>=0.0)]/1000.0
topg[0,np.nonzero(xCell<0.0)] = -100.0 + xCell[np.nonzero(xCell< 0.0)]/1000.0
gridfile.variables['bedTopography'][:] = topg[:]
# SMB
-print "Defining SMB."
+print("Defining SMB.")
SMB = np.zeros((1,nCells,))
# 0.5 m/yr is the standard value. 0.3 m/yr is also tested in MISMIP3D.
# Convert from units of m/yr to kg/m2/s using appropriate ice density
@@ -103,7 +107,7 @@
gridfile.variables['sfcMassBal'][:] = SMB[:]
# Thickness initial condition is no ice.
-print "Defining thickness."
+print("Defining thickness.")
thickness = np.zeros((nCells,))
thicknessICtype = 1 # 1=uniform, 2=b.l. solution
@@ -125,10 +129,10 @@
# calculations:
ind = np.logical_and(xCell>=0.0, xCell<=xg) # indices where xCell is between divide and GL
unique_xs=np.array(sorted(list(set(xCell[ind])), reverse=True)) # returns a list of x values from GL to divide (descending)
- print unique_xs
+ #print( unique_xs)
# i0 = np.nonzero(xCell == 0.0)[0][0] # index at divide
hg = rhow/rhoi * -1.0*(-100.0 - xg/1000.0) # thickness at GL
- print 'xg, hg=', xg, hg
+ print('xg={}, hg={}'.format(xg, hg))
ig = np.nonzero(np.logical_or(xCell >= xg, xCell <= -xg))[0] # indices at GL cells and shelf cells
thickness[ig] = hg/2.0 # make shelf thickness same as GL halved - this is reasonably close to the shelf thickness at SS and avoids large velocities (and small CFL time step limits if using the full GL thickness)
@@ -156,7 +160,7 @@
# For now approximate boundary conditions with 0 velocity.
-print "Defining velocity boundary conditions."
+print("Defining velocity boundary conditions.")
# This is not correct.
# west boundary should be dh/dx=ds/dx=0.
# north and south boundaries should be no slip lateral boundaries.
@@ -171,9 +175,9 @@
gridfile.variables['uReconstructY'][:] = 0.0
# beta is not correct
-print "Defining beta."
+print("Defining effectivePressure.")
#gridfile.variables['beta'][:] = 1.0e7 / 3.14e7**(1.0/m) # For the basal friction law being used, beta holds the 'C' coefficient in Pa m^-1/3 s^1/3
-gridfile.variables['beta'][:] = 31880.0 # For the basal friction law being used, beta holds the 'C' coefficient. The beta units in MPAS are a mess right now. This value translates to 10^7 Pa m^-1/3 s^1/3
+gridfile.variables['effectivePressure'][:] = 31880.0 # For the power-law basal friction law being used, effectivePressure holds the 'C' coefficient. This value translates to units of 10^7 Pa m^-1/3 s^1/3. Note that it should actually be 31651.755, but we've already done the experiments with 31880.0
# Setup layerThicknessFractions
gridfile.variables['layerThicknessFractions'][:] = 1.0 / float(nVertLevels)
@@ -181,5 +185,5 @@
gridfile.sync()
gridfile.close()
-print 'Successfully added MISMIP3D initial conditions to: ', options.filename
+print('Successfully added MISMIP3D initial conditions to: ' + options.filename)
diff --git a/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_perturb_domain.py b/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_perturb_domain.py
index 4bcac80354..4722ee6920 100755
--- a/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_perturb_domain.py
+++ b/testing_and_setup/compass/landice/MISMIP3D/setup_mismip3d_perturb_domain.py
@@ -7,6 +7,7 @@
see http://homepages.ulb.ac.be/~fpattyn/mismip3d/Mismip3Dv12.pdf
'''
+from __future__ import absolute_import, division, print_function, unicode_literals
GLbit = 256
@@ -32,7 +33,7 @@
if not options.outfilename:
sys.exit('ERROR: outfile required.')
if not options.restartfilename:
- print 'WARNING: No restart file specified. So uReconstructX will not be written.'
+ print('WARNING: No restart file specified. So uReconstructX will not be written.')
if not options.perturb:
sys.exit('ERROR: Perturbation amount required. Specify with -p')
@@ -102,7 +103,7 @@
unique_xs = np.array(sorted(list(set(xCell[:]))))
if np.absolute(dcEdge.max() - dcEdgeStnd.max()) > 0.01 or np.absolute(dcEdge.min() - dcEdgeStnd.min()) > 0.01: # use a tolerance here (in m)
- print "dcEdge maxes, mins:", dcEdge.max(),dcEdgeStnd.max(), dcEdge.min(), dcEdgeStnd.min()
+ print("dcEdge maxes, mins: {}, {}, {}, {}".format(dcEdge.max(), dcEdgeStnd.max(), dcEdge.min(), dcEdgeStnd.min() ) )
sys.exit('ERROR: The two files are not the same resolution')
if nCellsStnd == nCells:
@@ -111,20 +112,20 @@
eqSize = True
else:
if len(unique_ysStnd) != 3:
- print "unique yCell:", unique_ysStnd
+ print("unique yCell: {}".format(unique_ysStnd))
sys.exit('ERROR: This Stnd file appears to be a minimal width domain but it does not have 3 unique y values.')
eqSize = False # Assume we have a 3 cell wide minimal width domain
-print "DOMAIN INFORMATION"
-print "Stnd file y-range:", yCellStnd.max() - yCellStnd.min()
-print "Perturb file y-range:", yCell.max() - yCell.min()
-print "Stnd nCells:", nCellsStnd
-print "Perturb file nCells:", nCells
-print "Stnd file unique y-values on cells:", unique_ysStnd
-print "Perturbfile unique y-values on cells:", unique_ys
+print("DOMAIN INFORMATION")
+print("Stnd file y-range: {}, {}".format(yCellStnd.max() - yCellStnd.min()))
+print("Perturb file y-range: {}, {}".format(yCell.max() - yCell.min() ))
+print("Stnd nCells:".format(nCellsStnd))
+print("Perturb file nCells: {}".format(nCells))
+print("Stnd file unique y-values on cells: {}".format(unique_ysStnd))
+print("Perturbfile unique y-values on cells: {}".format(unique_ys))
-print "Defining thickness."
+print("Defining thickness.")
thickness = np.zeros((nCells,))
if eqSize:
thickness = thicknessStnd
@@ -139,12 +140,12 @@
for i in range(nCells):
ind = np.where(unique_xsStnd == xCell[i])[0]
thickness[i] = thkStndProfile[ind]
-# write it out
-gridfile.variables['thickness'][0,:] = thickness[:]
+# write it out
+gridfile.variables['thickness'][0,:] = thickness[:]
gridfile.sync()
if haveVelo:
- print "Defining uReconstructX."
+ print("Defining uReconstructX.")
if nVertLevelsStnd != nVertLevels:
sys.exit("ERROR: nVertLevels in the Stnd file does not match that in the full width domain.")
uX = np.zeros((nCells, nVertLevels+1))
@@ -152,49 +153,49 @@
uX = uXStnd
else:
for z in range(nVertLevels+1): # Note: there probably is a more efficient way to do this since the mapping should be the same for every level
- print "Mapping uReconstructX for level:", z
+ print("Mapping uReconstructX for level: {}".format(z))
# Need to map the minimal domain to the full domain
uXStndProfile = np.zeros((len(unique_xsStnd),))
for i in range(len(unique_xsStnd)):
ind = np.where(xCellStnd == unique_xsStnd[i])[0] # this should return either 1 or2 values
uXStndProfile[i] = uXStnd[ind, z].mean() # mean takes care of the places where there are two values - though they should be nearly identical
-
+
# Now assign the correct uX to each cell of the new file
for i in range(nCells):
ind = np.where(unique_xsStnd == xCell[i])[0]
uX[i, z] = uXStndProfile[ind]
- # write it out
- gridfile.variables['uReconstructX'][0,:] = uX[:]
+ # write it out
+ gridfile.variables['uReconstructX'][0,:] = uX[:]
gridfile.sync()
else:
- print "Skipping uReconstructX because it is not in the input file. You can use ncks to append it to your Stnd file from a restart file."
+ print("Skipping uReconstructX because it is not in the input file. You can use ncks to append it to your Stnd file from a restart file.")
-print "Determining grounding line position."
+print("Determining grounding line position.")
# Calculate GL position in Stnd output file
if eqSize:
GLindEast = np.nonzero(
np.logical_and( (
- (edgeMaskStnd[:] & GLbit) / GLbit == 1),
+ (edgeMaskStnd[:] & GLbit) // GLbit == 1),
(xEdgeStnd > 0.0)
) )[0]
GLindWest = np.nonzero(
np.logical_and( (
- (edgeMaskStnd[:] & GLbit) / GLbit == 1),
+ (edgeMaskStnd[:] & GLbit) // GLbit == 1),
(xEdgeStnd < 0.0)
) )[0]
else:
if len(unique_ysEdgeStnd) != 7:
sys.exit("ERROR: There are not 7 unique yEdge values in the Stnd file but this appears to be a minimal width domain.")
- print "Stnd file unique y-values on edges:", unique_ysEdgeStnd
+ print("Stnd file unique y-values on edges: {}".format(unique_ysEdgeStnd))
# First do east side
GLindEast = np.nonzero(
- np.logical_and(
- (edgeMaskStnd[:] & GLbit) / GLbit == 1,
+ np.logical_and(
+ (edgeMaskStnd[:] & GLbit) // GLbit == 1,
xEdgeStnd > 0.0) ) [0]
- print "GL indices east:", GLindEast
- print "at positions:", yEdgeStnd[GLindEast]
+ print("GL indices east: {}".format(GLindEast))
+ print("at positions: {}".format(yEdgeStnd[GLindEast]))
if len(GLindEast) != 5:
sys.exit("ERROR: East: There are not 5 unique yEdge GL values in the Stnd file but this appears to be a minimal width domain.")
# Note that the topmost and bottommost edge positions are effectively outside the domain,
@@ -203,30 +204,30 @@
# Note that "positions" 0 and 4 are both returned and should be identical, but only one of them should be used.
# However we shouldn't assume that the indices are ordered by increasing yEdge (though in periodic_hex they are).
# For now we are assuming these are periodic_hex meshes!
- print "East: All GL indices, their yEdge values:", GLindEast, yEdgeStnd[ GLindEast ]
+ print("East: All GL indices, their yEdge values: {}, {}".format(GLindEast, yEdgeStnd[ GLindEast ]))
GLindEast = GLindEast[ [0,1,2,3] ]
- print "East: Using yEdge values from Stnd:", yEdgeStnd[GLindEast]
- print "East: All possible yEdge values from Stnd:", unique_ysEdgeStnd
+ print("East: Using yEdge values from Stnd: {}".format(yEdgeStnd[GLindEast]))
+ print("East: All possible yEdge values from Stnd:".format(unique_ysEdgeStnd))
# Now do west side
GLindWest = np.nonzero(
np.logical_and(
- (edgeMaskStnd[:] & GLbit) / GLbit == 1,
+ (edgeMaskStnd[:] & GLbit) // GLbit == 1,
xEdgeStnd < 0.0) ) [0]
if len(GLindWest) != 5:
sys.exit("ERROR: West: There are not 5 unique yEdge GL values in the Stnd file but this appears to be a minimal width domain.")
GLindWest = GLindWest[ [0,1,2,3] ]
- print "West: Using yEdge values from Stnd:", yEdgeStnd[GLindEast]
- print "West: All possible yEdge values from Stnd:", unique_ysEdgeStnd
+ print("West: Using yEdge values from Stnd: {}".format(yEdgeStnd[GLindEast]))
+ print("West: All possible yEdge values from Stnd:".format(unique_ysEdgeStnd))
GLposEast = xEdgeStnd[GLindEast].mean()
GLposWest = xEdgeStnd[GLindWest].mean()
-print "Calculated GL x-positions (m). East:", GLposEast, " West:", GLposWest
-print "WARNING: The GL position calculation may be incorrect for meshes generated by a tool other than periodic_hex!!!"
+print("Calculated GL x-positions (m). East: {}, West: {}".format(GLposEast, GLposWest))
+print("WARNING: The GL position calculation may be incorrect for meshes generated by a tool other than periodic_hex!!!")
-print "Defining beta."
+print("Defining beta.")
# The beta units in MPAS are a mess right now. This value 10^7 Pa m^-1/3 s^1/3 translates to 31880 in the current MPAS units.
-# For the basal friction law being used, beta holds the 'C' coefficient.
+# For the basal friction law being used, beta holds the 'C' coefficient.
xc = 150000.0
yc = 10000.0
a = float(options.perturb) / 100.0
@@ -240,6 +241,6 @@
gridfile.sync()
gridfile.close()
-print " ======="
-print 'Successfully added MISMIP3D perturbation initial conditions to: ', options.filename
-print "Please set up graph.info, albany_input.xml, namelist, and streams files as desired! namelist and streams are set up by test case here: full_width/Stnd/P75"
+print(" =======")
+print('Successfully added MISMIP3D perturbation initial conditions to: '+options.filename)
+print("Please set up graph.info, albany_input.yaml, namelist, and streams files as desired! namelist and streams are set up by test case here: full_width/Stnd/P75")
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/1km_varres_jigsaw/standard_configuration/config_setup_experiments.xml b/testing_and_setup/compass/landice/Thwaites_variability/1km_varres_jigsaw/standard_configuration/config_setup_experiments.xml
index 0a79fa2074..706b58ea89 100644
--- a/testing_and_setup/compass/landice/Thwaites_variability/1km_varres_jigsaw/standard_configuration/config_setup_experiments.xml
+++ b/testing_and_setup/compass/landice/Thwaites_variability/1km_varres_jigsaw/standard_configuration/config_setup_experiments.xml
@@ -2,24 +2,16 @@
-
-
-
-
-
-
-
-
-
+
-
+
-
+
@@ -44,39 +36,39 @@
-
+
thwaites_jigsaw_netcdf.nc
mpas.nc
-
+
mpas.nc
ais-bedmap2
-
+
mpas.nc
thwaites_mask.nc
thwaites_minimal.geojson
-
+
mpas.nc
culled_grid.nc
thwaites_mask.nc
-
+
culled_grid.nc
culled_grid_converted.nc
-
+
culled_grid_converted.nc
thwaites_1-8km_resolution.nc
10
@@ -86,14 +78,14 @@
-
+
ais_input_data.nc
thwaites_1-8km_resolution.nc
d
-
+
thwaites_1-8km_resolution.nc
@@ -103,7 +95,7 @@
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_driver.xml b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_driver.xml
new file mode 100644
index 0000000000..c2a6119226
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_driver.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_full_run_step.xml
new file mode 100644
index 0000000000..4184920b8a
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_full_run_step.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0000-00-01_00:00:00
+ 0001-01-01_00:00:00
+
+
+ rst.$Y-$M-$D.nc
+ output_interval
+ 0001-00-01_00:00:00
+ 0001-01-01_00:00:00
+
+
+
+
+
+
+
+ thwaites.4km.nc
+
+
+ 12
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_restart_run_step.xml
new file mode 100644
index 0000000000..4dbcf985b8
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/config_restart_run_step.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0000-00-01_00:00:00
+ overwrite
+ 0001-01-01_00:00:00
+
+
+ rst.$Y-$M-$D.nc
+ output_interval
+ 0000-00-01_00:00:00
+ 0001-01-01_00:00:00
+
+
+
+
+
+
+
+ thwaites.4km.nc
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/output_comparison.xml b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/output_comparison.xml
new file mode 100644
index 0000000000..98dafbb95e
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/restart_test/output_comparison.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/standard_configuration/config_setup_model_step.xml b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/standard_configuration/config_setup_model_step.xml
index 11f717d998..e73ac20b20 100644
--- a/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/standard_configuration/config_setup_model_step.xml
+++ b/testing_and_setup/compass/landice/Thwaites_variability/4km_varres/standard_configuration/config_setup_model_step.xml
@@ -3,13 +3,12 @@
-
+
-
-
+
@@ -29,10 +28,10 @@
thwaites.4km.nc
-
+
16
-
+
32
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/albany_input.xml b/testing_and_setup/compass/landice/Thwaites_variability/albany_input.xml
deleted file mode 100644
index 9f38c4d816..0000000000
--- a/testing_and_setup/compass/landice/Thwaites_variability/albany_input.xml
+++ /dev/null
@@ -1,228 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/albany_input.yaml b/testing_and_setup/compass/landice/Thwaites_variability/albany_input.yaml
new file mode 100644
index 0000000000..e021dd1c6f
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/albany_input.yaml
@@ -0,0 +1,266 @@
+%YAML 1.1
+---
+ANONYMOUS:
+# In order to use ML, change Tpetra to Epetra in the following line,
+# and "Preconditioner Type: MueLu" to " Preconditioner Type: ML" several lines below
+ Build Type: Tpetra
+
+# Discretization Description
+ Discretization:
+ Exodus Output File Name: albany_output.exo
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: MueLu
+ Preconditioner Types:
+
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
+
+ MueLu:
+ Matrix:
+ PDE equations: 2
+ Factories:
+ myLineDetectionFact:
+ factory: LineDetectionFactory
+ 'linedetection: orientation': coordinates
+ mySemiCoarsenPFact1:
+ factory: SemiCoarsenPFactory
+ 'semicoarsen: coarsen rate': 14
+ UncoupledAggregationFact2:
+ factory: UncoupledAggregationFactory
+ 'aggregation: ordering': graph
+ 'aggregation: max selected neighbors': 0
+ 'aggregation: min agg size': 3
+ 'aggregation: phase3 avoid singletons': true
+ MyCoarseMap2:
+ factory: CoarseMapFactory
+ Aggregates: UncoupledAggregationFact2
+ myTentativePFact2:
+ 'tentative: calculate qr': true
+ factory: TentativePFactory
+ Aggregates: UncoupledAggregationFact2
+ CoarseMap: MyCoarseMap2
+ mySaPFact2:
+ 'sa: eigenvalue estimate num iterations': 10
+ 'sa: damping factor': 1.33333e+00
+ factory: SaPFactory
+ P: myTentativePFact2
+ myTransferCoordinatesFact:
+ factory: CoordinatesTransferFactory
+ CoarseMap: MyCoarseMap2
+ Aggregates: UncoupledAggregationFact2
+ myTogglePFact:
+ factory: TogglePFactory
+ 'semicoarsen: number of levels': 2
+ TransferFactories:
+ P1: mySemiCoarsenPFact1
+ P2: mySaPFact2
+ Ptent1: mySemiCoarsenPFact1
+ Ptent2: myTentativePFact2
+ Nullspace1: mySemiCoarsenPFact1
+ Nullspace2: myTentativePFact2
+ myRestrictorFact:
+ factory: TransPFactory
+ P: myTogglePFact
+ myToggleTransferCoordinatesFact:
+ factory: ToggleCoordinatesTransferFactory
+ Chosen P: myTogglePFact
+ TransferFactories:
+ Coordinates1: mySemiCoarsenPFact1
+ Coordinates2: myTransferCoordinatesFact
+ myRAPFact:
+ factory: RAPFactory
+ P: myTogglePFact
+ R: myRestrictorFact
+ TransferFactories:
+ For Coordinates: myToggleTransferCoordinatesFact
+ myRepartitionHeuristicFact:
+ factory: RepartitionHeuristicFactory
+ A: myRAPFact
+ 'repartition: min rows per proc': 3000
+ 'repartition: max imbalance': 1.327e+00
+ 'repartition: start level': 1
+ myZoltanInterface:
+ factory: ZoltanInterface
+ A: myRAPFact
+ Coordinates: myToggleTransferCoordinatesFact
+ number of partitions: myRepartitionHeuristicFact
+ myRepartitionFact:
+ factory: RepartitionFactory
+ A: myRAPFact
+ Partition: myZoltanInterface
+ 'repartition: remap parts': true
+ number of partitions: myRepartitionHeuristicFact
+ myRebalanceProlongatorFact:
+ factory: RebalanceTransferFactory
+ type: Interpolation
+ P: myTogglePFact
+ Coordinates: myToggleTransferCoordinatesFact
+ Nullspace: myTogglePFact
+ myRebalanceRestrictionFact:
+ factory: RebalanceTransferFactory
+ type: Restriction
+ R: myRestrictorFact
+ myRebalanceAFact:
+ factory: RebalanceAcFactory
+ A: myRAPFact
+ TransferFactories: { }
+ mySmoother1:
+ factory: TrilinosSmoother
+ type: LINESMOOTHING_BANDEDRELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother3:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother4:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': pre
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 4
+ 'relaxation: damping factor': 1.0
+ Hierarchy:
+ max levels: 7
+ 'coarse: max size': 2000
+ verbosity: None
+ Finest:
+ Smoother: mySmoother1
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+ All:
+ startLevel: 1
+ Smoother: mySmoother4
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+
+ ML:
+ Base Method Defaults: none
+ ML Settings:
+ default values: SA
+ ML output: 0
+ 'repartition: enable': 1
+ 'repartition: max min ratio': 1.327e+00
+ 'repartition: min per proc': 600
+ 'repartition: Zoltan dimensions': 2
+ 'repartition: start level': 4
+ 'semicoarsen: number of levels': 2
+ 'semicoarsen: coarsen rate': 14
+ 'smoother: sweeps': 4
+ 'smoother: type': Gauss-Seidel
+ 'smoother: Chebyshev eig boost': 1.2e+00
+ 'smoother: sweeps (level 0)': 1
+ 'smoother: type (level 0)': line Gauss-Seidel
+ 'smoother: line GS Type': standard
+ 'smoother: damping factor': 1.0e+00
+ 'smoother: pre or post': both
+ 'coarse: type': Gauss-Seidel
+ 'coarse: sweeps': 4
+ 'coarse: max size': 2000
+ 'coarse: pre or post': pre
+ max levels: 7
+
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/calculate_gl_slope.py b/testing_and_setup/compass/landice/Thwaites_variability/calculate_gl_slope.py
new file mode 100755
index 0000000000..bcb1284035
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/calculate_gl_slope.py
@@ -0,0 +1,327 @@
+#!/usr/bin/env python
+'''
+Script to compare some scalar values from different runs of Thwaites melt variability experiment.
+'''
+
+
+# Parse options
+from optparse import OptionParser
+parser = OptionParser()
+parser.add_option("-p", dest="process", action="store_true", help="read and process data", metavar="FILE")
+options, args = parser.parse_args()
+
+
+import sys
+import os
+import netCDF4
+import datetime
+import numpy as np
+import matplotlib.pyplot as plt
+import scipy.signal
+from matplotlib import cm
+import pickle
+
+
+outfname = 'output.nc'
+runs=[ adir for adir in sorted(os.listdir('.')) if (os.path.isdir(adir) and os.path.isfile(os.path.join(adir, outfname)))]
+print "Original run list:", runs
+#runs = [ 'steady', 'amp300_per20_pha0.00','amp300_per20_pha0.25', 'amp300_per20_pha0.50', 'amp300_per20_pha0.75']
+runs = ['steady','amp300_per20_pha0.00']
+runs = ['steady']
+runs = ['amp300_per20_pha0.00']
+# reorder to put the 'control' runs at the beginning
+special_runs = ('steady', 'no-melt')
+for r in special_runs:
+ if r in runs:
+ runs.remove(r)
+ runs.insert(0, r)
+print "Will process the following directories: ", runs
+
+# ----- needed functions ----
+def xtime2numtimeMy(xtime):
+ """Define a function to convert xtime character array to numeric time values using local arithmetic"""
+ # First parse the xtime character array into a string
+ xtimestr = netCDF4.chartostring(xtime) # convert from the character array to an array of strings using the netCDF4 module's function
+
+ numtime = np.zeros( (len(xtimestr),) )
+ ii = 0
+ dayOfMonthStart = [1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
+ for stritem in xtimestr:
+ itemarray = stritem.strip().replace('_', '-').replace(':', '-').split('-') # Get an array of strings that are Y,M,D,h,m,s
+ results = [int(i) for i in itemarray]
+ numtime[ii] = results[0] + (dayOfMonthStart[results[1]-1]-1 + results[2]) / 365.0 # decimal year
+ ii += 1
+ return numtime
+
+
+# --- Define data structures ---
+
+class modelRun:
+ def __init__(self, run):
+ '''
+ This reads results from a model run and saves and analyzes the needed results.
+
+ run = name of subdir in which the run was performed
+ '''
+
+ # some metadata about run
+ if 'amp' in run:
+ self.amp = float(run[3:6])
+ self.per = float(run[10:12])
+ self.pha = float(run[16:])
+ else:
+ self.amp = 0.0
+ self.per = 0.0
+ self.pha = 0.0
+
+ #print self.amp, self.per, self.pha
+
+ f = netCDF4.Dataset(run + '/' + outfname, 'r')
+ self.nt = len(f.dimensions['Time'])
+ self.yrs = np.zeros((self.nt,))
+ #yrs = f.variables['daysSinceStart'][:] / 365.0
+ self.xtimes = f.variables['xtime'][:]
+
+
+ self.yrs = xtime2numtimeMy(self.xtimes)
+ self.dyrs = self.yrs[1:] - self.yrs[0:-1]
+
+
+ xCell = f.variables['xCell'][:]
+ yCell = f.variables['yCell'][:]
+ xEdge = f.variables['xEdge'][:]
+ yEdge = f.variables['yEdge'][:]
+ conc= f.variables['cellsOnCell'][:,:]
+ cone= f.variables['cellsOnEdge'][:,:]
+ dcEdge = f.variables['dcEdge'][:]
+ areaCell = f.variables['areaCell'][:]
+ topg = f.variables['bedTopography'][0,:]
+
+ nt = len(f.dimensions['Time'])
+
+ self.time = np.zeros((nt,))
+ self.mnGLslope = np.zeros((nt,))
+ self.GA = np.zeros((nt,))
+ self.mnGLmelt = np.zeros((nt,))
+ self.mnGLdepthMPASMethod = np.zeros((nt,))
+ self.mnGLdepth = np.zeros((nt,))
+ self.mnCFmelt = np.zeros((nt,))
+ self.mnGLbedslope = np.zeros((nt,))
+ self.mnGLxpos = np.zeros((nt,))
+
+ spdThresh = 100.0/3.14e7
+ spdThresh = 900.0/3.14e7
+ for t in range(nt):
+# for t in np.arange(0,nt,10):
+# for t in np.arange(0,284,1):
+ print t
+ usrf = f.variables['upperSurface'][t,:]
+ edgeMask = f.variables['edgeMask'][t,:]
+ cellMask = f.variables['cellMask'][t,:]
+ thk = f.variables['thickness'][t,:]
+ speed = f.variables['surfaceSpeed'][t,:]
+ melt = f.variables['floatingBasalMassBal'][t,:]
+
+ ind = np.where(edgeMask&256>0)[0]
+ skipped = 0
+ kept = 0
+ for i in range(len(ind)):
+ c1 = cone[ind[i]-1,0]-1 # in python 0-based
+ c2 = cone[ind[i]-1,1]-1 # in python 0-based
+ if thk[c1] <= 0.0 or thk[c2] <= 0.0 or c1 <= 0 or c2 <= 0 or speed[c1] 0):
+ sign = 1.0
+ else:
+ sign = -1.0
+ self.mnGLbedslope[t] += sign*(topg[c1] - topg[c2])/dcEdge[ind[i]-1]
+ #print "skipped {} of {} edges".format(skipped, len(ind))
+ self.mnGLslope[t] /= kept # calc mean
+ self.mnGLmelt[t] /= kept
+ self.mnGLdepth[t] /= kept
+ self.mnGLbedslope[t] /= kept
+ self.mnGLxpos[t] /= kept
+ self.GA[t] = (areaCell[:] * (910.0/1028.0 * thk > -1.0 * topg)).sum()
+
+ ind = np.where(np.logical_and(edgeMask&256>0, np.logical_and(yEdge<-400.0e3, yEdge>-500.0e3)))[0]
+ self.mnGLxpos[t] = xEdge[ind].mean()
+ # calc GL depth using MPAS method
+ ind = np.where(cellMask&256>0)[0]
+ frac = 0.25
+ frac = 0.5
+ GLdepths = np.sort(topg[ind])
+ #print GLdepths
+ fracIdx = int(round(len(GLdepths) * frac)) # get the index that represents the deepest x% of entries
+ self.mnGLdepthMPASMethod[t] = GLdepths[0:fracIdx].mean()
+
+ # CF melt
+ ind = np.where(xCell<-1.56e6)
+ self.mnCFmelt[t] = melt[ind].mean()
+
+# ================
+# Loop over runs and collect needed data
+# ================
+runData = {} # init empty dictionary
+groups = {} # groups are a dictionary of dictionaries. May want to changes this to a dictionary of custom objects that can include metadata about the group alongside the group's data children. KISS for now.
+for run in runs:
+ print "Processing run: " + run
+
+ # Build a list that contains all run data objects
+ if options.process:
+ runData[run] = modelRun(run)
+ file_pi = open(run + '/' +'calc_gl_data.pi', 'w')
+ pickle.dump(runData[run], file_pi)
+ file_pi.close()
+ else:
+ file_pi = open(run + '/' +'calc_gl_data.pi', 'r')
+ runData[run] = pickle.load(file_pi)
+ file_pi.close()
+
+ # Populate each run into its group for ensemble runs (not for controls)
+ if 'amp' in run:
+ groupName = run[0:12] # this is the amp and per
+ #print groupName
+ phase = run[13:]
+ #print phase
+ if groupName not in groups:
+ groups[groupName] = {} # init an empty dict to add group members
+ groups[groupName][phase] = runData[run] # stick the run object into this group
+
+print "Processing complete.\n"
+
+
+# ------- figure --------
+fig = plt.figure(1, facecolor='w')
+
+ax1 = fig.add_subplot(1, 3, 1)
+plt.xlabel('time')
+plt.ylabel('GA')
+plt.grid()
+
+
+ax2 = fig.add_subplot(1, 3, 2)
+plt.xlabel('time')
+plt.ylabel('slope')
+plt.grid()
+
+
+axGAslope = fig.add_subplot(1, 3, 3)
+plt.xlabel('GA')
+plt.ylabel('slope')
+plt.grid()
+
+# ------
+fig = plt.figure(2, facecolor='w')
+axGAslope2 = fig.add_subplot(1, 1, 1)
+plt.xlabel('change in GA from initial')
+plt.ylabel('mean slope at GL')
+plt.grid()
+
+
+# -----
+fig = plt.figure(3, facecolor='w')
+nrow = 2; ncol = 2
+axGLslope = fig.add_subplot(nrow, ncol, 1)
+plt.xlabel('time (yr)')
+plt.ylabel('mean slope at GL')
+plt.grid()
+
+axGLmelt = fig.add_subplot(nrow, ncol, 2)
+plt.xlabel('time (yr)')
+plt.ylabel('mean melt at GL')
+plt.grid()
+
+axGLdepth = fig.add_subplot(nrow, ncol, 3)
+plt.xlabel('time (yr)')
+plt.ylabel('mean depth at GL')
+plt.grid()
+
+axGAvsGLmelt = fig.add_subplot(nrow, ncol, 4)
+plt.xlabel('change in GA from initial')
+plt.ylabel('melt at GL')
+plt.grid()
+
+
+fig = plt.figure(4, facecolor='w')
+nrow = 2; ncol = 2
+axCFmelt = fig.add_subplot(nrow, ncol, 1)
+plt.xlabel('time (yr)')
+plt.ylabel('mean melt of CF')
+plt.grid()
+
+axBedslope = fig.add_subplot(nrow, ncol, 2)
+plt.xlabel('time (yr)')
+plt.ylabel('mean bed slope at GL')
+plt.grid()
+
+axGLrate= fig.add_subplot(nrow, ncol, 3)
+plt.xlabel('time (yr)')
+plt.ylabel('GL xpos retreat rate (m/yr)')
+plt.grid()
+
+
+# --- Define colors for lines ---
+colors = []
+#colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:olive', 'tab:cyan']
+n150 = sum("amp150" in r for r in runs)
+colors.extend( [ cm.autumn(x) for x in np.linspace(0.0, 1.0, n150) ])
+n300 = sum("amp300" in r for r in runs)
+colors.extend( [ cm.winter(x) for x in np.linspace(0.0, 1.0, n300) ] )
+color_index = 0
+
+
+# ================
+# Loop over runs and plot data
+# ================
+runNumber = 0
+for run in runs:
+ print "Plotting run: " + run
+
+ thisRun = runData[run]
+ stuff = thisRun.mnGLdepthMPASMethod # somehow i need to access this member before using...?
+ # optional rules about coloring
+ if "steady" in run:
+ lw = 3
+ color = 'k'
+ #colors = [ cm.jet(x) for x in np.linspace(0.0, 1.0, len(runs)) ]; color = colors[color_index]; color_index += 1; lw=1
+ elif run=="no-melt":
+ lw = 2
+ color = [0.7, 0.7, 0.7] # gray
+ else:
+ lw = 1
+ color = colors[color_index]
+ color_index += 1
+
+
+ ax1.plot(thisRun.GA, '.', color=color)
+ ax2.plot(thisRun.mnGLslope, '.', color=color)
+ axGAslope.plot(thisRun.GA, thisRun.mnGLslope, '.', color=color)
+ axGAslope2.plot(thisRun.GA[0]-thisRun.GA, thisRun.mnGLslope, '.', color=color, markersize=2)
+ #fig 3
+ axGLslope.plot(thisRun.yrs, thisRun.mnGLslope, color=color)
+ axGLmelt.plot(thisRun.yrs, thisRun.mnGLmelt, color=color)
+ axGLdepth.plot(thisRun.yrs, thisRun.mnGLdepth, color=color)
+ axGLdepth.plot(thisRun.yrs, thisRun.mnGLdepthMPASMethod[:], '.', color=color)
+ step = 40
+ axGLdepth.plot(thisRun.yrs[step/2:-1*step/2], 20.0*(thisRun.mnGLdepthMPASMethod[:-1*step]-thisRun.mnGLdepthMPASMethod[step:]) / (thisRun.yrs[:-1*step]-thisRun.yrs[step:]), color='g', lineWidth=1.5)
+ step = 50
+ axGLdepth.plot(thisRun.yrs[step/2:-1*step/2], 80.0*(thisRun.mnGLdepth[:-1*step]-thisRun.mnGLdepth[step:]) / (thisRun.yrs[:-1*step]-thisRun.yrs[step:]), color='m', lineWidth=1.5)
+
+ axGAvsGLmelt.plot(thisRun.GA[0]-thisRun.GA, thisRun.mnGLmelt, '.', color=color, markersize=1)
+ axCFmelt.plot(thisRun.yrs, thisRun.mnCFmelt, color=color)
+ axBedslope.plot(thisRun.yrs, thisRun.mnGLbedslope, color=color)
+ #axGLrate.plot(thisRun.yrs[1:], -1*(thisRun.mnGLxpos[1:]-thisRun.mnGLxpos[:-1]), color=color, lineWidth=0.5)
+ step=30
+ axGLrate.plot(thisRun.yrs[step/2:-1*step/2], -1.0*(thisRun.mnGLxpos[:-1*step]-thisRun.mnGLxpos[step:]) / (thisRun.yrs[:-1*step]-thisRun.yrs[step:]), color=color, lineWidth=1.5)
+
+
+plt.show()
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/compare_variability_runs.py b/testing_and_setup/compass/landice/Thwaites_variability/compare_variability_runs.py
index 6b9269ba3a..94c40e5d5e 100755
--- a/testing_and_setup/compass/landice/Thwaites_variability/compare_variability_runs.py
+++ b/testing_and_setup/compass/landice/Thwaites_variability/compare_variability_runs.py
@@ -3,6 +3,8 @@
Script to compare some scalar values from different runs of Thwaites melt variability experiment.
'''
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import sys
import os
import netCDF4
@@ -11,17 +13,18 @@
import matplotlib.pyplot as plt
import scipy.signal
from matplotlib import cm
+from collections import OrderedDict
outfname = 'globalStats.nc'
-runs=[ adir for adir in sorted(os.listdir('.')) if (os.path.isdir(adir) and os.path.isfile(os.path.join(adir, outfname)))]
-print "Original run list:", runs
+runs=[ adir for adir in sorted(os.listdir('.')) if (os.path.isdir(adir) and 'amp'in adir and os.path.isfile(os.path.join(adir, outfname)))]
+print("Original run list: {}".format(runs))
# get just the 0 phase for each amp/per
#runs[:] = [r for r in runs if 'pha0.00' in r]
# get all the phase for one amp/per
#runs[:] = [r for r in runs if 'amp300_per70' in r]
-#runs.append('steady')
+runs.append('steady')
# reorder to put the 'control' runs at the beginning
special_runs = ('steady', 'no-melt')
@@ -30,10 +33,20 @@
runs.remove(r)
runs.insert(0, r)
+# For the special 'scaled-ensemble', put its runs at the end
+#for i in range(len(runs)):
+# if 'amp0.6' in runs[i]:
+# runs[i] = runs[i].replace('amp0.6', 'ampZ0.6')
+#runs.sort()
+#for i in range(len(runs)):
+# if 'ampZ0.6' in runs[i]:
+# runs[i] = runs[i].replace('ampZ0.6', 'amp0.6')
+
# optionally exclude some subset
-#runs[:] = [r for r in runs if not 'amp300_per02' in r]
+#runs[:] = [r for r in runs if not 'amp0.6_per20_pha0.17' in r]
-print "Will process the following directories: ", runs
+print("Will process the following directories: {}".format(runs))
+print(" total of {} runs".format(len(runs)))
# --- Define some needed parameters
rhoi = 910.0 # ice density
@@ -73,6 +86,9 @@ def xtime2numtimeMy(xtime):
ii += 1
return numtime
+def GTtoSL(GT):
+ #return (GT-VAF[0])*1.0e12/1028.0/1000.0**3/362.0e6*1000.0*1000.0
+ return GT *1.0e12/1028.0/1000.0**3/362.0e6*1000.0*1000.0 * -1.0
# --- Define data structures ---
@@ -110,7 +126,7 @@ def __init__(self, run):
# resampled version of time array - needed for filtering.
# (Filtering needed b/c the occasional tiny time step that the model is exhibiting leads to inaccurate (noisy) derivatives)
resampEndtime = self.yrs.max()
- resampEndtime = 300.0
+ resampEndtime = 500.0
self.resampYrs = np.linspace(0.0, resampEndtime, num=resampEndtime*12*2)
self.dresampYrs = self.resampYrs[1:] - self.resampYrs[0:-1]
@@ -132,6 +148,29 @@ def __init__(self, run):
self.GAsmooth = scipy.signal.savgol_filter(self.resampGA, window_length=windowLength, polyorder=1)
self.GArate = (self.GAsmooth[1:] - self.GAsmooth[0:-1]) / self.dresampYrs
+ # calculate lag
+ #self.VAFeven = np.arange(self.VAF[0], 100000.0, -250.0)
+ #self.VAFeven = np.linspace(70000.0, self.VAF[0], 350)
+ self.VAFeven = np.linspace(45000.0, 209053.0, 2000) #229728878784122
+ self.timeOnVAFeven = np.interp(self.VAFeven, self.VAF[::-1], self.yrs[::-1])
+ self.VAFrateOnVAFeven = np.interp(self.VAFeven, self.VAFsmooth[:0:-1], self.VAFsmoothrate[::-1])
+ self.meltOnVAFeven = np.interp(self.VAFeven, self.VAF[::-1], self.melt[::-1])
+ # redo as SLR
+ #self.VAFeven = GTtoSL(np.linspace(70000.0, 209053.0, 2000) - 209053.0) #229728878784122
+ #self.timeOnVAFeven = np.interp(self.VAFeven, GTtoSL(self.VAF[::-1] - self.VAF[0]), self.yrs[::-1])
+ #self.VAFrateOnVAFeven = np.interp(self.VAFeven, self.VAFsmooth[:0:-1], self.VAFsmoothrate[::-1])
+ #self.meltOnVAFeven = np.interp(self.VAFeven, self.VAF[::-1], self.melt[::-1])
+
+ self.GAeven = np.linspace(79737808225.442/1.0e3**2, 173169904261.254/1.0e3**2, 500)
+ self.timeOnGAeven = np.interp(self.GAeven, self.GA[::-1], self.yrs[::-1])
+ #self.VAFrateOnGAeven = np.interp(self.GAeven, self.VAFsmooth[:0:-1], self.VAFsmoothrate[::-1])
+ self.meltOnGAeven = np.interp(self.GAeven, self.GA[::-1], self.melt[::-1])
+
+
+ self.GLflux = f.variables['groundingLineFlux'][:] / 1.0e12
+
+ self.floatingVol = f.variables['floatingIceVolume'][:]# / 1.0e12 * rhoi
+ self.floatingArea = f.variables['floatingIceArea'][:]
f.close()
@@ -140,9 +179,9 @@ def __init__(self, run):
# Loop over runs and collect needed data
# ================
runData = {} # init empty dictionary
-groups = {} # groups are a dictionary of dictionaries. May want to changes this to a dictionary of custom objects that can include metadata about the group alongside the group's data children. KISS for now.
+groups = OrderedDict() # groups are a dictionary of dictionaries. May want to changes this to a dictionary of custom objects that can include metadata about the group alongside the group's data children. KISS for now.
for run in runs:
- print "Processing run: " + run
+ print("Processing run: " + run)
# Build a list that contains all run data objects
runData[run] = modelRun(run)
@@ -156,66 +195,72 @@ def __init__(self, run):
if groupName not in groups:
groups[groupName] = {} # init an empty dict to add group members
groups[groupName][phase] = runData[run] # stick the run object into this group
+if any("amp0.6" in s for s in groups):
+ newDict=OrderedDict()
+ new_keys = sorted(groups.keys(), reverse=True)
+ for i in new_keys:
+ newDict[i] = groups[i]
+ groups = newDict
-print "Processing complete.\n"
+print("Processing complete.\n")
-#print groups
+print groups
# --- set up figure axes ---
-print "Setting up figure axes."
+print("Setting up figure axes.")
fig = plt.figure(1, facecolor='w')
nrow=4
ncol=2
-xtickSpacing = 20.0
+xtickSpacing = 50.0
# melt forcing
axMeanMelt = fig.add_subplot(nrow, ncol, 1)
plt.xlabel('Year')
plt.ylabel('mean melt (m/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
axTotalMelt = fig.add_subplot(nrow, ncol, 3, sharex=axMeanMelt)
plt.xlabel('Year')
plt.ylabel('total melt (Gt/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
axCumuMelt = fig.add_subplot(nrow, ncol, 5, sharex=axMeanMelt)
plt.xlabel('Year')
plt.ylabel('cumulative melt (Gt)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
# VAF
axVAF = fig.add_subplot(nrow, ncol, 2, sharex=axMeanMelt)
plt.xlabel('Year')
plt.ylabel('VAF (Gt)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
axVAFrate = fig.add_subplot(nrow, ncol, 4, sharex=axMeanMelt)
plt.xlabel('Year')
plt.ylabel('VAF rate (Gt/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
# grounded area
axGA = fig.add_subplot(nrow, ncol, 6, sharex=axMeanMelt)
plt.xlabel('Year')
plt.ylabel('Grounded area (km^2)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
axGArate = fig.add_subplot(nrow, ncol, 8, sharex=axMeanMelt)
plt.xlabel('Year')
plt.ylabel('Grounded area rate (km^2/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
@@ -224,29 +269,42 @@ def __init__(self, run):
fig2 = plt.figure(2, facecolor='w')
-nrow=3
+nrow=5
ncol=1
# melt forcing
ax2MeanMelt = fig2.add_subplot(nrow, ncol, 1)
plt.xlabel('Year')
plt.ylabel('mean melt (m/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
# VAF
ax2VAF = fig2.add_subplot(nrow, ncol, 2, sharex=ax2MeanMelt)
plt.xlabel('Year')
plt.ylabel('VAF (Gt)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
ax2VAFrate = fig2.add_subplot(nrow, ncol, 3, sharex=ax2MeanMelt)
plt.xlabel('Year')
plt.ylabel('VAF rate (Gt/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+
+ax2GLflux = fig2.add_subplot(nrow, ncol, 4, sharex=ax2MeanMelt)
+plt.xlabel('Year')
+plt.ylabel('GL flux (Gt/yr)')
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
+ax2floatVol = fig2.add_subplot(nrow, ncol, 5, sharex=ax2MeanMelt)
+plt.xlabel('Year')
+plt.ylabel('mean shelf thickness (m)')
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+
+
# ======
# this figure shows the time levels in each run
figTimes = plt.figure(30, facecolor='w')
@@ -254,17 +312,47 @@ def __init__(self, run):
plt.xlabel('Year')
axTimesYlabels = []
+# =================== plot lag as function of mass left
+fig4 = plt.figure(4, facecolor='w')
+
+nrow=4
+ncol=1
+
+ax4timelag = fig4.add_subplot(nrow, ncol, 1)
+#plt.xlabel('VAF')
+plt.ylabel('SLR delay (yr)')
+plt.grid()
+
+ax4lagRate = fig4.add_subplot(nrow, ncol, 2, sharex=ax4timelag)
+#plt.xlabel('VAF')
+plt.ylabel('delay rate (yr (mm SLR)$^{-1}$)')
+plt.grid()
+
+ax4meltDiffRate = fig4.add_subplot(nrow, ncol, 3, sharex=ax4timelag)
+plt.xlabel('VAF')
+plt.ylabel('mean melt rate (m/yr)')
+plt.grid()
+
+ax4VAFrate = fig4.add_subplot(nrow, ncol, 4, sharex=ax4timelag)
+plt.xlabel('SLR (mm)')
+plt.ylabel('VAF rate (Gt yr$^{-1}$)')
+plt.grid()
+
+
# =========
-print "Done setting up figure axes."
+print("Done setting up figure axes.")
# =========
# --- Define colors for lines ---
+colors = []
#colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:olive', 'tab:cyan']
n150 = sum("amp150" in r for r in runs)
-colors = [ cm.autumn(x) for x in np.linspace(0.0, 1.0, n150) ]
+colors.extend( [ cm.autumn(x) for x in np.linspace(0.0, 1.0, n150) ])
n300 = sum("amp300" in r for r in runs)
colors.extend( [ cm.winter(x) for x in np.linspace(0.0, 1.0, n300) ] )
+n05 = sum("amp0." in r for r in runs)
+colors.extend( [ cm.spring(x) for x in np.linspace(0.0, 1.0, n05) ])
color_index = 0
@@ -273,7 +361,7 @@ def __init__(self, run):
# ================
runNumber = 0
for run in runs:
- print "Plotting run: " + run
+ print("Plotting run: " + run)
thisRun = runData[run]
# Pull needed data for plotting from this run
@@ -287,6 +375,7 @@ def __init__(self, run):
VAFsmoothrate=thisRun.VAFsmoothrate
GA=thisRun.GA
GArate=thisRun.GArate
+ GLflux = thisRun.GLflux
# optional rules about coloring
if "steady" in run:
@@ -323,16 +412,26 @@ def __init__(self, run):
ax2VAFrate.plot(resampYrs[windowLength:], VAFsmoothrate[windowLength-1:], color=color, linewidth=lw)
#ax2VAFrate.plot(resampYrs[:windowLength], VAFsmoothrate[0:windowLength-1], 'x', color=color) # used to see what values we are throwing away
+ ax2GLflux.plot(yrs, GLflux, color=color, linewidth=lw)
+
+ ax2floatVol.plot(yrs, thisRun.floatingVol/thisRun.floatingArea, color=color, linewidth=lw)
+
+ # plot run duration
axTimes.plot(yrs, yrs*0+runNumber, '.')
+
+ if run=='steady':
+ # print some stats
+ ind1 = np.nonzero(resampYrs<100.0)
+ ind2 = np.nonzero(np.logical_and(resampYrs>100.0, resampYrs<200.0))
+ print "VAF rate: 1st 100 yrs={}; 2nd 100 yrs={}".format(VAFsmoothrate[ind1].mean(), VAFsmoothrate[ind2].mean())
+
+ # accounting
axTimesYlabels.append(run)
runNumber += 1
axVAF.legend(loc='best', ncol=2)
# second ticks for SLR
-def GTtoSL(GT):
- #return (GT-VAF[0])*1.0e12/1028.0/1000.0**3/362.0e6*1000.0*1000.0
- return GT *1.0e12/1028.0/1000.0**3/362.0e6*1000.0*1000.0 * -1.0
axSLR=axVAF.twinx()
y1, y2=axVAF.get_ylim()
@@ -351,6 +450,8 @@ def GTtoSL(GT):
axSLRrate.set_xlim(x1, x2)
+
+
# Label the progress plot with each run
axTimes.set_yticks(range(runNumber))
axTimes.set_yticklabels(axTimesYlabels)
@@ -387,58 +488,192 @@ def GTtoSL(GT):
fig3 = plt.figure(3, facecolor='w')
-nrow=4
+nrow=5
ncol=1
# melt forcing
ax3MeanMelt = fig3.add_subplot(nrow, ncol, 1)
plt.xlabel('Year')
-plt.ylabel('mean melt (m/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.ylabel('mean melt (m yr$^{-1}$)')
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
# VAF
ax3VAF = fig3.add_subplot(nrow, ncol, 2, sharex=ax3MeanMelt)
plt.xlabel('Year')
plt.ylabel('VAF (Gt)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
# VAF diff
-ax3VAFdiff = fig3.add_subplot(nrow, ncol, 3, sharex=ax3MeanMelt)
-plt.xlabel('Year')
-plt.ylabel('VAF difference (Gt)')
-plt.xticks(np.arange(22)*xtickSpacing)
+#fig9 = plt.figure(9, facecolor='w')
+ax3VAFdiff = fig3.add_subplot(nrow, ncol, 4, sharex=ax3MeanMelt)
+#ax3VAFdiff = fig9.add_subplot(1, 1, 1)
+plt.xlabel('Year', axes=ax3VAFdiff)
+#plt.ylabel('VAF difference (%)')
+#plt.ylabel('VAF difference (Gt)')
+plt.ylabel('SLR difference (mm)', axes=ax3VAFdiff)
+#plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
+#plt.xlim((0.0,500.0))
# VAF rate
-ax3VAFrate = fig3.add_subplot(nrow, ncol, 4, sharex=ax3MeanMelt)
+ax3VAFrate = fig3.add_subplot(nrow, ncol, 3, sharex=ax3MeanMelt)
+#plt.xlabel('Year')
+plt.ylabel('VAF rate (Gt yr$^{-1}$)')
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+
+# delay
+ax3delay = fig3.add_subplot(nrow, ncol, 5, sharex=ax3MeanMelt)
plt.xlabel('Year')
-plt.ylabel('VAF rate (Gt/yr)')
-plt.xticks(np.arange(22)*xtickSpacing)
+plt.ylabel('delay (yr)')
+plt.xticks(np.arange(30)*xtickSpacing)
plt.grid()
+# === plot for delay adjusted results ===
+fig9 = plt.figure(9, facecolor='w')
+
+nrow=4
+ncol=1
+
+# delay rate
+ax9delayrate = fig9.add_subplot(nrow, ncol, 4)
+#plt.xlabel('Year')
+plt.ylabel('delay adjusted\ndelay rate\n(yr century$^{-1}$)')
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+plt.xlabel('Year')
+#ax9delayrate.text(-0.15, 0.95, 'd', transform=ax9delayrate.transAxes, fontsize=14, fontweight='bold')
+
+# delay-adjusted VAF rate
+ax9delayAdjVAFrate = fig9.add_subplot(nrow, ncol, 1, sharex=ax9delayrate)
+#plt.xlabel('Year')
+plt.ylabel('delay adjusted\nVAF rate\n(Gt yr$^{-1}$)')
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+#ax9delayAdjVAFrate.text(-0.15, 0.95, 'a', transform=ax9delayAdjVAFrate.transAxes, fontsize=14, fontweight='bold')
+#ax9delayAdjVAFrate.set_yscale("log", nonposy='clip')
+
+# delay-adjusted VAF rate diff
+#ax9delayAdjVAFrateDiff = fig9.add_subplot(nrow, ncol, 3, sharex=ax9delayrate)
+#plt.ylabel('delay adjusted\nVAF rate\ndifference (%)')
+#plt.xticks(np.arange(30)*xtickSpacing)
+#plt.grid()
+
+# delay-adjusted melt rate
+ax9delayAdjMelt = fig9.add_subplot(nrow, ncol, 2, sharex=ax9delayrate)
+#plt.xlabel('Year')
+plt.ylabel('delay adjusted\nmelt rate\n(m yr$^{-1}$)')
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+#ax9delayAdjMelt.text(-0.15, 0.95, 'b', transform=ax9delayAdjMelt.transAxes, fontsize=14, fontweight='bold')
+
+# delay-adjusted melt rate diff
+ax9delayAdjMeltDiff = fig9.add_subplot(nrow, ncol, 3, sharex=ax9delayrate)
+plt.ylabel('delay adjusted\nmelt rate difference\n(m yr$^{-1}$)')
+plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+#ax9delayAdjMeltDiff.text(-0.15, 0.95, 'c', transform=ax9delayAdjMeltDiff.transAxes, fontsize=14, fontweight='bold')
+
+
+# === plot for boxpot ===
+figBox = plt.figure(17, facecolor='w')
+
+nrow=1
+ncol=3
+
+#axBox = figBox.add_subplot(nrow, ncol, 1)
+#plt.xlabel('Year')
+#plt.ylabel('delay adjusted\ndelay rate\n(yr century$^{-1}$)')
+#plt.xticks(np.arange(30)*xtickSpacing)
+#plt.grid()
+#plt.xlabel('Year')
+axVal100 = figBox.add_subplot(nrow, ncol, 1)
+plt.ylabel("delay (yr)")
+axVal250 = figBox.add_subplot(nrow, ncol, 2)
+plt.ylabel("delay (yr)")
+axVal500 = figBox.add_subplot(nrow, ncol, 3)
+plt.ylabel("delay (yr)")
+
+
+
+
+
+
# define colors to use
#colors = [ cm.jet(x) for x in np.linspace(0.0, 1.0, len(groups)) ]
n150 = sum(1 for g in groups if 'amp150' in g)
colors = [ cm.autumn(x) for x in np.linspace(0.0, 1.0, n150) ]
n300 = sum(1 for g in groups if 'amp300' in g)
colors.extend( [ cm.winter(x) for x in np.linspace(0.0, 1.0, n300) ] )
+n05 = sum(1 for g in groups if 'amp0.' in g)
+colors.extend( [ cm.spring(x) for x in np.linspace(0.0, 1.0, n05) ] )
+
+print colors
+
+if len(groups) == 6: # standard plots
+ colors = [
+ (0., 146./255., 146./255., 1.0),
+ (0.0, 109./255., 219./255., 1.0),
+ (73.0/255., 0.0, 146.0/255., 1.0),
+
+ (244./255., 218./255., 34./255., 1.0),
+ (1.0, 0.50196078431372548, 0.0, 1.0),
+# (1.0, 1.0, 0.0, 1.0),
+ (1.0, 0.0, 0.0, 1.0),
+
+ #(0.0, 0.0, 1.0, 1.0),
+ #(0.0, 0.50196078431372548, 0.74901960784313726, 1.0),
+ ##(0.0, 1.0, 0.5, 1.0)
+ #(0., 204./255., 51./255., 1.0)
+
+ ]
+elif len(groups) == 2: #scaled-ensemble vs normal
+ colors = [
+ (1.0, 0.50196078431372548, 0.0, 1.0),
+ (0./255., 221./255., 205./255.)
+ ]
+else:
+ colors = [ cm.jet(x) for x in np.linspace(0.0, 1.0, len(groups)) ]
# ref value
steadyVAF = runData['steady'].VAFsmooth
+#steadyVAF = runData['control_run_10pct_D25_kappa8'].VAFsmooth
+steadyTimeOnVAFeven = runData['steady'].timeOnVAFeven
+steadyMeltOnVAFeven = runData['steady'].meltOnVAFeven
+steadyTimeOnGAeven = runData['steady'].timeOnGAeven
+steadyMeltOnGAeven = runData['steady'].meltOnGAeven
# add control run
if 'steady' in runData:
ax3MeanMelt.plot(runData['steady'].resampYrs[windowLength:], runData['steady'].resampMelt[windowLength:], 'k', label='steady')
- ax3VAF.plot(runData['steady'].resampYrs, runData['steady'].VAFsmooth, 'k', label='steady')
+ ax3VAF.plot(runData['steady'].resampYrs, runData['steady'].VAFsmooth, 'k', label='control')
ax3VAFrate.plot(runData['steady'].resampYrs[windowLength:], runData['steady'].VAFsmoothrate[windowLength-1:], 'k', label='steady')
+ ax4VAFrate.plot(GTtoSL(runData['steady'].VAFeven) - GTtoSL(runData['steady'].VAF[0]), runData['steady'].VAFrateOnVAFeven, 'k')
+
+ ax9delayAdjMelt.plot(runData['steady'].resampYrs[windowLength:], runData['steady'].resampMelt[windowLength:], 'k', linewidth=1.0)
+
+ ax9delayAdjVAFrate.plot(runData['steady'].resampYrs[windowLength:], runData['steady'].VAFsmoothrate[windowLength-1:] , '-', color='k', linewidth=1.0, label='control') # delay adj vaf rate
+
+ # try plotting acceleration - pretty noisy and hard to interpret!
+# filterLen = 401
+# ddy = np.gradient(np.gradient(np.convolve(np.ones(filterLen,'d')/filterLen, runData['steady'].VAFsmooth, mode='same')))
+# ax9delayAdjVAFrate.plot(runData['steady'].resampYrs, ddy, '-', color='k', linewidth=0.5)
+
+
+ ax3delay.plot(runData['steady'].resampYrs, 0.0*runData['steady'].resampYrs, 'k') # plot control as 0 delay for completeness
+ ax3VAFdiff.plot(runData['steady'].resampYrs, 0.0*runData['steady'].resampYrs, 'k') # plot control as 0 delay for completeness
+
+
+
groupNumber = 0
-for groupName in sorted(groups): # sorted puts them in alpha order
- print "Plotting group: " + groupName
+#for groupName in sorted(groups): # sorted puts them in alpha order
+for groupName in groups: # sorted puts them in alpha order
+ print("Plotting group: " + groupName)
group = groups[groupName] # gets the actual dictionary that this group is made of
nMembers = len(group)
@@ -450,10 +685,20 @@ def GTtoSL(GT):
VAFgroup = np.zeros((nMembers, nEntries))
VAFdiffGroup = np.zeros((nMembers, nEntries))
VAFrateGroup = np.zeros((nMembers, nEntries-1))
+ lagGroup = np.zeros((nMembers, len(group.values()[0].VAFeven)))
+ meltOnVAFGroup = np.zeros((nMembers, len(group.values()[0].VAFeven)))
+ VAFrateOnVAFGroup = np.zeros((nMembers, len(group.values()[0].VAFeven)))
+ lagGAGroup = np.zeros((nMembers, len(group.values()[0].GAeven)))
+ meltOnGAGroup = np.zeros((nMembers, len(group.values()[0].GAeven)))
+ delayGroup = np.zeros((nMembers, nEntries))
+ delayAdjMeltGroup = np.zeros((nMembers, nEntries))
+ effectiveTimeGroup = np.zeros((nMembers, nEntries))
# VAFmean = np.zeros((nMembers,))
# VAFmin= np.zeros((nMembers,))
# VAFmax= np.zeros((nMembers,))
+
+
# Loop through group members
runNumber = 0
for run in group:
@@ -464,17 +709,55 @@ def GTtoSL(GT):
yrsGroup = thisRun.resampYrs # (only need this once)
meltGroup[runNumber, :] = thisRun.resampMelt
VAFgroup[runNumber, :] = thisRun.VAFsmooth
- VAFdiffGroup[runNumber, :] = thisRun.VAFsmooth - steadyVAF # this version plots difference from control
+ #VAFdiffGroup[runNumber, :] = thisRun.VAFsmooth - steadyVAF # this version plots difference from control
+ VAFdiffGroup[runNumber, :] = GTtoSL(thisRun.VAFsmooth-steadyVAF) # this version plots difference from control as SLR
+ # VAFdiffGroup[runNumber, :] = (thisRun.VAFsmooth - steadyVAF)/(steadyVAF-steadyVAF[0])*100.0 # this version plots difference from control as %
VAFrateGroup[runNumber, :] = thisRun.VAFsmoothrate
+ meltOnVAFGroup[runNumber, :] = thisRun.meltOnVAFeven
+ meltOnGAGroup[runNumber, :] = thisRun.meltOnGAeven
+
+ # calculate delay in time-space
+ for t in range(len(thisRun.resampYrs)):
+ #steadyIndForThisVAF = np.nonzero(runData['steady'].VAFsmooth <= thisRun.VAFsmooth[t])[0][0]
+ steadyIndForThisVAF = np.nonzero(runData['steady'].GAsmooth <= thisRun.GAsmooth[t])[0][0]
+ delayGroup[runNumber, t] = runData['steady'].resampYrs[steadyIndForThisVAF] - thisRun.resampYrs[t]
+
+ #ax3delay.plot(thisRun.resampYrs, delayGroup[runNumber, :], color=colors[groupNumber])
+ # Calculate delay-adjusted melt
+ effectiveTimeGroup[runNumber,:] = thisRun.resampYrs[:] - delayGroup[runNumber, :]
+ delayAdjMeltGroup[runNumber, :] = np.interp(effectiveTimeGroup[runNumber,:], thisRun.resampYrs, thisRun.resampMelt) # generate y values for each x
+ #if runNumber % 3 == 0:
+ #ax9delayAdjMelt.plot(thisRun.resampYrs, delayAdjMeltGroup[runNumber, :], color=colors[groupNumber], lineWidth=0.2)
+
+
+ #VAFevenGroup = thisRun.VAFeven # only need this once)
+ VAFevenGroup = GTtoSL(thisRun.VAFeven-thisRun.VAF[0]) # only need this once - as SLR
+ lagGroup[runNumber,:] = thisRun.timeOnVAFeven - steadyTimeOnVAFeven
+ VAFrateOnVAFGroup[runNumber,:] = thisRun.VAFrateOnVAFeven
+# ax4timelag.plot(thisRun.VAFeven, lagGroup[runNumber,:], ':', color=colors[groupNumber], linewidth=0.5)
+# ax4VAFrate.plot(thisRun.VAFeven, thisRun.VAFrateOnVAFeven, color=colors[groupNumber], linewidth=0.4)
+ #ax4meltDiffRate.plot(thisRun.VAFeven, thisRun.meltOnVAFeven - steadyMeltOnVAFeven, color=colors[groupNumber])
+ #ax4meltDiffRate.plot(thisRun.VAFeven, thisRun.meltOnVAFeven , color=colors[groupNumber], linewidth=0.4)
+
+ GAevenGroup = thisRun.GAeven # only need this once)
+ lagGAGroup[runNumber,:] = thisRun.timeOnGAeven - steadyTimeOnGAeven
+ #ax4timelag.plot(thisRun.GAeven, lagGAGroup[runNumber,:], ':', color=colors[groupNumber], linewidth=0.5)
+ #ax4VAFrate.plot(thisRun.GAeven, thisRun.VAFrateOnVAFeven, color=colors[groupNumber])
+
runNumber += 1
+ # get index to final time that is meaningful after adjusting for delay
+ finalIndex = np.nonzero(yrsGroup < (yrsGroup[-1] + delayGroup.mean(0)[-1]))[0][-1]
+ indexPerYr = len(yrsGroup) / (yrsGroup[-1]-yrsGroup[0])
+
+
# melt plot
ax3MeanMelt.plot(yrsGroup[windowLength:], meltGroup.mean(0)[windowLength:], '-', color = colors[groupNumber], label=groupName)
ax3MeanMelt.plot(yrsGroup[windowLength:], meltGroup.max(0)[windowLength:], '--', color = colors[groupNumber], linewidth=0.5)
ax3MeanMelt.plot(yrsGroup[windowLength:], meltGroup.min(0)[windowLength:], '--', color = colors[groupNumber], linewidth=0.5)
# VAF plot
- ax3VAF.plot(yrsGroup, VAFgroup.mean(0), '-', color = colors[groupNumber], label=groupName)
+ ax3VAF.plot(yrsGroup, VAFgroup.mean(0), '-', color = colors[groupNumber], label="Amp={}m, Per={}yr".format(groupName[3:6], int(groupName[10:12])))#label=groupName)
ax3VAF.plot(yrsGroup, VAFgroup.max(0), '--', color = colors[groupNumber], linewidth=0.5)
ax3VAF.plot(yrsGroup, VAFgroup.min(0), '--', color = colors[groupNumber], linewidth=0.5)
@@ -487,15 +770,133 @@ def GTtoSL(GT):
ax3VAFrate.plot(yrsGroup[windowLength:], VAFrateGroup.mean(0)[windowLength-1:], '-', color = colors[groupNumber], label=groupName)
ax3VAFrate.plot(yrsGroup[windowLength:], VAFrateGroup.max(0)[windowLength-1:], '--', color = colors[groupNumber], linewidth=0.5)
ax3VAFrate.plot(yrsGroup[windowLength:], VAFrateGroup.min(0)[windowLength-1:], '--', color = colors[groupNumber], linewidth=0.5)
+ # delay adj VAF rate difference
+ delayAdjVAFrate = np.interp(effectiveTimeGroup.mean(0)[1:], yrsGroup[1:], VAFrateGroup.mean(0))
+ delayAdjVAF = np.interp(effectiveTimeGroup.mean(0), yrsGroup, VAFgroup.mean(0))
+ #ax9delayAdjVAFrate.plot(yrsGroup[windowLength:finalIndex], delayAdjVAFrate[windowLength-1:finalIndex-1] , '-', color=colors[groupNumber], linewidth=0.5) # delay adj vaf rate
+ ax9delayAdjVAFrate.plot(yrsGroup[windowLength:finalIndex], delayAdjVAFrate[windowLength-1:finalIndex-1] , '-', color=colors[groupNumber], linewidth=1.0, label="Amp={}m, Per={}yr".format(groupName[3:6], int(groupName[10:12]))) # delay adj vaf rate
+# ddy = np.gradient(np.gradient(delayAdjVAF))
+# ax9delayAdjVAFrate.plot(yrsGroup, ddy, '-', color=colors[groupNumber], linewidth=0.5)
+# ax9delayAdjVAFrate.plot(yrsGroup[windowLength:], delayAdjVAFrate[windowLength-1:] - runData['steady'].VAFsmoothrate[windowLength-1:], '-', color=colors[groupNumber], linewidth=0.5) # absolute diff
+ #ax9delayAdjVAFrateDiff.plot(yrsGroup[windowLength:finalIndex], (delayAdjVAFrate[windowLength-1:finalIndex-1] - runData['steady'].VAFsmoothrate[windowLength-1:finalIndex-1]) / runData['steady'].VAFsmoothrate[windowLength-1:finalIndex-1] * 100.0, '-', color=colors[groupNumber], linewidth=0.5) # as pct
+ # delay as fn of time
+ ax3delay.plot(yrsGroup, delayGroup.mean(0), color=colors[groupNumber])
+ ax3delay.plot(yrsGroup, delayGroup.max(0), '--', color=colors[groupNumber], linewidth=0.5)
+ ax3delay.plot(yrsGroup, delayGroup.min(0), '--', color=colors[groupNumber], linewidth=0.5)
+ # delay rate as fn of time
+ filterYr=20.0; step=int(np.round(filterYr*indexPerYr))
+ filterLen = step
+ print "Using filter length of {} years = {} indices".format(filterYr, step)
+ #ax9delayrate.plot(yrsGroup[step/2:-1*step/2], (delayGroup.mean(0)[:-1*step]-delayGroup.mean(0)[step:])/(yrsGroup[:-1*step]-yrsGroup[step:])*100, '-',color=colors[groupNumber], lineWidth=0.4)
+ ax9delayrate.plot(yrsGroup[step/2:-1*step/2] - - delayGroup.mean(0)[step/2:-1*step/2], (delayGroup.mean(0)[:-1*step]-delayGroup.mean(0)[step:])/(yrsGroup[:-1*step]-yrsGroup[step:])*100, '-',color=colors[groupNumber], lineWidth=1.0) # delay-adjusted delay rate!
+# delaySmooth = np.convolve(np.ones(filterLen,'d')/filterLen, delayGroup.mean(0), mode='same')
+# ax9delayrate.plot(yrsGroup[step/2:-1*step/2] - - delaySmooth[step/2:-1*step/2], (delaySmooth[:-1*step]-delaySmooth[step:])/(yrsGroup[:-1*step]-yrsGroup[step:])*100, '-',color=colors[groupNumber], lineWidth=0.4) # delay-adjusted delay rate!
+ # delay adj melt
+ #ax9delayAdjMelt.plot(yrsGroup, delayAdjMeltGroup.mean(0), '-', color=colors[groupNumber], linewidth=0.5)
+ delayAdjMelt = np.interp(effectiveTimeGroup.mean(0), yrsGroup, meltGroup.mean(0)) # generate y values for each x
+ ax9delayAdjMelt.plot(yrsGroup[:finalIndex], delayAdjMelt[:finalIndex], '-', color=colors[groupNumber], linewidth=1.0)
+ #ax9delayAdjMeltDiff.plot(yrsGroup[:finalIndex], 1* (delayAdjMelt - runData['steady'].resampMelt)[:finalIndex], '-', color=colors[groupNumber], linewidth=1.5) #also plot diff from steady
+
+ filterYr=7.0; step=int(np.round(filterYr*indexPerYr))
+ filterLen = step
+ print "Using filter length of {} years = {} indices".format(filterYr, step)
+ ax9delayAdjMeltDiff.plot(yrsGroup[:finalIndex], np.convolve(np.ones(filterLen,'d')/filterLen, 1* (delayAdjMelt - runData['steady'].resampMelt)[:finalIndex], mode='same'), '-', color=colors[groupNumber], linewidth=1.0) #also plot diff from steady (WITH SMOOTHING)
+ # optionally plot min/max adjusted
+ delayAdjMeltMin = np.interp(effectiveTimeGroup.mean(0), yrsGroup, meltGroup.min(0)) # generate y values for each x
+ ax9delayAdjMelt.plot(yrsGroup[:finalIndex], delayAdjMeltMin[:finalIndex], '--', color=colors[groupNumber], linewidth=0.5)
+ delayAdjMeltMax = np.interp(effectiveTimeGroup.mean(0), yrsGroup, meltGroup.max(0)) # generate y values for each x
+ ax9delayAdjMelt.plot(yrsGroup[:finalIndex], delayAdjMeltMax[:finalIndex], '--', color=colors[groupNumber], linewidth=0.5)
+ # plot diff in half range
+# ax9delayAdjMelt.plot(yrsGroup, 10*((delayAdjMeltMax-delayAdjMelt) - (delayAdjMelt-delayAdjMeltMin)), '--', color=colors[groupNumber], linewidth=0.5) # asymmetry of min and max from the mean
+
+
+ # plot DELAY
+ ax4timelag.plot(VAFevenGroup, lagGroup.mean(0), '-', color = colors[groupNumber], label=groupName)
+ ax4timelag.plot(VAFevenGroup, lagGroup.max(0), '--', color = colors[groupNumber], linewidth=0.5)
+ ax4timelag.plot(VAFevenGroup, lagGroup.min(0), '--', color = colors[groupNumber], linewidth=0.5)
+ #ax4timelag.plot(VAFevenGroup, lagGroup.max(0) - lagGroup.min(0), '-', color = colors[groupNumber], linewidth=1)
+ for t in np.arange(0.0, 500.0, 20.0):
+ idx = np.abs(steadyTimeOnVAFeven - t).argmin()
+ ax4timelag.plot(VAFevenGroup[idx], lagGroup.mean(0)[idx], 'o', color = colors[groupNumber], markersize=3)
+ for t in np.arange(0.0, 500.0, 100.0):
+ idx = np.abs(steadyTimeOnVAFeven - t).argmin()
+ ax4timelag.plot(VAFevenGroup[idx], lagGroup.mean(0)[idx], 'o', color = colors[groupNumber], markersize=5)
+
+ # plot lag rate
+ step=120
+ ax4lagRate.plot(VAFevenGroup[step/2:-1*step/2], (lagGroup.mean(0)[:-1*step]-lagGroup.mean(0)[step:]) / (VAFevenGroup[:-1*step]-VAFevenGroup[step:]), '-', color=colors[groupNumber])
+
+# # plot melt on VAF to go with lag
+## ax4meltDiffRate.plot(VAFevenGroup, meltOnVAFGroup.mean(0)- steadyMeltOnVAFeven, color=colors[groupNumber])
+ ax4meltDiffRate.plot(VAFevenGroup, meltOnVAFGroup.mean(0), color=colors[groupNumber])
+ ax4meltDiffRate.plot(VAFevenGroup, meltOnVAFGroup.max(0), '-', color=colors[groupNumber], linewidth=0.5)
+ ax4meltDiffRate.plot(VAFevenGroup, meltOnVAFGroup.min(0), '-', color=colors[groupNumber], linewidth=0.5)
+ filterLen = 201
+ #ax4meltDiffRate.plot(VAFevenGroup, np.convolve(np.ones(filterLen,'d')/filterLen,meltOnVAFGroup.mean(0),mode='same'), '-', color='r') #color=colors[groupNumber], linewidth=1) # this line plots a boxcar filtered version!
+ ax4meltDiffRate.plot(VAFevenGroup, steadyMeltOnVAFeven, color='k')
+ print groupName, "variability mean melt rate: ", meltOnVAFGroup.mean(0).mean(), " control mean melt rate: ", steadyMeltOnVAFeven.mean(), " ratio=", meltOnVAFGroup.mean(0).mean()/steadyMeltOnVAFeven.mean()
+
+ # plot VAF rate on VAF to go with lag
+ ax4VAFrate.plot(VAFevenGroup, (runData['steady'].VAFrateOnVAFeven- VAFrateOnVAFGroup.mean(0))/ runData['steady'].VAFrateOnVAFeven, '-', color = colors[groupNumber], label=groupName)
+ ax4VAFrate.plot(VAFevenGroup, VAFrateOnVAFGroup.mean(0), '-', color = colors[groupNumber], label=groupName)
+ ax4VAFrate.plot(VAFevenGroup, VAFrateOnVAFGroup.max(0), '-', color = colors[groupNumber], linewidth=0.5)
+ ax4VAFrate.plot(VAFevenGroup, VAFrateOnVAFGroup.min(0), '-', color = colors[groupNumber], linewidth=0.5)
+
+# # plot lag based on GA
+# ax4timelag.plot(GAevenGroup, lagGAGroup.mean(0), '-', color = colors[groupNumber], label=groupName)
+# ax4timelag.plot(GAevenGroup, lagGAGroup.max(0), '--', color = colors[groupNumber], linewidth=0.5)
+# ax4timelag.plot(GAevenGroup, lagGAGroup.min(0), '--', color = colors[groupNumber], linewidth=0.5)
+# #ax4timelag.plot(VAFevenGroup, lagGroup.max(0) - lagGroup.min(0), '-', color = colors[groupNumber], linewidth=1)
+# for t in np.arange(0.0, 500.0, 20.0):
+# idx = np.abs(steadyTimeOnGAeven - t).argmin()
+# ax4timelag.plot(GAevenGroup[idx], lagGAGroup.mean(0)[idx], 'o', color = colors[groupNumber], markersize=3)
+# for t in np.arange(0.0, 500.0, 100.0):
+# idx = np.abs(steadyTimeOnGAeven - t).argmin()
+# ax4timelag.plot(GAevenGroup[idx], lagGAGroup.mean(0)[idx], 'o', color = colors[groupNumber], markersize=5)
+#
+# # plot lag rate
+# step=30
+# ax4lagRate.plot(GAevenGroup[step/2:-1*step/2], (lagGAGroup.mean(0)[:-1*step]-lagGAGroup.mean(0)[step:]) / (GAevenGroup[:-1*step]-GAevenGroup[step:]), '-', color=colors[groupNumber])
+#
+## ax4meltDiffRate.plot(VAFevenGroup, meltOnVAFGroup.mean(0)- steadyMeltOnVAFeven, color=colors[groupNumber])
+# ax4meltDiffRate.plot(GAevenGroup, meltOnGAGroup.mean(0), color=colors[groupNumber])
+# ax4meltDiffRate.plot(GAevenGroup, steadyMeltOnGAeven, color='k')
+
+ # Box plot of delay
+ #axBox.boxplot(delayGroup[:, -1], showmeans=True, positions = [groupNumber])
+ n100 = np.where(yrsGroup>=100.0)[0][0]
+ n100 = np.where(np.logical_and(yrsGroup<=100.0, yrsGroup>50.0))[0]
+# print yrsGroup[n100]
+ axVal100.plot(groupNumber, delayGroup[:, n100].mean(), 'x', markersize=4, color = colors[groupNumber])
+ axVal100.plot(groupNumber, np.median(delayGroup[:, n100].mean(1)), 'o', markersize=4, color = colors[groupNumber])
+ axVal100.plot(np.ones(nMembers)*groupNumber, delayGroup[:, n100].mean(1), '.', markersize=2, color = colors[groupNumber])
+
+ n250 = np.where(yrsGroup>=250.0)[0][0]
+ n250 = np.where(np.logical_and(yrsGroup<=250.0, yrsGroup>200.0))[0]
+ axVal250.plot(groupNumber, delayGroup[:, n250].mean(), 'x', markersize=4, color = colors[groupNumber])
+ axVal250.plot(groupNumber, np.median(delayGroup[:, n250].mean(1)), 'o', markersize=4, color = colors[groupNumber])
+ axVal250.plot(np.ones(nMembers)*groupNumber, delayGroup[:, n250].mean(1), '.', markersize=2, color = colors[groupNumber])
+
+ n500 = -1
+ n500 = np.where(yrsGroup>=470.0)[0][0]
+ n500 = np.where(np.logical_and(yrsGroup<=500.0, yrsGroup>450.0))[0]
+ axVal500.plot(groupNumber, delayGroup[:, n500].mean(), 'x', markersize=4, color = colors[groupNumber])
+ axVal500.plot(groupNumber, np.median(delayGroup[:, n500].mean(1)), 'o', markersize=4, color = colors[groupNumber])
+ axVal500.plot(np.ones(nMembers)*groupNumber, delayGroup[:, n500].mean(1), '.', markersize=2, color = colors[groupNumber])
groupNumber += 1
+# Fix up histograms
+axVal100.set_ylim([axVal100.get_ylim()[0], 0.0])
+axVal250.set_ylim([axVal250.get_ylim()[0], 0.0])
+axVal500.set_ylim([axVal500.get_ylim()[0], 0.0])
+
# show legend
#legend = ax3VAF.legend(loc='lower left')
# or as multiple columns
handles, labels = ax3VAF.get_legend_handles_labels()
-l1 = ax3VAF.legend(handles[0:1], labels[0:1], loc='lower left', ncol=1) # control runs
-l2 = ax3VAF.legend(handles[1:], labels[1:], loc='lower center', ncol=2) # variability runs
+l1 = ax3VAF.legend(handles[0:1], labels[0:1], loc='lower center', ncol=1) # control runs
+l2 = ax3VAF.legend(handles[1:], labels[1:], loc='lower left', ncol=2) # variability runs
ax3VAF.add_artist(l1)
@@ -507,14 +908,30 @@ def GTtoSL(GT):
axSLR.set_ylabel('S.L. equiv. (mm)')
axSLR.set_xlim(x1, x2)
-axSLR=ax3VAFdiff.twinx()
-y1, y2=ax3VAFdiff.get_ylim()
-x1, x2=ax3VAFdiff.get_xlim()
-axSLR.set_ylim(GTtoSL(y1) , GTtoSL(y2) )
-#axSLR.set_yticks( range(int(GTtoSL(y1)), int(GTtoSL(y2))) )
-axSLR.set_ylabel('S.L. equiv. (mm)')
-axSLR.set_xlim(x1, x2)
+handles, labels = ax9delayAdjVAFrate.get_legend_handles_labels()
+l1 = ax9delayAdjVAFrate.legend(handles[0:1], labels[0:1], loc='lower center', ncol=1) # control runs
+l2 = ax9delayAdjVAFrate.legend(handles[1:], labels[1:], loc='lower left', ncol=2) # variability runs
+ax9delayAdjVAFrate.add_artist(l1)
+
+#axBox.set_xlim((-1,groupNumber))
+#axBox.set_xticks(range(groupNumber+1))
+#axBox.set_xticklabels(groups)
+#for tick in axBox.get_xticklabels():
+# tick.set_rotation(45)
+#axBox.set_ylabel('delay (yrs)')
+
+#axSLR=ax3VAFdiff.twinx()
+#y1, y2=ax3VAFdiff.get_ylim()
+#x1, x2=ax3VAFdiff.get_xlim()
+#axSLR.set_ylim(GTtoSL(y1) , GTtoSL(y2) )
+##axSLR.set_yticks( range(int(GTtoSL(y1)), int(GTtoSL(y2))) )
+#axSLR.set_ylabel('S.L. equiv. (mm)')
+#axSLR.set_xlim(x1, x2)
+plt.close(1)
+plt.close(2)
+plt.close(4)
+plt.close(30)
plt.show()
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/finalize_thwaites_initial_conditions.py b/testing_and_setup/compass/landice/Thwaites_variability/finalize_thwaites_initial_conditions.py
index 782343b086..2e07c8dd48 100755
--- a/testing_and_setup/compass/landice/Thwaites_variability/finalize_thwaites_initial_conditions.py
+++ b/testing_and_setup/compass/landice/Thwaites_variability/finalize_thwaites_initial_conditions.py
@@ -4,6 +4,8 @@
run with one argument for the file to be modified.
'''
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import sys
import netCDF4
import numpy as np
@@ -15,7 +17,7 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
f = netCDF4.Dataset(options.filename,'r+')
thickness = f.variables['thickness'][0,:]
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/plot_melt_perturbations.py b/testing_and_setup/compass/landice/Thwaites_variability/plot_melt_perturbations.py
new file mode 100755
index 0000000000..f097cb95e4
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/plot_melt_perturbations.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+'''
+Script to plot melt perturbations for Thwaites experiment
+'''
+
+import sys
+import os
+import netCDF4
+import datetime
+import numpy as np
+import matplotlib.pyplot as plt
+from matplotlib import cm
+
+perturbs = np.arange(0.0, 2.1, 0.2)
+nruns = len(perturbs)
+
+# === set up plots ===
+# another plot ===============
+
+fig = plt.figure(2, facecolor='w', figsize=(13,5))
+axVAF = fig.add_subplot(1,3,1)
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('VAF change (Gt/yr)')
+plt.grid()
+
+
+axPctDiff = fig.add_subplot(1,3,2)
+plt.xlabel('fractional change in melt rate from control')
+plt.ylabel('difference between + and - perturbations (%)')
+plt.grid()
+
+axAbsDiff = fig.add_subplot(1,3,3)
+plt.xlabel('fractional change in melt rate from control')
+plt.ylabel('difference between + and - perturbations (Gt yr$^{-1}$)')
+plt.grid()
+
+fig.tight_layout()
+
+
+
+
+yr_samples = [1.0, 2.5, 10.0]
+for yr in yr_samples:
+ print "Analyzing at year {}".format(yr)
+ # init some vectors
+ meltMag = np.zeros((nruns,))
+ GAchange = np.zeros((nruns,))
+ GAchangeInst = np.zeros((nruns,))
+ VAFchange = np.zeros((nruns,))
+ VAFchangeInst = np.zeros((nruns,))
+ GLfchange = np.zeros((nruns,))
+ GLfchangeInst = np.zeros((nruns,))
+
+ for i in range(nruns):
+ p = perturbs[i]
+ dname = "meltfactor{}".format(p)
+ print dname
+ fname = dname + "/globalStats.nc"
+ if os.path.isfile(fname):
+ f = netCDF4.Dataset(fname, 'r')
+ #meltMag[i] = f.variables['totalFloatingBasalMassBal'][1] /1.0e9 * -1.0
+ meltMag[i] = f.variables['totalFloatingBasalMassBal'][1:].mean() /1.0e9 /1000.0 * -1.0
+ GA = f.variables['groundedIceArea'][:] / 1000.0**2
+ VAF = f.variables['volumeAboveFloatation'][:] *910.0 /1.0e9 /1000.0
+ GLf = f.variables['groundingLineFlux'][:] /1.0e9 /1000.0
+ dt = f.variables['deltat'][:] / (3600.0*24.0*365.0)
+ yrs = f.variables['daysSinceStart'][:]/365.0
+ #ind = np.where(yrs == yr)[0][0]
+ ind = np.argmin(np.absolute(yrs-yr))
+ ind2 = np.argmin(np.absolute(yrs-(yr-1.0))) # index to one year before 'yr'
+ GAchange[i] = (GA[ind] - GA[0]) / (yrs[ind] - yrs[0])
+ GAchangeInst[i] = (GA[2] - GA[1]) / dt[2]
+ VAFchange[i] = (VAF[ind] - VAF[0]) / (yrs[ind] - yrs[0])
+ VAFchange[i] = (VAF[ind] - VAF[ind2]) / (yrs[ind] - yrs[ind2])
+ VAFchangeInst[i] = (VAF[2] - VAF[1]) / dt[2]
+ GLfchange[i] = (GLf[ind] - GLf[0]) / (yrs[ind] - yrs[0])
+ GLfchangeInst[i] = (GLf[2] - GLf[1]) / dt[2]
+ f.close()
+ else:
+ print "err"
+ # plot multiple years on the plots set up above
+ ind = np.where(perturbs==1.0)[0][0]
+ axVAF.plot(meltMag, VAFchange, '.', label="{} yr".format(yr))
+ axVAF.plot(meltMag[ind], VAFchange[ind], 'k.')
+ ind06 = np.argmin(np.absolute(perturbs-0.6))
+ ind14 = np.argmin(np.absolute(perturbs-1.4))
+ axVAF.plot(meltMag[ind], VAFchange[ [ind06, ind14] ].mean(), 'kx')
+ rng = np.arange(0,nruns-ind)
+ axPctDiff.plot(perturbs[ind+rng]-perturbs[ind], ((VAFchange[ind+rng] - VAFchange[ind]) - (VAFchange[ind] - VAFchange[ind-rng])) / VAFchange[ind] * 100.0, '.')
+ axAbsDiff.plot(perturbs[ind+rng]-perturbs[ind], (VAFchange[ind+rng] - VAFchange[ind]) - (VAFchange[ind] - VAFchange[ind-rng]) , '.')
+
+axVAF.legend()
+
+# plot ===============
+ind = np.where(perturbs==1.0)[0][0]
+
+fig = plt.figure(1, facecolor='w', figsize=(10,10))
+axGA = fig.add_subplot(3,2,1)
+plt.plot(meltMag, GAchange, '.')
+plt.plot(meltMag[ind], GAchange[ind], 'ko')
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('grounded area change\n (km$^2$/yr)')
+plt.grid()
+
+axGAinst = fig.add_subplot(3,2,2)
+plt.plot(meltMag, GAchangeInst, '.')
+plt.plot(meltMag[ind], GAchangeInst[ind], 'ko')
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('grounded area change\nin one time step (km$^2$)')
+plt.grid()
+
+axMelt = fig.add_subplot(3,2,3)
+plt.plot(meltMag, VAFchange, '.')
+plt.plot(meltMag[ind], VAFchange[ind], 'ko')
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('VAF change (Gt/yr)')
+plt.grid()
+
+axMelt = fig.add_subplot(3,2,4)
+plt.plot(meltMag, VAFchangeInst, '.')
+plt.plot(meltMag[ind], VAFchangeInst[ind], 'ko')
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('VAF change\nin one time step (Gt)')
+plt.grid()
+
+axMelt = fig.add_subplot(3,2,5)
+plt.plot(meltMag, GLfchange, '.')
+plt.plot(meltMag[ind], GLfchange[ind], 'ko')
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('GL flux change\n (Gt yr$^{-1}$/yr)')
+plt.grid()
+
+axMelt = fig.add_subplot(3,2,6)
+plt.plot(meltMag, GLfchangeInst, '.')
+plt.plot(meltMag[ind], GLfchangeInst[ind], 'ko')
+plt.xlabel('ice shelf melt rate (Gt yr$^{-1}$)')
+plt.ylabel('GL flux change\nin one time step (Gt yr$^{-1}$)')
+plt.grid()
+
+fig.tight_layout()
+
+
+plt.show()
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/plot_melt_vs_thermocline.py b/testing_and_setup/compass/landice/Thwaites_variability/plot_melt_vs_thermocline.py
new file mode 100755
index 0000000000..e45fe55f65
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/plot_melt_vs_thermocline.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+'''
+Script to compare some scalar values from different runs of Thwaites melt variability experiment.
+'''
+
+import sys
+import os
+import netCDF4
+import numpy as np
+import matplotlib.pyplot as plt
+
+outfname = 'globalStats.nc'
+runs=[ adir for adir in sorted(os.listdir('.')) if (os.path.isdir(adir) and 'adjust'in adir and os.path.isfile(os.path.join(adir, outfname)))]
+print "Original run list:", runs
+
+fig = plt.figure(1, facecolor='w')
+nrow = 1; ncol = 1;
+ax1 = fig.add_subplot(nrow, ncol, 1)
+plt.ylabel('depth to mCDW (m)')
+plt.xlabel('mean melt (m/yr)')
+#plt.xticks(np.arange(30)*xtickSpacing)
+plt.grid()
+
+baseDepth = -700.0
+runNumber = 0
+for run in runs:
+ print "Plotting run: " + run
+ depthChange = float(run[6:])
+ depth = baseDepth + depthChange
+
+ f = netCDF4.Dataset(run+"/globalStats.nc", 'r')
+ avgMelt = f.variables['avgSubshelfMelt'][-1]
+ totalMelt = f.variables['totalFloatingBasalMassBal'][-1]
+
+ ax1.plot(avgMelt, depth, '.k')
+ print depthChange, depth, avgMelt
+
+plt.show()
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/setup_many_runs.sh b/testing_and_setup/compass/landice/Thwaites_variability/setup_many_runs.sh
index 41ed66936c..85fc81a527 100755
--- a/testing_and_setup/compass/landice/Thwaites_variability/setup_many_runs.sh
+++ b/testing_and_setup/compass/landice/Thwaites_variability/setup_many_runs.sh
@@ -30,7 +30,7 @@ if [ $SETUP = 1 ]; then
# remove some unneeded garbage
rm ./make_graph_file.py ./metis ./setup_model.py
# remove symlink to a few files
- cp --remove-destination `readlink albany_input.xml` albany_input.xml
+ cp --remove-destination `readlink albany_input.yaml` albany_input.yaml
cp --remove-destination `readlink slurm.wolf.run` slurm.wolf.run
cp --remove-destination `readlink slurm.edison_bundle.run` slurm.edison_bundle.run
fi
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/setup_thermocline_pertubs.sh b/testing_and_setup/compass/landice/Thwaites_variability/setup_thermocline_pertubs.sh
new file mode 100755
index 0000000000..0fa76aaeff
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/setup_thermocline_pertubs.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# bash script to set up a suite of Thwaites variability runs
+
+
+# ===========================
+
+# Manually set/check these variables before running!
+
+BASE_DIR=`pwd` # Path in which all the versions will be set up
+#TEMPLATE_DIR=/scratch1/scratchdirs/hoffman2/thwaites_variability_ensemble_25pctGLcalc_from_year5_steady_from_bedmap2_D15_kappa11.0_sill663/run_template_base
+TEMPLATE_DIR=`pwd`/adjust+000
+
+elevs="-025 -050 -075 -100 -125 -150 -175 -200 -225 -250 -275 -300 +025 +050 +075 +100 +125 +150 +175 +200 +225 +250 +275 +300"
+
+# ==========================
+
+
+
+nlfile="namelist.landice"
+# now create all the instances in a flat dir structure
+
+cp ../slurm.edison.run .
+
+for elev in $elevs; do
+ cd $BASE_DIR
+
+ # build the dir name
+ dirname=adjust${elev}
+
+ # === Setting up the run ===
+ echo Setting up: $dirname
+ cp -r $TEMPLATE_DIR $dirname
+
+ # update the nl settings
+ cd $BASE_DIR/$dirname
+ udepth=`grep config_temperature_profile_thermocline_upper_depth $nlfile |cut -d "=" -f 2 |tr -d " " |cut -d "." -f 1`
+ echo udepth is $udepth
+ udepthnew=`python -c "x=$udepth;y=int('$elev'); print x+y"`
+ echo udepthnew is $udepthnew
+ sed -i.SEDBACKUP "s/config_temperature_profile_thermocline_upper_depth.*/config_temperature_profile_thermocline_upper_depth = $udepthnew/" $nlfile
+ ldepth=`grep config_temperature_profile_thermocline_lower_depth $nlfile |cut -d "=" -f 2 |tr -d " " |cut -d "." -f 1`
+ ldepthnew=`python -c "x=$ldepth;y=int('$elev'); print x+y"`
+ sed -i.SEDBACKUP "s/config_temperature_profile_thermocline_lower_depth.*/config_temperature_profile_thermocline_lower_depth = $ldepthnew/" $nlfile
+ rm $nlfile.SEDBACKUP
+
+ # add this run to the edison bundle
+ echo "cd ${BASE_DIR}/${dirname}" >> ../slurm.edison.run
+ echo "srun -n 48 -N 1 ../landice_model " >> ../slurm.edison.run
+done
+
+
+cd $BASE_DIR
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/subshelf_melt_parameterization.py b/testing_and_setup/compass/landice/Thwaites_variability/subshelf_melt_parameterization.py
new file mode 100755
index 0000000000..9c7f11f52f
--- /dev/null
+++ b/testing_and_setup/compass/landice/Thwaites_variability/subshelf_melt_parameterization.py
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+
+import numpy
+import matplotlib.pyplot as plt
+import os.path
+import netCDF4
+from matplotlib import cm
+
+# constants
+
+# Made up (typical for MISOMIP1, for example)
+SRef = 34.4
+
+# Constant for the non-local, quadratic melt parameterizaitotn
+Kappa = 8.5
+
+# slope of the ice draft
+alpha = 1e-2
+
+# thickness of the plume (m)
+D = 30.
+
+print "Kappa={}, D={}, alpha={}".format(Kappa, D, alpha)
+# Entrainment parameter (Jenkins 1991)
+E0 = 0.036
+
+# Stanton number (Jenkins et al. 2010)
+St = 5.9e-4
+
+
+iDepth=-1
+
+# Set depth of grounding line here
+# zGL = -1500.
+## zGL =-688.
+## zGL =-644.
+zGL =-693. # value MALI gets for initial condition of Thwaites domain
+zCF = -173. # calving front depth from Thwaites initial condition
+
+#zGL=-1453.0; zCF=-202.0 # TG sim at yr 325
+#zGL=-1107.0; zCF=-101.0 # TG sim at yr 225
+#zGL=-1235.0; zCF=-125.0 # TG sim approx at both 285 & 430
+
+
+# use a list to see how the melt rate changes with different profiles.
+# use a list with one entry to just plot up a single case.
+zLow = -1001.
+zUppers = numpy.linspace(-0.,-600., 13); zLow = zGL-400. # for variability histogram/profile plot (7)
+#zUppers = numpy.linspace(-0.,-600., 5); zLow = zGL-400. # For variability range plot in paper (Fig. 3)
+#zUppers = numpy.array([-200., -400.])
+#zUppers = numpy.array([-500.])
+#zUppers = numpy.array([-300.]); zLow = zGL-100.0 # "standard" value for Pine Island Bay
+
+zSill = -663. # estimate used for Thwaites
+
+# idealized Pine Island Bay temperatures
+TUpper = -1.
+TLower = 1.2
+
+
+# =============
+
+meanMeltRates = numpy.zeros((len(zUppers),))
+GLMeltRates = numpy.zeros((len(zUppers),))
+
+figVar = plt.figure(150, facecolor='w', figsize=(14, 4))
+nrow = 1; ncol = 3;
+
+# temperature plot
+axTvar = figVar.add_subplot(nrow, ncol, 1)
+plt.xlabel('ocean temperature ($^{\circ}$C)')
+plt.ylabel('depth (m)')
+plt.grid()
+axTvar.text(-0.15, 0.95, 'a', transform=axTvar.transAxes, fontsize=14, fontweight='bold')
+
+
+# melt plot
+axMeltvar = figVar.add_subplot(nrow, ncol, 2)
+plt.xlabel('melt rate (m yr$^{-1}$)')
+plt.ylabel('depth (m)')
+plt.grid()
+axMeltvar.text(-0.15, 0.95, 'b', transform=axMeltvar.transAxes, fontsize=14, fontweight='bold')
+
+# histogram
+axHist = figVar.add_subplot(nrow, ncol, 3)
+#plt.xlabel('ice shelf area (km$^2$)')
+plt.xlabel('fraction of ice shelf area')
+plt.ylabel('depth (m)')
+axHist.text(-0.15, 0.95, 'c', transform=axHist.transAxes, fontsize=14, fontweight='bold')
+
+if len(zUppers)>6:
+ nOneSide = (len(zUppers)-1)/2
+ colorsOneSide = numpy.array( [ cm.cool(x) for x in numpy.linspace(0.0, 1.0, nOneSide) ])
+ #print colorsOneSide
+else:
+ nOneSide = 2
+ colorsOneSide = numpy.flip(numpy.array( [ cm.bwr(x) for x in numpy.linspace(0.0, 1.0, nOneSide) ]),0)
+ colors = numpy.vstack( (colorsOneSide, [0,0,0,1], numpy.flip(colorsOneSide,0)))
+colors = numpy.vstack( (colorsOneSide, [0,0,0,1], numpy.flip(colorsOneSide,0)))
+
+for zUpper in zUppers:
+ iDepth = iDepth+1
+ print "iDepth={}, zUpper={}".format(iDepth, zUpper)
+
+ z = numpy.linspace(0., zLow, 1001)
+
+ zLower = zUpper - 400.
+
+ TRegional = numpy.zeros(z.shape)
+
+ TRegional[z >= zUpper] = TUpper
+ TRegional[z <= zLower] = TLower
+ mask = numpy.logical_and(z < zUpper, z > zLower)
+ TRegional[mask] = \
+ (TUpper - TLower)*(z[mask] - zLower)/(zUpper - zLower) + TLower
+
+ TSill = numpy.interp(zSill, z[::-1], TRegional[::-1])
+
+ TCavity = TRegional.copy()
+ TCavity[z <= zSill] = TSill
+
+ # Jenkins (1991)
+ TFreeze = 0.0901 - 0.0575*SRef + 7.61e-4*z
+
+ # length scale of decay of plume temperature
+ zeta = alpha*D/(E0*alpha + St)
+
+ # limit of exponental decay of T
+ TInfinity = (E0*alpha*TCavity + St*TFreeze)/(E0*alpha + St)
+
+ TGL = numpy.interp(zGL, z[::-1], TCavity[::-1])
+
+ exponent = numpy.minimum(-(z-zGL)/zeta, 0.)
+
+ TPlume = TInfinity + (TGL - TInfinity)*numpy.exp(exponent)
+
+ plt.figure(iDepth, figsize=(9,4))
+ plt.subplot(1,2,1)
+ plt.title("kappa={}, D={}, alpha={}, zGL={}".format(Kappa, D, alpha, zGL))
+ plt.plot(TRegional, z, label='TRegional')
+ plt.plot(TCavity, z, label='TCavity')
+ plt.plot(TFreeze, z, label='TFreeze')
+ plt.plot(TInfinity, z, label='TInfinity')
+ plt.plot(TPlume, z, label='TPlume')
+ plt.legend()
+
+ ThermalForcing = TPlume - TFreeze
+
+ ind = numpy.where(numpy.logical_and(z>zGL, zzGL].mean()
+ print "integrated melt rate=", meanMeltRates[iDepth]
+
+ GLMeltRates[iDepth] = meltRate[numpy.argmin(numpy.absolute((z-zGL))).min()]
+
+ # plot onto temp/melt var plot
+ axTvar.plot(TRegional, z, label='$T_{regional}$', color=colors[iDepth,:])
+ axMeltvar.plot(meltRate, z, color=colors[iDepth,:])
+
+ if len(zUppers) == 1:
+ # If only one plot was requested, also do a 'clean' version for the paper
+ #plt.rc('text', usetex=True)
+ fig = plt.figure(101, facecolor='w', figsize=(12, 5))
+ nrow = 1; ncol = 3;
+
+ # temperature plot
+ axT = fig.add_subplot(nrow, ncol, 1)
+ plt.xlabel('ocean temperature ($^{\circ}$C)')
+ plt.ylabel('depth (m)')
+ plt.grid()
+ axT.text(-0.15, 0.95, 'a', transform=axT.transAxes, fontsize=14, fontweight='bold')
+
+ plt.plot(TRegional, z, label='$T_{regional}$')
+ plt.plot(TCavity, z, label='$T_{cavity}$')
+ plt.plot(TFreeze, z, label='$T_{freeze}$')
+ plt.plot(TInfinity, z, label='$T_{infinity}$')
+ plt.plot(TPlume, z, label='$T_{plume}$')
+ plt.plot([TFreeze.min(), TRegional.max()], zGL*numpy.array([1.0, 1.0]), '--k', label='$z_{GL}$')
+ plt.plot([TFreeze.min(), TRegional.max()], zCF*numpy.array([1.0, 1.0]), ':k', label='$z_{CF}$')
+ plt.plot([TFreeze.min(), TRegional.max()], zSill*numpy.array([1.0, 1.0]), '-.k', label='$z_{sill}$')
+ plt.legend()
+
+ # TF plot
+ axTF = fig.add_subplot(nrow, ncol, 2)
+ plt.xlabel('thermal forcing ($^{\circ}$C)')
+ plt.ylabel('depth (m)')
+ plt.grid()
+ plt.plot(ThermalForcing, z, label='$TF_{local}$')
+ plt.plot(TFMean*numpy.array([1.0, 1.0]), [zGL, zCF], label='$TF_{mean}$', linewidth=3)
+ plt.plot([0.0, ThermalForcing.max()], zGL*numpy.array([1.0, 1.0]), '--k', label='$z_{GL}$')
+ plt.plot([0.0, ThermalForcing.max()], zCF*numpy.array([1.0, 1.0]), ':k', label='$z_{CF}$')
+ plt.legend()
+ axTF.text(-0.15, 0.95, 'b', transform=axTF.transAxes, fontsize=14, fontweight='bold')
+
+
+ # melt plot
+ axMelt = fig.add_subplot(nrow, ncol, 3)
+ plt.xlabel('melt rate (m yr$^{-1}$)')
+ plt.ylabel('depth (m)')
+ plt.grid()
+ axMelt.text(-0.15, 0.95, 'c', transform=axMelt.transAxes, fontsize=14, fontweight='bold')
+ # plot Rignot obs if available
+ obsFile = '/Users/mhoffman/Documents/PAPERS_PRESENTATIONS/2017_Thwaites_variability/melt_param_testing/iceshelf_melt_param_test/thwaites_1-8km_resolution.cleaned.withRignotMelt.nc'
+ if os.path.isfile(obsFile):
+ f = netCDF4.Dataset(obsFile, 'r')
+ meltObs = f.variables['floatingBasalMassBal'][0,:] / 910.0 * 3600.0 * 24.0 * 365.0
+ #ind = numpy.nonzero(meltObs != 0.0)
+ lowerSurface = f.variables['lowerSurface'][0,:]
+ xCell = f.variables['xCell'][:]
+ yCell = f.variables['yCell'][:]
+ f.close()
+ # divide into east and west shelf regions
+ x1=-1590948.400363433; y1=-459735.6052551331;
+ x2=-1531877.338559778; y2=-440731.18578141753;
+ m = (y2-y1)/(x2-x1); b = y1-m*x1
+ ind1 = numpy.nonzero(numpy.logical_and(meltObs!=0.0, yCell>=m*xCell+b))
+ ind2 = numpy.nonzero(numpy.logical_and(meltObs!=0.0, yCell< m*xCell+b))
+
+ plt.plot(meltObs[ind1], lowerSurface[ind1], '.', label='$obs_{east}$', markersize = 1)
+ plt.plot(meltObs[ind2], lowerSurface[ind2], '.', label='$obs_{west}$', markersize = 1)
+ # now plot param.
+ plt.plot(meltRate, z, label='model')
+ plt.plot([0.0, meltRate.max()], zGL*numpy.array([1.0, 1.0]), '--k', label='$z_{GL}$')
+ plt.plot([0.0, meltRate.max()], zCF*numpy.array([1.0, 1.0]), ':k', label='$z_{CF}$')
+ plt.legend()
+ axMelt.set_ylim(axTF.get_ylim())
+
+ plt.tight_layout()
+
+
+# clean up temp/melt var plot
+xmin=-1.0; xmax=1.2;
+axTvar.plot([xmin, xmax], zGL*numpy.array([1.0, 1.0]), '--k', label='$z_{GL}$')
+axTvar.plot([xmin, xmax], zCF*numpy.array([1.0, 1.0]), ':k', label='$z_{CF}$')
+axTvar.plot([xmin, xmax], zSill*numpy.array([1.0, 1.0]), '-.k', label='$z_{sill}$')
+
+axMeltvar.set_ylim(axTvar.get_ylim())
+xmax=72.0
+axMeltvar.plot([0.0, xmax], zGL*numpy.array([1.0, 1.0]), '--k', label='$z_{GL}$')
+axMeltvar.plot([0.0, xmax], zCF*numpy.array([1.0, 1.0]), ':k', label='$z_{CF}$')
+axMeltvar.plot([0.0, xmax], zSill*numpy.array([1.0, 1.0]), '-.k', label='$z_{sill}$')
+
+# plot histogram data
+outFile = '/Users/mhoffman/Documents/PAPERS_PRESENTATIONS/2017_Thwaites_variability/2018_OUTPUT/D30_control/output.nc'
+if os.path.isfile(outFile):
+ f = netCDF4.Dataset(outFile, 'r')
+ areaCell = f.variables['areaCell'][:] / 1000.0/1000.0
+ lsrf285 = f.variables['lowerSurface'][285,:]
+ mask285 = f.variables['cellMask'][285,:]
+ ind285 = numpy.nonzero(mask285&4>0)
+ bins = numpy.linspace(-1400.0, 0.0, 31)
+ axHist.hist(lsrf285[ind285], bins=bins, weights=areaCell[ind285]/areaCell[ind285].sum(), orientation="horizontal", alpha=0.5, label='year 285')
+
+ lsrf430 = f.variables['lowerSurface'][430,:]
+ mask430 = f.variables['cellMask'][430,:]
+ ind430 = numpy.nonzero(mask430&4>0)
+ axHist.hist(lsrf430[ind430], bins=bins, weights=areaCell[ind430]/areaCell[ind430].sum(), orientation="horizontal", alpha=0.5, label='year 430')
+ axHist.legend()
+
+
+
+figVar.tight_layout()
+
+
+
+if len(zUppers) > 1:
+ # plot summarizing everything for mean melt rate
+ plt.figure(200)
+ plt.plot(meanMeltRates, zUppers, '.')
+ plt.plot(meanMeltRates, zUppers-400.0, '.')
+ plotMeltMax=meanMeltRates.max()
+ plt.plot([0.0, plotMeltMax], [zSill, zSill],'r--')
+ plt.plot([0.0, plotMeltMax], [-700, -700],'k-')
+ plt.plot([0.0, plotMeltMax], [-400, -400],'k:')
+ plt.plot([0.0, plotMeltMax], [-1000, -1000],'k:')
+ #plt.plot([0.0, plotMeltMax], [-800, -800],'k-')
+ plt.xlabel('mean melt rate (m/yr)')
+ plt.ylabel('depth of thermocline (m)')
+ plt.title("kappa={}, D={}, alpha={}, zGL={}, zSill={}".format(Kappa, D, alpha, zGL, zSill))
+ plt.grid()
+
+ # repeat for melt at GL
+ plt.figure(201)
+ plt.plot(GLMeltRates, zUppers, '.')
+ plt.plot(GLMeltRates, zUppers-400.0, '.')
+ plotMeltMax=GLMeltRates.max()
+ plt.plot([0.0, plotMeltMax], [zSill, zSill],'r--')
+ plt.plot([0.0, plotMeltMax], [-700, -700],'k-')
+ plt.plot([0.0, plotMeltMax], [-400, -400],'k:')
+ plt.plot([0.0, plotMeltMax], [-1000, -1000],'k:')
+ #plt.plot([0.0, plotMeltMax], [-800, -800],'k-')
+ plt.xlabel('GL melt rate (m/yr)')
+ plt.ylabel('depth of thermocline (m)')
+ plt.title("kappa={}, D={}, alpha={}, zGL={}, zSill={}".format(Kappa, D, alpha, zGL, zSill))
+ plt.grid()
+
+plt.show()
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/thwaites_template.xml b/testing_and_setup/compass/landice/Thwaites_variability/thwaites_template.xml
index 25264a4408..2b8d558c90 100644
--- a/testing_and_setup/compass/landice/Thwaites_variability/thwaites_template.xml
+++ b/testing_and_setup/compass/landice/Thwaites_variability/thwaites_template.xml
@@ -86,7 +86,7 @@
0000-00-01_00:00:00
0000-01-01_00:00:00
overwrite
- netcdf
+
diff --git a/testing_and_setup/compass/landice/Thwaites_variability/uniform_resolution/resolution_testing_configuration/config_setup_experiments.xml b/testing_and_setup/compass/landice/Thwaites_variability/uniform_resolution/resolution_testing_configuration/config_setup_experiments.xml
index 7c826b3b5c..551df9f9f6 100644
--- a/testing_and_setup/compass/landice/Thwaites_variability/uniform_resolution/resolution_testing_configuration/config_setup_experiments.xml
+++ b/testing_and_setup/compass/landice/Thwaites_variability/uniform_resolution/resolution_testing_configuration/config_setup_experiments.xml
@@ -2,19 +2,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -38,49 +27,52 @@
-
+
+ 52
+ 32
+ 8000.0
-
+
grid.nc
-
+
grid.nc
culled_grid1.nc
-
+
culled_grid1.nc
-1.65e6
-560000.0
-
+
culled_grid1.nc
ais-bedmap2
-
+
culled_grid1.nc
thwaites_mask.nc
thwaites_minimal.geojson
-
+
culled_grid1.nc
culled_grid2.nc
thwaites_mask.nc
-
+
culled_grid2.nc
thwaites_uniform_resolution.nc
10
@@ -90,14 +82,14 @@
-
+
ais_input_data.nc
thwaites_uniform_resolution.nc
d
-
+
thwaites_uniform_resolution.nc
@@ -107,7 +99,7 @@
diff --git a/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/README b/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/README
new file mode 100644
index 0000000000..4573dfbc2a
--- /dev/null
+++ b/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/README
@@ -0,0 +1,20 @@
+This directory creates a very coarse 200 to 40 km variable resolution mesh for Antarctica
+that can be used for rapid testing with a (semi-) realistic geometry,
+
+The variable resolution mesh is generated using JIGSAW-GEO:
+https://github.com/dengwirda/jigsaw-geo-matlab
+JIGSAW-GEO needs to be run manually from Matlab before running the rest of this case.
+(It may be possible to include that step in the set up process, but it seems like
+more trouble than it is worth for now.)
+
+To create the mesh, run the .m script in the subdirectory 'jigsaw',
+and then copy or link the resulting .msh file into this directory.
+
+Also, a source file for interpolating the initial condition must be specified.
+By default, the system looks for: antarctica_8km_2018_04_20.nc
+This file must be copied/linked into the test case setup directory, or a
+different file can be used instead if the test case is adjusted.
+Similarly, the script will look for a temperature IC file called
+ais_temp_pattyn_cism_format.5km.filled.nc.
+
+After this is complete, set up and run the test case as normal.
diff --git a/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/config_setup_experiments.xml b/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/config_setup_experiments.xml
new file mode 100644
index 0000000000..06ec2a10c0
--- /dev/null
+++ b/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/config_setup_experiments.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ais200to40km-MESH.msh
+ ais200to40km_jigsaw_netcdf.nc
+
+
+
+
+ ais200to40km_jigsaw_netcdf.nc
+ mpas.nc
+
+
+
+
+ mpas.nc
+ ais-bedmap2
+
+
+
+
+ mpas.nc
+ li_full.nc
+ 1
+
+
+
+
+ ais_input_data.nc
+ li_full.nc
+ b
+
+
+
+
+
+ li_full.nc
+ numCells
+
+
+
+
+ li_full.nc
+ culled_grid.nc
+
+
+
+
+ culled_grid.nc
+ culled_grid_converted.nc
+
+
+
+
+ culled_grid_converted.nc
+ ais_200_to_40_km.nc
+ 10
+ glimmer
+
+
+
+
+
+
+
+ ais_input_data.nc
+ ais_200_to_40_km.nc
+ b
+
+
+
+
+ ais_temperature_input_data.nc
+ ais_200_to_40_km.nc
+ b
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/jigsaw/ais_200to40km_jigsaw.m b/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/jigsaw/ais_200to40km_jigsaw.m
new file mode 100644
index 0000000000..4c3396e5c1
--- /dev/null
+++ b/testing_and_setup/compass/landice/antarctica/200to40km_AIS_jigsaw/standard_configuration/jigsaw/ais_200to40km_jigsaw.m
@@ -0,0 +1,385 @@
+%function ais_100to20km_jigsaw()
+% 100to20km ais mesh
+
+ name = 'ais200to40km';
+
+ %addpath('dual-mesh');
+
+%------------------------------------ setup files for JIGSAW
+
+ opts.geom_file = ... % GEOM file
+ [name '-GEOM.msh'];
+
+ opts.jcfg_file = ... % JCFG file
+ [name '.jig'];
+
+ opts.mesh_file = ... % MESH file
+ [name '-MESH.msh'];
+
+ opts.hfun_file = ... % HFUN file
+ [name '-HFUN.msh'];
+
+%------------------------------------ define JIGSAW geometry
+
+ geom.mshID = 'EUCLIDEAN-MESH';
+
+ x0=-3.0e6; x1=3.0e6;
+ y0=-2.5e6; y1=2.5e6;
+ geom.point.coord = [ % list of xy "node" coordinates
+ x0, y0, 0
+ x1, y0, 0
+ x1, y1, 0
+ x0, y1, 0 ] ;
+
+ geom.edge2.index = [ % list of "edges" between nodes
+ 1, 2, 0
+ 2, 3, 0
+ 3, 4, 0
+ 4, 1, 0 ] ;
+
+ savemsh(opts.geom_file, geom) ;
+
+%------------------------------------ compute HFUN over GEOM
+
+%% read density function from a file
+% densFile='density.nc';
+% xpos=ncread(densFile, 'x');
+% ypos=ncread(densFile, 'y');
+% dens = ncread(densFile, 'density')';
+% hfun = dens.^-0.25*1000.0 * 10.0;
+%
+%
+%
+%
+% [XPOS,YPOS] = meshgrid(xpos,ypos) ;
+%
+%
+% hmat.mshID = 'EUCLIDEAN-GRID' ;
+% hmat.point.coord{1} = xpos ;
+% hmat.point.coord{2} = ypos ;
+% hmat.value = hfun ;
+%
+%
+% savemsh(opts.hfun_file,hmat) ;
+
+
+%% calculate density based on new criteria related to geometry
+
+%% load AIS data file
+
+aisFile = '/Users/mhoffman/documents/antarctica_data/piscees_complete/AIS/antarctica_8km_2018_04_20.nc';
+x1=ncread(aisFile, 'x1');
+y1=ncread(aisFile, 'y1');
+thk = ncread(aisFile, 'thk')';
+topg = ncread(aisFile, 'topg')';
+
+dx = x1(2)-x1(1);
+nx = length(x1);
+ny = length(y1);
+
+
+%% calculate mask of marine-based bed areas that are connected to the ocean
+%
+% marineElevationWAIS = -300.0; % elevation to consider marine bed
+% marineElevationEAIS = -300.0; % elevation to consider marine bed
+%
+%
+% % initialize mask
+maskSize = size(thk);
+% marineMask = zeros(maskSize, 'int8');
+% marineMask(2,2:end-1) = 1;
+% marineMask(end-1,2:end-1) = 1;
+% marineMask(2:end-1,2) = 1;
+% marineMask(2:end-1,end-1) = 1;
+%
+% lastSearchList = find(marineMask==1); % indices searched last iteration
+%
+% marineMask(1,:) = 1;
+% marineMask(end,:) = 1;
+% marineMask(:,1) = 1;
+% marineMask(:,end) = 1;
+%
+% searchedMask = marineMask;
+%
+%
+%
+% neighbors=[[1,0]; [-1,0]; [0,1]; [0,-1]]';
+%
+% % flood fill with elevation threshold
+% while (length(lastSearchList) > 0)
+% newSearchList = [];
+%
+% for iii=1:length(lastSearchList);
+% [i, j] = ind2sub(maskSize, lastSearchList(iii));
+% % search neighbors
+% for n=neighbors;
+% %n
+% ii=i+n(1); jj=j+n(2); % subscripts to neighbor
+% if searchedMask(ii,jj) == 0; % only consider unsearched neighbors
+% searchedMask(ii,jj) = 1; % mark as searched
+% if x1(j) > -500.0e3
+% marineElevation = marineElevationEAIS;
+% else
+% marineElevation = marineElevationWAIS;
+% end
+%
+% if (topg(ii, jj) < marineElevationWAIS & x1(j) < -500.0e3 ) | ... % check bed elevation for WAIS
+% (topg(ii, jj) < marineElevationEAIS & x1(j) > -500.0e3 & thk(ii,jj)<2500.0 ) | ... % check bed elevation AND ice thickness for EAIS
+% (thk(ii,jj) ==0.0); % include ice-free areas in marine mask (most connected ice-free areas are open ocean)
+% marineMask(ii,jj) = 1; % mark as marine
+% newSearchList = [newSearchList, sub2ind(maskSize, ii, jj)]; % add to list of newly found marine cells
+% end
+% end % if unsearched
+% end % 4 neighbors
+% end % one of found locations last time
+% lastSearchList = newSearchList;
+% end
+%
+%
+% figure(99); clf; hold all
+% pcolor(marineMask)
+% shading flat
+% colorbar
+% axis equal
+
+
+
+%% make masks
+
+
+neighbors=[[1,0]; [-1,0]; [0,1]; [0,-1]; [1,1]; [-1,-1]; [-1,1]; [1,-1]]';
+
+groundedMask = (thk > -1028.0/910.0 * topg);
+floatingMask = ~groundedMask & thk>0.0;
+
+
+% groundedNeighborMask = marineMask*0;
+% for n=neighbors;
+% groundedNeighborMask = groundedNeighborMask | ~(circshift(marineMask, n));
+% end
+% marineEdgeMask = marineMask & groundedNeighborMask; % where ice is floating and neighboring non-floating locations
+
+
+% ice margin mask
+marginMask = groundedMask*0;
+iceMask = thk>0;
+for n=neighbors;
+ marginMask = marginMask | ~(circshift(iceMask, n));
+end
+marginMask = marginMask & iceMask; % where ice exists and neighbors non-ice locations
+
+
+% GL mask
+GLMask = groundedMask*0;
+for n=neighbors;
+ GLMask = GLMask | (circshift(groundedMask, n));
+end
+GLMask = floatingMask & GLMask; % where ice exists and neighbors non-ice locations
+
+
+
+% == define edgeMask as the locations from which distance is calculated ===
+%edgeMask = marineEdgeMask; % just edge of the marine ice sheet
+%edgeMask = marineEdgeMask | marginMask; % edge of marine ice sheet or edge of entire ice sheet
+%edgeMask = marineEdgeMask | GLMask; % edge of marine ice sheet or GL
+
+edgeMask = GLMask; % search just around GL
+
+GLind = find(edgeMask==1);
+nGL = length(GLind);
+
+figure(98); clf; hold all
+pcolor(edgeMask)
+shading flat
+colorbar
+axis equal
+
+
+[YPOS,XPOS] = meshgrid(x1,y1);
+
+%% calculate distance to marine-based bed
+distToMarine = thk*0.0;
+
+% -- KEY PARAMETER: how big of a search 'box' (one-directional) to use.
+% Bigger number makes search slower, but if too small, the transition zone
+% could get truncated.
+% (could automatically set this from maxDist variables used in next section.)
+windowSize = 400.0e3;
+% ---
+
+d = int32(ceil(windowSize / dx))
+%d=80;
+rng = [-1*d:d];
+maxdist = double(d) * dx
+
+%ind = find( (marineMask==0) | (thk<(-1028/910*topg))); % just look over non-marine areas
+ind = find( thk > -1.0); % look everywhere
+for iii=1:length(ind);
+ [i, j] = ind2sub(maskSize, ind(iii));
+
+
+ irng = i+rng;
+ jrng = j+rng;
+
+ irng = irng(find(irng>0 & irng < nx));
+ jrng = jrng(find(jrng>0 & jrng < ny));
+
+ dist2Here = ((XPOS(irng,jrng)-x1(i)).^2 + (YPOS(irng,jrng)-y1(j)).^2).^0.5;
+ dist2Here(edgeMask(irng,jrng)==0) = maxdist;
+ distToMarine(i,j) = min(dist2Here(:));
+% minDist = 1.0e12;
+% for g = 1:nGL;
+% [ii,jj] = ind2sub(maskSize, GLind(g));
+% dist = sqrt((ii-i)^2 + (jj-j)^2) * dx;
+% minDist = min(minDist, dist);
+% end
+% distToMarine(i,j) = minDist;
+end
+
+
+figure(97); clf; hold all
+pcolor(distToMarine/1000.0)
+shading flat
+colorbar
+axis equal
+
+%% make spacing a fn of distance to GL
+
+
+
+% minSpacing = 10.0e3;
+% maxSpacing = 100.0e3;
+ minSpacing = 40.0e3;
+ maxSpacing = 200.0e3;
+
+ maxShelfSpacing = minSpacing * 3.0;
+
+ minDist = 0.0;
+ maxDist = 1000.0e3;
+
+ % linear - this is what should be used to get uniform 'doubling rate'
+ m = (maxSpacing-minSpacing) / (maxDist-minDist)
+ b = minSpacing - m * minDist;
+ % apply same density change rate everywhere
+ %hfun = m * distToMarine + b;
+
+ % apply slower density change rate where there is not grounded ice (floating ice and ice-free areas)
+ hfun = (m * groundedMask + 0.5 * m * ~groundedMask) .* distToMarine + b;
+
+% % power law (e.g. doubling every 100 km) - doesn't work well.
+% hfun = minSpacing * 2.^(distToMarine/100.0e3);
+
+
+ % apply min/max spacing values
+ hfun(hfunmaxSpacing) = maxSpacing;
+ % apply max spacing for ice shelves
+ hfun(floatingMask & hfun > maxShelfSpacing) = maxShelfSpacing;
+
+ hmat.value = hfun ;
+
+
+
+figure(96); clf; hold all
+pcolor(hfun/1000.0)
+shading flat
+colorbar
+axis equal
+
+
+%% save to jigsaw format
+
+ hmat.mshID = 'EUCLIDEAN-GRID' ;
+ hmat.point.coord{1} = x1 ;
+ hmat.point.coord{2} = y1 ;
+ hmat.value = hfun ;
+
+
+ savemsh(opts.hfun_file,hmat) ;
+
+
+%% ------------------------------------ build mesh via JIGSAW!
+
+ opts.hfun_scal = 'absolute';
+ opts.hfun_hmax = +inf ; % null HFUN limits
+ opts.hfun_hmin = 0.00 ;
+
+ opts.mesh_dims = +2 ; % 2-dim. simplexes
+
+ opts.optm_qlim = 0.9375 ;
+
+ opts.mesh_top1 = true ; % for sharp feat's
+ opts.geom_feat = true ;
+
+ mesh = jigsaw (opts) ;
+
+%------------------------------------ draw mesh/cost outputs
+
+ ang2 = triang2( ... % calc. tri-angles
+ mesh.point.coord(:,1:2), ...
+ mesh.tria3.index(:,1:3)) ;
+
+ t_90 = max(ang2,[],2) > 90.0 ;
+ t_95 = max(ang2,[],2) > 95.0 ;
+
+ figure(1); clf;
+ patch ('faces',geom.edge2.index(:,1:2), ...
+ 'vertices',geom.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[.1,.1,.1], ...
+ 'linewidth',1.5) ;
+ hold on; axis image;
+ title('JIGSAW GEOM data') ;
+%%
+ figure(2); clf; hold all;
+ pcolor(XPOS,YPOS,(hmat.value)');
+ axis equal;
+ shading interp ;
+ title('JIGSAW HFUN data') ;
+ patch ('faces',geom.edge2.index(:,1:2), ...
+ 'vertices',geom.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[1,.1,.1], ...
+ 'linewidth',1.5) ;
+ colorbar();
+%%
+
+ figure(3); clf;
+ patch ('faces',mesh.tria3.index(:,1:3), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[.2,.2,.2]) ;
+
+ hold on; axis image;
+ patch ('faces',mesh.tria3.index(t_90,1:3), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','y', ...
+ 'edgecolor',[.2,.2,.2]) ;
+ patch ('faces',mesh.tria3.index(t_95,1:3), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','r', ...
+ 'edgecolor',[.2,.2,.2]) ;
+ patch ('faces',mesh.edge2.index(:,1:2), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[.1,.1,.1], ...
+ 'linewidth',1.5) ;
+ axis equal
+ title('JIGSAW TRIA mesh') ;
+%%
+ drawscr(mesh.point.coord (:,1:2), ...
+ mesh.edge2.index (:,1:2), ...
+ mesh.tria3.index (:,1:3)) ;
+
+ drawnow ;
+% set(figure(1),'units','normalized', ...
+% 'position',[.05,.55,.30,.35]) ;
+% set(figure(2),'units','normalized', ...
+% 'position',[.35,.55,.30,.35]) ;
+% set(figure(3),'units','normalized', ...
+% 'position',[.35,.10,.30,.35]) ;
+% set(figure(4),'units','normalized', ...
+% 'position',[.05,.10,.30,.35]) ;
+ drawnow ;
+
+%end
diff --git a/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/README b/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/README
new file mode 100644
index 0000000000..1cbfa6e119
--- /dev/null
+++ b/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/README
@@ -0,0 +1,18 @@
+This directory creates a 2-20 km variable resolution mesh for Antarctica
+for ABUMIP - specifically uses highest resolution in all vulnerable marine sectors.
+
+The variable resolution mesh is generated using JIGSAW-GEO:
+https://github.com/dengwirda/jigsaw-geo-matlab
+JIGSAW-GEO needs to be run manually from Matlab before running the rest of this case.
+(It may be possible to include that step in the set up process, but it seems like
+more trouble than it is worth for now.)
+
+To create the mesh, run the .m script in the subdirectory 'jigsaw',
+and then copy or link the resulting file into this directory.
+
+Also, a source file for interpolating the initial condition must be specified.
+By default, the system looks for: antarctica_2km_2014_01_14.nc
+This file must be copied/linked into the test case setup directory, or a
+different file can be used instead if the test case is adjusted.
+
+After this is complete, set up and run the test case as normal.
diff --git a/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/config_setup_experiments.xml b/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/config_setup_experiments.xml
new file mode 100644
index 0000000000..a7dbe80ff7
--- /dev/null
+++ b/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/config_setup_experiments.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ais2km-MESH.msh
+ ais2km_jigsaw_netcdf.nc
+
+
+
+
+ ais2km_jigsaw_netcdf.nc
+ mpas_uncleaned.nc
+
+
+
+
+ mpas_uncleaned.nc
+ mpas.nc
+
+
+
+
+ mpas.nc
+ ais-bedmap2
+
+
+
+
+ mpas.nc
+ li_full.nc
+ 1
+
+
+
+
+ ais_input_data.nc
+ li_full.nc
+ b
+
+
+
+
+
+ li_full.nc
+ distance
+ 200.0
+
+
+
+
+ li_full.nc
+ culled_grid.nc
+
+
+
+
+ culled_grid.nc
+ culled_grid_converted.nc
+
+
+
+
+ culled_grid_converted.nc
+ ais_2_to_20_km.nc
+ 10
+
+
+
+
+
+
+
+ ais_input_data.nc
+ ais_2_to_20_km.nc
+ b
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/jigsaw/ais_2km_jigsaw.m b/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/jigsaw/ais_2km_jigsaw.m
new file mode 100644
index 0000000000..02dd695d6b
--- /dev/null
+++ b/testing_and_setup/compass/landice/antarctica/2km_ABUMIP_jigsaw/standard_configuration/jigsaw/ais_2km_jigsaw.m
@@ -0,0 +1,383 @@
+%function ais_2km_jigsaw()
+% 2km ais mesh
+
+ name = 'ais2km';
+
+ %addpath('dual-mesh');
+
+%------------------------------------ setup files for JIGSAW
+
+ opts.geom_file = ... % GEOM file
+ [name '-GEOM.msh'];
+
+ opts.jcfg_file = ... % JCFG file
+ [name '.jig'];
+
+ opts.mesh_file = ... % MESH file
+ [name '-MESH.msh'];
+
+ opts.hfun_file = ... % HFUN file
+ [name '-HFUN.msh'];
+
+%------------------------------------ define JIGSAW geometry
+
+ geom.mshID = 'EUCLIDEAN-MESH';
+
+ x0=-3.0e6; x1=3.0e6;
+ y0=-2.5e6; y1=2.5e6;
+ geom.point.coord = [ % list of xy "node" coordinates
+ x0, y0, 0
+ x1, y0, 0
+ x1, y1, 0
+ x0, y1, 0 ] ;
+
+ geom.edge2.index = [ % list of "edges" between nodes
+ 1, 2, 0
+ 2, 3, 0
+ 3, 4, 0
+ 4, 1, 0 ] ;
+
+ savemsh(opts.geom_file, geom) ;
+
+%------------------------------------ compute HFUN over GEOM
+
+%% read density function from a file
+% densFile='density.nc';
+% xpos=ncread(densFile, 'x');
+% ypos=ncread(densFile, 'y');
+% dens = ncread(densFile, 'density')';
+% hfun = dens.^-0.25*1000.0 * 10.0;
+%
+%
+%
+%
+% [XPOS,YPOS] = meshgrid(xpos,ypos) ;
+%
+%
+% hmat.mshID = 'EUCLIDEAN-GRID' ;
+% hmat.point.coord{1} = xpos ;
+% hmat.point.coord{2} = ypos ;
+% hmat.value = hfun ;
+%
+%
+% savemsh(opts.hfun_file,hmat) ;
+
+
+%% calculate density based on new criteria related to geometry
+
+%% load AIS data file
+
+aisFile = '/Users/mhoffman/documents/antarctica_data/piscees_complete/antarctica_8km_2014_01_14.nc';
+x1=ncread(aisFile, 'x1');
+y1=ncread(aisFile, 'y1');
+thk = ncread(aisFile, 'thk')';
+topg = ncread(aisFile, 'topg')';
+
+dx = x1(2)-x1(1);
+nx = length(x1);
+ny = length(y1);
+
+
+%% calculate mask of marine-based bed areas that are connected to the ocean
+
+marineElevationWAIS = -300.0; % elevation to consider marine bed
+marineElevationEAIS = -300.0; % elevation to consider marine bed
+
+
+% initialize mask
+maskSize = size(thk);
+marineMask = zeros(maskSize, 'int8');
+marineMask(2,2:end-1) = 1;
+marineMask(end-1,2:end-1) = 1;
+marineMask(2:end-1,2) = 1;
+marineMask(2:end-1,end-1) = 1;
+
+lastSearchList = find(marineMask==1); % indices searched last iteration
+
+marineMask(1,:) = 1;
+marineMask(end,:) = 1;
+marineMask(:,1) = 1;
+marineMask(:,end) = 1;
+
+searchedMask = marineMask;
+
+
+
+neighbors=[[1,0]; [-1,0]; [0,1]; [0,-1]]';
+
+% flood fill with elevation threshold
+while (length(lastSearchList) > 0)
+ newSearchList = [];
+
+ for iii=1:length(lastSearchList);
+ [i, j] = ind2sub(maskSize, lastSearchList(iii));
+ % search neighbors
+ for n=neighbors;
+ %n
+ ii=i+n(1); jj=j+n(2); % subscripts to neighbor
+ if searchedMask(ii,jj) == 0; % only consider unsearched neighbors
+ searchedMask(ii,jj) = 1; % mark as searched
+ if x1(j) > -500.0e3
+ marineElevation = marineElevationEAIS;
+ else
+ marineElevation = marineElevationWAIS;
+ end
+
+ if (topg(ii, jj) < marineElevationWAIS & x1(j) < -500.0e3 ) | ... % check bed elevation for WAIS
+ (topg(ii, jj) < marineElevationEAIS & x1(j) > -500.0e3 & thk(ii,jj)<2500.0 ) | ... % check bed elevation AND ice thickness for EAIS
+ (thk(ii,jj) ==0.0); % include ice-free areas in marine mask (most connected ice-free areas are open ocean)
+ marineMask(ii,jj) = 1; % mark as marine
+ newSearchList = [newSearchList, sub2ind(maskSize, ii, jj)]; % add to list of newly found marine cells
+ end
+ end % if unsearched
+ end % 4 neighbors
+ end % one of found locations last time
+ lastSearchList = newSearchList;
+end
+
+
+figure(99); clf; hold all
+pcolor(marineMask)
+shading flat
+colorbar
+axis equal
+
+
+
+%% make masks
+
+
+neighbors=[[1,0]; [-1,0]; [0,1]; [0,-1]; [1,1]; [-1,-1]; [-1,1]; [1,-1]]';
+
+groundedMask = (thk > -1028.0/910.0 * topg);
+floatingMask = ~groundedMask & thk>0.0;
+
+
+groundedNeighborMask = marineMask*0;
+for n=neighbors;
+ groundedNeighborMask = groundedNeighborMask | ~(circshift(marineMask, n));
+end
+marineEdgeMask = marineMask & groundedNeighborMask; % where ice is floating and neighboring non-floating locations
+
+
+% ice margin mask
+marginMask = marineMask*0;
+iceMask = thk>0;
+for n=neighbors;
+ marginMask = marginMask | ~(circshift(iceMask, n));
+end
+marginMask = marginMask & iceMask; % where ice exists and neighbors non-ice locations
+
+
+% GL mask
+GLMask = marineMask*0;
+for n=neighbors;
+ GLMask = GLMask | (circshift(groundedMask, n));
+end
+GLMask = floatingMask & GLMask; % where ice exists and neighbors non-ice locations
+
+
+
+% == define edgeMask as the locations from which distance is calculated ===
+%edgeMask = marineEdgeMask; % just edge of the marine ice sheet
+%edgeMask = marineEdgeMask | marginMask; % edge of marine ice sheet or edge of entire ice sheet
+edgeMask = marineEdgeMask | GLMask; % edge of marine ice sheet or GL
+
+
+GLind = find(edgeMask==1);
+nGL = length(GLind);
+
+figure(98); clf; hold all
+pcolor(edgeMask)
+shading flat
+colorbar
+axis equal
+
+
+[YPOS,XPOS] = meshgrid(x1,y1);
+
+%% calculate distance to marine-based bed
+distToMarine = thk*0.0;
+
+% -- KEY PARAMETER: how big of a search 'box' (one-directional) to use.
+% Bigger number makes search slower, but if too small, the transition zone
+% could get truncated.
+% (could automatically set this from maxDist variables used in next section.)
+windowSize = 400.0e3;
+% ---
+
+d = int32(ceil(windowSize / dx))
+%d=80;
+rng = [-1*d:d];
+maxdist = double(d) * dx
+
+ind = find( (marineMask==0) | (thk<(-1028/910*topg))); % just look over non-marine areas
+for iii=1:length(ind);
+ [i, j] = ind2sub(maskSize, ind(iii));
+
+
+ irng = i+rng;
+ jrng = j+rng;
+
+ irng = irng(find(irng>0 & irng < nx));
+ jrng = jrng(find(jrng>0 & jrng < ny));
+
+ dist2Here = ((XPOS(irng,jrng)-x1(i)).^2 + (YPOS(irng,jrng)-y1(j)).^2).^0.5;
+ dist2Here(edgeMask(irng,jrng)==0) = maxdist;
+ distToMarine(i,j) = min(dist2Here(:));
+% minDist = 1.0e12;
+% for g = 1:nGL;
+% [ii,jj] = ind2sub(maskSize, GLind(g));
+% dist = sqrt((ii-i)^2 + (jj-j)^2) * dx;
+% minDist = min(minDist, dist);
+% end
+% distToMarine(i,j) = minDist;
+end
+
+
+figure(97); clf; hold all
+pcolor(distToMarine/1000.0)
+shading flat
+colorbar
+axis equal
+
+%% make spacing a fn of distance to GL
+
+
+
+% minSpacing = 10.0e3;
+% maxSpacing = 100.0e3;
+ minSpacing = 2.0e3;
+ maxSpacing = 20.0e3;
+
+ maxShelfSpacing = minSpacing * 3.0;
+
+ minDist = 0.0;
+ maxDist = 400.0e3;
+
+ % linear - this is what should be used to get uniform 'doubling rate'
+ m = (maxSpacing-minSpacing) / (maxDist-minDist)
+ b = minSpacing - m * minDist;
+ % apply same density change rate everywhere
+ %hfun = m * distToMarine + b;
+
+ % apply slower density change rate where there is not grounded ice (floating ice and ice-free areas)
+ hfun = (m * groundedMask + 0.5 * m * ~groundedMask) .* distToMarine + b;
+
+% % power law (e.g. doubling every 100 km) - doesn't work well.
+% hfun = minSpacing * 2.^(distToMarine/100.0e3);
+
+
+ % apply min/max spacing values
+ hfun(hfunmaxSpacing) = maxSpacing;
+ % apply max spacing for ice shelves
+ hfun(floatingMask & hfun > maxShelfSpacing) = maxShelfSpacing;
+
+ hmat.value = hfun ;
+
+
+
+figure(96); clf; hold all
+pcolor(hfun/1000.0)
+shading flat
+colorbar
+axis equal
+
+
+%% save to jigsaw format
+
+ hmat.mshID = 'EUCLIDEAN-GRID' ;
+ hmat.point.coord{1} = x1 ;
+ hmat.point.coord{2} = y1 ;
+ hmat.value = hfun ;
+
+
+ savemsh(opts.hfun_file,hmat) ;
+
+
+%% ------------------------------------ build mesh via JIGSAW!
+
+ opts.hfun_scal = 'absolute';
+ opts.hfun_hmax = +inf ; % null HFUN limits
+ opts.hfun_hmin = 0.00 ;
+
+ opts.mesh_dims = +2 ; % 2-dim. simplexes
+
+ opts.optm_qlim = 0.9375 ;
+
+ opts.mesh_top1 = true ; % for sharp feat's
+ opts.geom_feat = true ;
+
+ mesh = jigsaw (opts) ;
+
+%------------------------------------ draw mesh/cost outputs
+
+ ang2 = triang2( ... % calc. tri-angles
+ mesh.point.coord(:,1:2), ...
+ mesh.tria3.index(:,1:3)) ;
+
+ t_90 = max(ang2,[],2) > 90.0 ;
+ t_95 = max(ang2,[],2) > 95.0 ;
+
+ figure(1); clf;
+ patch ('faces',geom.edge2.index(:,1:2), ...
+ 'vertices',geom.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[.1,.1,.1], ...
+ 'linewidth',1.5) ;
+ hold on; axis image;
+ title('JIGSAW GEOM data') ;
+%%
+ figure(2); clf; hold all;
+ pcolor(XPOS,YPOS,(hmat.value)');
+ axis equal;
+ shading interp ;
+ title('JIGSAW HFUN data') ;
+ patch ('faces',geom.edge2.index(:,1:2), ...
+ 'vertices',geom.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[1,.1,.1], ...
+ 'linewidth',1.5) ;
+ colorbar();
+%%
+
+ figure(3); clf;
+ patch ('faces',mesh.tria3.index(:,1:3), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[.2,.2,.2]) ;
+
+ hold on; axis image;
+ patch ('faces',mesh.tria3.index(t_90,1:3), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','y', ...
+ 'edgecolor',[.2,.2,.2]) ;
+ patch ('faces',mesh.tria3.index(t_95,1:3), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','r', ...
+ 'edgecolor',[.2,.2,.2]) ;
+ patch ('faces',mesh.edge2.index(:,1:2), ...
+ 'vertices',mesh.point.coord(:,1:2), ...
+ 'facecolor','w', ...
+ 'edgecolor',[.1,.1,.1], ...
+ 'linewidth',1.5) ;
+ axis equal
+ title('JIGSAW TRIA mesh') ;
+%%
+ drawscr(mesh.point.coord (:,1:2), ...
+ mesh.edge2.index (:,1:2), ...
+ mesh.tria3.index (:,1:3)) ;
+
+ drawnow ;
+% set(figure(1),'units','normalized', ...
+% 'position',[.05,.55,.30,.35]) ;
+% set(figure(2),'units','normalized', ...
+% 'position',[.35,.55,.30,.35]) ;
+% set(figure(3),'units','normalized', ...
+% 'position',[.35,.10,.30,.35]) ;
+% set(figure(4),'units','normalized', ...
+% 'position',[.05,.10,.30,.35]) ;
+ drawnow ;
+
+%end
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_1proc_run_model_step.xml
index aeba00a451..128cd10c82 100644
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_1proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_4proc_run_model_step.xml b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_4proc_run_model_step.xml
index cd64f07f69..d5dd39124a 100644
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_4proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_4proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -21,7 +20,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_setup_mesh_step.xml
index 854e5a06c2..d7c1dfcc19 100644
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/config_setup_mesh_step.xml
@@ -2,27 +2,26 @@
-
-
-
-
-
+
+ 40
+ 46
+ 1250.0
-
+
grid.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
5
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/output_comparison.xml b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/output_comparison.xml
index 335d0f8325..09e258235d 100644
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/output_comparison.xml
+++ b/testing_and_setup/compass/landice/circular-shelf/1250m/decomposition_test/output_comparison.xml
@@ -1,9 +1,9 @@
-
-
-
+
+
+
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/periodic_hex.namelist.input b/testing_and_setup/compass/landice/circular-shelf/1250m/periodic_hex.namelist.input
deleted file mode 100644
index 5705f6d158..0000000000
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/periodic_hex.namelist.input
+++ /dev/null
@@ -1,8 +0,0 @@
-&periodic_grid
- nx = 40,
- ny = 46,
- dc = 1250.,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 2, 4, 8,
-/
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_run_model_step.xml b/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_run_model_step.xml
index 1c0579a089..97c09fd23e 100644
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -21,7 +20,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_setup_mesh_step.xml
index 854e5a06c2..d7c1dfcc19 100644
--- a/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/circular-shelf/1250m/smoketest/config_setup_mesh_step.xml
@@ -2,27 +2,26 @@
-
-
-
-
-
+
+ 40
+ 46
+ 1250.0
-
+
grid.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
5
diff --git a/testing_and_setup/compass/landice/circular-shelf/albany_input.xml b/testing_and_setup/compass/landice/circular-shelf/albany_input.xml
deleted file mode 100644
index ceb00ad2c3..0000000000
--- a/testing_and_setup/compass/landice/circular-shelf/albany_input.xml
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/circular-shelf/albany_input.yaml b/testing_and_setup/compass/landice/circular-shelf/albany_input.yaml
new file mode 100644
index 0000000000..7378734d6e
--- /dev/null
+++ b/testing_and_setup/compass/landice/circular-shelf/albany_input.yaml
@@ -0,0 +1,105 @@
+%YAML 1.1
+---
+ANONYMOUS:
+ Build Type: Tpetra
+
+ Problem:
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+ 'Glen''s Law A': 5.7e-06
+ 'Glen''s Law n': 3.0
+
+# Discretization Description
+ Discretization:
+ #Exodus Output File Name: albany_output.exo
+ Workset Size: -1
+ Element Shape: Tetrahedron
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: Ifpack2
+ Preconditioner Types:
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
diff --git a/testing_and_setup/compass/landice/circular-shelf/setup_circular_shelf_initial_conditions.py b/testing_and_setup/compass/landice/circular-shelf/setup_circular_shelf_initial_conditions.py
index 10ad5ff4b0..d4f4d114a1 100755
--- a/testing_and_setup/compass/landice/circular-shelf/setup_circular_shelf_initial_conditions.py
+++ b/testing_and_setup/compass/landice/circular-shelf/setup_circular_shelf_initial_conditions.py
@@ -1,5 +1,9 @@
#!/usr/bin/env python
-# This script runs a "Circular Shelf Experiment".
+"""
+This script sets up a "Circular Shelf Experiment".
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys, numpy
from netCDF4 import Dataset
@@ -14,14 +18,14 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
# Open the file, get needed dimensions
gridfile = Dataset(options.filename,'r+')
nVertLevels = len(gridfile.dimensions['nVertLevels'])
if nVertLevels != 5:
- print 'nVertLevels in the supplied file was ', nVertLevels, '. This test case is typically run with 5 levels.'
+ print('nVertLevels in the supplied file was {}. This test case is typically run with 5 levels.'.format(nVertLevels))
# Get variables
xCell = gridfile.variables['xCell']
yCell = gridfile.variables['yCell']
@@ -41,7 +45,7 @@
# Center the dome in the center of the cell that is closest to the center of the domain.
# Only do this if it appears this has not already been done:
if xVertex[:].min() == 0.0:
- print "Shifting x/y coordinates to center domain at 0,0."
+ print("Shifting x/y coordinates to center domain at 0,0.")
# Find center of domain
x0 = xCell[:].min() + 0.5 * (xCell[:].max() - xCell[:].min() )
y0 = yCell[:].min() + 0.5 * (yCell[:].max() - yCell[:].min() )
@@ -73,16 +77,16 @@
thickness[0,:] = thickness_field
# flat bed at -2000 m everywhere with a single grounded point
-bedTopography[:] = -2000.0
+bedTopography[:] = -2000.0
bedTopography[0, centerCellIndex] = -880.0
if options.use_7cells:
- print 'Making the grounded portion of the domain cover 7 cells - the center cell and its 6 neighbors.'
+ print('Making the grounded portion of the domain cover 7 cells - the center cell and its 6 neighbors.')
bedTopography[0, cellsOnCell[centerCellIndex,:]-1] = -880.0 # use this to make the grounded area 7 cells instead of 1
else:
- print 'Making the grounded portion of the domain cover 1 cell - the center cell.'
+ print('Making the grounded portion of the domain cover 1 cell - the center cell.')
if options.use_beta:
- print 'Setting no-slip on the grounded portion of the domain by setting a high beta field there.'
+ print('Setting no-slip on the grounded portion of the domain by setting a high beta field there.')
beta = gridfile.variables['beta']
# beta is 0 everywhere except a high value in the grounded cell
beta[:] = 0.
@@ -90,7 +94,7 @@
if options.use_7cells:
beta[cellsOnCell[centerCellIndex,:]-1] = 1.0e8 # use this to make the grounded area 7 cells instead of 1
else: # use Dirichlet b.c.
- print 'Setting no-slip on the grounded portion of the domain by setting no-slip Dirichlet velocity boundary conditions there.'
+ print('Setting no-slip on the grounded portion of the domain by setting no-slip Dirichlet velocity boundary conditions there.')
dirMask = gridfile.variables['dirichletVelocityMask']
uvel = gridfile.variables['uReconstructX']
vvel = gridfile.variables['uReconstructY']
@@ -111,7 +115,7 @@
gridfile.close()
-print '\nSuccessfully added circular-shelf initial conditions to: ', options.filename
+print('\nSuccessfully added circular-shelf initial conditions to: '+options.filename)
diff --git a/testing_and_setup/compass/landice/circular-shelf/visualize_circular_shelf.py b/testing_and_setup/compass/landice/circular-shelf/visualize_circular_shelf.py
index df9bce3343..2583152a01 100755
--- a/testing_and_setup/compass/landice/circular-shelf/visualize_circular_shelf.py
+++ b/testing_and_setup/compass/landice/circular-shelf/visualize_circular_shelf.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import numpy as np
from netCDF4 import Dataset as NetCDFFile
from optparse import OptionParser
@@ -17,7 +20,7 @@
options, args = parser.parse_args()
if not options.filename:
- print "No filename provided. Using output.nc."
+ print("No filename provided. Using output.nc.")
options.filename = "output.nc"
time_slice = 0
@@ -34,7 +37,7 @@
try:
bedTopography = f.variables['bedTopography'] # not needed
except:
- print "bedTopography not in file. Continuing without it."
+ print("bedTopography not in file. Continuing without it.")
xCell = f.variables['xCell'][:]/1000.0
yCell = f.variables['yCell'][:]/1000.0
xEdge = f.variables['xEdge'][:]/1000.0
@@ -53,7 +56,7 @@
velnorm = (uReconstructX[:]**2 + uReconstructY[:]**2)**0.5 * secInYr
-print "Maximum velocity (m/yr) at cell centers in domain:", velnorm.max()
+print("Maximum velocity (m/yr) at cell centers in domain: {}".format(velnorm.max()))
##################
@@ -103,7 +106,7 @@
try:
plt.plot(xCell[indXsect], bedTopography[time_slice, indXsect], 'go-', label="Bed topography")
except:
- print "Skipping plotting of bedTopography."
+ print("Skipping plotting of bedTopography.")
plt.plot(xCell[indXsect], xCell[indXsect] * 0.0, ':k', label="sea level")
plt.legend(loc='best')
plt.title('cross-section at y=0' )
@@ -131,7 +134,7 @@
if options.hidefigs:
- print "Plot display disabled with -n argument."
+ print("Plot display disabled with -n argument.")
else:
plt.show()
diff --git a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_1proc_run_model_step.xml
index 3a6d775678..8e346983b5 100644
--- a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_1proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
diff --git a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_4proc_run_model_step.xml b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_4proc_run_model_step.xml
index a2a45dea68..1a1776d7f1 100644
--- a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_4proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_4proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -21,7 +20,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_setup_mesh_step.xml
index c3e5d66650..4333a11f95 100644
--- a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/config_setup_mesh_step.xml
@@ -2,28 +2,35 @@
-
-
-
-
-
+
+ 50
+ 58
+ 5000.0
+
+
-
+
grid.nc
- mpas_grid.nc
+ culled.nc
+
+
+ culled.nc
+ mpas_grid2.nc
+
+
-
- mpas_grid.nc
+
+ mpas_grid2.nc
landice_grid.nc
5
diff --git a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/output_comparison.xml b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/output_comparison.xml
index 010bf551e7..06386c05ee 100644
--- a/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/output_comparison.xml
+++ b/testing_and_setup/compass/landice/confined-shelf/5000m/decomposition_test/output_comparison.xml
@@ -1,9 +1,9 @@
-
-
-
+
+
+
diff --git a/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_run_model_step.xml b/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_run_model_step.xml
index adaa277263..d2a5f504f6 100644
--- a/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -21,7 +20,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_setup_mesh_step.xml
index c3e5d66650..4333a11f95 100644
--- a/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/confined-shelf/5000m/smoketest/config_setup_mesh_step.xml
@@ -2,28 +2,35 @@
-
-
-
-
-
+
+ 50
+ 58
+ 5000.0
+
+
-
+
grid.nc
- mpas_grid.nc
+ culled.nc
+
+
+ culled.nc
+ mpas_grid2.nc
+
+
-
- mpas_grid.nc
+
+ mpas_grid2.nc
landice_grid.nc
5
diff --git a/testing_and_setup/compass/landice/confined-shelf/albany_input.xml b/testing_and_setup/compass/landice/confined-shelf/albany_input.xml
deleted file mode 100644
index ceb00ad2c3..0000000000
--- a/testing_and_setup/compass/landice/confined-shelf/albany_input.xml
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/confined-shelf/albany_input.yaml b/testing_and_setup/compass/landice/confined-shelf/albany_input.yaml
new file mode 100644
index 0000000000..7378734d6e
--- /dev/null
+++ b/testing_and_setup/compass/landice/confined-shelf/albany_input.yaml
@@ -0,0 +1,105 @@
+%YAML 1.1
+---
+ANONYMOUS:
+ Build Type: Tpetra
+
+ Problem:
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+ 'Glen''s Law A': 5.7e-06
+ 'Glen''s Law n': 3.0
+
+# Discretization Description
+ Discretization:
+ #Exodus Output File Name: albany_output.exo
+ Workset Size: -1
+ Element Shape: Tetrahedron
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: Ifpack2
+ Preconditioner Types:
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
diff --git a/testing_and_setup/compass/landice/confined-shelf/setup_confined_shelf_initial_conditions.py b/testing_and_setup/compass/landice/confined-shelf/setup_confined_shelf_initial_conditions.py
index 9c80a67464..d3863dcc0c 100755
--- a/testing_and_setup/compass/landice/confined-shelf/setup_confined_shelf_initial_conditions.py
+++ b/testing_and_setup/compass/landice/confined-shelf/setup_confined_shelf_initial_conditions.py
@@ -1,6 +1,10 @@
#!/usr/bin/env python
-# This script sets up a "Confined Shelf Experiment".
-# see http://homepages.vub.ac.be/~phuybrec/eismint/shelf-descr.pdf
+"""
+This script sets up a "Confined Shelf Experiment".
+see http://homepages.vub.ac.be/~phuybrec/eismint/shelf-descr.pdf
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys
from netCDF4 import Dataset
@@ -15,7 +19,7 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
# Open the file, get needed dimensions
@@ -25,7 +29,7 @@
nVertLevels = len(gridfile.dimensions['nVertLevels'])
maxEdges = len(gridfile.dimensions['maxEdges'])
if nVertLevels != 5:
- print 'nVerLevels in the supplied file was ', nVertLevels, '. 5 levels are typically used with this test case.'
+ print('nVerLevels in the supplied file was '+ str(nVertLevels)+ '. 5 levels are typically used with this test case.')
# Get variables
xCell = gridfile.variables['xCell'][:]
yCell = gridfile.variables['yCell'][:]
@@ -41,18 +45,18 @@
# put the domain origin in the center of the center cell in the x-direction and in the 2nd row on the y-direction
# Only do this if it appears this has not already been done:
-if xVertex[:].min() == 0.0:
- print 'Shifting domain origin to center of shelf front, because it appears that this has not yet been done.'
+if xVertex[:].min() < 15000.0: # 15000 is to allow for the periodic cells to have been removed from the mesh
+ print('Shifting domain origin to center of shelf front, because it appears that this has not yet been done.')
unique_xs=np.array(sorted(list(set(xCell[:]))))
targetx = (unique_xs.max() - unique_xs.min()) / 2.0 + unique_xs.min() # center of domain range
best_x=unique_xs[ np.absolute((unique_xs - targetx)) == np.min(np.absolute(unique_xs - (targetx))) ][0]
- print 'Found a best x value to use of:' + str(best_x)
-
+ print('Found a best x value to use of:' + str(best_x))
+
unique_ys=np.array(sorted(list(set(yCell[:]))))
# print unique_ys
best_y = unique_ys[5] # get 6th value
- print 'Found a best y value to use of:' + str(best_y)
-
+ print('Found a best y value to use of:' + str(best_y))
+
xShift = -1.0 * best_x
yShift = -1.0 * best_y
xCell[:] = xCell[:] + xShift
@@ -115,6 +119,10 @@
for side in theSides:
thesideindices = np.nonzero( np.logical_and( xCell[:] == side[0] , yCell[:] <= 0.0 ) )[0]
kinbcmask[:, thesideindices] = 1
+# Now mark Dirichlet everywhere outside of the "box" to prevent Albany from calculating the extended cell solution there
+kinbcmask[:, xCell[:] < -L/2.0] = 1
+kinbcmask[:, xCell[:] > L/2.0] = 1
+kinbcmask[:, yCell[:] > L] = 1
gridfile.variables['dirichletVelocityMask'][:] = kinbcmask[:]
gridfile.sync()
del kinbcmask
@@ -140,7 +148,7 @@
gridfile.close()
-print 'Successfully added confined-shelf initial conditions to: ', options.filename
+print('Successfully added confined-shelf initial conditions to: ' + options.filename)
diff --git a/testing_and_setup/compass/landice/confined-shelf/visualize_confined_shelf.py b/testing_and_setup/compass/landice/confined-shelf/visualize_confined_shelf.py
index 85d9add00f..cda49b30bc 100755
--- a/testing_and_setup/compass/landice/confined-shelf/visualize_confined_shelf.py
+++ b/testing_and_setup/compass/landice/confined-shelf/visualize_confined_shelf.py
@@ -1,14 +1,16 @@
#!/usr/bin/env python
+"""
+Visualize results of the confined shelf experiment
+See http://homepages.vub.ac.be/~phuybrec/eismint/shelf-descr.pdf for description.
+"""
-# Visualize results of the confined shelf experiment
-# See http://homepages.vub.ac.be/~phuybrec/eismint/shelf-descr.pdf for description.
+from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
from netCDF4 import Dataset as NetCDFFile
from optparse import OptionParser
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
-# from matplotlib.contour import QuadContourSet
parser = OptionParser()
@@ -19,7 +21,7 @@
options, args = parser.parse_args()
if not options.filename:
- print "No filename provided. Using output.nc."
+ print("No filename provided. Using output.nc.")
options.filename = "output.nc"
time_slice = 0
@@ -72,7 +74,7 @@ def contourMPAS(field, contour_levs):
velnorm = (uReconstructX[:]**2 + uReconstructY[:]**2)**0.5
-print "Maximum speed (m/yr) at cell centers in domain:", velnorm.max() * secInYr
+print("Maximum speed (m/yr) at cell centers in domain: {}".format(velnorm.max() * secInYr))
var_slice = thickness[time_slice,:]
# var_slice = var_slice.reshape(time_length, ny, nx)
@@ -120,7 +122,7 @@ def contourMPAS(field, contour_levs):
plt.ylabel('Y position (km)')
plt.draw()
-print "Compare Figure 2 to test 3 results at http://homepages.vub.ac.be/~phuybrec/eismint/shelf-descr.pdf"
+print("Compare Figure 2 to test 3 results at http://homepages.vub.ac.be/~phuybrec/eismint/shelf-descr.pdf")
if options.saveimages:
plt.savefig('conf_shelf_velo_contours.png')
@@ -174,8 +176,8 @@ def contourMPAS(field, contour_levs):
if options.hidefigs:
- print "Plot display disabled with -n argument."
-else:
+ print("Plot display disabled with -n argument.")
+else:
plt.show()
f.close()
diff --git a/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_1proc_run_model_step.xml
index f8a46802df..2294e152ff 100644
--- a/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_1proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -23,7 +22,7 @@
diff --git a/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_4proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_4proc_run_model_step.xml
index 9803b7c1e8..da486b8ec1 100644
--- a/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_4proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_4proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_setup_mesh_step.xml
index 9f103daea1..6efe686827 100644
--- a/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/decomposition_test/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_run_model_step.xml
index 3d849377b9..fba7ad0e52 100644
--- a/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_setup_mesh_step.xml
index 9f103daea1..c79f59ffd1 100644
--- a/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/halfar_analytic_test/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
+
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
@@ -34,6 +42,9 @@
halfar
+
+ landice_grid.nc
+
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_1proc_run_model_step.xml
index 47a1a94a73..208351adb5 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_1proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -27,7 +26,7 @@
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_4proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_4proc_run_model_step.xml
index be4f922d81..1dedeb80ab 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_4proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_4proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -26,7 +25,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_setup_mesh_step.xml
index 319d5be4b9..f308b93152 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/output_comparison.xml b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/output_comparison.xml
index 0ea28561d7..bcaee28d41 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/output_comparison.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_decomposition_test/output_comparison.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_full_run_step.xml
index 8b64f052f8..19b1ea3199 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_full_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_full_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -14,8 +13,8 @@
-
-
+
+
@@ -24,20 +23,20 @@
- 0001-00-00_00:00:00
+ 0000-00-01_00:00:00
0000-01-01_00:00:00
- rst.$Y.nc
+ rst.$Y.$M.$D.nc
output_interval
- 0001-00-00_00:00:00
+ 0000-00-01_00:00:00
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_restart_run_step.xml
index d5cdd8f4c8..2f0804149b 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_restart_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_restart_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -14,8 +13,8 @@
-
-
+
+
@@ -23,9 +22,9 @@
-
-
-
+
+
+
@@ -34,21 +33,21 @@
- 0001-00-00_00:00:00
+ 0000-00-01_00:00:00
overwrite
0000-01-01_00:00:00
- rst.$Y.nc
+ rst.$Y.$M.$D.nc
output_interval
- 0001-00-00_00:00:00
+ 0000-00-01_00:00:00
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_setup_mesh_step.xml
index 319d5be4b9..f308b93152 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_restart_test/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_ho_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_ho_run_model_step.xml
index f60610e16d..8eb5c7d39f 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_ho_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_ho_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -27,7 +26,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_setup_mesh_step.xml
index 319d5be4b9..f308b93152 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_sia_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_sia_run_model_step.xml
index 5eb4acb0fa..f250e4382f 100644
--- a/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_sia_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/ho_vs_sia_test/config_sia_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -27,7 +26,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/dome/2000m/restart_test/config_full_run_step.xml
index b586b99b9c..18bbdbf81a 100644
--- a/testing_and_setup/compass/landice/dome/2000m/restart_test/config_full_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/restart_test/config_full_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -36,7 +35,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/dome/2000m/restart_test/config_restart_run_step.xml
index 39a1a1f573..02a24d7492 100644
--- a/testing_and_setup/compass/landice/dome/2000m/restart_test/config_restart_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/restart_test/config_restart_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -61,7 +60,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/restart_test/config_setup_mesh_step.xml
index 9f103daea1..6efe686827 100644
--- a/testing_and_setup/compass/landice/dome/2000m/restart_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/restart_test/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/2000m/smoketest/config_run_model_step.xml b/testing_and_setup/compass/landice/dome/2000m/smoketest/config_run_model_step.xml
index d019ec80a9..d85bf39134 100644
--- a/testing_and_setup/compass/landice/dome/2000m/smoketest/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/smoketest/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/2000m/smoketest/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/2000m/smoketest/config_setup_mesh_step.xml
index 9f103daea1..6efe686827 100644
--- a/testing_and_setup/compass/landice/dome/2000m/smoketest/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/2000m/smoketest/config_setup_mesh_step.xml
@@ -2,27 +2,35 @@
-
-
-
-
-
+
+ 30
+ 34
+ 2000.0
+
+
+ grid.nc
-
-
+
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/albany_input.xml b/testing_and_setup/compass/landice/dome/albany_input.xml
deleted file mode 100644
index 67965282e5..0000000000
--- a/testing_and_setup/compass/landice/dome/albany_input.xml
+++ /dev/null
@@ -1,154 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/dome/albany_input.yaml b/testing_and_setup/compass/landice/dome/albany_input.yaml
new file mode 100644
index 0000000000..14f75c9e16
--- /dev/null
+++ b/testing_and_setup/compass/landice/dome/albany_input.yaml
@@ -0,0 +1,102 @@
+%YAML 1.1
+---
+ANONYMOUS:
+ Build Type: Tpetra
+
+ Problem:
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+
+# Discretization Description
+ Discretization:
+ Element Shape: Tetrahedron
+ Exodus Output File Name: albany_output.exo
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: Ifpack2
+ Preconditioner Types:
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
diff --git a/testing_and_setup/compass/landice/dome/check_halfar_solution.py b/testing_and_setup/compass/landice/dome/check_halfar_solution.py
index 998a60563d..437a452469 100755
--- a/testing_and_setup/compass/landice/dome/check_halfar_solution.py
+++ b/testing_and_setup/compass/landice/dome/check_halfar_solution.py
@@ -1,14 +1,14 @@
#!/usr/bin/env python
-# A script to compare MPAS model output to the Halfar analytic solution of the dome test case.
-# Matt Hoffman, LANL, September 2013
+"""
+A script to compare MPAS model output to the Halfar analytic solution of the dome test case.
+Matt Hoffman, LANL, September 2013
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys
import datetime
-try:
- import netCDF4
-except ImportError:
- print 'Unable to import netCDF4 python modules:'
- sys.exit
+import netCDF4
from optparse import OptionParser
import numpy as np
import matplotlib.pyplot as plt
@@ -22,12 +22,12 @@
options, args = parser.parse_args()
if not options.filename:
options.filename = 'output.nc'
- print 'No file specified. Attempting to use output.nc'
+ print('No file specified. Attempting to use output.nc')
if options.t:
timelev = int(options.t)
else:
timelev = -1
- print 'No time level specified. Attempting to use final time.'
+ print('No time level specified. Attempting to use final time.')
################### DEFINE FUNCTIONS ######################
# Define the function to calculate the Halfar thickness
@@ -89,29 +89,29 @@ def xtime2numtime(xtime):
areaCell = filein.variables['areaCell'][:]
thk = filein.variables['thickness'][:]
-xtime = filein.variables['xtime'][:]
+xtime = filein.variables['xtime'][:]
numtime = xtime2numtime(xtime)
# Find out what the ice density and flowA values for this run were.
-print '\nCollecting parameter values from the output file.'
+print('\nCollecting parameter values from the output file.')
flowA = filein.config_default_flowParamA
-print 'Using a flowParamA value of: ' + str(flowA)
+print('Using a flowParamA value of: ' + str(flowA))
flow_n = filein.config_flowLawExponent
-print 'Using a flowLawExponent value of: ' + str(flow_n)
+print('Using a flowLawExponent value of: ' + str(flow_n))
if flow_n != 3:
- print 'Error: The Halfar script currently only supports a flow law exponent of 3.'
+ print('Error: The Halfar script currently only supports a flow law exponent of 3.')
sys.exit
rhoi = filein.config_ice_density
-print 'Using an ice density value of: ' + str(rhoi)
+print('Using an ice density value of: ' + str(rhoi))
dynamicThickness = filein.config_dynamic_thickness
-print '\nDynamic thickness for this run = ' + str(dynamicThickness)
+print('\nDynamic thickness for this run = ' + str(dynamicThickness))
-print 'Using model time of ' + xtime[timelev,:].tostring().strip() + '\n'
+print('Using model time of ' + xtime[timelev,:].tostring().decode('utf-8').strip() + '\n')
if filein.config_calendar_type != "gregorian_noleap":
- print 'Error: The Halfar script currently assumes a gregorian_noleap calendar. Modify it to proceed with your calendar type of: ', filein.config_calendar_type
+ print('Error: The Halfar script currently assumes a gregorian_noleap calendar. Modify it to proceed with your calendar type of: '+filein.config_calendar_type)
sys.exit
@@ -119,9 +119,9 @@ def xtime2numtime(xtime):
thkHalfar = halfar(numtime[timelev]-numtime[0], xCell, yCell, flowA, flow_n, rhoi)
iceCells = np.where( thk[timelev,:] > 0.0)
-print "# ice cells=", len(iceCells[0])
-thkDiff = (thk[timelev, :] - thkHalfar)
-thkDiffIce = thkDiff[iceCells] # Restrict to cells modeled to have ice
+print("# ice cells={}".format(len(iceCells[0])))
+thkDiff = (thk[timelev, :] - thkHalfar)
+thkDiffIce = thkDiff.data[iceCells] # Restrict to cells modeled to have ice
RMS = ( (thkDiffIce**2).sum() / float(len(thkDiffIce)) )**0.5
#RMSwtd = ( ((thkDiffIce * areaCell[iceCells] / areaCell[iceCells].sum())**2).sum() / float(len(thkDiffIce)) )**0.5
#RMSwtd = ( ((thkDiffIce * areaCell[iceCells])**2 ).sum() / areaCell[iceCells]**0.5.sum()
@@ -129,29 +129,29 @@ def xtime2numtime(xtime):
# Print some stats about the error
-print 'Error statistics for cells modeled to have ice:'
-print '* RMS error = ' + str( RMS )
-print '* RMS error (area weighted) = ' + str( RMSwtd )
-print '* Minimum error = ' + str( thkDiffIce.min() )
-print '* Maximum error = ' + str( thkDiffIce.max() )
-print '* Mean error = ' + str( thkDiffIce.mean() )
-print '* Median error = ' + str( np.median(thkDiffIce) )
-print '* Mean absolute error = ' + str( np.absolute(thkDiffIce).mean() )
-print '* Median absolute error = ' + str( np.median(np.absolute(thkDiffIce)) )
-print ''
+print('Error statistics for cells modeled to have ice:')
+print('* RMS error = ' + str( RMS ))
+print('* RMS error (area weighted) = ' + str( RMSwtd ))
+print('* Minimum error = ' + str( thkDiffIce.min() ))
+print('* Maximum error = ' + str( thkDiffIce.max() ))
+print('* Mean error = ' + str( thkDiffIce.mean() ))
+print('* Median error = ' + str( np.median(thkDiffIce) ))
+print('* Mean absolute error = ' + str( np.absolute(thkDiffIce).mean() ))
+print('* Median absolute error = ' + str( np.median(np.absolute(thkDiffIce)) ))
+print('')
# Plot the results
fig = plt.figure(1, figsize=(16, 4.5), facecolor='w', dpi=100)
markersize = 35.0
-gray = np.ones(3)*0.8
+gray = [np.ones(3)*0.8,]
fig.add_subplot(1,3,1)
-maskindices = np.nonzero(thk[:][timelev,:] > 0.0)[:]
+maskindices = np.nonzero(thk[:][timelev,:] > 0.0)[0]
plt.scatter(xCell/1000.0,yCell/1000.0,markersize,gray, marker='.', edgecolors='none')
plt.scatter(xCell[maskindices]/1000.0,yCell[maskindices]/1000.0,markersize,thk[timelev,maskindices], marker='h', edgecolors='none')
plt.colorbar()
plt.axis('equal')
-plt.title('Modeled thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
+plt.title('Modeled thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
plt.xlabel('x (km)'); plt.ylabel('y (km)')
fig.add_subplot(1,3,2)
@@ -160,7 +160,7 @@ def xtime2numtime(xtime):
plt.scatter(xCell[halmaskindices]/1000.0,yCell[halmaskindices]/1000.0,markersize,thkHalfar[halmaskindices], marker='h', edgecolors='none')
plt.colorbar()
plt.axis('equal')
-plt.title('Analytic thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
+plt.title('Analytic thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
plt.xlabel('x (km)'); plt.ylabel('y (km)')
fig.add_subplot(1,3,3)
@@ -169,7 +169,7 @@ def xtime2numtime(xtime):
plt.colorbar()
plt.clim([-1.0*np.absolute(thkDiff).max(), np.absolute(thkDiff).max()])
plt.axis('equal')
-plt.title('Modeled thickness - Analytic thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
+plt.title('Modeled thickness - Analytic thickness (m) \n at time ' + netCDF4.chartostring(xtime)[timelev].strip() )
plt.xlabel('x (km)'); plt.ylabel('y (km)')
plt.draw()
@@ -177,12 +177,12 @@ def xtime2numtime(xtime):
if options.saveimage:
plotname = 'halfar-results.png'
plt.savefig(plotname, dpi=150)
- print 'Saved plot as ' + plotname
+ print('Saved plot as ' + plotname)
if options.hidefigs:
- print "Plot display disabled with -n argument."
+ print("Plot display disabled with -n argument.")
else:
- print 'Showing plot... Close plot window to exit.'
+ print('Showing plot... Close plot window to exit.')
plt.show()
diff --git a/testing_and_setup/compass/landice/dome/setup_dome_initial_conditions.py b/testing_and_setup/compass/landice/dome/setup_dome_initial_conditions.py
index 4b8f6ba1c6..c185b1d746 100755
--- a/testing_and_setup/compass/landice/dome/setup_dome_initial_conditions.py
+++ b/testing_and_setup/compass/landice/dome/setup_dome_initial_conditions.py
@@ -1,5 +1,9 @@
#!/usr/bin/env python
-# Generate initial conditions for dome land ice test case
+"""
+Generate initial conditions for dome land ice test case
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
import sys, numpy
from netCDF4 import Dataset as NetCDFFile
@@ -13,16 +17,16 @@
options, args = parser.parse_args()
if options.dometype:
if options.dometype == 'cism' or options.dometype == 'halfar':
- print 'Setting up the dome type: ' + options.dometype
+ print('Setting up the dome type: ' + options.dometype)
else:
- print "Error: Invalid dome type specified. Valid types are 'halfar' or 'cism'."
+ print("Error: Invalid dome type specified. Valid types are 'halfar' or 'cism'.")
sys.exit
else:
options.dometype='halfar'
- print 'No dome type specified. Setting up the Halfar dome by default.'
+ print('No dome type specified. Setting up the Halfar dome by default.')
if not options.filename:
options.filename = 'landice_grid.nc'
- print 'No file specified. Attempting to use landice_grid.nc'
+ print('No file specified. Attempting to use landice_grid.nc')
# Open the file, get needed dimensions
@@ -80,12 +84,14 @@
else:
# halfar dome
thickness_field[r
-
+
-
@@ -23,7 +22,7 @@
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_4proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_4proc_run_model_step.xml
index a1abed8b80..3ccd1bf312 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_4proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_4proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_setup_mesh_step.xml
index 66c2079b64..68755cfee5 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/decomposition_test/config_setup_mesh_step.xml
@@ -3,21 +3,19 @@
-
+
-
-
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_run_model_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_run_model_step.xml
index cdd1a615c2..bd2f18d5a7 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_setup_mesh_step.xml
index 66c2079b64..f187505c9c 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/halfar_analytic_test/config_setup_mesh_step.xml
@@ -3,21 +3,19 @@
-
+
-
-
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_1proc_run_model_step.xml
index d55e091b8e..be8c2118cd 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_1proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -26,7 +25,7 @@
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_4proc_run_model_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_4proc_run_model_step.xml
index aa801ca422..dd36507360 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_4proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_4proc_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -25,7 +24,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_setup_mesh_step.xml
index 66c2079b64..f187505c9c 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/config_setup_mesh_step.xml
@@ -3,21 +3,19 @@
-
+
-
-
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/output_comparison.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/output_comparison.xml
index 0ea28561d7..bcaee28d41 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/output_comparison.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_decomposition_test/output_comparison.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_full_run_step.xml
index 5ccec20f70..56567549d1 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_full_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_full_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -37,7 +36,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_restart_run_step.xml
index 0b55aeb5a1..37bd638e7d 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_restart_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_restart_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -48,7 +47,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_setup_mesh_step.xml
index 66c2079b64..f187505c9c 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/ho_restart_test/config_setup_mesh_step.xml
@@ -3,21 +3,19 @@
-
+
-
-
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_full_run_step.xml
index bf248f5e0b..f521b79454 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_full_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_full_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -36,7 +35,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_restart_run_step.xml
index 791d27a77d..f8b8aba386 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_restart_run_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_restart_run_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -46,7 +45,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_setup_mesh_step.xml
index 66c2079b64..f187505c9c 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/restart_test/config_setup_mesh_step.xml
@@ -3,21 +3,19 @@
-
+
-
-
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_run_model_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_run_model_step.xml
index 8bb4bf2e2c..724279c249 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_run_model_step.xml
@@ -3,9 +3,8 @@
-
+
-
@@ -22,7 +21,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_setup_mesh_step.xml
index 66c2079b64..f187505c9c 100644
--- a/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/dome/variable_resolution/smoketest/config_setup_mesh_step.xml
@@ -3,21 +3,19 @@
-
+
-
-
-
+
mpas_grid.nc
landice_grid.nc
10
diff --git a/testing_and_setup/compass/landice/dome/visualize_dome.py b/testing_and_setup/compass/landice/dome/visualize_dome.py
index 8d35f5552e..7e6c88c0a6 100755
--- a/testing_and_setup/compass/landice/dome/visualize_dome.py
+++ b/testing_and_setup/compass/landice/dome/visualize_dome.py
@@ -1,13 +1,12 @@
#!/usr/bin/env python
+
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
import numpy
-# from netCDF import *
-# import math
-from Scientific.IO.NetCDF import *
-# from pylab import *
+import netCDF4
from optparse import OptionParser
import matplotlib.pyplot as plt
-# from matplotlib.contour import QuadContourSet
-# import time
parser = OptionParser()
@@ -22,14 +21,14 @@
options, args = parser.parse_args()
if not options.filename:
- print "No filename provided. Using output.nc."
- options.filename = "output.nc"
+ print("No filename provided. Using output.nc.")
+ options.filename = "output.nc"
if not options.time:
- print "No time provided. Using time 0."
- time_slice = 0
+ print("No time provided. Using time 0.")
+ time_slice = 0
else:
- time_slice = int(options.time)
+ time_slice = int(options.time)
#if not options.variable:
# parser.error("Variable is a required input.")
@@ -52,7 +51,7 @@
secInYr = 3600.0 * 24.0 * 365.0 # Note: this may be slightly wrong for some calendar types!
-f = NetCDFFile(options.filename,'r')
+f = netCDF4.Dataset(options.filename,'r')
times = f.variables['xtime']
thickness = f.variables['thickness']
@@ -76,7 +75,7 @@
time_length = times.shape[0]
# print "nx = ", nx, " ny = ", ny
-print "vert_levs = ", vert_levs, " time_length = ", time_length
+print("vert_levs = {}; time_length = {}".format(vert_levs, time_length))
# print "Computing global max and min"
@@ -106,7 +105,7 @@
plt.title('thickness at time ' + str(time_slice) )
plt.draw()
if options.saveimages:
- print "Saving figures to files."
+ print("Saving figures to files.")
plt.savefig('dome_thickness.png')
fig = plt.figure(2)
@@ -171,8 +170,8 @@
if options.hidefigs:
- print "Plot display disabled with -n argument."
-else:
+ print("Plot display disabled with -n argument.")
+else:
plt.show()
f.close()
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_driver.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_driver.xml
new file mode 100644
index 0000000000..a6977ceff1
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_driver.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_run_model_step.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_run_model_step.xml
new file mode 100644
index 0000000000..620b61b1cb
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_run_model_step.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ output1.nc
+ 5000-00-00_00:00:00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ output2.nc
+ 5000-00-00_00:00:00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ output3.nc
+ 1000-00-00_00:00:00
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+ restart.100000.nc
+ 268.15
+
+
+
+
+
+
+
+ restart.150000.nc
+ 243.15
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_setup_mesh_step.xml
new file mode 100644
index 0000000000..524f0e261d
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/config_setup_mesh_step.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+ 2
+ 2
+ 1000.0
+
+
+
+
+
+
+ grid.nc
+ mpas_grid.nc
+
+
+
+
+ mpas_grid.nc
+ landice_grid.nc
+ 50
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/output_comparison.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/output_comparison.xml
new file mode 100644
index 0000000000..44a3511e47
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/A/output_comparison.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_driver.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_driver.xml
new file mode 100644
index 0000000000..809f3f5766
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_driver.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_run_model_step.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_run_model_step.xml
new file mode 100644
index 0000000000..c68d75831b
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_run_model_step.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0001-00-00_00:00:00
+
+
+
+
+
+
+
+
+ 2
+
+
+
+ landice_grid.nc
+ 270.15
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml
new file mode 100644
index 0000000000..9ea496e75f
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+ 2
+ 2
+ 1000.0
+
+
+
+
+
+
+ grid.nc
+ mpas_grid.nc
+
+
+
+
+ mpas_grid.nc
+ landice_grid.nc
+ 50
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/enthalpy_1m_template.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/enthalpy_1m_template.xml
new file mode 100644
index 0000000000..ef12f4d036
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/enthalpy_1m_template.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ landice_grid.nc
+
+
+
+ output
+ output.nc
+ 0100-00-00_00:00:00
+ truncate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ input;output
+ restart.$Y.nc
+ output_interval
+ 25000-00-00_00:00:00
+ truncate
+ double
+ initial_only
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/README b/testing_and_setup/compass/landice/enthalpy-benchmark/README
new file mode 100644
index 0000000000..8efa2f935e
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/README
@@ -0,0 +1,61 @@
+This test case implements the enthalpy benchmarks described here:
+Kleiner, T., Rückamp, M., Bondzio, J. H., and Humbert, A.: Enthalpy benchmark experiments for numerical ice sheet models, The Cryosphere, 9, 217–228, https://doi.org/10.5194/tc-9-217-2015, 2015.
+
+
+For Benchmark A, we don't have to change the code.
+By default the Benchmark A visualization script saves the plot as .png file.
+However, it is possible to have it plot to an interactive python plot by adjusting a flag at the end of the script.
+The output frequency for A has been reduced so that the test will run quickly enough to include
+in regression testing. If you want more detailed output, you can adjust the output interval in the streams files.
+
+
+
+For Benchmark B, we need to make the following code changes:
+
+1) in mpas_li_thermal.F, in the subroutine enthalpy_matrix_elements,
+
+change
+
+subd(2:nVertLevels+1) = -factor * diffusivity(1:nVertLevels) * dsigmaTerm(1:nVertLevels,1)
+
+to
+
+subd(2:nVertLevels+1) = -factor * (diffusivity(1:nVertLevels) * dsigmaTerm(1:nVertLevels,1)+0.2/scyr*sqrt(dsigmaTerm(1:nVertLevels,1))*thickness)
+
+
+and change
+
+rhs(2:nVertLevels+1) = enthalpy(1:nVertLevels) + heatDissipation(1:nVertLevels) * deltat * rhoi * cp_ice
+
+to
+
+rhs(2:nVertLevels+1) = enthalpy(1:nVertLevels) + 0*heatDissipation(1:nVertLevels) * deltat * rhoi * cp_ice + 2.0_RKIND*5.3e-24_RKIND*((910.0_RKIND*9.81_RKIND*sin(4.0_RKIND*pii/180.0_RKIND))**4)*((thickness*layerCenterSigma(1:nVertLevels))**4)*deltat
+
+2) in mpas_li_constants.F
+
+change
+
+iceMeltingPointPressureDependence = 9.7456e-8_RKIND
+
+to
+
+iceMeltingPointPressureDependence = 0.0_RKIND
+
+
+and recompile the code before testing Benchmark B
+
+Also, for Benchmark B, you can run with more vertical layers to match the lower row of Kleiner Figure 4.
+To do so, make a change like this:
+diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml
+index 9ea496e7..743aa938 100644
+--- a/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml
++++ b/testing_and_setup/compass/landice/enthalpy-benchmark/1m/B/config_setup_mesh_step.xml
+@@ -25,7 +25,7 @@
+
+ mpas_grid.nc
+ landice_grid.nc
+- 50
++ 400
+
+
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/change_Ts.py b/testing_and_setup/compass/landice/enthalpy-benchmark/change_Ts.py
new file mode 100755
index 0000000000..754ba47f7c
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/change_Ts.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+import numpy as np
+from netCDF4 import Dataset
+from optparse import OptionParser
+
+parser = OptionParser(description='change surface air temperature')
+parser.add_option("-f", "--file", dest="input_file", help="the input file")
+parser.add_option("-v", "--value", dest="change_value", help="the temperature value in Kelvin")
+
+for option in parser.option_list:
+ if option.default != ("NO", "DEFAULT"):
+ option.help += (" " if option.help else "") + "[default: %default]"
+options, args = parser.parse_args()
+
+data = Dataset(options.input_file, 'r+')
+
+T_new = options.change_value
+
+data.variables['surfaceAirTemperature'][0,:] = float(T_new)
+
+data.close()
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/enthA_analy_result.mat b/testing_and_setup/compass/landice/enthalpy-benchmark/enthA_analy_result.mat
new file mode 100755
index 0000000000..5def1953fd
Binary files /dev/null and b/testing_and_setup/compass/landice/enthalpy-benchmark/enthA_analy_result.mat differ
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/enthB_analy_result.mat b/testing_and_setup/compass/landice/enthalpy-benchmark/enthB_analy_result.mat
new file mode 100755
index 0000000000..ec12705e44
Binary files /dev/null and b/testing_and_setup/compass/landice/enthalpy-benchmark/enthB_analy_result.mat differ
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/plot_enthalpy_benchmark_A.py b/testing_and_setup/compass/landice/enthalpy-benchmark/plot_enthalpy_benchmark_A.py
new file mode 100755
index 0000000000..ecd81bf748
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/plot_enthalpy_benchmark_A.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+
+from netCDF4 import Dataset
+import numpy as np
+import matplotlib
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+from scipy.io import loadmat
+
+anaData = loadmat('./enthA_analy_result.mat')
+basalMelt = anaData['basalMelt']
+
+SPY = 31556926
+G = 0.042
+kc = 2.1
+rhow = 1000.0
+Lw = 3.34e5
+
+dz = 2.5
+
+data1 = Dataset('./output1.nc','r')
+data2 = Dataset('./output2.nc','r')
+data3 = Dataset('./output3.nc','r')
+
+yr1 = data1.variables['daysSinceStart'][:]/365.0
+yr2 = data2.variables['daysSinceStart'][:]/365.0
+yr3 = data3.variables['daysSinceStart'][:]/365.0
+
+basalT1 = data1.variables['basalTemperature'][:,:]
+basalT2 = data2.variables['basalTemperature'][:,:]
+basalT3 = data3.variables['basalTemperature'][:,:]
+basalMeanT1 = np.mean(basalT1, axis=1)
+basalMeanT2 = np.mean(basalT2, axis=1)
+basalMeanT3 = np.mean(basalT3, axis=1)
+
+basalBmb1 = data1.variables['groundedBasalMassBal'][:,:]
+basalBmb2 = data2.variables['groundedBasalMassBal'][:,:]
+basalBmb3 = data3.variables['groundedBasalMassBal'][:,:]
+basalMeanBmb1 = np.mean(basalBmb1, axis=1)
+basalMeanBmb2 = np.mean(basalBmb2, axis=1)
+basalMeanBmb3 = np.mean(basalBmb3, axis=1)
+
+basalWaterThickness1 = data1.variables['basalWaterThickness'][:,:]
+basalWaterThickness2 = data2.variables['basalWaterThickness'][:,:]
+basalWaterThickness3 = data3.variables['basalWaterThickness'][:,:]
+basalMeanWaterThickness1 = np.mean(basalWaterThickness1, axis=1)
+basalMeanWaterThickness2 = np.mean(basalWaterThickness2, axis=1)
+basalMeanWaterThickness3 = np.mean(basalWaterThickness3, axis=1)
+
+T1 = data1.variables['temperature'][:,:,:]
+T2 = data2.variables['temperature'][:,:,:]
+T3 = data3.variables['temperature'][:,:,:]
+TMean1 = np.mean(T1, axis=1)
+TMean2 = np.mean(T2, axis=1)
+TMean3 = np.mean(T3, axis=1)
+TMean1_nvert = TMean1[:,-1]
+TMean2_nvert = TMean2[:,-1]
+TMean3_nvert = TMean3[:,-1]
+
+basalbmb1 = SPY*(G + kc*(TMean1_nvert - basalMeanT1)/dz)/(rhow*Lw)
+basalbmb2 = SPY*(G + kc*(TMean2_nvert - basalMeanT2)/dz)/(rhow*Lw)
+basalbmb3 = SPY*(G + kc*(TMean3_nvert - basalMeanT3)/dz)/(rhow*Lw)
+
+Hw1 = np.copy(basalbmb1)
+Hw2 = np.copy(basalbmb2)
+Hw3 = np.copy(basalbmb3)
+
+for i in range(len(basalbmb1)):
+ Hw1[i] = sum(basalbmb1[0:i])*10
+for i in range(len(basalbmb2)):
+ Hw2[i] = sum(basalbmb2[0:i])*10
+for i in range(len(basalbmb3)):
+ Hw3[i] = sum(basalbmb3[0:i])*10
+
+year = np.concatenate([yr1[1::], yr2, yr3])/1000.0
+basalMeanT = np.concatenate([basalMeanT1[1::],basalMeanT2,basalMeanT3])
+basalMeanBmb = np.concatenate([basalMeanBmb1[1::],basalMeanBmb2,basalMeanBmb3])
+basalMeanWaterThickness = np.concatenate([basalMeanWaterThickness1[1::],basalMeanWaterThickness2,basalMeanWaterThickness3])
+#basalbmb = np.concatenate([basalbmb1[1::],basalbmb2,basalbmb3])
+#Hw = np.concatenate([Hw1[1::],Hw2,Hw3])
+
+
+plt.figure (1)
+plt.subplot(311)
+plt.plot(year,basalMeanT-273.15)
+plt.ylabel('$T_{\\rm b}$ ($^\circ \\rm C$)')
+plt.text(10, -28, '(a)', fontsize=20)
+plt.grid(True)
+
+plt.subplot(312)
+plt.plot(year,-basalMeanBmb*SPY)
+plt.plot(basalMelt[1,:]/1000.0, basalMelt[0,:],linewidth=2)
+plt.ylabel('$a_{\\rm b}$ (mm a$^{-1}$ w.e.)')
+plt.text(10, -1.6, '(b)', fontsize=20)
+plt.grid(True)
+
+plt.subplot(313)
+plt.plot(year,basalMeanWaterThickness*910.0/1000.0)
+plt.ylabel('$H_{\\rm w}$ (m)')
+plt.xlabel('Year (ka)')
+plt.text(10, 8, '(c)', fontsize=20)
+plt.grid(True)
+
+
+# Create image plot
+plotname = 'enthalpy_A_results.png'
+plt.savefig(plotname, dpi=150)
+print('Saved plot as ' + plotname)
+
+displayImage = False
+if displayImage:
+ # Note: To get interactive plot, need to comment line at beginning of script "matplotlib.use('Agg')"
+ plt.show()
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/plot_enthalpy_benchmark_B.py b/testing_and_setup/compass/landice/enthalpy-benchmark/plot_enthalpy_benchmark_B.py
new file mode 100755
index 0000000000..26bb17eb68
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/plot_enthalpy_benchmark_B.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+from netCDF4 import Dataset
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.io import loadmat
+
+
+anaData = loadmat('./enthB_analy_result.mat')
+anaZ = anaData['enthB_analy_z']
+anaE = anaData['enthB_analy_E']
+anaT = anaData['enthB_analy_T']
+anaW = anaData['enthB_analy_omega']
+
+cp_ice = 2009.0
+rho_ice = 910.0
+
+data = Dataset('./output.nc','r')
+
+T = data.variables['temperature'][-1,:,:]
+horiMeanT = np.mean(T, axis=0)
+Ts = data.variables['surfaceTemperature'][-1,:]
+meanTs = np.mean(Ts)
+Tall = np.append(meanTs,horiMeanT)
+
+E = data.variables['enthalpy'][-1,:,:]
+horiMeanE = np.mean(E, axis=0)
+
+W = data.variables['waterFrac'][-1,:,:]
+horiMeanW = np.mean(W, axis=0)
+
+nz = len(data.dimensions['nVertLevels'])
+z = 1.0-(np.arange(nz)+1.0)/nz
+
+fsize = 14
+plt.figure (1)
+plt.subplot(1,3,1)
+plt.plot((horiMeanE/910.0+cp_ice*50)/1.0e3,z, label='MALI')
+plt.plot(anaE/1000, anaZ, label='analytical')
+plt.xlabel('$E$ (10$^3$ J kg$^{-1}$)', fontsize=fsize)
+plt.ylabel('$z/H$', fontsize=fsize)
+plt.xticks(np.arange(92,109,step=4), fontsize=fsize)
+plt.yticks(fontsize=fsize)
+plt.text(93,0.05,'a', fontsize=fsize)
+plt.legend()
+plt.grid(True)
+
+plt.subplot(1,3,2)
+plt.plot(Tall-273.15,np.append(1,z))
+plt.plot(anaT-273.15, anaZ)
+plt.xlabel('$T$ ($^\circ$C)', fontsize=fsize)
+#plt.ylabel('$\zeta$', fontsize=20)
+plt.xticks(np.arange(-3.5,0.51,step=1), fontsize=fsize)
+plt.yticks(fontsize=fsize)
+plt.text(-3.2,0.05,'b', fontsize=fsize)
+plt.grid(True)
+#plt.gca().invert_yaxis()
+
+
+plt.subplot(1,3,3)
+plt.plot(horiMeanW*100,z)
+plt.plot(anaW*100, anaZ)
+plt.xlabel('$\omega$ (%)', fontsize=fsize)
+#plt.ylabel('$\zeta$',fontsize=20)
+#plt.xlim(-0.5,3)
+plt.xticks(np.arange(-0.5, 2.51, step=1), fontsize=fsize)
+plt.yticks(fontsize=fsize)
+plt.text(-0.3,0.05,'c', fontsize=fsize)
+plt.grid(True)
+
+plt.show()
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/setup_initial_conditions_A.py b/testing_and_setup/compass/landice/enthalpy-benchmark/setup_initial_conditions_A.py
new file mode 100755
index 0000000000..00c75e169e
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/setup_initial_conditions_A.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+from netCDF4 import Dataset as NetCDFFile
+
+# Open the file, get needed dimensions
+gridfile = NetCDFFile('./landice_grid.nc','r+')
+nVertLevels = len(gridfile.dimensions['nVertLevels'])
+# Get variables
+thickness = gridfile.variables['thickness']
+bedTopography = gridfile.variables['bedTopography']
+basalHeatFlux = gridfile.variables['basalHeatFlux']
+surfaceAirTemperature = gridfile.variables['surfaceAirTemperature']
+temperature = gridfile.variables['temperature']
+
+thickness[:] = 1000
+bedTopography[:] = 0
+basalHeatFlux[:] = 0.042
+surfaceAirTemperature[:] = 243.15
+temperature[:] = 243.15
+
+gridfile.close()
+
diff --git a/testing_and_setup/compass/landice/enthalpy-benchmark/setup_initial_conditions_B.py b/testing_and_setup/compass/landice/enthalpy-benchmark/setup_initial_conditions_B.py
new file mode 100755
index 0000000000..78447e2598
--- /dev/null
+++ b/testing_and_setup/compass/landice/enthalpy-benchmark/setup_initial_conditions_B.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+from netCDF4 import Dataset as NetCDFFile
+
+# Open the file, get needed dimensions
+gridfile = NetCDFFile('./landice_grid.nc','r+')
+nVertLevels = len(gridfile.dimensions['nVertLevels'])
+# Get variables
+xCell = gridfile.variables['xCell']
+yCell = gridfile.variables['yCell']
+xEdge = gridfile.variables['xEdge']
+yEdge = gridfile.variables['yEdge']
+xVertex = gridfile.variables['xVertex']
+yVertex = gridfile.variables['yVertex']
+thickness = gridfile.variables['thickness']
+bedTopography = gridfile.variables['bedTopography']
+layerThicknessFractions = gridfile.variables['layerThicknessFractions']
+SMB = gridfile.variables['sfcMassBal']
+basalHeatFlux = gridfile.variables['basalHeatFlux']
+surfaceAirTemperature = gridfile.variables['surfaceAirTemperature']
+temperature = gridfile.variables['temperature']
+
+thickness[:] = 200
+bedTopography[:] = 0
+basalHeatFlux[:] = 0.0
+surfaceAirTemperature[:] = 270.15
+temperature[:] = 270.15
+
+gridfile.close()
+
diff --git a/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_1proc_run_model_step.xml
index 09bf4c9a23..d7359175f1 100644
--- a/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_1proc_run_model_step.xml
@@ -3,14 +3,13 @@
-
+
-
-
+
@@ -28,7 +27,7 @@
landice_grid.nc
diff --git a/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_8proc_run_model_step.xml b/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_8proc_run_model_step.xml
index e16a3ea6f7..e435fe52f4 100644
--- a/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_8proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/greenland/20km/decomposition_test/config_8proc_run_model_step.xml
@@ -3,14 +3,13 @@
-
+
-
-
+
@@ -27,7 +26,7 @@
landice_grid.nc
-
+
8
diff --git a/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_driver.xml b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_driver.xml
new file mode 100644
index 0000000000..c2a6119226
--- /dev/null
+++ b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_driver.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_full_run_step.xml
new file mode 100644
index 0000000000..29f04f3857
--- /dev/null
+++ b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_full_run_step.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0000-00-01_00:00:00
+ 0001-01-01_00:00:00
+
+
+ rst.$Y-$M-$D.nc
+ output_interval
+ 0001-00-01_00:00:00
+ 0001-01-01_00:00:00
+
+
+
+
+
+
+
+ landice_grid.nc
+
+
+ 12
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_restart_run_step.xml
new file mode 100644
index 0000000000..b1f6b0b242
--- /dev/null
+++ b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/config_restart_run_step.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0000-00-01_00:00:00
+ overwrite
+ 0001-01-01_00:00:00
+
+
+ rst.$Y-$M-$D.nc
+ output_interval
+ 0000-00-01_00:00:00
+ 0001-01-01_00:00:00
+
+
+
+
+
+
+
+ landice_grid.nc
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/output_comparison.xml b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/output_comparison.xml
new file mode 100644
index 0000000000..73170491f3
--- /dev/null
+++ b/testing_and_setup/compass/landice/greenland/20km/ho_restart_test/output_comparison.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/testing_and_setup/compass/landice/greenland/20km/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/greenland/20km/restart_test/config_full_run_step.xml
index cf58cd13e1..32cdbadc3b 100644
--- a/testing_and_setup/compass/landice/greenland/20km/restart_test/config_full_run_step.xml
+++ b/testing_and_setup/compass/landice/greenland/20km/restart_test/config_full_run_step.xml
@@ -3,15 +3,14 @@
-
+
-
+
-
@@ -42,7 +41,7 @@
landice_grid.nc
-
+
4
diff --git a/testing_and_setup/compass/landice/greenland/20km/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/greenland/20km/restart_test/config_restart_run_step.xml
index ada4ca0aa2..d5fbfdc497 100644
--- a/testing_and_setup/compass/landice/greenland/20km/restart_test/config_restart_run_step.xml
+++ b/testing_and_setup/compass/landice/greenland/20km/restart_test/config_restart_run_step.xml
@@ -2,15 +2,14 @@
-
+
-
+
-
@@ -51,7 +50,7 @@
landice_grid.nc
-
+
4
diff --git a/testing_and_setup/compass/landice/greenland/20km/smoke_test/config_run_model_step.xml b/testing_and_setup/compass/landice/greenland/20km/smoke_test/config_run_model_step.xml
index 15bb4ed1ec..83010afb1d 100644
--- a/testing_and_setup/compass/landice/greenland/20km/smoke_test/config_run_model_step.xml
+++ b/testing_and_setup/compass/landice/greenland/20km/smoke_test/config_run_model_step.xml
@@ -3,14 +3,13 @@
-
+
-
-
+
@@ -27,7 +26,7 @@
landice_grid.nc
-
+
4
diff --git a/testing_and_setup/compass/landice/greenland/albany_input.xml b/testing_and_setup/compass/landice/greenland/albany_input.xml
deleted file mode 100644
index 4f83838590..0000000000
--- a/testing_and_setup/compass/landice/greenland/albany_input.xml
+++ /dev/null
@@ -1,189 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testing_and_setup/compass/landice/greenland/albany_input.yaml b/testing_and_setup/compass/landice/greenland/albany_input.yaml
new file mode 100644
index 0000000000..4b8112a9be
--- /dev/null
+++ b/testing_and_setup/compass/landice/greenland/albany_input.yaml
@@ -0,0 +1,275 @@
+%YAML 1.1
+---
+ANONYMOUS:
+# In order to use ML, change Tpetra to Epetra in the following line,
+# and "Preconditioner Type: MueLu" to " Preconditioner Type: ML" several lines below
+ Build Type: Tpetra
+
+ Problem:
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+ 'Glen''s Law A': 1.0e-04
+ 'Glen''s Law n': 3.0e+00
+
+# Discretization Description
+ Discretization:
+ Element Shape: Tetrahedron
+ Exodus Output File Name: albany_output.exo
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: MueLu
+ Preconditioner Types:
+
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
+
+ MueLu:
+ Matrix:
+ PDE equations: 2
+ Factories:
+ myLineDetectionFact:
+ factory: LineDetectionFactory
+ 'linedetection: orientation': coordinates
+ mySemiCoarsenPFact1:
+ factory: SemiCoarsenPFactory
+ 'semicoarsen: coarsen rate': 14
+ UncoupledAggregationFact2:
+ factory: UncoupledAggregationFactory
+ 'aggregation: ordering': graph
+ 'aggregation: max selected neighbors': 0
+ 'aggregation: min agg size': 3
+ 'aggregation: phase3 avoid singletons': true
+ MyCoarseMap2:
+ factory: CoarseMapFactory
+ Aggregates: UncoupledAggregationFact2
+ myTentativePFact2:
+ 'tentative: calculate qr': true
+ factory: TentativePFactory
+ Aggregates: UncoupledAggregationFact2
+ CoarseMap: MyCoarseMap2
+ mySaPFact2:
+ 'sa: eigenvalue estimate num iterations': 10
+ 'sa: damping factor': 1.33333e+00
+ factory: SaPFactory
+ P: myTentativePFact2
+ myTransferCoordinatesFact:
+ factory: CoordinatesTransferFactory
+ CoarseMap: MyCoarseMap2
+ Aggregates: UncoupledAggregationFact2
+ myTogglePFact:
+ factory: TogglePFactory
+ 'semicoarsen: number of levels': 2
+ TransferFactories:
+ P1: mySemiCoarsenPFact1
+ P2: mySaPFact2
+ Ptent1: mySemiCoarsenPFact1
+ Ptent2: myTentativePFact2
+ Nullspace1: mySemiCoarsenPFact1
+ Nullspace2: myTentativePFact2
+ myRestrictorFact:
+ factory: TransPFactory
+ P: myTogglePFact
+ myToggleTransferCoordinatesFact:
+ factory: ToggleCoordinatesTransferFactory
+ Chosen P: myTogglePFact
+ TransferFactories:
+ Coordinates1: mySemiCoarsenPFact1
+ Coordinates2: myTransferCoordinatesFact
+ myRAPFact:
+ factory: RAPFactory
+ P: myTogglePFact
+ R: myRestrictorFact
+ TransferFactories:
+ For Coordinates: myToggleTransferCoordinatesFact
+ myRepartitionHeuristicFact:
+ factory: RepartitionHeuristicFactory
+ A: myRAPFact
+ 'repartition: min rows per proc': 3000
+ 'repartition: max imbalance': 1.327e+00
+ 'repartition: start level': 1
+ myZoltanInterface:
+ factory: ZoltanInterface
+ A: myRAPFact
+ Coordinates: myToggleTransferCoordinatesFact
+ number of partitions: myRepartitionHeuristicFact
+ myRepartitionFact:
+ factory: RepartitionFactory
+ A: myRAPFact
+ Partition: myZoltanInterface
+ 'repartition: remap parts': true
+ number of partitions: myRepartitionHeuristicFact
+ myRebalanceProlongatorFact:
+ factory: RebalanceTransferFactory
+ type: Interpolation
+ P: myTogglePFact
+ Coordinates: myToggleTransferCoordinatesFact
+ Nullspace: myTogglePFact
+ myRebalanceRestrictionFact:
+ factory: RebalanceTransferFactory
+ type: Restriction
+ R: myRestrictorFact
+ myRebalanceAFact:
+ factory: RebalanceAcFactory
+ A: myRAPFact
+ TransferFactories: { }
+ mySmoother1:
+ factory: TrilinosSmoother
+ type: LINESMOOTHING_BANDEDRELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother3:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother4:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': pre
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 4
+ 'relaxation: damping factor': 1.0
+ Hierarchy:
+ max levels: 7
+ 'coarse: max size': 2000
+ verbosity: None
+ Finest:
+ Smoother: mySmoother1
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+ All:
+ startLevel: 1
+ Smoother: mySmoother4
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+
+ ML:
+ Base Method Defaults: none
+ ML Settings:
+ default values: SA
+ ML output: 0
+ 'repartition: enable': 1
+ 'repartition: max min ratio': 1.327e+00
+ 'repartition: min per proc': 600
+ 'repartition: Zoltan dimensions': 2
+ 'repartition: start level': 4
+ 'semicoarsen: number of levels': 2
+ 'semicoarsen: coarsen rate': 14
+ 'smoother: sweeps': 4
+ 'smoother: type': Gauss-Seidel
+ 'smoother: Chebyshev eig boost': 1.2e+00
+ 'smoother: sweeps (level 0)': 1
+ 'smoother: type (level 0)': line Gauss-Seidel
+ 'smoother: line GS Type': standard
+ 'smoother: damping factor': 1.0e+00
+ 'smoother: pre or post': both
+ 'coarse: type': Gauss-Seidel
+ 'coarse: sweeps': 4
+ 'coarse: max size': 2000
+ 'coarse: pre or post': pre
+ max levels: 7
+
diff --git a/testing_and_setup/compass/landice/greenland/albany_schoof_input.yaml b/testing_and_setup/compass/landice/greenland/albany_schoof_input.yaml
new file mode 100644
index 0000000000..d4c403706d
--- /dev/null
+++ b/testing_and_setup/compass/landice/greenland/albany_schoof_input.yaml
@@ -0,0 +1,292 @@
+%YAML 1.1
+---
+ANONYMOUS:
+# In order to use ML, change Tpetra to Epetra in the following line,
+# and "Preconditioner Type: MueLu" to " Preconditioner Type: ML" several lines below
+ Build Type: Tpetra
+
+ Problem:
+ LandIce Viscosity:
+ Type: 'Glen''s Law'
+ Flow Rate Type: Uniform
+ 'Glen''s Law Homotopy Parameter': 1.0
+ 'Glen''s Law A': 1.0e-04
+ 'Glen''s Law n': 3.0e+00
+ LandIce BCs:
+ Number: 2
+ BC 0:
+ Cubature Degree: 3
+ Side Set Name: basalside
+ Type: Basal Friction
+ Basal Friction Coefficient:
+ Type: Regularized Coulomb
+ Given Field Variable Name: basal_friction
+ Zero Beta On Floating Ice: true
+ Coulomb Friction Coefficient: 1.0e+05
+ Power Exponent: 1.0
+ Bed Roughness: 1.0e+04
+ BC 1:
+ Cubature Degree: 3
+ Side Set Name: ice_margin_side
+ Type: Lateral
+
+# Discretization Description
+ Discretization:
+ Element Shape: Tetrahedron
+ Exodus Output File Name: albany_output.exo
+
+ Piro:
+# Nonlinear Solver Information
+ NOX:
+ Nonlinear Solver: Line Search Based
+ Line Search:
+ Full Step:
+ Full Step: 1.0e+00
+ Method: Backtrack
+ Solver Options:
+ Status Test Check Type: Minimal
+ Status Tests:
+ Test Type: Combo
+ Combo Type: OR
+ Number of Tests: 2
+ Test 0:
+ Test Type: NormF
+ Norm Type: Two Norm
+ Scale Type: Scaled
+ Tolerance: 1.0e-05
+ Test 1:
+ Test Type: MaxIters
+ Maximum Iterations: 50
+ Printing:
+ Output Precision: 3
+ Output Processor: 0
+ Output Information:
+ Error: true
+ Warning: true
+ Outer Iteration: true
+ Parameters: false
+ Details: false
+ Linear Solver Details: false
+ Stepper Iteration: true
+ Stepper Details: true
+ Stepper Parameters: true
+
+ Direction:
+ Method: Newton
+ Newton:
+ Forcing Term Method: Constant
+ Rescue Bad Newton Solve: true
+ Linear Solver:
+ Write Linear System: false
+ Tolerance: 1.0e-8
+
+ Stratimikos Linear Solver:
+ Stratimikos:
+
+# Linear Solver Information
+ Linear Solver Type: Belos
+ Linear Solver Types:
+ AztecOO:
+ Forward Solve:
+ AztecOO Settings:
+ Aztec Solver: GMRES
+ Convergence Test: r0
+ Size of Krylov Subspace: 200
+ Output Frequency: 20
+ Max Iterations: 200
+ Belos:
+ Solver Type: Block GMRES
+ Solver Types:
+ Block GMRES:
+ Output Frequency: 20
+ Output Style: 1
+ Verbosity: 33
+ Maximum Iterations: 200
+ Block Size: 1
+ Num Blocks: 200
+ Flexible Gmres: false
+ VerboseObject:
+ Output File: none
+ Verbosity Level: low
+
+# Preconditioner Information
+ Preconditioner Type: MueLu
+ Preconditioner Types:
+
+ Ifpack:
+ Overlap: 1
+ Prec Type: ILU
+ Ifpack Settings:
+ 'fact: level-of-fill': 0
+
+ Ifpack2:
+ Overlap: 1
+ Prec Type: ILUT
+
+ MueLu:
+ Matrix:
+ PDE equations: 2
+ Factories:
+ myLineDetectionFact:
+ factory: LineDetectionFactory
+ 'linedetection: orientation': coordinates
+ mySemiCoarsenPFact1:
+ factory: SemiCoarsenPFactory
+ 'semicoarsen: coarsen rate': 14
+ UncoupledAggregationFact2:
+ factory: UncoupledAggregationFactory
+ 'aggregation: ordering': graph
+ 'aggregation: max selected neighbors': 0
+ 'aggregation: min agg size': 3
+ 'aggregation: phase3 avoid singletons': true
+ MyCoarseMap2:
+ factory: CoarseMapFactory
+ Aggregates: UncoupledAggregationFact2
+ myTentativePFact2:
+ 'tentative: calculate qr': true
+ factory: TentativePFactory
+ Aggregates: UncoupledAggregationFact2
+ CoarseMap: MyCoarseMap2
+ mySaPFact2:
+ 'sa: eigenvalue estimate num iterations': 10
+ 'sa: damping factor': 1.33333e+00
+ factory: SaPFactory
+ P: myTentativePFact2
+ myTransferCoordinatesFact:
+ factory: CoordinatesTransferFactory
+ CoarseMap: MyCoarseMap2
+ Aggregates: UncoupledAggregationFact2
+ myTogglePFact:
+ factory: TogglePFactory
+ 'semicoarsen: number of levels': 2
+ TransferFactories:
+ P1: mySemiCoarsenPFact1
+ P2: mySaPFact2
+ Ptent1: mySemiCoarsenPFact1
+ Ptent2: myTentativePFact2
+ Nullspace1: mySemiCoarsenPFact1
+ Nullspace2: myTentativePFact2
+ myRestrictorFact:
+ factory: TransPFactory
+ P: myTogglePFact
+ myToggleTransferCoordinatesFact:
+ factory: ToggleCoordinatesTransferFactory
+ Chosen P: myTogglePFact
+ TransferFactories:
+ Coordinates1: mySemiCoarsenPFact1
+ Coordinates2: myTransferCoordinatesFact
+ myRAPFact:
+ factory: RAPFactory
+ P: myTogglePFact
+ R: myRestrictorFact
+ TransferFactories:
+ For Coordinates: myToggleTransferCoordinatesFact
+ myRepartitionHeuristicFact:
+ factory: RepartitionHeuristicFactory
+ A: myRAPFact
+ 'repartition: min rows per proc': 3000
+ 'repartition: max imbalance': 1.327e+00
+ 'repartition: start level': 1
+ myZoltanInterface:
+ factory: ZoltanInterface
+ A: myRAPFact
+ Coordinates: myToggleTransferCoordinatesFact
+ number of partitions: myRepartitionHeuristicFact
+ myRepartitionFact:
+ factory: RepartitionFactory
+ A: myRAPFact
+ Partition: myZoltanInterface
+ 'repartition: remap parts': true
+ number of partitions: myRepartitionHeuristicFact
+ myRebalanceProlongatorFact:
+ factory: RebalanceTransferFactory
+ type: Interpolation
+ P: myTogglePFact
+ Coordinates: myToggleTransferCoordinatesFact
+ Nullspace: myTogglePFact
+ myRebalanceRestrictionFact:
+ factory: RebalanceTransferFactory
+ type: Restriction
+ R: myRestrictorFact
+ myRebalanceAFact:
+ factory: RebalanceAcFactory
+ A: myRAPFact
+ TransferFactories: { }
+ mySmoother1:
+ factory: TrilinosSmoother
+ type: LINESMOOTHING_BANDEDRELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother3:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': both
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 1
+ 'relaxation: damping factor': 1.0
+ mySmoother4:
+ factory: TrilinosSmoother
+ type: RELAXATION
+ 'smoother: pre or post': pre
+ ParameterList:
+ 'relaxation: type': Gauss-Seidel
+ 'relaxation: sweeps': 4
+ 'relaxation: damping factor': 1.0
+ Hierarchy:
+ max levels: 7
+ 'coarse: max size': 2000
+ verbosity: None
+ Finest:
+ Smoother: mySmoother1
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+ All:
+ startLevel: 1
+ Smoother: mySmoother4
+ CoarseSolver: mySmoother4
+ P: myRebalanceProlongatorFact
+ Nullspace: myRebalanceProlongatorFact
+ CoarseNumZLayers: myLineDetectionFact
+ LineDetection_Layers: myLineDetectionFact
+ LineDetection_VertLineIds: myLineDetectionFact
+ A: myRebalanceAFact
+ Coordinates: myRebalanceProlongatorFact
+ Importer: myRepartitionFact
+
+ ML:
+ Base Method Defaults: none
+ ML Settings:
+ default values: SA
+ ML output: 0
+ 'repartition: enable': 1
+ 'repartition: max min ratio': 1.327e+00
+ 'repartition: min per proc': 600
+ 'repartition: Zoltan dimensions': 2
+ 'repartition: start level': 4
+ 'semicoarsen: number of levels': 2
+ 'semicoarsen: coarsen rate': 14
+ 'smoother: sweeps': 4
+ 'smoother: type': Gauss-Seidel
+ 'smoother: Chebyshev eig boost': 1.2e+00
+ 'smoother: sweeps (level 0)': 1
+ 'smoother: type (level 0)': line Gauss-Seidel
+ 'smoother: line GS Type': standard
+ 'smoother: damping factor': 1.0e+00
+ 'smoother: pre or post': both
+ 'coarse: type': Gauss-Seidel
+ 'coarse: sweeps': 4
+ 'coarse: max size': 2000
+ 'coarse: pre or post': pre
+ max levels: 7
+
diff --git a/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_1proc_run_model_step.xml b/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_1proc_run_model_step.xml
index eada8deaae..a45bf93da2 100644
--- a/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_1proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_1proc_run_model_step.xml
@@ -4,10 +4,10 @@
-
+
@@ -26,7 +26,7 @@
diff --git a/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_3proc_run_model_step.xml b/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_3proc_run_model_step.xml
index 9ea90bd51c..88c06c20be 100644
--- a/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_3proc_run_model_step.xml
+++ b/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_3proc_run_model_step.xml
@@ -4,10 +4,10 @@
-
+
@@ -25,7 +25,7 @@
-
+
3
diff --git a/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_setup_mesh_step.xml b/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_setup_mesh_step.xml
index 23bc1f776b..4baa4db047 100644
--- a/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_setup_mesh_step.xml
+++ b/testing_and_setup/compass/landice/hydro-radial/1000m/decomposition_test/config_setup_mesh_step.xml
@@ -2,27 +2,34 @@
-
-
-
-
-
+
+ 50
+ 58
+ 1000.0
+
+
+ grid.nc
-
-
+
grid.nc
+ culled.nc
+
+
+
+
+ culled.nc
mpas_grid.nc
-
+
mpas_grid.nc
landice_grid.nc
3
diff --git a/testing_and_setup/compass/landice/hydro-radial/1000m/periodic_hex.namelist.input b/testing_and_setup/compass/landice/hydro-radial/1000m/periodic_hex.namelist.input
deleted file mode 100644
index 1c6ef1dd7b..0000000000
--- a/testing_and_setup/compass/landice/hydro-radial/1000m/periodic_hex.namelist.input
+++ /dev/null
@@ -1,8 +0,0 @@
-&periodic_grid
- nx = 50,
- ny = 58,
- dc = 1000.,
- nVertLevels = 1,
- nTracers = 1,
- nproc = 1
-/
diff --git a/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_full_run_step.xml b/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_full_run_step.xml
index ab1b1b0a6a..7ca9b6d5ec 100644
--- a/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_full_run_step.xml
+++ b/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_full_run_step.xml
@@ -4,10 +4,10 @@
-
+
@@ -32,7 +32,7 @@
-
+
4
diff --git a/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_restart_run_step.xml b/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_restart_run_step.xml
index eec8d5e39c..d22ec8f513 100644
--- a/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_restart_run_step.xml
+++ b/testing_and_setup/compass/landice/hydro-radial/1000m/restart_test/config_restart_run_step.xml
@@ -4,10 +4,10 @@
-
+
@@ -58,7 +58,7 @@
-