// File: /workspace/github_cpp_makefile_star2_O2/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, -0x128(%rbp)
movsd %xmm2, -0xd8(%rbp)
movsd %xmm1, -0xd0(%rbp)
movq %rdx, -0xb0(%rbp)
movq %rsi, %r15
movsd %xmm0, -0xa8(%rbp)
movq %rdi, %rbx
movslq 0x34(%rdi), %r14
incq %r14
leaq -0x98(%rbp), %r12
andq $0x0, (%r12)
leaq -0xf0(%rbp), %r13
movq %r13, %rdi
callq 0x531c
leaq -0x148(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x17a40
leaq -0xf0(%rbp), %rdi
callq 0x5a64
movslq 0x34(%rbx), %r14
incq %r14
andq $0x0, (%r12)
leaq -0x120(%rbp), %r13
movq %r13, %rdi
callq 0x531c
leaq -0xf0(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x17a40
leaq -0x120(%rbp), %rdi
callq 0x5a64
movslq 0x34(%rbx), %r14
incq %r14
andq $0x0, (%r12)
leaq -0x108(%rbp), %r13
movq %r13, %rdi
callq 0x531c
leaq -0x120(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x17a40
leaq -0x108(%rbp), %rdi
callq 0x5a64
movslq 0x34(%rbx), %r14
incq %r14
andq $0x0, (%r12)
leaq -0x78(%rbp), %r13
movq %r13, %rdi
callq 0x531c
leaq -0x108(%rbp), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x17a40
leaq -0x78(%rbp), %rdi
callq 0x5a64
leaq -0x78(%rbp), %r14
movq %r14, %rdi
callq 0x4540
leaq 0x3280(%rip), %rsi      # 0x227a9
leaq -0x98(%rbp), %rdi
movq %r14, %rdx
callq 0x4160
leaq -0x98(%rbp), %rsi
movq %rbx, %rdi
callq 0xcf52
leaq -0x158(%rbp), %r12
movq %r12, %rdi
movq %rax, %rsi
callq 0xcf48
leaq -0x98(%rbp), %rdi
callq 0x41a0
leaq -0x78(%rbp), %rdi
callq 0x58aa
xorl %r14d, %r14d
movq %r15, -0xa0(%rbp)
movslq 0x34(%rbx), %rax
cmpq %rax, %r14
jge 0x1f715
movq %r12, %rdi
callq 0x538e
movq %rax, %rdi
movl %r14d, %esi
movsd -0xd0(%rbp), %xmm0
movsd -0xd8(%rbp), %xmm1
callq 0x10f96
movapd %xmm0, -0x40(%rbp)
leaq 0x1(%r14), %r13
movq %r15, %rdi
movq %r13, %rsi
callq 0x17efc
movsd (%rax), %xmm0
ucomisd 0x40(%rbx), %xmm0
jbe 0x1f70d
movq %r15, %rdi
movq %r14, %rsi
callq 0x17efc
movsd (%rax), %xmm0
ucomisd 0x40(%rbx), %xmm0
jbe 0x1f70d
movapd -0x40(%rbp), %xmm0
mulsd -0xa8(%rbp), %xmm0
movapd %xmm0, -0x40(%rbp)
xorpd 0x4a91(%rip), %xmm0     # 0x24090
movapd %xmm0, -0x60(%rbp)
movq %r15, %rdi
movq %r13, %rsi
callq 0x17efc
movsd (%rax), %xmm0
mulsd -0x60(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
leaq -0x148(%rbp), %rdi
movq %r13, %rsi
callq 0x537c
movsd -0x48(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r15, %rdi
movq %r13, %rsi
callq 0x17efc
movsd (%rax), %xmm0
mulsd -0x40(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
leaq -0xf0(%rbp), %rdi
movq %r14, %rsi
callq 0x537c
movsd -0x48(%rbp), %xmm0
movsd %xmm0, (%rax)
movapd -0x60(%rbp), %xmm1
mulsd 0x38(%rbx), %xmm1
movsd 0x4a00(%rip), %xmm0     # 0x24078
mulsd %xmm0, %xmm1
movapd %xmm1, -0x60(%rbp)
movq %r12, %r15
movq -0xb0(%rbp), %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x17efc
movapd -0x60(%rbp), %xmm0
mulsd (%rax), %xmm0
movapd %xmm0, -0x60(%rbp)
leaq -0x120(%rbp), %rdi
movq %r13, %rsi
callq 0x537c
movaps -0x60(%rbp), %xmm0
movsd %xmm0, (%rax)
movapd -0x40(%rbp), %xmm0
mulsd 0x38(%rbx), %xmm0
mulsd 0x49ab(%rip), %xmm0     # 0x24078
movapd %xmm0, -0x40(%rbp)
movq %r12, %rdi
movq %r15, %r12
movq -0xa0(%rbp), %r15
movq %r13, %rsi
callq 0x17efc
movapd -0x40(%rbp), %xmm0
mulsd (%rax), %xmm0
movapd %xmm0, -0x40(%rbp)
leaq -0x108(%rbp), %rdi
movq %r14, %rsi
callq 0x537c
movapd -0x40(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r13, %r14
jmp 0x1f578
leaq 0x70(%rbx), %rcx
movq %rcx, -0x48(%rbp)
leaq 0xa0(%rbx), %rcx
movq %rcx, -0xb0(%rbp)
leaq 0x88(%rbx), %r15
leaq 0xb8(%rbx), %rcx
movq %rcx, -0xa0(%rbp)
xorl %r14d, %r14d
leaq -0x98(%rbp), %r12
movq %rbx, -0x130(%rbp)
movq %r15, -0xa8(%rbp)
movslq %eax, %r13
cmpq %r13, %r14
jg 0x1f91f
movq -0x48(%rbp), %r13
movq %r13, %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movsd %xmm0, -0x78(%rbp)
leaq -0x148(%rbp), %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movsd %xmm0, -0x70(%rbp)
leaq -0xf0(%rbp), %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movsd %xmm0, -0x68(%rbp)
leaq -0xc8(%rbp), %rbx
movq %rbx, %rdi
callq 0x531c
movq %r12, %rdi
leaq -0x78(%rbp), %rsi
pushq $0x3
popq %rdx
movq %rbx, %rcx
callq 0x17e2a
movq %rbx, %rdi
callq 0x5a64
movq -0xb0(%rbp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
leaq -0x98(%rbp), %rdi
callq 0x20572
movsd %xmm0, -0x60(%rbp)
movsd %xmm1, -0x40(%rbp)
movq %r13, %rdi
movq %r14, %rsi
callq 0x537c
movsd -0x60(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r15, %rdi
movq %r14, %rsi
callq 0x537c
movsd -0x40(%rbp), %xmm0
movsd %xmm0, (%rax)
movq -0xa8(%rbp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movsd %xmm0, -0xc8(%rbp)
leaq -0x120(%rbp), %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movsd %xmm0, -0xc0(%rbp)
leaq -0x108(%rbp), %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movsd %xmm0, -0xb8(%rbp)
leaq -0x29(%rbp), %r12
movq %r12, %rdi
callq 0x531c
leaq -0x78(%rbp), %r13
movq %r13, %rdi
movq %rbx, %rsi
pushq $0x3
popq %rdx
movq %r12, %rcx
callq 0x17e2a
movq %r12, %rdi
callq 0x5a64
movq -0xa0(%rbp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0x537c
movsd (%rax), %xmm0
movq %r13, %rdi
callq 0x20572
movsd %xmm0, -0x60(%rbp)
movsd %xmm1, -0x40(%rbp)
movq %r15, %rdi
movq %r14, %rsi
callq 0x537c
movsd -0x60(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r12, %rdi
movq %r14, %rsi
callq 0x537c
movsd -0x40(%rbp), %xmm0
movsd %xmm0, (%rax)
movq %r13, %rdi
callq 0x53a6
leaq -0x98(%rbp), %r12
movq %r12, %rdi
callq 0x53a6
incq %r14
movq -0x130(%rbp), %rbx
movl 0x34(%rbx), %eax
jmp 0x1f758
leaq -0x98(%rbp), %r14
andq $0x0, (%r14)
leaq -0xc8(%rbp), %r15
movq %r15, %rdi
callq 0x531c
leaq -0x78(%rbp), %rdi
movq %r13, %rsi
movq %r14, %rdx
movq %r15, %rcx
callq 0x17a40
leaq -0xc8(%rbp), %rdi
callq 0x5a64
leaq -0x29(%rbp), %r14
movq %r14, %rdi
callq 0x4540
leaq 0x2e7a(%rip), %rsi      # 0x227e4
leaq -0x98(%rbp), %rdi
movq %r14, %rdx
callq 0x4160
leaq -0x98(%rbp), %rsi
movq %rbx, %rdi
callq 0xcf52
leaq -0xc8(%rbp), %r14
movq %r14, %rdi
movq %rax, %rsi
callq 0xcf48
leaq -0x98(%rbp), %rdi
callq 0x41a0
leaq -0x29(%rbp), %rdi
callq 0x58aa
xorl %r15d, %r15d
leaq -0xf0(%rbp), %r12
leaq -0x78(%rbp), %r13
movslq 0x34(%rbx), %rax
cmpq %rax, %r15
jge 0x1fa56
movq %r14, %rdi
callq 0x538e
movq %rax, %rdi
movl %r15d, %esi
movsd -0xd0(%rbp), %xmm0
movsd -0xd8(%rbp), %xmm1
callq 0x10f96
subsd -0x128(%rbp), %xmm0
mulsd 0x4673(%rip), %xmm0     # 0x24070
movsd %xmm0, -0x40(%rbp)
movq %r12, %rdi
movq %r15, %rsi
callq 0x537c
movsd -0x40(%rbp), %xmm0
mulsd (%rax), %xmm0
addsd 0x60(%rbx), %xmm0
movsd %xmm0, 0x60(%rbx)
movq %r12, %rdi
movq %r15, %rsi
callq 0x537c
movsd (%rax), %xmm0
xorps 0x465a(%rip), %xmm0     # 0x24090
movaps %xmm0, -0x40(%rbp)
movq %r13, %rdi
movq %r15, %rsi
callq 0x537c
movapd -0x40(%rbp), %xmm0
movlpd %xmm0, (%rax)
incq %r15
jmp 0x1f9bd
leaq -0x78(%rbp), %r14
xorpd %xmm0, %xmm0
movq %r14, %rdi
callq 0x20572
addsd %xmm0, %xmm1
movsd %xmm1, 0xe0(%rbx)
leaq -0xc8(%rbp), %rdi
callq 0x5398
movq %r14, %rdi
callq 0x53a6
leaq -0x158(%rbp), %rdi
callq 0x5398
leaq -0x108(%rbp), %rdi
callq 0x53a6
leaq -0x120(%rbp), %rdi
callq 0x53a6
leaq -0xf0(%rbp), %rdi
callq 0x53a6
leaq -0x148(%rbp), %rdi
callq 0x53a6
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 0x1fae8
movq %rax, %rbx
leaq -0x29(%rbp), %rdi
callq 0x58aa
jmp 0x1fb76
jmp 0x1fb7c
movq %rax, %rbx
leaq -0x98(%rbp), %rdi
callq 0x41a0
jmp 0x1fb0f
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x58aa
jmp 0x1fbb6
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x5a64
jmp 0x1fbc2
movq %rax, %rbx
leaq -0x108(%rbp), %rdi
callq 0x5a64
jmp 0x1fbce
movq %rax, %rbx
leaq -0x120(%rbp), %rdi
callq 0x5a64
jmp 0x1fbda
movq %rax, %rbx
leaq -0xf0(%rbp), %rdi
callq 0x5a64
jmp 0x1fbe6
movq %rax, %rbx
leaq -0xc8(%rbp), %rdi
callq 0x5398
leaq -0x78(%rbp), %rdi
jmp 0x1fba0
movq %rax, %rbx
leaq -0xc8(%rbp), %rdi
callq 0x5a64
jmp 0x1fbaa
movq %rax, %rbx
leaq -0x29(%rbp), %rdi
callq 0x5a64
leaq -0x98(%rbp), %rdi
callq 0x53a6
jmp 0x1fbaa
movq %rax, %rbx
leaq -0x158(%rbp), %rdi
callq 0x5398
leaq -0x108(%rbp), %rdi
callq 0x53a6
leaq -0x120(%rbp), %rdi
callq 0x53a6
leaq -0xf0(%rbp), %rdi
callq 0x53a6
leaq -0x148(%rbp), %rdi
callq 0x53a6
movq %rbx, %rdi
callq 0x45a0