Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)

project(crtm VERSION 3.1.5 LANGUAGES Fortran)
project(crtm VERSION 3.1.6 LANGUAGES Fortran)

option(OPENMP "Build crtm with OpenMP support" ON)
option(FIX_FILE_PATH "Path to fix files (default: fix/)" OFF)
Expand Down
6 changes: 3 additions & 3 deletions Get_CRTM_Binary_Files.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#https://bin.ssec.wisc.edu/pub/s4/CRTM/fix_REL-3.1.2.0.tgz (use this for jedi and stand-alone, some files have changed).
#https://bin.ssec.wisc.edu/pub/s4/CRTM/fix_REL-3.1.6.0.tgz (use this for jedi and stand-alone, some files have changed).

# This script is used to manually download the tarball of binary and netcdf coefficient files.
# The same files also download automatically during the cmake step, so you don't have to actually run this manually.

foldername="fix_REL-3.1.2.0"
checksum=0e5888cae80aa674b2e67ecd4490317d
foldername="fix_REL-3.1.6.0"
checksum=ecfba7bb866f2a34b6281ae03740b161
filename="${foldername}.tgz"
download_url=https://bin.ssec.wisc.edu/pub/s4/CRTM/$filename

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
CRTM REL-3.1.5
CRTM REL-3.1.6
====================

