/*****************************************************
**
**  S-PRES Copyright (c) 2010
**
**  Joshua T Berryman
**
**  This file is part of S-PRES
**
**  S-PRES is Free software: you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, either version 3 of the License, or
**  (at your option) any later version.
**
**  S-PRES is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
**
**  If you make use of this program for research 
**  resulting in a publication, please cite:
**
**  Joshua T Berryman and Tanja Schilling, 
**  Sampling rare events in nonequilibrium and nonstationary systems. 
**  
**  J Chem Phys, 133(24):244101, Dec 2010.
**
******************************************************/
#include <stdlib.h>
#include <string.h>
#include "shi.h"
#include "shiStats.h"

//#include <gsl/gsl_math.h>
//#include <gsl/gsl_fft_real.h>
//#include <gsl/gsl_fft_halfcomplex.h>


#define NUM_Q 10

//count formal structure factor, as in Puri & Wadhavan pp27.
//CAUTION this code never tested or used.
int shiStats::structureFactor( shi *shiState ) {

   double                       *radialDistribution;
   int                           i, R, *nOfR;
   int                           ii, jj;
   int                           jjMin, jjMax;

   radialDistribution = new double[int(shiState->xSize)];
   nOfR               = new int[int(shiState->xSize * 0.5)];
   for( i = 0; i < shiState->xSize * 0.5; i++ ){
        radialDistribution[i] = 0.0;
        nOfR[i]               = 0;   
   }

   //collapse the spin field onto a radial distribution
   for( R = 1; R < 0.5 * shiState->xSize; R++ ){

     radialDistribution[R] += pairCorrelate( shiState, 0, R, &nOfR[R] );
     radialDistribution[R] += pairCorrelate( shiState, R, 0, &nOfR[R] );

     for( ii =  1; ii < R; ii++ ){//loop over offsets - using mirror symmetry in jj to avoid double-counting
        jjMin = int(sqrt( ( R - 1 ) * ( R - 1 ) - ii * ii )); 
        jjMax = int(sqrt( R * R - ii * ii )); 
        for( jj = jjMin + 1; jj <= jjMax; jj++ ){
            radialDistribution[R] += pairCorrelate( shiState, ii, jj, &nOfR[R] );
            radialDistribution[R] += pairCorrelate( shiState, ii, -1 * jj, &nOfR[R] );
        }
     }

     //normalise
     if( nOfR[R] != 0 ) {
        
        //radialDistribution[R] /= double( nOfR[R] );
        //radialDistribution[R] -= shiState->magnetisation;
        
        //have located first zero-crossing: treat this as the correlation length.
        if( radialDistribution[R] <= 0.0 ){
            return( R );
        }
     }   
   }

   return( -1 );

}

//find probablity of a match between all spin pairs separated by the vector ii, jj.
int shiStats::pairCorrelate( shi *shiState, int ii, int jj, int *tries ) {

   int matches, i, j, iiWrap, jjWrap;

   matches = 0;

   for( i = 0; i < shiState->xSize; i++ ){
        for( j = 0; j < shiState->ySize; j++ ){
       
            if( shiState->spins[i][j] == SPIN_UP ) {
            
               *tries = *tries + 1;

                iiWrap = i + ii;
                //assuming ii is always positive
                if( iiWrap > shiState->xSize - 1){
                    iiWrap -= shiState->xSize;
                }
                jjWrap = j + jj;
                if( jjWrap > shiState->ySize - 1){
                    jjWrap -= shiState->ySize;
                }
                if( jjWrap < 0 ){
                    jjWrap += shiState->ySize;
                }

                //to avoid double-counting
                if( shiState->spins[iiWrap][jjWrap] == SPIN_UP ){
                     matches ++;
                } 
            }
       }
   }

   return( matches );

}





