/***************************************************************************
**
**  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: 2008-02-08
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "FKParameters.h"

namespace ArrayCore {

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

    Full description of class still missing
  */

  FKParameters::FKParameters()
    : ArrayParameters()
  {
    setDefaultValues(DirectSteering, RefinedGrid, ArrayStations::Vertical);
    _cacheGridStepFactor=0.05;
    _cacheGridStep=0.0;
    _gridStep=0.0;
    _gridSize=0;
    _kmin=0.0;
    _kmax=0.0;
    _smin=1.0/3500.0;
    _smax=1.0/50.0;
    _minAzimuth=0.0;
    _maxAzimuth=360.0;
    _sourceGridStep=1.0;
    _sourceGridSize=0.0;
  }

  FKParameters::FKParameters(const FKParameters& o)
    : ArrayParameters(o)
  {
    _inversionMethod=o._inversionMethod;
    _cacheGridStepFactor=o._cacheGridStepFactor;
    _cacheGridStep=o._cacheGridStep;
    _gridStepFactor=o._gridStepFactor;
    _gridStep=o._gridStep;
    _gridSize=o._gridSize;
    _kmin=o._kmin;
    _kmax=o._kmax;
    _smin=o._smin;
    _smax=o._smax;
    _minAzimuth=o._minAzimuth;
    _maxAzimuth=o._maxAzimuth;
    _refineGridIndex=o._refineGridIndex;
    _refineSlowMin=o._refineSlowMin;
    _refineSlowMax=o._refineSlowMax;
    _maxPeakCount=o._maxPeakCount;
    _absoluteThreshold=o._absoluteThreshold;
    _relativeThreshold=o._relativeThreshold;
    _exportAllFKGrids=o._exportAllFKGrids;
    _damping=o._damping;
    _rotateStepCount=o._rotateStepCount;
    _processType=o._processType;
    _arrays=o._arrays;
    _skipLove=o._skipLove;
    _fixedEllipticityFileName=o._fixedEllipticityFileName;
    _minimumDistance=o._minimumDistance;
    _maximumDistance=o._maximumDistance;
    _sourceGridStep=o._sourceGridStep;
    _sourceGridSize=o._sourceGridSize;
  }

  void FKParameters::setDefaultValues(ProcessType t, InversionMethod invm, ArrayStations::Mode m)
  {
    int n=1;
    switch(m) {
    case ArrayStations::Vertical:
      break;
    case ArrayStations::Horizontal:
      n=2;
      break;
    case ArrayStations::ThreeComponents:
      n=3;
      break;
    }
    _processType=t;
    _maxPeakCount=INT_MAX; // Avoid sensitivity to negligible differences between
                           // peak amplitudes. Accept by default all peaks down to
                           // 90% of the maximum amplitude.
    _absoluteThreshold=0.0;
    _relativeThreshold=90.0;

    _exportAllFKGrids=false;
    _refineGridIndex=-1;
    _skipLove=false;
    _damping=0.0;
    _rotateStepCount=72;
    setfrequencyBandwidth(0.05);
    blockAveraging().setStatisticCount(50);
    blockAveraging().setStatisticMaxOverlap(0.0);

    switch(_processType) {
    case DirectSteering:
    case DirectSteeringRadial:
    case DirectSteeringVertical:
    case DirectSteeringRefined:
    case Omni:
    case PoggiRadial:
    case PoggiVertical:
    case RTBF:
    case RTBFRadial:
    case Conventional:
      windowing().setPeriodCount(100.0);
      setOversamplingFactor(1.0);
      _minimumDistance=0.0;
      _maximumDistance=std::numeric_limits<double>::infinity();
      windowing().setSeismicEventTrigger(false);
      setSelectDurationFactor(0.0);
      break;
    case ActiveDirectSteering:
    case ActiveRTBF:
    case ActiveConventional:
      windowing().setLength(5.0);
      setOversamplingFactor(5.0);
      _minimumDistance=10.0;
      _maximumDistance=100.0;
      windowing().setSeismicEventTrigger(true);
      windowing().setSeismicEventDelay(-0.1);
      setSelectDurationFactor(0.0); // required for multi-shot with huge gaps
      break;
    }

    switch(_processType) {
    case DirectSteering:
    case DirectSteeringRadial:
    case DirectSteeringVertical:
    case DirectSteeringRefined:
    case Omni:
    case PoggiRadial:
    case PoggiVertical:
      blockAveraging().setCount(0);
      blockAveraging().setCountFactor(2.0*n);
      break;
    case RTBF:
    case RTBFRadial:
      blockAveraging().setCount(0);
      blockAveraging().setCountFactor(n==1 ? 2.0 : 2.0*(n-1));
      invm=RefinedGrid; // Gradient not supported for RTBF
      break;
    case Conventional:
      blockAveraging().setCount(0);
      blockAveraging().setCountFactor(n==1 ? 0.5 : 0.5*(n-1));
      setMaximumPeakCount(1);
      break;
    case ActiveConventional:
      blockAveraging().setCount(1);
      setMaximumPeakCount(1);
      break;
    case ActiveRTBF:
    case ActiveDirectSteering:
      blockAveraging().setCount(3);
      break;
    }
    _inversionMethod=invm;
    _gridStepFactor=defaultGridStepFactor(t, _inversionMethod);
    // Force default grid step and size if they are not yet set
    setKmin(_kmin);
    setKmax(_kmax);
  }

  double FKParameters::defaultGridStepFactor(ProcessType t, InversionMethod m)
  {
    switch(t) {
    case DirectSteering:
    case DirectSteeringRadial:
    case DirectSteeringVertical:
    case DirectSteeringRefined:
    case Omni:
    case PoggiRadial:
    case PoggiVertical:
    case RTBF:
    case RTBFRadial:
    case ActiveRTBF:
    case ActiveDirectSteering:
      switch(m) {
      case Gradient:
        return 0.5;
      case RefinedGrid:
        return 0.1;
      }
    case Conventional:
    case ActiveConventional:
      break;
    }
    switch(m) {
    case Gradient:
      break;
    case RefinedGrid:
      return 0.25;
    }
    return 1.0;
  }

  double FKParameters::gridSize(double kmax)
  {
    return kmax*2.0;
  }

  double FKParameters::cacheGridStep() const
  {
    if(_cacheGridStep==0.0) {
      return _kmin*_cacheGridStepFactor;
    } else {
      return _cacheGridStep;
    }
  }

  double FKParameters::gridStep() const
  {
    if(_gridStep==0.0) {
      return _kmin*_gridStepFactor;
    } else {
      return _gridStep;
    }
  }

  void FKParameters::setKmin(double k)
  {
    _kmin=k;
  }

  void FKParameters::setKmax(double k)
  {
    _kmax=k;
    if(_gridSize==0.0) {
      _gridSize=gridSize(_kmax);
    }
  }

  /*!
    Limit grid size to fall inside the frequency-slowness area of interest.
  */
  double FKParameters::effectiveGridSize() const
  {
    double ksmax=2.0*M_PI*frequencySampling().maximum()*_smax;
    // For the GUI frequency sampling maximum is usually null
    if(ksmax<_gridSize && ksmax>0.0) {
      return ksmax;
    } else {
      return _gridSize;
    }
  }

  /*!
    Convenience function to get the effective grid size at \a frequnecy,
    taking into account the maximum slowness.
  */
  double FKParameters::effectiveGridSize(double frequency) const
  {
    TRACE;
    double ksmax=2.0*M_PI*frequency*_smax;
    if(ksmax<_gridSize) {
      return ksmax;
    } else {
      return _gridSize;
    }
  }

  void FKParameters::clearCurveRefine()
  {
    TRACE;
    _refineSlowMin.clear();
    _refineSlowMax.clear();
  }

  /*!
    \a gridIndex can be -1, 0 or 1.
      \li -1 to switch off refine computation (full frequency range is computed)
      \li 0 Rayleigh grid
      \li 1 Love grid
  */
  void FKParameters::FKParameters::setRefineGridIndex(int gridIndex)
  {
    TRACE;
    ASSERT(gridIndex>=-1 || gridIndex<=1);
    _refineGridIndex=gridIndex;
  }

  void FKParameters::addCurveRefine(double f, double minSlow, double maxSlow)
  {
    TRACE;
    _refineSlowMin.append(Point2D(f, minSlow));
    _refineSlowMax.append(Point2D(f, maxSlow));
  }

  int FKParameters::keywordCount(PARAMETERS_KEYWORDCOUNT_ARGS) const
  {
    return 27+ArrayParameters::keywordCount();
  }

  void FKParameters::collectKeywords(PARAMETERS_COLLECTKEYWORDS_ARGS)
  {
    TRACE;
    int baseIndex=ArrayParameters::keywordCount();
    ArrayParameters::collectKeywords(keywords, prefix, suffix);
    keywords.add(prefix+"INVERSION_METHOD"+suffix, this, baseIndex+19);
    keywords.add(prefix+"CACHE_GRID_STEP"+suffix, this, baseIndex+20);
    keywords.add(prefix+"CACHE_GRID_STEP_FACTOR"+suffix, this, baseIndex+21);
    keywords.add(prefix+"GRID_STEP"+suffix, this, baseIndex+16);
    keywords.add(prefix+"GRID_STEP_FACTOR"+suffix, this, baseIndex+18);
    keywords.add(prefix+"GRID_SIZE"+suffix, this, baseIndex+17);
    keywords.add(prefix+"K_MIN"+suffix, this, baseIndex);
    keywords.add(prefix+"K_MAX"+suffix, this, baseIndex+1);
    keywords.add(prefix+"MIN_V"+suffix, this, baseIndex+2);
    keywords.add(prefix+"MAX_V"+suffix, this, baseIndex+24);
    keywords.add(prefix+"MIN_AZIMUTH"+suffix, this, baseIndex+25);
    keywords.add(prefix+"MAX_AZIMUTH"+suffix, this, baseIndex+26);
    keywords.add(prefix+"N_MAXIMA"+suffix, this, baseIndex+3);
    keywords.add(prefix+"ABSOLUTE_THRESHOLD"+suffix, this, baseIndex+4);
    keywords.add(prefix+"RELATIVE_THRESHOLD"+suffix, this, baseIndex+5);
    keywords.add(prefix+"EXPORT_ALL_FK_GRIDS"+suffix, this, baseIndex+6);
    keywords.add(prefix+"DAMPING_FACTOR"+suffix, this, baseIndex+7);
    keywords.add(prefix+"ROTATE_STEP_COUNT"+suffix, this, baseIndex+8);
    keywords.add(prefix+"PROCESS_TYPE"+suffix, this, baseIndex+9);
    keywords.add(prefix+"ARRAY"+suffix, this, baseIndex+10);
    keywords.add(prefix+"SKIP_LOVE"+suffix, this, baseIndex+11);
    keywords.add(prefix+"FIXED_ELLIPTICITY_FILE_NAME"+suffix, this, baseIndex+12);
    keywords.add(prefix+"MINIMUM_DISTANCE"+suffix, this, baseIndex+13);
    keywords.add(prefix+"MAXIMUM_DISTANCE"+suffix, this, baseIndex+14);
    keywords.add(prefix+"DO_DAMPING_FACTOR"+suffix, this, baseIndex+15); // For compatibility
    keywords.add(prefix+"SOURCE_GRID_STEP"+suffix, this, baseIndex+22);
    keywords.add(prefix+"SOURCE_GRID_SIZE"+suffix, this, baseIndex+23);
  }

  QString FKParameters::toString(PARAMETERS_TOSTRING_ARGS_IMPL) const
  {
    TRACE;
    QString log;
    log+=ArrayParameters::toString(prefix, suffix);
    log+="# Process types:\n"
         "#  [All types can be used with vertical or three component datasets]\n"
         "#  Keyword                Beamformer    Comments\n"
         "#  DirectSteering         Capon         Cross spectrum made of raw components E, N and Z.\n"
         "#                                       Radial and transverse projections included in steering matrix.\n"
         "#                                       Combined optimum power.\n"
         "#  Omni                   Capon         Same cross spectrum as DirectSteering.\n"
         "#                                       Ouput power is the sum of power in all directions\n"
         "#  RTBF                   Capon         According to Wathelet et al (2018).\n"
         "#                                       Cross spectrum made of radial and transverse projections.\n"
         "#  PoggiVertical          Capon         According Poggi et al. (2010)\n"
         "#                                       k picked from vertical processing\n"
         "#  PoggiRadial            Capon         According Poggi et al. (2010)\n"
         "#                                       k picked from radial processing\n"
         "#  Conventional           Conventional  Conventional FK processing\n"
         "#                                       Cross spectrum made of radial and transverse projections.\n"
         "#  ActiveRTBF             Capon         High resolution for active source\n"
         "#                                       Cross spectrum made of radial and transverse projections.\n"
         "#  ActiveDirectSteering   Capon         Cross spectrum made of raw components E, N and Z.\n"
         "#                                       Radial and transverse projections included in steering matrix.\n"
         "#  ActiveConventional     Conventional  Conventional FK processing\n"
         "#                                       Cross spectrum made of radial and transverse projections.\n"
         "#  Experimental modes:\n"
         "#  DirectSteeringVertical Capon         Cross spectrum made of raw components E, N and Z.\n"
         "#                                       Radial and transverse projections included in steering matrix.\n"
         "#                                       Radial ellipticity steering.\n"
         "#  DirectSteeringRadial   Capon         Cross spectrum made of raw components E, N and Z.\n"
         "#                                       Radial and transverse projections included in steering matrix.\n"
         "#                                       Vertical ellipticity steering.\n"
         "#  DirectSteeringRefined  Capon         Cross spectrum made of raw components E, N and Z.\n"
         "#                                       Radial and transverse projections included in steering matrix.\n"
         "#                                       Iterative ellitpticity assessment.\n";
    log+=prefix+"PROCESS_TYPE"+suffix+"="+processTypeString()+"\n";
    log+="# For debug purpose, save a bit of time by skipping Love computation\n";
    log+=prefix+"SKIP_LOVE"+suffix+"(y/n)="+(_skipLove ? "y" : "n")+"\n";

    log+="# Inversion method used for getting FK peaks: Gradient or RefinedGrid\n";
    log+=prefix+"INVERSION_METHOD"+suffix+"="+inversionMethodString()+"\n";

    log+="# Wavenumber fine gridding used as a cache for the FK maps\n";
    log+=prefix+"CACHE_GRID_STEP"+suffix+" (rad/m)="+QString::number(_cacheGridStep)+"\n";
    log+="# If CACHE_GRID_STEP is null, GRID_STEP is computed from K_MIN*CACHE_GRID_STEP_FACTOR.\n";
    log+=prefix+"CACHE_GRID_STEP_FACTOR"+suffix+"="+QString::number(_cacheGridStepFactor)+"\n";

    log+="# Wavenumber coarse gridding used for searching maxima of the FK maps\n";
    log+=prefix+"GRID_STEP"+suffix+" (rad/m)="+QString::number(_gridStep)+"\n";
    log+="# If GRID_STEP is null, GRID_STEP is computed from K_MIN*GRID_STEP_FACTOR.\n";
    log+=prefix+"GRID_STEP_FACTOR"+suffix+"="+QString::number(_gridStepFactor)+"\n";
    log+=prefix+"GRID_SIZE"+suffix+" (rad/m)="+QString::number(_gridSize)+"\n";

    log+="# Minimum velocity of the searched maxima of the FK map\n";
    log+=prefix+"MIN_V"+suffix+" (m/s)="+QString::number(1.0/_smax)+"\n";
    log+="# Maximum velocity of the searched maxima of the FK map\n";
    log+=prefix+"MAX_V"+suffix+" (m/s)="+QString::number(1.0/_smin)+"\n";

    log+="# Minimum azimuth of the searched maxima of the FK map (math\n";
    log+=prefix+"MIN_AZIMUTH"+suffix+" (deg.)="+QString::number(_minAzimuth)+"\n";
    log+="# Maximum azimith of the searched maxima of the FK map (math)\n";
    log+=prefix+"MAX_AZIMUTH"+suffix+" (deg.)="+QString::number(_maxAzimuth)+"\n";

    log+="# Theoretical Kmin and Kmax computed from array geometry\n";
    log+="# Used only for post-processing (AVIOS project)\n";
    log+=prefix+"K_MIN"+suffix+" (rad/m)="+QString::number(_kmin)+"\n";
    log+=prefix+"K_MAX"+suffix+" (rad/m)="+QString::number(_kmax)+"\n";
    log+=prefix+"N_MAXIMA"+suffix+"="+QString::number(_maxPeakCount)+"\n";
    log+=prefix+"ABSOLUTE_THRESHOLD"+suffix+"="+QString::number(_absoluteThreshold)+"\n";
    log+=prefix+"RELATIVE_THRESHOLD"+suffix+" (%)="+QString::number(_relativeThreshold)+"\n";
    log+=prefix+"EXPORT_ALL_FK_GRIDS"+suffix+"="+(_exportAllFKGrids ? "y" : "n")+"\n";
    log+=prefix+"DAMPING_FACTOR"+suffix+"="+QString::number(_damping)+"\n";
    log+="# If provided and PROCESS_TYPE==DirectSteering, the ellipticity is forced to the provided curve.\n"
         "# The file must contain two columns: frequency and signed ellipticity.\n"
         "# Provided sampling must not necessarily match the processing sampling frequency, linear interpolation is used.\n"
         "# Better for precision if the two sampling match.\n"
         "# To generate a synthetic curve: gpell M2.1.model -one-mode -R 1 -min 0.5 -max 50 -n 187 > curve.txt\n";
    log+=prefix+"FIXED_ELLIPTICITY_FILE_NAME"+suffix+"="+_fixedEllipticityFileName+"\n";
    log+="# Minimum distance between source and receiver (for active source only)\n";
    log+=prefix+"MINIMUM_DISTANCE"+suffix+"="+QString::number(_minimumDistance)+"\n";
    log+="# Maximum distance between source and receiver (for active source only)\n";
    log+=prefix+"MAXIMUM_DISTANCE"+suffix+"="+QString::number(_maximumDistance)+"\n";
    log+="# Experimental join processing of several arrays\n";
    log+="# Several ARRAY can be defined with a list of station names\n";
    for(QList<QStringList>::const_iterator it=_arrays.begin(); it!=_arrays.end(); it++) {
      log+=prefix+"ARRAY"+suffix+"="+it->join(',')+"\n";
    }

    switch(_processType) {
    case DirectSteering:
    case DirectSteeringRadial:
    case DirectSteeringRefined:
    case DirectSteeringVertical:
    case ActiveConventional:
    case ActiveRTBF:
    case ActiveDirectSteering:
    case Omni:
      break;
    case RTBF:
    case RTBFRadial:
    case PoggiVertical:
    case PoggiRadial:
    case Conventional:
      log+="# Number of steps for the computation of radial/transverse projections\n";
      log+=prefix+"ROTATE_STEP_COUNT"+suffix+"="+QString::number(_rotateStepCount)+"\n";
      break;
    }
    log+="# \n";
    log+=prefix+"SOURCE_GRID_STEP"+suffix+"="+QString::number(_sourceGridStep)+"\n";
    log+=prefix+"SOURCE_GRID_SIZE"+suffix+"="+QString::number(_sourceGridSize)+"\n";
    return log;
  }

  bool FKParameters::setValue(PARAMETERS_SETVALUE_ARGS)
  {
    TRACE;
    bool ok=true;
    switch(index-ArrayParameters::keywordCount()) {
    case 19:
      setInversionMethod(value);
      return true;
    case 20:
      _cacheGridStep=value.toDouble(&ok);
      return ok;
    case 21:
      _cacheGridStepFactor=value.toDouble(&ok);
      return ok;
    case 0:
      if(version()<1) {
        _gridStep=value.toDouble(&ok); // Old release were saving grid_step instead of kmin
        _kmin=0;                       // Force automatic computation from array geometry
      } else {
        _kmin=value.toDouble(&ok);
      }
      return ok;
    case 1:
      if(version()<1) {
        _gridSize=value.toDouble(&ok); // Old release were saving grid_size instead of kmax
        _kmax=0;                       // Force automatic computation from array geometry
      } else {
        _kmax=value.toDouble(&ok);
      }
      return ok;
    case 16:
      _gridStep=value.toDouble(&ok);
      return ok;
    case 17:
      _gridSize=value.toDouble(&ok);
      return ok;
    case 18:
      _gridStepFactor=value.toDouble(&ok);
      return ok;
    case 24:
      _smin=1.0/value.toDouble(&ok);
      return ok;
    case 2:
      _smax=1.0/value.toDouble(&ok);
      return ok;
    case 25:
      _minAzimuth=value.toDouble(&ok);
      return ok;
    case 26:
      _maxAzimuth=value.toDouble(&ok);
      return ok;
    case 3:
      _maxPeakCount=value.toInt(&ok);
      return ok;
    case 4:
      _absoluteThreshold=value.toDouble(&ok);
      return ok;
    case 5:
      _relativeThreshold=value.toDouble(&ok);
      return ok;
    case 6:
      _exportAllFKGrids=(value=="y");
      return true;
    case 7:
      if(_damping>=0.0) {
        _damping=value.toDouble(&ok);
      }
      return ok;
    case 8:
      _rotateStepCount=value.toInt(&ok);
      return ok;
    case 9:
      setProcessType(value);
      return true;
    case 10:
      _arrays.append(value.split(','));
      return true;
    case 11:
      _skipLove=(value=="y");
      return true;
    case 12:
      _fixedEllipticityFileName=value;
      return true;
    case 13:
      _minimumDistance=value.toDouble(&ok);
      return ok;
    case 14:
      _maximumDistance=value.toDouble(&ok);
      return ok;
    case 15: // For compatibility
      obsoleteKeyword(keywords, 15);
      if(value=="n") {
        _damping=-1.0;
      }
      return true;
    case 22:
      _sourceGridStep=value.toDouble(&ok);
      return ok;
    case 23:
      _sourceGridSize=value.toDouble(&ok);
      return ok;
    default:
      break;
    }
    return ArrayParameters::setValue(index, value, unit, keywords);
  }

  bool FKParameters::setProcessType(QString p)
  {
    p=p.toLower();
    if(p=="directsteering") {
      _processType=DirectSteering;
    } else if(p=="omni") {
      _processType=Omni;
    } else if(p=="conventional") {
      _processType=Conventional;
    } else if(p=="poggivertical") {
      _processType=PoggiVertical;
    } else if(p=="poggiradial") {
      _processType=PoggiRadial;
    } else if(p=="rtbf" ||
              p=="projections") {
      _processType=RTBF;
    } else if(p=="rtbfradial") {
      _processType=RTBFRadial;
    } else if(p=="directsteeringrefined") {
      _processType=DirectSteeringRefined;
    } else if(p=="directsteeringvertical") {
      _processType=DirectSteeringVertical;
    } else if(p=="directsteeringradial") {
      _processType=DirectSteeringRadial;
    } else if(p=="activeprojections") {
      _processType=ActiveRTBF;
    } else if(p=="activeconventional") {
      _processType=ActiveConventional;
    } else if(p=="activedirectsteering") {
      _processType=ActiveDirectSteering;
    } else {
      return false;
    }
    return true;
  }

  QString FKParameters::processTypeString() const
  {
    switch(_processType) {
    case DirectSteering:
      break;
    case Omni:
      return "Omni";
    case Conventional:
      return "Conventional";
    case PoggiVertical:
      return "PoggiVertical";
    case PoggiRadial:
      return "PoggiRadial";
    case RTBF:
      return "RTBF";
    case RTBFRadial:
      return "RTBFRadial";
    case DirectSteeringRefined:
      return "DirectSteeringRefined";
    case DirectSteeringVertical:
      return "DirectSteeringVertical";
    case DirectSteeringRadial:
      return "DirectSteeringRadial";
    case ActiveRTBF:
      return "ActiveRTBF";
    case ActiveConventional:
      return "ActiveConventional";
    case ActiveDirectSteering:
      return "ActiveDirectSteering";
    }
    return "DirectSteering";
  }

  bool FKParameters::isActiveProcessType() const
  {
    switch(_processType) {
    case ActiveConventional:
    case ActiveRTBF:
    case ActiveDirectSteering:
      break;
    case Omni:
    case Conventional:
    case PoggiVertical:
    case PoggiRadial:
    case RTBF:
    case RTBFRadial:
    case DirectSteering:
    case DirectSteeringRefined:
    case DirectSteeringVertical:
    case DirectSteeringRadial:
      return false;
    }
    return true;
  }


  bool FKParameters::setInversionMethod(QString p)
  {
    p=p.toLower();
    if(p=="refinedgrid") {
      _inversionMethod=RefinedGrid;
    } else if(p=="gradient") {
      _inversionMethod=Gradient;
    } else {
      return false;
    }
    return true;
  }

  QString FKParameters::inversionMethodString() const
  {
    switch(_inversionMethod) {
    case Gradient:
      break;
    case RefinedGrid:
      return "RefinedGrid";
    }
    return "Gradient";
  }

} // namespace ArrayCore
