/***************************************************************************
**
**  This file is part of gpsh.
**
**  gpsh 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.
**
**  gpsh 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: 2019-03-23
**  Copyright: 2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "KennettSH.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
KennettSH::KennettSH(Seismic1DModel * model)
{
  TRACE;
  _model=model;
  _layerCount=_model->layerCount();

  ai.set(0.0, 1.0);
  pi=M_PI;
  pi2=2.0*M_PI;

  uint n=_layerCount;
  uint n4=n*4;

  // dim1a
  cvp=new Complex[n];
  cvs=new Complex[n];

  // dim1a
  cka=new Complex[n];
  ckb=new Complex[n];
  cka2=new Complex[n];
  ckb2=new Complex[n];
  cnu=new Complex[n];
  cgam=new Complex[n];

  // dim2c
  _rd=new Complex[n4];
  _ru=new Complex[n4];
  _td=new Complex[n4];
  _tu=new Complex[n4];
  rdsh=new Complex[n];
  rush=new Complex[n];
  tdsh=new Complex[n];
  tush=new Complex[n];
  me1=new Complex[n];
  me2=new Complex[n];

  // dim2d
  _nt=new Complex[n4];
  _mt=new Complex[n4];
  ntsh=new Complex[n];
  mtsh=new Complex[n];

  // dim2e
  _fdo=new Complex[n4];
  _fup=new Complex[n4];
  fupsh=new Complex[n];
  fdosh=new Complex[n];

  // reflect4
  _ftup=nullptr;
  _ftdo=nullptr;
  _cfwave=new Complex[n4*3];
}

/*!
  Description of destructor still missing
*/
KennettSH::~KennettSH()
{
  TRACE;
  // dim1a
  delete [] cvp;
  delete [] cvs;

  // dim1a
  delete [] cka;
  delete [] ckb;
  delete [] cka2;
  delete [] ckb2;
  delete [] cnu;
  delete [] cgam;

  // dim2c
  delete [] _rd;
  delete [] _ru;
  delete [] _td;
  delete [] _tu;
  delete [] rdsh;
  delete [] rush;
  delete [] tdsh;
  delete [] tush;
  delete [] me1;
  delete [] me2;

  // dim2d
  delete [] _nt;
  delete [] _mt;
  delete [] ntsh;
  delete [] mtsh;

  // dim2e
  delete [] _fdo;
  delete [] _fup;
  delete [] fupsh;
  delete [] fdosh;

  // reflect4
  delete [] _cfwave;
}

