/***************************************************************************
**
**  This file is part of ArrayCore.
**
**  ArrayCore 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.
**
**  ArrayCore 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: 2007-11-12
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCoreTools.h>
#include "KminSolver.h"

namespace ArrayCore {

  /*!
    \class KminSolver KminSolver.h
    \brief Computes Kmin according to Wathelet et al. (2008)

    Kmin is defined by the width of the peak at its mid-height (from -kmin/2 to kmin/2).

    \todo Do not inherit TheoreticalLinearFK but rather use a pointer
  */

  /*!
    Returns Kmin of the station array.
    \a ok is set to false if no value at 0.5 can be found in at least one direction.
    The range of search is arbitrarily set to pi/(5*dmax) to 3*sqrt(2)*pi/dmin where
    dmin and dmax are the minimum and maximum distances between stations. In some
    extreme cases, kmin is larger than 3*sqrt(2)*pi/dmin and false is set to \a ok.
  */
  double KminSolver::calculate(bool& ok)
  {
    TRACE;
    ok=true;
    // Get possible limits for array response map
    double dmin, dmax;
    distanceRange(dmin, dmax);
    double sf=shapeFactor();
    if(sf<0.1 || sf>10.0) { // Linear array detected
      return 2.0*M_PI/dmax;
    } else {
      // 5 and 3 are default values that work well
      double gridMin=M_PI/(dmax*5.0);
      double gridMax=3.0*sqrt(2.0)*M_PI/dmin;

      double kminHalf=0.0;

      // Get the theoretical limit kmin
      RootSolver<KminSolver> kInv(this);
      for(double a=M_PI; a>0.0; a-=0.0628) {
        setRadians(a);
        kInv.setPrecision(1e-7);
        kInv.setRelativeStep(0.5);
        kInv.setPolarity(0.0);
        if(kInv.searchUpSlope(gridMin, gridMin, gridMax) ) {
          kInv.neville();
          double k=kInv.lower();
          if(k>kminHalf) kminHalf=k;
        } else {
          ok=false;
          return 0.0;
        }
      }
      return 2.0*kminHalf;
    }
  }

  double KminSolver::groundLevel(double kminHalf, double kmax)
  {
    TRACE;
    double sum=0;
    double dk=0.02*(kmax-kminHalf);
    for(double a=M_PI;a>0.0;a-=0.0628) {
      setRadians(a);
      for(double k=kminHalf;k<kmax;k+=dk) {
        double v=value(k);
        sum+=v;
      }
    }
    return sum*0.0004;
  }

} // namespace ArrayCore
