source: trunk/LMDZ.COMMON/libf/evolution/orbit.F90 @ 3989

Last change on this file since 3989 was 3989, checked in by jbclement, 5 weeks ago

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 size: 13.4 KB
RevLine 
[3989]1MODULE orbit
[2835]2
[2980]3!=======================================================================
4!
[3076]5! Purpose: Compute the maximum number of iteration for PEM based on the
[3022]6! stopping criterion given by the orbital parameters
[2980]7!
[3022]8! Author: RV, JBC
[2980]9!=======================================================================
10
[3076]11implicit none
[2835]12
[3989]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
[3076]19!=======================================================================
20contains
21!=======================================================================
[2835]22
[3989]23SUBROUTINE read_orbitpm(Year)
[3039]24
[3989]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)
74
[2982]75#ifdef CPP_IOIPSL
[3039]76    use IOIPSL,          only: getin
[2982]77#else
[3039]78    ! if not using IOIPSL, we still need to use (a local version of) getin
79    use ioipsl_getincom, only: getin
[2982]80#endif
[3961]81use planete_h,      only: e_elips, obliquit, lsperi
[3985]82use phys_constants, only: pi
[3989]83use evolution,      only: year_bp_ini, var_obl, var_ecc, var_lsp, convert_years
[2835]84
[3076]85implicit none
[2835]86
87!--------------------------------------------------------
88! Input Variables
89!--------------------------------------------------------
[3498]90real, intent(in) :: i_myear ! Martian year of the simulation
[2835]91
92!--------------------------------------------------------
93! Output Variables
94!--------------------------------------------------------
[3989]95real, intent(out) :: nyears_maxorb ! Maximum number of iteration of the PEM before orb changes too much
[2835]96
97!--------------------------------------------------------
[3076]98! Local variables
[2835]99!--------------------------------------------------------
[3791]100real                            :: Year                                           ! Year of the simulation
101real                            :: Lsp                                            ! Ls perihelion
102real                            :: max_change_obl, max_change_ecc, max_change_lsp ! Maximum admissible change
103real                            :: max_obl, max_ecc, max_lsp                      ! Maximum value of orbit param given the admissible change
104real                            :: min_obl, min_ecc, min_lsp                      ! Minimum value of orbit param given the admissible change
[3989]105real                            :: nyears_maxobl, nyears_maxecc, nyears_maxlsp       ! Maximum year iteration before reaching an inadmissible value of orbit param
106integer                         :: i                                          ! Loop variable
[3791]107real                            :: xa, xb, ya, yb                                 ! Variables for interpolation
108logical                         :: found_obl, found_ecc, found_lsp                ! Flag variables for orbital parameters
109real                            :: lsp_corr                                       ! Lsp corrected if the "modulo is crossed"
110real                            :: delta                                          ! Intermediate variable
111real, dimension(:), allocatable :: lsplask_unwrap                                 ! Unwrapped sequence of Lsp from Laskar's file
[2835]112
[3039]113! **********************************************************************
114! 0. Initializations
115! **********************************************************************
[3040]116Year = year_bp_ini + i_myear ! We compute the current year
117Lsp = lsperi*180./pi         ! We convert in degree
[2835]118
[3989]119call read_orbitpm(Year) ! Allocation of variables
[2835]120
[3039]121write(*,*) 'orbit_param_criterion, Current year =', Year
122write(*,*) 'orbit_param_criterion, Current obl. =', obliquit
123write(*,*) 'orbit_param_criterion, Current ecc. =', e_elips
124write(*,*) 'orbit_param_criterion, Current Lsp  =', Lsp
[2980]125
[3791]126! Unwrap the Lsp changes in Laskar's file
[3989]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)
[3791]131    if (delta > 180.) then
[3989]132        lsp_corr = lsp_lask(i - 1) - 360.
[3791]133    else if (delta < -180.) then
[3989]134        lsp_corr = lsp_lask(i - 1) + 360.
[3791]135    else
[3989]136        lsp_corr = lsp_lask(i - 1)
[3791]137    endif
[3989]138    lsplask_unwrap(i - 1) = lsplask_unwrap(i) + lsp_corr - lsp_lask(i)
[3791]139enddo
140
141! Correct the current Lsp according to the unwrapping
[3989]142delta = Lsp - lsplask_unwrap(iyear_lask)
[3791]143if (delta > 180.) then
144    Lsp = Lsp - 360.
145else if (delta < -180.) then
146    Lsp = Lsp + 360.
147endif
148
[3076]149! Constant max change case
[3791]150max_change_obl = 1.
151max_change_ecc = 5.e-3
152max_change_lsp = 20.
[2835]153
[3047]154call getin('max_change_obl',max_change_obl)
[3039]155max_obl = obliquit + max_change_obl
156min_obl = obliquit - max_change_obl
157write(*,*) 'Maximum obliquity accepted =', max_obl
158write(*,*) 'Minimum obliquity accepted =', min_obl
[2835]159
[3047]160call getin('max_change_ecc',max_change_ecc)
[3149]161max_ecc = min(e_elips + max_change_ecc,1. - 1.e-10) ! ecc < 1.
162min_ecc = max(e_elips - max_change_ecc,0.) ! ecc >= 0.
[3039]163write(*,*) 'Maximum eccentricity accepted =', max_ecc
164write(*,*) 'Minimum eccentricity accepted =', min_ecc
[2835]165
[3047]166call getin('max_change_lsp',max_change_lsp)
[3039]167max_lsp = Lsp + max_change_lsp
168min_lsp = Lsp - max_change_lsp
169write(*,*) 'Maximum Lsp accepted =', max_lsp
170write(*,*) 'Minimum Lsp accepted =', min_lsp
[3076]171! End Constant max change case
[2835]172
[2894]173! If we do not want some orb parameter to change, they should not be a stopping criterion,
174! So the number of iteration corresponding is set to maximum
[3989]175nyears_maxobl = 1000000.
176nyears_maxecc = 1000000.
177nyears_maxlsp = 1000000.
[2835]178
[3047]179! The maximum reachable year is found by interpolation according to the maximum admissible change of orbital parameters
180found_obl = .false.
181found_ecc = .false.
182found_lsp = .false.
183if (.not. var_obl) found_obl = .true.
184if (.not. var_ecc) found_ecc = .true.
185if (.not. var_lsp) found_lsp = .true.
186
[3989]187do i = iyear_lask,2,-1
188    xa = year_lask(i)
189    xb = year_lask(i - 1)
[3047]190
191    ! Obliquity
192    if (var_obl .and. .not. found_obl) then
[3989]193        ya = obl_lask(i)
194        yb = obl_lask(i - 1)
[3047]195        if (yb < min_obl) then ! The minimum accepted is overtaken
[3989]196            nyears_maxobl = (min_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]197            found_obl = .true.
198        else if (max_obl < yb) then ! The maximum accepted is overtaken
[3989]199            nyears_maxobl = (max_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]200            found_obl = .true.
[3039]201        endif
[3047]202    endif
[2835]203
[3047]204    ! Eccentricity
205    if (var_ecc .and. .not. found_ecc) then
[3989]206        ya = ecc_lask(i)
207        yb = ecc_lask(i - 1)
[3047]208        if (yb < min_ecc) then ! The minimum accepted is overtaken
[3989]209            nyears_maxecc = (min_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]210            found_ecc = .true.
211        else if (max_ecc < yb) then ! The maximum accepted is overtaken
[3989]212            nyears_maxecc = (max_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]213            found_ecc = .true.
[3039]214        endif
[3047]215    endif
[2980]216
[3047]217    ! Lsp
218    if (var_lsp .and. .not. found_lsp) then
[3989]219        ya = lsplask_unwrap(i)
220        yb = lsplask_unwrap(i - 1)
[3047]221        if (yb < min_lsp) then ! The minimum accepted is overtaken
[3989]222            nyears_maxlsp = (min_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]223            found_lsp = .true.
224        else if (max_lsp < yb) then ! The maximum accepted is overtaken
[3989]225            nyears_maxlsp = (max_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]226            found_lsp = .true.
227        endif
[3039]228    endif
[3047]229
230    if (found_obl .and. found_ecc .and. found_lsp) exit ! The loop is left as soon as everything is found
[3039]231enddo
232
[3791]233deallocate(lsplask_unwrap)
234
[3050]235if (.not. found_obl) write(*,*) 'The maximum reachable year for obl. could not be found in the file "obl_ecc_lsp.asc".'
236if (.not. found_ecc) write(*,*) 'The maximum reachable year for ecc. could not be found in the file "obl_ecc_lsp.asc".'
237if (.not. found_lsp) write(*,*) 'The maximum reachable year for Lsp could not be found in the file "obl_ecc_lsp.asc".'
[3039]238
[3989]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
[2835]242
[3989]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
[2835]246
[3039]247END SUBROUTINE orbit_param_criterion
[2835]248
[3076]249!***********************************************************************
[3989]250! Purpose: Recompute orbit parameters based on values by Laskar et al.
251SUBROUTINE set_new_orbitpm(i_myear,i_myear_leg)
[2835]252
[3989]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
[3039]257
[3989]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 TracBrowser for help on using the repository browser.