// File: /workspace/github_c_makefile_star2_O3/ugobas[P]tnm/kinetic_tnm.c
// Function: Kinetic_energy_fast
int Kinetic_energy_fast(struct Jacobian *J, struct axe *axe, int N_axes,
			atom *atoms, int N_atoms, struct Reference Ref)
{
  // The computation assumes that the center of mass is at zero and
  // the global rotations and shift have been computed for all axes
  // in the routine Eckart_main

  int k, l, i, j, iref;

  // Compute inertia tensor and center of mass for all atoms
  double **corr_sum=Allocate_mat2_d(3, 3);
  double **inertia=Allocate_mat2_d(3, 3);
  double M_tot=0, mr_tot[3];
  for(i=0; i<3; i++)mr_tot[i]=0;
  for(iref=0; iref< Ref.N_ref; iref++){
    double *r=atoms[Ref.atom_num[iref]].r;
    double  m= Ref.mass_atom[iref];
    M_tot+=m;
    for(i=0; i<3; i++){
      float mri=m*r[i]; mr_tot[i]+=mri;
      for(j=i; j<3; j++)corr_sum[i][j]+=mri*r[j];
    }
  }
  Inertia_tensor(inertia, corr_sum, mr_tot, M_tot);

  if(0){
    printf("Total: M= %.0f MR= %.4f %.4f %.4f\n",
	   M_tot, mr_tot[0], mr_tot[1], mr_tot[2]);
    printf("Inertia tensor:\n");
    printf("%8.0f %8.0f %8.0f\n%8.0f %8.0f %8.0f\n%8.0f %8.0f %8.0f\n",
	   inertia[0][0], inertia[0][1], inertia[0][2],
	   inertia[1][0], inertia[1][1], inertia[1][2],
	   inertia[2][0], inertia[2][1], inertia[2][2]);
  }

  // Compute kinetic energy tensor (only internal dof)
  // Lower tridiagonal matrix T_sqrt[l][k] with k<=l

  double I_tot_rot_l[3], I_part_rot_l[3];
  for(l=0; l<N_axes; l++){
    struct axe *axe_l=axe+l;

    // Inertia tensor was placed in local center of mass frame by Eckart
    for(i=0; i<3; i++){
      I_part_rot_l[i]=0; I_tot_rot_l[i]=0;
      for(j=0; j<3; j++){
	I_part_rot_l[i]+=axe_l->I[i][j]*axe_l->rot[j];
	I_tot_rot_l[i]+=inertia[i][j]*axe_l->global_rot[j];
      }
    }

    for(k=0; k<=l; k++){
      struct axe *axe_k=axe+k;
      double T=0, tv_kl[3], tv_lk[3];
 
      // Intersection of k and l
      // We use the fact that axes are nested: axe l>=k moves a
      // subset of atoms moved by axe k, unless side chain
      if(Dof_overlap(axe_k, axe_l)){
	T+=axe_l->mass*Scalar_product_3_d(axe_l->shift, axe_k->shift);
	T+=Scalar_product_3_d(I_part_rot_l, axe_k->rot);
	Vector_product_d(tv_kl, axe_k->shift, axe_l->rot);
	Vector_product_d(tv_lk, axe_l->shift, axe_k->rot);
	double tv[3]; for(j=0; j<3; j++)tv[j]=tv_kl[j]+tv_lk[j];
	T+=Scalar_product_3_d(tv, axe_l->MR);
      }

      // If Eckart conditions have been imposed, it is sufficient
      // to add the following terms:
      T-=M_tot*Scalar_product_3_d(axe_l->global_shift,axe_k->global_shift);
      T-=Scalar_product_3_d(I_tot_rot_l, axe_k->global_rot);
      J->T[l][k]=T;
      if(l!=k)J->T[k][l]=T;
    }
  }

  if(DBG){
    int ini=N_axes-20;
    printf("###  Kinetic energy matrix (calc):\n");
    for(k=ini; k<ini+20; k++){
      for(l=ini; l<=k; l++)printf(" %.3g", J->T[k][l]);
      printf("\n");
    }
  }

  Empty_matrix_d(corr_sum, 3);
  Empty_matrix_d(inertia, 3);

  return(0);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x158, %rsp            # imm = 0x158
movq %rcx, %r14
movl %edx, %r12d
movq %rsi, 0x20(%rsp)
movq %rdi, %rbx
movl $0x3, %edi
movl $0x3, %esi
callq 0x49804
movq %rax, %r15
movl $0x3, %edi
movl $0x3, %esi
callq 0x49804
xorps %xmm0, %xmm0
movaps %xmm0, 0xa0(%rsp)
movq $0x0, 0xb0(%rsp)
movslq 0x190(%rsp), %r11
testq %r11, %r11
jle 0x21cf5
leaq 0x190(%rsp), %rdx
movq 0x10(%rdx), %rcx
movq 0x28(%rdx), %rdx
xorps %xmm0, %xmm0
movaps %xmm0, 0x10(%rsp)
xorl %esi, %esi
movslq (%rdx,%rsi,4), %rdi
imulq $0x70, %rdi, %rdi
addq %r14, %rdi
xorps %xmm0, %xmm0
cvtss2sd (%rcx,%rsi,4), %xmm0
xorl %r8d, %r8d
movsd (%rdi,%r8,8), %xmm1
mulsd %xmm0, %xmm1
cvtsd2ss %xmm1, %xmm1
cvtss2sd %xmm1, %xmm1
movsd 0xa0(%rsp,%r8,8), %xmm2
addsd %xmm1, %xmm2
movsd %xmm2, 0xa0(%rsp,%r8,8)
movq (%r15,%r8,8), %r9
movq %r8, %r10
movsd (%rdi,%r10,8), %xmm2
mulsd %xmm1, %xmm2
addsd (%r9,%r10,8), %xmm2
movsd %xmm2, (%r9,%r10,8)
incq %r10
cmpq $0x3, %r10
jne 0x21caf
incq %r8
cmpq $0x3, %r8
jne 0x21c7e
movapd 0x10(%rsp), %xmm1
addsd %xmm0, %xmm1
movapd %xmm1, 0x10(%rsp)
incq %rsi
cmpq %r11, %rsi
jne 0x21c68
jmp 0x21cfd
xorps %xmm0, %xmm0
movaps %xmm0, 0x10(%rsp)
leaq 0xa0(%rsp), %rdx
movq %rax, 0x38(%rsp)
movq %rax, %rdi
movq %r15, 0x50(%rsp)
movq %r15, %rsi
movapd 0x10(%rsp), %xmm0
callq 0x226ac
movq %r12, 0x30(%rsp)
testl %r12d, %r12d
movq %rbx, 0x40(%rsp)
jle 0x21feb
movapd 0x10(%rsp), %xmm0
xorpd 0x2f34f(%rip), %xmm0    # 0x51090
movapd %xmm0, 0x10(%rsp)
movl 0x30(%rsp), %eax
movq %rax, 0x58(%rsp)
movq 0x20(%rsp), %rax
leaq 0xa8(%rax), %r13
leaq 0x110(%rax), %rdx
movl $0x1, %eax
movq %rax, 0x48(%rsp)
xorl %r8d, %r8d
xorl %r14d, %r14d
imulq $0x158, %r14, %rax      # imm = 0x158
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax), %r15
addq %rcx, %rax
addq $0x48, %rax
movq %rax, 0x80(%rsp)
movq %rdx, 0x60(%rsp)
movq %rdx, %rax
xorl %ecx, %ecx
movq 0x38(%rsp), %rdi
movq %r8, 0xc0(%rsp,%rcx,8)
movq %r8, 0xe0(%rsp,%rcx,8)
movq (%rdi,%rcx,8), %rdx
xorpd %xmm0, %xmm0
xorl %esi, %esi
xorpd %xmm1, %xmm1
movsd (%rax,%rsi,8), %xmm2
mulsd -0x60(%r13,%rsi,8), %xmm2
addsd %xmm2, %xmm0
movsd %xmm0, 0xc0(%rsp,%rcx,8)
movsd (%rdx,%rsi,8), %xmm2
mulsd (%r13,%rsi,8), %xmm2
addsd %xmm2, %xmm1
movsd %xmm1, 0xe0(%rsp,%rcx,8)
incq %rsi
cmpq $0x3, %rsi
jne 0x21dbf
incq %rcx
addq $0x18, %rax
cmpq $0x3, %rcx
jne 0x21da1
leaq 0x60(%r15), %rax
movq %rax, 0x70(%rsp)
leaq 0xf8(%r15), %rax
movq %rax, 0x68(%rsp)
leaq 0x90(%r15), %rax
movq %rax, 0x90(%rsp)
xorl %r12d, %r12d
movq %r14, 0x88(%rsp)
movq %r15, 0x78(%rsp)
imulq $0x158, %r12, %rbp      # imm = 0x158
addq 0x20(%rsp), %rbp
movq %rbp, %rdi
movq %r15, %rsi
callq 0x22755
testl %eax, %eax
je 0x21f46
movsd 0xf0(%r15), %xmm0
movsd %xmm0, 0x8(%rsp)
leaq 0x60(%rbp), %rbx
movq 0x70(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0x10433
movsd %xmm0, 0x28(%rsp)
leaq 0x48(%rbp), %r15
leaq 0xc0(%rsp), %rdi
movq %r15, %rsi
callq 0x10433
movsd %xmm0, 0x98(%rsp)
leaq 0x140(%rsp), %rdi
movq %rbx, %rsi
movq 0x80(%rsp), %rdx
callq 0x103bb
leaq 0x120(%rsp), %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x103bb
xorl %eax, %eax
movsd 0x140(%rsp,%rax,8), %xmm0
addsd 0x120(%rsp,%rax,8), %xmm0
movsd %xmm0, 0x100(%rsp,%rax,8)
incq %rax
cmpq $0x3, %rax
jne 0x21ecd
movsd 0x8(%rsp), %xmm0
mulsd 0x28(%rsp), %xmm0
addsd 0x2f273(%rip), %xmm0    # 0x51178
addsd 0x98(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
leaq 0x100(%rsp), %rdi
movq 0x68(%rsp), %rsi
callq 0x10433
addsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movq 0x40(%rsp), %rbx
movq 0x78(%rsp), %r15
movq 0x88(%rsp), %r14
jmp 0x21f50
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
leaq 0x90(%rbp), %rsi
movq 0x90(%rsp), %rdi
callq 0x10433
mulsd 0x10(%rsp), %xmm0
addsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
addq $0xa8, %rbp
leaq 0xe0(%rsp), %rdi
movq %rbp, %rsi
callq 0x10433
movsd 0x8(%rsp), %xmm1
subsd %xmm0, %xmm1
movq 0x20(%rbx), %rax
movq (%rax,%r14,8), %rcx
movsd %xmm1, (%rcx,%r12,8)
cmpq %r12, %r14
je 0x21fb4
movq (%rax,%r12,8), %rax
movsd %xmm1, (%rax,%r14,8)
incq %r12
cmpq 0x48(%rsp), %r12
jne 0x21e3b
incq %r14
incq 0x48(%rsp)
movl $0x158, %eax            # imm = 0x158
addq %rax, %r13
movq 0x60(%rsp), %rdx
addq %rax, %rdx
cmpq 0x58(%rsp), %r14
movl $0x0, %r8d
jne 0x21d73
cmpl $0x0, 0x57316(%rip)     # 0x79308
je 0x2206e
movq 0x30(%rsp), %r14
leal -0x14(%r14), %ebx
leaq 0x369e4(%rip), %rdi     # 0x589e8
callq 0x2090
movslq %ebx, %r12
movslq %r14d, %rax
movq %rax, 0x28(%rsp)
movl $0x1, %ebp
leaq 0x36cec(%rip), %r14     # 0x58d0c
movq %r12, 0x8(%rsp)
movq 0x40(%rsp), %r15
cmpq 0x8(%rsp), %r12
jl 0x22058
movl %ebp, %r13d
movq 0x8(%rsp), %rbx
movq 0x20(%r15), %rax
movq (%rax,%r12,8), %rax
movsd (%rax,%rbx,8), %xmm0
movq %r14, %rdi
movb $0x1, %al
callq 0x20f0
incq %rbx
decl %r13d
jne 0x22039
movl $0xa, %edi
callq 0x2060
incq %r12
incl %ebp
cmpq 0x28(%rsp), %r12
jl 0x2202a
movq 0x50(%rsp), %rdi
movl $0x3, %esi
callq 0x496ae
movq 0x38(%rsp), %rdi
movl $0x3, %esi
callq 0x496ae
xorl %eax, %eax
addq $0x158, %rsp            # imm = 0x158
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq