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

Last change on this file since 4003 was 3991, checked in by jbclement, 6 weeks ago

PEM:
Apply documentation template everywhere: standardized headers format with short description, separators between functions/subroutines, normalized code sections, aligned dependencies/arguments/variables declaration.
JBC

File size: 14.7 KB
RevLine 
[3989]1MODULE orbit
[3991]2!-----------------------------------------------------------------------
3! NAME
4!     orbit
5! DESCRIPTION
6!     Compute orbital-parameter-based stopping criteria and update
7!     planetary orbit parameters.
8! AUTHORS & DATE
9!     R. Vandemeulebrouck
10!     JB Clement, 2023-2025
11! NOTES
[2980]12!
[3991]13!-----------------------------------------------------------------------
[2980]14
[3991]15! DECLARATION
16! -----------
[3076]17implicit none
[2835]18
[3991]19! MODULE VARIABLES
20! ----------------
[3989]21real, dimension(:), allocatable :: year_lask  ! year before present from Laskar et al.
[3991]22real, dimension(:), allocatable :: obl_lask   ! obliquity [deg]
[3989]23real, dimension(:), allocatable :: ecc_lask   ! eccentricity
24real, dimension(:), allocatable :: lsp_lask   ! ls perihelie [deg]
25integer                         :: iyear_lask ! Index of the line in the file year_obl_lask.asc corresponding to the closest lower year to the current year
26
[3076]27contains
[3991]28!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
[3076]30!=======================================================================
[3989]31SUBROUTINE read_orbitpm(Year)
[3991]32!-----------------------------------------------------------------------
33! NAME
34!     read_orbitpm
35!
36! DESCRIPTION
37!     Read Laskar orbital file and prepare arrays; locate index for
38!     closest lower year relative to current simulation year.
39!
40! AUTHORS & DATE
41!     R. Vandemeulebrouck
42!     JB Clement, 2023-2025
43!
44! NOTES
45!     Converts kilo Earth years to Martian years using 'convert_years'.
46!-----------------------------------------------------------------------
[3039]47
[3991]48! DEPENDENCIES
49! ------------
[3989]50use evolution, only: convert_years
51
[3991]52! DECLARATION
53! -----------
[3989]54implicit none
55
[3991]56! ARGUMENTS
57! ---------
[3989]58real, intent(in) :: Year ! Martian year of the simulation
59
[3991]60! LOCAL VARIABLES
61! ---------------
62integer :: n ! Number of lines in Laskar files
[3989]63integer :: ierr, i
64
[3991]65! CODE
66! ----
[3989]67n = 0
68open(1,file = 'obl_ecc_lsp.asc',status = 'old',action = 'read')
69do
70    read(1,*,iostat = ierr)
71    if (ierr /= 0) exit
72    n = n + 1
73enddo
74close(1)
75allocate(year_lask(n),obl_lask(n),ecc_lask(n),lsp_lask(n))
76
77iyear_lask = 0
78do i = 1,size(year_lask,1)
79    read(1,*) year_lask(i), obl_lask(i), ecc_lask(i), lsp_lask(i)
80    year_lask(i) = year_lask(i)*1000./convert_years ! Conversion from Laskar's kilo Earth years to PEM Martian years
81    if (year_lask(i) > Year) iyear_lask = i + 1
82enddo
83close(1)
84if (iyear_lask == 0 .or. iyear_lask == size(year_lask,1) + 1) then
85    error stop 'The current year could not be found in the file "obl_ecc_lsp.asc".'
86else
87    write(*,*) 'The current year in the "obl_ecc_lsp.asc" file is at line:', iyear_lask
88endif
89
90END SUBROUTINE read_orbitpm
[3991]91!=======================================================================
[3989]92
93!=======================================================================
94SUBROUTINE end_orbit
[3991]95!-----------------------------------------------------------------------
96! NAME
97!     end_orbit
98!
99! DESCRIPTION
100!     Deallocate orbital data arrays.
101!
102! AUTHORS & DATE
103!     R. Vandemeulebrouck
104!     JB Clement, 2023-2025
105!
106! NOTES
107!
108!-----------------------------------------------------------------------
[3989]109
[3991]110! DECLARATION
111! -----------
[3989]112implicit none
113
[3991]114! CODE
115! ----
[3989]116if (allocated(year_lask)) deallocate(year_lask)
[3991]117if (allocated(obl_lask))  deallocate(obl_lask)
118if (allocated(ecc_lask))  deallocate(ecc_lask)
119if (allocated(lsp_lask))  deallocate(lsp_lask)
[3989]120
121END SUBROUTINE end_orbit
122!=======================================================================
123
[3991]124!=======================================================================
[3989]125SUBROUTINE orbit_param_criterion(i_myear,nyears_maxorb)
[3991]126!-----------------------------------------------------------------------
127! NAME
128!     orbit_param_criterion
129!
130! DESCRIPTION
131!     Determine maximum PEM iterations before orbital params change
132!     beyond admissible thresholds.
133!
134! AUTHORS & DATE
135!     R. Vandemeulebrouck
136!     JB Clement, 2023-2025
137!
138! NOTES
139!
140!-----------------------------------------------------------------------
[2982]141#ifdef CPP_IOIPSL
[3039]142    use IOIPSL,          only: getin
[2982]143#else
[3039]144    ! if not using IOIPSL, we still need to use (a local version of) getin
145    use ioipsl_getincom, only: getin
[2982]146#endif
[3961]147use planete_h,      only: e_elips, obliquit, lsperi
[3985]148use phys_constants, only: pi
[3989]149use evolution,      only: year_bp_ini, var_obl, var_ecc, var_lsp, convert_years
[2835]150
[3991]151! DECLARATION
152! -----------
[3076]153implicit none
[2835]154
[3991]155! ARGUMENTS
156! ---------
157real, intent(in)  :: i_myear       ! Martian year of the simulation
[3989]158real, intent(out) :: nyears_maxorb ! Maximum number of iteration of the PEM before orb changes too much
[2835]159
[3991]160! LOCAL VARIABLES
161! ---------------
[3791]162real                            :: Year                                           ! Year of the simulation
163real                            :: Lsp                                            ! Ls perihelion
164real                            :: max_change_obl, max_change_ecc, max_change_lsp ! Maximum admissible change
165real                            :: max_obl, max_ecc, max_lsp                      ! Maximum value of orbit param given the admissible change
166real                            :: min_obl, min_ecc, min_lsp                      ! Minimum value of orbit param given the admissible change
[3991]167real                            :: nyears_maxobl, nyears_maxecc, nyears_maxlsp    ! Maximum year iteration before reaching an inadmissible value of orbit param
168real                            :: xa, xb, ya, yb                  ! Variables for interpolation
169logical                         :: found_obl, found_ecc, found_lsp ! Flag variables for orbital parameters
170real                            :: lsp_corr                        ! Lsp corrected if the "modulo is crossed"
171real                            :: delta                           ! Intermediate variable
172real, dimension(:), allocatable :: lsplask_unwrap                  ! Unwrapped sequence of Lsp from Laskar's file
173integer                         :: i
[2835]174
[3991]175! CODE
176! ----
[3039]177! **********************************************************************
178! 0. Initializations
179! **********************************************************************
[3040]180Year = year_bp_ini + i_myear ! We compute the current year
181Lsp = lsperi*180./pi         ! We convert in degree
[2835]182
[3989]183call read_orbitpm(Year) ! Allocation of variables
[2835]184
[3039]185write(*,*) 'orbit_param_criterion, Current year =', Year
186write(*,*) 'orbit_param_criterion, Current obl. =', obliquit
187write(*,*) 'orbit_param_criterion, Current ecc. =', e_elips
188write(*,*) 'orbit_param_criterion, Current Lsp  =', Lsp
[2980]189
[3791]190! Unwrap the Lsp changes in Laskar's file
[3989]191allocate(lsplask_unwrap(iyear_lask))
192lsplask_unwrap(iyear_lask) = lsp_lask(iyear_lask)
193do i = iyear_lask,2,-1
194    delta = lsp_lask(i - 1) - lsp_lask(i)
[3791]195    if (delta > 180.) then
[3989]196        lsp_corr = lsp_lask(i - 1) - 360.
[3791]197    else if (delta < -180.) then
[3989]198        lsp_corr = lsp_lask(i - 1) + 360.
[3791]199    else
[3989]200        lsp_corr = lsp_lask(i - 1)
[3791]201    endif
[3989]202    lsplask_unwrap(i - 1) = lsplask_unwrap(i) + lsp_corr - lsp_lask(i)
[3791]203enddo
204
205! Correct the current Lsp according to the unwrapping
[3989]206delta = Lsp - lsplask_unwrap(iyear_lask)
[3791]207if (delta > 180.) then
208    Lsp = Lsp - 360.
209else if (delta < -180.) then
210    Lsp = Lsp + 360.
211endif
212
[3076]213! Constant max change case
[3791]214max_change_obl = 1.
215max_change_ecc = 5.e-3
216max_change_lsp = 20.
[2835]217
[3047]218call getin('max_change_obl',max_change_obl)
[3039]219max_obl = obliquit + max_change_obl
220min_obl = obliquit - max_change_obl
221write(*,*) 'Maximum obliquity accepted =', max_obl
222write(*,*) 'Minimum obliquity accepted =', min_obl
[2835]223
[3047]224call getin('max_change_ecc',max_change_ecc)
[3149]225max_ecc = min(e_elips + max_change_ecc,1. - 1.e-10) ! ecc < 1.
226min_ecc = max(e_elips - max_change_ecc,0.) ! ecc >= 0.
[3039]227write(*,*) 'Maximum eccentricity accepted =', max_ecc
228write(*,*) 'Minimum eccentricity accepted =', min_ecc
[2835]229
[3047]230call getin('max_change_lsp',max_change_lsp)
[3039]231max_lsp = Lsp + max_change_lsp
232min_lsp = Lsp - max_change_lsp
233write(*,*) 'Maximum Lsp accepted =', max_lsp
234write(*,*) 'Minimum Lsp accepted =', min_lsp
[3076]235! End Constant max change case
[2835]236
[2894]237! If we do not want some orb parameter to change, they should not be a stopping criterion,
238! So the number of iteration corresponding is set to maximum
[3989]239nyears_maxobl = 1000000.
240nyears_maxecc = 1000000.
241nyears_maxlsp = 1000000.
[2835]242
[3047]243! The maximum reachable year is found by interpolation according to the maximum admissible change of orbital parameters
244found_obl = .false.
245found_ecc = .false.
246found_lsp = .false.
247if (.not. var_obl) found_obl = .true.
248if (.not. var_ecc) found_ecc = .true.
249if (.not. var_lsp) found_lsp = .true.
250
[3989]251do i = iyear_lask,2,-1
252    xa = year_lask(i)
253    xb = year_lask(i - 1)
[3047]254
255    ! Obliquity
256    if (var_obl .and. .not. found_obl) then
[3989]257        ya = obl_lask(i)
258        yb = obl_lask(i - 1)
[3047]259        if (yb < min_obl) then ! The minimum accepted is overtaken
[3989]260            nyears_maxobl = (min_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]261            found_obl = .true.
262        else if (max_obl < yb) then ! The maximum accepted is overtaken
[3989]263            nyears_maxobl = (max_obl - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]264            found_obl = .true.
[3039]265        endif
[3047]266    endif
[2835]267
[3047]268    ! Eccentricity
269    if (var_ecc .and. .not. found_ecc) then
[3989]270        ya = ecc_lask(i)
271        yb = ecc_lask(i - 1)
[3047]272        if (yb < min_ecc) then ! The minimum accepted is overtaken
[3989]273            nyears_maxecc = (min_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]274            found_ecc = .true.
275        else if (max_ecc < yb) then ! The maximum accepted is overtaken
[3989]276            nyears_maxecc = (max_ecc - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]277            found_ecc = .true.
[3039]278        endif
[3047]279    endif
[2980]280
[3047]281    ! Lsp
282    if (var_lsp .and. .not. found_lsp) then
[3989]283        ya = lsplask_unwrap(i)
284        yb = lsplask_unwrap(i - 1)
[3047]285        if (yb < min_lsp) then ! The minimum accepted is overtaken
[3989]286            nyears_maxlsp = (min_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]287            found_lsp = .true.
288        else if (max_lsp < yb) then ! The maximum accepted is overtaken
[3989]289            nyears_maxlsp = (max_lsp - ya)*(xb - xa)/(yb - ya) + xa - Year
[3047]290            found_lsp = .true.
291        endif
[3039]292    endif
[3047]293
294    if (found_obl .and. found_ecc .and. found_lsp) exit ! The loop is left as soon as everything is found
[3039]295enddo
296
[3791]297deallocate(lsplask_unwrap)
298
[3050]299if (.not. found_obl) write(*,*) 'The maximum reachable year for obl. could not be found in the file "obl_ecc_lsp.asc".'
300if (.not. found_ecc) write(*,*) 'The maximum reachable year for ecc. could not be found in the file "obl_ecc_lsp.asc".'
301if (.not. found_lsp) write(*,*) 'The maximum reachable year for Lsp could not be found in the file "obl_ecc_lsp.asc".'
[3039]302
[3989]303write(*,*) 'Max. number of years for the obl. parameter =', nyears_maxobl
304write(*,*) 'Max. number of years for the ecc. parameter =', nyears_maxecc
305write(*,*) 'Max. number of years for the Lsp parameter  =', nyears_maxlsp
[2835]306
[3989]307nyears_maxorb = min(nyears_maxobl,nyears_maxecc,nyears_maxlsp)
308if (nyears_maxorb < 1.) nyears_maxorb = 1. ! nyears_maxorb should be at least equal to 1
309write(*,*) 'So the max. number of years for the orbital criteria =', nyears_maxorb
[2835]310
[3039]311END SUBROUTINE orbit_param_criterion
[3991]312!=======================================================================
[2835]313
[3991]314!=======================================================================
[3989]315SUBROUTINE set_new_orbitpm(i_myear,i_myear_leg)
[3991]316!-----------------------------------------------------------------------
317! NAME
318!     set_new_orbitpm
319!
320! DESCRIPTION
321!     Recompute orbit parameters from Laskar values at a new year and
322!     update planetary constants; handles Lsp modulo crossings.
323!
324! AUTHORS & DATE
325!     R. Vandemeulebrouck
326!     JB Clement, 2023-2025
327!
328! NOTES
329!
330!-----------------------------------------------------------------------
[2835]331
[3989]332use evolution,        only: year_bp_ini, var_obl, var_ecc, var_lsp
333use phys_constants,   only: pi
334use planete_h,        only: e_elips, obliquit, lsperi, periheli, aphelie, p_elips, peri_day, year_day
335use call_dayperi_mod, only: call_dayperi
[3039]336
[3991]337! DECLARATION
338! -----------
[3989]339implicit none
340
[3991]341! ARGUMENTS
342! ---------
[3989]343real, intent(in) :: i_myear     ! Number of simulated Martian years
344real, intent(in) :: i_myear_leg ! Number of iterations of the PEM
345
[3991]346! LOCAL VARIABLES
347! ---------------
[3989]348real    :: Year           ! Year of the simulation
349real    :: Lsp            ! Ls perihelion
350real    :: halfaxe        ! Million of km
[3991]351integer :: i
[3989]352real    :: unitastr
353real    :: xa, xb, ya, yb ! Variables for interpolation
354logical :: found_year     ! Flag variable
355
[3991]356! CODE
357! ----
[3989]358! **********************************************************************
359! 0. Initializations
360! **********************************************************************
361Year = year_bp_ini + i_myear ! We compute the current year
362Lsp = lsperi*180./pi         ! We convert in degree
363
364write(*,*) 'set_new_orbitpm, Old year =', Year - i_myear_leg
365write(*,*) 'set_new_orbitpm, Old obl. =', obliquit
366write(*,*) 'set_new_orbitpm, Old ecc. =', e_elips
367write(*,*) 'set_new_orbitpm, Old Lsp  =', Lsp
368write(*,*) 'set_new_orbitpm, New year =', Year
369
370found_year = .false.
371if (Year < 0.) then
372    do i = iyear_lask,2,-1
373        xa = year_lask(i)
374        xb = year_lask(i - 1)
375        if (xa <= Year .and. Year < xb) then
376            ! Obliquity
377            if (var_obl) then
378                ya = obl_lask(i)
379                yb = obl_lask(i - 1)
380                obliquit = (Year - xa)*(yb - ya)/(xb - xa) + ya
381            endif
382
383            ! Eccentricity
384            if (var_ecc) then
385                ya = ecc_lask(i)
386                yb = ecc_lask(i - 1)
387                e_elips = (Year - xa)*(yb - ya)/(xb - xa) + ya
388            endif
389
390            ! Lsp
391            if (var_lsp) then
392                ya = lsp_lask(i)
393                yb = lsp_lask(i - 1)
394                if (abs(yb - ya) > 300.) then ! If modulo is "crossed" through the interval
395                    if (ya < yb) then ! Lsp should be decreasing
396                        ya = ya + 360.
397                    else ! Lsp should be increasing
398                        yb = yb + 360.
399                    endif
400                endif
401                Lsp = modulo((Year - xa)*(yb - ya)/(xb - xa) + ya,360.)
402            endif
403            found_year = .true.
404            exit ! The loop is left as soon as the right interval is found
405        endif
406    enddo
407else if (Year >= 0 .and. Year < 100.) then ! For present orbital characteristics
408    if (var_obl) obliquit = 25.19
409    if (var_ecc) e_elips = 0.0934
410    if (var_lsp) Lsp = 251.
411    found_year = .true.
412endif
413
414if (.not. found_year) error stop 'The new year could not be found in the file "obl_ecc_lsp.asc".'
415
416write(*,*) 'set_new_orbitpm, New obl. =', obliquit
417write(*,*) 'set_new_orbitpm, New ecc. =', e_elips
418write(*,*) 'set_new_orbitpm, New Lsp  =', Lsp
419
420halfaxe = 227.94
421Lsp = Lsp*pi/180.
422periheli = halfaxe*(1 - e_elips)
423aphelie =  halfaxe*(1 + e_elips)
424unitastr = 149.597927
425p_elips = 0.5*(periheli + aphelie)*(1. - e_elips*e_elips)/unitastr
426
427call call_dayperi(Lsp,e_elips,peri_day,year_day)
428
429call end_orbit()
430
431END SUBROUTINE set_new_orbitpm
[3991]432!=======================================================================
[3989]433
434END MODULE orbit
435
Note: See TracBrowser for help on using the repository browser.