/***************************************************************************
**
**  This file is part of waran.
**
**  waran 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.
**
**  waran 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 Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2008-07-13
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <ArrayCore.h>
#include "PhaseShifter.h"

/*!
  \class PhaseShifter PhaseShifter.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
PhaseShifter::PhaseShifter(ArrayStations * array)
    : AbstractFunction()
{
  TRACE;
  int n=array->count();
  _relativePos.resize(n);
  for(int i=0; i<n; i++) {
    _relativePos[i]=array->relativePos(i);
  }
  _squaredKmaxGrid=0.0;
  _squaredSlowMax=std::numeric_limits<double>::infinity();
  _squaredKmaxTotal=std::numeric_limits<double>::infinity();

}

/*!
  Description of destructor still missing
*/
PhaseShifter::~PhaseShifter()
{
  TRACE;
}

/*!
  Automatically called by GridSearch upon initialization
*/
bool PhaseShifter::initGrid(int n)
{
  TRACE;
  _gridShifts.resize(n);
  _gridShiftConjugates.resize(n);

  int nStations=_relativePos.count();
  for(int i=0; i<n;i++) {
    _gridShifts[i].resize(1, nStations);
    _gridShiftConjugates[i].resize(nStations, 1);
  }
  return true;
}

void PhaseShifter::initGrid(const Point& k, int index)
{
  TRACE;
  int nStations=_relativePos.count();
  ComplexMatrix& shifts=_gridShifts[index];
  ComplexMatrix& shiftConjugates=_gridShiftConjugates[index];
  for(int i=0;i<nStations;i++) {
    const Point2D& p=_relativePos[i];
    Complex& c=shifts.at(0,i);
    c.setUnitExp(p.scalarProduct(k));
    shiftConjugates.at(i,0)=conjugate(c);
  }
  double squaredK=fabs(k.x())>fabs(k.y()) ? k.x()*k.x() : k.y()*k.y();
  if(squaredK > _squaredKmaxGrid) {
    _squaredKmaxGrid=squaredK;
  }
}

void PhaseShifter::setSquaredOmega(double omega2)
{
  _squaredKmaxTotal=omega2*_squaredSlowMax;
  if(_squaredKmaxTotal > _squaredKmaxGrid) _squaredKmaxTotal=_squaredKmaxGrid;
}

double PhaseShifter::value(const Point& k, int index) const
{
  TRACE;
  double k2=k.Point2D::abs2();
  if(k2 > _squaredKmaxTotal) return -1;
  Complex c=(_gridShifts[index]*_crossSpectrum*_gridShiftConjugates[index]).at(0,0);
  ASSERT(c.im()==0.0 || c.im()<1e-10*c.re());
  return c.re();
  //return (_gridShifts[index]*_crossSpectrum*_gridShiftConjugates[index]).at(0,0).re();
}

double PhaseShifter::value(const Point& k) const
{
  TRACE;
  double k2=k.Point2D::abs2();
  if(k2 > _squaredKmaxTotal) return -1;

  int nStations=_relativePos.count();
  ComplexMatrix shifts(1, nStations);
  ComplexMatrix shiftConjugates(nStations, 1);
  for(int i=0;i<nStations;i++) {
    const Point2D& p=_relativePos[i];
    Complex& c=shifts.at(0,i);
    c.setUnitExp(p.scalarProduct(k));
    shiftConjugates.at(i,0)=conjugate(c);
  }
  Complex c=(shifts*_crossSpectrum*shiftConjugates).at(0,0);
  ASSERT(c.im()==0.0 || c.im()<1e-10*c.re());
  return c.re();
  //return (shifts*_crossSpectrum*shiftConjugates).at(0,0).re();
}

