// File: /workspace/github_cpp_makefile_star2_O2/Luthaf[P]zeopp/area_and_volume.cc
// Function: NEWcalcAV(MATERIAL*, double, int, double, double)
double NEWcalcAV(MATERIAL *Mat, double r_probe, int numSamples, double low_dist_cutoff, double high_dist_cutoff){

  // Inital checks
  if(!(Mat->accessAnalysis.alreadySegmentedFlag))
      {
      cerr << "Cannot run calcAV without prior accessibility analysis.\nExiting with return 0\n";
      return 0;
      }

  // Setting parameters
  Mat->AVprobeRadius = r_probe;

  // Cleaning structures in case of previous runs
  Mat->AVcount = 0; 
  Mat->AVcount_inaxs = 0; 
  Mat->AVcount_within_range = 0; 
  Mat->AVcount_outside_range = 0;
  Mat->AVaxsPoints.clear(); 
  Mat->AVaxsPointsChannelIDs.clear(); 
  Mat->AVinaxsPoints.clear(); 
  Mat->AVinaxsPointsPocketIDs.clear(); 
  Mat->AVcount_inChannel.clear();
  Mat->AVcount_inPocket.clear();


  //determine whether we are only sampling volume within a specific distance range of the surface
  bool within_range = false;
  if(!(low_dist_cutoff<0 || high_dist_cutoff<0)) {
    if(high_dist_cutoff<low_dist_cutoff) { //swap them
      double temp = low_dist_cutoff;
      low_dist_cutoff = high_dist_cutoff;
      high_dist_cutoff = temp;
    }
    within_range = true;
  }

  Mat->AVwithin_rangeFlag = within_range;

  // setting up MC sampling
  srand(randSeed);

  numSamples = int(numSamples * calcDeterminant(Mat->atmnet.ucVectors));
  Mat->AVnumSamples = numSamples;

  cout << "Number of samples in volume calc: " << numSamples << endl;

  bool excludePockets = true; // this is default (in old version, without voro-stuff it was used)

  int count = 0;
  int count_inaxs = 0;
  int count_within_range = 0;
  int count_outside_range = 0;

  // MC statistics can be collected w.r.t to identified channels and inaccessible pockets
  Mat->AVcount_inChannel.resize(Mat->accessAnalysis.n_channels,0);
  Mat->AVcount_inPocket.resize(Mat->accessAnalysis.n_pockets,0);

  for(int i = 0; i < numSamples; i++){
    bool overlaps = false;
    bool inside = false;

    // Randomly sample point across the unit cell
    double aPoint = (rand()*1.0)/RAND_MAX;
    double bPoint = (rand()*1.0)/RAND_MAX;
    double cPoint = (rand()*1.0)/RAND_MAX;

    // Convert coords relative to the unit cell vectors into (x,y,z) coords
    Point samplingPoint = Mat->atmnet.abc_to_xyz(aPoint, bPoint, cPoint);

    // Calling accessibility object to determine accessibility of the point (this replaced a big chunk of code by Thomas)
    pair<bool,bool> answer = (Mat->accessAnalysis.isVPointInsideAtomAndNotAccessible(samplingPoint));
    inside = answer.first; overlaps = answer.second;
    if(Mat->accessAnalysis.needToResample() == true) i--; // the sampled point could not be analyzed in isVPointInsideAtomAndNotAccessible() function, resampling needed

    if(inside == false && excludePockets == false) overlaps = false; // if ignore inacceible pockets, treat the point as accessible (unless inside atom)
      
    // Store sampled points that did not overlap with an atom but were inaccessible for later visualization
    if(Mat->accessAnalysis.needToResample() == false && !inside && overlaps){
      count_inaxs++;
      pair <int,int> CoP = Mat->accessAnalysis.lastChannelOrPocket();
      if(CoP.first!=-1) 
        {
        cout << "Error: CoP.first!=-1 in pocket, consult source code provider\n";
        } else {
        Mat->AVcount_inPocket[CoP.second]++;
        };
      if(!within_range) {
        //Point abcCoords = Point(aPoint, bPoint, cPoint); // to be removed as now we store fractional coordinates
        //Point coords = Mat->atmnet.abc_to_xyz(abcCoords);
        Point coords = Point(aPoint, bPoint, cPoint);
        Mat->AVinaxsPoints.push_back(coords);
        Mat->AVinaxsPointsPocketIDs.push_back(CoP.second);
      };
    };

    // Store accessible points for later visualization
    if(Mat->accessAnalysis.needToResample() == false && !overlaps) {
      count++;     
      pair <int,int> CoP = Mat->accessAnalysis.lastChannelOrPocket();
      if(CoP.second!=-1) 
        {
        cout << "Error: CoP.second!=-1 in channel, consult source code provider\n";
        } else {
        Mat->AVcount_inChannel[CoP.first]++;
        };
      //Point abcCoords = Point(aPoint, bPoint, cPoint);  // to be removed as now we store fractional coordinates
      //Point coords = Mat->atmnet.abc_to_xyz(abcCoords);
      Point coords = Point(aPoint, bPoint, cPoint);
      if(within_range) {
        if(Mat->accessAnalysis.lastMinDist() >= low_dist_cutoff && Mat->accessAnalysis.lastMinDist() <= high_dist_cutoff) { //NOTE: minDist is the distance between centroids, it is NOT the distance to the surface - here we are comparing this distance to the tolerance range
                                                                               // RECHECK IF STILL TRUE FOR NON INFLATED ATOMS
          count_within_range++;
          Mat->AVaxsPoints.push_back(coords);
        } else {
          count_outside_range++;
          Mat->AVinaxsPoints.push_back(coords);
        }
      } else 
      {
      Mat->AVaxsPoints.push_back(coords); 
      Mat->AVaxsPointsChannelIDs.push_back(CoP.first);
      };
    }
  }; // ends a for loop over all sampled points

  // Warn user if points were resampled
  int resampleCount =  Mat->accessAnalysis.getResampleCount();
  if(resampleCount != 0){
    cerr << "\n" << "\n"
         << "Warning: Resampled " << resampleCount << " points out of " << numSamples
         << " when analyzing " << Mat->atmnet.name << "\n"
         << "\n" << "\n";
  };

  Mat->AVcount = count;
  Mat->AVcount_inaxs = count_inaxs;
  Mat->AVcount_within_range = count_within_range;
  Mat->AVcount_outside_range = count_outside_range;


  return count/numSamples;

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
cmpb $0x0, 0xb1d(%rdi)
je 0x30e88
movl %esi, %r14d
movq %rdi, %r12
movsd %xmm0, 0xc70(%rdi)
xorpd %xmm0, %xmm0
movupd %xmm0, 0xc7c(%rdi)
movq 0xc90(%rdi), %rax
cmpq %rax, 0xc98(%rdi)
je 0x30da6
movq %rax, 0xc98(%r12)
movq 0xca8(%r12), %rax
cmpq %rax, 0xcb0(%r12)
je 0x30dc0
movq %rax, 0xcb0(%r12)
movq 0xcc0(%r12), %rax
cmpq %rax, 0xcc8(%r12)
je 0x30dda
movq %rax, 0xcc8(%r12)
movq 0xcd8(%r12), %rax
cmpq %rax, 0xce0(%r12)
je 0x30df4
movq %rax, 0xce0(%r12)
movq 0xcf0(%r12), %rax
cmpq %rax, 0xcf8(%r12)
je 0x30e0e
movq %rax, 0xcf8(%r12)
movq 0xd08(%r12), %rax
cmpq %rax, 0xd10(%r12)
je 0x30e28
movq %rax, 0xd10(%r12)
leaq 0xcf0(%r12), %rax
movq %rax, 0x58(%rsp)
leaq 0xd08(%r12), %rax
movq %rax, 0x50(%rsp)
xorpd %xmm0, %xmm0
movapd %xmm2, %xmm4
cmpnltpd %xmm0, %xmm4
movapd %xmm1, %xmm3
cmpnltpd %xmm0, %xmm3
andpd %xmm4, %xmm3
movd %xmm3, %eax
movl %eax, 0x20(%rsp)
testb $0x1, %al
je 0x30ea4
movapd %xmm2, %xmm0
minsd %xmm1, %xmm0
maxsd %xmm2, %xmm1
movapd %xmm1, 0xa0(%rsp)
movapd %xmm0, 0xb0(%rsp)
jmp 0x30eb6
movq 0x11f161(%rip), %rdi    # 0x14fff0
leaq 0xcfb52(%rip), %rsi     # 0x1009e8
callq 0x4480
xorpd %xmm0, %xmm0
jmp 0x312fb
movapd %xmm1, 0xb0(%rsp)
movapd %xmm2, 0xa0(%rsp)
leaq 0x990(%r12), %r13
leaq 0xc90(%r12), %rax
movq %rax, 0x68(%rsp)
leaq 0xca8(%r12), %rax
movq %rax, 0x80(%rsp)
leaq 0xcc0(%r12), %rax
movq %rax, 0x60(%rsp)
leaq 0xcd8(%r12), %rax
movq %rax, 0x78(%rsp)
movl 0x20(%rsp), %eax
andb $0x1, %al
movb %al, 0xc8c(%r12)
movl $0x3b4ca6f5, %edi       # imm = 0x3B4CA6F5
callq 0x4460
cvtsi2sd %r14d, %xmm0
movsd %xmm0, 0x28(%rsp)
leaq 0x80(%r12), %rdi
callq 0x63835
mulsd 0x28(%rsp), %xmm0
cvttsd2si %xmm0, %r14d
movl %r14d, 0xc78(%r12)
movq 0x11f081(%rip), %rdi    # 0x14ffc0
leaq 0xcfaf1(%rip), %rsi     # 0x100a37
callq 0x4480
movq %rax, %rdi
movl %r14d, %esi
callq 0x4760
movq %rax, %rdi
callq 0x4230
movslq 0xa68(%r12), %rsi
leaq 0x88(%rsp), %r15
andl $0x0, (%r15)
movq 0x58(%rsp), %rdi
movq %r15, %rdx
callq 0x36f18
movslq 0xa6c(%r12), %rsi
andl $0x0, (%r15)
leaq 0x88(%rsp), %rdx
movq 0x50(%rsp), %rdi
callq 0x36f18
movl $0x0, 0x3c(%rsp)
movl $0x0, 0x34(%rsp)
movl $0x0, 0x30(%rsp)
xorl %ebp, %ebp
movl $0x0, 0x38(%rsp)
movl %r14d, 0x24(%rsp)
cmpl %r14d, %ebp
jge 0x31215
callq 0x4170
cvtsi2sd %eax, %xmm1
movsd 0xcf5a2(%rip), %xmm0    # 0x100580
divsd %xmm0, %xmm1
movsd %xmm1, 0x28(%rsp)
callq 0x4170
cvtsi2sd %eax, %xmm0
divsd 0xcf587(%rip), %xmm0    # 0x100580
movsd %xmm0, 0x40(%rsp)
callq 0x4170
cvtsi2sd %eax, %xmm2
divsd 0xcf570(%rip), %xmm2    # 0x100580
leaq 0x88(%rsp), %rdi
movq %r12, %rsi
movsd 0x28(%rsp), %xmm0
movsd 0x40(%rsp), %xmm1
movsd %xmm2, 0x70(%rsp)
callq 0x3f0e6
movq 0x98(%rsp), %rax
movq %rax, 0x10(%rsp)
movupd 0x88(%rsp), %xmm0
movupd %xmm0, (%rsp)
movq %r13, %rdi
callq 0x6f4b2
movl %eax, %r15d
movq %r13, %rdi
callq 0x36f4c
movl %eax, %r14d
movq %r13, %rdi
callq 0x36f4c
testb %al, %al
jne 0x3111c
testb $0x1, %r15b
jne 0x3111c
movl %r15d, %eax
andl $0x100, %eax            # imm = 0x100
je 0x3111c
movq %r13, %rdi
callq 0x36f90
movq %rax, 0x48(%rsp)
cmpl $-0x1, %eax
jne 0x310ae
sarq $0x20, %rax
movq 0x50(%rsp), %rcx
movq (%rcx), %rcx
incl (%rcx,%rax,4)
jmp 0x310c1
movq 0x11ef0b(%rip), %rdi    # 0x14ffc0
leaq 0xcf604(%rip), %rsi     # 0x1006c0
callq 0x4480
testb $0x1, 0x20(%rsp)
jne 0x31118
movq %rbp, %rbx
movl %r14d, %ebp
movq %r12, %r14
leaq 0xc0(%rsp), %r12
movq %r12, %rdi
movsd 0x28(%rsp), %xmm0
movsd 0x40(%rsp), %xmm1
movsd 0x70(%rsp), %xmm2
callq 0x63c46
movq 0x60(%rsp), %rdi
movq %r12, %rsi
movq %r14, %r12
movl %ebp, %r14d
movq %rbx, %rbp
callq 0x2468e
movq 0x78(%rsp), %rdi
leaq 0x4c(%rsp), %rsi
callq 0x9434
incl 0x3c(%rsp)
shrl $0x8, %r15d
andl $0x1, %r15d
movq %r13, %rdi
callq 0x36f4c
orb %r15b, %al
jne 0x31201
movq %r13, %rdi
callq 0x36f90
movq %rax, 0x48(%rsp)
movabsq $-0x100000001, %rcx     # imm = 0xFFFFFFFEFFFFFFFF
cmpq %rcx, %rax
leaq 0xc0(%rsp), %rbx
jbe 0x31168
movq 0x58(%rsp), %rcx
movq (%rcx), %rcx
cltq
incl (%rcx,%rax,4)
jmp 0x3117b
movq 0x11ee51(%rip), %rdi    # 0x14ffc0
leaq 0xcf588(%rip), %rsi     # 0x1006fe
callq 0x4480
movq %rbx, %rdi
movsd 0x28(%rsp), %xmm0
movsd 0x40(%rsp), %xmm1
movsd 0x70(%rsp), %xmm2
callq 0x63c46
testb $0x1, 0x20(%rsp)
je 0x311cb
movsd 0xad8(%r12), %xmm0
ucomisd 0xb0(%rsp), %xmm0
jb 0x311ec
movapd 0xa0(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jb 0x311ec
incl 0x34(%rsp)
movq 0x68(%rsp), %rdi
jmp 0x311f5
movq 0x68(%rsp), %rdi
movq %rbx, %rsi
callq 0x2468e
movq 0x80(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x9434
jmp 0x311fd
incl 0x30(%rsp)
movq 0x60(%rsp), %rdi
movq %rbx, %rsi
callq 0x2468e
incl 0x38(%rsp)
movzbl %r14b, %eax
negl %eax
addl %eax, %ebp
incl %ebp
movl 0x24(%rsp), %r14d
jmp 0x30fc4
movl 0xb18(%r12), %r15d
testl %r15d, %r15d
je 0x312c1
movq 0x11edc3(%rip), %rdi    # 0x14fff0
leaq 0xd134a(%rip), %r14     # 0x10257e
movq %r14, %rsi
callq 0x4480
movq %rax, %rdi
movq %r14, %rsi
callq 0x4480
leaq 0xcf4f0(%rip), %rsi     # 0x10073e
movq %rax, %rdi
callq 0x4480
movq %rax, %rdi
movl %r15d, %esi
callq 0x4760
leaq 0xcf4ea(%rip), %rsi     # 0x100752
movq %rax, %rdi
callq 0x4480
movq %rax, %rdi
movl 0x24(%rsp), %esi
callq 0x4760
leaq 0xdcfa3(%rip), %rsi     # 0x10e226
movq %rax, %rdi
callq 0x4480
leaq 0x320(%r12), %rsi
movq %rax, %rdi
callq 0x43f0
movq %rax, %rdi
movq %r14, %rsi
callq 0x4480
movq %rax, %rdi
movq %r14, %rsi
callq 0x4480
movq %rax, %rdi
movq %r14, %rsi
movl 0x24(%rsp), %r14d
callq 0x4480
movl 0x38(%rsp), %ecx
movl %ecx, 0xc7c(%r12)
movl 0x3c(%rsp), %eax
movl %eax, 0xc80(%r12)
movl 0x34(%rsp), %eax
movl %eax, 0xc84(%r12)
movl 0x30(%rsp), %eax
movl %eax, 0xc88(%r12)
movl %ecx, %eax
cltd
idivl %r14d
cvtsi2sd %eax, %xmm0
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq