Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/soca/LinearVariableChange/Balance/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ soca_target_sources(
soca_balance.interface.F90
soca_ksshts_mod.F90
soca_kst_mod.F90
soca_write_jacobian_mod.F90
)
15 changes: 15 additions & 0 deletions src/soca/LinearVariableChange/Balance/soca_balance_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module soca_balance_mod
use soca_ksshts_mod, only: soca_ksshts, soca_steric_jacobian
use soca_kst_mod, only: soca_kst, soca_soft_jacobian
use soca_state_mod, only: soca_state
use soca_write_jacobian_mod, only: write_jacobian_to_netcdf

implicit none
private
Expand Down Expand Up @@ -96,6 +97,7 @@ subroutine soca_balance_setup(self, f_conf, traj, geom)

! declarations related to the dynamic height Jacobians
character(len=:), allocatable :: filename
character(len=:), allocatable :: str
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'str' is declared but never deallocated. Since it's an allocatable character string that gets assigned values from f_conf%get_or_die, it should be deallocated after use to prevent memory leaks, or the allocation should be handled more carefully within the scope where it's used.

Copilot uses AI. Check for mistakes.

! declarations related to the sea-ice Jacobian
character(len=:), allocatable :: kct_name
Expand Down Expand Up @@ -165,6 +167,12 @@ subroutine soca_balance_setup(self, f_conf, traj, geom)
end do
end do
deallocate(jac)

! optionally write out Kst Jacobian
if ( f_conf%has("kst.jacobian_output")) then
call f_conf%get_or_die("kst.jacobian_output.filename", str)
call write_jacobian_to_netcdf(self%kst%jacobian, geom, str, "kst_jacobian")
end if
end if

! Get configuration for Ksshts
Expand Down Expand Up @@ -193,6 +201,13 @@ subroutine soca_balance_setup(self, f_conf, traj, geom)
end do
deallocate(jac)

! optionally write out Ksshts Jacobian
if ( f_conf%has("ksshts.jacobian_output")) then
call f_conf%get_or_die("ksshts.jacobian_output.filename", str)
call write_jacobian_to_netcdf(self%ksshts%kssht, geom, str, "kssht_jacobian")
call write_jacobian_to_netcdf(self%ksshts%ksshs, geom, str, "ksshs_jacobian")
Comment on lines +207 to +208
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writing both kssht_jacobian and ksshs_jacobian to the same file by calling write_jacobian_to_netcdf twice with the same filename will likely result in the second call overwriting the first, or potentially causing errors. The FMS write_data function may not support appending multiple variables to the same file in this manner. Consider either using different filenames for each Jacobian or implementing a mechanism to write both variables in a single call.

Suggested change
call write_jacobian_to_netcdf(self%ksshts%kssht, geom, str, "kssht_jacobian")
call write_jacobian_to_netcdf(self%ksshts%ksshs, geom, str, "ksshs_jacobian")
filename = str
call write_jacobian_to_netcdf(self%ksshts%kssht, geom, filename, "kssht_jacobian")
filename = trim(str)//"_ksshs"
call write_jacobian_to_netcdf(self%ksshts%ksshs, geom, filename, "ksshs_jacobian")

Copilot uses AI. Check for mistakes.
end if

! Compute Kct
if (traj%has("sea_ice_area_fraction")) then
! Setup dc/dT
Expand Down
35 changes: 35 additions & 0 deletions src/soca/LinearVariableChange/Balance/soca_write_jacobian_mod.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
! (C) Copyright 2017-2025 UCAR
!
! This software is licensed under the terms of the Apache Licence Version 2.0
! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.

module soca_write_jacobian_mod

use kinds, only: kind_real
use soca_geom_mod, only: soca_geom
use fms_mod, only: write_data, set_domain
use fms_io_mod, only: fms_io_init, fms_io_exit

implicit none
private
public :: write_jacobian_to_netcdf

contains

subroutine write_jacobian_to_netcdf(jacobian, geom, filename, varname)
real(kind=kind_real), intent(in) :: jacobian(:,:,:)
type(soca_geom), intent(in) :: geom
character(len=*), intent(in) :: filename
character(len=*), intent(in) :: varname


call fms_io_init()
call set_domain(geom%Domain%mpp_domain)

! Write the jacobian data from all PEs
call write_data(filename, varname, jacobian, geom%Domain%mpp_domain)

call fms_io_exit()
Comment on lines +26 to +32
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling fms_io_init and fms_io_exit on every invocation can be problematic. In soca_geom_mod, fms_io_init is guarded by a counter check to ensure it's only called once per geometry initialization. Repeatedly initializing and finalizing the FMS I/O subsystem for each Jacobian write could lead to resource management issues or conflicts, especially if multiple Jacobians are written in sequence. Consider checking if FMS I/O is already initialized or coordinating with the existing initialization in soca_geom_mod.

Copilot uses AI. Check for mistakes.
end subroutine write_jacobian_to_netcdf

end module soca_write_jacobian_mod