// File: /workspace/github_cpp_makefile_star2_O3/TBody[P]atomicpp/Prad.cpp
// Function: main
int main(){
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//Setup the atomicpp::ImpuritySpecies object
	const std::string expt_results_json="sd1d-case-05.json";
	std::string impurity_symbol="c";
	std::string hydrogen_symbol="h";

	atomicpp::ImpuritySpecies impurity(impurity_symbol);
	atomicpp::ImpuritySpecies hydrogen(hydrogen_symbol);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Process the expt_results_json to extract
	// 	density(s) 					= electron density (in m^-3)
	// 	temperature(s)				= electron/ion temperature (in eV)
	// 	neutral_fraction(s)			= neutral density/electron density (no units)
	// where s is 1D distance index. Time is already contracted (using final time-step)
	// Second argument is impurity fraction
	atomicpp::SD1DData experiment(expt_results_json, 1e-2);
	// N.b. This is only for training the data

	//Cast the SD1D data into a form which is like how the function will be called by SD1D
	//This is all not required for SD1D -- it's just to train the code with reasonable numbers
		// const double mz = impurity.get_mass(); //amu

		int constant_position_index = 0;
		double Te = experiment.get_temperature()[constant_position_index];
		double Ne = experiment.get_density()[constant_position_index];
		double Vi = 3.10080599e-01 * 69205.6142373; //Picked random values from SD1D output. Using rho_s0 * Omega_ci to normalise (probably wrong!!)
		double Vn = 1.32440666e-01 * 69205.6142373; //Picked random values from SD1D output. Using rho_s0 * Omega_ci to normalise (probably wrong!!)
		double neutral_fraction = experiment.get_neutral_fraction()[constant_position_index];
		double Nn = Ne * neutral_fraction;
		
		double Nz = experiment.get_impurity_density()[constant_position_index];
		// Compute the iz-stage-distribution to create the Nzk (charged-resolved impurity) density std::vector
		std::vector<double> iz_stage_distribution = computeIonisationDistribution(impurity, Te, Ne, Nz, Nn);
		std::vector<double> Nzk(impurity.get_atomic_number()+1);
		for(int k=0; k<=impurity.get_atomic_number(); ++k){
			// Use the plasma temperature, and then add a scaling based on the charge so that there's different velocities for each charge
			// (so that momentum transfer results in an observable effect)
			Nzk[k] = Nz * iz_stage_distribution[k];
			// std::printf("Nzk^%d: %e \n", k, Nzk[k]); //To train python data
		}
		std::vector<double> Vzk(impurity.get_atomic_number()+1);
		for(int k=0; k<=impurity.get_atomic_number(); ++k){
			Vzk[k] = Vi;
			// sqrt(2 * Te * eV_to_J / (mz * amu_to_kg));
			// std::printf("Vz_i^(%i):  %+.2e [m/s]\n",k ,Vzk[k]);
		}

		std::vector<double> Nhk(hydrogen.get_atomic_number()+1);
		Nhk[0] = Nn;
		Nhk[1] = Ne;
		std::vector<double> Vhk(hydrogen.get_atomic_number()+1);
		for(int k=0; k<=hydrogen.get_atomic_number(); ++k){
			Vhk[k] = Vi;
		}
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Time dependant solver code
	
	atomicpp::RateEquations impurity_derivatives(impurity); //Organised as a atomicpp::RateEquations object for cleanliness
	impurity_derivatives.setThresholdDensity(0); //Density threshold - ignore ionisation stages which don't have at least this density
	impurity_derivatives.setDominantIonMass(1.0); //Dominant ion mass in amu, for the stopping time calculation

	atomicpp::DerivStruct derivative_struct = impurity_derivatives.computeDerivs(50, 1e19, Vi, Nn, Vn, Nzk, Vzk);
	// double Pcool             = derivative_struct.Pcool;
	// double Prad              = derivative_struct.Prad;
	// std::vector<double> dNzk = derivative_struct.dNzk;
	// std::vector<double> F_zk = derivative_struct.F_zk;
	// double dNe               = derivative_struct.dNe;
	// double F_i               = derivative_struct.F_i;
	// double dNn               = derivative_struct.dNn;
	// double F_n               = derivative_struct.F_n;
	
	std::printf("\nDerivatives for %s\n",impurity.get_name().c_str());
	impurity_derivatives.printDerivativeStruct(derivative_struct);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// atomicpp::RateEquations hydrogen_derivatives(hydrogen); //Organised as a atomicpp::RateEquations object for cleanliness
	// hydrogen_derivatives.setThresholdDensity(0.0); //Density threshold - ignore ionisation stages which don't have at least this density

	// atomicpp::DerivStruct derivative_struct_H = hydrogen_derivatives.computeDerivsHydrogen(6309.573445, 1e19, Nhk, Vhk);
	
	// std::printf("\nDerivatives for %s\n",hydrogen.get_name().c_str());
	// hydrogen_derivatives.printDerivativeStruct(derivative_struct_H);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


	// Comparison to Post PSI
	// Ne = 1e18;
	// Te = 6;
	// Nn = 0;
	// total_power = computeRadiatedPower(impurity, Te, Ne, Nz, Nn);
	// std::cout << "Comparison to PSI paper:" << total_power << "W/m3" << std::endl;
	// std::cout << "Comparison to PSI paper:" << total_power/(Nz*Ne) << "Wm3" << std::endl;


	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// std::pair<int, double> Te_interp, Ne_interp;
	// Te_interp = findSharedInterpolation(impurity.get_rate_coefficient("blank")->get_log_temp(), Te);
	// Ne_interp = findSharedInterpolation(impurity.get_rate_coefficient("blank")->get_log_dens(), Ne);

	// int Z = impurity.get_atomic_number();
	// const double eV_to_J = 1.60217662e-19; //J per eV

	// if (impurity.get_has_charge_exchange()){
	// 	std::vector<double> dNn_from_stage(impurity.get_atomic_number(), 0.0);
	// 	std::vector<double>   cx_rec_to_below(Z+1, 0.0);
	// 	std::vector<double> cx_rec_from_above(Z+1, 0.0);

	// 	std::shared_ptr<atomicpp::RateCoefficient> cx_recombination_coefficient = impurity.get_rate_coefficient("cx_rec");
	// 	std::shared_ptr<atomicpp::RateCoefficient> cx_power_coefficient = impurity.get_rate_coefficient("cx_power");

	// 	for(int k=0; k < Z; ++k){//N.b. iterating over all data indicies of the rate coefficient, hence the <
	// 		// m^-3 s^-1
	// 		double cx_recombination_coefficient_evaluated = cx_recombination_coefficient->call0D(k, Te_interp, Ne_interp);
	// 		double cx_recombination_rate = cx_recombination_coefficient_evaluated * Nn * Nzk[k+1];

	// 		// W m^-3
	// 		double cx_power_coefficient_evaluated = cx_power_coefficient->call0D(k, Te_interp, Ne_interp);
	// 		double cx_power_rate = cx_power_coefficient_evaluated * Nn * Nzk[k+1] / eV_to_J;

	// 		std::printf("cx: %e [m^-3 s^-1], cx_power: %e [eV m^-3 s^-1], per transition: %e [eV] \n", cx_recombination_rate, cx_power_rate, cx_power_rate/cx_recombination_rate);
	// 	}
	// }

}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x440, %rsp            # imm = 0x440
leaq -0x1a8(%rbp), %rbx
movq %rbx, %rdi
callq 0x4540
leaq 0x1d391(%rip), %rsi     # 0x22059
leaq -0x208(%rbp), %rdi
movq %rbx, %rdx
callq 0x4160
leaq -0x1a8(%rbp), %rdi
callq 0x58c6
movq %rbx, %rdi
callq 0x4540
leaq 0x1eabc(%rip), %rsi     # 0x237ae
leaq -0x1e8(%rbp), %rdi
movq %rbx, %rdx
callq 0x4160
leaq -0x1a8(%rbp), %rdi
callq 0x58c6
movq %rbx, %rdi
callq 0x4540
leaq 0x1d34f(%rip), %rsi     # 0x2206b
leaq -0x1c8(%rbp), %rdi
movq %rbx, %rdx
callq 0x4160
leaq -0x1a8(%rbp), %rdi
callq 0x58c6
leaq -0x348(%rbp), %rdi
leaq -0x1e8(%rbp), %rsi
callq 0xb228
leaq -0x460(%rbp), %rdi
leaq -0x1c8(%rbp), %rsi
callq 0xb228
leaq -0x270(%rbp), %rdi
leaq -0x208(%rbp), %rsi
movsd 0x1d29d(%rip), %xmm0    # 0x22010
callq 0x1d68c
leaq -0x1a8(%rbp), %rdi
leaq -0x270(%rbp), %rsi
callq 0x1dc6a
movq %rbx, %rdi
xorl %esi, %esi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0x30(%rbp)
movq %rbx, %rdi
callq 0x53c6
leaq -0x1a8(%rbp), %rdi
leaq -0x270(%rbp), %rsi
callq 0x1dc82
movq %rbx, %rdi
xorl %esi, %esi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0x28(%rbp)
movq %rbx, %rdi
callq 0x53c6
leaq -0x1a8(%rbp), %rdi
leaq -0x270(%rbp), %rsi
callq 0x1dc9e
movq %rbx, %rdi
xorl %esi, %esi
callq 0x539c
movsd (%rax), %xmm0
mulsd -0x28(%rbp), %xmm0
movsd %xmm0, -0x38(%rbp)
movq %rbx, %rdi
callq 0x53c6
leaq -0x1a8(%rbp), %rdi
leaq -0x270(%rbp), %rsi
callq 0x1dcc6
movq %rbx, %rdi
xorl %esi, %esi
callq 0x539c
movsd (%rax), %xmm0
movsd %xmm0, -0x40(%rbp)
movq %rbx, %rdi
callq 0x53c6
leaq -0xb8(%rbp), %rdi
leaq -0x348(%rbp), %rsi
movsd -0x30(%rbp), %xmm0
movsd -0x28(%rbp), %xmm1
callq 0x49dc
leaq -0x348(%rbp), %rdi
callq 0xc10e
incl %eax
movslq %eax, %rbx
leaq -0x1a8(%rbp), %r14
movq %r14, %rdi
callq 0x533c
leaq -0x70(%rbp), %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x5346
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
xorl %ebx, %ebx
leaq -0x348(%rbp), %r14
leaq -0xb8(%rbp), %r15
leaq -0x70(%rbp), %r12
movq %r14, %rdi
callq 0xc10e
cltq
cmpq %rax, %rbx
jg 0x4ee2
movq %r15, %rdi
movq %rbx, %rsi
callq 0x539c
movsd (%rax), %xmm0
mulsd -0x40(%rbp), %xmm0
movsd %xmm0, -0x30(%rbp)
movq %r12, %rdi
movq %rbx, %rsi
callq 0x539c
movsd -0x30(%rbp), %xmm0
movsd %xmm0, (%rax)
incq %rbx
jmp 0x4ea1
leaq -0x348(%rbp), %rdi
callq 0xc10e
incl %eax
movslq %eax, %rbx
leaq -0x1a8(%rbp), %r14
movq %r14, %rdi
callq 0x533c
leaq -0x58(%rbp), %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x5346
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
xorl %ebx, %ebx
leaq -0x348(%rbp), %r14
leaq -0x58(%rbp), %r15
movabsq $0x40d4f4d45f4db325, %r12 # imm = 0x40D4F4D45F4DB325
movq %r14, %rdi
callq 0xc10e
cltq
cmpq %rax, %rbx
jg 0x4f56
movq %r15, %rdi
movq %rbx, %rsi
callq 0x539c
movq %r12, (%rax)
incq %rbx
jmp 0x4f34
leaq -0x460(%rbp), %rdi
callq 0xc10e
incl %eax
movslq %eax, %rbx
leaq -0x1a8(%rbp), %r14
movq %r14, %rdi
callq 0x533c
leaq -0xa0(%rbp), %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x5346
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
leaq -0xa0(%rbp), %rbx
movq %rbx, %rdi
xorl %esi, %esi
callq 0x539c
movsd -0x38(%rbp), %xmm0
movsd %xmm0, (%rax)
movl $0x1, %esi
movq %rbx, %rdi
callq 0x539c
movsd -0x28(%rbp), %xmm0
movsd %xmm0, (%rax)
leaq -0x460(%rbp), %rdi
callq 0xc10e
incl %eax
movslq %eax, %rbx
movq %r14, %rdi
callq 0x533c
leaq -0x88(%rbp), %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x5346
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
xorl %ebx, %ebx
leaq -0x460(%rbp), %r14
leaq -0x88(%rbp), %r15
movq %r14, %rdi
callq 0xc10e
cltq
cmpq %rax, %rbx
jg 0x502d
movq %r15, %rdi
movq %rbx, %rsi
callq 0x539c
movq %r12, (%rax)
incq %rbx
jmp 0x500b
leaq -0x1a8(%rbp), %rdi
leaq -0x348(%rbp), %rsi
movsd 0x1cfd5(%rip), %xmm0    # 0x22018
movsd 0x1cfbd(%rip), %xmm1    # 0x22008
callq 0x1ea78
leaq -0x1a8(%rbp), %rdi
xorpd %xmm0, %xmm0
callq 0x1ed8c
leaq -0x1a8(%rbp), %rdi
movsd 0x1cf99(%rip), %xmm0    # 0x22008
callq 0x1ed98
leaq -0x3a8(%rbp), %rdi
leaq -0x1a8(%rbp), %rsi
movsd 0x1cf96(%rip), %xmm0    # 0x22020
movsd 0x1cf96(%rip), %xmm1    # 0x22028
movsd 0x1cf96(%rip), %xmm2    # 0x22030
movsd 0x1cf96(%rip), %xmm4    # 0x22038
leaq -0x70(%rbp), %rdx
leaq -0x58(%rbp), %rcx
movsd -0x38(%rbp), %xmm3
callq 0x1ee04
leaq -0x290(%rbp), %rdi
leaq -0x348(%rbp), %rsi
callq 0xc0e8
leaq -0x290(%rbp), %rbx
movq %rbx, %rdi
callq 0x4180
leaq 0x1cf90(%rip), %rdi     # 0x2206d
movq %rax, %rsi
xorl %eax, %eax
callq 0x4080
movq %rbx, %rdi
callq 0x41a0
leaq -0x1a8(%rbp), %rdi
leaq -0x3a8(%rbp), %rsi
callq 0x20f96
leaq -0x3a8(%rbp), %rdi
callq 0x5408
leaq -0x1a8(%rbp), %rdi
callq 0x542c
leaq -0x88(%rbp), %rdi
callq 0x53c6
leaq -0xa0(%rbp), %rdi
callq 0x53c6
leaq -0x58(%rbp), %rdi
callq 0x53c6
leaq -0x70(%rbp), %rdi
callq 0x53c6
leaq -0xb8(%rbp), %rdi
callq 0x53c6
leaq -0x270(%rbp), %rdi
callq 0x5470
leaq -0x460(%rbp), %rdi
callq 0x54a2
leaq -0x348(%rbp), %rdi
callq 0x54a2
leaq -0x1c8(%rbp), %rdi
callq 0x41a0
leaq -0x1e8(%rbp), %rdi
callq 0x41a0
leaq -0x208(%rbp), %rdi
callq 0x41a0
xorl %eax, %eax
addq $0x440, %rsp            # imm = 0x440
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
jmp 0x51ac
movq %rax, %rbx
leaq -0x3a8(%rbp), %rdi
callq 0x5408
jmp 0x529b
jmp 0x5298
jmp 0x52a9
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
jmp 0x52b8
movq %rax, %rbx
jmp 0x52b8
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
jmp 0x52c9
jmp 0x52c6
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
jmp 0x52d7
jmp 0x52d4
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x5a80
jmp 0x52e0
movq %rax, %rbx
jmp 0x52e0
jmp 0x523c
jmp 0x523c
jmp 0x523c
jmp 0x523c
movq %rax, %rbx
jmp 0x52ec
movq %rax, %rbx
jmp 0x52f8
movq %rax, %rbx
jmp 0x5304
movq %rax, %rbx
jmp 0x5310
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x58c6
jmp 0x531c
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x58c6
jmp 0x5328
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x58c6
jmp 0x5334
movq %rax, %rbx
leaq -0x1a8(%rbp), %rdi
callq 0x542c
jmp 0x52ac
movq %rax, %rbx
leaq -0x88(%rbp), %rdi
callq 0x53c6
leaq -0xa0(%rbp), %rdi
callq 0x53c6
jmp 0x52c9
movq %rax, %rbx
leaq -0x58(%rbp), %rdi
callq 0x53c6
jmp 0x52d7
movq %rax, %rbx
leaq -0x70(%rbp), %rdi
callq 0x53c6
leaq -0xb8(%rbp), %rdi
callq 0x53c6
leaq -0x270(%rbp), %rdi
callq 0x5470
leaq -0x460(%rbp), %rdi
callq 0x54a2
leaq -0x348(%rbp), %rdi
callq 0x54a2
leaq -0x1c8(%rbp), %rdi
callq 0x41a0
leaq -0x1e8(%rbp), %rdi
callq 0x41a0
leaq -0x208(%rbp), %rdi
callq 0x41a0
movq %rbx, %rdi
callq 0x45a0