All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines
Public Member Functions
QGpCoreWave::Dispersion Class Reference

Calculate Love and Rayleigh dispersion curves. More...

#include <Dispersion.h>

Inheritance diagram for QGpCoreWave::Dispersion:
QGpCoreWave::ModalStorage

List of all members.

Public Member Functions

bool calculate (Rayleigh *waveModel, Ellipticity *ell=0, QAtomicInt *terminated=0)
bool calculate (Love *waveModel, QAtomicInt *terminated=0)
QGPCOREWAVE_EXPORT ModalStoragedeltaK () const
QGPCOREWAVE_EXPORT Dispersion (int nModes, const QVector< double > *x)
QGPCOREWAVE_EXPORT bool refine (int modeIndex, int lastIndex, double omega, RootSolver< Rayleigh > &modelS, Ellipticity &ell)
QGPCOREWAVE_EXPORT void setGroupSlowness ()
void setPrecision (double p)

Detailed Description

Calculate Love and Rayleigh dispersion curves.

The main function used to calculate the dispersion curve is calculate().


Constructor & Destructor Documentation

QGpCoreWave::Dispersion::Dispersion ( int  nModes,
const QVector< double > *  x 
)

References TRACE.

  : ModalStorage(nModes, x)
{
  TRACE;
  _precision=1e-7; // Default precision without ellipticity
}

Member Function Documentation

bool QGpCoreWave::Dispersion::calculate ( Rayleigh waveModel,
Ellipticity ell = 0,
QAtomicInt *  terminated = 0 
) [inline]
bool QGpCoreWave::Dispersion::calculate ( Love waveModel,
QAtomicInt *  terminated = 0 
) [inline]
  {
    return calculate<double, Love>(waveModel, 0, terminated);
  }

Returns a new ModalStorage with wavenumber differences between modes

References QGpCoreWave::ModalStorage::ModalStorage(), QGpCoreWave::ModalStorage::mode(), QGpCoreWave::ModalStorage::modeCount(), QGpCoreTools::Value< numberType >::setValid(), QGpCoreTools::Value< numberType >::setValue(), TRACE, QGpCoreWave::ModalStorage::x(), and QGpCoreWave::ModalStorage::xCount().

Referenced by DispersionReader::parse().

{
  TRACE;
  ModalStorage * s=new ModalStorage(modeCount()-1, x());
  for(int im=modeCount()-1; im>0; im--) {
    const RealValue * m1=mode(im);
    const RealValue * m2=mode(im-1);
    RealValue * dk=s->mode(im-1);
    for(int is=xCount()-1; is>=0; is--) {
      if(m1[is].isValid() && m2[is].isValid()) {
        dk[is].setValue(x(is)*(m2[is].value()-m1[is].value()));
        dk[is].setValid(true);
      } else {
        dk[is].setValid(false);
      }
    }
  }
  return s;
}
bool QGpCoreWave::Dispersion::refine ( int  modeIndex,
int  lastIndex,
double  omega,
RootSolver< Rayleigh > &  solver,
Ellipticity ell 
)

Used by the ellipticity computation, it allows the refinement of the ellipticity peak. The method for dispersion computation is the same as calculate(). It is just a resume to a particular frequency sample. lastIndex is the x index of the fixed and already computed curve. It avoids searching in the x list every time this function is called. lastIndex must be less than xCount()-1.