/*!
    program psv1d (kennett)
        Authors:
          Pierre-Yves Bard (LGIT, Grenoble, France)
          Cecile Cornou (LGIT, Grenoble, France), minor modifications
          Marc Wathelet (LGIT, Grenoble, France), port to subroutine


        frequency          Current frequency
        receiverDepth      Depth of receiver
*/
double KennettSH::sh(double frequency, double receiverDepth)
{
  // Variation of Q versus frequency
  double refFrequency=10.0;
  double qualityFactorFactor=0.0;

  double incidenceAngle=0.0;
  int mode=3; // SH
  int jcas=0;

  uint n=_layerCount;
  double * depths=new double[n];
  depths[0]=0.0;
  for(int li=1; li<_layerCount; li++) {
    depths[li]=depths[li-1]+_model->h(li-1);
  }
  int receiverLayerIndex=_layerCount-1;
  for(int li=1; li<_layerCount; li++) {
    if(receiverDepth<depths[li]) {
      receiverLayerIndex=li-1;
      break;
    }
  }

  double om0=pi2*refFrequency;
  double aw=-pi/1.0e20;
  double rw=frequency*pi2;
  Complex omega(rw,aw);
  double adr=std::log(omega.abs()/om0);
  double phi=omega.phase();
  Complex ad(adr, phi);
  double df=frequency-refFrequency;
  if(df<0.0) {
    df=0.0;
  }
  Complex * alpha=new Complex[n];
  Complex * beta=new Complex[n];
  Complex * wa2=new Complex[n];
  Complex * wb2=new Complex[n];
  Complex wan, wbn;
  for(int li=0; li<_layerCount; li++) {
    double qsi=_model->qs(li)*(1. + qualityFactorFactor*df);
    double piqs=1./(pi*qsi);
    Complex cqs=1. - .5*ai/qsi;
    Complex cds=1. - piqs*ad;
    beta[li]=1.0/(cds*cqs*_model->slowS(li));
    //beta[li]=beta0[li]*(1. + .5*ai/qsi + piqs*adr)
    double qpi=_model->qp(li)*(1. + qualityFactorFactor*df);
    double piqp=1./(pi*qpi);
    Complex cqp=1. - .5*ai/qpi;
    Complex cdp=1. - piqp*ad;
    alpha[li]=1.0/(cdp*cqp*_model->slowP(li));
    //alpha[li]=alpha0[li]*(1. + .5*ai/qpi + piqp*adr)
    Complex wb=omega/beta[li];
    wb2[li]=wb*wb;
    Complex wa=omega/alpha[li];
    wa2[li]=wa*wa;
    if(li==_layerCount-1) {
      wan=wa;
      wbn=wb;
    }
  }

  double tet=Angle::degreesToRadians(incidenceAngle);
  Complex wx0, c1;
  if(mode==1) {
    wx0=wan*std::sin(tet);
    c1=-ai/wan;
  } else {
    wx0=wbn*std::sin(tet);
    c1=ai/wbn;
  }
  Complex wx02=wx0*wx0;

  setFrequency(wx0,omega,alpha,beta);
  reflect1(jcas);
  reflect2();
  reflect4(jcas);
  delete [] alpha;
  delete [] beta;

  /*   si mode =1 ou 2
       1=onde p montante
       2=onde p descendante
       3=onde sv montante
       4=onde sv descendante

       si mode=3
         1=onde sh montante
         1=onde sh descendante
  */
  Complex * wza=new Complex[n];
  Complex * wzb=new Complex[n];
  for(int li=0; li<_layerCount; li++) {
    Complex wza2=wa2[li] - wx02;
    Complex wzb2=wb2[li] - wx02;
    wza[li]=QGpCoreTools::sqrt(wza2);
    wzb[li]=QGpCoreTools::sqrt(wzb2);
    if(wza[li].im()>0.0) {
      wza[li]=-wza[li];
    }
    if(wzb[li].im()>0.0) {
      wzb[li]=-wzb[li];
    }
  }
  delete [] wa2;
  delete [] wb2;

  int li=receiverLayerIndex;
  double z=receiverDepth-depths[li];
  Complex phaspu=QGpCoreTools::exp(ai*wza[li]*z);
  Complex phassu=QGpCoreTools::exp(ai*wzb[li]*z);
  Complex phaspd=1./phaspu;
  Complex phassd=1./phassu;

  delete [] wza;
  delete [] wzb;
  delete [] depths;

  // PSV
  /*Complex u1=-ai*wx0;
  Complex u4= ai*wzb[li];
  Complex w1= ai*wza[li];

  int li1=4*li;
  int li2=li1+1;
  int li3=li2+1;
  int li4=li3+1;
  Complex f1=cfwave(li1,mode)*phaspu;
  Complex f2=cfwave(li2,mode)*phaspd;
  Complex f3=cfwave(li3,mode)*phassu;
  Complex f4=cfwave(li4,mode)*phassd;
  Complex uh0=u1*(f1 + f2) + u4*(f4 - f3);
  Complex uv0=w1*(f1 - f2) + u1*(f3 + f4);

  return (uh0*c1).abs();  // u
  return (uv0*c1).abs();  // w */
  // SH
  int lish1=2*li;
  int lish2=lish1+1;
  // Factor comes for the reference: either the true motion at the bedrock or
  // the motion at a free-surface over a half-space with the properties of the bedrock.
  // Factor 2 ensures that function is 1 at low frequencies
  return 0.5*(cfwave(lish1,mode)*phassu + cfwave(lish2,mode)*phassd).abs();
}

void KennettSH::setFrequency(Complex ckx, Complex comega, Complex * calpha, Complex *cbeta)
{
  cwx=ckx;
  cwx2=cwx*cwx;
  omega=comega;
  omega2=omega*omega;
  for (int ic=0; ic<_layerCount; ++ic) {
    cvp[ic]=calpha[ic];
    cvs[ic]=cbeta[ic];
    cka[ic]=omega/cvp[ic];
    ckb[ic]=omega/cvs[ic];
    ckb2[ic]=ckb[ic]*ckb[ic];
    cka2[ic]=cka[ic]*cka[ic];
    cnu[ic]=QGpCoreTools::sqrt(cka2[ic]-cwx2);
    if(cnu[ic].im()>0.0) {
      cnu[ic]=-cnu[ic];
    }
    cgam[ic]=QGpCoreTools::sqrt(ckb2[ic]-cwx2);
    if(cgam[ic].im()>0.0) {
      cgam[ic]=-cgam[ic];
    }
  }
}

