/***************************************************************************
**
**  This file is part of QGpCoreWave.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2004-04-28
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <math.h>
#include <stdlib.h>

#include "Love.h"

namespace QGpCoreWave {

#define twopi (2*M_PI)

/*!
  \class Love
  \brief Implementation of Love surface waves
  
  It is a layered model able to calculate the roots corresponding
  to the theoretical Love dispersion curve.
*/

/*!
  \fn double Love::ellipticity()

  Useless for Love case\n
*/

/*!
  Computation of the Love function whose roots are located at the
  Love dispersion curves.\n
*/
double Love::y(double slowness)
{
  TRACE;
  int i=_model->layerCount()-1;
  // slowness is the inverse of V_L, the Love velocity
  double k=_omega*slowness;
  // inverse of V_s
  double slowS=_model->slowS(i);
  // Wave number for S waves
  double ks=_omega*slowS;
  double nu=sqrt(fabs(k*k-ks*ks));
  double l21=_model->rho(i)*nu;
  double l22=slowS*slowS;
  double g11, sinq, g12, g21, q, mui, numui;
  for(i--;i>=0;i--) {
    slowS=_model->slowS(i);
    ks=_omega*slowS;
    nu=sqrt(fabs(k*k-ks*ks));
    q=_model->h(i)*nu; // Q is always positive
    mui=_model->mu(i);
    numui=nu*mui;
    if(k<ks) {
      g11=cos(q); //=g22
      sinq=sin(q);
      g12=sinq/numui;
      g21=-numui*sinq; // minus sign comes from i*i=-1
     }
    else if(k==ks) {
      g11=1; //=g22
      g12=_model->h(i)/mui;
      g21=0;
    }
    else {
      double fac=0;
      if(q<21.2) fac=exp(-2.0*q); /* min significative number is 1e-19
                                      19/2 *ln(10)=21.2, 0.0<fac<1.0 */
      g11=(1.0+fac)*0.5; //=g22 0.5<g11<2
      sinq=(1.0-fac)*0.5; // 0<sinq<0.5
      g12=sinq/numui; // 0<g12<0.5/numui
      g21=numui*sinq; // 0<g21<numui*0.5
    }
    /* Normalization (we can multiply both elements by any constant factor,
       the root will be unchanged) to avoid possible overflow. */
    double l21n=l21*g11+l22*g21;
    double l22n=l21*g12+l22*g11;
    double maxL=fabs(l21n);
    if(fabs(l22n)>maxL) maxL=fabs(l22n);
    if(maxL>1.0e5) {
      maxL=1.0e5/maxL;
      l21=l21n*maxL;
      l22=l22n*maxL;
    }
    else {
      l21=l21n;
      l22=l22n;
    }
  }
  return l21;
}

} // namespace QGpCoreWave
