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 @@ +