// File: /workspace/github_c_makefile_star2_O1/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, %r14
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, 0x20(%rsp)
cmpl $0x0, 0x1b0(%rdi)
jne 0x6d10d
leaq -0x601bf(%rip), %rax    # 0xcf4c
jmp 0x6d114
leaq -0x5fb40(%rip), %rax    # 0xd5d4
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 %r14, 0x60(%rsp)
movslq 0xf08(%rbx), %r13
leaq (,%r13,8), %rdi
callq 0x8460
movq %rax, 0x8(%rsp)
testq %rax, %rax
je 0x6d397
movq %r15, 0x18(%rsp)
testl %r13d, %r13d
jle 0x6d191
movq 0xf10(%rbx), %rax
movaps 0x840ba(%rip), %xmm0    # 0xf1230
movq 0x8(%rsp), %rcx
movsd -0x8(%rax,%r13,8), %xmm1
xorps %xmm0, %xmm1
movlps %xmm1, (%rcx)
addq $0x8, %rcx
decq %r13
jne 0x6d17b
movq 0x80(%r14), %r15
movslq 0x94(%r15), %rbp
leaq 0x8(,%rbp,8), %rdi
callq 0x8460
testq %rax, %rax
je 0x6d3da
movq %rax, %r13
movq 0x8(%rsp), %rcx
movsd (%rcx), %xmm0
movsd %xmm0, (%rax)
movslq 0x10(%r14), %rax
movsd -0x8(%rcx,%rax,8), %xmm0
movsd %xmm0, (%r13,%rbp,8)
cmpl $0x2, %ebp
jl 0x6d204
leal -0x1(%rbp), %eax
movq 0xa0(%r15), %rcx
xorl %edx, %edx
movaps 0x84042(%rip), %xmm0    # 0xf1230
movsd (%rcx,%rdx,8), %xmm1
xorps %xmm0, %xmm1
movlps %xmm1, 0x8(%r13,%rdx,8)
incq %rdx
cmpq %rdx, %rax
jne 0x6d1ee
testl %ebp, %ebp
jle 0x6d358
leaq 0x78(%r14), %rax
movq %rax, 0x40(%rsp)
leaq 0x1064(%rbx), %rax
movq %rax, (%rsp)
xorl %r15d, %r15d
movq 0x18(%rsp), %r12
movq 0x80(%r14), %rax
movl %r15d, 0x90(%rax)
movsd (%r13,%r15,8), %xmm0
movq %r12, %rsi
movq %rbx, %rdx
movaps %xmm0, 0x30(%rsp)
movq %r14, %rcx
callq 0x6dd3e
testl %eax, %eax
jne 0x6d475
movaps 0x30(%rsp), %xmm0
xorps 0x83fcc(%rip), %xmm0    # 0xf1230
movq %r12, %rdi
movl $0x1, %esi
xorl %edx, %edx
movq 0x40(%rsp), %rcx
movq 0x28(%rsp), %r8
callq 0x5ea8c
cmpl $0x1, %eax
je 0x6d4b4
cmpl $0x1, 0x1c(%rbx)
jne 0x6d2cc
movq 0x80(%r14), %rax
movl 0x8c(%rax), %eax
cmpq %rax, %r15
jne 0x6d2cc
movsd 0x8(%r13,%r15,8), %xmm1
movl 0xf08(%rbx), %edx
leaq 0x48(%rsp), %rdi
movaps 0x30(%rsp), %xmm0
movq 0x8(%rsp), %rsi
callq 0x6e543
testl %eax, %eax
je 0x6d34c
jmp 0x6d545
movsd 0x8(%r13,%r15,8), %xmm1
movq 0x80(%r14), %rax
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(%rbx), %eax
subq $0x8, %rsp
leaq 0x1fba(%rip), %rdi      # 0x6f2d3
movaps 0x38(%rsp), %xmm0
leaq 0x50(%rsp), %r8
leaq 0x2a3a(%rip), %r9       # 0x6fd64
pushq 0x8(%rsp)
pushq $0x0
pushq 0xdec62(%rip)           # 0x14bf98
pushq %rax
pushq 0x30(%rsp)
callq *0x40(%rsp)
addq $0x30, %rsp
cmpl $0x1, %eax
je 0x6d4f9
incq %r15
cmpq %r15, %rbp
jne 0x6d228
cmpl $0x0, 0x1c(%rbx)
je 0x6d423
movq 0x80(%r14), %rax
cmpl $0x0, 0x94(%rax)
je 0x6d37e
movq 0xb8(%rax), %rdi
callq 0x70586
movq %r13, %rdi
callq 0x8410
movq 0x8(%rsp), %rdi
callq 0x8410
xorl %eax, %eax
jmp 0x6d58e
shll $0x3, %r13d
leaq 0x83c62(%rip), %rsi     # 0xf1004
leaq 0xa4ce8(%rip), %rdx     # 0x112091
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movl %r13d, %ecx
xorl %eax, %eax
callq 0x30c2c
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x83c6b(%rip), %rsi     # 0xf1034
leaq 0xa4ccb(%rip), %rdx     # 0x11209b
movq %rbx, %rdi
movl $0x635, %ecx            # imm = 0x635
jmp 0x6d41b
leal 0x8(,%rbp,8), %ecx
leaq 0x83c1c(%rip), %rsi     # 0xf1004
leaq 0xa4cc1(%rip), %rdx     # 0x1120b0
leaq 0x70(%rsp), %r14
movq %r14, %rdi
xorl %eax, %eax
callq 0x30c2c
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x83c28(%rip), %rsi     # 0xf1034
leaq 0xa4c88(%rip), %rdx     # 0x11209b
movq %rbx, %rdi
movl $0x63d, %ecx            # imm = 0x63D
movq %r14, %r8
jmp 0x6d582
movq %rbx, %rdx
movq %r14, %rcx
callq 0x7037b
testl %eax, %eax
je 0x6d535
addq $0x1064, %rbx           # imm = 0x1064
leaq 0x83fac(%rip), %rsi     # 0xf13f0
leaq 0xa4f4c(%rip), %rdx     # 0x112397
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rcx
xorl %eax, %eax
callq 0x30c2c
leaq 0x83bd0(%rip), %rsi     # 0xf1034
leaq 0xa4c30(%rip), %rdx     # 0x11209b
movq %rbx, %rdi
movl $0x6a2, %ecx            # imm = 0x6A2
jmp 0x6d41b
leaq 0x83f74(%rip), %rsi     # 0xf13f0
leaq 0xa4c3c(%rip), %rdx     # 0x1120bf
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x30c2c
leaq 0x83b94(%rip), %rsi     # 0xf1034
leaq 0xa4bf4(%rip), %rdx     # 0x11209b
movq %r14, %rdi
movl $0x660, %ecx            # imm = 0x660
jmp 0x6d57f
movq 0x18(%rsp), %rcx
addq $0xd1c, %rcx            # imm = 0xD1C
leaq 0x83f29(%rip), %rsi     # 0xf13f0
leaq 0xa4c40(%rip), %rdx     # 0x11210e
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
xorl %eax, %eax
callq 0x30c2c
leaq 0x83b50(%rip), %rsi     # 0xf1034
leaq 0xa4bb0(%rip), %rdx     # 0x11209b
movq (%rsp), %rdi
movl $0x66b, %ecx            # imm = 0x66B
jmp 0x6d57f
leaq 0x83ef0(%rip), %rsi     # 0xf13f0
leaq 0xa4d09(%rip), %rdx     # 0x112210
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x30c2c
leaq 0x83b10(%rip), %rsi     # 0xf1034
leaq 0xa4b70(%rip), %rdx     # 0x11209b
movq %r14, %rdi
movl $0x695, %ecx            # imm = 0x695
jmp 0x6d57f
movsd 0x70(%r14), %xmm0
movsd %xmm0, 0x20(%rbx)
jmp 0x6d362
leaq 0x83ea4(%rip), %rsi     # 0xf13f0
leaq 0xa4c2f(%rip), %rdx     # 0x112182
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %r14
movq %r14, %rcx
xorl %eax, %eax
callq 0x30c2c
leaq 0x83ac4(%rip), %rsi     # 0xf1034
leaq 0xa4b24(%rip), %rdx     # 0x11209b
movq %r14, %rdi
movl $0x67e, %ecx            # imm = 0x67E
movq %rbx, %r8
xorl %eax, %eax
callq 0x30c2c
movl $0x1, %eax
addq $0x878, %rsp            # imm = 0x878
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq