Ignore:
Timestamp:
Feb 12, 2026, 9:09:12 AM (2 weeks ago)
Author:
jbclement
Message:

PEM:
Major refactor following the previous ones (r3989 and r3991) completing the large structural reorganization and cleanup of the PEM codebase. This revision introduces newly designed modules, standardizes interfaces with explicit ini/end APIs and adds native NetCDF I/O together with explicit PCM/PEM adapters. In detail:

  • Some PEM models were corrected or improved:
    • Frost/perennial ice semantics are clarified via renaming;
    • Soil temperature remapping clarified, notably by removing the rescaling of temperature deviation;
    • Geothermal flux for the PCM is computed based on the PEM state;
  • New explicit PEM/PCM adapters ("set_*"/"build4PCM_*") to decouple PEM internal representation from PCM file layouts and reconstruct consistent fields returned to the PCM;
  • New explicit build/teardown routines that centralize allocation and initialization ordering, reducing accidental use of uninitialized data and making the model lifecycle explicit;
  • Add native read/write helpers for NetCDF that centralize all low-level NetCDF interactions with major improvements (and more simplicity) compared to legacy PEM/PCM I/O (see the modules "io_netcdf" and "output"). They support reading, creation and writing of "diagevol.nc" (renamed from "diagpem.nc") and start/restart files;
  • Provide well-focused modules ("numerics"/"maths"/"utility"/"display") to host commonly-used primitives:
    • "numerics" defines numerical types and constants for reproducibility, portability across compilers and future transitions (e.g. quadruple precision experiments);
    • "display" provides a single controlled interface for runtime messages, status output and diagnostics, avoiding direct 'print'/'write' to enable silent mode, log redirection, and MPI-safe output in the future.
    • "utility" (new module) hosts generic helpers used throughout the code (e.g. "int2str" or "real2str");
  • Add modules "clim_state_init"/"clim_state_rec" which provide robust read/write logic for "start/startfi/startpem", including 1D fallbacks, mesh conversions and dimension checks. NetCDF file creation is centralized and explicit. Restart files are now self-consistent and future-proof, requiring changes only to affected variables;
  • Add module "atmosphere" which computes pressure fields, reconstructs potential temperature and air mass. It also holds the whole logic to define sigma or hybrid coordinates for altitudes;
  • Add module "geometry" to centrilize dimensions logic and grid conversions routines (including 2 new ones "dyngrd2vect"/"vect2dyngrd");
  • Add module "slopes" to isolate slopes handling;
  • Add module "surface" to isolate surface management. Notably, albedo and emissivity are now fully reconstructed following the PCM settings;
  • Add module "allocation" to check the dimension initialization and centrilize allocation/deallocation;
  • Finalize module decomposition and renaming to consolidate domain-based modules, purpose-based routines and physics/process-based variables;
  • The main program now drives a clearer sequence of conceptual steps (initialization / reading / evolution / update / build / writing) and fails explicitly instead of silently defaulting;
  • Ice table logic is made restart-safe;
  • 'Open'/'read' intrinsic logic is made safe and automatic;
  • Improve discoverability and standardize the data handling (private vs protected vs public);
  • Apply consistent documentation/header style already introduced;
  • Update deftank scripts to reflect new names and launch wrappers;

This revision is a structural milestone aiming to be behavior-preserving where possible. It has been tested via compilation and short integration runs. However, due to extensive renames, moves, and API changes, full validation is still ongoing.
Note: the revision includes one (possibly two) easter egg hidden in the code for future archaeologists of the PEM. No physics were harmed.
JBC

