// File: /workspace/github_cpp_makefile_star2_O3/TBody[P]atomicpp/atomicpp/RateEquations.cpp
// Function: atomicpp::RateEquations::calculateChargeExchangePopulationEquation(double, std::vector<double, std::allocator<double>> const&, std::vector<double, std::allocator<double>> const&, double, double, double)
void RateEquations::calculateChargeExchangePopulationEquation(
	const double Nn,
	const std::vector<double>& Nzk,
	const std::vector<double>& Vzk,
	const double Te,
	const double Ne,
	const double plasma_ionisation_potential
	){
	
	std::vector<double>     cx_rec_to_below(Z+1, 0.0); //Rate (m^-3 s^-1)
	std::vector<double>   cx_rec_from_above(Z+1, 0.0);
	std::vector<double>   cx_rec_p_to_below(Z+1, 0.0); //Momentum (kg m/s s^-1 = N)
	std::vector<double> cx_rec_p_from_above(Z+1, 0.0);

	std::shared_ptr<RateCoefficient> cx_recombination_coefficient = rate_coefficients["cx_rec"];
	for(int k=0; k < Z; ++k){//N.b. iterating over all data indicies of the rate coefficient, hence the <
		double cx_recombination_coefficient_evaluated = cx_recombination_coefficient->call0D(k, Te, Ne);
		
		// Note that cx_recombination coefficients are indexed from 1 to Z
		int k_rec = k + 1; //The target charge state for recombination -- makes it a bit easier to understand

		double cx_recombination_rate_factor = cx_recombination_coefficient_evaluated * Nn;

		// Want both the target and source densities to be above the Nthres density threshold
		if((Nzk[k_rec] > Nthres) and (Nzk[k_rec-1] > Nthres)){
			cx_rec_to_below[k_rec]     = -cx_recombination_rate_factor * Nzk[k_rec];
			cx_rec_from_above[k_rec-1] = +cx_recombination_rate_factor * Nzk[k_rec];

			cx_rec_p_to_below[k_rec]     = -cx_recombination_rate_factor * mz * amu_to_kg * Vzk[k_rec];
			cx_rec_p_from_above[k_rec-1] = +cx_recombination_rate_factor * mz * amu_to_kg * Vzk[k_rec];
		}
		// Otherwise, the rates stay as default = 0
	}


	for(int k=0; k <= Z; ++k){
		std::vector<double> rates_for_stage          = {dNzk[k], cx_rec_to_below[k], cx_rec_from_above[k]}; //Add cx to the sum
		std::pair<double, double> neumaier_pair_dNzk = neumaierSum(rates_for_stage,dNzk_correction[k]); //Extend on previous compensation
		dNzk[k]                                      = neumaier_pair_dNzk.first;
		dNzk_correction[k]                           = neumaier_pair_dNzk.second; //Overwrite compensation with updated value

		std::vector<double> momentum_for_stage           = {F_zk[k], cx_rec_p_to_below[k], cx_rec_p_from_above[k]}; //Add cx to the sum
		std::pair<double, double> neumaier_pair_momentum = neumaierSum(momentum_for_stage,F_zk_correction[k]);
		F_zk[k]                                          = neumaier_pair_momentum.first; 
		F_zk_correction[k]                               = neumaier_pair_momentum.second; //Overwrite compensation with updated value
	}
	//For Neumaier summation of the change in Nn from the different rates 
	std::vector<double> dNn_from_stage(Z, 0.0); //Only need Z indices, but adding an extra to the end means that the calculation
	// can be performed in a single loop
	// Ionisation potential (in eV per transition) is not a rate coefficient, but is treated as one since the interpolation methods and
	// data shape are identical. This is used to calculate the effect of iz and rec on the electron energy (in Pcool).
	std::shared_ptr<RateCoefficient> ionisation_potential = rate_coefficients["ionisation_potential"];
	for(int k=0; k < Z; ++k){
		double ionisation_potential_evaluated            = ionisation_potential->call0D(k, Te, Ne);
		// Charge exchange simultaneously neutralises an impurity ion and ionises a dominant-species neutral. Modify Pcool to reflect this.
		Pcool                                            += eV_to_J * (ionisation_potential_evaluated-plasma_ionisation_potential) * cx_rec_from_above[k];

		dNn_from_stage[k] = -cx_rec_from_above[k]; //N.b. cx_rec_from_above[Z] = 0.0 always, included so we can use a single loop
	}
	
	std::pair<double, double> neumaier_pair_dNn = neumaierSum(dNn_from_stage);
	dNn = neumaier_pair_dNn.first + neumaier_pair_dNn.second;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movsd %xmm3, -0x130(%rbp)
movsd %xmm2, -0xd0(%rbp)
movsd %xmm1, -0xc8(%rbp)
movq %rdx, -0xa8(%rbp)
movq %rsi, %r15
movsd %xmm0, -0xa0(%rbp)
movq %rdi, %rbx
movslq 0x34(%rdi), %r14
incq %r14
leaq -0x98(%rbp), %r12
movq $0x0, (%r12)
leaq -0xe8(%rbp), %r13
movq %r13, %rdi
callq 0x533c
leaq -0x158(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x1802a
leaq -0xe8(%rbp), %rdi
callq 0x5a80
movslq 0x34(%rbx), %r14
incq %r14
movq $0x0, (%r12)
leaq -0x118(%rbp), %r13
movq %r13, %rdi
callq 0x533c
leaq -0xe8(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x1802a
leaq -0x118(%rbp), %rdi
callq 0x5a80
movslq 0x34(%rbx), %r14
incq %r14
movq $0x0, (%r12)
leaq -0x100(%rbp), %r13
movq %r13, %rdi
callq 0x533c
leaq -0x118(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x1802a
leaq -0x100(%rbp), %rdi
callq 0x5a80
movslq 0x34(%rbx), %r14
incq %r14
movq $0x0, (%r12)
leaq -0x78(%rbp), %r13
movq %r13, %rdi
callq 0x533c
leaq -0x100(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x1802a
leaq -0x78(%rbp), %rdi
callq 0x5a80
leaq -0x78(%rbp), %r14
movq %r14, %rdi
callq 0x4540
leaq 0x39f8(%rip), %rsi      # 0x237a9
leaq -0x98(%rbp), %rdi
movq %r14, %rdx
callq 0x4160
leaq -0x98(%rbp), %rsi
movq %rbx, %rdi
callq 0xd17e
leaq -0x140(%rbp), %rdi
movq %rax, %rsi
callq 0xd174
leaq -0x98(%rbp), %rdi
callq 0x41a0
leaq -0x78(%rbp), %rdi
callq 0x58c6
movl 0x34(%rbx), %eax
testl %eax, %eax
jle 0x1ffa6
xorl %r14d, %r14d
leaq -0x140(%rbp), %r12
movq %r15, -0x120(%rbp)
movq %r12, %rdi
callq 0x53ae
movq %rax, %rdi
movl %r14d, %esi
movsd -0xc8(%rbp), %xmm0
movsd -0xd0(%rbp), %xmm1
callq 0x11312
movaps %xmm0, -0x40(%rbp)
leaq 0x1(%r14), %r13
movq %r15, %rdi
movq %r13, %rsi
callq 0x184f2
movsd (%rax), %xmm0
ucomisd 0x40(%rbx), %xmm0
jbe 0x1ff96
movq %r15, %rdi
movq %r14, %rsi
callq 0x184f2
movsd (%rax), %xmm0
ucomisd 0x40(%rbx), %xmm0
jbe 0x1ff96
movapd -0x40(%rbp), %xmm0
mulsd -0xa0(%rbp), %xmm0
movapd %xmm0, -0x40(%rbp)
xorpd 0x5208(%rip), %xmm0     # 0x25090
movapd %xmm0, -0x60(%rbp)
movq %r15, %rdi
movq %r13, %rsi
callq 0x184f2
movsd (%rax), %xmm0
mulsd -0x60(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
leaq -0x158(%rbp), %rdi
movq %r13, %rsi
callq 0x539c
movsd -0x48(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r15, %rdi
movq %r13, %rsi
callq 0x184f2
movsd (%rax), %xmm0
mulsd -0x40(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
leaq -0xe8(%rbp), %rdi
movq %r14, %rsi
callq 0x539c
movsd -0x48(%rbp), %xmm0
movsd %xmm0, (%rax)
movapd -0x60(%rbp), %xmm1
mulsd 0x38(%rbx), %xmm1
movsd 0x516f(%rip), %xmm0     # 0x25070
mulsd %xmm0, %xmm1
movapd %xmm1, -0x60(%rbp)
movq %r12, %r15
movq -0xa8(%rbp), %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x184f2
movapd -0x60(%rbp), %xmm0
mulsd (%rax), %xmm0
movapd %xmm0, -0x60(%rbp)
leaq -0x118(%rbp), %rdi
movq %r13, %rsi
callq 0x539c
movaps -0x60(%rbp), %xmm0
movsd %xmm0, (%rax)
movapd -0x40(%rbp), %xmm0
mulsd 0x38(%rbx), %xmm0
mulsd 0x511a(%rip), %xmm0     # 0x25070
movapd %xmm0, -0x40(%rbp)
movq %r12, %rdi
movq %r15, %r12
movq -0x120(%rbp), %r15
movq %r13, %rsi
callq 0x184f2
movapd -0x40(%rbp), %xmm0
mulsd (%rax), %xmm0
movapd %xmm0, -0x40(%rbp)
leaq -0x100(%rbp), %rdi
movq %r14, %rsi
callq 0x539c
movapd -0x40(%rbp), %xmm0
movsd %xmm0, (%rax)
movslq 0x34(%rbx), %rax
movq %r13, %r14
cmpq %rax, %r13
jl 0x1fe0f
testl %eax, %eax
js 0x201ae
leaq 0x70(%rbx), %rax
movq %rax, -0x48(%rbp)
leaq 0xa0(%rbx), %rax
movq %rax, -0xa8(%rbp)
leaq 0x88(%rbx), %r15
leaq 0xb8(%rbx), %rax
movq %rax, -0xa0(%rbp)
movq $-0x1, %r14
movq %rbx, -0x128(%rbp)
movq %r15, %r12
incq %r14
movq -0x48(%rbp), %r13
movq %r13, %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0x78(%rbp)
leaq -0x158(%rbp), %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0x70(%rbp)
leaq -0xe8(%rbp), %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0x68(%rbp)
leaq -0xc0(%rbp), %rbx
movq %rbx, %rdi
callq 0x533c
movl $0x3, %edx
leaq -0x98(%rbp), %rdi
leaq -0x78(%rbp), %rsi
movq %rbx, %rcx
callq 0x1841c
movq %rbx, %rdi
callq 0x5a80
movq -0xa8(%rbp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
leaq -0x98(%rbp), %rdi
callq 0x20e6e
movsd %xmm0, -0x60(%rbp)
movsd %xmm1, -0x40(%rbp)
movq %r13, %rdi
movq %r14, %rsi
callq 0x539c
movsd -0x60(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r15, %rdi
movq %r14, %rsi
callq 0x539c
movsd -0x40(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r12, %r15
movq %r12, %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0xc0(%rbp)
leaq -0x118(%rbp), %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0xb8(%rbp)
leaq -0x100(%rbp), %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0xb0(%rbp)
leaq -0x29(%rbp), %r12
movq %r12, %rdi
callq 0x533c
movl $0x3, %edx
leaq -0x78(%rbp), %rdi
movq %rbx, %rsi
movq %r12, %rcx
callq 0x1841c
movq %r12, %rdi
callq 0x5a80
movq -0xa0(%rbp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
leaq -0x78(%rbp), %rbx
movq %rbx, %rdi
callq 0x20e6e
movsd %xmm0, -0x60(%rbp)
movsd %xmm1, -0x40(%rbp)
movq %r15, %rdi
movq %r14, %rsi
callq 0x539c
movsd -0x60(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r12, %rdi
movq %r14, %rsi
callq 0x539c
movsd -0x40(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %rbx, %rdi
callq 0x53c6
leaq -0x98(%rbp), %rdi
callq 0x53c6
movq -0x128(%rbp), %rbx
movslq 0x34(%rbx), %r13
cmpq %r13, %r14
jl 0x1ffe7
jmp 0x201b1
movslq %eax, %r13
leaq -0x98(%rbp), %r14
movq $0x0, (%r14)
leaq -0xc0(%rbp), %r15
movq %r15, %rdi
callq 0x533c
leaq -0x78(%rbp), %rdi
movq %r13, %rsi
movq %r14, %rdx
movq %r15, %rcx
callq 0x1802a
leaq -0xc0(%rbp), %rdi
callq 0x5a80
leaq -0x29(%rbp), %r14
movq %r14, %rdi
callq 0x4540
leaq 0x35e5(%rip), %rsi      # 0x237e4
leaq -0x98(%rbp), %rdi
movq %r14, %rdx
callq 0x4160
leaq -0x98(%rbp), %rsi
movq %rbx, %rdi
callq 0xd17e
leaq -0xc0(%rbp), %rdi
movq %rax, %rsi
callq 0xd174
leaq -0x98(%rbp), %rdi
callq 0x41a0
leaq -0x29(%rbp), %rdi
callq 0x58c6
cmpl $0x0, 0x34(%rbx)
jle 0x202ed
xorl %r14d, %r14d
leaq -0xe8(%rbp), %r12
leaq -0x78(%rbp), %r13
movq %r15, %rdi
callq 0x53ae
movq %rax, %rdi
movl %r14d, %esi
movsd -0xc8(%rbp), %xmm0
movsd -0xd0(%rbp), %xmm1
callq 0x11312
subsd -0x130(%rbp), %xmm0
mulsd 0x4dec(%rip), %xmm0     # 0x25078
movsd %xmm0, -0x40(%rbp)
movq %r12, %rdi
movq %r14, %rsi
callq 0x539c
movsd -0x40(%rbp), %xmm0
mulsd (%rax), %xmm0
addsd 0x60(%rbx), %xmm0
movsd %xmm0, 0x60(%rbx)
movq %r12, %rdi
movq %r14, %rsi
callq 0x539c
movsd (%rax), %xmm0
xorps 0x4dcb(%rip), %xmm0     # 0x25090
movaps %xmm0, -0x40(%rbp)
movq %r13, %rdi
movq %r14, %rsi
callq 0x539c
movapd -0x40(%rbp), %xmm0
movlpd %xmm0, (%rax)
incq %r14
movslq 0x34(%rbx), %rax
cmpq %rax, %r14
jl 0x20259
leaq -0x78(%rbp), %r14
xorpd %xmm0, %xmm0
movq %r14, %rdi
callq 0x20e6e
addsd %xmm0, %xmm1
movsd %xmm1, 0xe0(%rbx)
leaq -0xc0(%rbp), %rdi
callq 0x53b8
movq %r14, %rdi
callq 0x53c6
leaq -0x140(%rbp), %rdi
callq 0x53b8
leaq -0x100(%rbp), %rdi
callq 0x53c6
leaq -0x118(%rbp), %rdi
callq 0x53c6
leaq -0xe8(%rbp), %rdi
callq 0x53c6
leaq -0x158(%rbp), %rdi
callq 0x53c6
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq -0x98(%rbp), %rdi
callq 0x41a0
jmp 0x2037f
movq %rax, %rbx
leaq -0x29(%rbp), %rdi
callq 0x58c6
jmp 0x2040d
jmp 0x20413
movq %rax, %rbx
leaq -0x98(%rbp), %rdi
callq 0x41a0
jmp 0x203a6
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x58c6
jmp 0x2044d
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x5a80
jmp 0x20459
movq %rax, %rbx
leaq -0x100(%rbp), %rdi
callq 0x5a80
jmp 0x20465
movq %rax, %rbx
leaq -0x118(%rbp), %rdi
callq 0x5a80
jmp 0x20471
movq %rax, %rbx
leaq -0xe8(%rbp), %rdi
callq 0x5a80
jmp 0x2047d
movq %rax, %rbx
leaq -0xc0(%rbp), %rdi
callq 0x53b8
leaq -0x78(%rbp), %rdi
jmp 0x20437
movq %rax, %rbx
leaq -0xc0(%rbp), %rdi
callq 0x5a80
jmp 0x20441
movq %rax, %rbx
leaq -0x29(%rbp), %rdi
callq 0x5a80
leaq -0x98(%rbp), %rdi
callq 0x53c6
jmp 0x20441
movq %rax, %rbx
leaq -0x140(%rbp), %rdi
callq 0x53b8
leaq -0x100(%rbp), %rdi
callq 0x53c6
leaq -0x118(%rbp), %rdi
callq 0x53c6
leaq -0xe8(%rbp), %rdi
callq 0x53c6
leaq -0x158(%rbp), %rdi
callq 0x53c6
movq %rbx, %rdi
callq 0x45a0
nop