/*!
******************************************************************************
*                                                          AXITRA Version 1.0 *
*                         subroutine REFLECT1                                 *
*                                                                             *
*               Calcul des coefficients de reflexion/transmission             *
*               Matrice de Reflexion/Transmission et Dephasage                *
*       (Les coefficients de reflexion/transmission utilisent les memes       *
*            termes intermediaires que Aki-Richards p149, MAIS :              *
*            Aki utilise la convention inverse pour la TF (exp(-iwt)),        *
*        et travaille avec le parametre de rai et les angles d'incidences)    *
*                                                                             *
*      Le potentiel PSI utilise pour l'onde SV est defini par :               *
*                  u=rot (rot (PSI))                                          *
*      i.e. un terme de derivation supplementaire par rapport a la convention *
*      habituelle : u= rot (PSI)                                              *
*                                                                             *
*   On deduit les coefficients de REF/TRANS de ceux definis par la convention *
*      classique en divisant le potentiel PSI par 1./ai/cwx=coef              *
* ---------FAIT LE 03/10/89 (PYB) --------------------------------------------*
*                                                                             *
*       Ordre de stockage :                                                   *
*                              pp=(1,1)   sp=(1,2)                            *
*                              ps=(2,1)   ss=(2,2)                            *
******************************************************************************
*/
void KennettSH::reflect1(int jcas)
{
  // Coefficient pour la convention sur PSI (coef) et sur la TF (aki=-1.)
  double aki=-1.;

  Complex cdd;

  if(jcas==0) {
    // Coefficient a la surface libre
    Complex cf1=(ckb2[0]-2.*cwx2);
    Complex cf2=cf1*cf1;
    Complex cf3=4.*cnu[0]*cwx2*cgam[0];
    cdd=cf2+cf3;

    ru(0,1,1)=(-cf2+cf3)/cdd;
    ru(0,2,1)=4.*cwx*cnu[0]*cf1/cdd*aki;
    ru(0,2,2)=(cf2-cf3)/cdd*aki;
    ru(0,1,2)=4.*cwx*cgam[0]*cf1/cdd;
    tu(0,1,1)=0.;
    tu(0,1,2)=0.;
    tu(0,2,1)=0.;
    tu(0,2,2)=0.;
    rush[0]=1.;
    tush[0]=0.;
  } else {
    // Coefficient pour espace infini
    ru(0,1,1)=0.;
    ru(0,2,1)=0.;
    ru(0,2,2)=0.;
    ru(0,1,2)=0.;
    tu(0,1,1)=1.;
    tu(0,1,2)=0.;
    tu(0,2,1)=0.;
    tu(0,2,2)=1.;
    rush[0]=0.;
    tush[0]=1.;
  }

  // Coefficients aux interfaces entre couches
  for(int ic=1; ic<_layerCount; ic++) {
    Complex cb1=cwx2/ckb2[ic-1];
    Complex cb2=cwx2/ckb2[ic];
    Complex ca1d=_model->rho(ic-1)*(1.-2.*cb1);
    Complex ca2d=_model->rho(ic)*(1.-2.*cb2);
    Complex ca=ca2d-ca1d;
    Complex cb=ca2d+2.*_model->rho(ic-1)*cb1;
    Complex cc=ca1d+2.*_model->rho(ic)*cb2;
    Complex cd=2.*(_model->rho(ic)/ckb2[ic]-_model->rho(ic-1)/ckb2[ic-1]);
    Complex ce=cb*cnu[ic-1]+cc*cnu[ic];
    Complex cf=cb*cgam[ic-1]+cc*cgam[ic];
    Complex cg=ca-cd*cnu[ic-1]*cgam[ic];
    Complex ch=ca-cd*cnu[ic]*cgam[ic-1];
    cdd=ce*cf+cg*ch*cwx2;

    rd(ic,1,1)= (cf*(cb*cnu[ic-1]-cc*cnu[ic])-
                ch*cwx2*(ca+cd*cnu[ic-1]*cgam[ic]))/cdd;
    rd(ic,1,2)=-2.*cwx*cgam[ic-1]*
                (ca*cb+cc*cd*cnu[ic]*cgam[ic])/cdd*aki;
    rd(ic,2,2)=-(ce*(cb*cgam[ic-1]-cc*cgam[ic])-
                cg*cwx2*(ca+cd*cnu[ic]*cgam[ic-1]))/cdd*aki;
    rd(ic,2,1)=-2.*cwx*cnu[ic-1]*
                (ca*cb+cc*cd*cnu[ic]*cgam[ic])/cdd;
    td(ic,1,1)= 2.*_model->rho(ic-1)*cnu[ic-1]*cf/cdd;
    td(ic,1,2)=-2.*_model->rho(ic-1)*cgam[ic-1]*cg*cwx/cdd*aki;
    td(ic,2,2)= 2.*_model->rho(ic-1)*cgam[ic-1]*ce/cdd;
    td(ic,2,1)= 2.*_model->rho(ic-1)*cnu[ic-1]*ch*cwx/cdd*aki;

    ru(ic,1,1)=-(cf*(cb*cnu[ic-1]-cc*cnu[ic])+
                cg*cwx2*(ca+cd*cnu[ic]*cgam[ic-1]))/cdd;
    ru(ic,1,2)= 2.*cwx*cgam[ic]*
                (ca*cc+cb*cd*cnu[ic-1]*cgam[ic-1])/cdd;
    ru(ic,2,2)= (ce*(cb*cgam[ic-1]-cc*cgam[ic])+
                ch*cwx2*(ca+cd*cnu[ic-1]*cgam[ic]))/cdd*aki;
    ru(ic,2,1)= 2.*cwx*cnu[ic]*
                (ca*cc+cb*cd*cnu[ic-1]*cgam[ic-1])/cdd*aki;
    tu(ic,1,1)= 2.*_model->rho(ic)*cnu[ic]*cf/cdd;
    tu(ic,1,2)= 2.*_model->rho(ic)*cgam[ic]*ch*cwx/cdd;
    tu(ic,2,2)= 2.*_model->rho(ic)*cgam[ic]*ce/cdd;
    tu(ic,2,1)=-2.*_model->rho(ic)*cnu[ic]*cg*cwx/cdd;

    me1[ic-1]=exp(-ai*cnu[ic-1]*_model->h(ic-1));
    me2[ic-1]=exp(-ai*cgam[ic-1]*_model->h(ic-1));

    Complex cs1=_model->rho(ic-1)/ckb2[ic-1]*cgam[ic-1];
    Complex cs2=_model->rho(ic)/ckb2[ic]*cgam[ic];
    Complex cdelt=cs1+cs2;

    rush[ic]=(cs2-cs1)/cdelt;
    rdsh[ic]=-rush[ic];
    tush[ic]=2.*cs2/cdelt;
    tdsh[ic]=2.*cs1/cdelt;
  }
}

/*!
*******************************************************************************
*                                                          AXITRA Version 1.0 *
*                         subroutine REFLECT2                                 *
*                                                                             *
*       Calcul des matrices de reflectivite mt,mb ou nt,nb dans chaque couche *
*         (rapport des potentiels montant/descendant ou descendant/montant)   *
*       Le suffixe t ou b precise si la matrice est donnee au sommet (top)    *
*       ou au bas (bottom) de la couche.                                      *
*       fup et fdo sont des matrices intermediaires utilisees dans le calcul  *
*       des potentiels.                                                       *
*       Ordre de stockage :                                                   *
*                    pp=(1,1)   sp=(1,2)                                      *
*                    ps=(2,1)   ss=(2,2)                                      *
*******************************************************************************
*/
void KennettSH::reflect2()
{
  // Calcul pour les couches au dessus de la source

  nt(0,1,1)=ru(0,1,1);
  nt(0,1,2)=ru(0,1,2);
  nt(0,2,1)=ru(0,2,1);
  nt(0,2,2)=ru(0,2,2);
  ntsh[0]=rush[0];

  int nc1=_layerCount-1;
  for(int ic=0; ic<nc1; ic++) {
    Complex nb11=me1[ic]*me1[ic]*nt(ic,1,1);
    Complex nb12=me1[ic]*me2[ic]*nt(ic,1,2);
    Complex nb21=me2[ic]*me1[ic]*nt(ic,2,1);
    Complex nb22=me2[ic]*me2[ic]*nt(ic,2,2);
    Complex nbsh=me2[ic]*me2[ic]*ntsh[ic];

    Complex ca1=1.-(rd(ic+1,1,1)*nb11+rd(ic+1,1,2)*nb21);
    Complex ca2=-(rd(ic+1,1,1)*nb12+rd(ic+1,1,2)*nb22);
    Complex ca3=-(rd(ic+1,2,1)*nb11+rd(ic+1,2,2)*nb21);
    Complex ca4=1.-(rd(ic+1,2,1)*nb12+rd(ic+1,2,2)*nb22);
    Complex cadet=ca1*ca4-ca2*ca3;
    Complex cash=1./(1.-rdsh[ic+1]*nbsh);

    Complex cb1=td(ic+1,1,1)*nb11+td(ic+1,1,2)*nb21;
    Complex cb2=td(ic+1,1,1)*nb12+td(ic+1,1,2)*nb22;
    Complex cb3=td(ic+1,2,1)*nb11+td(ic+1,2,2)*nb21;
    Complex cb4=td(ic+1,2,1)*nb12+td(ic+1,2,2)*nb22;
    Complex cbsh=tdsh[ic+1]*nbsh;

    Complex cc1=(ca4*tu(ic+1,1,1)-ca2*tu(ic+1,2,1))/cadet;
    Complex cc2=(ca4*tu(ic+1,1,2)-ca2*tu(ic+1,2,2))/cadet;
    Complex cc3=(-ca3*tu(ic+1,1,1)+ca1*tu(ic+1,2,1))/cadet;
    Complex cc4=(-ca3*tu(ic+1,1,2)+ca1*tu(ic+1,2,2))/cadet;
    Complex ccsh=cash*tush[ic+1];

    nt(ic+1,1,1)=ru(ic+1,1,1)+cb1*cc1+cb2*cc3;
    nt(ic+1,1,2)=ru(ic+1,1,2)+cb1*cc2+cb2*cc4;
    nt(ic+1,2,1)=ru(ic+1,2,1)+cb3*cc1+cb4*cc3;
    nt(ic+1,2,2)=ru(ic+1,2,2)+cb3*cc2+cb4*cc4;
    ntsh[ic+1]=rush[ic+1]+cbsh*ccsh;

    fup(ic,1,1)=cc1*me1[ic];
    fup(ic,1,2)=cc2*me1[ic];
    fup(ic,2,1)=cc3*me2[ic];
    fup(ic,2,2)=cc4*me2[ic];
    fupsh[ic]=ccsh*me2[ic];
  }
  // Calcul pour les couches au dessous de la source

  mt(_layerCount-1,1,1)=0.;
  mt(_layerCount-1,1,2)=0.;
  mt(_layerCount-1,2,1)=0.;
  mt(_layerCount-1,2,2)=0.;
  mtsh[_layerCount-1]=0.;

  for(int ic=_layerCount-2; ic>=0; ic--) {
    Complex ca1=1.-(ru(ic+1,1,1)*mt(ic+1,1,1)+ru(ic+1,1,2)*mt(ic+1,2,1));
    Complex ca2=-(ru(ic+1,1,1)*mt(ic+1,1,2)+ru(ic+1,1,2)*mt(ic+1,2,2));
    Complex ca3=-(ru(ic+1,2,1)*mt(ic+1,1,1)+ru(ic+1,2,2)*mt(ic+1,2,1));
    Complex ca4=1.-(ru(ic+1,2,1)*mt(ic+1,1,2)+ru(ic+1,2,2)*mt(ic+1,2,2));
    Complex cadet=ca1*ca4-ca2*ca3;
    Complex cash=1./(1.-rush[ic+1]*mtsh[ic+1]);

    Complex cb1=tu(ic+1,1,1)*mt(ic+1,1,1)+tu(ic+1,1,2)*mt(ic+1,2,1);
    Complex cb2=tu(ic+1,1,1)*mt(ic+1,1,2)+tu(ic+1,1,2)*mt(ic+1,2,2);
    Complex cb3=tu(ic+1,2,1)*mt(ic+1,1,1)+tu(ic+1,2,2)*mt(ic+1,2,1);
    Complex cb4=tu(ic+1,2,1)*mt(ic+1,1,2)+tu(ic+1,2,2)*mt(ic+1,2,2);
    Complex cbsh=tush[ic+1]*mtsh[ic+1];

    Complex cc1=(ca4*td(ic+1,1,1)-ca2*td(ic+1,2,1))/cadet;
    Complex cc2=(ca4*td(ic+1,1,2)-ca2*td(ic+1,2,2))/cadet;
    Complex cc3=(-ca3*td(ic+1,1,1)+ca1*td(ic+1,2,1))/cadet;
    Complex cc4=(-ca3*td(ic+1,1,2)+ca1*td(ic+1,2,2))/cadet;
    Complex ccsh=cash*tdsh[ic+1];

    Complex mb11=rd(ic+1,1,1)+cb1*cc1+cb2*cc3;
    Complex mb12=rd(ic+1,1,2)+cb1*cc2+cb2*cc4;
    Complex mb21=rd(ic+1,2,1)+cb3*cc1+cb4*cc3;
    Complex mb22=rd(ic+1,2,2)+cb3*cc2+cb4*cc4;
    Complex mbsh=rdsh[ic+1]+cbsh*ccsh;

    mt(ic,1,1)=me1[ic]*me1[ic]*mb11;
    mt(ic,1,2)=me1[ic]*me2[ic]*mb12;
    mt(ic,2,1)=me2[ic]*me1[ic]*mb21;
    mt(ic,2,2)=me2[ic]*me2[ic]*mb22;
    mtsh[ic]=me2[ic]*me2[ic]*mbsh;

    fdo(ic+1,1,1)=cc1*me1[ic];
    fdo(ic+1,1,2)=cc2*me2[ic];
    fdo(ic+1,2,1)=cc3*me1[ic];
    fdo(ic+1,2,2)=cc4*me2[ic];
    fdosh[ic+1]=ccsh*me2[ic];
  }
}