File:
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/LMDZ.COMMON/libf/evolution/info.F90

    r4064 r4065  
    1 MODULE info_pem
     1MODULE info
    22!-----------------------------------------------------------------------
    33! NAME
    4 !     info_pem
     4!     info
    55!
    66! DESCRIPTION
    7 !     Handles counters for PCM/PEM coupled runs and simulation metadata.
     7!     Handles counters for PCM/PEM coupled runs and duration information
     8!     of the simulation metadata.
    89!
    910! AUTHORS & DATE
    10 !     R. Vandemeulebrouck
    1111!     JB Clement, 2023-2025
    1212!
     
    1515!-----------------------------------------------------------------------
    1616
     17! DEPENDENCIES
     18! ------------
     19use numerics, only: dp, di, k4
     20
    1721! DECLARATION
    1822! -----------
    1923implicit none
    2024
    21 ! MODULE VARIABLES
    22 ! ----------------
    23 integer :: iPCM, iPEM, nPCM, nPCM_ini ! Data about the chained simulation of PCM/PEM runs
     25! PARAMETERS
     26! ----------
     27character(14), parameter :: infofile_name = 'launchPEM.info'
     28
     29! VARIABLES
     30! ---------
     31integer(di) :: iPCM, iPEM, nPCM, nPCM_ini ! Data about the chained simulation of PCM/PEM runs
    2432
    2533contains
     
    2735
    2836!=======================================================================
    29 SUBROUTINE update_info(i_myear_leg,stopPEM,i_myear,nyears_tot)
     37SUBROUTINE read_info()
     38!-----------------------------------------------------------------------
     39! NAME
     40!    read_info
     41!
     42! DESCRIPTION
     43!    Read the file "launchPEM.info" to get the number of simulated
     44!    years.
     45!
     46! AUTHORS & DATE
     47!    JB Clement, 12/2025
     48!
     49! NOTES
     50!
     51!-----------------------------------------------------------------------
     52
     53! DEPENDENCIES
     54! ------------
     55use stoppage,  only: stop_clean
     56use evolution, only: n_yr_sim, nmax_yr_sim, set_r_plnt2earth_yr
     57use display,   only: print_msg
     58
     59! DECLARATION
     60! -----------
     61implicit none
     62
     63! LOCAL VARIABLES
     64! ---------------
     65logical(k4) :: here
     66real(dp)    :: tmp
     67integer(di) :: ierr, funit
     68
     69! CODE
     70! ----
     71inquire(file = infofile_name,exist = here)
     72if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//infofile_name//'"! It should be created by the launching script.',1)
     73call print_msg('> Reading "'//infofile_name//'"')
     74open(newunit = funit,file = infofile_name,status = 'old',form = 'formatted',action = 'read',iostat = ierr)
     75if (ierr /= 0) call stop_clean(__FILE__,__LINE__,'error opening file "'//infofile_name//'"!',ierr)
     76read(funit,*) n_yr_sim, nmax_yr_sim, tmp, iPCM, iPEM, nPCM, nPCM_ini
     77call set_r_plnt2earth_yr(tmp)
     78close(funit)
     79
     80END SUBROUTINE read_info
     81!=======================================================================
     82
     83!=======================================================================
     84SUBROUTINE update_info(n_yr_run,stopPEM,n_yr_sim,nmax_yr_sim)
    3085!-----------------------------------------------------------------------
    3186! NAME
     
    3489! DESCRIPTION
    3590!    Update the first line of "launchPEM.info" to count the number of
    36 !    simulated Martian years. Write in "launchPEM.info" the reason why
    37 !    the PEM stopped and the number of simulated years.
     91!    simulated years. Write in "launchPEM.info" the reason why the PEM
     92!    stopped and the number of simulated years.
    3893!
    3994! AUTHORS & DATE
     
    47102! DEPENDENCIES
    48103! ------------
    49 use evolution, only: convert_years, year_bp_ini
     104use evolution, only: r_plnt2earth_yr, pem_ini_date
     105use utility,   only: int2str, nb_digits
     106use stoppage,  only: stop_clean
     107use display,   only: print_msg
    50108
    51109! DECLARATION
     
    55113! ARGUMENTS
    56114! ---------
    57 integer, intent(in) :: stopPEM     ! Reason to stop
    58 real,    intent(in) :: i_myear_leg ! # of years
    59 real,    intent(in) :: i_myear     ! Current simulated Martian year
    60 real,    intent(in) :: nyears_tot  ! Maximum number of Martian years to be simulated
     115integer(di), intent(in) :: stopPEM    ! Reason to stop
     116real(dp),    intent(in) :: n_yr_run ! # of years
     117real(dp),    intent(in) :: n_yr_sim ! Current simulated year
     118real(dp),    intent(in) :: nmax_yr_sim ! Maximum number of years to be simulated
    61119
    62120! LOCAL VARIABLES
    63121! ---------------
    64 logical       :: ok
    65 integer       :: cstat
     122logical(k4)   :: here
     123integer(di)   :: cstat, ierr, funit
    66124character(20) :: fch1, fch2, fch3
    67125
    68126! CODE
    69127! ----
    70 inquire(file = 'launchPEM.info',exist = ok)
    71 if (ok) then
    72     write(fch1,'(f'//int2str(nb_digits(i_myear) + 5)//'.4)') i_myear
    73     write(fch2,'(f'//int2str(nb_digits(nyears_tot) + 5)//'.4)') nyears_tot
    74     write(fch3,'(f6.4)') convert_years ! 4 digits to the right of the decimal point to respect the precision of Martian year in "launch_pem.sh"
    75     call execute_command_line('sed -i "1s/.*/'//trim(fch1)//' '//trim(fch2)//' '//trim(fch3)//' '//int2str(iPCM)//' '//int2str(iPEM + 1)//' '//int2str(nPCM)//' '//int2str(nPCM_ini)//'/" launchPEM.info',cmdstat = cstat)
    76     if (cstat > 0) then
    77         error stop 'update_info: command execution failed!'
    78     else if (cstat < 0) then
    79         error stop 'update_info: command execution not supported!'
    80     endif
    81     open(1,file = 'launchPEM.info',status = "old",position = "append",action = "write")
    82     ! Martian date, Number of Martians years done by the PEM run, Number of Martians years done by the chainded simulation, Code of the stopping criterion
    83     ! The conversion ratio from Planetary years to Earth years is given in the header of the file
    84     write(1,'(f20.4,f20.4,f20.4,i20)') year_bp_ini + i_myear, i_myear_leg, i_myear, stopPEM
    85     close(1)
    86 else
    87     error stop 'The file ''launchPEM.info'' does not exist and cannot be updated!'
    88 endif
     128call print_msg('> Updating "'//infofile_name//'"')
     129inquire(file = infofile_name,exist = here)
     130if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//infofile_name//'"! It should be created by the launching script.',1)
     131
     132! Modify the header (first line)
     133write(fch1,'(f'//int2str(nb_digits(n_yr_sim) + 5)//'.4)') n_yr_sim
     134write(fch2,'(f'//int2str(nb_digits(nmax_yr_sim) + 5)//'.4)') nmax_yr_sim
     135write(fch3,'(f6.4)') r_plnt2earth_yr ! 4 digits to the right of the decimal point to respect the precision of year in "launch_pem.sh"
     136call execute_command_line('sed -i "1s/.*/'//trim(fch1)//' '//trim(fch2)//' '//trim(fch3)//' '//int2str(iPCM)//' '//int2str(iPEM + 1)//' '//int2str(nPCM)//' '//int2str(nPCM_ini)//'/" launchPEM.info',cmdstat = cstat)
     137if (cstat > 0) then
     138    call stop_clean(__FILE__,__LINE__,'command execution failed!',1)
     139else if (cstat < 0) then
     140    call stop_clean(__FILE__,__LINE__,'command execution not supported!',1)
     141end if
     142
     143! Add the information of current PEM run at the end of file
     144open(newunit = funit,file = infofile_name,status = "old",position = "append",action = "write",iostat = ierr)
     145if (ierr /= 0) call stop_clean(__FILE__,__LINE__,'error opening file "'//infofile_name//'"!',ierr)
     146! Date, Number of years done by the PEM run, Number of years done by the chainded simulation, Code of the stopping criterion
     147write(funit,'(f20.4,f20.4,f20.4,i20)') pem_ini_date + n_yr_sim, n_yr_run, n_yr_sim, stopPEM
     148close(funit)
    89149
    90150END SUBROUTINE update_info
    91151!=======================================================================
    92152
    93 !=======================================================================
    94 FUNCTION int2str(i) RESULT(str)
    95 !-----------------------------------------------------------------------
    96 ! NAME
    97 !     int2str
    98 !
    99 ! DESCRIPTION
    100 !     Convert an integer into a string.
    101 !
    102 ! AUTHORS & DATE
    103 !     JB Clement, 2023-2025
    104 !
    105 ! NOTES
    106 !
    107 !-----------------------------------------------------------------------
    108 
    109 ! DECLARATION
    110 ! -----------
    111 implicit none
    112 
    113 ! ARGUMENTS
    114 ! ---------
    115 integer, intent(in) :: i
    116 
    117 ! LOCAL VARIABLES
    118 ! ---------------
    119 character(20)             :: str_tmp
    120 character(:), allocatable :: str
    121 
    122 ! CODE
    123 ! ----
    124 if (nb_digits(real(i)) > len(str_tmp)) error stop 'int2str [info_pem]: invalid integer for conversion!'
    125 write(str_tmp,'(i0)') i
    126 str = trim(adjustl(str_tmp))
    127 
    128 END FUNCTION int2str
    129 !=======================================================================
    130 
    131 !=======================================================================
    132 FUNCTION nb_digits(x) RESULT(idigits)
    133 !-----------------------------------------------------------------------
    134 ! NAME
    135 !     nb_digits
    136 !
    137 ! DESCRIPTION
    138 !     Give the number of digits for the integer part of a real number.
    139 !
    140 ! AUTHORS & DATE
    141 !     JB Clement, 2023-2025
    142 !
    143 ! NOTES
    144 !
    145 !-----------------------------------------------------------------------
    146 
    147 ! DECLARATION
    148 ! -----------
    149 implicit none
    150 
    151 ! ARGUMENTS
    152 ! ---------
    153 real, intent(in) :: x
    154 
    155 ! LOCAL VARIABLES
    156 ! ---------------
    157 integer :: idigits
    158 
    159 ! CODE
    160 ! ----
    161 idigits = 1
    162 ! If x /= 0 then:
    163 if (abs(x) > 1.e-10) idigits = int(log10(abs(x))) + 1
    164 
    165 END FUNCTION nb_digits
    166 !=======================================================================
    167 
    168 END MODULE info_pem
     153END MODULE info
Note: See TracChangeset for help on using the changeset viewer.