diff --git a/src/core_ocean/analysis_members/Makefile b/src/core_ocean/analysis_members/Makefile
index a9f301c380..b27cff4761 100644
--- a/src/core_ocean/analysis_members/Makefile
+++ b/src/core_ocean/analysis_members/Makefile
@@ -25,7 +25,8 @@ MEMBERS = mpas_ocn_global_stats.o \
mpas_ocn_rpn_calculator.o \
mpas_ocn_transect_transport.o\
mpas_ocn_eddy_product_variables.o\
- mpas_ocn_moc_streamfunction.o
+ mpas_ocn_moc_streamfunction.o\
+ mpas_ocn_ocean_heat_content.o
all: $(OBJS)
diff --git a/src/core_ocean/analysis_members/Registry_analysis_members.xml b/src/core_ocean/analysis_members/Registry_analysis_members.xml
index bee733ba8e..5a1cf9e962 100644
--- a/src/core_ocean/analysis_members/Registry_analysis_members.xml
+++ b/src/core_ocean/analysis_members/Registry_analysis_members.xml
@@ -29,3 +29,4 @@
#include "Registry_transect_transport.xml"
#include "Registry_eddy_product_variables.xml"
#include "Registry_moc_streamfunction.xml"
+#include "Registry_ocean_heat_content.xml"
diff --git a/src/core_ocean/analysis_members/Registry_ocean_heat_content.xml b/src/core_ocean/analysis_members/Registry_ocean_heat_content.xml
new file mode 100644
index 0000000000..35be4a66e2
--- /dev/null
+++ b/src/core_ocean/analysis_members/Registry_ocean_heat_content.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core_ocean/analysis_members/mpas_ocn_analysis_driver.F b/src/core_ocean/analysis_members/mpas_ocn_analysis_driver.F
index 7beba155b6..6ddb26d26d 100644
--- a/src/core_ocean/analysis_members/mpas_ocn_analysis_driver.F
+++ b/src/core_ocean/analysis_members/mpas_ocn_analysis_driver.F
@@ -48,6 +48,7 @@ module ocn_analysis_driver
use ocn_transect_transport
use ocn_eddy_product_variables
use ocn_moc_streamfunction
+ use ocn_ocean_heat_content
! use ocn_TEM_PLATE
implicit none
@@ -193,6 +194,7 @@ subroutine ocn_analysis_setup_packages(configPool, packagePool, iocontext, err)!
call mpas_pool_add_config(analysisMemberList, 'transectTransport', 1)
call mpas_pool_add_config(analysisMemberList, 'eddyProductVariables', 1)
call mpas_pool_add_config(analysisMemberList, 'mocStreamfunction', 1)
+ call mpas_pool_add_config(analysisMemberList, 'oceanHeatContent', 1)
! call mpas_pool_add_config(analysisMemberList, 'temPlate', 1)
! DON'T EDIT BELOW HERE
@@ -300,6 +302,7 @@ subroutine ocn_analysis_bootstrap(domain, err)!{{{
call mpas_pool_get_config(domain % configs, configName, config_AM_enable)
+ print *, poolItr % memberName(1:nameLength)
if ( config_AM_enable ) then
timerName = trim(initReadTimerPrefix) // poolItr % memberName(1:nameLength)
call mpas_timer_start(timerName)
@@ -1122,6 +1125,8 @@ subroutine ocn_init_analysis_members(domain, analysisMemberName, iErr)!{{{
call ocn_init_eddy_product_variables(domain, err_tmp)
else if ( analysisMemberName(1:nameLength) == 'mocStreamfunction' ) then
call ocn_init_moc_streamfunction(domain, err_tmp)
+ else if ( analysisMemberName(1:nameLength) == 'oceanHeatContent' ) then
+ call ocn_init_ocean_heat_content(domain, err_tmp)
! else if ( analysisMemberName(1:nameLength) == 'temPlate' ) then
! call ocn_init_TEM_PLATE(domain, err_tmp)
! rpn is third to last
@@ -1214,6 +1219,8 @@ subroutine ocn_compute_analysis_members(domain, timeLevel, analysisMemberName, i
call ocn_compute_eddy_product_variables(domain, timeLevel, err_tmp)
else if ( analysisMemberName(1:nameLength) == 'mocStreamfunction' ) then
call ocn_compute_moc_streamfunction(domain, timeLevel, err_tmp)
+ else if ( analysisMemberName(1:nameLength) == 'oceanHeatContent' ) then
+ call ocn_compute_ocean_heat_content(domain, timeLevel, err_tmp)
! else if ( analysisMemberName(1:nameLength) == 'temPlate' ) then
! call ocn_compute_TEM_PLATE(domain, timeLevel, err_tmp)
! rpn is third to last
@@ -1311,6 +1318,8 @@ subroutine ocn_restart_analysis_members(domain, analysisMemberName, iErr)!{{{
call ocn_restart_eddy_product_variables(domain, err_tmp)
else if ( analysisMemberName(1:nameLength) == 'mocStreamfunction' ) then
call ocn_restart_moc_streamfunction(domain, err_tmp)
+ else if ( analysisMemberName(1:nameLength) == 'oceanHeatContent' ) then
+ call ocn_restart_ocean_heat_content(domain, err_tmp)
! else if ( analysisMemberName(1:nameLength) == 'temPlate' ) then
! call ocn_restart_TEM_PLATE(domain, err_tmp)
! rpn is third to last
@@ -1402,6 +1411,8 @@ subroutine ocn_finalize_analysis_members(domain, analysisMemberName, iErr)!{{{
call ocn_finalize_eddy_product_variables(domain, err_tmp)
else if ( analysisMemberName(1:nameLength) == 'mocStreamfunction' ) then
call ocn_finalize_moc_streamfunction(domain, err_tmp)
+ else if ( analysisMemberName(1:nameLength) == 'oceanHeatContent' ) then
+ call ocn_finalize_ocean_heat_content(domain,err_tmp)
! else if ( analysisMemberName(1:nameLength) == 'temPlate' ) then
! call ocn_finalize_TEM_PLATE(domain, err_tmp)
! rpn is third to last
diff --git a/src/core_ocean/analysis_members/mpas_ocn_ocean_heat_content.F b/src/core_ocean/analysis_members/mpas_ocn_ocean_heat_content.F
new file mode 100644
index 0000000000..93fa7e0735
--- /dev/null
+++ b/src/core_ocean/analysis_members/mpas_ocn_ocean_heat_content.F
@@ -0,0 +1,345 @@
+! 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
+!
+!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+!
+! ocn_ocean_heat_content
+!
+!> \brief MPAS ocean analysis mode member: Computes Ocean Heat Content at
+!> standard layers
+!> \author Luke Van Roekel
+!> \date February 25, 2020
+!> \details
+!> Computes ocean heat content in 0-700, 700-2000, 2000-Bottom and 0-Bottom
+!> layers
+!> Returns a nCells array for each layer
+!>
+!-----------------------------------------------------------------------
+
+module ocn_ocean_heat_content
+
+ use mpas_derived_types
+ use mpas_pool_routines
+ use mpas_dmpar
+ use mpas_timekeeping
+ use mpas_stream_manager
+
+ use ocn_constants
+ use ocn_diagnostics_routines
+
+ implicit none
+ private
+ save
+
+ !--------------------------------------------------------------------
+ !
+ ! Public parameters
+ !
+ !--------------------------------------------------------------------
+
+ !--------------------------------------------------------------------
+ !
+ ! Public member functions
+ !
+ !--------------------------------------------------------------------
+
+ public :: ocn_init_ocean_heat_content, &
+ ocn_compute_ocean_heat_content, &
+ ocn_restart_ocean_heat_content, &
+ ocn_finalize_ocean_heat_content
+
+ !--------------------------------------------------------------------
+ !
+ ! Private module variables
+ !
+ !--------------------------------------------------------------------
+
+!***********************************************************************
+
+contains
+
+!***********************************************************************
+!
+! routine ocn_init_ocean_heat_content
+!
+!> \brief Initialize MPAS-Ocean analysis member
+!> \author Luke Van Roekel
+!> \date February 25, 2020
+!> \details
+!> This routine conducts all initializations required for the
+!> MPAS-Ocean analysis member.
+!
+!-----------------------------------------------------------------------
+
+ subroutine ocn_init_ocean_heat_content(domain, err)!{{{
+
+ !-----------------------------------------------------------------
+ !
+ ! input variables
+ !
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ !
+ ! input/output variables
+ !
+ !-----------------------------------------------------------------
+
+ type(domain_type), intent(inout) :: domain
+
+ !-----------------------------------------------------------------
+ !
+ ! output variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ !
+ ! local variables
+ !
+ !-----------------------------------------------------------------
+
+ err = 0
+
+ end subroutine ocn_init_ocean_heat_content!}}}
+
+!***********************************************************************
+!
+! routine ocn_compute_ocean_heat_content
+!
+!> \brief Compute MPAS-Ocean analysis member
+!> \author Luke Van Roekel
+!> \date February 25, 2020
+!> \details
+!> This routine conducts all computation required for this
+!> MPAS-Ocean analysis member.
+!
+!-----------------------------------------------------------------------
+
+ subroutine ocn_compute_ocean_heat_content(domain, timeLevel, err)!{{{
+
+ !-----------------------------------------------------------------
+ !
+ ! input variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(in) :: timeLevel
+
+ !-----------------------------------------------------------------
+ !
+ ! input/output variables
+ !
+ !-----------------------------------------------------------------
+
+ type(domain_type), intent(inout) :: domain
+
+ !-----------------------------------------------------------------
+ !
+ ! output variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ !
+ ! local variables
+ !
+ !-----------------------------------------------------------------
+
+ type(mpas_pool_type), pointer :: oceanHeatContentAMPool
+ type(dm_info) :: dminfo
+ type(block_type), pointer :: block
+ type(mpas_pool_type), pointer :: statePool
+ type(mpas_pool_type), pointer :: meshPool
+ type(mpas_pool_type), pointer :: scratchPool
+ type(mpas_pool_type), pointer :: diagnosticsPool
+ type(mpas_pool_type), pointer :: tracersPool
+
+ ! Here are some example variables which may be needed for your analysis member
+ integer, pointer :: nVertLevels, nCellsSolve, nEdgesSolve, nVerticesSolve, index_temperature
+ integer :: iTracer, k, iCell
+ integer, dimension(:), pointer :: maxLevelCell, maxLevelEdgeTop, maxLevelVertexBot
+
+ real(kind=RKIND), dimension(:, :, :), pointer :: tracers
+ real(kind=RKIND), dimension(:, :), pointer :: zMid, layerThickness
+ real(kind=RKIND), dimension(:), pointer :: areaCell, dcEdge, dvEdge, &
+ oceanHeatContentSfcToBot, oceanHeatContentSfcTo700m, &
+ oceanHeatContent700mto2000m, oceanHeatContent2000mtoBot
+
+ real(kind=RKIND) :: heatLayer
+ err = 0
+
+ dminfo = domain%dminfo
+
+ block => domain%blocklist
+ do while (associated(block))
+ call mpas_pool_get_subpool(block%structs, 'state', statePool)
+ 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, 'diagnostics', diagnosticsPool)
+ call mpas_pool_get_subpool(block%structs, 'layeredOceanHeatContent', oceanHeatContentAMPool)
+ call mpas_pool_get_subpool(statePool, 'tracers', tracersPool)
+
+ call mpas_pool_get_dimension(tracersPool, 'index_temperature', index_temperature)
+ call mpas_pool_get_dimension(block%dimensions, 'nVertLevels', nVertLevels)
+ 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, 'nVerticesSolve', nVerticesSolve)
+
+ call mpas_pool_get_array(meshPool, 'areaCell', areaCell)
+ call mpas_pool_get_array(meshPool, 'dcEdge', dcEdge)
+ call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge)
+ call mpas_pool_get_array(meshPool, 'maxLevelCell', maxLevelCell)
+ call mpas_pool_get_array(meshPool, 'maxLevelEdgeTop', maxLevelEdgeTop)
+ call mpas_pool_get_array(meshPool, 'maxLevelVertexBot', maxLevelVertexBot)
+
+ call mpas_pool_get_array(tracersPool, 'activeTracers', tracers, timeLevel)
+ call mpas_pool_get_array(diagnosticsPool, 'zMid', zMid)
+ call mpas_pool_get_array(statePool, 'layerThickness', layerThickness)
+
+ call mpas_pool_get_array(oceanHeatContentAMPool, 'oceanHeatContentSfcToBot', oceanHeatContentSfcToBot)
+ call mpas_pool_get_array(oceanHeatContentAMPool, 'oceanHeatContentSfcTo700m', oceanHeatContentSfcTo700m)
+ call mpas_pool_get_array(oceanHeatContentAMPool, 'oceanHeatContent700mto2000m', oceanHeatContent700mto2000m)
+ call mpas_pool_get_array(oceanHeatContentAMPool, 'oceanHeatContent2000mtoBot', oceanHeatContent2000mtoBot)
+
+ do iCell = 1, nCellsSolve
+ k = 1
+ oceanHeatContentSfcTo700m(iCell) = 0.0_RKIND
+ oceanHeatContentSfcToBot(iCell) = 0.0_RKIND
+ oceanHeatContent700mto2000m(iCell) = 0.0_RKIND
+ oceanHeatContent2000mtoBot(iCell) = 0.0_RKIND
+ do while (zMid(k, iCell) .ge. -700.0_RKIND .and. k .le. maxLevelCell(iCell))
+ heatLayer = layerThickness(k, iCell)*areaCell(iCell)*cp_sw*rho_sw* &
+ (tracers(index_temperature, k, iCell) + 273.15_RKIND)
+ oceanHeatContentSfcTo700m(iCell) = oceanHeatContentSfcTo700m(iCell) + heatLayer
+ oceanHeatContentSfcToBot(iCell) = oceanHeatContentSfcToBot(iCell) + heatLayer
+ k = k + 1
+ enddo
+
+ do while (zMid(k, iCell) .ge. -2000.0_RKIND .and. k .le. maxLevelCell(iCell))
+ heatLayer = layerThickness(k, iCell)*areaCell(iCell)*cp_sw*rho_sw* &
+ (tracers(index_temperature, k, iCell) + 273.15_RKIND)
+ oceanHeatContent700mto2000m(iCell) = oceanHeatContent700mto2000m(iCell) + heatLayer
+ oceanHeatContentSfcToBot(iCell) = oceanHeatContentSfcToBot(iCell) + heatLayer
+ k = k + 1
+ enddo
+
+ do while (k .le. maxLevelCell(iCell))
+ heatLayer = layerThickness(k, iCell)*areaCell(iCell)*cp_sw*rho_sw* &
+ (tracers(index_temperature, k, iCell) + 273.15_RKIND)
+ oceanHeatContent2000mtoBot(iCell) = oceanHeatContent2000mtoBot(iCell) + heatLayer
+ oceanHeatContentSfcToBot(iCell) = oceanHeatContentSfcToBot(iCell) + heatLayer
+ k = k + 1
+ end do
+ end do
+
+ block => block%next
+ end do
+
+ end subroutine ocn_compute_ocean_heat_content!}}}
+
+!***********************************************************************
+!
+! routine ocn_restart_ocean_heat_content
+!
+!> \brief Save restart for MPAS-Ocean analysis member
+!> \author Luke Van Roekel
+!> \date February 25, 2020
+!> \details
+!> This routine conducts computation required to save a restart state
+!> for the MPAS-Ocean analysis member.
+!
+!-----------------------------------------------------------------------
+
+ subroutine ocn_restart_ocean_heat_content(domain, err)!{{{
+
+ !-----------------------------------------------------------------
+ !
+ ! input variables
+ !
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ !
+ ! input/output variables
+ !
+ !-----------------------------------------------------------------
+
+ type(domain_type), intent(inout) :: domain
+
+ !-----------------------------------------------------------------
+ !
+ ! output variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ !
+ ! local variables
+ !
+ !-----------------------------------------------------------------
+
+ err = 0
+
+ end subroutine ocn_restart_ocean_heat_content!}}}
+
+!***********************************************************************
+!
+! routine ocn_finalize_ocean_heat_content
+!
+!> \brief Finalize MPAS-Ocean analysis member
+!> \author Luke Van Roekel
+!> \date February 25, 2020
+!> \details
+!> This routine conducts all finalizations required for this
+!> MPAS-Ocean analysis member.
+!
+!-----------------------------------------------------------------------
+
+ subroutine ocn_finalize_ocean_heat_content(domain, err)!{{{
+
+ !-----------------------------------------------------------------
+ !
+ ! input variables
+ !
+ !-----------------------------------------------------------------
+
+ !-----------------------------------------------------------------
+ !
+ ! input/output variables
+ !
+ !-----------------------------------------------------------------
+
+ type(domain_type), intent(inout) :: domain
+
+ !-----------------------------------------------------------------
+ !
+ ! output variables
+ !
+ !-----------------------------------------------------------------
+
+ integer, intent(out) :: err !< Output: error flag
+
+ !-----------------------------------------------------------------
+ !
+ ! local variables
+ !
+ !-----------------------------------------------------------------
+
+ err = 0
+
+ end subroutine ocn_finalize_ocean_heat_content!}}}
+
+end module ocn_ocean_heat_content
+
+! vim: foldmethod=marker
diff --git a/testing_and_setup/compass/ocean/templates/analysis_members/ocean_heat_content.xml b/testing_and_setup/compass/ocean/templates/analysis_members/ocean_heat_content.xml
new file mode 100644
index 0000000000..3d5212386e
--- /dev/null
+++ b/testing_and_setup/compass/ocean/templates/analysis_members/ocean_heat_content.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+ single_file
+ oceanHeatContentOutput
+ 01-00-00_00:00:00
+ truncate
+ 00-00-05_00:00:00
+ analysis_members/oceanHeatContent.$Y-$M-$D_$h.$m.$s.nc
+ 0001-01-01_00:00:00
+ oceanHeatContentAMPKG
+ output
+
+
+
+
+
+
+
+
+
+