LCOV - code coverage report
Current view: top level - binary/private - binary_timestep.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 28.7 % 167 48
Test Date: 2025-05-08 18:23:42 Functions: 50.0 % 2 1

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2010-2019  Pablo Marchant & The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              : 
      21              :       module binary_timestep
      22              : 
      23              :       use const_def, only: dp, msun, secyer
      24              :       use math_lib
      25              :       use star_lib
      26              :       use star_def
      27              :       use binary_def
      28              : 
      29              :       implicit none
      30              : 
      31              :       contains
      32              : 
      33            0 :       subroutine set_star_timesteps(b)  ! sets the smallest next timestep for all stars
      34              :          type (binary_info), pointer :: b
      35              :          integer :: i, l
      36            0 :          real(dp) :: dt_min
      37              :          type (star_info), pointer :: s
      38              :          integer :: ierr, num_stars
      39            0 :          ierr = 0
      40            0 :          dt_min = 1d99
      41            0 :          num_stars = 2
      42            0 :          if (b% point_mass_i > 0) num_stars = 1
      43            0 :          do l = 1, num_stars
      44            0 :             if (l == 1 .and. b% point_mass_i == 1) then
      45              :                i = 2
      46              :             else
      47            0 :                i = l
      48              :             end if
      49            0 :             call star_ptr(b% star_ids(i), s, ierr)
      50            0 :             if (ierr /= 0) then
      51            0 :                 write(*, *) trim('star_ptr') // ' ierr', ierr
      52            0 :                 return
      53              :             end if
      54            0 :             if (s% dt_next < dt_min) then
      55            0 :                dt_min = s% dt_next
      56              :             end if
      57              :          end do
      58            0 :          if (b% max_timestep <= dt_min) then
      59              :             dt_min = b% max_timestep
      60              :          else
      61            0 :             b% dt_why_reason = b_Tlim_comp
      62              :          end if
      63              :          ! just to be sure we dont cause a segfault
      64            0 :          if (b% dt_why_reason < 1 .or. b% dt_why_reason > b_numTlim) then
      65            0 :             dt_why_str(Tlim_binary) = " "
      66              :          else
      67            0 :             dt_why_str(Tlim_binary) = binary_dt_why_str(b% dt_why_reason)
      68              :          end if
      69            0 :          do l = 1, num_stars
      70            0 :             if (l == 1 .and. b% point_mass_i == 1) then
      71              :                i = 2
      72              :             else
      73            0 :                i = l
      74              :             end if
      75            0 :             call star_ptr(b% star_ids(i), s, ierr)
      76            0 :             if (ierr /= 0) then
      77            0 :                 write(*, *) trim('star_ptr') // ' ierr', ierr
      78            0 :                 return
      79              :             end if
      80            0 :             if (s% dt_next > dt_min) then
      81            0 :                s% dt_next = dt_min
      82            0 :                s% why_Tlim = Tlim_binary
      83              :             end if
      84              :          end do
      85              : 
      86            0 :          if (b% have_to_reduce_timestep_due_to_j) then
      87              :             ! lower timesteps after retries due to large changes in angular momentum
      88            0 :             if (b% point_mass_i /= 1) then
      89            0 :                b% s1% dt = b% s1% dt*b% dt_reduction_factor_for_j
      90              :             end if
      91            0 :             if (b% point_mass_i /= 2) then
      92            0 :                b% s2% dt = b% s2% dt*b% dt_reduction_factor_for_j
      93              :             end if
      94            0 :             b% have_to_reduce_timestep_due_to_j = .false.
      95              :          end if
      96              : 
      97              :       end subroutine set_star_timesteps
      98              : 
      99            2 :       integer function binary_pick_next_timestep(b)
     100              :          type (binary_info), pointer :: b
     101              :          type (star_info), pointer :: s
     102              : 
     103              :          real(dp) :: &
     104            2 :             env_change, dtm, dtj, dta, dtr, dte, dtdm, &
     105            2 :             j_change, sep_change, rel_gap_change, e_change, set_dt, &
     106            2 :             rel_change
     107              : 
     108              :          include 'formats'
     109              : 
     110            2 :          dtm = 1d99
     111            2 :          dtj = 1d99
     112            2 :          dta = 1d99
     113            2 :          dtr = 1d99
     114            2 :          dte = 1d99
     115            2 :          dtdm = 1d99
     116              : 
     117            2 :          binary_pick_next_timestep = keep_going
     118              : 
     119            2 :          s => b% s_donor
     120              : 
     121            2 :          if (b% max_timestep < 0) b% max_timestep = b% s_donor% dt
     122              : 
     123            2 :          b% env(b% d_i) = s% star_mass - s% he_core_mass
     124            2 :          if (b% point_mass_i == 0) then
     125            0 :             b% env(b% a_i) = b% s_accretor% star_mass - b% s_accretor% he_core_mass
     126              :          end if
     127              : 
     128            2 :          if(.not. b% doing_first_model_of_run) then
     129            2 :             if (b% env_old(b% d_i) /= 0) then
     130            0 :                env_change = b% env(b% d_i) - b% env_old(b% d_i)
     131              :             else
     132              :                env_change = 0
     133              :             end if
     134              : 
     135            2 :             if (b% rl_relative_gap_old(b% d_i) /= 0) then
     136            2 :                rel_gap_change = b% rl_relative_gap_old(b% d_i) - b% rl_relative_gap(b% d_i)
     137              :             else
     138              :                rel_gap_change = 0
     139              :             end if
     140              : 
     141            2 :             if (b% angular_momentum_j_old /= 0) then
     142            0 :                j_change = b% angular_momentum_j - b% angular_momentum_j_old
     143              :             else
     144              :                j_change = 0
     145              :             end if
     146              : 
     147            2 :             if (b% separation_old /= 0) then
     148            0 :                sep_change = b% separation - b% separation_old
     149              :             else
     150              :                sep_change = 0
     151              :             end if
     152            2 :             if (b% eccentricity_old /= 0) then
     153            0 :                e_change = b% eccentricity - b% eccentricity_old
     154              :             else
     155              :                e_change = 0
     156              :             end if
     157              :          else
     158              :             env_change = 0
     159              :             rel_gap_change = 0
     160              :             j_change = 0
     161              :             sep_change = 0
     162              :             e_change = 0
     163              :          end if
     164              : 
     165              :          ! get limits for dt based on relative changes
     166            2 :          if (b% fj > 0) then
     167            0 :             rel_change = abs(j_change/b% angular_momentum_j)
     168              :             if (.not. b% ignore_hard_limits_this_step .and. &
     169            0 :                b% fj_hard > 0d0 .and. rel_change > b% fj_hard * b% time_delta_coeff) then
     170            0 :                write(*,*) "retry because of fj_hard limit,", &
     171            0 :                   "fj_hard:", b% fj_hard, "rel_change:", rel_change
     172            0 :                binary_pick_next_timestep = retry
     173            0 :                b% have_to_reduce_timestep_due_to_j = .true.
     174            0 :                return
     175              :             end if
     176            0 :             dtj = s% time_step/(rel_change/(b% fj * b% time_delta_coeff)+1d-99)
     177              :          end if
     178              : 
     179            2 :          if (b% fm > 0) then
     180            0 :             rel_change = abs(env_change/max(b% env(b% d_i), b% fm_limit))
     181              :             if (.not. b% ignore_hard_limits_this_step .and. &
     182            0 :                b% fm_hard > 0d0 .and. rel_change > b% fm_hard * b% time_delta_coeff) then
     183            0 :                write(*,*) "retry because of fm_hard limit,", &
     184            0 :                   "fm_hard:", b% fm_hard, "rel_change:", rel_change
     185            0 :                binary_pick_next_timestep = retry
     186            0 :                return
     187              :             end if
     188            0 :             dtm = s% time_step/(rel_change/(b% fm * b% time_delta_coeff)+1d-99)
     189              :          end if
     190              : 
     191            2 :          if (b% fr > 0) then
     192            2 :             rel_change = abs(rel_gap_change/max(abs(b% rl_relative_gap(b% d_i)), b% fr_limit))
     193              :             if (.not. b% ignore_hard_limits_this_step .and. &
     194            2 :                b% fr_hard > 0d0 .and. rel_change > b% fr_hard * b% time_delta_coeff) then
     195            0 :                write(*,*) "retry because of fr_hard limit for donor,", &
     196            0 :                   "fr_hard:", b% fr_hard, "rel_change:", rel_change
     197            0 :                binary_pick_next_timestep = retry
     198            0 :                return
     199              :             end if
     200            2 :             dtr = s% time_step/(rel_change/(b% fr * b% time_delta_coeff)+1d-99)
     201              : 
     202              :             ! Check for accretor as well
     203            2 :             if (b% rl_relative_gap_old(b% a_i) /= 0) then
     204            0 :                rel_gap_change = b% rl_relative_gap_old(b% a_i) - b% rl_relative_gap(b% a_i)
     205              :             else
     206              :                rel_gap_change = 0
     207              :             end if
     208            2 :             rel_change = abs(rel_gap_change/max(abs(b% rl_relative_gap(b% a_i)), b% fr_limit))
     209              :             if (.not. b% ignore_hard_limits_this_step .and. &
     210            2 :                b% fr_hard > 0d0 .and. rel_change > b% fr_hard * b% time_delta_coeff) then
     211            0 :                write(*,*) "retry because of fr_hard limit for accretor,", &
     212            0 :                   "fr_hard:", b% fr_hard, "rel_change:", rel_change
     213            0 :                binary_pick_next_timestep = retry
     214            0 :                return
     215              :             end if
     216            2 :             dtr = min(dtr, s% time_step/(rel_change/(b% fr * b% time_delta_coeff)+1d-99))
     217              :          end if
     218            2 :          if (dtr < b% fr_dt_limit) dtr = b% fr_dt_limit
     219              : 
     220            2 :          if (b% fa > 0) then
     221            0 :             rel_change = abs(sep_change/b% separation)
     222              :             if (.not. b% ignore_hard_limits_this_step .and. &
     223            0 :                b% fa_hard > 0d0 .and. rel_change > b% fa_hard * b% time_delta_coeff) then
     224            0 :                write(*,*) "retry because of fa_hard limit,", &
     225            0 :                   "fa_hard:", b% fa_hard, "rel_change:", rel_change
     226            0 :                binary_pick_next_timestep = retry
     227            0 :                return
     228              :             end if
     229            0 :             dta = s% time_step/(rel_change/(b% fa * b% time_delta_coeff)+1d-99)
     230              :          end if
     231              : 
     232            2 :          if (b% fe > 0) then
     233            0 :             rel_change = abs(e_change/ max(b% eccentricity, b% fe_limit))
     234              :             if (.not. b% ignore_hard_limits_this_step .and. &
     235            0 :                b% fe_hard > 0d0 .and. rel_change > b% fe_hard * b% time_delta_coeff) then
     236            0 :                write(*,*) "retry because of fe_hard limit,", &
     237            0 :                   "fe_hard:", b% fe_hard, "rel_change:", rel_change
     238            0 :                binary_pick_next_timestep = retry
     239            0 :                return
     240              :             end if
     241            0 :             dte = s% time_step/(rel_change/(b% fe * b% time_delta_coeff)+1d-99)
     242              :          end if
     243              : 
     244            2 :          if (b% fdm > 0d0) then
     245            0 :             rel_change = abs(b% m(b% d_i) - b% m_old(b% d_i))/b% m_old(b% d_i)
     246              :             if (.not. b% ignore_hard_limits_this_step .and. &
     247            0 :                b% fdm_hard > 0d0 .and. rel_change > b% fdm_hard * b% time_delta_coeff) then
     248            0 :                write(*,*) "retry because of fdm_hard limit for donor,", &
     249            0 :                   "fdm_hard:", b% fdm_hard, "rel_change:", rel_change
     250            0 :                binary_pick_next_timestep = retry
     251            0 :                return
     252              :             end if
     253            0 :             dtdm = s% time_step/(rel_change/(b% fdm * b% time_delta_coeff)+1d-99)
     254              : 
     255            0 :             rel_change = abs(b% m(b% a_i) - b% m_old(b% a_i))/b% m_old(b% a_i)
     256              :             if (.not. b% ignore_hard_limits_this_step .and. &
     257            0 :                b% fdm_hard > 0d0 .and. rel_change > b% fdm_hard * b% time_delta_coeff) then
     258            0 :                write(*,*) "retry because of fdm_hard limit for accretor,", &
     259            0 :                   "fdm_hard:", b% fdm_hard, "rel_change:", rel_change
     260            0 :                binary_pick_next_timestep = retry
     261            0 :                return
     262              :             end if
     263            0 :             dtdm = min(dtdm, s% time_step/(rel_change/(b% fdm * b% time_delta_coeff)+1d-99))
     264              :          end if
     265              : 
     266            2 :          set_dt = min(dtm, dtr, dtj, dta, dte, dtdm)
     267              : 
     268            2 :          if (set_dt == dtm) then
     269            0 :             b% dt_why_reason = b_Tlim_env
     270            2 :          else if (set_dt == dtr) then
     271            2 :             b% dt_why_reason = b_Tlim_roche
     272            0 :          else if (set_dt == dtj) then
     273            0 :             b% dt_why_reason = b_Tlim_jorb
     274            0 :          else if (set_dt == dta) then
     275            0 :             b% dt_why_reason = b_Tlim_sep
     276            0 :          else if (set_dt == dte) then
     277            0 :             b% dt_why_reason = b_Tlim_ecc
     278            0 :          else if (set_dt == dtdm) then
     279            0 :             b% dt_why_reason = b_Tlim_dm
     280              :          else
     281            0 :             call mesa_error(__FILE__,__LINE__,'Something wrong in binary timestep')
     282              :          end if
     283              : 
     284            2 :          if (set_dt < 1d-7) set_dt = 1d-7  ! there's a limit to everything
     285              : 
     286              :          b% max_timestep = exp10(b% dt_softening_factor*log10(b% max_timestep) + &
     287            2 :              (1-b% dt_softening_factor)*log10(set_dt*secyer))
     288              : 
     289              :          ! use variable varcontrols for different phases of evolution
     290            2 :          if (abs(b% mtransfer_rate)/Msun*secyer > 1d-20) then
     291            0 :             if (b% s_donor% center_h1 > 1d-12 .and. b% varcontrol_case_a > 0d0) then
     292            0 :                b% s_donor% varcontrol_target = b% varcontrol_case_a
     293            0 :                if (b% point_mass_i == 0) &
     294            0 :                    b% s_accretor% varcontrol_target = b% varcontrol_case_a
     295            0 :             else if (b% s_donor% center_h1 < 1d-12 .and. b% varcontrol_case_b > 0d0) then
     296            0 :                b% s_donor% varcontrol_target = b% varcontrol_case_b
     297            0 :                if (b% point_mass_i == 0) &
     298            0 :                    b% s_accretor% varcontrol_target = b% varcontrol_case_b
     299              :             end if
     300              :          else
     301            2 :             if (b% s_donor% center_h1 > 1d-12) then
     302            0 :                if (b% varcontrol_ms > 0d0) &
     303            0 :                    b% s_donor% varcontrol_target = b% varcontrol_ms
     304              :             else
     305            2 :                if (b% varcontrol_post_ms > 0d0) &
     306            0 :                    b% s_donor% varcontrol_target = b% varcontrol_post_ms
     307              :             end if
     308              : 
     309            2 :             if (b% point_mass_i == 0) then
     310            0 :                if (b% s_accretor% center_h1 > 1d-12) then
     311            0 :                   if (b% varcontrol_ms > 0d0) &
     312            0 :                       b% s_accretor% varcontrol_target = b% varcontrol_ms
     313              :                else
     314            0 :                   if (b% varcontrol_post_ms > 0d0) &
     315            0 :                       b% s_accretor% varcontrol_target = b% varcontrol_post_ms
     316              :                end if
     317              :             end if
     318              :          end if
     319              : 
     320            2 :          b% ignore_hard_limits_this_step = .false.
     321              : 
     322            2 :       end function binary_pick_next_timestep
     323              : 
     324              : 
     325              :       end module binary_timestep
        

Generated by: LCOV version 2.0-1