A Tour of MESA/star

This document gives a mid-level overview of the structure and control flow of MESA/star.

The star program

The star executable is generated in the context of a work directory, the template of which lives at star/work. This executable is linked against the various MESA modules, including star itself.

The source file src/run.f90 contains the program statement. This file invokes routines that read the star_job namelist and then start a run.

The invoked routines live in star/job in the files run_star.f90 and run_star_support.f90. (This directory also contains the code associated with the standard run_star_extras hooks and the special test_suite_extras routines used to produce output for the TestHub.)

The routines in run_star_support.f90 contain key parts of the control flow. The routine run1_star knows how to initialize the various things needed for a star run and contains the evolve_loop. This is a simple do loop, each iteration of which is a stellar evolution step.

1
2
3
4
5
6
         evolve_loop: do while(continue_evolve_loop) ! evolve one step per loop
         
            continue_evolve_loop = do_evolve_one_step(s, dbg, ierr)
            if (failed('do_evolve_one_step',ierr)) return

         end do evolve_loop

Within that loop are calls the routine do_evolve_one_step, which contains the step_loop. This loop consists of attempting a stellar evolution step, and then either accepting the step or rejecting it and repeating the attempt (via a redo or retry).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
         step_loop: do ! may need to repeat this loop
         
            if (stop_is_requested(s)) then
               continue_evolve_loop = .false.
               result = terminate
               exit
            end if
         
            result = star_evolve_step(id, first_try)
            if (result == keep_going) result = star_check_model(id)
            if (result == keep_going) result = s% extras_check_model(id)
            if (result == keep_going) result = star_pick_next_timestep(id)            
            if (result == keep_going) exit step_loop
            
            model_number = get_model_number(id, ierr)
            if (failed('get_model_number',ierr)) return
                           
            if (result == retry .and. s% job% report_retries) then
               write(*,'(i6,3x,a,/)') model_number, &
                  'retry reason ' // trim(result_reason_str(s% result_reason))
            end if
            
            if (result == redo) then
               result = star_prepare_to_redo(id)
            end if
            if (result == retry) then
               result = star_prepare_to_retry(id)
            end if
            if (result == terminate) then
               continue_evolve_loop = .false.
               exit step_loop
            end if
            first_try = .false.
            
         end do step_loop

The stellar evolution step itself is triggered via a call to star_evolve_step, which is a function defined in the public star_lib interface.

In star/public, in the file star_lib.f90, this function is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
      integer function star_evolve_step(id, first_try)
         ! returns either keep_going, redo, retry, or terminate
         use star_def, only: terminate, keep_going
         use star_utils, only: start_time, update_time
         integer, intent(in) :: id
         logical, intent(in) :: first_try 
            ! true on the first try to take this step
            ! false if this is a repeat for a retry
         type (star_info), pointer :: s
         integer :: ierr
         integer(8) :: time0, clock_rate
         real(dp) :: total
         star_evolve_step = terminate
         ierr = 0
         call star_ptr(id, s, ierr)
         if (ierr /= 0) return
         if (s% doing_timing) call start_time(s, time0, total)
         star_evolve_step = star_evolve_step_part1(id, first_try)
         if (star_evolve_step == keep_going) &
            star_evolve_step = star_evolve_step_part2(id, first_try)
         if (s% doing_timing) call update_time(s, time0, total, s% time_evolve_step)         
      end function star_evolve_step

You can see that this splits the step into two parts (part1 and part2). Those are implemented in star/private.

Before we go deeper, we should become familiar with the star_info type, which is conventionally assigned the variable name s.

The star_info structure

The star_info type is defined in the star_data module. (It is split off in order to allow for star to depend on other modules that need to know the definition of the star_info type, without introducing circular dependencies.)

The definition of this derived type occurs in public/star_data_def.f90, but most of the details are deferred to various include files (*.inc).

First, is star_data.inc, which has information about the structure of the star itself.

! star_data.inc

include "star_data_step_input.inc" 
   ! input for taking a step.
   ! modified during the step so that at end holds the new model.
   ! can be saved in models and photos.
   
include "star_data_step_work.inc"
   ! working storage for data derived from inputs while taking a step.
   ! can be undefined when start to take a step (e.g. by calling fill_arrays_with_NaNs).
   ! not saved in models or in photos.
   
include "star_data_procedures.inc"
   ! procedure pointers for hooks and such

This defers to another set of files that divide things up based on whether they are inputs for a step or things that are calculated from these inputs during the process of taking a step.

Some of the most important variables defined in star_data_step_input.inc are the arrays xh(:,:) and xa(:,:), which hold the structure variables and abundance variables for the model. These are the “truth” about the stellar structure. Other quantities are derived from these through simple transformations (e.g., Rho) or by the interaction with other modules (e.g., Cp via the eos).

The various namelist options for star_job, controls, and pgstar are also part of the star_info structure. They are also added through *.inc files, but these live in star_data/private.

Note

If you are adding a new inlist option, your best bet is to pick an existing option that it is similar to and grep in star and star_data. That will generally show you all the places you will need to add code.

There is far too much contained in star_info to go through it piece by piece, but you should spend some time perusing theses files to get a feel for what sorts of things go where.

star/private

The guts of MESA live in star/private.

evolve.f90

There are many files, but the starting point is evolve.f90. This file contains the definitions of the part1 and part2 functions we saw previously.

Part 1 is mainly preparing for the step (see the functions do_evolve_step_part1 and do_step_part1). It ends with making an initial estimate for the mass transfer rate. (The necessity of the part1/part2 split is primarily driven by binary, where the two stars interact in a way that means their mass change rates are related.)

Part 2 contains the bulk of the work associate with a step (see the functions do_evolve_step_part2 and do_step_part2).

It contains a loop (implicit_mdot_loop) that allows this part to be repeated multiple times in cases where the mass change rate may depend on the calculated stellar structure.

Within this loop is what one generally thinks of as taking a stellar evolution step. First, some of the operator-split actions are taken (i.e., CPM, diffusion). Then, the fully-coupled parts are solved in the call to do_struct_burn_mix.

do_struct_burn_mix

The function do_struct_burn_mix lives in struct_burn_mix.f90.

Warning

Forthcoming