// File: /workspace/github_c_makefile_star2_O2/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 $0x148, %rsp            # imm = 0x148
movq %rcx, %r15
movq %rdx, 0x18(%rsp)
movq %rsi, 0x10(%rsp)
movq %rdi, 0x38(%rsp)
leaq 0x180(%rsp), %r12
pushq $0x3
popq %rbx
movl %ebx, %edi
movl %ebx, %esi
callq 0x43878
movq %rax, %r14
movl %ebx, %edi
movl %ebx, %esi
callq 0x43878
movq %rax, 0x8(%rsp)
xorl %eax, %eax
cmpq $0x3, %rax
je 0x1fccb
andq $0x0, 0x90(%rsp,%rax,8)
incq %rax
jmp 0x1fcb7
movl (%r12), %eax
movq 0x28(%r12), %rcx
movq 0x10(%r12), %rdx
xorl %esi, %esi
testl %eax, %eax
cmovlel %esi, %eax
xorpd %xmm3, %xmm3
movq 0x8(%rsp), %r12
cmpq %rax, %rsi
je 0x1fd67
movslq (%rcx,%rsi,4), %rdi
imulq $0x70, %rdi, %rdi
addq %r15, %rdi
cvtss2sd (%rdx,%rsi,4), %xmm0
xorl %r8d, %r8d
cmpq $0x3, %r8
je 0x1fd5e
movsd (%rdi,%r8,8), %xmm1
mulsd %xmm0, %xmm1
cvtsd2ss %xmm1, %xmm1
cvtss2sd %xmm1, %xmm1
movsd 0x90(%rsp,%r8,8), %xmm2
addsd %xmm1, %xmm2
movsd %xmm2, 0x90(%rsp,%r8,8)
movq %r8, %r9
cmpq $0x3, %r9
je 0x1fd59
movq (%r14,%r8,8), %r10
movsd (%rdi,%r9,8), %xmm2
mulsd %xmm1, %xmm2
addsd (%r10,%r9,8), %xmm2
movsd %xmm2, (%r10,%r9,8)
incq %r9
jmp 0x1fd34
incq %r8
jmp 0x1fd01
addsd %xmm0, %xmm3
incq %rsi
jmp 0x1fce9
leaq 0x90(%rsp), %rdx
movq %r12, %rdi
movq %r14, %rsi
movapd %xmm3, %xmm0
movapd %xmm3, 0x40(%rsp)
callq 0x20681
movapd 0x40(%rsp), %xmm0
xorpd 0x2b32e(%rip), %xmm0    # 0x4b0c0
movapd %xmm0, 0x40(%rsp)
xorl %r13d, %r13d
movq 0x18(%rsp), %rax
testl %eax, %eax
movl $0x0, %ecx
cmovgl %eax, %ecx
movq %rcx, 0x50(%rsp)
movq 0x10(%rsp), %rax
leaq 0xa8(%rax), %r15
addq $0x110, %rax            # imm = 0x110
movq %rax, 0x20(%rsp)
pushq $0x1
popq %rax
movq %rax, 0x28(%rsp)
cmpq 0x50(%rsp), %r13
je 0x20034
imulq $0x158, %r13, %rax      # imm = 0x158
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax), %rbp
addq %rcx, %rax
addq $0x48, %rax
movq %rax, 0x60(%rsp)
movq 0x20(%rsp), %rax
xorl %ecx, %ecx
cmpq $0x3, %rcx
je 0x1fe67
andq $0x0, 0xb0(%rsp,%rcx,8)
andq $0x0, 0xd0(%rsp,%rcx,8)
movq (%r12,%rcx,8), %rdx
xorpd %xmm0, %xmm0
xorl %esi, %esi
xorpd %xmm1, %xmm1
cmpq $0x3, %rsi
je 0x1fe5e
movsd (%rax,%rsi,8), %xmm2
mulsd -0x60(%r15,%rsi,8), %xmm2
addsd %xmm2, %xmm1
movsd %xmm1, 0xb0(%rsp,%rcx,8)
movsd (%rdx,%rsi,8), %xmm2
mulsd (%r15,%rsi,8), %xmm2
addsd %xmm2, %xmm0
movsd %xmm0, 0xd0(%rsp,%rcx,8)
incq %rsi
jmp 0x1fe22
incq %rcx
addq $0x18, %rax
jmp 0x1fdfc
leaq 0x60(%rbp), %rax
movq %rax, 0x30(%rsp)
leaq 0xf8(%rbp), %rax
movq %rax, 0x58(%rsp)
leaq 0x90(%rbp), %rax
movq %rax, 0x78(%rsp)
xorl %r12d, %r12d
movq %r13, 0x70(%rsp)
movq %rbp, 0x68(%rsp)
cmpq 0x28(%rsp), %r12
je 0x20015
imulq $0x158, %r12, %rbx      # imm = 0x158
addq 0x10(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x2072b
testl %eax, %eax
je 0x1ffa1
movsd 0xf0(%rbp), %xmm0
movsd %xmm0, (%rsp)
leaq 0x60(%rbx), %r13
movq 0x30(%rsp), %rdi
movq %r13, %rsi
callq 0xf96f
movsd %xmm0, 0x88(%rsp)
leaq 0x48(%rbx), %rbp
leaq 0xb0(%rsp), %rdi
movq %rbp, %rsi
callq 0xf96f
movsd %xmm0, 0x80(%rsp)
leaq 0x130(%rsp), %rdi
movq %r13, %rsi
movq 0x70(%rsp), %r13
movq 0x60(%rsp), %rdx
callq 0xf8f7
leaq 0x110(%rsp), %rdi
movq 0x30(%rsp), %rsi
movq %rbp, %rdx
callq 0xf8f7
xorl %eax, %eax
cmpq $0x3, %rax
je 0x1ff5a
movsd 0x130(%rsp,%rax,8), %xmm0
addsd 0x110(%rsp,%rax,8), %xmm0
movsd %xmm0, 0xf0(%rsp,%rax,8)
incq %rax
jmp 0x1ff34
movsd (%rsp), %xmm0
mulsd 0x88(%rsp), %xmm0
addsd 0x2b0e0(%rip), %xmm0    # 0x4b050
addsd 0x80(%rsp), %xmm0
movsd %xmm0, (%rsp)
leaq 0xf0(%rsp), %rdi
movq 0x58(%rsp), %rsi
callq 0xf96f
addsd (%rsp), %xmm0
movsd %xmm0, (%rsp)
movq 0x68(%rsp), %rbp
jmp 0x1ffaa
xorpd %xmm0, %xmm0
movsd %xmm0, (%rsp)
leaq 0x90(%rbx), %rsi
movq 0x78(%rsp), %rdi
callq 0xf96f
mulsd 0x40(%rsp), %xmm0
addsd (%rsp), %xmm0
movsd %xmm0, (%rsp)
addq $0xa8, %rbx
leaq 0xd0(%rsp), %rdi
movq %rbx, %rsi
callq 0xf96f
movsd (%rsp), %xmm1
subsd %xmm0, %xmm1
movq 0x38(%rsp), %rax
movq 0x20(%rax), %rax
movq (%rax,%r13,8), %rcx
movsd %xmm1, (%rcx,%r12,8)
cmpq %r12, %r13
je 0x2000d
movq (%rax,%r12,8), %rax
movsd %xmm1, (%rax,%r13,8)
incq %r12
jmp 0x1fe95
incq %r13
incq 0x28(%rsp)
movl $0x158, %eax            # imm = 0x158
addq %rax, %r15
addq %rax, 0x20(%rsp)
movq 0x8(%rsp), %r12
jmp 0x1fdce
cmpl $0x0, 0x542cd(%rip)     # 0x74308
je 0x200a3
movq 0x18(%rsp), %r15
leal -0x14(%r15), %ebx
leaq 0x328fb(%rip), %rdi     # 0x52948
callq 0x2090
movslq %ebx, %rbx
movslq %r15d, %r13
leaq 0x32c0d(%rip), %r15     # 0x52c6c
movq %rbx, %rbp
cmpq %r13, %rbp
jge 0x200a3
movq %rbx, %r12
cmpq %rbp, %r12
jg 0x20091
movq 0x38(%rsp), %rax
movq 0x20(%rax), %rax
movq (%rax,%rbp,8), %rax
movsd (%rax,%r12,8), %xmm0
movq %r15, %rdi
movb $0x1, %al
callq 0x20f0
incq %r12
jmp 0x2006a
pushq $0xa
popq %rdi
callq 0x2060
incq %rbp
movq 0x8(%rsp), %r12
jmp 0x20062
pushq $0x3
popq %rbx
movq %r14, %rdi
movl %ebx, %esi
callq 0x4372a
movq %r12, %rdi
movl %ebx, %esi
callq 0x4372a
xorl %eax, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq