| 1 | MODULE orbit |
|---|
| 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 |
|---|
| 12 | ! |
|---|
| 13 | !----------------------------------------------------------------------- |
|---|
| 14 | |
|---|
| 15 | ! DEPENDENCIES |
|---|
| 16 | ! ------------ |
|---|
| 17 | use numerics, only: dp, di, k4, largest_nb, minieps |
|---|
| 18 | |
|---|
| 19 | ! DECLARATION |
|---|
| 20 | ! ----------- |
|---|
| 21 | implicit none |
|---|
| 22 | |
|---|
| 23 | ! PARAMETERS |
|---|
| 24 | ! ---------- |
|---|
| 25 | ! File-related: |
|---|
| 26 | character(15), parameter :: orbitfile_name = 'obl_ecc_lsp.asc' |
|---|
| 27 | integer(di), protected :: iyear_lask! Index of the line in the file year_obl_lask.asc corresponding to the closest lower year to the current year |
|---|
| 28 | real(dp), dimension(:), allocatable, protected :: year_lask ! Current_year before present from Laskar et al. |
|---|
| 29 | real(dp), dimension(:), allocatable, protected :: obl_lask ! Obliquity in Laskar's data [deg] |
|---|
| 30 | real(dp), dimension(:), allocatable, protected :: ecc_lask ! Eccentricity in Laskar's data |
|---|
| 31 | real(dp), dimension(:), allocatable, protected :: lsp_lask ! Ls perihelie in Laskar's data [deg] |
|---|
| 32 | ! Planet-related: |
|---|
| 33 | real(dp), protected :: obliquity ! Planet obliquity [deg] |
|---|
| 34 | real(dp), protected :: eccentricity ! Orbit eccentricity |
|---|
| 35 | real(dp), protected :: ls_peri ! Solar longitude of the perihelion [deg] |
|---|
| 36 | real(dp), protected :: perihelion ! Perihelion [Mkm] |
|---|
| 37 | real(dp), protected :: semimaj_axis ! Semi-major axis [Mkm] |
|---|
| 38 | real(dp), protected :: aphelion ! Aphelion [Mkm] |
|---|
| 39 | real(dp), protected :: date_peri ! Date of perihelion [sol] |
|---|
| 40 | real(dp), protected :: sol_len_s ! Length of a sol [s] |
|---|
| 41 | real(dp), protected :: yr_len_sol ! Length of a year [sol] |
|---|
| 42 | ! Evolution-related: |
|---|
| 43 | logical(k4), protected :: evol_orbit ! Flag to follow the orbital parameters |
|---|
| 44 | logical(k4), protected :: evol_obl ! Flag the PEM to follow obliquity |
|---|
| 45 | logical(k4), protected :: evol_ecc ! Flag the PEM to follow eccenticity |
|---|
| 46 | logical(k4), protected :: evol_lsp ! Flag the PEM to follow Ls perihelie |
|---|
| 47 | real(dp), protected :: max_change_obl ! Maximum admissible change for obliquity |
|---|
| 48 | real(dp), protected :: max_change_ecc ! Maximum admissible change for eccentricity |
|---|
| 49 | real(dp), protected :: max_change_lsp ! Maximum admissible change for Lsp |
|---|
| 50 | |
|---|
| 51 | contains |
|---|
| 52 | !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 53 | |
|---|
| 54 | !======================================================================= |
|---|
| 55 | SUBROUTINE set_orbit_config(evol_orbit_in,evol_obl_in,evol_ecc_in,evol_lsp_in,max_change_obl_in,max_change_ecc_in,max_change_lsp_in) |
|---|
| 56 | !----------------------------------------------------------------------- |
|---|
| 57 | ! NAME |
|---|
| 58 | ! set_orbit_config |
|---|
| 59 | ! |
|---|
| 60 | ! DESCRIPTION |
|---|
| 61 | ! Setter for 'orbit' configuration parameters. |
|---|
| 62 | ! |
|---|
| 63 | ! AUTHORS & DATE |
|---|
| 64 | ! JB Clement, 02/2026 |
|---|
| 65 | ! |
|---|
| 66 | ! NOTES |
|---|
| 67 | ! |
|---|
| 68 | !----------------------------------------------------------------------- |
|---|
| 69 | |
|---|
| 70 | ! DEPENDENCIES |
|---|
| 71 | ! ------------ |
|---|
| 72 | use utility, only: real2str, bool2str |
|---|
| 73 | use display, only: print_msg |
|---|
| 74 | |
|---|
| 75 | ! DECLARATION |
|---|
| 76 | ! ----------- |
|---|
| 77 | implicit none |
|---|
| 78 | |
|---|
| 79 | ! ARGUMENTS |
|---|
| 80 | ! --------- |
|---|
| 81 | logical(k4), intent(in) :: evol_orbit_in, evol_obl_in, evol_ecc_in, evol_lsp_in |
|---|
| 82 | real(dp), intent(in) :: max_change_obl_in, max_change_ecc_in, max_change_lsp_in |
|---|
| 83 | |
|---|
| 84 | ! CODE |
|---|
| 85 | ! ---- |
|---|
| 86 | evol_orbit = evol_orbit_in |
|---|
| 87 | evol_obl = evol_obl_in |
|---|
| 88 | evol_ecc = evol_ecc_in |
|---|
| 89 | evol_lsp = evol_lsp_in |
|---|
| 90 | max_change_obl = max_change_obl_in |
|---|
| 91 | max_change_ecc = max_change_ecc_in |
|---|
| 92 | max_change_lsp = max_change_lsp_in |
|---|
| 93 | call print_msg('evol_orbit = '//bool2str(evol_orbit)) |
|---|
| 94 | call print_msg('evol_obl = '//bool2str(evol_obl)) |
|---|
| 95 | call print_msg('evol_ecc = '//bool2str(evol_ecc)) |
|---|
| 96 | call print_msg('evol_lsp = '//bool2str(evol_lsp)) |
|---|
| 97 | call print_msg('max_change_obl = '//real2str(max_change_obl)) |
|---|
| 98 | call print_msg('max_change_ecc = '//real2str(max_change_ecc)) |
|---|
| 99 | call print_msg('max_change_lsp = '//real2str(max_change_lsp)) |
|---|
| 100 | |
|---|
| 101 | END SUBROUTINE set_orbit_config |
|---|
| 102 | !======================================================================= |
|---|
| 103 | |
|---|
| 104 | !======================================================================= |
|---|
| 105 | SUBROUTINE init_orbit(obliquity_in,perihelion_in,aphelion_in,date_peri_in,yr_len_sol_in,sol_len_s_in) |
|---|
| 106 | !----------------------------------------------------------------------- |
|---|
| 107 | ! NAME |
|---|
| 108 | ! init_orbit |
|---|
| 109 | ! |
|---|
| 110 | ! DESCRIPTION |
|---|
| 111 | ! Initialize orbital characteristics of the planet. |
|---|
| 112 | ! |
|---|
| 113 | ! AUTHORS & DATE |
|---|
| 114 | ! JB Clement, 12/2025 |
|---|
| 115 | ! |
|---|
| 116 | ! NOTES |
|---|
| 117 | ! Taken from 'iniorbit' in the Mars PCM. |
|---|
| 118 | !----------------------------------------------------------------------- |
|---|
| 119 | |
|---|
| 120 | ! DEPENDENCIES |
|---|
| 121 | ! ------------ |
|---|
| 122 | use maths, only: pi |
|---|
| 123 | use display, only: print_msg |
|---|
| 124 | use utility, only: real2str |
|---|
| 125 | |
|---|
| 126 | ! DECLARATION |
|---|
| 127 | ! ----------- |
|---|
| 128 | implicit none |
|---|
| 129 | |
|---|
| 130 | ! ARGUMENTS |
|---|
| 131 | ! --------- |
|---|
| 132 | real(dp), intent(in) :: obliquity_in, perihelion_in, aphelion_in, date_peri_in, yr_len_sol_in, sol_len_s_in |
|---|
| 133 | |
|---|
| 134 | ! LOCAL VARIABLES |
|---|
| 135 | ! --------------- |
|---|
| 136 | real(dp) :: zxref, zanom, zz, zx0, zdx |
|---|
| 137 | real(dp) :: lsp ! Solar longitude of the perihelion [rad] |
|---|
| 138 | integer(di) :: iter |
|---|
| 139 | |
|---|
| 140 | ! CODE |
|---|
| 141 | ! ---- |
|---|
| 142 | ! Setters |
|---|
| 143 | obliquity = obliquity_in |
|---|
| 144 | perihelion = perihelion_in |
|---|
| 145 | aphelion = aphelion_in |
|---|
| 146 | date_peri = date_peri_in |
|---|
| 147 | sol_len_s = sol_len_s_in |
|---|
| 148 | yr_len_sol = yr_len_sol_in |
|---|
| 149 | |
|---|
| 150 | ! Compute eccentricity and semi-major axis |
|---|
| 151 | eccentricity = (aphelion - perihelion)/(aphelion + perihelion) |
|---|
| 152 | semimaj_axis = 0.5_dp*(aphelion + perihelion) |
|---|
| 153 | |
|---|
| 154 | ! Compute mean anomaly zanom |
|---|
| 155 | zz = (yr_len_sol - date_peri)/yr_len_sol |
|---|
| 156 | zanom = 2._dp*pi*(zz - nint(zz)) |
|---|
| 157 | zxref = abs(zanom) |
|---|
| 158 | |
|---|
| 159 | ! Solve equation zx0 - e*sin(zx0) = zxref for eccentric anomaly zx0 using Newton method |
|---|
| 160 | zx0 = zxref + eccentricity*sin(zxref) |
|---|
| 161 | do iter = 1,100 |
|---|
| 162 | zdx = -(zx0 - eccentricity*sin(zx0) - zxref)/(1._dp - eccentricity*cos(zx0)) |
|---|
| 163 | if (abs(zdx) <= 1.e-12_dp) exit |
|---|
| 164 | zx0 = zx0 + zdx |
|---|
| 165 | end do |
|---|
| 166 | |
|---|
| 167 | zx0 = zx0 + zdx |
|---|
| 168 | if (zanom < 0.) zx0 = -zx0 |
|---|
| 169 | |
|---|
| 170 | ! Compute solar longitude of the perihelion |
|---|
| 171 | lsp = -2._dp*atan(sqrt((1._dp + eccentricity)/(1._dp - eccentricity))*tan(zx0/2._dp)) |
|---|
| 172 | lsp = modulo(lsp,2._dp*pi) |
|---|
| 173 | ls_peri = lsp*180._dp/pi ! Conversion in degree |
|---|
| 174 | |
|---|
| 175 | call print_msg('Obliquity [deg] = '//real2str(obliquity)) |
|---|
| 176 | call print_msg('Eccentricity [-] = '//real2str(eccentricity)) |
|---|
| 177 | call print_msg('Ls of perihelion [deg] = '//real2str(ls_peri)) |
|---|
| 178 | call print_msg('Perihelion [Mkm] = '//real2str(perihelion)) |
|---|
| 179 | call print_msg('Aphelion [Mkm] = '//real2str(aphelion)) |
|---|
| 180 | call print_msg('Semi-major axis [Mkm] = '//real2str(semimaj_axis)) |
|---|
| 181 | call print_msg('Date of perihelion [sol] = '//real2str(date_peri)) |
|---|
| 182 | call print_msg('Length of a sol [s] = '//real2str(sol_len_s)) |
|---|
| 183 | call print_msg('Length of a year [sol] = '//real2str(yr_len_sol)) |
|---|
| 184 | |
|---|
| 185 | END SUBROUTINE init_orbit |
|---|
| 186 | !======================================================================= |
|---|
| 187 | |
|---|
| 188 | !======================================================================= |
|---|
| 189 | SUBROUTINE lsp2datep(lsp,datep) |
|---|
| 190 | !----------------------------------------------------------------------- |
|---|
| 191 | ! NAME |
|---|
| 192 | ! lsp2datep |
|---|
| 193 | ! |
|---|
| 194 | ! DESCRIPTION |
|---|
| 195 | ! Initialize orbital data of the planet. |
|---|
| 196 | ! |
|---|
| 197 | ! AUTHORS & DATE |
|---|
| 198 | ! JB Clement, 12/2025 |
|---|
| 199 | ! |
|---|
| 200 | ! NOTES |
|---|
| 201 | ! Taken from 'lsp2solp' in the Mars PCM. |
|---|
| 202 | !----------------------------------------------------------------------- |
|---|
| 203 | |
|---|
| 204 | ! DEPENDENCIES |
|---|
| 205 | ! ------------ |
|---|
| 206 | use maths, only: pi |
|---|
| 207 | |
|---|
| 208 | ! DECLARATION |
|---|
| 209 | ! ----------- |
|---|
| 210 | implicit none |
|---|
| 211 | |
|---|
| 212 | ! ARGUMENTS |
|---|
| 213 | ! --------- |
|---|
| 214 | real(dp), intent(in) :: lsp ! Ls at perihelion [deg] |
|---|
| 215 | real(dp), intent(out) :: datep ! Date at perihelion [sol] |
|---|
| 216 | |
|---|
| 217 | ! LOCAL VARIABLES |
|---|
| 218 | ! --------------- |
|---|
| 219 | real(dp) :: zx0 ! Eccentric anomaly at Ls = 0 |
|---|
| 220 | |
|---|
| 221 | ! CODE |
|---|
| 222 | ! ---- |
|---|
| 223 | ! Compute orbit geometrical parameters |
|---|
| 224 | zx0 = -2._dp*atan(tan(0.5_dp*lsp*pi/180._dp)*sqrt((1._dp - eccentricity)/(1._dp + eccentricity))) |
|---|
| 225 | if (zx0 <= 0._dp) zx0 = zx0 + 2._dp*pi |
|---|
| 226 | |
|---|
| 227 | ! Compute sol at perihelion |
|---|
| 228 | datep = yr_len_sol*(1._dp - (zx0 - eccentricity*sin(zx0))/(2._dp*pi)) |
|---|
| 229 | |
|---|
| 230 | END SUBROUTINE lsp2datep |
|---|
| 231 | !======================================================================= |
|---|
| 232 | |
|---|
| 233 | !======================================================================= |
|---|
| 234 | SUBROUTINE ini_orbit() |
|---|
| 235 | !----------------------------------------------------------------------- |
|---|
| 236 | ! NAME |
|---|
| 237 | ! ini_orbit |
|---|
| 238 | ! |
|---|
| 239 | ! DESCRIPTION |
|---|
| 240 | ! Initialize the parameters of module 'orbit'. |
|---|
| 241 | ! |
|---|
| 242 | ! AUTHORS & DATE |
|---|
| 243 | ! R. Vandemeulebrouck |
|---|
| 244 | ! JB Clement, 2023-2025 |
|---|
| 245 | ! |
|---|
| 246 | ! NOTES |
|---|
| 247 | ! |
|---|
| 248 | !----------------------------------------------------------------------- |
|---|
| 249 | |
|---|
| 250 | ! DEPENDENCIES |
|---|
| 251 | ! ------------ |
|---|
| 252 | use stoppage, only: stop_clean |
|---|
| 253 | |
|---|
| 254 | ! DECLARATION |
|---|
| 255 | ! ----------- |
|---|
| 256 | implicit none |
|---|
| 257 | |
|---|
| 258 | ! LOCAL VARIABLES |
|---|
| 259 | ! --------------- |
|---|
| 260 | integer(di) :: n ! Number of lines in the file |
|---|
| 261 | integer(di) :: ierr, funit |
|---|
| 262 | logical(k4) :: here |
|---|
| 263 | |
|---|
| 264 | ! CODE |
|---|
| 265 | ! ---- |
|---|
| 266 | inquire(file = orbitfile_name,exist = here) |
|---|
| 267 | if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//orbitfile_name//'"!',1) |
|---|
| 268 | |
|---|
| 269 | ! Get the number of lines for Laskar's orbital file |
|---|
| 270 | open(newunit = funit,file = orbitfile_name,status = 'old',action = 'read',iostat = ierr) |
|---|
| 271 | if (ierr /= 0) call stop_clean(__FILE__,__LINE__,'error opening file "'//orbitfile_name//'"!',ierr) |
|---|
| 272 | n = 0 |
|---|
| 273 | do |
|---|
| 274 | read(funit,*,iostat = ierr) |
|---|
| 275 | if (ierr /= 0) exit |
|---|
| 276 | n = n + 1 |
|---|
| 277 | end do |
|---|
| 278 | close(funit) |
|---|
| 279 | |
|---|
| 280 | ! Allocation of module arrays |
|---|
| 281 | if (.not. allocated(year_lask)) allocate(year_lask(n)) |
|---|
| 282 | if (.not. allocated(obl_lask)) allocate(obl_lask(n)) |
|---|
| 283 | if (.not. allocated(ecc_lask)) allocate(ecc_lask(n)) |
|---|
| 284 | if (.not. allocated(lsp_lask)) allocate(lsp_lask(n)) |
|---|
| 285 | |
|---|
| 286 | END SUBROUTINE ini_orbit |
|---|
| 287 | !======================================================================= |
|---|
| 288 | |
|---|
| 289 | !======================================================================= |
|---|
| 290 | SUBROUTINE end_orbit |
|---|
| 291 | !----------------------------------------------------------------------- |
|---|
| 292 | ! NAME |
|---|
| 293 | ! end_orbit |
|---|
| 294 | ! |
|---|
| 295 | ! DESCRIPTION |
|---|
| 296 | ! Deallocate orbital data arrays. |
|---|
| 297 | ! |
|---|
| 298 | ! AUTHORS & DATE |
|---|
| 299 | ! R. Vandemeulebrouck |
|---|
| 300 | ! JB Clement, 2023-2025 |
|---|
| 301 | ! |
|---|
| 302 | ! NOTES |
|---|
| 303 | ! |
|---|
| 304 | !----------------------------------------------------------------------- |
|---|
| 305 | |
|---|
| 306 | ! DECLARATION |
|---|
| 307 | ! ----------- |
|---|
| 308 | implicit none |
|---|
| 309 | |
|---|
| 310 | ! CODE |
|---|
| 311 | ! ---- |
|---|
| 312 | if (allocated(year_lask)) deallocate(year_lask) |
|---|
| 313 | if (allocated(obl_lask)) deallocate(obl_lask) |
|---|
| 314 | if (allocated(ecc_lask)) deallocate(ecc_lask) |
|---|
| 315 | if (allocated(lsp_lask)) deallocate(lsp_lask) |
|---|
| 316 | |
|---|
| 317 | END SUBROUTINE end_orbit |
|---|
| 318 | !======================================================================= |
|---|
| 319 | |
|---|
| 320 | !======================================================================= |
|---|
| 321 | SUBROUTINE read_orbitpm(n_yr_sim) |
|---|
| 322 | !----------------------------------------------------------------------- |
|---|
| 323 | ! NAME |
|---|
| 324 | ! read_orbitpm |
|---|
| 325 | ! |
|---|
| 326 | ! DESCRIPTION |
|---|
| 327 | ! Read Laskar's orbital file and locate index for |
|---|
| 328 | ! closest lower year relative to current simulation year. |
|---|
| 329 | ! |
|---|
| 330 | ! AUTHORS & DATE |
|---|
| 331 | ! JB Clement, 2023-2025 |
|---|
| 332 | ! |
|---|
| 333 | ! NOTES |
|---|
| 334 | ! |
|---|
| 335 | !----------------------------------------------------------------------- |
|---|
| 336 | |
|---|
| 337 | ! DEPENDENCIES |
|---|
| 338 | ! ------------ |
|---|
| 339 | use evolution, only: pem_ini_date, r_plnt2earth_yr |
|---|
| 340 | use stoppage, only: stop_clean |
|---|
| 341 | use display, only: print_msg |
|---|
| 342 | use utility, only: real2str, int2str |
|---|
| 343 | |
|---|
| 344 | ! DECLARATION |
|---|
| 345 | ! ----------- |
|---|
| 346 | implicit none |
|---|
| 347 | |
|---|
| 348 | ! ARGUMENTS |
|---|
| 349 | ! --------- |
|---|
| 350 | real(dp), intent(in) :: n_yr_sim |
|---|
| 351 | |
|---|
| 352 | ! LOCAL VARIABLES |
|---|
| 353 | ! --------------- |
|---|
| 354 | integer(di) :: ierr, funit, i, n |
|---|
| 355 | logical(k4) :: here |
|---|
| 356 | real(dp) :: current_year |
|---|
| 357 | |
|---|
| 358 | ! CODE |
|---|
| 359 | ! ---- |
|---|
| 360 | call print_msg('> Reading "'//orbitfile_name//'"') |
|---|
| 361 | ! Compute the current year |
|---|
| 362 | current_year = pem_ini_date + n_yr_sim |
|---|
| 363 | call print_msg('Current year = '//real2str(current_year)) |
|---|
| 364 | |
|---|
| 365 | inquire(file = orbitfile_name,exist = here) |
|---|
| 366 | if (.not. here) call stop_clean(__FILE__,__LINE__,'cannot find required file "'//orbitfile_name//'"!',1) |
|---|
| 367 | |
|---|
| 368 | ! Read the Laskars's orbital file |
|---|
| 369 | open(newunit = funit,file = orbitfile_name,status = 'old',action = 'read',iostat = ierr) |
|---|
| 370 | if (ierr /= 0) call stop_clean(__FILE__,__LINE__,'error opening file "'//orbitfile_name//'"!',ierr) |
|---|
| 371 | n = size(year_lask,1) ! Number of lines in the file |
|---|
| 372 | iyear_lask = 0 ! Line number for closest lower year relative to current simulation year |
|---|
| 373 | do i = 1,n |
|---|
| 374 | read(funit,*) year_lask(i), obl_lask(i), ecc_lask(i), lsp_lask(i) |
|---|
| 375 | year_lask(i) = year_lask(i)*1000._dp/r_plnt2earth_yr ! Conversion from Laskar's kilo Earth years to planetary years |
|---|
| 376 | if (year_lask(i) > current_year) iyear_lask = i + 1 |
|---|
| 377 | end do |
|---|
| 378 | close(funit) |
|---|
| 379 | if (iyear_lask == 0 .or. iyear_lask == n + 1) then |
|---|
| 380 | call stop_clean(__FILE__,__LINE__,'the current year could not be found in the file "'//orbitfile_name//'".',1) |
|---|
| 381 | else |
|---|
| 382 | call print_msg('The current year in "'//orbitfile_name//'" is at line '//int2str(iyear_lask)//'.') |
|---|
| 383 | end if |
|---|
| 384 | |
|---|
| 385 | END SUBROUTINE read_orbitpm |
|---|
| 386 | !======================================================================= |
|---|
| 387 | |
|---|
| 388 | !======================================================================= |
|---|
| 389 | SUBROUTINE compute_maxyr_orbit(n_yr_sim,nmax_yr_runorb) |
|---|
| 390 | !----------------------------------------------------------------------- |
|---|
| 391 | ! NAME |
|---|
| 392 | ! compute_maxyr_orbit |
|---|
| 393 | ! |
|---|
| 394 | ! DESCRIPTION |
|---|
| 395 | ! Determine maximum number of years before orbital params change |
|---|
| 396 | ! beyond admissible thresholds. |
|---|
| 397 | ! |
|---|
| 398 | ! AUTHORS & DATE |
|---|
| 399 | ! R. Vandemeulebrouck |
|---|
| 400 | ! JB Clement, 2023-2025 |
|---|
| 401 | ! |
|---|
| 402 | ! NOTES |
|---|
| 403 | ! Handles Lsp modulo crossings. |
|---|
| 404 | !----------------------------------------------------------------------- |
|---|
| 405 | |
|---|
| 406 | ! DEPENDENCIES |
|---|
| 407 | ! ------------ |
|---|
| 408 | use evolution, only: pem_ini_date |
|---|
| 409 | use display, only: print_msg |
|---|
| 410 | use utility, only: real2str |
|---|
| 411 | |
|---|
| 412 | ! DECLARATION |
|---|
| 413 | ! ----------- |
|---|
| 414 | implicit none |
|---|
| 415 | |
|---|
| 416 | ! ARGUMENTS |
|---|
| 417 | ! --------- |
|---|
| 418 | real(dp), intent(in) :: n_yr_sim ! Current year of the simulation |
|---|
| 419 | real(dp), intent(out) :: nmax_yr_runorb ! Maximum number of years of the PEM before orbital parameters change too much |
|---|
| 420 | |
|---|
| 421 | ! LOCAL VARIABLES |
|---|
| 422 | ! --------------- |
|---|
| 423 | real(dp) :: current_year |
|---|
| 424 | real(dp) :: max_obl, max_ecc, max_lsp |
|---|
| 425 | real(dp) :: min_obl, min_ecc, min_lsp |
|---|
| 426 | real(dp) :: nmax_yr_runobl, nmax_yr_runecc, nmax_yr_runlsp ! Maximum year iteration before reaching an inadmissible value of orbit param |
|---|
| 427 | real(dp) :: xa, xb, ya, yb |
|---|
| 428 | logical(k4) :: found_obl, found_ecc, found_lsp |
|---|
| 429 | real(dp) :: lsp_corr ! Lsp corrected if the "modulo is crossed" |
|---|
| 430 | real(dp) :: delta |
|---|
| 431 | real(dp), dimension(:), allocatable :: lsplask_unwrap |
|---|
| 432 | integer(di) :: i |
|---|
| 433 | |
|---|
| 434 | ! CODE |
|---|
| 435 | ! ---- |
|---|
| 436 | if (.not. evol_orbit) then |
|---|
| 437 | nmax_yr_runorb = largest_nb ! Default huge value |
|---|
| 438 | return |
|---|
| 439 | end if |
|---|
| 440 | call print_msg('> Computing the accepted maximum number of years due to orbital parameters') |
|---|
| 441 | current_year = pem_ini_date + n_yr_sim ! We compute the current year |
|---|
| 442 | |
|---|
| 443 | ! Unwrap the Lsp changes in Laskar's file |
|---|
| 444 | allocate(lsplask_unwrap(iyear_lask)) |
|---|
| 445 | lsplask_unwrap(iyear_lask) = lsp_lask(iyear_lask) |
|---|
| 446 | do i = iyear_lask,2,-1 |
|---|
| 447 | delta = lsp_lask(i - 1) - lsp_lask(i) |
|---|
| 448 | if (delta > 180._dp) then |
|---|
| 449 | lsp_corr = lsp_lask(i - 1) - 360._dp |
|---|
| 450 | else if (delta < -180._dp) then |
|---|
| 451 | lsp_corr = lsp_lask(i - 1) + 360._dp |
|---|
| 452 | else |
|---|
| 453 | lsp_corr = lsp_lask(i - 1) |
|---|
| 454 | end if |
|---|
| 455 | lsplask_unwrap(i - 1) = lsplask_unwrap(i) + lsp_corr - lsp_lask(i) |
|---|
| 456 | end do |
|---|
| 457 | |
|---|
| 458 | ! Correct the current Lsp according to the unwrapping |
|---|
| 459 | delta = ls_peri - lsplask_unwrap(iyear_lask) |
|---|
| 460 | if (delta > 180._dp) then |
|---|
| 461 | ls_peri = ls_peri - 360._dp |
|---|
| 462 | else if (delta < -180._dp) then |
|---|
| 463 | ls_peri = ls_peri + 360._dp |
|---|
| 464 | end if |
|---|
| 465 | |
|---|
| 466 | ! Maximum change accepted for orbital parameters |
|---|
| 467 | max_obl = obliquity + max_change_obl |
|---|
| 468 | min_obl = obliquity - max_change_obl |
|---|
| 469 | call print_msg('Obl. (current|accepted min|accepted max): '//real2str(obliquity)//' | '//real2str(min_obl)//real2str(max_obl)) |
|---|
| 470 | |
|---|
| 471 | max_ecc = min(eccentricity + max_change_ecc,1. - minieps) ! ecc < 1. |
|---|
| 472 | min_ecc = max(eccentricity - max_change_ecc,0._dp) ! ecc >= 0. |
|---|
| 473 | call print_msg('Ecc. (current|accepted min|accepted max): '//real2str(eccentricity)//' | '//real2str(min_ecc)//' | '//real2str(max_ecc)) |
|---|
| 474 | |
|---|
| 475 | max_lsp = ls_peri + max_change_lsp |
|---|
| 476 | min_lsp = ls_peri - max_change_lsp |
|---|
| 477 | call print_msg('Lsp (current|accepted min|accepted max): '//real2str(ls_peri)//' | '//real2str(min_lsp)//' | '//real2str(max_lsp)) |
|---|
| 478 | |
|---|
| 479 | ! Initialization |
|---|
| 480 | nmax_yr_runobl = largest_nb ! Default huge value |
|---|
| 481 | nmax_yr_runecc = largest_nb ! Default huge value |
|---|
| 482 | nmax_yr_runlsp =largest_nb ! Default huge value |
|---|
| 483 | found_obl = .false. |
|---|
| 484 | found_ecc = .false. |
|---|
| 485 | found_lsp = .false. |
|---|
| 486 | if (.not. evol_obl) found_obl = .true. |
|---|
| 487 | if (.not. evol_ecc) found_ecc = .true. |
|---|
| 488 | if (.not. evol_lsp) found_lsp = .true. |
|---|
| 489 | |
|---|
| 490 | ! The maximum reachable year is found by interpolation according to the maximum admissible change of orbital parameters |
|---|
| 491 | do i = iyear_lask,2,-1 |
|---|
| 492 | xa = year_lask(i) |
|---|
| 493 | xb = year_lask(i - 1) |
|---|
| 494 | |
|---|
| 495 | ! Obliquity |
|---|
| 496 | if (evol_obl .and. .not. found_obl) then |
|---|
| 497 | ya = obl_lask(i) |
|---|
| 498 | yb = obl_lask(i - 1) |
|---|
| 499 | if (yb < min_obl) then ! The minimum accepted is overtaken |
|---|
| 500 | nmax_yr_runobl = (min_obl - ya)*(xb - xa)/(yb - ya) + xa - current_year |
|---|
| 501 | found_obl = .true. |
|---|
| 502 | else if (max_obl < yb) then ! The maximum accepted is overtaken |
|---|
| 503 | nmax_yr_runobl = (max_obl - ya)*(xb - xa)/(yb - ya) + xa - current_year |
|---|
| 504 | found_obl = .true. |
|---|
| 505 | end if |
|---|
| 506 | end if |
|---|
| 507 | |
|---|
| 508 | ! Eccentricity |
|---|
| 509 | if (evol_ecc .and. .not. found_ecc) then |
|---|
| 510 | ya = ecc_lask(i) |
|---|
| 511 | yb = ecc_lask(i - 1) |
|---|
| 512 | if (yb < min_ecc) then ! The minimum accepted is overtaken |
|---|
| 513 | nmax_yr_runecc = (min_ecc - ya)*(xb - xa)/(yb - ya) + xa - current_year |
|---|
| 514 | found_ecc = .true. |
|---|
| 515 | else if (max_ecc < yb) then ! The maximum accepted is overtaken |
|---|
| 516 | nmax_yr_runecc = (max_ecc - ya)*(xb - xa)/(yb - ya) + xa - current_year |
|---|
| 517 | found_ecc = .true. |
|---|
| 518 | end if |
|---|
| 519 | end if |
|---|
| 520 | |
|---|
| 521 | ! Lsp |
|---|
| 522 | if (evol_lsp .and. .not. found_lsp) then |
|---|
| 523 | ya = lsplask_unwrap(i) |
|---|
| 524 | yb = lsplask_unwrap(i - 1) |
|---|
| 525 | if (yb < min_lsp) then ! The minimum accepted is overtaken |
|---|
| 526 | nmax_yr_runlsp = (min_lsp - ya)*(xb - xa)/(yb - ya) + xa - current_year |
|---|
| 527 | found_lsp = .true. |
|---|
| 528 | else if (max_lsp < yb) then ! The maximum accepted is overtaken |
|---|
| 529 | nmax_yr_runlsp = (max_lsp - ya)*(xb - xa)/(yb - ya) + xa - current_year |
|---|
| 530 | found_lsp = .true. |
|---|
| 531 | end if |
|---|
| 532 | end if |
|---|
| 533 | |
|---|
| 534 | if (found_obl .and. found_ecc .and. found_lsp) exit ! The loop is left as soon as everything is found |
|---|
| 535 | end do |
|---|
| 536 | |
|---|
| 537 | deallocate(lsplask_unwrap) |
|---|
| 538 | |
|---|
| 539 | if (.not. found_obl) call print_msg('The maximum reachable year for obl. could not be found in "'//orbitfile_name//'".') |
|---|
| 540 | if (.not. found_ecc) call print_msg('The maximum reachable year for ecc. could not be found in "'//orbitfile_name//'".') |
|---|
| 541 | if (.not. found_lsp) call print_msg('The maximum reachable year for Lsp could not be found in "'//orbitfile_name//'".') |
|---|
| 542 | |
|---|
| 543 | call print_msg('Number of years accepted for obl. = '//real2str(nmax_yr_runobl)) |
|---|
| 544 | call print_msg('Number of years accepted for ecc. = '//real2str(nmax_yr_runecc)) |
|---|
| 545 | call print_msg('Number of years accepted for Lsp = '//real2str(nmax_yr_runlsp)) |
|---|
| 546 | |
|---|
| 547 | nmax_yr_runorb = min(nmax_yr_runobl,nmax_yr_runecc,nmax_yr_runlsp) |
|---|
| 548 | if (nmax_yr_runorb < 1._dp) nmax_yr_runorb = 1._dp ! nmax_yr_runorb should be at least equal to 1 |
|---|
| 549 | |
|---|
| 550 | call print_msg('So the max. number of years for the orbital criterion = '//real2str(nmax_yr_runorb)) |
|---|
| 551 | |
|---|
| 552 | END SUBROUTINE compute_maxyr_orbit |
|---|
| 553 | !======================================================================= |
|---|
| 554 | |
|---|
| 555 | !======================================================================= |
|---|
| 556 | SUBROUTINE update_orbit(n_yr_sim,n_yr_run) |
|---|
| 557 | !----------------------------------------------------------------------- |
|---|
| 558 | ! NAME |
|---|
| 559 | ! update_orbit |
|---|
| 560 | ! |
|---|
| 561 | ! DESCRIPTION |
|---|
| 562 | ! Update orbital parameters from Laskar values at a new year. |
|---|
| 563 | ! |
|---|
| 564 | ! AUTHORS & DATE |
|---|
| 565 | ! R. Vandemeulebrouck |
|---|
| 566 | ! JB Clement, 2023-2025 |
|---|
| 567 | ! |
|---|
| 568 | ! NOTES |
|---|
| 569 | ! |
|---|
| 570 | !----------------------------------------------------------------------- |
|---|
| 571 | |
|---|
| 572 | use evolution, only: pem_ini_date |
|---|
| 573 | use call_dayperi_mod, only: call_dayperi |
|---|
| 574 | use stoppage, only: stop_clean |
|---|
| 575 | use display, only: print_msg |
|---|
| 576 | use utility, only: real2str |
|---|
| 577 | |
|---|
| 578 | ! DECLARATION |
|---|
| 579 | ! ----------- |
|---|
| 580 | implicit none |
|---|
| 581 | |
|---|
| 582 | ! ARGUMENTS |
|---|
| 583 | ! --------- |
|---|
| 584 | real(dp), intent(in) :: n_yr_sim ! Number of simulated years |
|---|
| 585 | real(dp), intent(in) :: n_yr_run ! Number of iterations of the PEM |
|---|
| 586 | |
|---|
| 587 | ! LOCAL VARIABLES |
|---|
| 588 | ! --------------- |
|---|
| 589 | integer(di) :: i |
|---|
| 590 | real(dp) :: current_year, old_year, obl_old, ecc_old, lsp_old |
|---|
| 591 | real(dp) :: xa, xb, ya, yb ! Variables for interpolation |
|---|
| 592 | logical(k4) :: found_year |
|---|
| 593 | |
|---|
| 594 | ! CODE |
|---|
| 595 | ! ---- |
|---|
| 596 | call print_msg('> Updating the orbital parameters for the new year') |
|---|
| 597 | current_year = pem_ini_date + n_yr_sim ! We compute the current year |
|---|
| 598 | old_year = current_year - n_yr_run |
|---|
| 599 | obl_old = obliquity |
|---|
| 600 | ecc_old = eccentricity |
|---|
| 601 | lsp_old = ls_peri |
|---|
| 602 | |
|---|
| 603 | found_year = .false. |
|---|
| 604 | if (current_year < 0._dp) then |
|---|
| 605 | do i = iyear_lask,2,-1 |
|---|
| 606 | xa = year_lask(i) |
|---|
| 607 | xb = year_lask(i - 1) |
|---|
| 608 | if (xa <= current_year .and. current_year < xb) then |
|---|
| 609 | ! Obliquity |
|---|
| 610 | if (evol_obl) then |
|---|
| 611 | ya = obl_lask(i) |
|---|
| 612 | yb = obl_lask(i - 1) |
|---|
| 613 | obliquity = (current_year - xa)*(yb - ya)/(xb - xa) + ya |
|---|
| 614 | end if |
|---|
| 615 | |
|---|
| 616 | ! Eccentricity |
|---|
| 617 | if (evol_ecc) then |
|---|
| 618 | ya = ecc_lask(i) |
|---|
| 619 | yb = ecc_lask(i - 1) |
|---|
| 620 | eccentricity = (current_year - xa)*(yb - ya)/(xb - xa) + ya |
|---|
| 621 | end if |
|---|
| 622 | |
|---|
| 623 | ! Lsp |
|---|
| 624 | if (evol_lsp) then |
|---|
| 625 | ya = lsp_lask(i) |
|---|
| 626 | yb = lsp_lask(i - 1) |
|---|
| 627 | if (abs(yb - ya) > 300._dp) then ! If modulo is "crossed" through the interval |
|---|
| 628 | if (ya < yb) then ! Lsp should be decreasing |
|---|
| 629 | ya = ya + 360._dp |
|---|
| 630 | else ! Lsp should be increasing |
|---|
| 631 | yb = yb + 360._dp |
|---|
| 632 | end if |
|---|
| 633 | end if |
|---|
| 634 | ls_peri = modulo((current_year - xa)*(yb - ya)/(xb - xa) + ya,360._dp) |
|---|
| 635 | end if |
|---|
| 636 | found_year = .true. |
|---|
| 637 | exit ! The loop is left as soon as the right interval is found |
|---|
| 638 | end if |
|---|
| 639 | end do |
|---|
| 640 | else if (current_year >= 0._dp .and. current_year < 100._dp) then ! For present orbital characteristics |
|---|
| 641 | if (evol_obl) obliquity = obl_lask(1) |
|---|
| 642 | if (evol_ecc) eccentricity = ecc_lask(1) |
|---|
| 643 | if (evol_lsp) ls_peri = lsp_lask(1) |
|---|
| 644 | found_year = .true. |
|---|
| 645 | end if |
|---|
| 646 | |
|---|
| 647 | if (.not. found_year) call stop_clean(__FILE__,__LINE__,'the new year could not be found in the file "'//orbitfile_name//'".',1) |
|---|
| 648 | |
|---|
| 649 | call lsp2datep(ls_peri,date_peri) |
|---|
| 650 | perihelion = semimaj_axis*(1._dp - eccentricity) |
|---|
| 651 | aphelion = semimaj_axis*(1._dp + eccentricity) |
|---|
| 652 | |
|---|
| 653 | call print_msg('Year (ini|now) = '//real2str(old_year)//' | '//real2str(current_year)) |
|---|
| 654 | call print_msg('Obl. (ini|now) = '//real2str(obl_old)//' | '//real2str(obliquity)) |
|---|
| 655 | call print_msg('Ecc. (ini|now) = '//real2str(ecc_old)//' | '//real2str(eccentricity)) |
|---|
| 656 | call print_msg('Lsp (ini|now) = '//real2str(lsp_old)//' | '//real2str(ls_peri)) |
|---|
| 657 | |
|---|
| 658 | END SUBROUTINE update_orbit |
|---|
| 659 | !======================================================================= |
|---|
| 660 | |
|---|
| 661 | END MODULE orbit |
|---|