[![Build Status](https://app.travis-ci.com/JCSDA/CRTMv3.svg?branch=develop)](https://app.travis-ci.com/JCSDA/CRTMv3)

Preamble
--------

CRTM v3.1.5 release (`REL-3.1.5`)
CRTM v3.1.6 release (`REL-3.1.6`)

v3.1.5 (in development): loads netCDF NLTECoeff/ACCoeff sibling files (previously silently skipped)
v3.1.6 released October 2, 2026: removes the per-call zero-fill of the RTV work arrays in RTV_Create that dominated the cost of CRTM calls with clouds, aerosols or visible sensors (#370); CRTM_AOD_TL/AD/K now honor Options%Skip_Profile (#372); calls that pass more than one sensor now return correct results; new coefficient set fix_REL-3.1.6.0 (47 new sensors and the 3.1.x-compatible updates from the v3.2.0 coefficients)
v3.1.5 released August 23, 2026: loads netCDF NLTECoeff/ACCoeff sibling files (previously silently skipped)
v3.1.4 released June 8, 2026
v3.1.3 released February 10, 2025
v3.1.2 released July 11, 2025
Expand Down Expand Up @@ -60,7 +61,7 @@ Contents

Configuration, building, and testing the library
================================================
JCSDA CRTM v3.1.5 Build Instructions
JCSDA CRTM v3.1.6 Build Instructions

The CRTM repository directory structure looks (something) like:

Expand Down Expand Up @@ -119,7 +120,7 @@ But after a clean clone of the development repository, none of the links to sour
Configuration
-------------
By default, the `fix/` directory is provided through ftp using the Get_CRTM_Binary_Files.sh script to obtain and unpack the dataset.
If this directory doesn't exist during the `cmake` step, then cmake will download and install into `./test-data-release/fix_REL-3.1.2.x/fix/`. (no longer in build directory, but off of source dir).
If this directory doesn't exist during the `cmake` step, then cmake will download and install into `./test-data-release/fix_REL-3.1.6.0/fix/`. (no longer in build directory, but off of source dir).
The path to an existing fix file installation can be specified using the `FIX_FILE_PATH` option (see CMake variables summary below).

The fix/ directory (as of v3.1.x) contains most of the netCDF SpcCoeff and TauCoeff files, as part of our ongoing effort to transition toward netCDF-only CRTM. We expect to deprecate the binary formats in v3.2.x, but code to read / convert binary format will continue.
Expand Down
2 changes: 1 addition & 1 deletion VERSION.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# 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.

set( ${PROJECT_NAME}_VERSION_STR "3.1.5")
set( ${PROJECT_NAME}_VERSION_STR "3.1.6")

9 changes: 9 additions & 0 deletions src/AtmScatter/CRTM_AOD_Module.f90
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,9 @@ FUNCTION CRTM_AOD_TL( &
Check_Input = .TRUE.
IF (Options_Present) THEN
Check_Input = Options(m)%Check_Input

! Check whether to skip this profile
IF ( Options(m)%Skip_Profile ) CYCLE Profile_Loop
END IF


Expand Down Expand Up @@ -887,6 +890,9 @@ FUNCTION CRTM_AOD_AD( &
Check_Input = .TRUE.
IF (Options_Present) THEN
Check_Input = Options(m)%Check_Input

! Check whether to skip this profile
IF ( Options(m)%Skip_Profile ) CYCLE Profile_Loop
END IF


Expand Down Expand Up @@ -1239,6 +1245,9 @@ FUNCTION CRTM_AOD_K ( &
Check_Input = .TRUE.
IF (Options_Present) THEN
Check_Input = Options(m)%Check_Input

! Check whether to skip this profile
IF ( Options(m)%Skip_Profile ) CYCLE Profile_Loop
END IF


Expand Down
5 changes: 4 additions & 1 deletion src/CRTM_Adjoint_Module.f90
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,10 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
AtmOptics%Include_Scattering ) THEN
! Assign algorithm selector
RTV%RT_Algorithm_Id = Opt%RT_Algorithm_Id
CALL RTV_Create( RTV, MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )
! RTV is per-profile; for the 2nd+ sensor of a multi-sensor call it
! is already allocated (same dims) and re-ALLOCATE would fail.
IF ( .NOT. RTV_Associated(RTV) ) &
CALL RTV_Create( RTV, MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )
IF ( .NOT. RTV_Associated(RTV) ) THEN
Error_Status=FAILURE
WRITE( Message,'("Error allocating RTV structure for profile #",i0, &
Expand Down
21 changes: 16 additions & 5 deletions src/CRTM_Forward_Module.f90
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
INTEGER :: SensorIndex
INTEGER :: ChannelIndex
INTEGER :: ln, nc, ks
INTEGER :: ln_base
INTEGER :: n_Full_Streams, mth_Azi
INTEGER :: cloud_coverage_flag
REAL(fp) :: Source_ZA
Expand Down Expand Up @@ -819,7 +820,10 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
SpcCoeff_IsUltravioletSensor(SC(SensorIndex)) .OR. &
SpcCoeff_IsVisibleSensor(SC(SensorIndex)) ) .AND. &
AtmOptics(nt)%Include_Scattering ) THEN
CALL RTV_Create( RTV(nt), MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )
! RTV is per-profile; for the 2nd+ sensor of a multi-sensor call it
! is already allocated (same dims) and re-ALLOCATE would fail.
IF ( .NOT. RTV_Associated(RTV(nt)) ) &
CALL RTV_Create( RTV(nt), MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )

IF ( .NOT. RTV_Associated(RTV(nt)) ) THEN
Error_Status=FAILURE
Expand Down Expand Up @@ -868,9 +872,12 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
! ------------
! THREAD LOOP
! ------------
! ln_base is the read-only per-sensor base; every Thread_Loop iteration
! rebuilds ln from it, and the post-loop advance derives from it too.
ln_base = ln
!$OMP PARALLEL DO NUM_THREADS(n_channel_threads) &
!$OMP FIRSTPRIVATE(ln) &
!$OMP PRIVATE(Message, ChannelIndex, n_Full_Streams, AAvar, &
!$OMP FIRSTPRIVATE(ln_base) &
!$OMP PRIVATE(Message, ChannelIndex, n_Full_Streams, AAvar, ln, &
!$OMP start_ch, end_ch, Wavenumber, transmittance, &
!$OMP transmittance_clear, l, mth_Azi, ks)
Thread_Loop: DO nt = 1, n_channel_threads
Expand All @@ -881,7 +888,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
ELSE
end_ch = start_ch + chunk_ch - 1
END IF
ln = (start_ch - 1) - n_inactive_channels(nt)
! Rebuild ln from the per-sensor base every iteration, offset by this
! chunk. Never accumulate onto the previous iteration's ln.
ln = ln_base + (start_ch - 1) - n_inactive_channels(nt)
! -------------
! CHANNEL LOOP
! -------------
Expand Down Expand Up @@ -1193,7 +1202,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )

IF ( Error_Status == FAILURE ) RETURN

ln = ln + n_sensor_channels - n_inactive_channels(n_channel_threads + 1)
! Advance from ln_base, not the loop-exit ln: on a serial channel loop
! Thread_Loop mutates the outer ln and accumulating here would double-count.
ln = ln_base + n_sensor_channels - n_inactive_channels(n_channel_threads + 1)

END DO Sensor_Loop

Expand Down
21 changes: 16 additions & 5 deletions src/CRTM_K_Matrix_Module.f90
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
INTEGER :: SensorIndex
INTEGER :: ChannelIndex
INTEGER :: ln
INTEGER :: ln_base
INTEGER :: n_Full_Streams, mth_Azi
INTEGER :: cloud_coverage_flag
REAL(fp) :: Source_ZA
Expand Down Expand Up @@ -934,7 +935,10 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
SpcCoeff_IsVisibleSensor(SC(SensorIndex)).OR.SpcCoeff_IsUltravioletSensor(SC(SensorIndex)) ) .AND. &
AtmOptics(nt)%Include_Scattering ) THEN
RTV(nt)%RT_Algorithm_Id = Opt%RT_Algorithm_Id
CALL RTV_Create( RTV(nt), MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )
! RTV is per-profile; for the 2nd+ sensor of a multi-sensor call it
! is already allocated (same dims) and re-ALLOCATE would fail.
IF ( .NOT. RTV_Associated(RTV(nt)) ) &
CALL RTV_Create( RTV(nt), MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )
IF ( .NOT. RTV_Associated(RTV(nt)) ) THEN
Error_Status=FAILURE
WRITE( Message,'("Error allocating RTV structure for profile #",i0, &
Expand Down Expand Up @@ -988,6 +992,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
! ------------
!** BTJ preprocessor directive bypass of OMP directives causing issues when compiling with modern ifort/ifx
!** https://github.com/JCSDA/CRTMv3/issues/231
! ln_base is the read-only per-sensor base; every Thread_Loop iteration
! rebuilds ln from it, and the post-loop advance derives from it too.
ln_base = ln
#if 1
IF (n_channel_threads > 1) THEN
WRITE( Message,'("ERROR: n_channel_threads > 1, this should not happen with the current preprocessor directives")')
Expand All @@ -997,8 +1004,8 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
END IF
#else
!$OMP PARALLEL DO NUM_THREADS(n_channel_threads) &
!$OMP FIRSTPRIVATE(ln, r_cloudy) &
!$OMP PRIVATE(Message, ChannelIndex, n_Full_Streams, AAvar, &
!$OMP FIRSTPRIVATE(ln_base, r_cloudy) &
!$OMP PRIVATE(Message, ChannelIndex, n_Full_Streams, AAvar, ln, &
!$OMP start_ch, end_ch, Wavenumber, Status_FWD, Status_K, &
!$OMP transmittance, transmittance_K, transmittance_clear, &
!$OMP transmittance_clear_K, l, mth_Azi, ks)
Expand All @@ -1011,7 +1018,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
ELSE
end_ch = start_ch + chunk_ch - 1
END IF
ln = (start_ch - 1) - n_inactive_channels(nt)
! Rebuild ln from the per-sensor base every iteration, offset by this
! chunk. Never accumulate onto the previous iteration's ln.
ln = ln_base + (start_ch - 1) - n_inactive_channels(nt)

! -------------
! CHANNEL LOOP
Expand Down Expand Up @@ -1677,7 +1686,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
#endif

IF ( Error_Status == FAILURE ) RETURN
ln = ln + n_sensor_channels - n_inactive_channels(n_channel_threads + 1)
! Advance from ln_base, not the loop-exit ln: on a serial channel loop
! Thread_Loop mutates the outer ln and accumulating here would double-count.
ln = ln_base + n_sensor_channels - n_inactive_channels(n_channel_threads + 1)

END DO Sensor_Loop

Expand Down
21 changes: 16 additions & 5 deletions src/CRTM_Tangent_Linear_Module.f90
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
INTEGER :: SensorIndex
INTEGER :: ChannelIndex
INTEGER :: ln, nc, ks
INTEGER :: ln_base
INTEGER :: n_Full_Streams, mth_Azi
INTEGER :: cloud_coverage_flag
REAL(fp) :: Source_ZA, r_cloudy
Expand Down Expand Up @@ -887,7 +888,10 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
AtmOptics(nt)%Include_Scattering ) THEN
! Assign algorithm selector
RTV(nt)%RT_Algorithm_Id = Opt%RT_Algorithm_Id
CALL RTV_Create( RTV(nt), MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )
! RTV is per-profile; for the 2nd+ sensor of a multi-sensor call it
! is already allocated (same dims) and re-ALLOCATE would fail.
IF ( .NOT. RTV_Associated(RTV(nt)) ) &
CALL RTV_Create( RTV(nt), MAX_N_ANGLES, MAX_N_LEGENDRE_TERMS, Atm%n_Layers )

IF ( .NOT. RTV_Associated(RTV(nt)) ) THEN
Error_Status=FAILURE
Expand Down Expand Up @@ -942,9 +946,12 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
! ------------
! THREAD LOOP
! ------------
! ln_base is the read-only per-sensor base; every Thread_Loop iteration
! rebuilds ln from it, and the post-loop advance derives from it too.
ln_base = ln
!$OMP PARALLEL DO NUM_THREADS(n_channel_threads) &
!$OMP FIRSTPRIVATE(ln, r_cloudy) &
!$OMP PRIVATE(Message, ChannelIndex, n_Full_Streams, AAvar, &
!$OMP FIRSTPRIVATE(ln_base, r_cloudy) &
!$OMP PRIVATE(Message, ChannelIndex, n_Full_Streams, AAvar, ln, &
!$OMP start_ch, end_ch, Wavenumber, transmittance, transmittance_TL, &
!$OMP transmittance_clear, transmittance_clear_TL, l, mth_Azi, ks, Status_FWD,Status_TL)
Thread_Loop: DO nt = 1, n_channel_threads
Expand All @@ -955,7 +962,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )
ELSE
end_ch = start_ch + chunk_ch - 1
END IF
ln = (start_ch - 1) - n_inactive_channels(nt)
! Rebuild ln from the per-sensor base every iteration, offset by this
! chunk. Never accumulate onto the previous iteration's ln.
ln = ln_base + (start_ch - 1) - n_inactive_channels(nt)

! -------------
! CHANNEL LOOP
Expand Down Expand Up @@ -1372,7 +1381,9 @@ FUNCTION profile_solution (m, Opt, AncillaryInput) RESULT( Error_Status )

IF ( Error_Status == FAILURE ) RETURN

ln = ln + n_sensor_channels - n_inactive_channels(n_channel_threads + 1)
! Advance from ln_base, not the loop-exit ln: on a serial channel loop
! Thread_Loop mutates the outer ln and accumulating here would double-count.
ln = ln_base + n_sensor_channels - n_inactive_channels(n_channel_threads + 1)

END DO Sensor_Loop

Expand Down
2 changes: 1 addition & 1 deletion src/CRTM_Version.inc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define CRTM_VERSION 'v3.1.2'
#define CRTM_VERSION 'v3.1.6'
Loading
Loading