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 profile
21 :
22 : use star_private_def
23 : use star_profile_def
24 : use const_def, only: dp, strlen
25 : use profile_getval
26 :
27 : implicit none
28 :
29 : private
30 : public :: write_profile_info
31 : public :: set_profile_columns
32 : public :: get_profile_val
33 : public :: do_save_profiles
34 : public :: do_get_data_for_profile_columns
35 : public :: do_get_num_standard_profile_columns
36 :
37 : ! model log priorities
38 : integer, parameter :: delta_priority = 1
39 : integer, parameter :: phase_priority = 2
40 :
41 : contains
42 :
43 1 : recursive subroutine add_profile_columns( &
44 : s, level, capacity, spec, profile_columns_file, report, ierr)
45 : use utils_lib
46 : use utils_def
47 : use chem_def
48 : use chem_lib
49 : use const_def, only: mesa_dir
50 : type (star_info), pointer :: s
51 : integer, intent(in) :: level
52 : integer, intent(inout) :: capacity
53 : integer, pointer :: spec(:)
54 : character (len=*), intent(in) :: profile_columns_file
55 : logical, intent(in) :: report
56 : integer, intent(out) :: ierr
57 :
58 : integer :: iounit, n, i, t, j, k, nxt_spec, spec_err
59 : character (len=strlen) :: buffer, string, filename
60 : integer, parameter :: max_level = 20
61 :
62 : logical :: exists
63 : logical, parameter :: dbg = .false.
64 :
65 : include 'formats'
66 :
67 1 : if (level > max_level) then
68 0 : write(*,*) 'too many levels of nesting for log column files', level
69 0 : ierr = -1
70 0 : return
71 : end if
72 :
73 1 : ierr = 0
74 1 : spec_err = 0
75 :
76 : ! first try local directory
77 1 : filename = profile_columns_file
78 :
79 1 : if(level==1) then ! First pass either the user set the file or we load the defaults
80 1 : if (len_trim(filename) == 0) filename = 'profile_columns.list'
81 :
82 1 : exists=.false.
83 1 : inquire(file=filename,exist=exists)
84 :
85 1 : if(.not.exists) filename = trim(mesa_dir) // '/star/defaults/profile_columns.list'
86 : else
87 : ! User had include '' in their profile_columns.list file, so dont try to load the local one, jump to the defaults
88 0 : if (len_trim(filename) == 0) filename =trim(mesa_dir) // '/star/defaults/profile_columns.list'
89 : end if
90 :
91 1 : open(newunit=iounit, file=trim(filename), action='read', status='old', iostat=ierr)
92 1 : if (ierr /= 0) then
93 0 : write(*,*) 'failed to open ' // trim(profile_columns_file)
94 0 : return
95 : end if
96 :
97 :
98 : if (dbg) then
99 : write(*,'(A)')
100 : write(*,*) 'profile_columns_file <' // trim(filename) // '>'
101 : end if
102 :
103 1 : call count_specs
104 :
105 1 : n = 0
106 1 : i = 0
107 :
108 : do
109 13 : t = token(iounit, n, i, buffer, string)
110 : if (dbg) write(*,*) 'token', t
111 13 : if (t == eof_token) then
112 : if (dbg) write(*,*) 'eof token'
113 : exit
114 : end if
115 12 : if (t /= name_token) then
116 0 : call error; return
117 : end if
118 :
119 0 : select case(string)
120 :
121 : case ('include')
122 0 : t = token(iounit, n, i, buffer, string)
123 : if (dbg) write(*,*) 'include file token', t
124 : if (dbg) write(*,*) 'include file string len', len_trim(string)
125 0 : if (t /= string_token) then
126 0 : call error; return
127 : end if
128 : if (dbg) write(*,*) 'include file <' // trim(string) // '>'
129 0 : call add_profile_columns(s, level+1, capacity, spec, string, report, spec_err)
130 0 : if (spec_err /= 0) then
131 0 : write(*,*) 'failed for included profile columns list: ' // trim(string)
132 0 : ierr = -1; call error; return
133 : end if
134 0 : call count_specs
135 :
136 : case ('add_eps_neu_rates')
137 0 : call insert_spec(eps_neu_rate_offset, 'add_eps_neu_rate', spec_err)
138 0 : if (spec_err /= 0) then
139 0 : ierr = -1; call error; return
140 : end if
141 :
142 : case ('add_eps_nuc_rates')
143 0 : call insert_spec(eps_nuc_rate_offset, 'add_eps_nuc_rate', spec_err)
144 0 : if (spec_err /= 0) then
145 0 : ierr = -1; call error; return
146 : end if
147 :
148 : case ('add_screened_rates')
149 0 : call insert_spec(screened_rate_offset, 'add_screened_rates', spec_err)
150 0 : if (spec_err /= 0) then
151 0 : ierr = -1; call error; return
152 : end if
153 :
154 : case ('add_raw_rates')
155 0 : call insert_spec(raw_rate_offset, 'add_raw_rates', spec_err)
156 0 : if (spec_err /= 0) then
157 0 : ierr = -1; call error; return
158 : end if
159 :
160 : case ('add_abundances')
161 : ! add all of the isos that are in the current net
162 0 : call insert_spec(add_abundances, 'add_abundances', spec_err)
163 0 : if (spec_err /= 0) then
164 0 : ierr = -1; call error; return
165 : end if
166 :
167 : case ('add_log_abundances')
168 : ! add logs of all of the isos that are in the current net
169 0 : call insert_spec(add_log_abundances, 'add_log_abundances', spec_err)
170 0 : if (spec_err /= 0) then
171 0 : ierr = -1; call error; return
172 : end if
173 :
174 : case ('add_reaction_categories') ! add all the reaction categories
175 0 : do k = 1, num_categories
176 0 : call insert_spec(category_offset + k, category_name(k), spec_err)
177 0 : if (spec_err /= 0) then
178 0 : ierr = -1; call error; return
179 : end if
180 : end do
181 :
182 : case default
183 : spec_err = 0
184 12 : nxt_spec = do1_profile_spec(s, iounit, n, i, string, buffer, report, spec_err)
185 24 : if (spec_err /= 0) then
186 0 : ierr = spec_err
187 : else
188 12 : if (nxt_spec > 0) then
189 12 : call insert_spec(nxt_spec, string, spec_err)
190 12 : if (spec_err /= 0) ierr = spec_err
191 : else
192 0 : if (report) &
193 0 : write(*,*) 'failed to recognize item for profile columns: ' // trim(string)
194 0 : ierr = -1
195 : end if
196 : end if
197 : end select
198 :
199 : end do
200 :
201 : if (dbg) write(*,*) 'finished ' // trim(filename)
202 :
203 1 : close(iounit)
204 :
205 2 : if (dbg) then
206 : write(*,'(A)')
207 : write(*,*) 'done add_profile_columns ' // trim(filename)
208 : write(*,'(A)')
209 : end if
210 :
211 :
212 : contains
213 :
214 :
215 1 : subroutine count_specs
216 : integer :: i
217 1 : j = 1
218 1 : do i=1, capacity
219 1 : if (spec(i) == 0) then
220 1 : j = i; exit
221 : end if
222 : end do
223 1 : end subroutine count_specs
224 :
225 :
226 12 : subroutine make_room(ierr)
227 : integer, intent(out) :: ierr
228 12 : if (j < capacity) return
229 0 : capacity = 50 + (3*capacity)/2
230 0 : call realloc_integer(spec,capacity,ierr)
231 0 : spec(j+1:capacity) = 0
232 : end subroutine make_room
233 :
234 :
235 24 : subroutine insert_spec(c, name, ierr)
236 : integer, intent(in) :: c
237 : character (len=*) :: name
238 : integer, intent(out) :: ierr
239 : integer :: i
240 : include 'formats'
241 78 : do i=1,j-1
242 78 : if (spec(i) == c) return
243 : end do
244 12 : call make_room(ierr)
245 12 : if (ierr /= 0) return
246 12 : spec(j) = c
247 : if (dbg) write(*,2) trim(name), spec(j)
248 12 : j = j+1
249 : end subroutine insert_spec
250 :
251 :
252 0 : subroutine error
253 0 : ierr = -1
254 0 : close(iounit)
255 0 : end subroutine error
256 :
257 :
258 : end subroutine add_profile_columns
259 :
260 :
261 1 : subroutine set_profile_columns(id, profile_columns_file, report, ierr)
262 : use utils_lib, only: realloc_integer
263 : integer, intent(in) :: id
264 : character (len=*), intent(in) :: profile_columns_file
265 : logical, intent(in) :: report
266 : integer, intent(out) :: ierr
267 :
268 : type (star_info), pointer :: s
269 : integer :: capacity, cnt, i
270 : logical, parameter :: dbg = .false.
271 : if (dbg) write(*,*) 'set_profile_columns'
272 : ierr = 0
273 1 : call get_star_ptr(id, s, ierr)
274 1 : if (ierr /= 0) return
275 1 : if (associated(s% profile_column_spec)) deallocate(s% profile_column_spec)
276 1 : capacity = 100 ! will increase if needed
277 1 : allocate(s% profile_column_spec(capacity), stat=ierr)
278 1 : if (ierr /= 0) return
279 101 : s% profile_column_spec(:) = 0
280 : call add_profile_columns( &
281 1 : s, 1, capacity, s% profile_column_spec, profile_columns_file, report, ierr)
282 1 : if (ierr /= 0) return
283 : ! delete trailing 0's
284 1 : cnt = capacity+1
285 13 : do i=1, capacity
286 13 : if (s% profile_column_spec(i) == 0) then
287 : cnt = i; exit
288 : end if
289 0 : if (dbg) write(*,*) 'profile col', i, s% profile_column_spec(i)
290 : end do
291 1 : call realloc_integer(s% profile_column_spec, cnt-1, ierr)
292 : if (dbg) write(*,*) 'num profile columns', cnt-1
293 : if (dbg) call mesa_error(__FILE__,__LINE__,'debug: set_profile_columns')
294 1 : end subroutine set_profile_columns
295 :
296 :
297 2 : integer function do_get_num_standard_profile_columns(s) ! not including extra profile columns
298 : use star_def, only: star_info
299 : type (star_info), pointer :: s
300 : integer :: numcols, j, num_specs
301 2 : numcols = 0
302 2 : if (.not. associated(s% profile_column_spec)) then
303 : num_specs = 0
304 : else
305 2 : num_specs = size(s% profile_column_spec, dim=1)
306 : end if
307 26 : do j = 1, num_specs
308 24 : if (s% profile_column_spec(j) == add_abundances .or. &
309 2 : s% profile_column_spec(j) == add_log_abundances) then
310 0 : numcols = numcols + s% species
311 : else if (s% profile_column_spec(j) == raw_rate_offset .or. &
312 : s% profile_column_spec(j) == screened_rate_offset .or. &
313 24 : s% profile_column_spec(j) == eps_nuc_rate_offset .or. &
314 : s% profile_column_spec(j) == eps_neu_rate_offset) then
315 0 : numcols = numcols + s% num_reactions
316 : else
317 24 : numcols = numcols + 1
318 : end if
319 : end do
320 2 : do_get_num_standard_profile_columns = numcols
321 2 : end function do_get_num_standard_profile_columns
322 :
323 :
324 0 : subroutine do_get_data_for_profile_columns(s, nz, &
325 : names, vals, is_int, ierr)
326 : type (star_info), pointer :: s
327 : integer, intent(in) :: nz
328 : character (len=maxlen_profile_column_name), pointer :: names(:) ! (num_profile_columns)
329 : real(dp), pointer :: vals(:,:) ! (nz,num_profile_columns)
330 : logical, pointer :: is_int(:) ! (num_profile_columns) true iff the values in the column are integers
331 : integer, intent(out) :: ierr
332 : character (len=0) :: fname
333 : logical, parameter :: write_flag = .false.
334 : call do_profile_info(s, fname, &
335 0 : write_flag, names, vals, is_int, ierr)
336 2 : end subroutine do_get_data_for_profile_columns
337 :
338 :
339 2 : subroutine write_profile_info(s, fname, ierr)
340 : use chem_def
341 : use net_def ! categories
342 : use rates_def, only: i_rate
343 : type (star_info), pointer :: s
344 : character (len=*) :: fname
345 : integer, intent(out) :: ierr
346 2 : character (len=maxlen_profile_column_name), pointer :: names(:) ! (num_profile_columns)
347 2 : real(dp), pointer :: vals(:,:) ! (nz,num_profile_columns)
348 2 : logical, pointer :: is_int(:)
349 : logical, parameter :: write_flag = .true.
350 2 : names => null()
351 2 : vals => null()
352 2 : is_int => null()
353 : call do_profile_info(s, fname, &
354 2 : write_flag, names, vals, is_int, ierr)
355 2 : end subroutine write_profile_info
356 :
357 :
358 2 : subroutine do_profile_info(s, fname, &
359 : write_flag, names, vals, is_int, ierr)
360 2 : use chem_def
361 : use net_def ! categories
362 : use rates_def, only: i_rate
363 : use ctrls_io, only: write_controls
364 : use write_model, only: do_write_model
365 : use pulse, only: export_pulse_data
366 : use math_lib, only: math_backend
367 : use utils_lib, only: mkdir, folder_exists
368 :
369 : type (star_info), pointer :: s
370 : character (len=*) :: fname
371 : logical, intent(in) :: write_flag
372 : character (len=maxlen_profile_column_name), pointer :: names(:) ! (num_profile_columns)
373 : real(dp), pointer :: vals(:,:) ! (nz,num_profile_columns)
374 : logical, pointer :: is_int(:)
375 : integer, intent(out) :: ierr
376 :
377 2 : real(dp) :: mstar, dt
378 : integer :: io, i, j, jj, nz, col, k, kk, n, species, &
379 : num_specs, numcols, num_extra_cols, num_extra_header_items, num_digits
380 2 : integer, pointer :: chem_id(:)
381 : logical, parameter :: dbg = .false.
382 : character (len=strlen) :: fname1, dbl_fmt, int_fmt, txt_fmt, fname_out, fstring, str
383 : character (len=maxlen_profile_column_name), pointer :: &
384 2 : extra_col_names(:), extra_header_item_names(:)
385 2 : real(dp), pointer :: extra_col_vals(:,:), extra_header_item_vals(:)
386 : type(net_general_info),pointer :: g=>null()
387 :
388 : include "formats"
389 :
390 2 : dbl_fmt = s% profile_dbl_format
391 2 : int_fmt = s% profile_int_format
392 2 : txt_fmt = s% profile_txt_format
393 :
394 : ierr = 0
395 2 : nullify(extra_col_names, extra_col_vals)
396 :
397 2 : call get_net_ptr(s%net_handle, g, ierr)
398 2 : if(ierr/=0) return
399 :
400 2 : nz = s% nz
401 2 : species = s% species
402 2 : chem_id => s% chem_id
403 2 : mstar = s% mstar
404 2 : dt = s% dt
405 2 : if (.not. associated(s% profile_column_spec)) then
406 : num_specs = 0
407 : else
408 2 : num_specs = size(s% profile_column_spec, dim=1)
409 : end if
410 :
411 2 : if (num_specs == 0) then
412 0 : write(*,*) 'WARNING: do not have any output specified for profiles.'
413 0 : return
414 : end if
415 :
416 2 : numcols = do_get_num_standard_profile_columns(s)
417 :
418 2 : num_extra_cols = s% how_many_extra_profile_columns(s% id)
419 2 : if (num_extra_cols > 0) then
420 : allocate( &
421 0 : extra_col_names(num_extra_cols), extra_col_vals(nz,num_extra_cols), stat=ierr)
422 0 : if (ierr /= 0) return
423 0 : extra_col_names(1:num_extra_cols) = 'unknown'
424 0 : extra_col_vals(1:nz,1:num_extra_cols) = -1d99
425 : call s% data_for_extra_profile_columns( &
426 0 : s% id, num_extra_cols, nz, extra_col_names, extra_col_vals, ierr)
427 0 : if (ierr /= 0) then
428 0 : deallocate(extra_col_names, extra_col_vals)
429 0 : return
430 : end if
431 0 : do i=1,num_extra_cols
432 0 : if(trim(extra_col_names(i))=='unknown') then
433 0 : write(*,*) "Warning empty profile name for extra_profile_column ",i
434 : end if
435 : end do
436 : end if
437 :
438 2 : if (.not. write_flag) then
439 :
440 0 : if (associated(names)) then
441 0 : if (size(names,dim=1) < numcols+num_extra_cols) then
442 0 : write(*,2) 'size(names,dim=1)', size(names,dim=1)
443 0 : write(*,2) 'numcols+num_extra_cols', numcols+num_extra_cols
444 0 : write(*,2) 'numcols', numcols
445 0 : write(*,2) 'num_extra_cols', num_extra_cols
446 0 : write(*,*) 'bad size for names in do_profile_info'
447 0 : ierr = -1
448 0 : return
449 : end if
450 : else
451 0 : write(*,*) 'failed to provide names array for do_profile_info'
452 0 : ierr = -1
453 0 : return
454 : end if
455 :
456 0 : if (associated(vals)) then
457 0 : if (size(vals,dim=1) < nz) then
458 0 : write(*,2) 'size(vals,dim=1)', size(vals,dim=1)
459 0 : write(*,2) 'nz', nz
460 0 : write(*,*) 'bad size dim=1 for vals in do_profile_info'
461 0 : ierr = -1
462 0 : return
463 : end if
464 0 : if (size(vals,dim=2) < numcols+num_extra_cols) then
465 0 : write(*,2) 'size(vals,dim=2)', size(vals,dim=2)
466 0 : write(*,2) 'numcols+num_extra_cols', numcols+num_extra_cols
467 0 : write(*,2) 'numcols', numcols
468 0 : write(*,2) 'num_extra_cols', num_extra_cols
469 0 : write(*,*) 'bad size dim=1 for names in do_profile_info'
470 0 : ierr = -1
471 0 : return
472 : end if
473 : else
474 0 : write(*,*) 'failed to provide vals array for do_profile_info'
475 0 : ierr = -1
476 0 : return
477 : end if
478 :
479 : end if
480 :
481 2 : if (write_flag) then
482 2 : if(.not. folder_exists(trim(s% log_directory))) call mkdir(trim(s% log_directory))
483 :
484 2 : if (len_trim(s% profile_data_header_suffix) == 0) then
485 2 : fname1 = fname
486 : else
487 0 : fname1 = trim(fname) // s% profile_data_header_suffix
488 : end if
489 2 : open(newunit=io, file=trim(fname1), action='write', status='replace', iostat=ierr)
490 2 : if (ierr /= 0) then
491 0 : write(*,*) 'failed to open ' // trim(fname1)
492 0 : return
493 : end if
494 :
495 2 : num_extra_header_items = s% how_many_extra_profile_header_items(s% id)
496 2 : if (num_extra_header_items > 0) then
497 : allocate( &
498 : extra_header_item_names(num_extra_header_items), &
499 0 : extra_header_item_vals(num_extra_header_items), stat=ierr)
500 0 : if (ierr /= 0) then
501 : return
502 : end if
503 0 : extra_header_item_names(1:num_extra_header_items) = 'unknown'
504 0 : extra_header_item_vals(1:num_extra_header_items) = -1d99
505 : call s% data_for_extra_profile_header_items( &
506 : s% id, num_extra_header_items, &
507 0 : extra_header_item_names, extra_header_item_vals, ierr)
508 0 : if (ierr /= 0) then
509 0 : deallocate(extra_header_item_names, extra_header_item_vals)
510 0 : return
511 : end if
512 0 : do i=1,num_extra_header_items
513 0 : if(trim(extra_header_item_names(i))=='unknown') then
514 0 : write(*,*) "Warning empty profile name for extra_profile_header ",i
515 : end if
516 : end do
517 : end if
518 :
519 8 : do i=1, 3
520 6 : col = 0
521 6 : call do_integer(i, 'model_number', s% model_number)
522 6 : call do_integer(i, 'num_zones', s% nz)
523 6 : call do_val(i, 'initial_mass', s% initial_mass)
524 6 : call do_val(i, 'initial_z', s% initial_z)
525 6 : call do_val(i, 'star_age', s% star_age)
526 6 : call do_val(i, 'time_step', s% time_step)
527 :
528 6 : if (s% M_center /= 0d0) &
529 0 : call do_val(i, 'M_center', s% M_center)
530 6 : if (s% v_center /= 0d0) &
531 0 : call do_val(i, 'v_center', s% v_center)
532 6 : if (s% R_center /= 0d0) &
533 0 : call do_val(i, 'R_center', s% R_center)
534 6 : if (s% L_center /= 0d0) &
535 0 : call do_val(i, 'L_center', s% L_center)
536 :
537 6 : call do_val(i, 'Teff', s% Teff)
538 6 : call do_val(i, 'photosphere_L', s% photosphere_L)
539 6 : call do_val(i, 'photosphere_r', s% photosphere_r)
540 :
541 6 : call do_val(i, 'center_eta', s% center_degeneracy)
542 6 : call do_val(i, 'center_h1', s% center_h1)
543 6 : call do_val(i, 'center_he3', s% center_he3)
544 6 : call do_val(i, 'center_he4', s% center_he4)
545 6 : call do_val(i, 'center_c12', s% center_c12)
546 6 : call do_val(i, 'center_n14', s% center_n14)
547 6 : call do_val(i, 'center_o16', s% center_o16)
548 6 : call do_val(i, 'center_ne20', s% center_ne20)
549 6 : call do_val(i, 'star_mass', s% star_mass)
550 6 : call do_val(i, 'star_mdot', s% star_mdot)
551 6 : call do_val(i, 'star_mass_h1', s% star_mass_h1)
552 6 : call do_val(i, 'star_mass_he3', s% star_mass_he3)
553 6 : call do_val(i, 'star_mass_he4', s% star_mass_he4)
554 6 : call do_val(i, 'star_mass_c12', s% star_mass_c12)
555 6 : call do_val(i, 'star_mass_n14', s% star_mass_n14)
556 6 : call do_val(i, 'star_mass_o16', s% star_mass_o16)
557 6 : call do_val(i, 'star_mass_ne20', s% star_mass_ne20)
558 6 : call do_val(i, 'he_core_mass', s% he_core_mass)
559 6 : call do_val(i, 'co_core_mass', s% co_core_mass)
560 6 : call do_val(i, 'fe_core_mass', s% fe_core_mass)
561 6 : call do_val(i, 'neutron_rich_core_mass', s% neutron_rich_core_mass)
562 6 : call do_val(i, 'dynamic_time', s% dynamic_timescale)
563 6 : call do_val(i, 'kh_timescale', s% kh_timescale)
564 6 : call do_val(i, 'nuc_timescale', s% nuc_timescale)
565 :
566 6 : call do_val(i, 'power_nuc_burn', s% power_nuc_burn)
567 6 : call do_val(i, 'power_h_burn', s% power_h_burn)
568 6 : call do_val(i, 'power_he_burn', s% power_he_burn)
569 6 : call do_val(i, 'power_neu', s% power_neutrinos)
570 :
571 6 : call do_val(i, 'burn_min1', s% burn_min1)
572 6 : call do_val(i, 'burn_min2', s% burn_min2)
573 :
574 6 : call do_val(i, 'time_seconds', s% time)
575 :
576 6 : call do_string(i, 'version_number', version_number)
577 :
578 6 : if (s% profile_header_include_sys_details) then ! make this optional
579 6 : call do_string(i, 'compiler', compiler_name)
580 6 : call do_string(i, 'build', compiler_version_name)
581 6 : call do_string(i, 'MESA_SDK_version', mesasdk_version_name)
582 6 : call do_string(i, 'math_backend', math_backend)
583 6 : call do_string(i, 'date', date)
584 : end if
585 :
586 6 : call do_val(i, 'msun', msun)
587 6 : call do_val(i, 'rsun', rsun)
588 6 : call do_val(i, 'lsun', lsun)
589 :
590 6 : do j=1,num_extra_header_items
591 6 : call do_val(i, extra_header_item_names(j), extra_header_item_vals(j))
592 : end do
593 :
594 8 : write(io, *)
595 :
596 : end do
597 :
598 2 : write(io, *)
599 :
600 2 : if (num_extra_header_items > 0) &
601 0 : deallocate(extra_header_item_names, extra_header_item_vals)
602 :
603 : end if
604 :
605 8 : do i = 1, 3
606 :
607 6 : if (i==3) then
608 2 : if (s% max_num_profile_zones > 1) then
609 0 : n = min(nz, s% max_num_profile_zones)
610 : else
611 2 : n = nz
612 : end if
613 2 : if (write_flag .and. len_trim(s% profile_data_header_suffix) > 0) then
614 0 : close(io)
615 : open(newunit=io, file=trim(fname), &
616 0 : action='write', status='replace', iostat=ierr)
617 0 : if (ierr /= 0) then
618 0 : write(*,*) 'failed to open ' // trim(fname)
619 0 : return
620 : end if
621 : end if
622 : else
623 : n = 1
624 : end if
625 :
626 3468 : do k=1, n
627 3460 : col = 0
628 3460 : if (n > 1 .and. n < nz) then
629 0 : kk = floor(1.5d0 + dble(nz-1)*dble(k-1)/dble(n-1))
630 : else
631 3460 : kk = k
632 : end if
633 44980 : do j = 1, num_specs
634 41520 : if (s% profile_column_spec(j) == add_abundances .or. &
635 3460 : s% profile_column_spec(j) == add_log_abundances) then
636 0 : do jj = 1, species
637 0 : col = col+1
638 0 : call do_abundance_col(i, j, jj, kk)
639 : end do
640 : else if (s% profile_column_spec(j) == raw_rate_offset .or. &
641 : s% profile_column_spec(j) == screened_rate_offset .or. &
642 41520 : s% profile_column_spec(j) == eps_nuc_rate_offset .or. &
643 : s% profile_column_spec(j) == eps_neu_rate_offset) then
644 0 : do jj = 1, s% num_reactions
645 0 : col = col+1
646 0 : call do_col(i, j, jj, kk)
647 : end do
648 : else
649 41520 : col = col+1
650 41520 : call do_col(i, j, 0, kk)
651 : end if
652 : end do
653 3460 : do j=1,num_extra_cols
654 0 : col = col+1
655 3460 : call do_extra_col(i, j, kk)
656 : end do
657 3466 : if (write_flag) write(io, *)
658 : end do
659 :
660 : end do
661 :
662 2 : if (associated(extra_col_vals)) deallocate(extra_col_vals)
663 2 : if (associated(extra_col_names)) deallocate(extra_col_names)
664 :
665 6 : if (write_flag) then
666 :
667 2 : close(io)
668 :
669 2 : s% most_recent_profile_filename = trim(fname1)
670 :
671 2 : write(str,'(a)') 'save ' // trim(fname1)
672 2 : write(*,'(a)', advance='no') trim(str)
673 2 : call write_to_extra_terminal_output_file(s, str, .false.)
674 :
675 2 : if (s% write_pulse_data_with_profile) then
676 0 : fname_out = trim(fname) // '.' // trim(s% pulse_data_format)
677 : call export_pulse_data(s%id, s%pulse_data_format, fname_out, &
678 : s%add_center_point_to_pulse_data, s%keep_surface_point_for_pulse_data, &
679 0 : s%add_atmosphere_to_pulse_data, ierr)
680 0 : if (ierr /= 0) then
681 0 : write(*,*) 'save_pulsation_info failed to open ' // trim(fname_out)
682 0 : ierr = 0
683 : else
684 0 : write(*,'(a)', advance='no') ' ' // trim(fname_out)
685 : end if
686 : end if
687 :
688 2 : if (s% write_model_with_profile) then
689 0 : fname_out = s% model_data_filename
690 0 : call do_write_model(s% id, fname_out, ierr)
691 0 : if (ierr /= 0) then
692 0 : write(*,*) 'failed to open ' // trim(fname_out)
693 0 : ierr = 0
694 : else
695 0 : write(*,'(a)', advance='no') ' ' // trim(fname_out)
696 : end if
697 : end if
698 :
699 2 : if (s% write_controls_info_with_profile) then
700 0 : fname_out = s% model_controls_filename
701 0 : call write_controls(s, fname_out, ierr)
702 0 : if (ierr /= 0) then
703 0 : write(*,*) 'failed to write ' // trim(fname_out)
704 0 : ierr = 0
705 : else
706 0 : s% most_recent_controls_filename = trim(fname_out)
707 : end if
708 0 : write(*,'(a)', advance='no') ' ' // trim(fname_out)
709 : end if ! write_controls_info_with_profile
710 :
711 2 : num_digits = 1 + log10(dble(max(1,s% model_number)))
712 2 : write(fstring,'( "(a,i",i2.2,".",i2.2,")" )') num_digits, num_digits
713 :
714 2 : write(str,fstring) ' for model ', s% model_number
715 2 : write(*,'(a)') trim(str)
716 2 : call write_to_extra_terminal_output_file(s, str, .false.)
717 :
718 : end if
719 :
720 :
721 : contains
722 :
723 :
724 36 : subroutine do_string(pass, col_name, val)
725 : integer, intent(in) :: pass
726 : character (len=*), intent(in) :: col_name, val
727 : character(len=strlen) :: my_val
728 36 : col = col+1
729 36 : my_val = '"'//trim(val)//'"'
730 36 : if (pass == 1) then
731 12 : write(io, fmt=int_fmt, advance='no') col
732 24 : else if (pass == 2) then
733 12 : write(io, fmt=txt_fmt, advance='no') trim(col_name)
734 12 : else if (pass == 3) then
735 12 : write(io, fmt=txt_fmt, advance='no') adjustr(trim('"'//trim(val)//'"'))
736 : end if
737 2 : end subroutine do_string
738 :
739 :
740 12 : subroutine do_integer(pass, col_name, val)
741 : integer, intent(in) :: pass
742 : character (len=*), intent(in) :: col_name
743 : integer, intent(in) :: val
744 12 : col = col+1
745 12 : if (pass == 1) then
746 4 : write(io, fmt=int_fmt, advance='no') col
747 8 : else if (pass == 2) then
748 4 : write(io, fmt=txt_fmt, advance='no') trim(col_name)
749 4 : else if (pass == 3) then
750 4 : write(io, fmt=int_fmt, advance='no') val
751 : end if
752 12 : end subroutine do_integer
753 :
754 :
755 246 : subroutine do_val(pass, col_name, val)
756 : integer, intent(in) :: pass
757 : character (len=*), intent(in) :: col_name
758 : real(dp), intent(in) :: val
759 246 : real(dp) :: v
760 : include 'formats'
761 246 : col = col+1
762 246 : if (pass == 1) then
763 82 : write(io, fmt=int_fmt, advance='no') col
764 164 : else if (pass == 2) then
765 82 : write(io, fmt=txt_fmt, advance='no') trim(col_name)
766 82 : else if (pass == 3) then
767 82 : v = val
768 82 : if (is_bad_num(v)) then
769 0 : write(*,1) 'bad value for ' // trim(col_name), v
770 0 : if (s% stop_for_bad_nums) call mesa_error(__FILE__,__LINE__,'profile do_val')
771 0 : v = 0
772 : end if
773 82 : write(io, fmt=dbl_fmt, advance='no') v
774 : end if
775 246 : end subroutine do_val
776 :
777 :
778 0 : subroutine do_extra_col(pass, j, k)
779 : use rates_def
780 : integer, intent(in) :: pass, j, k
781 0 : if (pass == 1) then
782 0 : if (write_flag) write(io, fmt=int_fmt, advance='no') col
783 0 : else if (pass == 2) then
784 0 : if (write_flag) then
785 0 : write(io, fmt=txt_fmt, advance='no') trim(extra_col_names(j))
786 : else
787 0 : names(col) = trim(extra_col_names(j))
788 : end if
789 0 : else if (pass == 3) then
790 0 : if (write_flag) then
791 0 : write(io, fmt=dbl_fmt, advance='no') extra_col_vals(k,j)
792 : else
793 0 : vals(k,col) = extra_col_vals(k,j)
794 0 : is_int(col) = .false.
795 : end if
796 : end if
797 0 : end subroutine do_extra_col
798 :
799 :
800 41520 : subroutine do_col(pass, j, jj, k)
801 0 : use rates_def
802 : use profile_getval, only: getval_for_profile
803 : integer, intent(in) :: pass, j, jj, k
804 : integer :: i, c, int_val, ir
805 : real(dp) :: val
806 : logical :: int_flag
807 : character (len=128) :: col_name
808 : logical, parameter :: dbg = .false.
809 : include 'formats'
810 41520 : c = s% profile_column_spec(j) + jj
811 41520 : val = 0; int_val = 0
812 41520 : if (pass == 1) then
813 24 : if (write_flag) write(io, fmt=int_fmt, advance='no') col
814 41496 : else if (pass == 2) then
815 24 : if (c > extra_offset) then
816 0 : i = c - extra_offset
817 0 : col_name = trim(s% profile_extra_name(i))
818 24 : else if (c > eps_neu_rate_offset) then
819 0 : i = c - eps_neu_rate_offset
820 0 : ir = g% reaction_id(i)
821 0 : col_name = 'eps_neu_rate_' // trim(reaction_name(ir))
822 24 : else if (c > eps_nuc_rate_offset) then
823 0 : i = c - eps_nuc_rate_offset
824 0 : ir = g% reaction_id(i)
825 0 : col_name = 'eps_nuc_rate_' // trim(reaction_name(ir))
826 24 : else if (c > screened_rate_offset) then
827 0 : i = c - screened_rate_offset
828 0 : ir = g% reaction_id(i)
829 0 : col_name = 'screened_rate_' // trim(reaction_name(ir))
830 24 : else if (c > raw_rate_offset) then
831 0 : i = c - raw_rate_offset
832 0 : ir = g% reaction_id(i)
833 0 : col_name = 'raw_rate_' // trim(reaction_name(ir))
834 24 : else if (c > diffusion_D_offset) then
835 0 : i = c - diffusion_D_offset
836 0 : col_name = 'diffusion_D_' // trim(chem_isos% name(i))
837 24 : else if (c > diffusion_dX_offset) then
838 0 : i = c - diffusion_dX_offset
839 0 : col_name = 'diffusion_dX_' // trim(chem_isos% name(i))
840 24 : else if (c > log_concentration_offset) then
841 0 : i = c - log_concentration_offset
842 0 : col_name = 'log_concentration_' // trim(chem_isos% name(i))
843 24 : else if (c > log_g_rad_offset) then
844 0 : i = c - log_g_rad_offset
845 0 : col_name = 'log_g_rad_' // trim(chem_isos% name(i))
846 24 : else if (c > v_rad_offset) then
847 0 : i = c - v_rad_offset
848 0 : col_name = 'v_rad_' // trim(chem_isos% name(i))
849 24 : else if (c > extra_diffusion_factor_offset) then
850 0 : i = c - extra_diffusion_factor_offset
851 0 : col_name = 'extra_diffusion_factor_' // trim(chem_isos% name(i))
852 24 : else if (c > edv_offset) then
853 0 : i = c - edv_offset
854 0 : col_name = 'edv_' // trim(chem_isos% name(i))
855 24 : else if (c > typical_charge_offset) then
856 0 : i = c - typical_charge_offset
857 0 : col_name = 'typical_charge_' // trim(chem_isos% name(i))
858 24 : else if (c > ionization_offset) then
859 0 : i = c - ionization_offset
860 0 : col_name = 'ionization_' // trim(chem_isos% name(i))
861 24 : else if (c > xaprev_offset) then
862 0 : i = c - xaprev_offset
863 0 : col_name = 'xaprev_' // trim(chem_isos% name(i))
864 24 : else if (c > xadot_offset) then
865 0 : i = c - xadot_offset
866 0 : col_name = 'xadot_' // trim(chem_isos% name(i))
867 24 : else if (c > log_abundance_offset) then
868 0 : i = c - log_abundance_offset
869 0 : col_name = 'log_' // trim(chem_isos% name(i))
870 24 : else if (c > abundance_offset) then
871 0 : i = c - abundance_offset
872 0 : col_name = trim(chem_isos% name(i))
873 24 : else if (c > category_offset) then
874 6 : i = c - category_offset
875 6 : col_name = trim(category_name(i))
876 : else
877 18 : col_name = trim(profile_column_name(c))
878 : end if
879 24 : if (write_flag) then
880 24 : write(io, fmt=txt_fmt, advance='no') trim(col_name)
881 : else
882 0 : names(col) = trim(col_name)
883 : end if
884 41472 : else if (pass == 3) then
885 41472 : call getval_for_profile(s, c, k, val, int_flag, int_val)
886 41472 : if (write_flag) then
887 41472 : if (int_flag) then
888 3456 : write(io, fmt=int_fmt, advance='no') int_val
889 : else
890 38016 : if (is_bad(val)) val = 1d99
891 38016 : write(io, fmt=dbl_fmt, advance='no') val
892 : end if
893 : else
894 0 : if (int_flag) then
895 0 : vals(k,col) = dble(int_val)
896 0 : is_int(col) = .true.
897 : else
898 0 : vals(k,col) = val
899 0 : is_int(col) = .false.
900 : end if
901 : end if
902 : end if
903 41520 : end subroutine do_col
904 :
905 :
906 0 : subroutine do_abundance_col(pass, j, jj, k)
907 : integer, intent(in) :: pass, j, jj, k
908 0 : real(dp) :: val
909 : logical :: log_abundance
910 : character (len=128) :: col_name
911 : logical, parameter :: dbg = .false.
912 : include 'formats'
913 0 : log_abundance = (s% profile_column_spec(j) == add_log_abundances)
914 0 : if (pass == 1) then
915 0 : if (write_flag) write(io, fmt=int_fmt, advance='no') col
916 0 : else if (pass == 2) then
917 0 : if (log_abundance) then
918 0 : col_name = 'log_'
919 : else
920 0 : col_name = ''
921 : end if
922 0 : col_name = trim(col_name) // trim(chem_isos% name(s% chem_id(jj)))
923 0 : if (write_flag) then
924 0 : write(io, fmt=txt_fmt, advance='no') trim(col_name)
925 : else
926 0 : names(col) = trim(col_name)
927 : end if
928 0 : else if (pass == 3) then
929 0 : val = s% xa(jj,k)
930 0 : if (log_abundance) val = safe_log10(val)
931 0 : if (write_flag) then
932 0 : write(io, fmt=dbl_fmt, advance='no') val
933 : else
934 0 : vals(k,col) = val
935 0 : is_int(col) = .false.
936 : end if
937 : end if
938 41520 : end subroutine do_abundance_col
939 :
940 :
941 : end subroutine do_profile_info
942 :
943 :
944 2 : subroutine do_save_profiles( &
945 : s, ierr)
946 : type (star_info), pointer :: s
947 : integer, intent(out) :: ierr
948 :
949 2 : integer, pointer, dimension(:) :: model_numbers, model_priorities, model_logs
950 : integer :: nz, max_num_mods, num_models, model_profile_number
951 : character (len=strlen) :: fname
952 : integer :: model_priority
953 :
954 : include 'formats'
955 :
956 2 : ierr = 0
957 2 : nz = s% nz
958 :
959 2 : if (.not. s% write_profiles_flag) return
960 3458 : if (.not. s% v_flag) s% v(1:nz) = 0
961 3458 : if (.not. s% u_flag) s% u(1:nz) = 0
962 3458 : if (.not. s% rotation_flag) s% omega(1:nz) = 0
963 :
964 2 : max_num_mods = s% max_num_profile_models
965 2 : if (max_num_mods < 0) max_num_mods = s% model_number
966 2 : model_priority = s% save_profiles_model_priority
967 :
968 : allocate(model_numbers(max_num_mods), model_priorities(max_num_mods), &
969 2 : model_logs(max_num_mods), stat=ierr)
970 2 : if (ierr /= 0) return
971 :
972 2 : write(fname, '(3a)') trim(s% log_directory), '/', trim(s% profiles_index_name)
973 :
974 : call read_profiles_info( &
975 2 : fname, max_num_mods, num_models, model_numbers, model_priorities, model_logs)
976 :
977 : call make_room_for_profile_info( &
978 2 : s% model_number, max_num_mods, num_models, model_numbers, model_priorities, model_logs, ierr)
979 2 : if (ierr /= 0) then
980 0 : call dealloc; return
981 : end if
982 :
983 : call pick_model_profile_number( &
984 2 : max_num_mods, num_models, model_logs, model_profile_number, ierr)
985 2 : if (ierr /= 0) then
986 0 : call dealloc; return
987 : end if
988 :
989 2 : call get_model_profile_filename(s, model_profile_number)
990 :
991 : ! add the new model to the list at the end
992 2 : num_models = num_models+1
993 2 : model_numbers(num_models) = s% model_number
994 2 : model_priorities(num_models) = model_priority
995 2 : model_logs(num_models) = model_profile_number
996 :
997 2 : s% save_profiles_model_priority = delta_priority ! reset it to the default value
998 :
999 : ! write the profiles before adding them to the list
1000 : ! so if user interrupts during write, the index is still okay.
1001 2 : call write_profile_info(s, s% model_profile_filename, ierr)
1002 2 : if (ierr /= 0) then
1003 0 : call dealloc; return
1004 : end if
1005 :
1006 : call write_profiles_list( &
1007 2 : fname, num_models, model_numbers, model_priorities, model_logs, ierr)
1008 2 : if (ierr /= 0) then
1009 0 : call dealloc; return
1010 : end if
1011 :
1012 10 : call dealloc
1013 :
1014 :
1015 : contains
1016 :
1017 2 : subroutine dealloc
1018 2 : deallocate(model_numbers, model_priorities, model_logs)
1019 2 : end subroutine dealloc
1020 :
1021 : end subroutine do_save_profiles
1022 :
1023 :
1024 2 : subroutine write_profiles_list( &
1025 : fname, num_models, model_numbers, model_priorities, model_logs, ierr)
1026 : character (len=*), intent(in) :: fname
1027 : integer, intent(in) :: num_models
1028 : integer, pointer, dimension(:) :: model_numbers, model_priorities, model_logs
1029 : integer, intent(out) :: ierr
1030 : integer :: iounit, i
1031 2 : ierr = 0
1032 : ! write the new list
1033 2 : open(newunit=iounit, file=trim(fname), action='write', iostat=ierr)
1034 2 : if (ierr /= 0) then
1035 0 : write(*, *) 'failed to open ' // trim(fname)
1036 : else
1037 2 : if (num_models == 1) then
1038 1 : write(iounit, *) num_models, &
1039 2 : 'model. lines hold model number, priority, and profile number.'
1040 : else
1041 1 : write(iounit, *) num_models, &
1042 2 : 'models. lines hold model number, priority, and profile number.'
1043 : end if
1044 5 : do i=1, num_models
1045 5 : write(iounit, *) model_numbers(i), model_priorities(i), model_logs(i)
1046 : end do
1047 2 : close(iounit)
1048 : end if
1049 2 : end subroutine write_profiles_list
1050 :
1051 :
1052 2 : subroutine pick_model_profile_number( &
1053 : max_num_mods, num_models, model_logs, model_profile_number, ierr)
1054 : integer, intent(in) :: max_num_mods
1055 : integer, intent(inout) :: num_models
1056 : integer, pointer, dimension(:) :: model_logs
1057 : integer, intent(out) :: model_profile_number, ierr
1058 4 : logical :: in_use(max_num_mods)
1059 : integer :: i
1060 : ! pick log number for the new model
1061 2 : ierr = 0
1062 202 : in_use = .false.
1063 3 : do i=1, num_models
1064 3 : in_use(model_logs(i)) = .true.
1065 : end do
1066 2 : model_profile_number = 0
1067 3 : do i=1, max_num_mods
1068 3 : if (.not. in_use(i)) then
1069 2 : model_profile_number = i; exit
1070 : end if
1071 : end do
1072 2 : if (model_profile_number == 0) then
1073 0 : write(*, *) 'model_profile_number == 0, cannot happen?'
1074 0 : ierr = -1
1075 : return
1076 : end if
1077 2 : end subroutine pick_model_profile_number
1078 :
1079 :
1080 2 : subroutine make_room_for_profile_info( &
1081 : model_number, max_num_mods, num_models, model_numbers, model_priorities, model_logs, ierr)
1082 : integer, intent(in) :: model_number, max_num_mods
1083 : integer, intent(inout) :: num_models
1084 : integer, pointer, dimension(:) :: model_numbers, model_priorities, model_logs
1085 : integer, intent(out) :: ierr
1086 : integer :: i, j, nm
1087 : logical, parameter :: dbg = .false.
1088 : include 'formats'
1089 2 : ierr = 0
1090 : ! delete models with model number greater or equal to current model number
1091 2 : nm = num_models; j = 0
1092 3 : do i=1, nm
1093 3 : if (model_numbers(i) < model_number .and. model_logs(i) <= max_num_mods) then
1094 : ! keep this one
1095 1 : j = j+1
1096 1 : if (j < i) then
1097 0 : model_numbers(j) = model_numbers(i)
1098 0 : model_priorities(j) = model_priorities(i)
1099 0 : model_logs(j) = model_logs(i)
1100 : end if
1101 : end if
1102 : end do
1103 2 : num_models = j
1104 2 : if (num_models == max_num_mods) then ! pick one to delete
1105 : j = 1
1106 0 : do i=2, num_models
1107 : if (dbg) then
1108 : write(*,3) 'model_priorities(i)', i, model_priorities(i)
1109 : write(*,3) 'model_priorities(j)', j, model_priorities(j)
1110 : write(*,3) 'model_numbers(i)', i, model_numbers(i)
1111 : write(*,3) 'model_numbers(j)', j, model_numbers(j)
1112 : write(*,*) 'model_priorities(i) < model_priorities(j)', model_priorities(i) < model_priorities(j)
1113 : write(*,*) 'model_numbers(i) < model_numbers(j)', model_numbers(i) < model_numbers(j)
1114 : end if
1115 0 : if (model_priorities(i) < model_priorities(j)) then
1116 : if (dbg) write(*,3) '1 change j'
1117 : j = i
1118 0 : else if (model_priorities(i) == model_priorities(j) .and. &
1119 : model_numbers(i) < model_numbers(j)) then
1120 : if (dbg) write(*,3) '2 change j'
1121 0 : j = i
1122 : end if
1123 : if (dbg) write(*,3) 'new j', j
1124 0 : if (dbg) write(*,*)
1125 : end do
1126 : ! delete j
1127 : if (dbg) write(*,*) 'delete j', j
1128 0 : do i=j+1, num_models
1129 0 : model_numbers(i-1) = model_numbers(i)
1130 0 : model_priorities(i-1) = model_priorities(i)
1131 0 : model_logs(i-1) = model_logs(i)
1132 : end do
1133 0 : num_models = num_models-1
1134 : end if
1135 2 : end subroutine make_room_for_profile_info
1136 :
1137 :
1138 2 : subroutine read_profiles_info( &
1139 : fname, max_num_mods, num_models, model_numbers, model_priorities, model_logs)
1140 : character (len=*), intent(in) :: fname
1141 : integer, intent(in) :: max_num_mods
1142 : integer, intent(out) :: num_models
1143 : integer, pointer, dimension(:) :: model_numbers, model_priorities, model_logs
1144 : integer :: iounit, i, ierr
1145 2 : num_models = 0
1146 2 : ierr = 0
1147 2 : open(newunit=iounit, file=trim(fname), action='read', status='old', iostat=ierr)
1148 2 : if (ierr == 0) then ! file exists
1149 1 : read(iounit, *, iostat=ierr) num_models
1150 1 : if (ierr == 0) then
1151 1 : if (num_models > max_num_mods) num_models = max_num_mods
1152 2 : do i=1, num_models
1153 1 : read(iounit, *, iostat=ierr) model_numbers(i), model_priorities(i), model_logs(i)
1154 2 : if (ierr /= 0) exit
1155 : end do
1156 : end if
1157 1 : close(iounit)
1158 1 : if (ierr /= 0) num_models = 0
1159 : end if
1160 2 : end subroutine read_profiles_info
1161 :
1162 :
1163 2 : subroutine get_model_profile_filename(s, model_profile_number)
1164 : ! sets s% model_profile_filename and s% model_controls_filename
1165 : type (star_info), pointer :: s
1166 : integer, intent(in) :: model_profile_number
1167 : character (len=strlen) :: profile_prefix, controls_prefix, model_prefix, fstring
1168 : integer :: num_digits
1169 :
1170 2 : profile_prefix = trim(s% log_directory) // '/' // trim(s% profile_data_prefix)
1171 2 : controls_prefix = trim(s% log_directory) // '/' // trim(s% controls_data_prefix)
1172 2 : model_prefix = trim(s% log_directory) // '/' // trim(s% model_data_prefix)
1173 :
1174 2 : num_digits = 1 + log10(dble(max(1,model_profile_number)))
1175 2 : write(fstring,'( "(a,i",i2.2,".",i2.2,",a)" )') num_digits, num_digits
1176 :
1177 : write(s% model_profile_filename, fmt=fstring) &
1178 2 : trim(profile_prefix), model_profile_number, trim(s% profile_data_suffix)
1179 : write(s% model_controls_filename, fmt=fstring) &
1180 2 : trim(controls_prefix), model_profile_number, trim(s% controls_data_suffix)
1181 : write(s% model_data_filename, fmt=fstring) &
1182 2 : trim(model_prefix), model_profile_number, trim(s% model_data_suffix)
1183 :
1184 2 : end subroutine get_model_profile_filename
1185 :
1186 : end module profile
|