// File: /workspace/github_c_makefile_star2_O2/PoulinV[P]AxiCLASS/build/../source/thermodynamics.c
// Function: thermodynamics_solve
int thermodynamics_solve(
                         struct precision * ppr,
                         struct background * pba,
                         struct thermodynamics * pth,
                         struct thermo_workspace * ptw,
                         double * pvecback
                         ) {
  /** Summary: */

  /** - define local variables */
  /* Index of current approximation scheme */
  int index_ap;
  /* number of time intervals of one approximation scheme */
  int interval_number;
  /* index running over such time intervals */
  int index_interval;
  /* edge of intervals where approximation scheme is uniform: z_ini, z_switch_1, ..., z_end */
  double * interval_limit;
  /* other z sampling variables */
  int i;
  double * mz_output;

  /* contains all fixed parameters which should be passed to thermodynamics_derivs */
  struct thermodynamics_parameters_and_workspace tpaw;

  /* function pointer to ODE evolver and names of possible evolvers. */
  extern int evolver_rk(EVOLVER_PROTOTYPE);
  extern int evolver_ndf15(EVOLVER_PROTOTYPE);
  int (*generic_evolver)(EVOLVER_PROTOTYPE) = evolver_ndf15;

  /** - choose evolver */
  switch (ppr->thermo_evolver) {
  case rk:
    generic_evolver = evolver_rk;
    break;
  case ndf15:
    generic_evolver = evolver_ndf15;
    break;
  }

  /** - define the fields of the 'thermodynamics parameter and workspace' structure */
  tpaw.pba = pba;
  tpaw.ppr = ppr;
  tpaw.pth = pth;
  tpaw.pvecback = pvecback;
  tpaw.ptw = ptw;

  /** - define time sampling: create a local array of minus z values
      called mz (from mz=-zinitial growing towards mz=0) */

  class_alloc(mz_output,pth->tt_size*sizeof(double), pth->error_message);
  for (i=0; i < pth->tt_size; ++i) {
    mz_output[i] = -pth->z_table[pth->tt_size-1-i];
  }

  /** - define intervals for each approximation scheme */

  /* create the array of interval limits */
  class_alloc(interval_limit,(ptw->ptdw->ap_size+1)*sizeof(double),pth->error_message);
  /* fix interval number to number of approximations */
  interval_number = ptw->ptdw->ap_size;
  /* integration starts at z_ini and ends at z_end */
  interval_limit[0]= mz_output[0];
  interval_limit[ptw->ptdw->ap_size] = mz_output[ptw->Nz_tot-1];
  /* each interval ends with the proper ending redshift of its approximation */
  for (index_ap=0; index_ap < ptw->ptdw->ap_size-1; index_ap++) {
    interval_limit[index_ap+1] = -ptw->ptdw->ap_z_limits[index_ap];
  }

  /** - loop over intervals over which approximation scheme is
      uniform. For each interval: */

  for (index_interval=0; index_interval<interval_number; index_interval++) {

    /** - --> (a) fix current approximation scheme. */

    ptw->ptdw->ap_current = index_interval;

    /** - --> (b) define the vector of quantities to be integrated
        over. If the current interval starts from the
        initial time zinitial, fill the vector with initial
        conditions. If it starts from an approximation
        switching point, redistribute correctly the values
        from the previous to the new vector. For both
        RECFAST and HYREC, the vector consists of Tmat, x_H,
        x_He, + others for exotic models */

    class_call(thermodynamics_vector_init(ppr,
                                          pba,
                                          pth,
                                          interval_limit[index_interval],
                                          ptw),
               pth->error_message,
               pth->error_message);

    /* find the value of last_index_back at z = - interval_limit[index_interval], in order to speed up
       subsequent interpolations in thermodynamics_derivs */
    class_call(background_at_z(pba,
                               -interval_limit[index_interval],
                               normal_info,
                               inter_normal,
                               &(ptw->last_index_back),
                               pvecback),
               pba->error_message,
               pth->error_message);

    /** - --> (c1) If we have the optical depth tau_reio as input the
        last evolver step (reionization approximation) is done
        separately in a loop, to find the approximate redshift of
        reionization given the input of tau_reio, using a bisection
        method. This is similar to the general CLASS shooting method,
        but doing this step here is more advantageous since we only
        need to do repeatedly the last approximation step of the
        integration, instead of the full background and thermodynamics
        module */
    if ((pth->reio_z_or_tau == reio_tau) && (index_interval == ptw->ptdw->index_ap_reio)) {

      class_call(thermodynamics_reionization_evolve_with_tau(&tpaw,
                                                             interval_limit[index_interval],
                                                             interval_limit[index_interval+1],
                                                             mz_output,
                                                             pth->tt_size),
                 pth->error_message,
                 pth->error_message);
    }

    /** --> (c2) otherwise, just integrate quantities over the current interval. */
    else{

      class_call(generic_evolver(thermodynamics_derivs,
                                 interval_limit[index_interval],
                                 interval_limit[index_interval+1],
                                 ptw->ptdw->ptv->y,
                                 ptw->ptdw->ptv->used_in_output,
                                 ptw->ptdw->ptv->ti_size,
                                 &tpaw,
                                 ppr->tol_thermo_integration,
                                 ppr->smallest_allowed_variation,
                                 thermodynamics_timescale,  // timescale
                                 ppr->thermo_integration_stepsize, // stepsize = this number * timescale
                                 mz_output, // values of z for output
                                 pth->tt_size, // size of previous array
                                 thermodynamics_sources, // function for output
                                 NULL, // print variables
                                 pth->error_message),
                 pth->error_message,
                 pth->error_message);
    }

  }

  /** - Compute reionization optical depth, if not supplied as input parameter */
  if (pth->reio_z_or_tau == reio_z) {

    class_call(thermodynamics_reionization_get_tau(ppr,
                                                   pba,
                                                   pth,
                                                   ptw),
               pth->error_message,
               pth->error_message);

    pth->tau_reio=ptw->reionization_optical_depth;

  }

  /** - free quantities allocated at the beginning of the routine */
  if (ptw->ptdw->ap_size != 0) {
    class_call(thermodynamics_vector_free(ptw->ptdw->ptv),
               pth->error_message,
               pth->error_message);
  }

  free(interval_limit);
  free(mz_output);

  return _SUCCESS_;

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x878, %rsp            # imm = 0x878
movq %r8, 0x28(%rsp)
movq %rcx, %rbp
movq %rdx, %rbx
movq %rsi, %r13
movq %rdi, 0x20(%rsp)
cmpl $0x0, 0x1b0(%rdi)
jne 0x663a5
leaq -0x5ac53(%rip), %rax    # 0xb750
jmp 0x663ac
leaq -0x5a5d0(%rip), %rax    # 0xbddc
movq %rax, 0x10(%rsp)
movq %r13, 0x48(%rsp)
movq 0x20(%rsp), %rax
movq %rax, 0x50(%rsp)
movq %rbx, 0x58(%rsp)
movq 0x28(%rsp), %rax
movq %rax, 0x68(%rsp)
movq %rbp, 0x60(%rsp)
movslq 0xf08(%rbx), %r15
movq %r15, %rdi
shlq $0x3, %rdi
callq 0x8490
testq %rax, %rax
je 0x6661c
movq %rax, %r12
xorl %eax, %eax
testl %r15d, %r15d
movl $0x0, %ecx
cmovgl %r15d, %ecx
leal -0x1(%r15), %edx
cmpq %rax, %rcx
je 0x6642c
movq 0xf10(%rbx), %rsi
movslq %edx, %rdx
movsd (%rsi,%rdx,8), %xmm0
xorps 0x7ee10(%rip), %xmm0    # 0xe5230
movlps %xmm0, (%r12,%rax,8)
incq %rax
decl %edx
jmp 0x66405
movq %rbx, 0x8(%rsp)
movq %r13, 0x18(%rsp)
movq 0x80(%rbp), %r15
movslq 0x94(%r15), %r14
leaq 0x8(,%r14,8), %rdi
callq 0x8490
testq %rax, %rax
je 0x66660
movq %rax, %r13
movsd (%r12), %xmm0
movsd %xmm0, (%rax)
movslq 0x10(%rbp), %rax
movsd -0x8(%r12,%rax,8), %xmm0
movsd %xmm0, (%r13,%r14,8)
cmpl $0x2, %r14d
pushq $0x1
popq %rax
cmovgel %r14d, %eax
decl %eax
xorl %ecx, %ecx
movaps 0x7eda1(%rip), %xmm1    # 0xe5230
movq 0x8(%rsp), %rdx
cmpq %rcx, %rax
je 0x664b3
movq 0xa0(%r15), %rsi
movsd (%rsi,%rcx,8), %xmm0
xorps %xmm1, %xmm0
movlps %xmm0, 0x8(%r13,%rcx,8)
incq %rcx
jmp 0x66494
leaq 0x78(%rbp), %rax
movq %rax, 0x40(%rsp)
leaq 0x1064(%rdx), %rax
movq %rax, (%rsp)
xorl %r15d, %r15d
testl %r14d, %r14d
cmovlel %r15d, %r14d
cmpq %r15, %r14
je 0x666ac
movq %r12, %rbx
movq 0x80(%rbp), %rax
movl %r15d, 0x90(%rax)
movq %r13, %r12
movsd (%r13,%r15,8), %xmm0
movq %rbp, %rcx
movq 0x18(%rsp), %rbp
movq %rbp, %rsi
movaps %xmm0, 0x30(%rsp)
movq %rcx, %r13
callq 0x66fe1
testl %eax, %eax
jne 0x666e9
movaps 0x30(%rsp), %xmm0
xorps 0x7ed0f(%rip), %xmm0    # 0xe5230
movq %rbp, %rdi
pushq $0x1
popq %rsi
xorl %edx, %edx
movq 0x40(%rsp), %rcx
movq 0x28(%rsp), %r8
callq 0x585e8
cmpl $0x1, %eax
je 0x66728
movq 0x8(%rsp), %rdi
cmpl $0x1, 0x1c(%rdi)
movq %r13, %rbp
movq 0x80(%r13), %rax
jne 0x66593
movl 0x8c(%rax), %ecx
cmpq %rcx, %r15
jne 0x66593
movq %r12, %r13
movsd 0x8(%r12,%r15,8), %xmm1
movl 0xf08(%rdi), %edx
leaq 0x48(%rsp), %rdi
movaps 0x30(%rsp), %xmm0
movq %rbx, %r12
movq %rbx, %rsi
callq 0x676ee
testl %eax, %eax
je 0x6660f
jmp 0x667fb
movq %r12, %r13
movsd 0x8(%r12,%r15,8), %xmm1
movq 0xb8(%rax), %rax
movq 0x18(%rax), %rsi
movq 0x28(%rax), %rdx
movl (%rax), %ecx
movq 0x20(%rsp), %rax
movsd 0xa28(%rax), %xmm3
movsd 0x1b8(%rax), %xmm2
movsd 0x1c0(%rax), %xmm4
movl 0xf08(%rdi), %eax
subq $0x8, %rsp
leaq 0x1d24(%rip), %rdi      # 0x68300
movaps 0x38(%rsp), %xmm0
leaq 0x50(%rsp), %r8
leaq 0x27bf(%rip), %r9       # 0x68dac
pushq 0x8(%rsp)
pushq $0x0
pushq 0xdc99f(%rip)           # 0x142f98
pushq %rax
movq %rbx, %r12
pushq %rbx
callq *0x40(%rsp)
addq $0x30, %rsp
cmpl $0x1, %eax
je 0x6676d
incq %r15
movq 0x8(%rsp), %rdx
jmp 0x664d1
leal (,%r15,8), %ecx
leaq 0x7e9d9(%rip), %rsi     # 0xe5004
leaq 0x9f94f(%rip), %rdx     # 0x105f81
leaq 0x70(%rsp), %r14
movq %r14, %rdi
xorl %eax, %eax
callq 0x2e014
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x7e9e5(%rip), %rsi     # 0xe5034
leaq 0x9f935(%rip), %rdx     # 0x105f8b
movq %rbx, %rdi
movl $0x635, %ecx            # imm = 0x635
jmp 0x666a4
leal 0x8(,%r14,8), %ecx
leaq 0x7e995(%rip), %rsi     # 0xe5004
leaq 0x9f92a(%rip), %rdx     # 0x105fa0
leaq 0x70(%rsp), %r14
movq %r14, %rdi
xorl %eax, %eax
callq 0x2e014
movq 0x8(%rsp), %rdi
addq $0x1064, %rdi           # imm = 0x1064
leaq 0x7e99c(%rip), %rsi     # 0xe5034
leaq 0x9f8ec(%rip), %rdx     # 0x105f8b
movl $0x63d, %ecx            # imm = 0x63D
movq %r14, %r8
jmp 0x66838
cmpl $0x0, 0x1c(%rdx)
je 0x667ac
movq 0x80(%rbp), %rax
cmpl $0x0, 0x94(%rax)
je 0x666d2
movq 0xb8(%rax), %rdi
callq 0x695be
movq %r13, %rdi
callq 0x8430
movq %r12, %rdi
callq 0x8430
xorl %eax, %eax
jmp 0x66842
leaq 0x7ed00(%rip), %rsi     # 0xe53f0
leaq 0x9f8b8(%rip), %rdx     # 0x105faf
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x2e014
leaq 0x7e920(%rip), %rsi     # 0xe5034
leaq 0x9f870(%rip), %rdx     # 0x105f8b
movq %r14, %rdi
movl $0x660, %ecx            # imm = 0x660
jmp 0x66835
movq 0x18(%rsp), %rcx
addq $0xd1c, %rcx            # imm = 0xD1C
leaq 0x7ecb5(%rip), %rsi     # 0xe53f0
leaq 0x9f8bc(%rip), %rdx     # 0x105ffe
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
xorl %eax, %eax
callq 0x2e014
leaq 0x7e8dc(%rip), %rsi     # 0xe5034
leaq 0x9f82c(%rip), %rdx     # 0x105f8b
movq (%rsp), %rdi
movl $0x66b, %ecx            # imm = 0x66B
jmp 0x66835
leaq 0x7ec7c(%rip), %rsi     # 0xe53f0
leaq 0x9f985(%rip), %rdx     # 0x106100
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x2e014
leaq 0x7e89c(%rip), %rsi     # 0xe5034
leaq 0x9f7ec(%rip), %rdx     # 0x105f8b
movq %r14, %rdi
movl $0x695, %ecx            # imm = 0x695
jmp 0x66835
movq %rbp, %rcx
movq %rdx, %rbx
callq 0x693b9
testl %eax, %eax
je 0x66854
leaq 0x7ec2a(%rip), %rsi     # 0xe53f0
leaq 0x9faba(%rip), %rdx     # 0x106287
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x2e014
leaq 0x7e84a(%rip), %rsi     # 0xe5034
leaq 0x9f79a(%rip), %rdx     # 0x105f8b
movq %r14, %rdi
movl $0x6a2, %ecx            # imm = 0x6A2
jmp 0x66835
leaq 0x7ebee(%rip), %rsi     # 0xe53f0
leaq 0x9f869(%rip), %rdx     # 0x106072
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x2e014
leaq 0x7e80e(%rip), %rsi     # 0xe5034
leaq 0x9f75e(%rip), %rdx     # 0x105f8b
movq %r14, %rdi
movl $0x67e, %ecx            # imm = 0x67E
movq %rbx, %r8
xorl %eax, %eax
callq 0x2e014
pushq $0x1
popq %rax
addq $0x878, %rsp            # imm = 0x878
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x70(%rbp), %xmm0
movsd %xmm0, 0x20(%rbx)
jmp 0x666b6