Seismic
Seis is an object that is composed of several datasets and groups:
traces are separated from trace headers.
Trace headers are kept on double
format while trace data is float
.
Seis is designed to provide high perfomance while keeping simple API.
Create Seis
Seismic parameters includes: survey type (2D or 3D), data type (stack or prestack), number of traces, number of samples etc:
#include <iostream>
#include <h5geo/h5seiscontainer.h>
#include <h5geo/h5seis.h>
#include <h5geo/h5horizon.h>
int main(){
std::string fileName = "seis.h5";
H5SeisCnt_ptr cnt(h5geo::createSeisContainerByName(
fileName, h5geo::CreationType::OPEN_OR_CREATE));
if (!cnt){
std::cout << "Unable to open or create seis container" << std::endl;
return -1;
}
H5SeisParam p;
p.domain = h5geo::Domain::OWT;
p.lengthUnits = "millimeter";
p.temporalUnits = "millisecond";
p.angularUnits = "degree";
p.dataUnits = "psi";
p.dataType = h5geo::SeisDataType::PRESTACK;
p.surveyType = h5geo::SurveyType::TWO_D;
p.nTrc = 30;
p.nSamp = 10;
p.srd = 20;
p.spatialReference = "EPSG:8139";
std::string seisName = "mySeis";
H5Seis_ptr seis(cnt->createSeis(
seisName, p, h5geo::CreationType::OPEN_OR_CREATE));
if (!seis){
std::cout << "Unable to open or create seis" << std::endl;
return -1;
}
return 0;
}
Write/Read data
By analogy with SEGY
format H5Seis
contains:
text header, binary header, traces headers, trace data.
Write/Read text header
std::vector<std::string> txtHdr;
for (size_t i = 0; i < 40; i++)
txtHdr.push_back("Bart Simpson");
if (!seis->writeTextHeader(txtHdr)){
std::cout << "Unable to write text header" << std::endl;
return -1;
}
// another way is to write C-array: 'char txtHdr_c [40][80];'
Note
Text header is a dataset of size [40, 80]
.
Thus everything outside of this range will be lost.
To read text header:
std::vector<std::string> txtHdr_out =
seis->getTextHeader();
if (txtHdr_out.size() < 1){
std::cout << "Unable to read text header" << std::endl;
return -1;
}
Write/Read binary header
The simplest way to write binary header is:
// convert 'seconds' to the temporal units of seis object
if (!seis->writeBinHeader("SAMP_RATE", 0.002, "sec", seis->getTemporalUnits())){
std::cout << "Unable to write samp rate" << std::endl;
return -1;
}
and to get it back:
double sampRate = seis->getBinHeader("SAMP_RATE", seis->getTemporalUnits(), "ms");
if (isnan(sampRate))
std::cout << "Unable to get samp rate" << std::endl;
return -1;
}
Note
List of binary header names is available through getBinHeaderNames
function declared in h5core_util.h.
Header names are consistent to those used in SEGY
viewer SeiSee
Write/Read trace headers
There are many functions to do this. Here is one of them:
Eigen::MatrixXd cdp(3);
cdp << 1, 2, 3;
// write starting from 5th trace
if (!seis->writeTraceHeader("CDP", cdp, 5)){
std::cout << "Unable to write CDP trace header from 5th trace" << std::endl;
return -1;
}
and to get it back:
// get 'cdp' trace header from 3 traces starting from 5th trace
Eigen::MatrixXd cdp_out = seis->getTraceHeader("CDP", 5, 3);
if (cdp_out.size() < 1){
std::cout << "Unable to get CDP trace header">> std::endl;
return -1;
}
// update trace header limits is needed when trace headers are written
if (!seis->updateTraceHeaderLimits()){
std::cout << "Unable to update trace header limits" << std::endl;
return -1;
}
Note
List of trace header names is available through getTraceHeaderNames
function declared in h5core_util.h.
Header names are consistent to those used in SEGY
viewer SeiSee
Warning
Call updateTraceHeaderLimits
everytime when trace header min/max
values changed.
Write/Read trace data
Once again there are many functions to do this, here are some:
Eigen::MatrixXd traces(p.nSamp, 3);
Eigen::MatrixXf traces = Eigen::MatrixXf::Random(
seis->getNSamp(), seis->getNTrc());
// write starting from zero's trace
if (!seis->writeTrace(traces, 0)){
std::cout << "Unable to write traces" << std::endl;
return -1;
}
Get traces back:
// from 3rd trace, 10 traces, from 2nd sample, 5 samples
traces_out = seis->getTrace(3, 10, 2, 5);
if (traces_out.size() < 1){
std::cout << "Unable to get traces">> std::endl;
return -1;
}
Note
write/get
trace headers and trace data have pretty wide opportunities
including trace selection and working with sorted data.
Take a look at seis.h
to see all them.
Sorting
The idea behind sorting is to prepare sorting by primary keys (PKey).
To accelerate the IO process the user need to add PKey sorting first
addPKeySort
and then use getSortedData
function to retrieve
the data.
No need to manually resort data, h5geo only keeps indexes
and unique values of prepared sortings.
In theory this should make work with big data pretty effective.
For example there is widely used sorting CDP-OFFSET
(OFFSET
is called DSREG
in h5geo).
Add Pkey CDP
and then you are free to retrieve any CDP-...
sorted data.
if (!seis->addPKeySort("CDP")){
std::cout << "Unable to add CDP PKey" << std::endl;
return -1;
}
// then you are allowed to use convenient 'getSortedData' function
Eigen::MatrixXf trace_out;
Eigen::MatrixXd trc_header_out;
// from CDP 1 to 2, from DSREG 0 to 500
// 'trc_ind' - contains indexes of selected traces
Eigen::VectorX<size_t> trc_ind = seis->getSortedData(
trace_out, trc_header_out, {"CDP", "DSREG"}, {1, 0}, {2, 500});
Note
Use updatePKeySort
when data was mixed.
Sorting uses parallelization over the threads.
Warning
Sorting idea is effetive only if the chosen PKey has many repeating values.
Calculating XY boundary around the survey
There is a convenient function to calculate XY boundary around survey.
For 3D and 2D prestack data it uses convex hull algorithm.
For 2D stack data it simply shows CDP
coordinates of traces.
if (!seis->updateBoundary()){
std::cout << "Unable to update boundary" << std::endl;
return -1;
}
Eigen::MatrixXd boundary = seis->calcBoundary();
if (!boundary.size() < 1){
std::cout << "Unable to calculate boundary" << std::endl;
return -1;
}
std::string horizonName = "boundary";
H5HorizonParam p_hrz;
p_hrz.components["X"] = 0;
p_hrz.components["Y"] = 1;
p_hrz.nPoints = 10;
p_hrz.pointsChunkSize = 10;
p_hrz.domain = h5geo::Domain::TWT;
p_hrz.lengthUnits = p.lengthUnits;
p_hrz.spatialReference = p.spatialReference;
H5Horizon_ptr hrz(
seis->createHorizon(
horizonName, p_hrz, h5geo::CreationType::CREATE_OR_OVERWRITE));
ASSERT_TRUE(hrz != nullptr);
if (!hrz){
std::cout << "Unable to create horizon (boundary)" << std::endl;
return -1;
}
if (!hrz->writeComponent("X", boundary.col(0))){
std::cout << "Unable to write X to boundary" << std::endl;
return -1;
}
if (!hrz->writeComponent("Y", boundary.col(1))){
std::cout << "Unable to write Y to boundary" << std::endl;
return -1;
}
To get calculated values:
Eigen::VectorXd X = hrz->getComponent("X");
if (X.size() < 1){
std::cout << "Unable to get X from boundary" << std::endl;
return -1;
}
Eigen::VectorXd Y = hrz->getComponent("Y");
if (Y.size() < 1){
std::cout << "Unable to get Y from boundary" << std::endl;
return -1;
}
Read SEGY
Reading SEGY
is pretty simple:
if (!seis->readSEGYTextHeader("file.sgy")){
std::cout << "Unable to read segy text header" << std::endl;
return -1;
}
if (!seis->readSEGYBinHeader("file.sgy")){
std::cout << "Unable to read segy binary header" << std::endl;
return -1;
}
// SEGY files will be concatenated
if (!seis->readSEGYTraces({"file1.sgy", "file2.sgy", "file3.sgy"})){
std::cout << "Unable to read segy binary header" << std::endl;
return -1;
}
Note
To read SEGY
files h5geo uses memory-mapping technique and
parallelization over the threads (OpenMP library). Thus it should work
pretty fast but there is a limitation with memory-mapping:
the SEGY
files should be on the PC’s hard drive.
See more on wiki.
Map SEGY
The user may want not to spend time on reading SEGY
file but simply map it.
In h5geo you are allowed to do this at H5Seis
creation time:
H5SeisParam p_mapped = p;
p_mapped.mapSEGY = true;
p_mapped.segyFiles = {"file1.sgy", "file2.sgy", "file3.sgy"};
std::string mappedSeisName = "seisMapped";
H5Seis_ptr seisMapped(cnt->createSeis(
mappedSeisName, p_mapped, h5geo::CreationType::OPEN_OR_CREATE));
if (!seisMapped){
std::cout << "Unable to open or create mapped seis" << std::endl;
return -1;
}
Then you are free to use it as with regular seis object but with some limitations:
probably it is impossible to resize file
data loss when writing to trace headers and binary header (
double
is casted toint
andshort
)only
SEGY ieee-32
format are supported