Calculate Love and Rayleigh dispersion curves. More...
#include <Dispersion.h>
Public Member Functions | |
| bool | calculate (Rayleigh *waveModel, Ellipticity *ell=0, QAtomicInt *terminated=0) |
| bool | calculate (Love *waveModel, QAtomicInt *terminated=0) |
| QGPCOREWAVE_EXPORT ModalStorage * | deltaK () 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) |
Calculate Love and Rayleigh dispersion curves.
The main function used to calculate the dispersion curve is calculate().
| QGpCoreWave::Dispersion::Dispersion | ( | int | nModes, |
| const QVector< double > * | x | ||
| ) |
References TRACE.
: ModalStorage(nModes, x) { TRACE; _precision=1e-7; // Default precision without ellipticity }
| bool QGpCoreWave::Dispersion::calculate | ( | Rayleigh * | waveModel, |
| Ellipticity * | ell = 0, |
||
| QAtomicInt * | terminated = 0 |
||
| ) | [inline] |
Referenced by QGpCoreWave::DispersionFactory::calculate(), dispersion_curve_love_(), dispersion_curve_rayleigh_(), EllipticityReader::parse(), and DispersionReader::parse().
{
return calculate<double, Rayleigh>(waveModel, ell, terminated);
}
| bool QGpCoreWave::Dispersion::calculate | ( | Love * | waveModel, |
| QAtomicInt * | terminated = 0 |
||
| ) | [inline] |
{
return calculate<double, Love>(waveModel, 0, terminated);
}
| ModalStorage * QGpCoreWave::Dispersion::deltaK | ( | ) | const |
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;}