Ignore:
Timestamp:
Dec 11, 2025, 12:56:05 PM (5 weeks ago)
Author:
jbclement
Message:

PEM:
Massive structural refactor of the PEM codebase for improved readability, consistency and maintainability. The goal is to modernize, standardize and consolidate the code while removing legacy complexity. In detail, this change:

  • Performs large-scale cleanup removing unused code, obsolete routines, duplicated functionality and deprecated initialization logic;
  • Removes "*_mod" wrappers;
  • Replaces mixed naming conventions with clearer variable names, domain-based file/module names and purpose-based routine names;
  • Adds native reading/writing capabilities to the PEM removing the cumbersome dependency on Mars PCM subroutines;
  • Centralizes soil/ice/orbital/PEM configuration logic into dedicated modules;
  • Simplifies routines and updates calls/interfaces to match the new structure.

This refactor significantly clarifies the codebase and provides a cleaner foundation for forthcoming developments.
JBC

File:
1 moved

Legend:

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

    r3988 r3989  
    1 MODULE orbit_param_criterion_mod
     1MODULE orbit
    22
    33!=======================================================================
     
    1111implicit none
    1212
     13real, dimension(:), allocatable :: year_lask  ! year before present from Laskar et al.
     14real, dimension(:), allocatable :: obl_lask   ! obliquity    [deg]
     15real, dimension(:), allocatable :: ecc_lask   ! eccentricity
     16real, dimension(:), allocatable :: lsp_lask   ! ls perihelie [deg]
     17integer                         :: iyear_lask ! Index of the line in the file year_obl_lask.asc corresponding to the closest lower year to the current year
     18
    1319!=======================================================================
    1420contains
    1521!=======================================================================
    1622
    17 SUBROUTINE orbit_param_criterion(i_myear,n_myear_leg)
     23SUBROUTINE read_orbitpm(Year)
     24
     25use evolution, only: convert_years
     26
     27implicit none
     28
     29real, intent(in) :: Year ! Martian year of the simulation
     30
     31integer :: n ! number of lines in Laskar files
     32integer :: ierr, i
     33
     34n = 0
     35open(1,file = 'obl_ecc_lsp.asc',status = 'old',action = 'read')
     36do
     37    read(1,*,iostat = ierr)
     38    if (ierr /= 0) exit
     39    n = n + 1
     40enddo
     41close(1)
     42allocate(year_lask(n),obl_lask(n),ecc_lask(n),lsp_lask(n))
     43
     44iyear_lask = 0
     45do i = 1,size(year_lask,1)
     46    read(1,*) year_lask(i), obl_lask(i), ecc_lask(i), lsp_lask(i)
     47    year_lask(i) = year_lask(i)*1000./convert_years ! Conversion from Laskar's kilo Earth years to PEM Martian years
     48    if (year_lask(i) > Year) iyear_lask = i + 1
     49enddo
     50close(1)
     51if (iyear_lask == 0 .or. iyear_lask == size(year_lask,1) + 1) then
     52    error stop 'The current year could not be found in the file "obl_ecc_lsp.asc".'
     53else
     54    write(*,*) 'The current year in the "obl_ecc_lsp.asc" file is at line:', iyear_lask
     55endif
     56
     57END SUBROUTINE read_orbitpm
     58
     59!=======================================================================
     60
     61SUBROUTINE end_orbit
     62
     63implicit none
     64
     65if (allocated(year_lask)) deallocate(year_lask)
     66if (allocated(obl_lask)) deallocate(obl_lask)
     67if (allocated(ecc_lask)) deallocate(ecc_lask)
     68if (allocated(lsp_lask)) deallocate(lsp_lask)
     69
     70END SUBROUTINE end_orbit
     71!=======================================================================
     72
     73SUBROUTINE orbit_param_criterion(i_myear,nyears_maxorb)
    1874
    1975#ifdef CPP_IOIPSL
     
    2581use planete_h,      only: e_elips, obliquit, lsperi
    2682use phys_constants, only: pi
    27 use time_evol_mod,  only: year_bp_ini, var_obl, var_ecc, var_lsp, convert_years
    28 use lask_param_mod, only: yearlask, obllask, ecclask, lsplask, ini_lask_param_mod, last_ilask
     83use evolution,      only: year_bp_ini, var_obl, var_ecc, var_lsp, convert_years
    2984
    3085implicit none
     
    3893! Output Variables
    3994!--------------------------------------------------------
    40 real, intent(out) :: n_myear_leg ! Maximum number of iteration of the PEM before orb changes too much
     95real, intent(out) :: nyears_maxorb ! Maximum number of iteration of the PEM before orb changes too much
    4196
    4297!--------------------------------------------------------
     
    48103real                            :: max_obl, max_ecc, max_lsp                      ! Maximum value of orbit param given the admissible change
    49104real                            :: min_obl, min_ecc, min_lsp                      ! Minimum value of orbit param given the admissible change
    50 real                            :: max_obl_iter, max_ecc_iter, max_lsp_iter       ! Maximum year iteration before reaching an inadmissible value of orbit param
    51 integer                         :: ilask                                          ! Loop variable
     105real                            :: nyears_maxobl, nyears_maxecc, nyears_maxlsp       ! Maximum year iteration before reaching an inadmissible value of orbit param
     106integer                         :: i                                          ! Loop variable
    52107real                            :: xa, xb, ya, yb                                 ! Variables for interpolation
    53108logical                         :: found_obl, found_ecc, found_lsp                ! Flag variables for orbital parameters
     
    62117Lsp = lsperi*180./pi         ! We convert in degree
    63118
    64 call ini_lask_param_mod() ! Allocation of variables
     119call read_orbitpm(Year) ! Allocation of variables
    65120
    66121write(*,*) 'orbit_param_criterion, Current year =', Year
     
    69124write(*,*) 'orbit_param_criterion, Current Lsp  =', Lsp
    70125
    71 ! We read the file
    72 open(73,file = 'obl_ecc_lsp.asc',status = 'old',action = 'read')
    73 last_ilask = 0
    74 do ilask = 1,size(yearlask,1)
    75     read(73,*) yearlask(ilask), obllask(ilask), ecclask(ilask), lsplask(ilask)
    76     yearlask(ilask) = yearlask(ilask)*1000./convert_years ! Conversion from Laskar's kilo Earth years to PEM Martian years
    77     if (yearlask(ilask) > Year) last_ilask = ilask + 1
     126! Unwrap the Lsp changes in Laskar's file
     127allocate(lsplask_unwrap(iyear_lask))
     128lsplask_unwrap(iyear_lask) = lsp_lask(iyear_lask)
     129do i = iyear_lask,2,-1
     130    delta = lsp_lask(i - 1) - lsp_lask(i)
     131    if (delta > 180.) then
     132        lsp_corr = lsp_lask(i - 1) - 360.
     133    else if (delta < -180.) then
     134        lsp_corr = lsp_lask(i - 1) + 360.
     135    else
     136        lsp_corr = lsp_lask(i - 1)
     137    endif
     138    lsplask_unwrap(i - 1) = lsplask_unwrap(i) + lsp_corr - lsp_lask(i)
    78139enddo
    79 close(73)
    80 if (last_ilask == 0 .or. last_ilask == size(yearlask,1) + 1) then
    81     error stop 'The current year could not be found in the file "obl_ecc_lsp.asc".'
    82 else
    83     write(*,*) 'The current year in the "obl_ecc_lsp.asc" file is at line:', last_ilask
    84 endif
    85 
    86 ! Unwrap the Lsp changes in Laskar's file
    87 allocate(lsplask_unwrap(last_ilask))
    88 lsplask_unwrap(last_ilask) = lsplask(last_ilask)
    89 do ilask = last_ilask,2,-1
    90     delta = lsplask(ilask - 1) - lsplask(ilask)
    91     if (delta > 180.) then
    92         lsp_corr = lsplask(ilask - 1) - 360.
    93     else if (delta < -180.) then
    94         lsp_corr = lsplask(ilask - 1) + 360.
    95     else
    96         lsp_corr = lsplask(ilask - 1)
    97     endif
    98     lsplask_unwrap(ilask - 1) = lsplask_unwrap(ilask) + lsp_corr - lsplask(ilask)
    99 enddo
    100140
    101141! Correct the current Lsp according to the unwrapping
    102 delta = Lsp - lsplask_unwrap(last_ilask)
     142delta = Lsp - lsplask_unwrap(iyear_lask)
    103143if (delta > 180.) then
    104144    Lsp = Lsp - 360.
     
    133173! If we do not want some orb parameter to change, they should not be a stopping criterion,
    134174! So the number of iteration corresponding is set to maximum
    135 max_obl_iter = 1000000.
    136 max_ecc_iter = 1000000.
    137 max_lsp_iter = 1000000.
     175nyears_maxobl = 1000000.
     176nyears_maxecc = 1000000.
     177nyears_maxlsp = 1000000.
    138178
    139179! The maximum reachable year is found by interpolation according to the maximum admissible change of orbital parameters
     
    145185if (.not. var_lsp) found_lsp = .true.
    146186
    147 do ilask = last_ilask,2,-1
    148     xa = yearlask(ilask)
    149     xb = yearlask(ilask - 1)
     187do i = iyear_lask,2,-1
     188    xa = year_lask(i)
     189    xb = year_lask(i - 1)
    150190
    151191    ! Obliquity
    152192    if (var_obl .and. .not. found_obl) then
    153         ya = obllask(ilask)
    154         yb = obllask(ilask - 1)
     193        ya = obl_lask(i)
     194        yb = obl_lask(i - 1)
    155195        if (yb < min_obl) then ! The minimum accepted is overtaken
    156             max_obl_iter = (min_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
     196            nyears_maxobl = (min_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
    157197            found_obl = .true.
    158198        else if (max_obl < yb) then ! The maximum accepted is overtaken
    159             max_obl_iter = (max_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
     199            nyears_maxobl = (max_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
    160200            found_obl = .true.
    161201        endif
     
    164204    ! Eccentricity
    165205    if (var_ecc .and. .not. found_ecc) then
    166         ya = ecclask(ilask)
    167         yb = ecclask(ilask - 1)
     206        ya = ecc_lask(i)
     207        yb = ecc_lask(i - 1)
    168208        if (yb < min_ecc) then ! The minimum accepted is overtaken
    169             max_ecc_iter = (min_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
     209            nyears_maxecc = (min_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
    170210            found_ecc = .true.
    171211        else if (max_ecc < yb) then ! The maximum accepted is overtaken
    172             max_ecc_iter = (max_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
     212            nyears_maxecc = (max_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
    173213            found_ecc = .true.
    174214        endif
     
    177217    ! Lsp
    178218    if (var_lsp .and. .not. found_lsp) then
    179         ya = lsplask_unwrap(ilask)
    180         yb = lsplask_unwrap(ilask - 1)
     219        ya = lsplask_unwrap(i)
     220        yb = lsplask_unwrap(i - 1)
    181221        if (yb < min_lsp) then ! The minimum accepted is overtaken
    182             max_lsp_iter = (min_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
     222            nyears_maxlsp = (min_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
    183223            found_lsp = .true.
    184224        else if (max_lsp < yb) then ! The maximum accepted is overtaken
    185             max_lsp_iter = (max_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
     225            nyears_maxlsp = (max_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
    186226            found_lsp = .true.
    187227        endif
     
    197237if (.not. found_lsp) write(*,*) 'The maximum reachable year for Lsp could not be found in the file "obl_ecc_lsp.asc".'
    198238
    199 write(*,*) 'Max. number of iterations for the obl. parameter =', max_obl_iter
    200 write(*,*) 'Max. number of iterations for the ecc. parameter =', max_ecc_iter
    201 write(*,*) 'Max. number of iterations for the Lsp parameter  =', max_lsp_iter
    202 
    203 n_myear_leg = min(max_obl_iter,max_ecc_iter,max_lsp_iter)
    204 if (n_myear_leg < 1.) n_myear_leg = 1. ! n_myear_leg should be at least equal to 1
    205 write(*,*) 'So the max. number of iterations for the orbital criteria =', n_myear_leg
     239write(*,*) 'Max. number of years for the obl. parameter =', nyears_maxobl
     240write(*,*) 'Max. number of years for the ecc. parameter =', nyears_maxecc
     241write(*,*) 'Max. number of years for the Lsp parameter  =', nyears_maxlsp
     242
     243nyears_maxorb = min(nyears_maxobl,nyears_maxecc,nyears_maxlsp)
     244if (nyears_maxorb < 1.) nyears_maxorb = 1. ! nyears_maxorb should be at least equal to 1
     245write(*,*) 'So the max. number of years for the orbital criteria =', nyears_maxorb
    206246
    207247END SUBROUTINE orbit_param_criterion
    208248
    209249!***********************************************************************
    210 
    211 END MODULE orbit_param_criterion_mod
    212 
     250! Purpose: Recompute orbit parameters based on values by Laskar et al.
     251SUBROUTINE set_new_orbitpm(i_myear,i_myear_leg)
     252
     253use evolution,        only: year_bp_ini, var_obl, var_ecc, var_lsp
     254use phys_constants,   only: pi
     255use planete_h,        only: e_elips, obliquit, lsperi, periheli, aphelie, p_elips, peri_day, year_day
     256use call_dayperi_mod, only: call_dayperi
     257
     258implicit none
     259
     260!--------------------------------------------------------
     261! Input Variables
     262!--------------------------------------------------------
     263real, intent(in) :: i_myear     ! Number of simulated Martian years
     264real, intent(in) :: i_myear_leg ! Number of iterations of the PEM
     265
     266!--------------------------------------------------------
     267! Output Variables
     268!--------------------------------------------------------
     269
     270!--------------------------------------------------------
     271! Local variables
     272!--------------------------------------------------------
     273real    :: Year           ! Year of the simulation
     274real    :: Lsp            ! Ls perihelion
     275integer :: i          ! Loop variable
     276real    :: halfaxe        ! Million of km
     277real    :: unitastr
     278real    :: xa, xb, ya, yb ! Variables for interpolation
     279logical :: found_year     ! Flag variable
     280
     281! **********************************************************************
     282! 0. Initializations
     283! **********************************************************************
     284Year = year_bp_ini + i_myear ! We compute the current year
     285Lsp = lsperi*180./pi         ! We convert in degree
     286
     287write(*,*) 'set_new_orbitpm, Old year =', Year - i_myear_leg
     288write(*,*) 'set_new_orbitpm, Old obl. =', obliquit
     289write(*,*) 'set_new_orbitpm, Old ecc. =', e_elips
     290write(*,*) 'set_new_orbitpm, Old Lsp  =', Lsp
     291write(*,*) 'set_new_orbitpm, New year =', Year
     292
     293found_year = .false.
     294if (Year < 0.) then
     295    do i = iyear_lask,2,-1
     296        xa = year_lask(i)
     297        xb = year_lask(i - 1)
     298        if (xa <= Year .and. Year < xb) then
     299            ! Obliquity
     300            if (var_obl) then
     301                ya = obl_lask(i)
     302                yb = obl_lask(i - 1)
     303                obliquit = (Year - xa)*(yb - ya)/(xb - xa) + ya
     304            endif
     305
     306            ! Eccentricity
     307            if (var_ecc) then
     308                ya = ecc_lask(i)
     309                yb = ecc_lask(i - 1)
     310                e_elips = (Year - xa)*(yb - ya)/(xb - xa) + ya
     311            endif
     312
     313            ! Lsp
     314            if (var_lsp) then
     315                ya = lsp_lask(i)
     316                yb = lsp_lask(i - 1)
     317                if (abs(yb - ya) > 300.) then ! If modulo is "crossed" through the interval
     318                    if (ya < yb) then ! Lsp should be decreasing
     319                        ya = ya + 360.
     320                    else ! Lsp should be increasing
     321                        yb = yb + 360.
     322                    endif
     323                endif
     324                Lsp = modulo((Year - xa)*(yb - ya)/(xb - xa) + ya,360.)
     325            endif
     326            found_year = .true.
     327            exit ! The loop is left as soon as the right interval is found
     328        endif
     329    enddo
     330else if (Year >= 0 .and. Year < 100.) then ! For present orbital characteristics
     331    if (var_obl) obliquit = 25.19
     332    if (var_ecc) e_elips = 0.0934
     333    if (var_lsp) Lsp = 251.
     334    found_year = .true.
     335endif
     336
     337if (.not. found_year) error stop 'The new year could not be found in the file "obl_ecc_lsp.asc".'
     338
     339write(*,*) 'set_new_orbitpm, New obl. =', obliquit
     340write(*,*) 'set_new_orbitpm, New ecc. =', e_elips
     341write(*,*) 'set_new_orbitpm, New Lsp  =', Lsp
     342
     343halfaxe = 227.94
     344Lsp = Lsp*pi/180.
     345periheli = halfaxe*(1 - e_elips)
     346aphelie =  halfaxe*(1 + e_elips)
     347unitastr = 149.597927
     348p_elips = 0.5*(periheli + aphelie)*(1. - e_elips*e_elips)/unitastr
     349
     350call call_dayperi(Lsp,e_elips,peri_day,year_day)
     351
     352call end_orbit()
     353
     354END SUBROUTINE set_new_orbitpm
     355
     356END MODULE orbit
     357
Note: See TracChangeset for help on using the changeset viewer.