/*!
              Calcul des potentiels des ondes P et S, montantes et
              descendantes, dans chaque couche, pour
                - une onde P montante (jcas=0) dans la couche ln
                - une onde S montante (jcas=0) dans la couche ln

                - une onde P descendante (jcas=1) dans la couche ln
                - une onde S descendante (jcas=1) dans la couche ln


  Matrices de passage des vecteurs potentiels dans la
  couche source aux vecteurs potentiel dans chaque couche

                    [ftup] et [ftdo]

               ------------------------

  Les vecteurs potentiels pu() et pd() sont obtenus a
  partir des vecteurs potentiels su() et sd() dans la
  couche origine par:

  Couche (n) au dessus de la couche source (jcas=0):

   pu(n)=[fup(n)]*[fup(n+1)]* *[fup(_layerCount-1] . su

   d'ou l'on tire pd(n) par  pd(n)=[nt(n)] . pu(n)

  Couche (m) au dessous de la couche source (jcas=1):

   pd(m)=[fdo(m)]*[fdo(m-1)]* *[fdo(2)] . sd

   d'ou l'on tire pu(m) par  pu(m)=[mt(m)] . pd(m)

                -------------------------
   On pose :

        [ftup(n)]=[fup(n)]*...*[fup(isc-1)]*[tud]

        [ftdo(m)]=[fdo(m)]*...*[fdo(isc+1)]*[tdu]

*/
void KennettSH::reflect4(int jcas)
{
  uint n=_layerCount;

  if(jcas!=1) {
    // Cas jcas=0: reflexions surface libre
    _ftup=new Complex[n*4];
    Complex * ftupsh=new Complex[n];

    ftup(_layerCount-1,1,1)=1.;
    ftup(_layerCount-1,1,2)=0.;
    ftup(_layerCount-1,2,1)=0.;
    ftup(_layerCount-1,2,2)=1.;
    ftupsh[_layerCount-1]=1.;

    for(int ic=_layerCount-2; ic>=0; ic--) {
      ftup(ic,1,1)=fup(ic,1,1)*ftup(ic+1,1,1)+fup(ic,1,2)*ftup(ic+1,2,1);
      ftup(ic,1,2)=fup(ic,1,1)*ftup(ic+1,1,2)+fup(ic,1,2)*ftup(ic+1,2,2);
      ftup(ic,2,1)=fup(ic,2,1)*ftup(ic+1,1,1)+fup(ic,2,2)*ftup(ic+1,2,1);
      ftup(ic,2,2)=fup(ic,2,1)*ftup(ic+1,1,2)+fup(ic,2,2)*ftup(ic+1,2,2);
      ftupsh[ic]=fupsh[ic]*ftupsh[ic+1];
    }
    // Vecteurs potentiel montant (pu) et descendant (pd),
    // dans chaque couche recepteur, pour les 6 sources elementaires

    //           Recepteurs au dessus de la source
    for(int ic=0; ic<_layerCount; ic++) {
      int ic1=4*ic;
      int ic2=ic1+1;
      int ic3=ic2+1;
      int ic4=ic3+1;
      Complex pu11=ftup(ic,1,1);
      Complex pu21=ftup(ic,2,1);
      Complex pd11=nt(ic,1,1)*pu11+nt(ic,1,2)*pu21;
      Complex pd21=nt(ic,2,1)*pu11+nt(ic,2,2)*pu21;
      cfwave(ic1,1)=pu11;
      cfwave(ic2,1)=pd11;
      cfwave(ic3,1)=pu21;
      cfwave(ic4,1)=pd21;

      Complex pu12=ftup(ic,1,2);
      Complex pu22=ftup(ic,2,2);
      Complex pd12=nt(ic,1,1)*pu12+nt(ic,1,2)*pu22;
      Complex pd22=nt(ic,2,1)*pu12+nt(ic,2,2)*pu22;
      cfwave(ic1,2)=pu12;
      cfwave(ic2,2)=pd12;
      cfwave(ic3,2)=pu22;
      cfwave(ic4,2)=pd22;

      int icsh1=2*ic;
      int icsh2=icsh1+1;
      Complex push=ftupsh[ic];
      Complex pdsh=ntsh[ic]*push;
      cfwave(icsh1,3)=push;
      cfwave(icsh2,3)=pdsh;
    }
    delete [] _ftup;
    delete [] ftupsh;
  } else {
    // Cas jcas=1 : pas d'onde montante incidente
    _ftdo=new Complex[n*4];
    Complex * ftdosh=new Complex[n];

    ftdo(0,1,1)=1.;
    ftdo(0,1,2)=0.;
    ftdo(0,2,1)=0.;
    ftdo(0,2,2)=1.;
    ftdosh[0]=1.;

    for(int ic=1; ic<_layerCount; ic++) {
      ftdo(ic,1,1)=fdo(ic,1,1)*ftdo(ic-1,1,1)+fdo(ic,1,2)*ftdo(ic-1,2,1);
      ftdo(ic,1,2)=fdo(ic,1,1)*ftdo(ic-1,1,2)+fdo(ic,1,2)*ftdo(ic-1,2,2);
      ftdo(ic,2,1)=fdo(ic,2,1)*ftdo(ic-1,1,1)+fdo(ic,2,2)*ftdo(ic-1,2,1);
      ftdo(ic,2,2)=fdo(ic,2,1)*ftdo(ic-1,1,2)+fdo(ic,2,2)*ftdo(ic-1,2,2);
      ftdosh[ic]=fdosh[ic]*ftdosh[ic-1];
    }

    for(int ic=0; ic<_layerCount; ic++) {
      int ic1=4*ic;
      int ic2=ic1+1;
      int ic3=ic2+1;
      int ic4=ic3+1;
      Complex pd11=ftdo(ic,1,1);
      Complex pd21=ftdo(ic,2,1);
      Complex pu11=mt(ic,1,1)*pd11+mt(ic,1,2)*pd21;
      Complex pu21=mt(ic,2,1)*pd11+mt(ic,2,2)*pd21;
      cfwave(ic1,1)=pu11;
      cfwave(ic2,1)=pd11;
      cfwave(ic3,1)=pu21;
      cfwave(ic4,1)=pd21;

      Complex pd12=ftdo(ic,1,2);
      Complex pd22=ftdo(ic,2,2);
      Complex pu12=mt(ic,1,1)*pd12+mt(ic,1,2)*pd22;
      Complex pu22=mt(ic,2,1)*pd12+mt(ic,2,2)*pd22;
      cfwave(ic1,2)=pu12;
      cfwave(ic2,2)=pd12;
      cfwave(ic3,2)=pu22;
      cfwave(ic4,2)=pd22;

      int icsh1=2*ic;
      int icsh2=icsh1+1;
      Complex pdsh=ftdosh[ic];
      Complex push=mtsh[ic]*pdsh;
      cfwave(icsh1,3)=push;
      cfwave(icsh2,3)=pdsh;
    }
    delete [] _ftdo;
    delete [] ftdosh;
  }
}