References QGpCoreWave::Seismic1DModel::checkVelocityInversion(), QGpCoreWave::RayleighTemplate< RealType >::ellipticity(), QGpCoreTools::endl(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::inversePolarity(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::lower(), QGpCoreWave::Seismic1DModel::maxSlowR(), QGpCoreWave::Seismic1DModel::minSlowS(), QGpCoreWave::ModalStorage::mode(), modeIndex, QGpCoreWave::RayleighTemplate< RealType >::model(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::neville(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::precision(), QGpCoreWave::ModalStorage::refineAdd(), SAFE_UNINITIALIZED, QGpCoreTools::RootSolverTemplate< double, FunctionClass >::searchDown(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::searchStep(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::searchUp(), QGpCoreWave::RayleighTemplate< RealType >::setOmega(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::setPolarity(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::setPrecision(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::setRelativeStep(), QGpCoreWave::ModalRefine::setValid(), QGpCoreWave::ModalRefine::setValue(), QGpCoreTools::tr(), TRACE, QGpCoreTools::RootSolverTemplate< double, FunctionClass >::upper(), QGpCoreTools::Value< numberType >::value(), QGpCoreTools::RootSolverTemplate< double, FunctionClass >::values(), QGpCoreWave::ModalStorage::x(), QGpCoreWave::ModalStorage::xCount(), and QGpCoreWave::RayleighTemplate< RealType >::y().

{
  TRACE;
  ASSERT(lastIndex<xCount()-1);
  ModalRefine& dispRef=refineAdd(omega);
  ModalRefine& ellRef=ell.refineAdd(omega);
  RealValue * values=mode(0)+lastIndex;

  Rayleigh * waveModel=solver.values();
  const Seismic1DModel * model=waveModel->model();
  double minSlow=model->minSlowS();
  double maxSlow, curSlow, lastSupBound=model->maxSlowR(), newCurSlow;
  SAFE_UNINITIALIZED(curSlow,0);
  bool forbitVelocityInversion=model->checkVelocityInversion()==-1;
  // Initialize equation's polarity
  waveModel->setOmega(0.05); // the sign of polarity is the same at all frequencies
  solver.setPolarity(model->maxSlowR());

  for(int iMode=0; iMode <= modeIndex; iMode++ ) {
    solver.setPrecision(_precision);
    if(iMode==0) {
      maxSlow=model->maxSlowR();
    } else {
      maxSlow=curSlow;
      solver.inversePolarity();
    }
    while(true) {
      waveModel->setOmega(omega);
      //printf("\nFrequency=%.15lg Hz\n\n",0.5 * omega/M_PI);
      bool errorDetected=false;
      curSlow=values[iMode*xCount()+1].value();
      if( ! solver.searchDown(curSlow, minSlow, maxSlow) ) {
        if(iMode==0) {
          // for fundamental mode this condition can never occur unless a mode jumping occured
          App::stream() << tr( "** Warning ** : mode jumping for mode %1 (end), reducing "
                        "step ratio to %2" ).arg(iMode).arg(Number::toDouble(solver.searchStep() * 0.1) ) << endl;
          errorDetected=true;
        } else {
          dispRef.setValid(iMode, false);
          ellRef.setValid(iMode, false);
          curSlow=minSlow;
        }
      } else {
        solver.neville();
        newCurSlow=solver.lower();
        //printf("%lg %lg-->%lg %lg\n",minSlow, curSlow, newCurSlow, maxSlow);
        waveModel->y(0.5 * (solver.upper() + newCurSlow) );
        ellRef.setValue(iMode, waveModel->ellipticity());
        if(newCurSlow - curSlow > _precision) {
          if(forbitVelocityInversion) {
            errorDetected=true;
            App::stream() << tr( "** Warning ** : retrograde dispersion not allowed (mode %1), "
                          "reducing step ratio to %2" ).arg(iMode).arg(Number::toDouble(solver.searchStep() * 0.1) ) << endl;
          } else {
            // Inversions are allowed, check at last point that no mode exist at a higher slowness
            waveModel->setOmega(x( lastIndex) );
            solver.setRelativeStep(solver.searchStep() * 0.1);
            if(solver.searchUp(lastSupBound, maxSlow) ) {
              // recalculating curve because of mode jumping
              App::stream() << tr( "** Warning ** : mode jumping for mode %1 (middle), "
                            "reducing step ratio to %2" ).arg(iMode).arg(Number::toDouble(solver.searchStep() * 0.1) ) << endl;
              errorDetected=true;
            }
            solver.setRelativeStep(solver.searchStep() * 10.0);
          }
        }
        if(!errorDetected) {
          lastSupBound=solver.upper();
          curSlow=newCurSlow;
          dispRef.setValue(iMode, curSlow);
          // When calculating the dispersion curve, stepRatio is positive to search downwards
          // (From maxSlow towards minSlow)
          // Here we want to search carefully upwards: from curSlow to maxSlow
          // If at least one root is found, this proves that mode jumping occured
          if(curSlow > minSlow) {
            // The curSlow was calculated using _solve and _x2 is the value returned by
            // Solve (slightly greater than the true root).
            // Here we need the _x1 value, e.g. slightly less than the true root, in
            // order to be sure that the root eventually found will not be the same
            // as curSlow
            curSlow=solver.upper();
          }
          // Contrary to normal dispersion curve computation, here we know the next point on the curve
          // Hence, we simulate its computation and we must find the same number, if not mode jumping occured.
          waveModel->setOmega(x( lastIndex) );
          //printf("Check refine jumpig: frequency=%.15lg Hz\n",0.5 * x(lastIndex)/M_PI);
          double correctSlow=values[iMode*xCount()].value();
          bool ok;
          if(iMode==0) {
            ok=solver.searchDown(curSlow, minSlow, maxSlow);
          } else {
            double lastMaxSlow=values[(iMode-1)*xCount()].value();
            if(curSlow>lastMaxSlow) curSlow=lastMaxSlow;
            ok=solver.searchDown(curSlow, minSlow, lastMaxSlow);
          }
          if(ok) {
            solver.neville();
            newCurSlow=solver.lower();
          }
          //printf("%lg %lg-->%lg %lg=%lg %lg %lg\n",minSlow, curSlow, newCurSlow, lastMaxSlow, correctSlow, newCurSlow-correctSlow, _precision);
          if( !ok || fabs(newCurSlow-correctSlow)>_precision) {
            ok=true;
            App::stream() << tr( "** Warning ** : mode jumping for mode %1 (refine), reducing "
                          "step ratio to %2" ).arg(iMode).arg(Number::toDouble(solver.searchStep() * 0.1) ) << endl;
            errorDetected=true;
          }
        }
      }
      if(errorDetected) {
        // recalculating curve because of mode jumping
        if(solver.searchStep() < 1e-4) {
          App::stream() << tr( "** Warning ** : dispersion curve impossible to obtain "
                        "for mode %1" ).arg(iMode) << endl;
          return false;
        }
        solver.setPrecision(solver.precision() * 0.1);
        solver.setRelativeStep(solver.searchStep() * 0.1);
      } else break;
    }
  }
  return true;
}

Convert phase slownesses into group slownesses

References QGpCoreWave::ModalStorage::mode(), QGpCoreWave::ModalStorage::modeCount(), QGpCoreTools::Value< numberType >::setValid(), TRACE, QGpCoreTools::Value< numberType >::value(), QGpCoreWave::ModalStorage::x(), and QGpCoreWave::ModalStorage::xCount().

Referenced by QGpCoreWave::DispersionFactory::calculate(), dispersion_curve_love_(), dispersion_curve_rayleigh_(), and DispersionReader::parse().

{
  TRACE;
  int nx=xCount()-1;
  RealValue tmp[ xCount() ];
  for(int im=0;im<modeCount();im++) {
    RealValue * point=mode(im);
    for(int i=1;i<nx;i++) {
      if(point[i-1].isValid() && point[i].isValid() && point[i+1].isValid()) {
        double val=point[i].value();
        double  derslow=0.5*((val-point[i-1].value())/(x(i)-x(i-1))+
                            (point[i+1].value()-val)/(x(i+1)-x(i)));
        derslow*=x(i);
        tmp[ i ]=val+derslow;
      } else {
        tmp[ i ].setValid(false);
      }
    }
    point[0].setValid(false);
    for(int i=1;i<nx;i++) {
      point[i]=tmp[i];
    }
    point[nx].setValid(false);
  }
}
void QGpCoreWave::Dispersion::setPrecision ( double  p) [inline]

Set precision in slowness for dispersion computation. If you need more than 1e-16, you must use the big number version of calculate().

Referenced by EllipticityReader::parse().

{_precision=p;}

The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines