// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
leaq 0x10(%rbp), %rax
movq %rax, -0x140(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq %rcx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
movl $0x3, %esi
movl %esi, %edi
callq 0x694a0
movq %rax, -0x40(%rbp)
movl $0x3, %esi
movl %esi, %edi
callq 0x694a0
movq %rax, -0x48(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x50(%rbp)
movl $0x0, -0x30(%rbp)
cmpl $0x3, -0x30(%rbp)
jge 0x2f516
movslq -0x30(%rbp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, -0x70(%rbp,%rax,8)
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x2f4f8
movl $0x0, -0x38(%rbp)
movq -0x140(%rbp), %rcx
movl -0x38(%rbp), %eax
cmpl (%rcx), %eax
jge 0x2f633
movq -0x140(%rbp), %rax
movq -0x20(%rbp), %rcx
movq 0x28(%rax), %rdx
movslq -0x38(%rbp), %rsi
movslq (%rdx,%rsi,4), %rdx
imulq $0x70, %rdx, %rdx
addq %rdx, %rcx
movq %rcx, -0x78(%rbp)
movq 0x10(%rax), %rax
movslq -0x38(%rbp), %rcx
movss (%rax,%rcx,4), %xmm0
cvtss2sd %xmm0, %xmm0
movsd %xmm0, -0x80(%rbp)
movsd -0x80(%rbp), %xmm0
addsd -0x50(%rbp), %xmm0
movsd %xmm0, -0x50(%rbp)
movl $0x0, -0x30(%rbp)
cmpl $0x3, -0x30(%rbp)
jge 0x2f623
movsd -0x80(%rbp), %xmm0
movq -0x78(%rbp), %rax
movslq -0x30(%rbp), %rcx
mulsd (%rax,%rcx,8), %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, -0x84(%rbp)
movss -0x84(%rbp), %xmm0
cvtss2sd %xmm0, %xmm0
movslq -0x30(%rbp), %rax
addsd -0x70(%rbp,%rax,8), %xmm0
movsd %xmm0, -0x70(%rbp,%rax,8)
movl -0x30(%rbp), %eax
movl %eax, -0x34(%rbp)
cmpl $0x3, -0x34(%rbp)
jge 0x2f613
movss -0x84(%rbp), %xmm0
cvtss2sd %xmm0, %xmm0
movq -0x78(%rbp), %rax
movslq -0x34(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm2
movq -0x40(%rbp), %rax
movslq -0x30(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x34(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x2f5c7
jmp 0x2f615
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x2f57d
jmp 0x2f625
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0x2f51d
movq -0x48(%rbp), %rdi
movq -0x40(%rbp), %rsi
leaq -0x70(%rbp), %rdx
movsd -0x50(%rbp), %xmm0
callq 0x30340
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
cmpl -0x14(%rbp), %eax
jge 0x2f9eb
movq -0x10(%rbp), %rax
movslq -0x2c(%rbp), %rcx
imulq $0x158, %rcx, %rcx      # imm = 0x158
addq %rcx, %rax
movq %rax, -0xc8(%rbp)
movl $0x0, -0x30(%rbp)
cmpl $0x3, -0x30(%rbp)
jge 0x2f76c
movslq -0x30(%rbp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, -0xc0(%rbp,%rax,8)
movslq -0x30(%rbp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, -0xa0(%rbp,%rax,8)
movl $0x0, -0x34(%rbp)
cmpl $0x3, -0x34(%rbp)
jge 0x2f75c
movq -0xc8(%rbp), %rax
addq $0x110, %rax            # imm = 0x110
movslq -0x30(%rbp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movslq -0x34(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0xc8(%rbp), %rax
movslq -0x34(%rbp), %rcx
movsd 0x48(%rax,%rcx,8), %xmm2
movslq -0x30(%rbp), %rax
movsd -0xc0(%rbp,%rax,8), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xc0(%rbp,%rax,8)
movq -0x48(%rbp), %rax
movslq -0x30(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x34(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0xc8(%rbp), %rax
movslq -0x34(%rbp), %rcx
movsd 0xa8(%rax,%rcx,8), %xmm2
movslq -0x30(%rbp), %rax
movsd -0xa0(%rbp,%rax,8), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xa0(%rbp,%rax,8)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x2f6ad
jmp 0x2f75e
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x2f67c
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jg 0x2f9db
movq -0x10(%rbp), %rax
movslq -0x28(%rbp), %rcx
imulq $0x158, %rcx, %rcx      # imm = 0x158
addq %rcx, %rax
movq %rax, -0xd0(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0xd8(%rbp)
movq -0xd0(%rbp), %rdi
movq -0xc8(%rbp), %rsi
callq 0x304e0
cmpl $0x0, %eax
je 0x2f8e8
movq -0xc8(%rbp), %rax
movsd 0xf0(%rax), %xmm0
movsd %xmm0, -0x148(%rbp)
movq -0xc8(%rbp), %rdi
addq $0x60, %rdi
movq -0xd0(%rbp), %rsi
addq $0x60, %rsi
callq 0x14c00
movaps %xmm0, %xmm2
movsd -0x148(%rbp), %xmm0
movsd -0xd8(%rbp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xd8(%rbp)
leaq -0xc0(%rbp), %rdi
movq -0xd0(%rbp), %rsi
addq $0x48, %rsi
callq 0x14c00
addsd -0xd8(%rbp), %xmm0
movsd %xmm0, -0xd8(%rbp)
leaq -0xf0(%rbp), %rdi
movq -0xd0(%rbp), %rsi
addq $0x60, %rsi
movq -0xc8(%rbp), %rdx
addq $0x48, %rdx
callq 0x14aa0
leaq -0x110(%rbp), %rdi
movq -0xc8(%rbp), %rsi
addq $0x60, %rsi
movq -0xd0(%rbp), %rdx
addq $0x48, %rdx
callq 0x14aa0
movl $0x0, -0x34(%rbp)
cmpl $0x3, -0x34(%rbp)
jge 0x2f8be
movslq -0x34(%rbp), %rax
movsd -0xf0(%rbp,%rax,8), %xmm0
movslq -0x34(%rbp), %rax
addsd -0x110(%rbp,%rax,8), %xmm0
movslq -0x34(%rbp), %rax
movsd %xmm0, -0x130(%rbp,%rax,8)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x2f886
leaq -0x130(%rbp), %rdi
movq -0xc8(%rbp), %rsi
addq $0xf8, %rsi
callq 0x14c00
addsd -0xd8(%rbp), %xmm0
movsd %xmm0, -0xd8(%rbp)
movsd -0x50(%rbp), %xmm0
movsd %xmm0, -0x150(%rbp)
movq -0xc8(%rbp), %rdi
addq $0x90, %rdi
movq -0xd0(%rbp), %rsi
addq $0x90, %rsi
callq 0x14c00
movaps %xmm0, %xmm2
movsd -0x150(%rbp), %xmm0
movsd -0xd8(%rbp), %xmm1
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xd8(%rbp)
leaq -0xa0(%rbp), %rdi
movq -0xd0(%rbp), %rsi
addq $0xa8, %rsi
callq 0x14c00
movaps %xmm0, %xmm1
movsd -0xd8(%rbp), %xmm0
subsd %xmm1, %xmm0
movsd %xmm0, -0xd8(%rbp)
movsd -0xd8(%rbp), %xmm0
movq -0x8(%rbp), %rax
movq 0x20(%rax), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x28(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x2c(%rbp), %eax
cmpl -0x28(%rbp), %eax
je 0x2f9cb
movsd -0xd8(%rbp), %xmm0
movq -0x8(%rbp), %rax
movq 0x20(%rax), %rax
movslq -0x28(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x2c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
jmp 0x2f9cd
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x2f773
jmp 0x2f9dd
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x2f650
cmpl $0x0, 0x6c8da(%rip)     # 0x9c2cc
je 0x2fa89
movl -0x14(%rbp), %eax
subl $0x14, %eax
movl %eax, -0x134(%rbp)
leaq 0x4de54(%rip), %rdi     # 0x7d85f
movb $0x0, %al
callq 0x10d0
movl -0x134(%rbp), %eax
movl %eax, -0x28(%rbp)
movl -0x28(%rbp), %eax
movl -0x134(%rbp), %ecx
addl $0x14, %ecx
cmpl %ecx, %eax
jge 0x2fa87
movl -0x134(%rbp), %eax
movl %eax, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
cmpl -0x28(%rbp), %eax
jg 0x2fa6e
movq -0x8(%rbp), %rax
movq 0x20(%rax), %rax
movslq -0x28(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x2c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
leaq 0x4e472(%rip), %rdi     # 0x7dece
movb $0x1, %al
callq 0x10d0
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x2fa34
leaq 0x4e603(%rip), %rdi     # 0x7e078
movb $0x0, %al
callq 0x10d0
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x2fa1b
jmp 0x2fa89
movq -0x40(%rbp), %rdi
movl $0x3, %esi
callq 0x692a0
movq -0x48(%rbp), %rdi
movl $0x3, %esi
callq 0x692a0
xorl %eax, %eax
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq