/***************************************************************************
**
**  This file is part of QGpCompatibility.
**
**  QGpCompatibility 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.
**
**  QGpCompatibility 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: 2004-10-22
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "CompatModalEllipticity.h"
#include "CompatModalDispersion.h"
#include "CompatEllipticityData.h"

namespace QGpCompatibility {

const QString CompatModalEllipticity::xmlModalEllipticityTag="ModalEllipticity";

/*!
  \class CompatModalEllipticity CompatModalEllipticity.h
  \brief Calculate Rayleigh ellipticity curves and their misfits
  
  The main function used to calculate the ellipticity curve is calculate().
  
  Misfits can be computed by misfit() or closestModeMisfit().
*/

/*!
  \fn double misfit()
  Calculate the misfit for the current calculated ellipticity curve.\n
*/

void CompatModalEllipticity::operator=(CompatModalEllipticity& o)
{
  TRACE;
  CompatModalRefinedCurves::operator=(o);
  _peakFrequencyMisfit=o._peakFrequencyMisfit;
  _f0=o._f0;
}

/*!
  Calculate the misfit for the current calculated ellipticity curve between
  frequency indexes iMin and iMax.\n
*/
double CompatModalEllipticity::misfit(int iMin, int iMax)
{
  TRACE;
  // Global RMS is the sum of the RMS of all modes
  double rms_val=0;
  int omegaCountReal=iMax-iMin+1;
  int omegaCountData=omegaCountReal;
  CompatVDataPointVector point=mode(0);
  for(int i=iMin;i<=iMax;i++)
    rms_val+=point[i].misfitOrder2(omegaCountData, omegaCountReal, COMPATMODALELLIPTICITY_INVALID_VALUE);
  if(omegaCountReal>0)
    rms_val=sqrt(rms_val/omegaCountReal)*(1+omegaCountData-omegaCountReal);
  else if(omegaCountData==0) rms_val=0;
  else {
    App::log(tr(" *** ERROR *** : no common value between calculated and data, this should never happen!\n") );
    rms_val=10000; 
  }
  return rms_val;
}

void CompatModalEllipticity::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
{
  TRACE;
  writeProperty(s, "peakFrequencyMisfit",_peakFrequencyMisfit);
  CompatModalRefinedCurves::xml_writeProperties(s, context);
}

void CompatModalEllipticity::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
{
  TRACE;
  _f0.xml_save(s, context);
  CompatModalRefinedCurves::xml_writeChildren(s, context);
}

XMLMember CompatModalEllipticity::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  if(tag=="DataPoint") return XMLMember(&_f0);
  else if(tag=="peakFrequencyMisfit") return XMLMember(0);
  return CompatModalRefinedCurves::xml_member(tag, attributes, context)+1;
}

bool CompatModalEllipticity::xml_setProperty(XML_SETPROPERTY_ARGS)
{
  TRACE;
  if(memberID==0) {
    _peakFrequencyMisfit=content.toBool();
    return true;
  } else return CompatModalRefinedCurves::xml_setProperty(memberID-1, tag, attributes, content, context);
}

// To be removed in the future, when Dinver will be completly finished
CompatEllipticityData * CompatModalEllipticity::oldStyle()
{
  TRACE;
  int nm=nModes();
  int nf=nOmegas();
  CompatEllipticityData * ell=new CompatEllipticityData(nm,nf);
  for(int i=0;i<nf;i++) {
    ell->setFrequency(i,omega(i)/(2*M_PI));
  }
  for(int im=0;im<nm;im++) {
    CompatVDataPointVector point=mode(im);
    for(int i=0;i<nf;i++) {
      ell->setMean(i,im,point[i].mean());
      ell->setStddev(i,im,point[i].stddev());
      ell->setWeight(i,im,point[i].weight());
      ell->setValue(i,im,point[i].value());
    }
  }
  return ell;
}

} // namespace QGpCompatibility
