// File: /workspace/github_c_makefile_star2_O3/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, %r15
movq %rdi, 0x20(%rsp)
cmpl $0x0, 0x1b0(%rdi)
jne 0x6a786
leaq -0x5d754(%rip), %rax    # 0xd030
jmp 0x6a78d
leaq -0x5d0d5(%rip), %rax    # 0xd6b8
movq %rax, 0x10(%rsp)
movq %r15, 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), %r13
leaq (,%r13,8), %rdi
callq 0x8460
testq %rax, %rax
je 0x6aa2f
movq %rax, %r12
movq %r15, 0x18(%rsp)
testl %r13d, %r13d
jle 0x6a80f
movq 0xf10(%rbx), %rax
leaq (%rax,%r13,8), %rax
addq $-0x8, %rax
xorl %ecx, %ecx
movaps 0x83a39(%rip), %xmm0    # 0xee230
movsd (%rax), %xmm1
xorps %xmm0, %xmm1
movlps %xmm1, (%r12,%rcx,8)
incq %rcx
addq $-0x8, %rax
cmpq %rcx, %r13
jne 0x6a7f7
movq 0x80(%rbp), %r15
movslq 0x94(%r15), %r14
leaq 0x8(,%r14,8), %rdi
callq 0x8460
testq %rax, %rax
je 0x6aa72
movq %rax, %r13
movsd (%r12), %xmm0
movsd %xmm0, (%rax)
movslq 0x10(%rbp), %rax
movq %r12, 0x8(%rsp)
movsd -0x8(%r12,%rax,8), %xmm0
movsd %xmm0, (%r13,%r14,8)
cmpl $0x2, %r14d
jl 0x6a887
leal -0x1(%r14), %eax
movq 0xa0(%r15), %rcx
xorl %edx, %edx
movaps 0x839bf(%rip), %xmm0    # 0xee230
movsd (%rcx,%rdx,8), %xmm1
xorps %xmm0, %xmm1
movlps %xmm1, 0x8(%r13,%rdx,8)
incq %rdx
cmpq %rdx, %rax
jne 0x6a871
testl %r14d, %r14d
jle 0x6a9ed
leaq 0x78(%rbp), %rax
movq %rax, 0x40(%rsp)
leaq 0x1064(%rbx), %rax
movq %rax, (%rsp)
xorl %r15d, %r15d
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
movq %rbx, %r13
movq %rbx, %rdx
movaps %xmm0, 0x30(%rsp)
movq %rcx, %rbx
callq 0x6b3d6
testl %eax, %eax
jne 0x6ab0e
movaps 0x30(%rsp), %xmm0
xorps 0x8393f(%rip), %xmm0    # 0xee230
movq %rbp, %rdi
movl $0x1, %esi
xorl %edx, %edx
movq 0x40(%rsp), %rcx
movq 0x28(%rsp), %r8
callq 0x5c3a8
cmpl $0x1, %eax
je 0x6ab4d
cmpl $0x1, 0x1c(%r13)
movq %rbx, %rbp
movq 0x80(%rbx), %rax
jne 0x6a961
movl 0x8c(%rax), %ecx
cmpq %rcx, %r15
jne 0x6a961
movsd 0x8(%r12,%r15,8), %xmm1
movq %r13, %rbx
movl 0xf08(%r13), %edx
leaq 0x48(%rsp), %rdi
movaps 0x30(%rsp), %xmm0
movq 0x8(%rsp), %rsi
callq 0x6bb5f
testl %eax, %eax
je 0x6a9de
jmp 0x6abdd
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
movq %r13, %rbx
movl 0xf08(%r13), %eax
subq $0x8, %rsp
leaq 0x1e7f(%rip), %rdi      # 0x6c82a
movaps 0x38(%rsp), %xmm0
leaq 0x50(%rsp), %r8
leaq 0x290f(%rip), %r9       # 0x6d2cb
pushq 0x8(%rsp)
pushq $0x0
pushq 0xde5d0(%rip)           # 0x148f98
pushq %rax
pushq 0x30(%rsp)
callq *0x40(%rsp)
addq $0x30, %rsp
cmpl $0x1, %eax
je 0x6ab92
incq %r15
cmpq %r15, %r14
movq %r12, %r13
jne 0x6a8a7
cmpl $0x0, 0x1c(%rbx)
movq 0x8(%rsp), %r14
je 0x6aabc
movq 0x80(%rbp), %rax
cmpl $0x0, 0x94(%rax)
je 0x6aa18
movq 0xb8(%rax), %rdi
callq 0x6dafb
movq %r13, %rdi
callq 0x8410
movq %r14, %rdi
callq 0x8410
xorl %eax, %eax
jmp 0x6ac26
shll $0x3, %r13d
leaq 0x835ca(%rip), %rsi     # 0xee004
leaq 0xa46a0(%rip), %rdx     # 0x10f0e1
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movl %r13d, %ecx
xorl %eax, %eax
callq 0x30af0
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x835d3(%rip), %rsi     # 0xee034
leaq 0xa4683(%rip), %rdx     # 0x10f0eb
movq %rbx, %rdi
movl $0x635, %ecx            # imm = 0x635
jmp 0x6aab4
leal 0x8(,%r14,8), %ecx
leaq 0x83583(%rip), %rsi     # 0xee004
leaq 0xa4678(%rip), %rdx     # 0x10f100
leaq 0x70(%rsp), %r14
movq %r14, %rdi
xorl %eax, %eax
callq 0x30af0
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x8358f(%rip), %rsi     # 0xee034
leaq 0xa463f(%rip), %rdx     # 0x10f0eb
movq %rbx, %rdi
movl $0x63d, %ecx            # imm = 0x63D
movq %r14, %r8
jmp 0x6ac1a
movq %rbx, %rdx
movq %rbp, %rcx
callq 0x6d8dc
testl %eax, %eax
je 0x6abce
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x83913(%rip), %rsi     # 0xee3f0
leaq 0xa4903(%rip), %rdx     # 0x10f3e7
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rcx
xorl %eax, %eax
callq 0x30af0
leaq 0x83537(%rip), %rsi     # 0xee034
leaq 0xa45e7(%rip), %rdx     # 0x10f0eb
movq %rbx, %rdi
movl $0x6a2, %ecx            # imm = 0x6A2
jmp 0x6aab4
leaq 0x838db(%rip), %rsi     # 0xee3f0
leaq 0xa45f3(%rip), %rdx     # 0x10f10f
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x30af0
leaq 0x834fb(%rip), %rsi     # 0xee034
leaq 0xa45ab(%rip), %rdx     # 0x10f0eb
movq %r14, %rdi
movl $0x660, %ecx            # imm = 0x660
jmp 0x6ac17
movq 0x18(%rsp), %rcx
addq $0xd1c, %rcx            # imm = 0xD1C
leaq 0x83890(%rip), %rsi     # 0xee3f0
leaq 0xa45f7(%rip), %rdx     # 0x10f15e
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
xorl %eax, %eax
callq 0x30af0
leaq 0x834b7(%rip), %rsi     # 0xee034
leaq 0xa4567(%rip), %rdx     # 0x10f0eb
movq (%rsp), %rdi
movl $0x66b, %ecx            # imm = 0x66B
jmp 0x6ac17
leaq 0x83857(%rip), %rsi     # 0xee3f0
leaq 0xa46c0(%rip), %rdx     # 0x10f260
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x30af0
leaq 0x83477(%rip), %rsi     # 0xee034
leaq 0xa4527(%rip), %rdx     # 0x10f0eb
movq %r14, %rdi
movl $0x695, %ecx            # imm = 0x695
jmp 0x6ac17
movsd 0x70(%rbp), %xmm0
movsd %xmm0, 0x20(%rbx)
jmp 0x6a9fc
leaq 0x8380c(%rip), %rsi     # 0xee3f0
leaq 0xa45e7(%rip), %rdx     # 0x10f1d2
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x30af0
leaq 0x8342c(%rip), %rsi     # 0xee034
leaq 0xa44dc(%rip), %rdx     # 0x10f0eb
movq %r14, %rdi
movl $0x67e, %ecx            # imm = 0x67E
movq %rbx, %r8
xorl %eax, %eax
callq 0x30af0
movl $0x1, %eax
addq $0x878, %rsp            # imm = 0x878
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq