// File: /workspace/github_cpp_makefile_star2_O2/shuwenyue[P]MD_code_cell_list/particle.cpp
// Function: particle::initialize(double, int, double, double)
void particle::initialize(double BoxLength, int NParticles, double T, double dt)
{
	int particles = 0;

	// resize NParticles x 3 matrices to hold positions, previous positions, and velocities
	positionVector.resize(NParticles);
    positionPrevVector.resize(NParticles);
    velocityVector.resize(NParticles);

	// calculate length of lattice box, or alternatively the length a particle "takes up"
	double ParticleLength = BoxLength/pow(NParticles,1.0/3.0);

	// calculate number of lattice boxes on each side of big box, also the number of particles in 1 dimension of box
	double ParticlesPerSide = pow(NParticles, 1.0/3.0);	

	// initialize positions, looping over x, y, z directions of lattice to place particle at each point
	for (int x = 0; x < ParticlesPerSide; x++)
	{
		for (int y = 0; y < ParticlesPerSide; y++)
		{
			for (int z = 0; z < ParticlesPerSide; z++) 
			{
				// x,y,z coordinates for 1 single particle
				// position = cooridinate * lattice box length
				position.x = x * ParticleLength; 
				position.y = y * ParticleLength;
				position.z = z * ParticleLength;

				// put that position of 1 particle in positionVector corresponding to particle number
				positionVector[particles] = position;

				particles = particles + 1;

			}
		}
	}

	// initialize velocity variables to 0
    double totalVx = 0;
    double totalVy = 0;
    double totalVz = 0;
    double totalV2 = 0;

	// initialize velocities using random numbers
	for (int j = 0; j < NParticles; j++)
	{
		// draw random number from -0.5 and 0.5 for velocity of 1 particle
        velocityVector[j].x = (rand() / double(RAND_MAX)) - 0.5;
        velocityVector[j].y = (rand() / double(RAND_MAX)) - 0.5;
        velocityVector[j].z = (rand() / double(RAND_MAX)) - 0.5;
       
        // add random new velocity to total velocity 
        totalVx = totalVx + velocityVector[j].x;
        totalVy = totalVy + velocityVector[j].y;
        totalVz = totalVz + velocityVector[j].z;
       
		// total velocity^2 calculated from all 3 components 
        totalV2 = totalV2 + (velocityVector[j].x)*(velocityVector[j].x) + (velocityVector[j].y)*(velocityVector[j].y) + (velocityVector[j].z)*(velocityVector[j].z);

	}

	// average total velocities to each particle
	double averageVx;
	double averageVy;
	double averageVz;
	double averageV2;

	// average velocities over all particles
    averageVx = totalVx/NParticles;
    averageVy = totalVy/NParticles;
    averageVz = totalVz/NParticles;
    averageV2 = totalV2/NParticles;
    
    // scale factor for velocities
    double fScale = sqrt((3*T)/averageV2);
	box boxObj;
    
    for (int k = 0; k < NParticles; k++)
    {
		// subtracting by averageV gives center of mass = 0 so box does not shift
		// fscale assigns the correct velocity to produce the input temperature
        velocityVector[k].x = (velocityVector[k].x - averageVx) * fScale;
        velocityVector[k].y = (velocityVector[k].y - averageVy) * fScale;
        velocityVector[k].z = (velocityVector[k].z - averageVz) * fScale;
       
		// initialize matrix of 'previous' positions by moving 1 time step
        positionPrevVector[k].x = positionVector[k].x - (velocityVector[k].x)*dt;
        positionPrevVector[k].y = positionVector[k].y - (velocityVector[k].y)*dt;
        positionPrevVector[k].z = positionVector[k].z - (velocityVector[k].z)*dt;

		// periodic boundary conditions
		positionPrevVector[k].x = boxObj.pbc(positionPrevVector[k].x, BoxLength);
		positionPrevVector[k].y = boxObj.pbc(positionPrevVector[k].y, BoxLength);
		positionPrevVector[k].z = boxObj.pbc(positionPrevVector[k].z, BoxLength);
    }

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movapd %xmm2, 0x60(%rsp)
movsd %xmm1, 0x50(%rsp)
movl %esi, %r12d
movsd %xmm0, 0x18(%rsp)
movq %rdi, %r13
leaq 0x18(%rdi), %rbx
movslq %esi, %rbp
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x36a4
leaq 0x30(%r13), %r14
movq %r14, %rdi
movq %rbp, %rsi
callq 0x36a4
leaq 0x48(%r13), %r15
movq %r15, %rdi
movq %rbp, %rsi
callq 0x36a4
cvtsi2sd %ebp, %xmm0
movapd %xmm0, 0x30(%rsp)
movsd 0x228c(%rip), %xmm1     # 0x5008
callq 0x2200
movsd 0x18(%rsp), %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, 0x20(%rsp)
movapd 0x30(%rsp), %xmm0
movsd 0x2269(%rip), %xmm1     # 0x5008
callq 0x2200
xorl %eax, %eax
xorl %ecx, %ecx
movsd 0x20(%rsp), %xmm4
cvtsi2sd %eax, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x2e20
mulsd %xmm4, %xmm1
xorl %edx, %edx
cvtsi2sd %edx, %xmm2
ucomisd %xmm2, %xmm0
jbe 0x2e1c
mulsd %xmm4, %xmm2
movslq %ecx, %rsi
imulq $0x18, %rsi, %rdi
xorl %esi, %esi
cvtsi2sd %esi, %xmm3
ucomisd %xmm3, %xmm0
jbe 0x2e16
movsd %xmm1, (%r13)
movsd %xmm2, 0x8(%r13)
mulsd %xmm4, %xmm3
movsd %xmm3, 0x10(%r13)
movq 0x18(%r13), %r8
movupd (%r13), %xmm3
movupd %xmm3, (%r8,%rdi)
movq 0x10(%r13), %r9
movq %r9, 0x10(%r8,%rdi)
incl %esi
addq $0x18, %rdi
jmp 0x2dd5
addl %esi, %ecx
incl %edx
jmp 0x2dbe
incl %eax
jmp 0x2dae
xorl %ebp, %ebp
testl %r12d, %r12d
cmovlel %ebp, %r12d
imulq $0x18, %r12, %r13
xorpd %xmm0, %xmm0
movapd %xmm0, 0x20(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
xorpd %xmm1, %xmm1
cmpq %rbp, %r13
je 0x2f15
movsd %xmm1, 0x40(%rsp)
callq 0x2040
cvtsi2sd %eax, %xmm0
movsd 0x23c3(%rip), %xmm1     # 0x5228
divsd %xmm1, %xmm0
movsd 0x23bf(%rip), %xmm1     # 0x5230
addsd %xmm1, %xmm0
movq (%r15), %rax
movsd %xmm0, (%rax,%rbp)
callq 0x2040
cvtsi2sd %eax, %xmm0
divsd 0x239a(%rip), %xmm0     # 0x5228
addsd 0x239a(%rip), %xmm0     # 0x5230
movq (%r15), %rax
movsd %xmm0, 0x8(%rax,%rbp)
callq 0x2040
cvtsi2sd %eax, %xmm0
divsd 0x2378(%rip), %xmm0     # 0x5228
addsd 0x2378(%rip), %xmm0     # 0x5230
movq (%r15), %rax
movsd %xmm0, 0x10(%rax,%rbp)
movupd (%rax,%rbp), %xmm1
movapd 0x20(%rsp), %xmm2
addpd %xmm1, %xmm2
movapd %xmm2, 0x20(%rsp)
movsd 0x10(%rsp), %xmm2
addsd %xmm0, %xmm2
movsd %xmm2, 0x10(%rsp)
movapd %xmm1, %xmm2
mulsd %xmm1, %xmm2
addsd 0x40(%rsp), %xmm2
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
mulsd %xmm1, %xmm1
addsd %xmm2, %xmm1
mulsd %xmm0, %xmm0
addsd %xmm1, %xmm0
addq $0x18, %rbp
movapd %xmm0, %xmm1
jmp 0x2e45
movapd 0x30(%rsp), %xmm0
movapd %xmm0, %xmm2
unpcklpd %xmm0, %xmm2            # xmm2 = xmm2[0],xmm0[0]
divsd %xmm0, %xmm1
movsd 0x50(%rsp), %xmm0
mulsd 0x2303(%rip), %xmm0     # 0x5238
divsd %xmm1, %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jb 0x2f49
sqrtsd %xmm0, %xmm1
jmp 0x2f5e
movapd %xmm2, 0x40(%rsp)
callq 0x2110
movapd 0x40(%rsp), %xmm2
movapd %xmm0, %xmm1
movapd 0x20(%rsp), %xmm0
divpd %xmm2, %xmm0
movapd %xmm0, 0x20(%rsp)
movsd 0x10(%rsp), %xmm0
divsd 0x30(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movapd %xmm1, 0x40(%rsp)
unpcklpd %xmm1, %xmm1            # xmm1 = xmm1[0,0]
movapd %xmm1, 0x30(%rsp)
movaps 0x60(%rsp), %xmm0
movlhps %xmm0, %xmm0            # xmm0 = xmm0[0,0]
movaps %xmm0, 0x50(%rsp)
xorl %ebp, %ebp
leaq 0xf(%rsp), %r12
cmpq %rbp, %r13
je 0x3067
movq (%r15), %rax
movupd (%rax,%rbp), %xmm1
subpd 0x20(%rsp), %xmm1
mulpd 0x30(%rsp), %xmm1
movupd %xmm1, (%rax,%rbp)
movsd 0x10(%rax,%rbp), %xmm2
subsd 0x10(%rsp), %xmm2
mulsd 0x40(%rsp), %xmm2
movsd %xmm2, 0x10(%rax,%rbp)
movq (%rbx), %rax
movq (%r14), %rcx
movupd (%rax,%rbp), %xmm0
mulpd 0x50(%rsp), %xmm1
subpd %xmm1, %xmm0
movupd %xmm0, (%rcx,%rbp)
movsd 0x10(%rax,%rbp), %xmm1
mulsd 0x60(%rsp), %xmm2
subsd %xmm2, %xmm1
movsd %xmm1, 0x10(%rcx,%rbp)
movq %r12, %rdi
movsd 0x18(%rsp), %xmm1
callq 0x455e
movq (%r14), %rax
movsd %xmm0, (%rax,%rbp)
movsd 0x8(%rax,%rbp), %xmm0
movq %r12, %rdi
movsd 0x18(%rsp), %xmm1
callq 0x455e
movq (%r14), %rax
movsd %xmm0, 0x8(%rax,%rbp)
movsd 0x10(%rax,%rbp), %xmm0
movq %r12, %rdi
movsd 0x18(%rsp), %xmm1
callq 0x455e
movq (%r14), %rax
movsd %xmm0, 0x10(%rax,%rbp)
addq $0x18, %rbp
jmp 0x2fa4
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq