Line data Source code
1 : ! ***********************************************************************
2 : !
3 : ! Copyright (C) 2010-2019 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 : module report
21 :
22 : use star_private_def
23 : use chem_def
24 : use utils_lib
25 : use star_utils
26 : use num_lib, only: find0
27 : use const_def, only: avo, kerg, pi, amu, clight, crad, Rsun, Lsun, Msun, &
28 : secday, secyer, ln10, mev_amu, ev2erg, one_third, two_thirds, four_thirds_pi, &
29 : no_mixing, convective_mixing, semiconvective_mixing
30 :
31 : implicit none
32 :
33 : contains
34 :
35 33 : subroutine set_min_gamma1(s)
36 : type (star_info), pointer :: s
37 : integer :: k
38 33 : real(dp) :: vesc
39 : include 'formats'
40 33 : s% min_gamma1 = 1d99
41 18256 : do k = s% nz, 1, -1
42 18256 : if (s% q(k) > s% gamma1_limit_max_q) exit
43 18223 : vesc = sqrt(2*s% cgrav(k)*s% m(k)/(s% r(k)))
44 18223 : if (s% u_flag) then
45 0 : if (s% u(k) > vesc*s% gamma1_limit_max_v_div_vesc) exit
46 18223 : else if (s% v_flag) then
47 0 : if (s% v(k) > vesc*s% gamma1_limit_max_v_div_vesc) exit
48 : end if
49 18256 : if (s% gamma1(k) < s% min_gamma1) s% min_gamma1 = s% gamma1(k)
50 : end do
51 33 : end subroutine set_min_gamma1
52 :
53 :
54 11 : subroutine set_power_info(s)
55 : use chem_def, only: category_name
56 : type (star_info), pointer :: s
57 : integer :: j, k, nz
58 11 : real(dp) :: eps_nuc
59 : include 'formats'
60 11 : nz = s% nz
61 :
62 275 : do j=1,num_categories
63 : s% L_by_category(j) = &
64 314352 : dot_product(s% dm(1:nz), s% eps_nuc_categories(j,1:nz))/Lsun
65 264 : s% center_eps_burn(j) = center_value_eps_burn(j)
66 275 : if (is_bad(s% L_by_category(j))) then
67 0 : do k=1,nz
68 0 : if (is_bad(s% eps_nuc_categories(j,k))) then
69 0 : write(*,2) trim(category_name(j)) // ' eps_nuc logT', k, s% eps_nuc_categories(j,k), s% lnT(k)/ln10
70 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'set_power_info')
71 : end if
72 : end do
73 : end if
74 : end do
75 :
76 11 : if (s% eps_nuc_factor == 0d0) then
77 0 : s% power_nuc_burn = 0d0
78 0 : s% power_nuc_neutrinos = 0d0
79 0 : s% power_nonnuc_neutrinos = 0d0
80 0 : s% power_neutrinos = 0d0
81 0 : s% power_h_burn = 0d0
82 0 : s% power_he_burn = 0d0
83 0 : s% power_z_burn = 0d0
84 0 : s% power_photo = 0d0
85 : else
86 : ! better if set power_nuc_burn using eps_nuc instead of categories
87 : ! categories can be subject to numerical jitters at very high temperatures
88 11 : s% power_nuc_burn = 0d0
89 13098 : do k=1,nz
90 13087 : if (s% op_split_burn .and. s% T_start(k) >= s% op_split_burn_min_T) then
91 0 : eps_nuc = s% burn_avg_epsnuc(k)
92 : else
93 13087 : eps_nuc = s% eps_nuc(k)
94 : end if
95 13098 : s% power_nuc_burn = s% power_nuc_burn + eps_nuc*s% dm(k)
96 : end do
97 11 : s% power_nuc_burn = s% power_nuc_burn/Lsun
98 13098 : s% power_nuc_neutrinos = dot_product(s% dm(1:nz),s% eps_nuc_neu_total(1:nz))/Lsun
99 11 : s% power_h_burn = s% L_by_category(ipp) + s% L_by_category(icno)
100 11 : s% power_he_burn = s% L_by_category(i3alf)
101 11 : s% power_z_burn = s% power_nuc_burn - (s% power_h_burn + s% power_he_burn)
102 11 : s% power_photo = s% L_by_category(iphoto)
103 : end if
104 :
105 11 : if (s% non_nuc_neu_factor == 0d0) then
106 0 : s% power_nonnuc_neutrinos = 0d0
107 : else
108 : s% power_nonnuc_neutrinos = &
109 13098 : dot_product(s% dm(1:nz),s% non_nuc_neu(1:nz))/Lsun
110 : end if
111 11 : s% power_neutrinos = s% power_nuc_neutrinos + s% power_nonnuc_neutrinos
112 11 : s% L_nuc_burn_total = s% power_nuc_burn
113 :
114 : contains
115 :
116 264 : real(dp) function center_value_eps_burn(j)
117 : integer, intent(in) :: j
118 264 : real(dp) :: sum_x, sum_dq, dx, dq
119 : integer :: k
120 264 : sum_x = 0
121 264 : sum_dq = 0
122 264 : do k = s% nz, 1, -1
123 264 : dq = s% dq(k)
124 264 : dx = s% eps_nuc_categories(j,k)*dq
125 264 : if (sum_dq+dq >= s% center_avg_value_dq) then
126 264 : sum_x = sum_x + dx*(s% center_avg_value_dq - sum_dq)/dq
127 264 : sum_dq = s% center_avg_value_dq
128 264 : exit
129 : end if
130 0 : sum_x = sum_x + dx
131 0 : sum_dq = sum_dq + dq
132 : end do
133 264 : center_value_eps_burn = sum_x/sum_dq
134 11 : end function center_value_eps_burn
135 :
136 : end subroutine set_power_info
137 :
138 :
139 33 : subroutine do_report(s, ierr)
140 : use rates_def, only: &
141 : i_rate, i_rate_dRho, i_rate_dT
142 : use star_utils, only: get_phot_info
143 : use hydro_rotation, only: set_surf_avg_rotation_info
144 : type (star_info), pointer :: s
145 : integer, intent(out) :: ierr
146 :
147 : integer :: k, nz, h1, h2, he3, he4, c12, n14, o16, ne20, si28, co56, ni56, k_min, k_fe
148 33 : real(dp) :: radius, dr, non_fe_core_mass, nu_for_delta_Pg, v, mstar, luminosity, mass_sum
149 33 : integer, pointer :: net_iso(:)
150 : real(dp), pointer :: velocity(:) => null()
151 :
152 : include 'formats'
153 :
154 33 : ierr = 0
155 33 : nz = s% nz
156 33 : net_iso => s% net_iso
157 :
158 33 : h1 = net_iso(ih1)
159 33 : h2 = net_iso(ih2)
160 33 : he3 = net_iso(ihe3)
161 33 : he4 = net_iso(ihe4)
162 33 : c12 = net_iso(ic12)
163 33 : n14 = net_iso(in14)
164 33 : o16 = net_iso(io16)
165 33 : ne20 = net_iso(ine20)
166 33 : si28 = net_iso(isi28)
167 33 : co56 = net_iso(ico56)
168 33 : ni56 = net_iso(ini56)
169 :
170 33 : radius = s% r(1) ! radius in cm
171 33 : s% log_surface_radius = log10(radius/Rsun)
172 : ! log10(stellar radius in solar units)
173 33 : s% log_center_density = center_value(s, s% lnd)/ln10
174 40799 : s% log_max_temperature = maxval(s% lnT(1:nz))/ln10
175 33 : s% log_center_temperature = center_value(s, s% lnT)/ln10
176 33 : s% log_center_pressure = center_value(s, s% lnPeos)/ln10
177 33 : s% center_degeneracy = center_value(s, s% eta)
178 :
179 33 : s% center_eps_nuc = center_value(s, s% eps_nuc)
180 :
181 33 : s% d_center_eps_nuc_dlnT = center_value(s, s% d_epsnuc_dlnT)
182 33 : s% d_center_eps_nuc_dlnd = center_value(s, s% d_epsnuc_dlnd)
183 33 : s% center_non_nuc_neu = center_value(s, s% non_nuc_neu)
184 :
185 33 : s% center_abar = center_value(s, s% abar)
186 33 : s% center_zbar = center_value(s, s% zbar)
187 33 : s% center_mu = center_value(s, s% mu)
188 33 : s% center_ye = center_value(s, s% ye)
189 33 : s% center_entropy = exp(center_value(s, s% lnS))*amu/kerg
190 40799 : s% max_entropy = exp(maxval(s% lnS(1:nz)))*amu/kerg
191 :
192 33 : if (.not. s% rotation_flag) then
193 40766 : s% omega(1:nz) = 0
194 33 : s% center_omega = 0
195 33 : s% center_omega_div_omega_crit = 0
196 : else
197 0 : s% center_omega = center_value(s, s% omega)
198 0 : s% center_omega_div_omega_crit = center_omega_div_omega_crit()
199 : end if
200 :
201 33 : luminosity = s% L(1)
202 :
203 33 : if (s% u_flag) then
204 0 : s% v_surf = s% u(1)
205 33 : else if (s% v_flag) then
206 0 : s% v_surf = s% v(1)
207 : else
208 33 : s% v_surf = 0d0
209 : end if
210 :
211 33 : call set_surf_avg_rotation_info(s)
212 :
213 33 : call set_min_gamma1(s)
214 :
215 : ! s% time is in seconds
216 33 : s% star_age = s% time/secyer
217 33 : s% time_years = s% time/secyer
218 33 : s% time_days = s% time/secday
219 33 : if ( s% model_number <= 0 ) then
220 1 : s% star_age = 0d0
221 1 : s% time_days = 0d0
222 1 : s% time_years = 0d0
223 : end if
224 :
225 : ! s% dt is in seconds
226 33 : s% time_step = s% dt/secyer ! timestep in years
227 33 : s% dt_years = s% dt/secyer
228 33 : s% dt_days = s% dt/secday
229 :
230 33 : mstar = s% mstar
231 33 : s% star_mass = mstar/Msun ! stellar mass in solar units
232 :
233 33 : s% kh_timescale = eval_kh_timescale(s% cgrav(1), mstar, radius, luminosity)/secyer
234 : ! kelvin-helmholtz timescale in years (about 1.6x10^7 for the sun)
235 :
236 33 : if (is_bad(s% kh_timescale)) then
237 0 : write(*,1) 's% kh_timescale', s% kh_timescale
238 0 : write(*,1) 's% cgrav(1)', s% cgrav(1)
239 0 : write(*,1) 'mstar', mstar
240 0 : write(*,1) 'radius', radius
241 0 : write(*,1) 'luminosity', luminosity
242 0 : stop
243 : end if
244 :
245 33 : if (luminosity > 0d0) then
246 33 : s% nuc_timescale = 1d10*s% star_mass/(luminosity/Lsun)
247 : else
248 0 : s% nuc_timescale = 1d99
249 : end if
250 : ! nuclear timescale in years (e.g., about 10^10 years for sun)
251 33 : if (s% cgrav(1) <= 0d0) then
252 0 : s% dynamic_timescale = 1d99
253 : else
254 33 : s% dynamic_timescale = 2*pi*sqrt(radius*radius*radius/(s% cgrav(1)*mstar))
255 : end if
256 :
257 : ! center_avg_x and surface_avg_x check if the species is not in the net
258 : ! and set's the values to 0 if so. So dont check species here.
259 33 : s% center_h1 = center_avg_x(s,h1)
260 33 : s% surface_h1 = surface_avg_x(s,h1)
261 33 : s% center_he3 = center_avg_x(s,he3)
262 33 : s% surface_he3 = surface_avg_x(s,he3)
263 33 : s% center_he4 = center_avg_x(s,he4)
264 33 : s% surface_he4 = surface_avg_x(s,he4)
265 33 : s% center_c12 = center_avg_x(s,c12)
266 33 : s% surface_c12 = surface_avg_x(s,c12)
267 33 : s% center_n14 = center_avg_x(s,n14)
268 33 : s% surface_n14 = surface_avg_x(s,n14)
269 33 : s% center_o16 = center_avg_x(s,o16)
270 33 : s% surface_o16 = surface_avg_x(s,o16)
271 33 : s% center_ne20 = center_avg_x(s,ne20)
272 33 : s% surface_ne20 = surface_avg_x(s,ne20)
273 33 : s% center_si28 = center_avg_x(s,si28)
274 :
275 : ! FYI profile stuff
276 40766 : do k=1,nz
277 :
278 40733 : s% entropy(k) = exp(s% lnS(k))/(avo*kerg)
279 40733 : if (is_bad(s% entropy(k))) then
280 0 : ierr = -1
281 0 : write(*,2) 'report: s% entropy(k)', k, s% entropy(k)
282 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'report')
283 0 : return
284 : end if
285 :
286 40733 : if (k == nz) then
287 33 : dr = s% r(k) - s% R_center
288 : else
289 40700 : dr = s% r(k) - s% r(k+1)
290 : end if
291 :
292 40733 : s% dr_div_csound(k) = dr/s% csound(k)
293 40733 : if (is_bad(s% dr_div_csound(k))) then
294 0 : ierr = -1
295 0 : write(*,2) 'report: s% dr_div_csound(k)', &
296 0 : k, s% dr_div_csound(k), dr, s% csound(k)
297 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'report')
298 0 : return
299 : end if
300 :
301 40733 : if (s% u_flag) then
302 0 : v = s% u(k)
303 40733 : else if (s% v_flag) then
304 0 : v = s% v(k)
305 : else
306 40733 : v = 0d0
307 : end if
308 :
309 40733 : if (is_bad(v)) then
310 0 : ierr = -1
311 0 : write(*,2) 'report: v', k, v
312 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'report')
313 0 : return
314 : end if
315 :
316 40733 : s% v_div_csound(k) = v/s% csound_face(k)
317 40766 : if (is_bad(s% v_div_csound(k))) then
318 0 : ierr = -1
319 0 : write(*,2) 'report: s% v_div_csound(k)', k, s% v_div_csound(k), &
320 0 : v, s% csound_face(k)
321 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'report')
322 0 : return
323 : end if
324 :
325 : end do
326 :
327 33 : call set_phot_info(s)
328 :
329 33 : if (s% photosphere_r*Rsun >= s% r(1)) then
330 : s% photosphere_acoustic_r = sum(s% dr_div_csound(1:nz)) + &
331 40766 : (s% photosphere_r*Rsun - s% r(1))/s% csound(1)
332 : else
333 0 : do k=2,nz
334 0 : if (s% photosphere_r*Rsun > s% r(k)) then
335 : s% photosphere_acoustic_r = sum(s% dr_div_csound(k:nz)) + &
336 0 : (s% photosphere_r*Rsun - s% r(k))/s% csound(k-1)
337 0 : exit
338 : end if
339 : end do
340 : end if
341 :
342 33 : if (.not. s% get_delta_nu_from_scaled_solar) then
343 33 : s% delta_nu = 1d6/(2*s% photosphere_acoustic_r) ! microHz
344 : else
345 : s% delta_nu = &
346 : s% delta_nu_sun*sqrt(s% star_mass)*pow3(s% Teff/s% astero_Teff_sun) / &
347 0 : pow(s% L_phot,0.75d0)
348 : end if
349 :
350 33 : call get_mass_info(s, s% dm, ierr)
351 33 : if (failed('get_mass_info')) return
352 :
353 : s% nu_max = s% nu_max_sun*s% star_mass/ &
354 33 : (pow2(s% photosphere_r)*sqrt(max(0d0,s% Teff)/s% astero_Teff_sun))
355 : s% acoustic_cutoff = &
356 33 : 0.25d6/pi*s% grav(1)*sqrt(s% gamma1(1)*s% rho(1)/s% Peos(1))
357 33 : nu_for_delta_Pg = s% nu_max
358 33 : if (s% delta_Pg_mode_freq > 0) nu_for_delta_Pg = s% delta_Pg_mode_freq
359 33 : if ( .not. s% delta_Pg_traditional) then
360 0 : call get_delta_Pg_bildsten2012(s, nu_for_delta_Pg, s% delta_Pg)
361 : else
362 33 : call get_delta_Pg_traditional(s, s% delta_Pg)
363 : end if
364 :
365 33 : if (s% rsp_flag) return
366 :
367 33 : call get_mixing_regions(s, ierr)
368 33 : if (failed('get_mixing_regions')) return
369 :
370 33 : call set_mass_conv_core
371 33 : call set_mass_semiconv_core
372 33 : call find_conv_mx_regions
373 33 : call find_mx_regions
374 33 : call get_burn_zone_info(s, ierr)
375 33 : if (failed('get_burn_zone_info')) return
376 :
377 :
378 33 : s% fe_core_infall = 0d0
379 33 : s% non_fe_core_infall = 0d0
380 33 : s% non_fe_core_rebound = 0d0
381 33 : s% max_infall_speed_mass = 0d0
382 33 : k_fe = -1 ! initialize, in case u_flag & v_flag = .false.
383 33 : k_min = -1 ! initialize, in case u_flag & v_flag = .false.
384 :
385 66 : if(s% u_flag .or. s% v_flag) then
386 :
387 0 : if(s% u_flag) then
388 0 : velocity => s% u
389 : else
390 0 : velocity => s% v
391 : end if
392 0 : k_min = minloc(velocity(1:nz), dim=1)
393 :
394 0 : s% max_infall_speed_mass = s% m(k_min)/Msun
395 :
396 0 : mass_sum = 0d0
397 0 : if (s% fe_core_mass > 0) then
398 : ! check if [> fe_core_infall_mass] of core is infalling
399 : ! instead of a for loop, we move inside out and only check regions inside the fe_core
400 0 : k = nz
401 0 : do while (k > 1)
402 0 : if (s% m(k) > Msun * s% fe_core_mass) exit ! exit when outside Fe core
403 0 : if (-velocity(k) > s% fe_core_infall) then
404 0 : mass_sum = mass_sum + s% dm(k)
405 : end if
406 0 : k = k-1 ! loop outwards
407 : end do
408 0 : k_fe = k ! mark fe_core_mass boundary cell location, k_fe = nz if no fe_core
409 :
410 0 : if (s% report_max_infall_inside_fe_core) then ! report peak infall velocity inside fe_core (not necessarily the maximum, since infall tends to start outside in)
411 0 : if (mass_sum > s% fe_core_infall_mass*msun) then ! prevents toggling when k == nz
412 0 : s% fe_core_infall = - minval(s%v(k_fe:nz))
413 : end if
414 : else !(default in r24.03.1 prior) report max infall velocity anywhere
415 0 : if(mass_sum > s% fe_core_infall_mass*msun) then
416 0 : s% fe_core_infall = -velocity(k_min)
417 : end if
418 : end if
419 : end if
420 :
421 0 : non_fe_core_mass = s% he_core_mass
422 0 : mass_sum = 0d0
423 :
424 0 : if (non_fe_core_mass > 0) then
425 0 : do k=1, nz
426 0 : if (s% m(k) > Msun * non_fe_core_mass) cycle
427 0 : if (s% m(k) < Msun * s% fe_core_mass) exit
428 0 : if(-velocity(k) > s% non_fe_core_infall) mass_sum = mass_sum + s% dm(k)
429 : end do
430 :
431 0 : if ((mass_sum > s% non_fe_core_infall_mass*msun) .and. &
432 : (s%m(k_min) <= s% he_core_mass * msun)) then
433 0 : s% non_fe_core_infall = -velocity(k_min)
434 : end if
435 :
436 0 : s% non_fe_core_rebound = maxval(velocity(s%he_core_k:s%fe_core_k),dim=1)
437 :
438 : end if
439 :
440 0 : nullify(velocity)
441 : end if
442 :
443 :
444 : contains
445 :
446 :
447 99 : logical function failed(str)
448 : character (len=*), intent(in) :: str
449 99 : failed = (ierr /= 0)
450 99 : if (failed) then
451 0 : write(*, *) trim(str) // ' ierr', ierr
452 : end if
453 33 : end function failed
454 :
455 :
456 33 : subroutine set_mass_conv_core
457 : integer :: j, nz, k
458 33 : real(dp) :: dm_limit
459 : include 'formats'
460 33 : s% mass_conv_core = 0
461 33 : dm_limit = s% conv_core_gap_dq_limit*s% xmstar
462 33 : nz = s% nz
463 33 : do j = 1, s% n_conv_regions
464 : ! ignore possible small gap at center
465 33 : if (s% cz_bot_mass(j) <= s% m(nz) + dm_limit) then
466 32 : s% mass_conv_core = s% cz_top_mass(j)/Msun
467 : ! jump over small gaps
468 32 : do k = j+1, s% n_conv_regions
469 32 : if (s% cz_bot_mass(k) - s% cz_top_mass(k-1) >= dm_limit) exit
470 32 : s% mass_conv_core = s% cz_top_mass(k)/Msun
471 : end do
472 : exit
473 : end if
474 : end do
475 33 : end subroutine set_mass_conv_core
476 :
477 :
478 33 : subroutine set_mass_semiconv_core
479 : integer :: k, ktop, nz
480 33 : real(dp) :: qb
481 : include 'formats'
482 33 : s% mass_semiconv_core = s% mass_conv_core
483 33 : nz = s% nz
484 33 : if (s% mixing_type(nz) /= convective_mixing) return
485 33 : ktop = 1
486 33 : do k=nz-1,1,-1
487 33 : if (s% mixing_type(k) == convective_mixing) then
488 : ktop = k
489 : exit
490 : end if
491 : end do
492 33 : if (ktop == 1 .or. s% mixing_type(ktop) /= semiconvective_mixing) return
493 0 : do k=ktop-1,1,-1
494 0 : if (s% mixing_type(k) /= semiconvective_mixing) then
495 0 : qb = s% q(k) - s% cz_bdy_dq(k)
496 0 : s% mass_semiconv_core = (qb*s% xmstar + s% M_center)/Msun
497 0 : return
498 : end if
499 : end do
500 0 : s% mass_semiconv_core = s% star_mass
501 : end subroutine set_mass_semiconv_core
502 :
503 :
504 : real(dp) function volume_at_q(q)
505 : use interp_1d_def
506 : use interp_1d_lib
507 : real(dp), intent(in) :: q
508 : integer, parameter :: n_old = 4, n_new = 1, nwork = pm_work_size
509 : real(dp) :: qlo, x_old(n_old), v_old(n_old), x_new(n_new), v_new(n_new)
510 : integer :: k, nz, k00, ierr
511 : real(dp), target :: work_ary(n_old*nwork)
512 : real(dp), pointer :: work(:)
513 : work => work_ary
514 :
515 : include 'formats'
516 : nz = s% nz
517 :
518 : if (q == 0d0) then
519 : volume_at_q = 0
520 : return
521 : end if
522 :
523 : if (q <= s% q(nz)) then
524 : volume_at_q = (q/s% q(nz))*four_thirds_pi*s% r(nz)*s% r(nz)*s% r(nz)
525 : return
526 : end if
527 : k00 = 1
528 : do k=nz-1,2,-1
529 : if (s% q(k) >= q) then
530 : k00 = k; exit
531 : end if
532 : end do
533 : if (k00 == 1) then
534 : volume_at_q = four_thirds_pi*q*s% r(1)*s% r(1)*s% r(1)
535 : write(*,1) 'volume_at_q', volume_at_q
536 : return
537 : end if
538 :
539 : x_old(1) = 0
540 : if (k00+1 == nz) then
541 : v_old(1) = s% R_center*s% R_center*s% R_center
542 : qlo = 0
543 : else
544 : v_old(1) = s% r(k00+2)*s% r(k00+2)*s% r(k00+2)
545 : qlo = s% q(k00+2)
546 : end if
547 :
548 : x_old(2) = s% dq(k00+1)
549 : v_old(2) = s% r(k00+1)*s% r(k00+1)*s% r(k00+1)
550 :
551 : x_old(3) = x_old(2) + s% dq(k00)
552 : v_old(3) = s% r(k00)*s% r(k00)*s% r(k00)
553 :
554 : x_old(4) = x_old(3) + s% dq(k00-1)
555 : v_old(4) = s% r(k00-1)*s% r(k00-1)*s% r(k00-1)
556 :
557 : ierr = 0
558 : x_new(1) = q-qlo
559 : call interpolate_vector( &
560 : n_old, x_old, n_new, x_new, v_old, v_new, interp_pm, nwork, work, &
561 : 'report volume_at_q', ierr)
562 : if (ierr /= 0) then
563 : write(*,*) 'volume_at_q: failed in interpolate_vector'
564 : volume_at_q = (v_old(2) + v_old(3))/2
565 : return
566 : end if
567 :
568 : volume_at_q = four_thirds_pi*v_new(1)
569 :
570 : end function volume_at_q
571 :
572 :
573 0 : real(dp) function center_omega_div_omega_crit()
574 0 : real(dp) :: sum_x, sum_dq, dx, dq
575 : integer :: k
576 0 : center_omega_div_omega_crit = 0
577 0 : if (.not. s% rotation_flag) return
578 0 : sum_x = 0
579 0 : sum_dq = 0
580 0 : do k = s% nz, 1, -1
581 0 : dq = s% dq(k)
582 0 : dx = dq*s% omega(k)/omega_crit(s,k)
583 0 : if (sum_dq+dq >= s% center_avg_value_dq) then
584 0 : sum_x = sum_x+ dx*(s% center_avg_value_dq - sum_dq)/dq
585 0 : sum_dq = s% center_avg_value_dq
586 0 : exit
587 : end if
588 0 : sum_x = sum_x + dx
589 0 : sum_dq = sum_dq + dq
590 : end do
591 0 : center_omega_div_omega_crit = min(1d0,sum_x/sum_dq)
592 0 : end function center_omega_div_omega_crit
593 :
594 :
595 33 : subroutine find_conv_mx_regions
596 33 : real(dp) :: conv_mx1_dq, conv_mx2_dq, mx_dq
597 : integer :: i, ktop, kbot, conv_mx1, conv_mx2
598 :
599 : include 'formats'
600 :
601 33 : s% largest_conv_mixing_region = 0
602 :
603 33 : s% conv_mx1_top = 0
604 33 : s% conv_mx1_bot = 0
605 33 : s% conv_mx2_top = 0
606 33 : s% conv_mx2_bot = 0
607 :
608 33 : s% conv_mx1_top_r = 0
609 33 : s% conv_mx1_bot_r = 0
610 33 : s% conv_mx2_top_r = 0
611 33 : s% conv_mx2_bot_r = 0
612 :
613 33 : if (s% num_mixing_regions == 0) return
614 :
615 : conv_mx1 = 0
616 : conv_mx2 = 0
617 : conv_mx1_dq = 0
618 : conv_mx2_dq = 0
619 :
620 102 : do i = 1, s% num_mixing_regions
621 69 : if (s% mixing_region_type(i) /= convective_mixing) cycle
622 : ! mx_dq = s% q(s% mixing_region_top(i)) - s% q(s% mixing_region_bottom(i))
623 6070 : mx_dq = sum(s% dq(s% mixing_region_top(i):s% mixing_region_bottom(i)))
624 102 : if (mx_dq > conv_mx1_dq) then
625 : conv_mx2_dq = conv_mx1_dq; conv_mx1_dq = mx_dq
626 : conv_mx2 = conv_mx1; conv_mx1 = i
627 0 : else if (mx_dq > conv_mx2_dq) then
628 69 : conv_mx2_dq = mx_dq
629 69 : conv_mx2 = i
630 : end if
631 : end do
632 :
633 33 : if (conv_mx1 > 0) then
634 33 : s% largest_conv_mixing_region = conv_mx1
635 33 : ktop = s% mixing_region_top(conv_mx1)
636 33 : kbot = s% mixing_region_bottom(conv_mx1)
637 33 : s% conv_mx1_top = s% q(ktop) - s% cz_bdy_dq(ktop)
638 33 : s% conv_mx1_bot = s% q(kbot) - s% cz_bdy_dq(kbot)
639 33 : s% conv_mx1_top_r = s% r(ktop)/Rsun
640 33 : s% conv_mx1_bot_r = s% r(kbot)/Rsun
641 : end if
642 :
643 33 : if (conv_mx2 > 0) then
644 33 : ktop = s% mixing_region_top(conv_mx2)
645 33 : kbot = s% mixing_region_bottom(conv_mx2)
646 33 : s% conv_mx2_top = s% q(ktop) - s% cz_bdy_dq(ktop)
647 33 : s% conv_mx2_bot = s% q(kbot) - s% cz_bdy_dq(kbot)
648 33 : s% conv_mx2_top_r = s% r(ktop)/Rsun
649 33 : s% conv_mx2_bot_r = s% r(kbot)/Rsun
650 : end if
651 :
652 : end subroutine find_conv_mx_regions
653 :
654 :
655 33 : subroutine find_mx_regions
656 33 : real(dp) :: mx1_dq, mx2_dq, mx_dq
657 : integer :: i, ktop, kbot, mx1_top_region, mx1_bottom_region, &
658 : mx2_top_region, mx2_bottom_region, &
659 : current_top_region, current_bottom_region, &
660 : current_top_point, current_bottom_point
661 :
662 : include 'formats'
663 :
664 33 : s% mx1_top = 0
665 33 : s% mx1_bot = 0
666 33 : s% mx2_top = 0
667 33 : s% mx2_bot = 0
668 :
669 33 : s% mx1_top_r = 0
670 33 : s% mx1_bot_r = 0
671 33 : s% mx2_top_r = 0
672 33 : s% mx2_bot_r = 0
673 :
674 33 : if (s% num_mixing_regions == 0) return
675 :
676 : mx1_top_region = 0
677 : mx1_bottom_region = 0
678 : mx1_dq = 0
679 :
680 : mx2_top_region = 0
681 : mx2_bottom_region = 0
682 : mx2_dq = 0
683 :
684 : i = 1
685 : do
686 102 : if (i > s% num_mixing_regions) exit
687 69 : current_top_region = i
688 69 : current_top_point = s% mixing_region_top(current_top_region)
689 : do
690 69 : current_bottom_region = i
691 69 : current_bottom_point = s% mixing_region_bottom(current_bottom_region)
692 69 : i = i+1
693 69 : if (i > s% num_mixing_regions) exit
694 69 : if (s% mixing_region_top(i) /= current_bottom_point+1) exit
695 : end do
696 : ! mx_dq = s% q(current_top_point) - s% q(current_bottom_point)
697 6070 : mx_dq = sum(s% dq(current_top_point:current_bottom_point))
698 102 : if (mx_dq > mx1_dq) then
699 : mx2_dq = mx1_dq; mx1_dq = mx_dq
700 : mx2_top_region = mx1_top_region
701 : mx1_top_region = current_top_region
702 : mx2_bottom_region = mx1_bottom_region
703 : mx1_bottom_region = current_bottom_region
704 0 : else if (mx_dq > mx2_dq) then
705 0 : mx2_dq = mx_dq
706 0 : mx2_top_region = current_top_region
707 0 : mx2_bottom_region = current_bottom_region
708 : end if
709 : end do
710 :
711 33 : if (mx1_top_region > 0) then
712 33 : ktop = s% mixing_region_top(mx1_top_region)
713 33 : kbot = s% mixing_region_bottom(mx1_bottom_region)
714 33 : s% mx1_top = s% q(ktop) - s% cz_bdy_dq(ktop)
715 33 : s% mx1_bot = s% q(kbot) - s% cz_bdy_dq(kbot)
716 33 : s% mx1_top_r = s% r(ktop)/Rsun
717 33 : s% mx1_bot_r = s% r(kbot)/Rsun
718 : end if
719 :
720 33 : if (mx2_top_region > 0) then
721 33 : ktop = s% mixing_region_top(mx2_top_region)
722 33 : kbot = s% mixing_region_bottom(mx2_bottom_region)
723 33 : s% mx2_top = s% q(ktop) - s% cz_bdy_dq(ktop)
724 33 : s% mx2_bot = s% q(kbot) - s% cz_bdy_dq(kbot)
725 33 : s% mx2_top_r = s% r(ktop)/Rsun
726 33 : s% mx2_bot_r = s% r(kbot)/Rsun
727 : end if
728 :
729 : end subroutine find_mx_regions
730 :
731 :
732 : end subroutine do_report
733 :
734 :
735 33 : subroutine get_burn_zone_info(s, ierr)
736 : type (star_info), pointer :: s
737 : integer, intent(out) :: ierr
738 33 : real(dp) :: burn_min1, burn_min2
739 : integer :: i, i_start
740 : include 'formats'
741 33 : burn_min1 = s% burn_min1; burn_min2 = s% burn_min2
742 : ! up to 3 zones where eps_nuc > burn_min1 erg/g/s
743 : ! for each zone have 4 numbers: start1, start2, end2, end1
744 : ! start1 is mass of inner edge where first goes > burn_min1 (or -20 if none such)
745 : ! start2 is mass of inner edge where first zone reaches burn_min2 erg/g/sec (or -20 if none such)
746 : ! end2 is mass of outer edge where first zone drops back below burn_min2 erg/g/s
747 : ! end1 is mass of outer edge where first zone ends (i.e. eps_nuc < burn_min1)
748 : ! similar for second and third zones
749 33 : i_start = s% nz
750 132 : do i=1,3
751 : call find_epsnuc_zone(s, i_start, &
752 : s% burn_zone_mass(1,i), s% burn_zone_mass(2,i), &
753 : s% burn_zone_mass(3,i), s% burn_zone_mass(4,i), &
754 132 : s% burn_min1, s% burn_min2, ierr)
755 : end do
756 33 : end subroutine get_burn_zone_info
757 :
758 :
759 99 : subroutine find_epsnuc_zone( &
760 : s, i_start, bzm_1, bzm_2, bzm_3, bzm_4, burn_min1, burn_min2, ierr)
761 : type (star_info), pointer :: s
762 : integer, intent(inout) :: i_start
763 : real(dp), intent(out) :: bzm_1, bzm_2, bzm_3, bzm_4
764 : real(dp), intent(in) :: burn_min1, burn_min2
765 : integer, intent(out) :: ierr
766 :
767 : real(dp), parameter :: null_zone = -20
768 : integer :: i, burn_zone
769 99 : real(dp) :: prev_m, prev_x, cur_m, cur_x
770 99 : ierr = 0
771 99 : bzm_1 = null_zone; bzm_2 = null_zone; bzm_3 = null_zone; bzm_4 = null_zone
772 99 : burn_zone = 0 ! haven't entered the zone yet
773 99 : if (i_start /= s% nz) then
774 66 : i = i_start+1
775 66 : prev_m = s% m(i)
776 66 : prev_x = s% eps_nuc(i)
777 : else ! keep the compiler happy
778 33 : prev_m = 0
779 33 : prev_x = 0
780 : end if
781 40832 : do i = i_start, 1, -1
782 40766 : cur_m = s% m(i)
783 40766 : cur_x = s% eps_nuc(i)
784 36981 : select case (burn_zone)
785 : case (0)
786 36981 : if ( cur_x > burn_min2 ) then
787 33 : if ( i == s% nz ) then ! use star center as start of zone
788 33 : bzm_2 = 0d0
789 : else ! interpolate to estimate where rate reached burn_min1
790 0 : bzm_2 = find0(prev_m, prev_x-burn_min2, cur_m, cur_x-burn_min2)
791 : end if
792 33 : bzm_1 = bzm_2
793 33 : burn_zone = 2
794 36948 : elseif ( cur_x > burn_min1 ) then
795 0 : if ( i == s% nz ) then ! use star center as start of zone
796 0 : bzm_1 = 0d0
797 : else ! interpolate to estimate where rate reached burn_min1
798 0 : bzm_1 = find0(prev_m, prev_x-burn_min1, cur_m, cur_x-burn_min1)
799 : end if
800 : burn_zone = 1
801 : end if
802 : case (1) ! in the initial eps > burn_min1 region
803 0 : if ( cur_x > burn_min2 ) then
804 0 : bzm_2 = find0(prev_m, prev_x-burn_min2, cur_m, cur_x-burn_min2)
805 0 : burn_zone = 2
806 0 : else if ( cur_x < burn_min1 ) then
807 0 : bzm_4 = find0(prev_m, prev_x-burn_min1, cur_m, cur_x-burn_min1)
808 0 : i_start = i
809 99 : return
810 : end if
811 : case (2) ! in the initial eps > burn_min2 region
812 1429 : if ( cur_x < burn_min1 ) then
813 0 : bzm_4 = find0(prev_m, prev_x-burn_min1, cur_m, cur_x-burn_min1)
814 0 : bzm_3 = bzm_4
815 0 : i_start = i
816 0 : return
817 : end if
818 1429 : if ( cur_x < burn_min2 ) then
819 33 : bzm_3 = find0(prev_m, prev_x-burn_min2, cur_m, cur_x-burn_min2)
820 33 : burn_zone = 3
821 : end if
822 : case (3) ! in the final eps > burn_min1 region
823 2356 : if ( cur_x < burn_min1 ) then
824 33 : bzm_4 = find0(prev_m, prev_x-burn_min1, cur_m, cur_x-burn_min1)
825 33 : i_start = i
826 33 : return
827 : end if
828 : case default
829 : ierr = -1
830 : write(*,*) 'error in find_eps_nuc_zone'
831 40766 : return
832 : end select
833 40799 : prev_m = cur_m; prev_x = cur_x
834 : end do
835 66 : i_start = 0
836 : select case (burn_zone)
837 : case (0)
838 0 : return
839 : case (1)
840 0 : bzm_4 = cur_m
841 : case (2)
842 0 : bzm_3 = cur_m
843 0 : bzm_4 = cur_m
844 : case (3)
845 0 : bzm_4 = cur_m
846 : case default
847 : ierr = -1
848 : write(*,*) 'error in find_eps_nuc_zone'
849 66 : return
850 : end select
851 : end subroutine find_epsnuc_zone
852 :
853 :
854 33 : subroutine get_mass_info(s, cell_masses, ierr)
855 : type (star_info), pointer :: s
856 : real(dp), pointer, intent(in) :: cell_masses(:)
857 : integer, intent(out) :: ierr
858 :
859 : integer :: k, nz, j
860 33 : real(dp) :: cell_mass
861 33 : integer, pointer :: net_iso(:)
862 :
863 : include 'formats'
864 :
865 33 : ierr = 0
866 33 : nz = s% nz
867 33 : net_iso => s% net_iso
868 :
869 33 : s% star_mass_h1=0d0
870 33 : s% star_mass_he3=0d0
871 33 : s% star_mass_he4=0d0
872 33 : s% star_mass_c12 = 0d0
873 33 : s% star_mass_n14 = 0d0
874 33 : s% star_mass_o16 = 0d0
875 33 : s% star_mass_ne20 = 0d0
876 :
877 40766 : do k = 1, nz
878 40733 : cell_mass = cell_masses(k)
879 366630 : do j=1, s% species
880 366597 : if (s% chem_id(j) == ih1) then
881 40733 : s% star_mass_h1 = s% star_mass_h1 + cell_mass*s% xa(j, k)
882 285131 : else if (s% chem_id(j) == ihe3) then
883 40733 : s% star_mass_he3 = s% star_mass_he3 + cell_mass*s% xa(j, k)
884 244398 : else if (s% chem_id(j) == ihe4) then
885 40733 : s% star_mass_he4 = s% star_mass_he4 + cell_mass*s% xa(j, k)
886 203665 : else if (s% chem_id(j) == ic12) then
887 40733 : s% star_mass_c12 = s% star_mass_c12 + cell_mass*s% xa(j, k)
888 162932 : else if (s% chem_id(j) == in14) then
889 40733 : s% star_mass_n14 = s% star_mass_n14 + cell_mass*s% xa(j, k)
890 122199 : else if (s% chem_id(j) == io16) then
891 40733 : s% star_mass_o16 = s% star_mass_o16 + cell_mass*s% xa(j, k)
892 81466 : else if (s% chem_id(j) == ine20) then
893 40733 : s% star_mass_ne20 = s% star_mass_ne20 + cell_mass*s% xa(j, k)
894 : end if
895 : end do
896 : end do
897 :
898 33 : s% star_mass_h1 = s% star_mass_h1 / Msun
899 33 : s% star_mass_he3 = s% star_mass_he3 / Msun
900 33 : s% star_mass_he4 = s% star_mass_he4 / Msun
901 33 : s% star_mass_c12 = s% star_mass_c12 / Msun
902 33 : s% star_mass_n14 = s% star_mass_n14 / Msun
903 33 : s% star_mass_o16 = s% star_mass_o16 / Msun
904 33 : s% star_mass_ne20 = s% star_mass_ne20 / Msun
905 :
906 33 : call get_core_info(s)
907 33 : call get_shock_info(s)
908 :
909 33 : end subroutine get_mass_info
910 :
911 :
912 0 : subroutine get_info_at_surface( &
913 : s, bdy_m, bdy_r, bdy_lgT, bdy_lgRho, bdy_L, bdy_v, bdy_time, &
914 : bdy_omega, bdy_omega_div_omega_crit)
915 : type (star_info), pointer :: s
916 : real(dp), intent(out) :: &
917 : bdy_m, bdy_r, bdy_lgT, bdy_lgRho, bdy_L, bdy_v, &
918 : bdy_omega, bdy_omega_div_omega_crit, bdy_time
919 :
920 0 : real(dp) :: bdy_omega_crit
921 :
922 0 : bdy_time = 0
923 0 : bdy_m = s% star_mass
924 0 : bdy_r = s% r(1)/Rsun
925 0 : bdy_lgT = s% lnT(1)/ln10
926 0 : bdy_lgRho = s% lnd(1)/ln10
927 0 : bdy_L = s% L(1)/Lsun
928 0 : if (s% v_flag) then
929 0 : bdy_v = s% v(1)
930 0 : else if (s% u_flag) then
931 0 : bdy_v = s% u_face_ad(1)%val
932 : else
933 0 : bdy_v = 0d0
934 : end if
935 0 : if (s% rotation_flag) then
936 0 : bdy_omega = s% omega_avg_surf
937 0 : bdy_omega_crit = s% omega_crit_avg_surf
938 0 : bdy_omega_div_omega_crit = s% w_div_w_crit_avg_surf
939 : else
940 0 : bdy_omega = 0
941 0 : bdy_omega_div_omega_crit = 0
942 : end if
943 :
944 0 : end subroutine get_info_at_surface
945 :
946 :
947 0 : subroutine get_mach1_location_info( &
948 : s, dbg, k_shock, v, r, &
949 : mach1_mass, &
950 : mach1_q, &
951 : mach1_radius, &
952 : mach1_velocity, &
953 : mach1_csound, &
954 : mach1_lgT, &
955 : mach1_lgRho, &
956 : mach1_lgP, &
957 : mach1_gamma1, &
958 : mach1_entropy, &
959 : mach1_tau, &
960 : mach1_k)
961 : type (star_info), pointer :: s
962 : integer, intent(in) :: k_shock
963 : logical, intent(in) :: dbg
964 : real(dp), intent(in), pointer :: v(:)
965 : real(dp), intent(in) :: r
966 : real(dp), intent(out) :: &
967 : mach1_mass, &
968 : mach1_q, &
969 : mach1_radius, &
970 : mach1_velocity, &
971 : mach1_csound, &
972 : mach1_lgT, &
973 : mach1_lgRho, &
974 : mach1_lgP, &
975 : mach1_gamma1, &
976 : mach1_entropy, &
977 : mach1_tau
978 : integer, intent(out) :: mach1_k
979 :
980 : integer :: k
981 0 : real(dp) :: alfa, beta
982 :
983 : include 'formats'
984 :
985 0 : k = k_shock
986 : if (r < s% R_center .or. r > s% r(1) .or. &
987 : k < 1 .or. k > s% nz .or. &
988 0 : .not. associated(v) .or. &
989 : .not. (s% v_flag .or. s% u_flag)) then
990 0 : mach1_mass = 0
991 0 : mach1_q = 0
992 0 : mach1_radius = 0
993 0 : mach1_velocity = 0
994 0 : mach1_csound = 0
995 0 : mach1_lgT = 0
996 0 : mach1_lgRho = 0
997 0 : mach1_lgP = 0
998 0 : mach1_gamma1 = 0
999 0 : mach1_entropy = 0
1000 0 : mach1_tau = 0
1001 0 : mach1_k = 0
1002 0 : return
1003 : end if
1004 :
1005 0 : mach1_radius = r/Rsun
1006 0 : mach1_k = k
1007 0 : if (k < s% nz) then
1008 0 : alfa = (r - s% r(k))/(s% r(k+1) - s% r(k))
1009 0 : beta = 1d0 - alfa
1010 0 : mach1_mass = (alfa*s% m(k+1) + beta*s% m(k))/Msun
1011 0 : mach1_q = alfa*s% q(k+1) + beta*s% q(k)
1012 0 : mach1_velocity = alfa*v(k+1) + beta*v(k)
1013 : else
1014 0 : mach1_mass = s% m(k)/Msun
1015 0 : mach1_q = s% q(k)
1016 0 : mach1_velocity = v(k)
1017 : end if
1018 0 : mach1_csound = s% csound(k)
1019 0 : mach1_lgT = s% lnT(k)/ln10
1020 0 : mach1_lgRho = s% lnd(k)/ln10
1021 0 : mach1_lgP = s% lnPeos(k)/ln10
1022 0 : mach1_gamma1 = s% gamma1(k)
1023 0 : mach1_entropy = s% entropy(k)
1024 0 : mach1_tau = s% tau(k)
1025 :
1026 : end subroutine get_mach1_location_info
1027 :
1028 :
1029 33 : subroutine get_core_info(s)
1030 : type (star_info), pointer :: s
1031 :
1032 : integer :: k, j, A_max, h1, he4, c12, o16, ne20, si28, species, nz
1033 33 : integer, pointer :: net_iso(:)
1034 : logical :: have_he, have_co, have_one, have_fe
1035 33 : real(dp) :: sumx, min_x
1036 : integer, parameter :: &
1037 : A_max_fe = 47, &
1038 : A_max_si = 28, &
1039 : A_max_one = 20, &
1040 : A_max_co = 16, &
1041 : A_max_he = 4
1042 :
1043 : include 'formats'
1044 :
1045 33 : net_iso => s% net_iso
1046 33 : species = s% species
1047 33 : nz = s% nz
1048 33 : h1 = net_iso(ih1)
1049 33 : he4 = net_iso(ihe4)
1050 33 : c12 = net_iso(ic12)
1051 33 : o16 = net_iso(io16)
1052 33 : ne20 = net_iso(ine20)
1053 33 : si28 = net_iso(isi28)
1054 33 : min_x = s% min_boundary_fraction
1055 :
1056 : call clear_core_info(s% neutron_rich_core_k, &
1057 : s% neutron_rich_core_mass, s% neutron_rich_core_radius, s% neutron_rich_core_lgT, &
1058 : s% neutron_rich_core_lgRho, s% neutron_rich_core_L, s% neutron_rich_core_v, &
1059 33 : s% neutron_rich_core_omega, s% neutron_rich_core_omega_div_omega_crit)
1060 :
1061 40766 : do k=1,nz
1062 40766 : if (s% Ye(k) <= s% neutron_rich_core_boundary_Ye_max) then
1063 : call set_core_info(s, k, s% neutron_rich_core_k, &
1064 : s% neutron_rich_core_mass, s% neutron_rich_core_radius, s% neutron_rich_core_lgT, &
1065 : s% neutron_rich_core_lgRho, s% neutron_rich_core_L, s% neutron_rich_core_v, &
1066 0 : s% neutron_rich_core_omega, s% neutron_rich_core_omega_div_omega_crit)
1067 0 : exit
1068 : end if
1069 : end do
1070 :
1071 : call clear_core_info(s% fe_core_k, &
1072 : s% fe_core_mass, s% fe_core_radius, s% fe_core_lgT, &
1073 : s% fe_core_lgRho, s% fe_core_L, s% fe_core_v, &
1074 33 : s% fe_core_omega, s% fe_core_omega_div_omega_crit)
1075 : call clear_core_info(s% co_core_k, &
1076 : s% co_core_mass, s% co_core_radius, s% co_core_lgT, &
1077 : s% co_core_lgRho, s% co_core_L, s% co_core_v, &
1078 33 : s% co_core_omega, s% co_core_omega_div_omega_crit)
1079 : call clear_core_info(s% one_core_k, &
1080 : s% one_core_mass, s% one_core_radius, s% one_core_lgT, &
1081 : s% one_core_lgRho, s% one_core_L, s% one_core_v, &
1082 33 : s% one_core_omega, s% one_core_omega_div_omega_crit)
1083 : call clear_core_info(s% he_core_k, &
1084 : s% he_core_mass, s% he_core_radius, s% he_core_lgT, &
1085 : s% he_core_lgRho, s% he_core_L, s% he_core_v, &
1086 33 : s% he_core_omega, s% he_core_omega_div_omega_crit)
1087 :
1088 33 : have_he = .false.
1089 33 : have_co = .false.
1090 33 : have_one = .false.
1091 33 : have_fe = .false.
1092 :
1093 40766 : do k=1,nz
1094 :
1095 407330 : j = maxloc(s% xa(1:species,k),dim=1)
1096 40733 : A_max = chem_isos% Z_plus_N(s% chem_id(j))
1097 :
1098 : if (.not. have_fe) then
1099 40733 : if (s% fe_core_boundary_si28_fraction < 0) then
1100 0 : if (A_max >= A_max_fe) then
1101 : call set_core_info(s, k, s% fe_core_k, &
1102 : s% fe_core_mass, s% fe_core_radius, s% fe_core_lgT, &
1103 : s% fe_core_lgRho, s% fe_core_L, s% fe_core_v, &
1104 0 : s% fe_core_omega, s% fe_core_omega_div_omega_crit)
1105 0 : exit
1106 : end if
1107 40733 : else if (si28 /= 0) then
1108 0 : if (s% xa(si28,k) <= s% fe_core_boundary_si28_fraction) then
1109 : sumx = 0
1110 0 : do j=1,species
1111 0 : if (chem_isos% Z_plus_N(s% chem_id(j)) >= A_max_fe) &
1112 0 : sumx = sumx + s% xa(j,k)
1113 : end do
1114 0 : if (sumx >= min_x) then
1115 : call set_core_info(s, k, s% fe_core_k, &
1116 : s% fe_core_mass, s% fe_core_radius, s% fe_core_lgT, &
1117 : s% fe_core_lgRho, s% fe_core_L, s% fe_core_v, &
1118 0 : s% fe_core_omega, s% fe_core_omega_div_omega_crit)
1119 0 : exit
1120 : end if
1121 : end if
1122 : end if
1123 : end if
1124 :
1125 40733 : if (.not. have_one) then
1126 40733 : if (s% one_core_boundary_he4_c12_fraction < 0) then
1127 0 : if (A_max >= A_max_one) then
1128 : call set_core_info(s, k, s% one_core_k, &
1129 : s% one_core_mass, s% one_core_radius, s% one_core_lgT, &
1130 : s% one_core_lgRho, s% one_core_L, s% one_core_v, &
1131 0 : s% one_core_omega, s% one_core_omega_div_omega_crit)
1132 0 : have_one = .true.
1133 : end if
1134 40733 : else if (he4 /= 0 .and. c12 /= 0 .and. o16 /= 0 .and. ne20 /=0) then
1135 40733 : if (s% xa(he4,k)+s% xa(c12,k) <= s% one_core_boundary_he4_c12_fraction .and. &
1136 : s% xa(o16,k)+s% xa(ne20,k) >= min_x) then
1137 : call set_core_info(s, k, s% one_core_k, &
1138 : s% one_core_mass, s% one_core_radius, s% one_core_lgT, &
1139 : s% one_core_lgRho, s% one_core_L, s% one_core_v, &
1140 0 : s% one_core_omega, s% one_core_omega_div_omega_crit)
1141 0 : have_one = .true.
1142 : end if
1143 : end if
1144 : end if
1145 :
1146 40733 : if (.not. have_co) then
1147 40733 : if (s% co_core_boundary_he4_fraction < 0) then
1148 0 : if (A_max >= A_max_co) then
1149 : call set_core_info(s, k, s% co_core_k, &
1150 : s% co_core_mass, s% co_core_radius, s% co_core_lgT, &
1151 : s% co_core_lgRho, s% co_core_L, s% co_core_v, &
1152 0 : s% co_core_omega, s% co_core_omega_div_omega_crit)
1153 0 : have_co = .true.
1154 : end if
1155 40733 : else if (he4 /= 0 .and. c12 /= 0 .and. o16 /= 0) then
1156 40733 : if (s% xa(he4,k) <= s% co_core_boundary_he4_fraction .and. &
1157 : s% xa(c12,k)+s% xa(o16,k) >= min_x) then
1158 : call set_core_info(s, k, s% co_core_k, &
1159 : s% co_core_mass, s% co_core_radius, s% co_core_lgT, &
1160 : s% co_core_lgRho, s% co_core_L, s% co_core_v, &
1161 0 : s% co_core_omega, s% co_core_omega_div_omega_crit)
1162 0 : have_co = .true.
1163 : end if
1164 : end if
1165 : end if
1166 :
1167 40766 : if (.not. have_he) then
1168 40733 : if (s% he_core_boundary_h1_fraction < 0) then
1169 0 : if (A_max >= A_max_he) then
1170 : call set_core_info(s, k, s% he_core_k, &
1171 : s% he_core_mass, s% he_core_radius, s% he_core_lgT, &
1172 : s% he_core_lgRho, s% he_core_L, s% he_core_v, &
1173 0 : s% he_core_omega, s% he_core_omega_div_omega_crit)
1174 0 : have_he = .true.
1175 : end if
1176 40733 : else if (h1 /= 0 .and. he4 /= 0) then
1177 40733 : if (s% xa(h1,k) <= s% he_core_boundary_h1_fraction .and. &
1178 : s% xa(he4,k) >= min_x) then
1179 : call set_core_info(s, k, s% he_core_k, &
1180 : s% he_core_mass, s% he_core_radius, s% he_core_lgT, &
1181 : s% he_core_lgRho, s% he_core_L, s% he_core_v, &
1182 0 : s% he_core_omega, s% he_core_omega_div_omega_crit)
1183 0 : have_he = .true.
1184 : end if
1185 : end if
1186 : end if
1187 :
1188 : end do
1189 :
1190 66 : end subroutine get_core_info
1191 :
1192 :
1193 66 : subroutine clear_core_info( &
1194 : core_k, core_m, core_r, core_lgT, core_lgRho, core_L, core_v, &
1195 : core_omega, core_omega_div_omega_crit)
1196 : integer, intent(out) :: core_k
1197 : real(dp), intent(out) :: &
1198 : core_m, core_r, core_lgT, core_lgRho, core_L, core_v, &
1199 : core_omega, core_omega_div_omega_crit
1200 66 : core_k = 0
1201 66 : core_m = 0
1202 66 : core_r = 0
1203 66 : core_lgT = 0
1204 66 : core_lgRho = 0
1205 66 : core_L = 0
1206 66 : core_v = 0
1207 66 : core_omega = 0
1208 66 : core_omega_div_omega_crit = 0
1209 0 : end subroutine clear_core_info
1210 :
1211 :
1212 0 : subroutine set_core_info(s, k, &
1213 : core_k, core_m, core_r, core_lgT, core_lgRho, core_L, core_v, &
1214 : core_omega, core_omega_div_omega_crit)
1215 : type (star_info), pointer :: s
1216 : integer, intent(in) :: k
1217 : integer, intent(out) :: core_k
1218 : real(dp), intent(out) :: &
1219 : core_m, core_r, core_lgT, core_lgRho, core_L, core_v, &
1220 : core_omega, core_omega_div_omega_crit
1221 :
1222 : integer :: jm1, j00
1223 0 : real(dp) :: dm1, d00, qm1, q00, core_q, &
1224 0 : core_lgP, core_g, core_X, core_Y, &
1225 0 : core_scale_height, core_dlnX_dr, core_dlnY_dr, core_dlnRho_dr
1226 :
1227 : include 'formats'
1228 :
1229 0 : if (k == 1) then
1230 0 : core_q = 1d0
1231 : else
1232 0 : jm1 = maxloc(s% xa(:,k-1), dim=1)
1233 0 : j00 = maxloc(s% xa(:,k), dim=1)
1234 0 : qm1 = s% q(k-1) - 0.5d0*s% dq(k-1) ! center of k-1
1235 0 : q00 = s% q(k) - 0.5d0*s% dq(k) ! center of k
1236 0 : dm1 = s% xa(j00,k-1) - s% xa(jm1,k-1)
1237 0 : d00 = s% xa(j00,k) - s% xa(jm1,k)
1238 0 : if (dm1*d00 > 0d0) then
1239 0 : write(*,2) 'bad args for set_core_info', k, dm1, d00
1240 0 : call mesa_error(__FILE__,__LINE__)
1241 0 : core_q = 0.5d0*(qm1 + q00)
1242 0 : else if (dm1 == 0d0 .and. d00 == 0d0) then
1243 0 : core_q = 0.5d0*(qm1 + q00)
1244 0 : else if (dm1 == 0d0) then
1245 0 : core_q = qm1
1246 0 : else if (d00 == 0d0) then
1247 0 : core_q = q00
1248 : else
1249 0 : core_q = find0(qm1, dm1, q00, d00)
1250 : end if
1251 : end if
1252 :
1253 : call get_info_at_q(s, core_q, &
1254 : core_k, core_m, core_r, core_lgT, core_lgRho, core_L, core_v, &
1255 : core_lgP, core_g, core_X, core_Y, &
1256 : core_scale_height, core_dlnX_dr, core_dlnY_dr, core_dlnRho_dr, &
1257 0 : core_omega, core_omega_div_omega_crit)
1258 :
1259 0 : end subroutine set_core_info
1260 :
1261 :
1262 0 : subroutine get_info_at_q(s, bdy_q, &
1263 : kbdy, bdy_m, bdy_r, bdy_lgT, bdy_lgRho, bdy_L, bdy_v, &
1264 : bdy_lgP, bdy_g, bdy_X, bdy_Y, &
1265 : bdy_scale_height, bdy_dlnX_dr, bdy_dlnY_dr, bdy_dlnRho_dr, &
1266 : bdy_omega, bdy_omega_div_omega_crit)
1267 :
1268 : type (star_info), pointer :: s
1269 : real(dp), intent(in) :: bdy_q
1270 : integer, intent(out) :: kbdy
1271 : real(dp), intent(out) :: &
1272 : bdy_m, bdy_r, bdy_lgT, bdy_lgRho, bdy_L, bdy_v, &
1273 : bdy_lgP, bdy_g, bdy_X, bdy_Y, &
1274 : bdy_scale_height, bdy_dlnX_dr, bdy_dlnY_dr, bdy_dlnRho_dr, &
1275 : bdy_omega, bdy_omega_div_omega_crit
1276 :
1277 0 : real(dp) :: x, x0, x1, x2, alfa, bdy_omega_crit
1278 : integer :: k, klo, khi
1279 :
1280 : include 'formats'
1281 :
1282 0 : bdy_m=0; bdy_r=0; bdy_lgT=0; bdy_lgRho=0; bdy_L=0; bdy_v=0
1283 0 : bdy_lgP=0; bdy_g=0; bdy_X=0; bdy_Y=0
1284 0 : bdy_scale_height=0; bdy_dlnX_dr=0; bdy_dlnY_dr=0; bdy_dlnRho_dr=0
1285 0 : bdy_omega=0; bdy_omega_div_omega_crit=0
1286 0 : kbdy = 0
1287 :
1288 0 : if (bdy_q <= 0) return
1289 0 : k = k_for_q(s,bdy_q)
1290 0 : if (k >= s% nz) then
1291 0 : kbdy = s% nz
1292 0 : return
1293 : end if
1294 0 : if (k <= 1) then
1295 0 : bdy_m = s% star_mass
1296 0 : bdy_r = s% r(1)/Rsun
1297 0 : bdy_lgT = s% lnT(1)/ln10
1298 0 : bdy_lgRho = s% lnd(1)/ln10
1299 0 : bdy_L = s% L(1)/Lsun
1300 0 : if (s% u_flag) then
1301 0 : bdy_v = s% u(1)
1302 0 : else if (s% v_flag) then
1303 0 : bdy_v = s% v(1)
1304 : end if
1305 0 : bdy_lgP = s% lnPeos(1)/ln10
1306 0 : bdy_g = s% grav(1)
1307 0 : bdy_X = s% X(1)
1308 0 : bdy_Y = s% Y(1)
1309 0 : bdy_scale_height = s% scale_height(1)
1310 0 : bdy_omega = s% omega(k)
1311 0 : if (s% rotation_flag) then
1312 0 : bdy_omega_crit = omega_crit(s,1)
1313 0 : bdy_omega_div_omega_crit = min(1d0,bdy_omega/bdy_omega_crit)
1314 : else
1315 0 : bdy_omega_crit = 0
1316 : bdy_omega_div_omega_crit = 0
1317 : end if
1318 0 : kbdy = 1
1319 0 : return
1320 : end if
1321 :
1322 0 : kbdy = k+1
1323 :
1324 0 : bdy_m = (s% M_center + s% xmstar*bdy_q)/Msun
1325 :
1326 0 : x = s% q(k-1) - bdy_q
1327 0 : x0 = s% dq(k-1)/2
1328 0 : x1 = s% dq(k)/2 + s% dq(k-1)
1329 0 : x2 = s% dq(k+1)/2 + s% dq(k) + s% dq(k-1)
1330 :
1331 0 : alfa = max(0d0, min(1d0, (bdy_q - s% q(k+1))/s% dq(k)))
1332 :
1333 0 : bdy_lgT = interp3(s% lnT(k-1), s% lnT(k), s% lnT(k+1))/ln10
1334 0 : bdy_lgRho = interp3(s% lnd(k-1), s% lnd(k), s% lnd(k+1))/ln10
1335 0 : bdy_lgP = interp3(s% lnPeos(k-1), s% lnPeos(k), s% lnPeos(k+1))/ln10
1336 0 : bdy_X = interp3(s% X(k-1), s% X(k), s% X(k+1))
1337 0 : bdy_Y = interp3(s% Y(k-1), s% Y(k), s% Y(k+1))
1338 :
1339 : bdy_r = pow( &
1340 0 : interp2(s% r(k)*s% r(k)*s% r(k), s% r(k+1)*s% r(k+1)*s% r(k+1)),one_third)/Rsun
1341 0 : bdy_L = interp2(s% L(k), s% L(k+1))/Lsun
1342 0 : bdy_g = interp2(s% grav(k), s% grav(k+1))
1343 0 : bdy_scale_height = interp2(s% scale_height(k), s% scale_height(k+1))
1344 :
1345 0 : klo = k-1
1346 0 : khi = k+1
1347 : bdy_dlnX_dr = log(max(1d-99,max(1d-99,s% X(klo))/max(1d-99,s% X(khi)))) &
1348 0 : / (s% rmid(klo) - s% rmid(khi))
1349 : bdy_dlnY_dr = log(max(1d-99,max(1d-99,s% Y(klo))/max(1d-99,s% Y(khi)))) &
1350 0 : / (s% rmid(klo) - s% rmid(khi))
1351 0 : bdy_dlnRho_dr = (s% lnd(klo) - s% lnd(khi))/(s% rmid(klo) - s% rmid(khi))
1352 :
1353 0 : if (s% u_flag) then
1354 0 : bdy_v = interp2(s% u(k), s% u(k+1))
1355 0 : else if (s% v_flag) then
1356 0 : bdy_v = interp2(s% v(k), s% v(k+1))
1357 : end if
1358 0 : if (s% rotation_flag) then
1359 0 : bdy_omega = interp2(s% omega(k), s% omega(k+1))
1360 0 : bdy_omega_crit = interp2(omega_crit(s,k), omega_crit(s,k+1))
1361 0 : bdy_omega_div_omega_crit = min(1d0,bdy_omega/bdy_omega_crit)
1362 : else
1363 : bdy_omega = 0
1364 0 : bdy_omega_crit = 0
1365 : bdy_omega_div_omega_crit = 0
1366 : end if
1367 :
1368 : contains
1369 :
1370 0 : real(dp) function interp3(f0, f1, f2)
1371 : real(dp), intent(in) :: f0, f1, f2
1372 0 : real(dp) :: fmin, fmax
1373 0 : fmin = min(f0,f1,f2)
1374 0 : fmax = max(f0,f1,f2)
1375 : interp3 = (f1*(x-x0)*(x-x2)*(x0-x2)-&
1376 : (x-x1)*(f0*(x-x2)*(x1-x2) + (x-x0)*(x0-x1)*x2))/ &
1377 0 : ((x0-x1)*(x0-x2)*(-x1+x2))
1378 0 : interp3 = min(fmax, max(fmin, interp3))
1379 0 : end function interp3
1380 :
1381 0 : real(dp) function interp2(f0, f1)
1382 : real(dp), intent(in) :: f0, f1
1383 0 : interp2 = alfa*f0 + (1-alfa)*f1
1384 : end function interp2
1385 :
1386 : end subroutine get_info_at_q
1387 :
1388 :
1389 33 : subroutine get_mixing_regions(s, ierr)
1390 : type (star_info), pointer :: s
1391 : integer, intent(out) :: ierr
1392 : integer :: prev_type, cur_type, cur_top, n, k
1393 : include 'formats'
1394 33 : ierr = 0
1395 33 : cur_type = s% mixing_type(1)
1396 33 : cur_top = 1
1397 33 : n = 0
1398 40733 : do k = 2, s% nz
1399 40700 : prev_type = cur_type
1400 40700 : cur_type = s% mixing_type(k)
1401 40700 : if (cur_type == prev_type .and. k < s% nz) cycle
1402 : ! change of type from k-1 to k
1403 138 : if (prev_type /= no_mixing) then
1404 69 : n = n + 1
1405 69 : s% mixing_region_type(n) = prev_type
1406 69 : s% mixing_region_top(n) = cur_top
1407 69 : if (k == s% nz) then
1408 33 : s% mixing_region_bottom(n) = k
1409 : else
1410 36 : s% mixing_region_bottom(n) = k-1
1411 : end if
1412 69 : if (n == max_num_mixing_regions) exit
1413 : end if
1414 40595 : cur_top = k
1415 : end do
1416 33 : s% num_mixing_regions = n
1417 33 : end subroutine get_mixing_regions
1418 :
1419 : end module report
|