POSC Specifications
Version 2.2
Usage Guide
Seismic 2D Line Example

[Usage Guide Table of Contents]


1.1 Seismic 2D Line Example

This section deals with instantiating and using a 2d Seismic Line. It will begin with a simple post stack 2d line, in which it is desired to store locations and references to the data. The data will not be stored in the database itself, but will be referred to as being on a tape somewhere.

Further sections will build on this. One variation will be a crooked line. Another will store the seismic data. Another will add references to acquisition data. Another will add references to supplementary data such as observer's sheets, velocity functions, etc. Finally, references to output plots and seismic processing will be shown.

Although the discussion in this section is restricted to a 2d line, the extension to 3d is straightforward.

1.1.1 Assumptions

The examples will be given in Express-I as modified for POSC. All examples will be done for the logical data model. Among the modifications will be references to pre-existing data instances. These come in three forms: POSC reference entities and standard values, locally loaded reference entities and standard values, and pre-loaded data. A short-hand notation will be used as follows to indicate references to these values.

An example of a POSC reference entities is ref_existence_kind.name = 'actual'. Many entities have an attribute which must reference this value. This will be shown by the notation:

ref_existence_kind --> @PRV_actual;

This is to be read as the attribute, ref_existence_kind, is related to the POSC reference entity instance, ref_existence_kind.name = 'actual'. The "PRV" stands for POSC reference value, and refers to reference and standard instances which have their source attribute = 'POSC'. Where the selection is more complicated, the part in brackets [ ] will be more fully expanded to include the use of the DAE path expression. Other reference entity and standard instances will be treated similarly.

An example of a locally loaded reference entity is an instance of ref_naming_system that refers to your company's codes. The instance value might be 'MyCompany code', and would appear in your database as ref_naming_system.kind = 'MyCompany code'. The notation for this instance would be:

ref_naming_system --> @RV_MyCompany_code;

which differs from the previous example by having @RV rather than @PRV.

Note 1: Throughout this section, an assumption is that MyCompany is the name of your company. References to the source attribute of locally instantiated entities would be ref_source.name = 'MyCompany'

Finally, an example of pre-loaded data would be a list of company names. Assuming MyCompany deals with a bunch of service companies, there would be already loaded a list of these companies. Rather than instantiating these in this section, I will assume they are already loaded, and will refer to them with the notation:

business_associate --> @PL_Best_Seismic;

The interpretation is that there is a pre-loaded instance of business_associate with identifier = 'Best Seismic'.

1.1.2 Definition

A 2D seismic line is defined by its geometry. For post stack data, the geometry of the bin nodes can be parameterized naturally by a single index. The index is commonly called a CDP point or a CMP point, but will be referred to as a bin node in this section.

It should be noted that this definition of a seismic line does not consider the shooting geometry. For example, a binned line may be extracted from a 3D survey, and presented to the user as a single line. It should also be noted that Epicentre does not differentiate between a line, a set of lines, and a 3D survey. It handles them all the same. Thus, it is not useful to pedantically differentiate between them. Your intuitive notion of a seismic line will fit this example.

A seismic line is separated into two main parts. The first part is the geometry, and the information that is related to the geometry. The second is the seismic data. That is, the geometry of the seismic experiment can exist without any seismic traces. Likewise, seismic traces can exist without knowing anything about the geometry of the experiment. This separation will be carried in the examples in which the seismic line first will be stored in the database without storing any of the data.

1.1.3 Description of Example

For purposes of this section, an example data set will be "created." The example will contain many parameters, such as shot spacing, bin node spacing, nominal fold, etc. These parameters will be given parametric names and defined in a table. Thus, it will be easy to generalize the example to other seismic lines. Where the values are used in the Express-I, they will have 'PAR_' in front of them. The description follows:

Line RD-1-88 was shot by RunDown Geophysical in 1988 for MyCompany. It was collected in the state of Oklahoma. It consists of 463 shots at 55 foot shot spacing (96 shots per mile). There were 120 receivers, end on, also at 55 ft. spacing, leading to a stacked line of 1141 bin nodes at 27.5 ft. spacing, and a nominal fold of 60. The data was collected at a 2 ms sample interval, with 4 s of data recorded. The bin nodes are in a straight line. The first bin node on tape is at shot point 6, and the last is at station 577, which is beyond the last shot point. The lat/long of the first shot point is 33°32'16.22" N, 102°26'09.11" W, and the line extends due north.

The processing was done by Best Seismic, and was completed August 13, 1988. MyCompany received the field reels and the stack tape on August 15. The processed data is 4 s at a 4 ms sample interval.

Table 1-1 is the table of parameters.

Table 1-1: Parameter Table for Basic Line

Parameter Description

Parameter Label

Value and Unit

First station point latitude

SPFirstLat

33.537839 dega

First station point longitude

SPFirstLong

-102.43586 dega

First station point local location x value

SPFirstLocx

0. ft

First station point local location y value

SPFirstLocy

0. ft

First bin node local location x value

BinFirstLocx

0. ft

First bin node local location y value

BinFirstLocy

275 ft

Last bin node local location x value

BinLastLocx

0. ft

Last bin node local location y value

BinLastLocy

31350 ft

Source event count

SrcCount

463

Recording Channel count

ChnCount

120

Station spacing

StatSpac

55. ft

Number of stations

StatCount

583

Bin node spacing

BinNodeSpac

27.5 ft

Number of bin nodes

BinNodeCount

1411

Area where shot

LineArea

Oklahoma

Line shooting date

AcqStartDate

1988

Acquisition company

AcqCompany

RunDown Geophysical

End of processing - date received in house.

ProcEndDate

1988-08-15

Processing company

ProcCompany

Best Seismic

Acquisition sample interval

AcqSampInt

2 ms

Acquisition total time

AcqTotTime

4 s

Final sample interval

FinalSampInt

4 ms

Final total time

FinalTotTime

4 s

 Since it would be difficult to calculate the latitude and longitude of the various stations, a relative coordinate system was set up. The zero point is at the first shot point station, the x-axis is east, and the y-axis is north. Since this is "parallel" to the state plane coordinate system, we can use that, and redefine the origin.

 1.1.4 Epicentre Description

The main entity in seismic is the seismic_geometry_set. This is where the line will receive its identification. The dates will be carried in the seismic_acquisition_activity and seismic_processing_activity, and the companies doing these will be carried in a relationship to business_associate. Since an activity has a many-to-many relationship to business_associate, there is always an intermediate business_associate_activity_role that ties these together, and additionally gives a role relationship.

The binset information will be carried in a binset_grid, which consists of a grid_structured for which we can define information about the bin points. In this example, the only information we want to record is the relationship of the bin points and the seismic stations. This information is useful because many maps plot the "shot points," which means that it is necessary to tie a bin node index to a shot point name.

The industry has used the term "shot point" in a very ambiguous way. In some cases, it means a point where a shot occurred. In other cases, it is a location where a shot could have occurred. It may also be where receivers were located, but no shots were taken. It can mean a bin node location. To some, it's a location, to others it is a point without a location being necessary.

Epicentre attempts to sidestep the confusion by not using the term shot point. Instead, we define a source_event (the occurrence of a "shot") and its location. We also define a station, which is a point of interest. In the example, we have 463 source_events and 583 stations. The additional 120 stations are the positions that had receiver locations beyond the "shooting" stations.

1.1.5 Instantiate Line and Locations

----> Begin Example: 2D Seismic Line

2dline = SEISMIC_GEOMETRY_SET {
   identifier(M,K) --> 'RD-1-88';
   description --> 'North-south seismic line collected 
                   in Oklahoma in 1988.';
   ref_seismic_geometry(M) --> @PRV_2d_line;
   ref_survey_environment --> @PRV_land;
   seismic_station_uid --> @stationgrid;

(* Although it can be inferred that we will refer to these 
  stations by their uid numbers (i.e., 1, 2, 3, ..., 583),
  this is not part of the semantics. In order to semantically
  state this fact, we will instantiate a station_name array,
  which is array an of 583 string values: '1', '2', '3', ... '583' . *)

   station_name --> ELEMENT {
      snframe = PROPERTY_FRAME {
        detailed_type --> EGRID_1DNODE;
        descriptor --> ( @sndescr);
        leaf_frame --> ( @snvalues );
        grid_or_mesh --> @stationgrid; };
      sndescr = DESCRIPTOR {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_StatCount; };
      snvalues = LEAF_FRAME {
        ref_property_kind(M) --> @PRV_name;
(* ref_property_kind.ref_property_type[ref_descriptive_property].name = 'name' *)
        data_type --> DAE_C_CHAR;
        data_values(M) --> LIST('1', '2', '3', ... , '583' );};};
   binset_grid <-- SET( @binset );
   secondary_topological_object <-- SET( @inOkla );};

(* Now create a topological relationship to 'Oklahoma' to say that the 
  seismic_geometry_set is in Oklahoma. This requires creating a land
  area that represents Oklahoma, then saying that the line is inside it *)

landOkla = GENERAL_SURFACE_AREA {
   identifier(K) --> 'Oklahoma';
   earth_surface_feature(K) <-- ( @PRV_Oklahoma );
   primary_topological_relationship(M,K) <-- @inOkla;}; 
(* @PRV_Oklahoma refers to geopolitical_feature.name = 'Oklahoma' *)

inOkla = TOPOLOGICAL_RELATIONSHIP {
   ref_object_intersection(M,K) --> @PRV_inside;
   primary_topological_object(M,K) --> @landOkla; --general_surface_area
   secondary_topological_object(M,K) --> @2dline;}; 

(* Now define the first shotpoint, so it can be used as an origin *)

firstshot = OTHER_VERTEX{
   name(M,K) --> 'MD-1-88 First Station';
   pty_location_1d <-- ( @firstshotloc ); }; (* will have lat/long *)
Note: This is altered in version 2.2. A new entity, seismic_acquisition_vertex has been added to be used in place of the other_vertex entity. The instance should be as follows:
firstshot = SEISMIC_ACQUISITION_VERTEX{
   seismic_geometry_set --> @2dline;
   ref_seismic_acquisition_vertex --> @PRV_seismic_station;
   pty_location_1d <-- ( @firstshotloc ); };
It is recommended that releases 2.2 and above use this entity.

firstshotloc = PTY_LOCATION_2D {
   other_spatial_object --> @firstshot;
   data_value(M) --> LOCATION {
      coordinate_system(M) --> @PRV_NAD27;
      coordinates(M) --> LIST(PAR_SPFirstLat, PARSPFirstLong);
      ref_unit_of_measure(M) --> LIST(@PRV_dega, @PRV_dega);};};

(* To identify the stations as above, we need a grid for the station uids. *)

stationgridaxis = GENERAL_COORDINATE_SYSTEM_AXIS {
   ref_quantity_property(M,K) --> @PRV_seismic_station_uid'];};

stationgrid = GRID_1D_EQUAL {
   name(M,K) --> 'RD-1-88 station grid';
   origin(M) --> ANYQUANTITY {
      real_value --> 1.0;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_type --> @PRV_index; };
 (* ndt_any_quantity requires a ref_quantity_type, a value, and a unit *)
   step(M) --> ANYQUANTITY {
      real_value --> 1.0;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_type --> @PRV_index; };
   point_count(M) --> PAR_StatCount;
   connected(M) --> FALSE;
   coordinate_system_axis(M) --> @stationgridaxis;};

(* To create the binset, we need to create a grid. The binset will
  reference this grid. Information about the binset points (such as
  their locations) can then be instantiated as arrays using the grid. *)

binpointgridaxis = GENERAL_COORDINATE_SYSTEM_AXIS {
   ref_quantity_property(M,K) --> @PRV_bin_point_index;
   source -->RV_MyCompany; };

binpointgrid = GRID_1D_EQUAL {
   name(M,K) --> 'RD-1-88 bin point grid';
   origin(M) --> ANYQUANTITY {
      real_value --> 1.0;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_type --> @PRV_index; };
   step(M) --> ANYQUANTITY {
      real_value --> 1.0;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_type --> @PRV_index; };
   point_count(M) --> PAR_BinNodeCount;
   connected(M) --> FALSE;
   coordinate_system_axis(M) --> @binpointgridaxis; };

binset = BINSET_GRID {
   name(M,K) --> 'RD-1-88 main binset';
   ref_binset_geometry_class --> @PRV_regular;
   seismic_geometry_set(M,K) --> @2dline;
   grid_structured(M) --> @binpointgrid;
   pty_geometry_2d_edge <-- SET( @binlocs ); (* This will create
      an array of locations that will use the binpointgrid. This
      will give the ties between the bin point index and their location. *)
   bin_station --> ELEMENT {
      bsframe = property_frame {
        detailed_type --> EGRID_1DNODE;
        descriptor --> LIST( @bsdescr);
        leaf_frame --> SET( @bsvalues );
        grid_or_mesh --> @binpointgrid; };
      bsdescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_BinNodeCount; };
      bsvalues = leaf_frame {
        ref_property_kind(M) --> @PRV_seismic_station_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_type --> DAE_C_INT;
        data_values(M) --> LIST(6, 6, 7, 7, ..., 576, 576, 577); };};};

(* the values as given assigns to each bin node, the nearest station uid.
  Since every other bin node is between stations, I arbitrarily decided
  to assign the bin node to the previous station. So the instantiation
  is pairs of station uids, with one single at the far end. An alternative
  would be to assign the numbers 6, 7, ... 577 to every other point on the
  grid. Then the grid full array would be 6, NULL, 7, NULL, ...
  This way is not recommended. *)

binlocs = PTY_GEOMETRY_2D_EDGE {
   binset(K) --> @binset;
   data_value --> LINE_GRID {
      blocframe = GEOMETRY_FRAME {
        detailed_type --> FT_LINE;
        descriptor --> LIST( @blocdescr);
        leaf_frame --> SET( @bnorvalues, @beastvalues );
        grid_or_mesh --> @binpointgrid;
        coordinate_system --> @PRV_NAD27_/_Oklahoma_South;
        vertex --> @firstshot; };
      blocdescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_BinNodeCount; };
      bnorvalues = leaf_frame {
        data_type --> DAE_C_FLOAT;
        coordinate_system_axis --> @PRV_northing_in_ftUS;
(*coordinate_system_axis.ref_quantity_property.name = 'northing in ftUS'*)
        ref_unit_of_measure --> @PRV_ftUS;
        data_values(M) --> LIST( 0., 0., 0., ... 0., 0. );};
      beastvalues = leaf_frame {
        coordinate_system_axis --> @PRV_easting_in_ftUS;
        ref_unit_of_measure --> @PRV_ftUS;
(*coordinate_system_axis.ref_quantity_property.name = 'easting in ftUS'*)
        data_values(M) --> LIST( PAR_BinFirstLocy,
               PAR_BinFirstLocy + PAR_BinNodeSpac,
               PAR_BinFirstLocy + 2 * PAR_BinNodeSpac,
               PAR_BinFirstLocy + 3 * PAR_BinNodeSpac,
                       ...
               PAR_BinLastLocy );};};
(* the data_value attribute is an array of PAR_BinNodeCount pairs of
  location values. All share the same coordinate system and the same units pair *)
               };

----> Pause Example: 2D Line

1.1.6 Alternative Way to Store Locations

The above example stores locations of all the bin nodes by using a pty_geometry_2d_edge. There is an array of 1411 locations. But the pattern of locations is very regular. We can take advantage of this regularity. In fact, if we give the locations of the two end points (end bin nodes, that is), and the number of bin nodes there are, we can calculate all the intermediate points. See Section 1.2, Four Point Geometry Calculations for more details.

Part of this information is already known. The size of the grid is 1411 points. This tells us the number of bin nodes. Also, the ref_binset_geometry_class = 'regular' indicates that the line is straight, and the bin nodes are equally spaced.

All that is left is to give the two endpoints and their locations. This is done by forming an alternate binset - binset_grid_variant - which will only have two nodes. The two nodes will be labelled 1 and 1411. Each will have a location.

--> Modify example: Seismic 2d line

(* Unnecessary: binlocs = pty_geometry_2d_edge *)

binset = BINSET_GRID { (* continuation *)
   binset_grid_variant <-- SET( @altbinset );};

(* First build a grid with 2 points only. Labelled 1, and 1411 *)

smallgrid = GRID_1D_EQUAL {
  SUBOF (GRID_STRUCTURED);
   name(M,K) --> 'RD-1-88 first last grid';
   origin(M) --> ANYQUANTITY {
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_type --> @PRV_bin_point_index; };
   step(M) --> ANYQUANTITY {
      real_value --> 1410.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_type --> @PRV_bin_point_index; };
(* Note that this makes the second point value = 1 + 1410 = 1411 *)
   point_count(M) --> 2; (* only have 2 points here *)
   connected(M) --> 'False';
   coordinate_system_axis(M) --> @binpointgridaxis; };
(* from previous section *)

altbinset = BINSET_GRID_VARIANT {
   name(M,K) --> 'RD-1-88 first-last main binset';
   description --> 'Contains only the first and last bin nodes from the main binset';
   binset_grid(M,K) --> @binset; (* the "parent" binset *)
   ref_grid_variant --> @PRV_corners_only;
   grid_structure(M) --> @smallgrid;
   pty_geometry_2d_edge <-- SET( @firstlastloc );};

binlocs = PTY_GEOMETRY_2D_EDGE {
   binset --> @altbinset;
   data_value(M) --> LINE_GRID {
      blocframe = GEOMETRY_FRAME {
        detailed_type --> FT_LINE;
        descriptor --> LIST( @blocdescr);
        leaf_frame --> SET( @bnorvalues, @beastvalues );
        grid_or_mesh --> @binpointgrid;
        coordinate_system --> @PRV_NAD27_/_Oklahoma_South;
        vertex --> @firstshot;};
      blocdescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> 2; };
      bnorvalues = leaf_frame {
        property_axis --> @PRV_northing_in_ftUS;
        ref_unit_of_measure --> @PRV_ftUS;
        data_values(M) --> LIST(PAR_BinFirstLocx,PAR_BinLastLocx);};
      beastvalues = leaf_frame {
        property_axis --> @PRV_easting_in_ftUS;
        ref_unit_of_measure --> @PRV_ftUS;
        data_values --> LIST(PAR_BinFirstLocy, PAR_BinLastLocy);};
(* end of data value structure. Only two value pairs. *)
};};

----> End Modification: Seismic 2d Line

1.1.6.1 Variation: Line is not North-South

The example above had a north-south line. This allowed us to calculate locations relative to the starting point very easily. It also allowed us to use a pre-existing coordinate system that had axes that ran due east and due north. Since the line ran north, the "easting" coordinate value was unchanged for the whole line.

When the line does not follow one of these axes, there are two choices. One is to create a coordinate system in which the axis corresponds to the line, and later relate that coordinate system to a standard one. The second approach is to use the existing standard one (as was done in this section) and calculate the locations in this coordinate system. In doing this second approach, it is only necessary to calculate the "change in x" and "change in y" in moving from one station to the next. The example in this section had the change in x as 0., and the change in y the same as the distance between stations.

As an example (for the second case), consider that the line runs at an azimuth of 115 dega, which is a little south of east. The inter-bin node distance of 27.5 ft becomes a change in x of 27.5 * cos(-25°) = 24.9 ft, and a change in y of 27.5 * sin (-25°) = -11.6 ft. (The inter-station distance is twice the inter-bin node distance, so its changes would be 49.8 and -23.2 ft respectively). Note that the change in y is negative, which means that the next station will have a smaller y value than the previous station. You would expect this for a line that is running south easterly. Under this situation, the first shot point would still define the origin, and would be at (0., 0.). The first bin node (at station 6) would have a location (249, -116). The next bin node location would be (249+24.9, -116 -11.6) = (273.9, -127.6). (Of course, round-off error would change these values slightly as you go down the line). The final station 577 would have a location (28412.7, -13249.1).

There is no difficulty in instantiating this situation. The @binlocs would have a data_value array that would reflect the above location values, rather than the ones given in the example.

If it was later found that the locations are wrong (for example, resurveying showed the azimuth to be 112°), a new pty_geometry_2d_edge can be instantiated.

Of course, the "geometry", i.e., locations, could be given in the alternative way as shown earlier.

1.1.6.2 Variation: Crooked Line

A crooked line offers little change from the previous example. A usable coordinate system is a 1d coordinate system that can record "length along the line" beginning from the first station. The main difference is that there is no way to calculate the (easting, northing) (or (x,y)) coordinate from the length along the line value. This information must be given from an outside source.

The storage of the information is the same.

The other difference from the previous example(s) is that the line is no longer 'regular'. The value for ref_binset_geometry_class will be 'regular crooked line', which means that the bin nodes are regularly spaced along the line, but the locations must be given from outside information.

1.1.7 Additional and Optional Information

Many options for additional information will be given in later sections. Three will be given here.

1.1.7.1 Storing Summary Information

The first is the pty_seismic_geometry_summary, that is an attribute of seismic_geometry_set. It can be used to store a lot of summary information about the line. An example with some of the information is shown below. It should be remembered that this is a summary more of the acquisition information than of the binset.

--> Continue example: Seismic 2d Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   pty_seismic_geometry_summary <-- SET( @linesummary );};

linesummary = PTY_SEISMIC_GEOMETRY_SUMMARY {
   seismic_geometry_set(K) --> @2dline;
   receiver_line_count --> 1;
   receiver_point_nominal_spacing --> QUANTITY { -- ndt_length
      real_value --> 55.;
      ref_unit_of_measure --> @PRV_ft; };
   ref_spread --> @PRV_end_on;
   source_line_count --> 1;
   source_point_count --> 463;
   source_point_nominal_spacing --> QUANTITY { --ndt_length
      real_value --> 55.;
      ref_unit_of_measure --> @PRV_ft; };
   surface_length --> QUANTITY { -- ndt_length
      real_value --> 6.;
      ref_unit_of_measure --> @PRV_mi; }; };

----> Pause example: Seismic 2d line

1.1.7.2 Storing a Bounding Box

The second bit of information is the pty_bounding_rectangle, which is an attribute of both seismic_geometry_set and binset. This allows the user to create a rectangle on the earth, and to say that the line is within that rectangle. This facilitates searches based on locations. The bounding_rectangle is defined by its upper right corner and lower left corner, and allows the locations of these to be instantiated in any coordinate system. Generally, a geographic coordinate system (lat, long) is the coordinate system of choice.

----> Continue Example: 2d Seismic Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
  SUBOF (COMPOSITE_SPATIAL_OBJECT);
   pty_bounding_rectangle <-- SET ( @box );};

box = PTY_BOUNDING_RECTANGLE {
   composite_spatial_object(K) --> @2dline;
   lower_left_corner --> LOCATION {
      coordinate_system(M) --> @PRV_NAD27;
      ref_unit_of_measure(M) --> LIST(@PRV_dega, @PRV_dega);
      coordinates(M) --> LIST( PAR_SPFirstLat,
                               PAR_SPFirstLong-.0002 ); };
   upper_right_corner --> LOCATION {
      coordinate_system(M) --> @PRV_NAD27;
      ref_unit_of_measure(M) --> LIST(@PRV_dega, @PRV_dega);
      coordinates(M) --> LIST( PAR_SPFirstLat+ .10, 
                               PAR_SPFirstLong+.0002 ); };};

(* the small amount, .0002, added to and subtracted from the longitude
  value is there to give some width to the box. Actually, the line
  doesn't change its longitude, since it is due north (geographic).
  The .10 added to the latitude in the upper right corner reflects the
  fact that the line is just over 6 miles long. A degree of latitude is
  60 nautical miles, or about 69 statute miles. So 6 statute miles is
  about .086 of a degree. Adding a bit more gives an upper bound. *)

----> Pause Example: Seismic 2d Line 

1.1.7.3 Acquisition Activity - Who and When

The third extra piece of information is who did it and when. This will be the seismic_acquisition_activity. This, together with the business_associate and the intersection entity combining the two (business_associate_activity_role) can describe the activity of data acquisition to whatever level of detail is desired. In this example, we will state that the seismic_acquisition_activity was conducted at a certain time by a business_associate, acting in the role of "data acquisition." It will be assumed that the business_associate is pre-loaded.

----> Continue example: Seismic 2d Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_acquisition_activity <-- SET( @acquisition );};

acquisition = SEISMIC_ACQUISITION_ACTIVITY {
   name(K) --> 'RD-1-88 data acquisition';
   ref_existence_kind(M,K) --> @PRV_actual;
   start_time --> PAR_AcqStartDate;
   seismic_geometry_set(K) --> @2dline;
   business_associate_activity_role <-- SET( @acqrole ); };

acqrole = BUSINESS_ASSOCIATE_ACTIVITY_ROLE {
   activity(M,K) --> @acquisition;
   business_associate(M,K) --> @PL_RunDown_Geophysical; 
(* a reference to the entity that contains PAR_AcqCompany. Assumed to be preloaded. *)
   ref_business_associate_activity_role(K) --> @PRV_data_acquisition; };

----> Pause example: Seismic 2d Line

1.1.8 Referring to Data Stored Offline (such as SEG Y data)

Three cases of offline storage will be presented. The first is the auxiliary data, such as an observer's report. This will be stored as a hardcopy_document, and will be stored in some location that can be found.

The second will be the field reels. These will not require a seismic_data_set to be instantiated. In fact, it will be stored in the same general way as the observer's report. But there is a key difference. While the observer's report is a hardcopy rendering of the information, the field reels will be a digital format (such as SEG D or SEG Y) rendering on a storage medium (such as 9 track tapes or 8 mm tapes). I.e., there is a bit of extra information that is required for the electronic storage (both the format and the medium).

Finally, the stack reel will be stored. This will be done by instantiating a seismic_data_set so that we can identify the stored data to be "stacked," and give more information about the processing if desired. The seismic_offline_data, though, will be the same. There will be a seismic_processing_activity instantiated in order to indicate who did the processing and when.

----> Continue Example: Seismic 2d Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_offline_data <-- SET( @obsrep, @fieldreels, @stackreel );
   seismic_data_set <-- SET( @stackdata );
   seismic_processing_activity <-- SET( @processdata );};
 
binset = BINSET_GRID { (* continuation *)
   seismic_data_set <-- SET( @stackdata );
   seismic_processing_activity --> @processdata; }; 

(* asserts the activity that created the binset *)

stackdata = SEISMIC_DATA_SET {
   name(M,K) --> 'RD-1-88 final stack';
   seismic_geometry_set(M,K) --> @2dline;
   binset --> @binset;
   ref_processing_indicator --> LIST(@RV_deconvolution, @RV_filter, 
                               @RV_statics, @RV_NMO, @RV_stack );
(* This is a high-level description of the processing, which may be 
  adequate for most purposes. It is also possible to give a detailed 
  description. *)
   seismic_offline_data <-- SET( @stackreel );
   seismic_processing_activity --> @processdata; };
(* In order to say who did the processing and when, we will
   instantiate a seismic_processing_activity. Since many people
   can be involved in the processing activity (for example,
   the processing company, the in-house geophysicist who oversees
   the processing), there is another entity,
   the business_associate_activity_role, that tells who did it,
   and what his role was. Finally, there is the business_associate
   itself, which we will assume is preloaded *)

processdata = SEISMIC_PROCESSING_ACTIVITY {
   name(K) --> 'Basic processing'
   ref_existence_kind(M,K) --> @PRV_actual;
   cost --> MONEY {
      value --> 6000;
      ref_currency_unit --> @PRV_USD; };
   end_time --> PAR_ProcEndDate;
   seismic_geometry_set(K) --> @2dline;
   seismic_data_set <-- SET ( @stackdata );
   binset <-- SET( @binset )
   business_associate_activity_role <-- SET( @processor ); };

processor = BUSINESS_ASSOCIATE_ACTIVITY_ROLE {
   activity(M,K) --> @processdata;
   business_associate(M,K) --> @PL_Best_Seismic; 
(* a reference to the entity that contains PAR_ProcCompany.
   Assumed to be preloaded. *)
   business_associate_activity_role(K) --> @PRV_processor; };

(* Now we can get to the offline storage information. First the 
    observer's sheet *)

obsrep = SEISMIC_OFFLINE_DATA {
  SUBOF(DOCUMENT_SPECIFICATION);
   identifier(M,K) --> 'RD-1-88 Observers Report';
   seismic_geometry_set(K) --> @2dline;
   typical_document_specification --> @PRV_observers_report;};

(* Next the field reels *)

fieldreels = SEISMIC_OFFLINE_DATA {
  SUBOF(DOCUMENT_SPECIFICATION);
   identifier(M,K) --> 'RD-1-88 Field Reels';
   seismic_geometry_set(K) --> @2dline;
  typical_document_specification --> @PRV_field_data; };

(* Finally the stack data *)

stackreel = SEISMIC_OFFLINE_DATA {
  SUBOF(DOCUMENT_SPECIFICATION);
   identifier(M,K) --> 'RD-1-88 Final Stack';
   seismic_geometry_set(K) --> @2dline;
   typical_document_specification --> @PRV_processed_data;
   seismic_data_set(K) --> @stackdata; }; 

(* This is an additional attribute that the first two do not
  have, so that we have a little more information about what
  is on the reels. *)
(* The above three are subtypes of document_specification. That
  is, they specify the information that will be stored on the
  documents. Assume that the observer's report is stored on a
  paper copy, which is stored in a file cabinet. The paper copy
  itself is a document (subtype: hardcopy_document), and the file
  cabinet is a storage facility. The tapes will be dealt with later. *)

obssheets = HARDCOPY_DOCUMENT {
  SUBOF(DOCUMENT);
   identifier(K) --> 'RD-1-88 observers report, field copy';
(* allows for multiple copies to be made and stored. *)
   description --> 'The copy of the observers report for line
                 RD-1-88 as originally filled out by the crew chief.'
   ref_naming_system --> @RV_MyCompany_Filing;
   document_specification(M,K) --> @obsrep;
   inventory_object_storage <-- SET( @storeobssheet ); };

filecabinet = GENERAL_FACILITY {
   name(K) --> '1993 R-S'; -- identifier of a file cabinet 
   ref_existence_kind --> @PRV_actual;
   start_date --> PAR_ProcEndDate; 
(* The date the seismic was received. Also was the date we filed
   the data - although they may be different *)
   inventory_object_storage <-- SET( @storeobssheet ); };

(* The next entity ties the two instances above together. This resolves
  a many to many relationship. The reason for one many is that a file
  cabinet may store many different documents. The other many is that this
  is a transient association. While this is a single document, it may be
  moved. The second many allows the history of the moves to be recorded.
  For example, if it is moved to Judy Jones office (an interpreter), we
  would instantiate a second inventory_object_storage to indicate another
  storage location for the sheets. *)

storeobssheet = INVENTORY_OBJECT_STORAGE {
   start_time(K) --> PAR_ProcEndDate; 
(* There is also an end time if the document is moved. *)
   general_faciltiy(M,K) --> @filecabinet;
   inventory_object(M,K) --> @obssheets; };

(* The same system is used to store the data on tape. The difference
  being that the storage on tape is an electronic document rather than
  a hardcopy document. However, there is presently a problem with the
  implementation of this in Epicentre, and the exact method of instantiating
  is not given here. *)

----> Pause example: 2d Seismic Line

1.1.9 More Information about the Seismic Data

The final stack data as given above is stored on the stacked reels. It is possible to find out how many traces are stored through its relationship to the binset_grid (@binset). But there is no information stored about the length of the traces or the sample interval.

This information is captured in Epicentre in the grid which describes the data. The grid will be a part of the "geometry." In order to capture this information, we will form a grid (which will be grid_1d_equal, in this case), and relate this to the seismic_data_set through the pty_geometry.

It should be noted that there will be no values given in the pty_geometry that is instantiated. This is because the values are carried in the 1d equal instance. If the points are equally spaced, they can be given through the (origin, step, count) triple in the grid_1d_equal. If they are not equally spaced, they must be given explicitly in the pty_geometry instance.

----> Continue example: 2d Seismic Line

stackdata = SEISMIC_DATA_SET { (* continuation *)
   pty_geometry_2d_face <-- SET( @seisdatadescr );};

(* Add a time axis to the binpoint grid to form a new grid. Since this
  axis needs a datum defined, I will make a coordinate_system_axis, and
  have it reference a vertical datum that is 500 feet above sea level. *)

coordtimeaxis = VERTICAL_TIME_SYSTEM_AXIS {
  SUBOF (COORDINATE_SYSTEM_AXIS);
   ref_quantity_property(M,K) --> @PRV_seismic time_;
   vertical_datum --> @sealevelplus500; };

(* These next two set up a datum that is 500 feet above the
  geoid mean sea level *)

sealevelplus500 = LOCAL_VERTICAL_DATUM {
   identifier(M,K) --> '500 feet above sea level';
   terminate_offset <-- @offset500; };

offset500 = VERTICAL_DATUM_OFFSET {
   initial_datum(M,K) --> @PRV_Mean_Sea_Level; -- A standard geoid
   terminal_datum(M,K) --> @sealevelplus500;
   length_offset --> QUANTITY {
      real_value --> 500.;
      ref_unit_of_measure --> @PRV_ft; };};

(* Now form the time grid that points to this axis. It will get the
  properties of 'seismic time', and the datum of zero time represents
  500 feet above sea level from the axis *)

timegrid = GRID_1D_EQUAL {
   name(M,K) --> 'MD-1-88 time axis';
   origin(M) --> ANYQUANTITY {
      real_value --> 0.0;
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   step(M) --> ANYQUANTITY {
      real_value --> PARFinalSampInt;
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   point_count(M) --> 2001; (* derivable from PAR_FinalTotTime *)
   connected(M) --> False;
   coordinate_system_axis(M) --> @coordtimeaxis; };

(* combine this axis with the previously used binpointgrid *)

seisdatagrid = GRID_STRUCTURED {
   name(M,K) --> 'MD-1-88 seismic post stack data grid';
   grid_structured(M) --> LIST(@binpointgrid, @timegrid ); };

(* sets up I = bin point axis, J = time axis *)
(* A geometry frame (below) refers to a coordinate system.
  In this case, it is the (time, bin point) coordinate system.
  The axes have been formed in sections 3.2 and this section,
  but they have never been put together into a coordinate system.
  Now we are required to do so *)

timebincoordsys = LOCAL_SPATIAL_COORDINATE_SYSTEM {
   identifier(M,K) --> 'MD-1-88 time, bin coordinate system';
   coordinate_system_axis(M) --> LIST( @binpointgridaxis, @coordtimeaxis );
   ref_coordinate_system_constraint(M) --> @PRV_geometry_2d; };

(* Now can give the pty_geometry that describes the data *)

seisdatadescr = PTY_GEOMETRY_2D_FACE {
   seismic_data_set(K) --> @stackdata;
   data_value(M) --> SURFACE_GRID {
      sdataframe = geometry_frame {
        detailed_type(M) --> FT_SURFACE;
        descriptor --> LIST(@numtraces, @numvalues);
        leaf_frame(M) --> SET(@traces_leaf, @values_leaf);
        grid_or_mesh --> @seisdatagrid;
        coordinate_system(M) --> @timebincoordsys;};
      numtraces = descriptor {
        dimension --> 'INDEX_I';
        lower_bound --> 1;
        count --> 1141; (* number of traces *)};
      numvalues = descriptor {
        dimension --> 'INDEX_J';
        lower_bound --> 1;
        count --> 1001; }; -- number of points per trace
      traces_leaf = leaf_frame {
(* by giving no values, Epicentre says to take the values from the
  definition of the equal axis grid. This grid labels the bin nodes
  as 1, 2, ..., 1141 *)
        property_axis --> @binpointgridaxis;
        ref_unit_of_measure --> @PRV_Euc;
        data_type --> DAE_C_INT; };
      values_leaf = leaf_frame {
(* by giving no values, Epicentre says to take the values from the
  definition of the equal axis grid. This grid defines
 (origin, step, count) = (0., 4 ms., 1001). *)
        property_axis --> @coordtimeaxis;
        ref_unit_of_measure --> @PRV_ms;
        data_type --> DAE_C_FLOAT; }; }; };

----> Pause Example: 2d Seismic Line

1.1.10 Variations on Data

The previous section had the data stored offline. The only knowledge the database has of the data is that it exists, it is of a certain "type" (processing state, etc.), and that it is located through the Epicentre inventory control.

But it is also possible to have the data "online." The database itself knows of the data, and can access it.

This can be done in two ways. The first, and obvious way, is to load the into frames, and store the frame data (using the attribute, data_value, in seismic_data_set). A second alternative is to leave the data in its own format, and, when forming the frame, tell the frame what method to use to access the data and what parameters are required for the method to know where the data is stored. This second way is intermediate, because the database sees the data_value attribute indicating that the data is there. But when it tries to get the data, it finds that it needs to do a little extra work to actually access it. This method (normally only invoked by specialized loaders) is very good for large amounts of legacy data, because you do not need to convert the data. Yet, to the user, if appears that the data is sitting there online.

Note that the previous section did the work of defining the grid - the pty_geometry that is needed. Having defined this, it is now straightforward to add the data_value attribute to seismic_data_set.

----> Modify Example: Seismic 2D Line

stackdata = SEISMIC_DATA_SET { (* continuation *)
   data_value --> ELEMENT {
      propframe = Property_frame {
        detailed_type --> 'EGRID_1DNODE';
        descriptor --> LIST(@binpoint_desc, @time_descr );
        leaf_frame --> SET(@tracevalues);
        grid_or_mesh --> @seisdatagrid; };
      time_descr = descriptor {
        dimension --> 'INDEX_J';
        lower_bound --> 1;
        count --> 2001; };
      binpoint_descr = descriptor {
        dimension --> 'INDEX_I';
        lower_bound --> 1;
        count --> PAR_BinNodeCount; };
      tracevalues = leaf_frame {
        ref_property_kind --> @PRV[ref_property_kind.
                               ref_quantity_property.name
                               = 'seismic amplitude' AND
                               ref_property_kind.
                               ref_kind_descriptor.name = 'P-wave'];
        ref_unit_of_measure --> @PRV_Euc;
        data_type(M) --. 'DAE_C_FLOAT';
        data_values(M) LIST(...here is an array of
                            2001 * 1141 floating point values ...);
      }; }; };

----> Pause Example: 2D Seismic Line

1.1.10.1 Alternative way to reference the data

The above example actually has data in the data_values attribute of the leaf_frame. The alternative way to reference the data is to store the data in a format invoked through a call to daeMethodChoice. The defined method may be something like 'SEGYWritingMethod', and would be able to run the appropriate read/write applications on the appropriate tape or file. However, none of the information in the above section would change under this scenario.

This is mentioned, because it might be useful to store the data in (for example) SEGY format. This would allow existing applications that expect SEGY data to use the data, while allowing direct access also through Epicentre.

 

1.1.10.2 Multiple Data Versions of the Same Line

The only data stored on the system so far has been the stacked line. However there is generally more data associated with a seismic line. The simplest extension would be other versions of the same data. For example, the migrated section. Epicentre will handle these cases very easily.

--> Modify example: 2d Seismic Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_data_set <-- SET( @stackdata, @migrateddata ); };

(* Note: added @migrateddata to the set *)

binset = BINSET_GRID { (* continuation *)
   seismic_data_set <-- SET( @stackdata, @migrateddata ); };

(* Note: added @migrateddata to the set *

migrateddata = SEISMIC_DATA_SET {
   name(M,K) --> 'RD-1-88 migrated data';
   seismic_geometry_set(M,K) --> @2dline;
   binset --> @binset;
   ref_processing_indicator --> LIST(@RV-_deconvolution, @RV_filter, 
                  @RV_statics, @RV_NMO, @RV_stack, @RV_igrated ); };

(* This is a high-level description of the processing, which may be
   adequate for most purposes. It is also possible to give a
   detailed description. *)
... 
(* At this point, it is possible to carry on as in the example of 
   section 1.1.9. There is no need in this example to repeat this portion. *)

----> Pause example: 2d Seismic Line

1.1.10.3 Velocity Function

The velocity function starts the same. If the function is kept on tape, there is no difference between section 1.1.8 with the modification as in section 1.1.10.2 (except, of course, there is a different data set.). But this example will show how to actually store the function.

The function will be stored using a grid_1d_parametric, and the previously developed bin point grid axis. The parametric axis does nothing more than to set up a grid to attach points to. The meaning of the points is given by the geometry and the values assigned to each point.

Table 1-2 defines the velocity function that will be stored. It is up to five time-velocity pairs at four bin node positions.

Table 1-2: Bin point indexes

bin point index

101

147

195

245

5600, 1040

6000, 1500

5400, 900

5500, 1000

6430, 2250

9000, 5000

6000, 1800

7000, 3100

7590, 3700

 

7250, 3275

8750, 4700

8500, 4500

 

8000, 4150

 

 

 

9000, 5100

 

 The velocity function is stored as is generated as is the seismic trace data -- with an important distinction. The time axis is part of the "geometry," since it is part of the independent variable. (I.e., we are saying that velocity is a function of (bin point index, time)). With seismic data, the geometry of the time variable is expressed as part of the grid_1d_equal creation. I.e., the grid_1d_equal allows us to define the "time" meaning of the grid index, by using the origin, step, and point_count attributes. With the velocity function, since the times are not equally spaced, we cannot do that. So we must form a grid_1d_parametric, and explicitly give the "time" values of every point we use. This is done using the pty_geometry_2d_face. Actually, we need to give both the (bin point index, time) pairs for every point, but we use the bin point index defined by its grid_1d_equal to supply these points by implication.

--> Modify example: 2d Seismic Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_data_set <-- SET( @stackdata, @migrateddata, @velocityfcn ); };

(* Note: I added the @velocityfcn to the set *)

binset = BINSET_GRID { (* continuation *)
   seismic_data_set <-- SET( @stackdata, @migrateddata, @velocityfcn ); };

(* Note: I added the @velocityfcn to the set *)
(* Need to develop a grid to attach the velocity function to. There is
    already a bin point grid. Need to create a time grid, and group the
    two together. In the actual storage in this example, a sparse is used,
    which makes the storage order irrelevant.*)

parmtimegrid = GRID_1D_PARAMETRIC {
   name(M,K) --> '100 point grid';
   point_count(M) --> 100;
   connected(M) --> False;
   grid_defined_grid <-- SET(@vtbingrid); };

vtbingrid = GRID_DEFINED_GRID {
   name(M,K) --> 'time, binpoint grid';
   grid_structured(M) --> LIST( @parmtimegrid, @binpointgrid ); };

(* The grid is ready. Instantiate a new seismic data set which will be
   the velocity function. *)

velocityfcn = SEISMIC_DATA_SET {
   name(M,K) --> 'RD-1-88 stacking velocity function';
   seismic_geometry_set(M,K) --> @2dline;
   binset --> @binset;
   pty_geometry_2d_face <-- SET(@stackingtime );
(* the pty_geometry_2d_face will define the "independent variables, which
   is the time and bin point index. Since it is a pty, it is a separate entity. *)
(* the velocity information will be given in the data_value attribute *)
   data_value --> ELEMENT {
      frame = property_frame {
        detailed_type(M) --> 'SGRID_2DNODE';
        descriptor(M) --> LIST(@sparse_desc );
        leaf_frame(M) --> SET(@indexbin, @indextime, @velleaf );
        grid_or_mesh --> @vtbingrid; };
      sparse_desc = descriptor {
        dimension(M) --> 'INDEX_UNDEFINED';
        count(M) --> 14; };
      indexbin = leaf_frame {
(* This will define the J (bin index) value of each sparse value *)
        index_name --> 'J';
        data_type --> 'DAE_C_INT';
        data_value --> LIST(1,1,1,1,47,47,95,95,95,95,95,145,145,145);};
      indextime = leaf_frame {
(* This will define the I (time index) value of each sparse value *)
        index_name --> 'I';
        data_type --> 'DAE_C_INT';
        data_value --> LIST(1,2,3,4,1,2,1,2,3,4,5,1,2,3); };
      velleaf = leaf_frame {
(* This will give the velocity at each of the above index locations *)
        ref_property_kind --> @PRV_seismic_velocity_Pwave_NMO;
(* ref_property_kind.ref_quantity_property. name = 'seismic velocity' 
AND ref_property_kind. ref_property_qualifier.name = 'migration' 
AND ref_property_kind.ref_kind_descriptor.name = 'P wave' *)
        ref_unit_of_measure --> @PRV_ft/s;
        data_type --> 'DAE_C_FLOAT';
        data_value --> LIST(5600, 6430, 7590, 8500, 6000, 9000, 5400,
                  6000, 7250, 8000, 9000, 5500, 7000, 8750 ); }; }; };

(* Now give the time values, through the use of the pty_geometry_2d_face *)

stackingtime = PTY_GEOMETRY_2D_FACE {
   seismic_data_set(K) --> @velocityfcn;
   data_value(M) --> SURFACE_GRID {
      geomframe = geometry_frame {
        detailed_type(M) --> 'FT_SSURFACE'; 
        descriptor(M) --> LIST( @sparsedesc );
        leaf_frame(M) --> SET( @pickbinleaf, @picktimeleaf,
                               @timeleaf, @binleaf );
        grid_or_mesh --> @vtbingrid;
        coordinate_system(M) --> @timebincoordsys; };
(* The following descriptor says there will be 14 points given *)
      sparsedesc = descriptor {
        dimension(M) --> 'INDEX_UNDEFINED';
        count(M) --> 14; };
(* The following leaf_frame gives the bin indexes of the 14 points. There
   will be four picks at bin point index '1', two at '47', five at '95',
   and three at '147' *)
      pickbinleaf = leaf_frame {
        index_name --> 'J';
        data_type --> 'DAE_C_INT';
        data_value --> LIST(1, 1, 1, 1, 47, 47, 95, 95, 95,
                            95, 95, 145, 145, 145); };
(* Now give the indexes on the time grid that will be populated. Note that
  the time grid axis is parametric, so the grid position doesn't carry the
  same semantics as does the bin point grid axis above *)
      picktimeleaf = leaf_frame {
        index_name --> 'I';
        data_type --> 'DAE_C_INT';
        data_value --> LIST(1,2,3,4,1,2,1,2,3,4,5,1,2,3); };
(* Now give the "bin point" and "time values" that go with each I,J pair
   of indexes. *)
      binleaf = leaf_frame {
(* Note. No values will be given. By implication, we are saying that the bin
   values are as given in the specification for the bin point index values.
   These were given in the formation of binpointgrid in Section 1.1.5 *)
        property_axis --> @binpointgridaxis;
        ref_unit_of_measure --> @PRV_Euc;
        data_type --> ' DAE_C_INT'; };
      timeleaf = leaf_frame {
        property_axis --> @coordtimeaxis;
        ref_unit_of_measure --> @PRV_ms;
        data_type --> ' DAE_C_FLOAT';
        data_value --> LIST(1040, 2550, 3700, 4500, 1500, 5000, 900, 1800,
                            3275, 4150, 5100, 1000, 3100, 4700);};};};
(* The time at each pick *)

----> Pause example: 2d Seismic Line

1.1.11 Supplementary Information

The previous sections store the information necessary to understand the data. But there is a lot of supplementary information about seismic data that can be included. For example, the shooting geometry may be included, although references to this information is not retained in stacked data. Likewise, the data ownership can be recorded. This information is not necessary for technical analysis of the data, but is useful as additional information. Finally, the sections that are plotted and stored may be noted.

1.1.11.1 Including Acquisition Information

Some acquisition information has already been stored. In particular, see "Acquisition Activity - Who and When" covered the acquisition activity (who and when). See "Storing Summary Information" instantiated the summary information, which included summary information about the number of source points, nominal spacing, etc.

This section will more fully describe the acquisition. We will expand upon Figure 1-1. In particular, there will be shots starting at station 1 and continuing through to station 463. Each shot will record 120 channels. The receivers for shot n will be located from stations n+1 to n+120. Assume that three vibrators were used for every shot, and that they had a linear downsweep from 80 to 12 over 18 seconds.

----> Continue example: 2D Seismic Line

vibrator1 = SEISMIC_SOURCE_FACILITY {
   ref_existence_kind(M,K) --> @PRV_actual;
   name(K) --> 'MD-1-88 3 vibrators';
   element_count --> 3;
   element_spacing --> QUANTITY { --ndt_length
      real_value --> 10.;
      ref_unit_of_measure --> @PRV_ft; };
   ref_seismic_vibrator_sweep --> @PRV_linear;
   vibrator_sweep_duration --> QUANTITY { --ndt_seismic_time
      real_value --> 18;
      ref_unit_of_measure --> @PRV_s; };
   vibrator_sweep_start_frequency --> QUANTITY { --ndt_frequency
      real_value --> 80.;
      ref_unit_of_measure --> @PRV_Hz; };
   vibrator_sweep_end_frequency --> QUANTITY { --ndt_frequency
      real_value --> 12.;
      ref_unit_of_measure --> @PRV_Hz; };
   vibrator_sweep_count --> 1;
   seismic_acquisition_activity --> @acquisition;
   description --> '3 inline vibrators, which were used for the whole line.';
   limited_usage <-- SET ( @2dline );};

(* In order to describe the shooting geometry completely, it will be necessary
  to set up several grids. These will define the uids for the source, the
  receiver, and the channel. There is already a uid set up for the stations
  (section 1.1.5). In addition, a field_trace_uid grid will be set up by 
  combining the source and receiver grids. *)

sourcegridaxis = GENERAL_COORDINATE_SYSTEM_AXIS {
  ref_quantity_property(M,K) --> @PRV_source_event_uid;
  ref_source --> @RV_MyCompany; };

sourceeventgrid = GRID_1D_EQUAL {
   name(M,K) --> 'RD-1-88 source event grid';
   origin(M) --> ANYQUANTITY { 
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_property --> @PRV_index; };
   step(M) --> ANYQUANTITY { 
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_property --> @PRV_index; };
   point_count(M) --> PAR_SrcCount;
   connected(M) --> FALSE;
   coordinate_system_axis(M) --> @sourcegridaxis; };

receivergridaxis = GENERAL_COORDINATE_SYSTEM_AXIS {
   ref_quantity_property(M,K) --> @PRV_receiver_uid;
   ref_source(M) --> @RV_MyCompany; };

receivergrid = GRID_1D_EQUAL {
   name(M,K) --> 'RD-1-88 receiver grid';
   origin(M) --> ANYQUANTITY { 
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_property --> @PRV_index; };
   step(M) --> ANYQUANTITY {
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_property --> @PRV_index; };
   point_count(M) --> PAR_StatCount - 1;
   connected(M) --> FALSE;
   coordinate_system_axis(M) --> @receivergridaxis;};

channelgridaxis = GENERAL_COORDINATE_SYSTEM_AXIS {
   ref_quantity_property(M,K) --> @PRV_channel_uid;
   ref_source(M) --> @RV_MyCompany; };

channelgrid = GRID_1D_EQUAL {
   name(M,K) --> 'RD-1-88 channel grid';
   origin(M) --> ANYQUANTITY { 
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_property --> @PRV_index; };
   step --> ANYQUANTITY { 
      real_value --> 1.;
      ref_unit_of_measure --> @PRV_Euc;
      ref_quantity_property --> @PRV_index; };
   point_count(M) --> PAR_ChnCount;
   connected(M) --> FALSE;
   coordinate_system_axis(M) --> @channelgridaxis;};

fieldtracegrid = GRID_DEFINED_GRID {
   name(M,K) --> 'RD-1-88 field trace grid';
   grid_structured(M) -->LIST(@sourceeventgrid, @channelgrid);};

(* Having defined all these grids, we can now refer to them
   in the (continuation of the) seismic_geometry_set *)
(* Note that seismic_station_uid has already been defined in section 1.1.5 *)
(* After storing these grids in the ..._uid attributes, the grids
   will be filled in with properties or arrays that connect them. *)

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_facility --> SET( @vibrator1 );
   field_trace_uid --> @fieldtracegrid;
   receiver_uid --> @receivergrid;
   source_event_uid --> @sourceeventgrid;
   channel_uid --> @channelgrid;
   channel_connection --> ELEMENT {
      chnframe = property_frame {
        detailed_type --> 'EGRID_2DNODE';
        descriptor --> LIST( @srcdescr, @chndescr);
        leaf_frame --> SET( @chnvalues );
        grid_or_mesh --> @fieldtracegrid;};
      srcdescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_SrcCount;};
      chndescr = descriptor {
        dimension --> INDEX_J;
        lower_bound --> 1;
        count --> PAR_ChnCount;};
      chnvalues = leaf_frame {
        ref_property_kind(M) --> @PRV_receiver_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_values(M) --> LIST( 1, 2, 3, ... 120,
                                 2, 3, 4, ...,121,
                                 3, 4, 5, ...,122, 
                                 4, 5, 6, ...,123,
                                   ...
                                 463, 465, 466, ..., 582 );};
(* the channel_connection is like a stacking chart. It reads that,
   for source_event 1, recorded on receiver uids 1, 2, 3, ..., 120.
   It is not quite like a stacking chart, because these are uid's,
   and have no semantic meaning. I.e., there is no guarantee that
   receiver uid 1 occurs at source event 1 (in general, it doesn't). *)

   receiver_station --> ELEMENT {
      recframe = property_frame {
        detailed_type --> 'EGRID_1DNODE';
        descriptor --> LIST( @recdescr );
        leaf_frame --> SET( @recvalues );
        grid_or_mesh --> @receivergrid;};
      recdescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_StatCount-1;};
      recvalues = leaf_frame {
        ref_property_kind(M) --> @PRV_seismic_station_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_values(M) --> LIST( 2, 3, 4, ..., 583 );};
(* the receiver_station tells which seismic_station_uid a particular
   receiver_station is located at. In this example, receiver_station
   with uid = 1 is located at seismic_station with uid = 2, etc. *)

   source_station --> ELEMENT {
      recframe = property_frame {
        detailed_type --> 'EGRID_1DNODE';
        descriptor --> LIST( @sourcedescr );
        leaf_frame --> SET( @sourcevalues );
        grid_or_mesh --> @sourceeventgrid;};
      sourcedescr = descriptor {
        dimension --> INDEX_I;
        lower_bount --> 1;
        count --> PAR_SrcCount; };
      sourcevalues = leaf_frame {
        ref_property_kind(M) --> @PRV_seismic_station_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_values(M) --> LIST( 1, 2, 3, ..., 463 );};
(* the source_station tells which seismic_station_uid a source event
   occurred at. In this example, there is a 1-1. This is a coincidence
   and may not be counted on in general. For example, there may be two
   shots a station, a station may be skipped, etc. *)
};

----> Pause example: 2D Seismic Line

Variation: Two different sources

There are two ways to indicate information about the source that was used. If the same source facility was used throughout the seismic_geometry_set, the relationship to seismic_source_facility is instantiated as in the above example. If more than one is used, this method cannot be used. In particular, it is necessary to define which source facility was used for which source event.

The most common example of this would be a multistreamer marine, in which two source cables are towed, and are alternately used as shots. Clearly, this pattern needs to be stored. The variation considered in this example, though, will be somewhat different. We will assume that, when vibrating at seismic station with uid = 384, one vibrator breaks. We reshoot this station, and then continue with just two vibrators. Furthermore, in order to get the required energy, the two vibrators each conduct two sweeps at each station (the results are vertically stacked).

In order to sort all of this out, it will be necessary to store the seismic facility uid's in an array related to the source events. The first step, then, will be to create the two source facilities, and assign uid's to them. Then the relationship between a seismic_geometry_set and the source facilities will be through an implied relationship rather than the direct relationship that was established in the above example. To do this, the relationship, seismic_source_facility, in the seismic_geometry_set will dropped, and the relationship, seismic_facility, will be instantiated.

----> Modify example: 2D Seismic Line

vibrator3 = SEISMIC_SOURCE_FACILITY {
   ref_existence_kind(M,K) --> @PRV_actual;
   name(K) --> 'MD-1-88 3 vibrators';
   element_count --> 3;
   vibrator_sweep_count --> 1;
   element_spacing --> QUANTITY { --ndt_length
      real_value --> 10;
      ref_unit_of_measure --> @PRV_ft; };
   ref_seismic_vibrator_sweep --> @PRV_linear;
   vibrator_sweep_duration --> QUANTITY { --ndt_seismic_time
      real_value --> 18.;
      ref_unit_of_measure --> @PRV_s; };
   vibrator_sweep_start_frequency --> QUANTITY { --ndt_frequency
      real_value --> 80.;
      ref_unit_of_measure --> @PRV_Hz; };
   vibrator_sweep_end_frequency --> QUANTITY { -- ndt_frequency
      real_value --> 12.;
      ref_unit_of_measure --> @PRV_Hz; };
      description --> '3 inline vibrators.';
(* limited_usage <-- ( @2dline ) This is dropped, and replaced
   by the following two *)
   seismic_facility_uid --> 1;
   seismic_geometry_set <-- SET( @2dline );};

vibrator2 = SEISMIC_SOURCE_FACILITY {
   ref_existence_kind(M,K) --> @PRV_actual;
   name(K) --> 'MD-1-88 2 vibrators';
   element_count --> 2;
   vibrator_sweep_count --> 2;
   element_spacing --> QUANTITY { --ndt_length
      real_value --> 10;
      ref_unit_of_measure --> @PRV_ft; };
   ref_seismic_vibrator_sweep --> @PRV_linear;
   vibrator_sweep_duration --> QUANTITY { --ndt_seismic_time
      real_value --> 18.;
      ref_unit_of_measure --> @PRV_s; };
   vibrator_sweep_start_frequency --> QUANTITY { --ndt_frequency
      real_value --> 80.;
      ref_unit_of_measure --> @PRV_Hz; };
   vibrator_sweep_end_frequency --> QUANTITY { -- ndt_frequency
      real_value --> 12.;
      ref_unit_of_measure --> @PRV_Hz; };
   description --> '2 inline vibrators. 2 sweeps';
   seismic_facility_uid --> 2;
   seismic_geometry_set <-- SET( @2dline );};

(* The axes and grids are set up the same as in the previous example.
   Furthermore, all the relationships are the same, with the
   exceptions shown below. One will be removed, and two will be added. *)
(* The other change (two shots at one station) will change the
   source_station array. Since there is one more shot, it will be
   necessary to create a new source_event_uid array. Also changed will
   be the "stacking chart", which will have the 384th and 385th rows
   be the same, because the same receivers were used for both shots. *)

sourceeventgrid2 = GRID_1D_EQUAL {
   name(M,K) --> 'RD-1-88 source event grid alt';
   origin(M) --> ANYQUANTITY {
      real_value --> 1.;
      ref_quantity_property --> @PRV_index;
      ref_unit_of_measure --> @PRV_Euc; };
   step(M) --> ANYQUANTITY {
      real_value --> 1.;
      ref_quantity_property --> @PRV_index;
      ref_unit_of_measure --> @PRV_Euc; };
   point_count(M) --> PAR_SrcCount + 1; (* one extra shot *)
   connected(M) --> FALSE;
   coordinate_system_axis(M) --> @sourcegridaxis;};

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
(* this attribute changes the source_event_uid. Replace old one *)
   source_event_uid --> @sourceeventgrid2;
(* seismic_source_facility --> @vibrator1 Replace this with *)
   seismic_facility --> SET( @vibrator3, @vibrator2 );
(* The next attribute tells which facility was used for which shot *)
   source_facility --> ELEMENT {
      sfframe = property_frame {
        detailed_type --> 'EGRID_1DNODE';
        descriptor --> LIST( @sfdescr );
        leaf_frame --> SET( @sfvalues );
        grid_or_mesh --> @sourceeventgrid2;};
      sourcedescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_SrcCount+1;};
      sourcevalues = leaf_frame {
        ref_property_kind(M) --> @PRV_source_event_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_values(M) --> LIST( 1, 1, 1,...,1, 2, 2,...,2); }; };
(* the array changed from 1 (at position 384) to 2 (at position 385) *)

   source_station --> ELEMENT {
      ssframe = property_frame {
        detailed_type -->'EGRID_1DNODE';
        descriptor --> LIST( @sourcedescr );
        leaf_frame --> SET( @sourcevalues );
        grid_or_mesh --> @sourceeventgrid2;};
      sourcedescr = descriptor {
        dimension --> INDEX_I;
        lower_bount --> 1;
        count --> PAR_SrcCount+1;};
      sourcevalues = leaf_frame {
        ref_property_kind(M) --> @PRV_seismic_station_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_values(M) --> LIST( 1, 2, 3, ...,384, 384,... 463);};};
(* This array has values = 384 at node 384, and values = 384 at node 385,
 because the 384th shot and the 385th shot both occurred at the same station. *)

   channel_connection --> ELEMENT {
      chnframe = property_frame {
        detailed_type --> 'EGRID_2DNODE';
        descriptor --> LIST( @srcdescr, @chndescr);
        leaf_frame --> SET( @chnvalues );
        grid_or_mesh --> @fieldtracegrid;};
      srcdescr = descriptor {
        dimension --> INDEX_I;
        lower_bound --> 1;
        count --> PAR_SrcCount+1;};
      chndescr = descriptor {
        dimension --> INDEX_J;
        lower_bound --> 1;
        count --> PAR_ChnCount;};
      chnvalues = leaf_frame {
        ref_property_kind(M) --> @PRV_receiver_uid;
        ref_unit_of_measure --> @PRV_Euc;
        data_values(M) --> LIST( 1, 2, 3, ... 120,
                                 2, 3, 4, ...,121, 
                                 3, 4, 5, ...,122, 
                                 4, 5, 6, ...,123,
                                    ...
                                 384, 385, 386, ..., 503,
                                 384, 385, 386, ..., 503,
                                    ...
                                 463, 465, 466, ..., 582 ;};};};

----> Pause example: 2D Seismic Line

1.1.11.2 Referring to Data Ownership

Who owns the data? Who is responsible for the data? Who may trade or sell the data? All of these are rights or privileges or guidelines or restrictions that are placed on (in general) business_objects. They will be recorded using the business_associate_privilege.

The business_associate_privilege resolves a many-to-many between business_associate and a business_object. (Both seismic_geometry_set and seismic_line_segment are business_objects). So it is possible to assign many of the privileges to many different business associates.

This example will create three types of privileges: (1) internal responsibility, (2) trade, and (3) final seismic. The first will basically state who inside the company is responsible for the data. The second will identify that a particular business associate has trade rights with the data. The third will identify that a business associate is able to view, map, work with, etc., the final seismic section and data, but may not have access to the pre-stack data. These are local reference entity values, and have no meaning other than what this example puts on them.

Having defined these three privileges, the example will say that the Anadarko Project Team has privileges (1) and (2), and another company, Acme Exploration, has privilege (3). These privileges will apply to the whole line, but it is also possible to identify a segment, and have the privileges apply to the segment.

----> Continue example: 2D Seismic Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   guideline_or_privilege <-- SET(@RV_responsible, 
                                 @RV_trade, @RV_finalseismic );};

(* Form the three reference entity values *)

RV_responsible = REF_BUSINESS_ASSOCIATE_PRIVILEGE {
   kind(M,K) --> 'internal responsibility';
   description --> 'The business associate is within the company,
                    and has ownership responsibility for the data.
                    The data may not be traded or sold without
                    permission of the responsible business associate.';
   source(M) --> @RV_MyCompany; };

RV_trade = REF_BUSINESS_ASSOCIATE_PRIVILEGE {
   kind(M,K) --> 'trade';
   description --> 'The business associate may freely trade the
                    data with other companies.';
   source(M) --> @RV_MyCompany;};

RV_final_seismic = REF_BUSINESS_ASSOCIATE_PRIVILEGE {
   kind(M,K) --> 'final seismic';
   description --> 'The business associate has rights to printed
                    seismic sections, and to the post-stack or
                    migrated digital data. The business associate
                    does not have rights to access the prestack data.
                    Nor does he have rights to sell, trade, show,
                    exhibit, or in any way share the data with any
                    other company.';
   source(M) --> @RV_MyCompany;};

(* Give the business_associate_privileges for the line *)

responsible = BUSINESS_ASSOCIATE_PRIVILEGE {
 SUBOF (GUIDELINE_OR_PRIVILEGE);
   ref_business_associate_privilege(M,K) --> @RV_responsible;
   identifier(M,K) --> 'Anadarko Team responsibility';
   description(M) --> 'The Anadarko Team has data responsibility';
   business_object --> SET( @2dline );
   business_associate(M,K) --> @PL_Anadarko_Project_Team;};

trade = BUSINESS_ASSOCIATE_PRIVILEGE {
 SUBOF (GUIDELINE_OR_PRIVILEGE); 
    ref_business_associate_privilege(M,K) --> @RV_trade;
    identifier(M,K) --> 'Anadarko Team trade rights';
    description(M) --> 'The Anadarko Team has trade rights.';
    business_object --> SET( @2dline );
    business_associate(M,K) --> @PL_Anadarko_Project_Team;};

finalseismic = BUSINESS_ASSOCIATE_PRIVILEGE {
SUBOF(GUIDELINE_OR_PRIVILEGE);
   ref_business_associate_privilege(M,K) --> @RV_final_seismic;
   identifier(M,K) --> 'Acme Exploration view rights';
   description(M) --> 'Acme Exploration may view the data';
   business_object --> SET( @2dline );
   business_associate(M,K) --> @PL_Acme_Exploration; };

----> Pause example: 2D Seismic Line

Note that the business_object attribute is a set, and allows many objects to be included in this same instance. For example, all the lines that are the responsibility of the Anadarko Project Team can be included in the @responsible instance.

1.1.11.3 Referring to section plots

A seismic section is more than just a display of (generally) wiggle traces. A seismic section also contains information about the data and information about the acquisition and processing of the data. It also contains information about related data, such as the location of wells, crossing lines, and lease/concession/block boundaries.

Much of this information can be obtained from the seismic_data_set. There is a mandatory relationship to the Seismic_data_set, which can provide the information about the data. The Seismic_data_set also has relationships to seismic_processing_activity and, through the seismic_geometry_set, to the seismic_acquisition_activity.

Thus, much of the context of a seismic section is captured through its relationships. The information relating to the plotting of the seismic trace itself will be carried in the entity seismic_display.

Note that the whole line need not be plotted. In order to indicate that only a part of the line is plotted, you may wish to refer to a seismic_line_segment or a seismic_traverse.

----> Continue Example: Seismic 2D Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_line_segment <-- SET( @segmentplotted ); };

stackdata = SEISMIC_DATA_SET { (* continuation *)
  seismic_display <-- SET( @section ); };

segmentplotted = SEISMIC_LINE_SEGMENT {
   seismic_geometry_set(M,K) --> @2dline;
   begin_station_uid --> 6;
   end_station_uid --> 577;
   seismic_display <-- SET( @section ); };

section = SEISMIC_DISPLAY {
 SUBOF (DOCUMENT_SPECIFICATION);
   identifier(M,K) --> 'MD-1-88 stacked line';
   ref_seismic_display_mode --> @PRV_wiggle_trace_with_variable_area;
   ref_seismic_polarity --> @PRV_normal;
   x_scale --> ANYQUANTITY { -- 10 traces per inch *)
      real_value --> 10.;
      ref_unit_of_measure --> @PRV_1/in;
      ref_quantity_property --> @PRV_resolution; };
   y_scale --> ANYQUANTITY { -- 200 msec per inch, or, 5 inches per second 
      real_value --> 200.;
      ref_unit_of_measure--> @PRV_ms/in;
      ref_quantity_property --> @PRV_time_scale; };
   seismic_data_set(M,K) --> @stackdata;
   seismic_line_segment --> @segmentplotted; 
(* actually, we plotted the whole line. But it is possible, even in
     this case, to indicate such with the seismic_line_segment *)
   document <-- SET( @film, @paper ); };
(* Both a film and a paper copy were made, and are under document control *)

paper = HARDCOPY_DOCUMENT {
 SUBOF (DOCUMENT);
   identifier(K) --> 'MD-1-88 file paper copy';
   ref_hardcopy_document --> @PRV_seismic_paper_section;
   document_specification(M,K) --> @section;
   inventory_object_storage <-- SET( @storepaper ); };

film = HARDCOPY_DOCUMENT {
 SUBOF (DOCUMENT);
   identifier(K) --> 'MD-1-88 file film copy';
   ref_hardcopy_document --> @PRV_seismic_film;
   document_specification(M,K) --> @section;
   inventory_object_storage <-- SET( @storefilm ); };

filecabinet = OTHER_FACILITY {
 SUBOF (GENERAL_FACILITY);
(* this will be where the paper copy is stored. Later, an
   inventory_object_storage will tie these two together. *)
   ref_existence_kind(M,K) --> @PRV_actual;
   name(K) --> 'Anadarko 1989 K-N';
   inventory_object_storage <-- SET( @storepaper ); };

storeroom = OTHER_FACILITY {
 SUBOF (GENERAL_FACILITY);
(* this will be where the film copy is stored. Later, an
   inventory_object_storage will tie these two together. *)
   ref_existence_kind(M,K) --> @PRV_actual;
   name(K) --> 'Bin 28, Anadarko storage room';
   inventory_object_storage <-- SET( @storefilm ); };

storepaper = INVENTORY_OBJECT_STORAGE {
   inventory_object(M,K) --> @paper; (* the paper copy is in *)
   general_facility(M,K) --> @filecabinet; (* the filecabinet *) };

storefilm =  INVENTORY_OBJECT_STORAGE {
   inventory_object(M,K) --> @film; (* the film copy is in *)
   general_facility(M,K) --> @storeroom; (* the storeroom *) };

----> Pause Example: Seismic 2D Line

This section is very brief on the inventory portion. The above example does nothing more than make the simple statement that the paper copy (for example) is in a file cabinet (with a given label). But the inventory portion of the model is much richer than indicated. It is possible, for example, to say that the paper copy is in a file drawer, which is in a file cabinet, which is in a room or office, which is in a building, etc. It can also have the paper copy moved (for example) from the file cabinet to a person's office, and then to a library.

These capabilities are based on a contained-containing relationship on general_facility, and on time attributes on the inventory_object_storage. The inventory_object_storage is designed as an intersection entity to resolve a many-to-many relationship between the document and the storage facility. Clearly, many documents can be stored in a given facility. And a document may be stored in many facilities - over time. I.e., the time history may be tracked, if desired. (The time history for an electronic_document becomes important if there is a disk crash, and a backup tape is needed to restore the information).

However, this section is about the seismic line, and not about the inventory model. So a very cursory dip into the inventory model was made.

1.1.12 Processing Information

By the time the data is stacked, most of processing information is not relevant. It is used mostly for quality control - to analyze the pedigree of the data. So this information has been successfully passed over so far.

This section will show two levels of storing this processing information. The first is not preferred, because it hides the information in the description attribute. But there are times when all you have is a text string that describes the processing, and this may be the only way to store the processing history without making up data.

The second way uses the process model. It will be more fully described in Section 1.1.12.2, "Process Model".

Assume that we "create" our data set by the operations of filter, decon, NMO, and stack. There are actually four processes involved. Epicentre only allows us to have one process to create the data. To meet this criterion, we use the contained-containing relationship on activity. I.e., we will have one processing activity create the data, which will contain the four given subprocesses. Thus, the strategy will be to have a single process that takes us to the seismic_data_set, and to break it up as appropriate to describe more detail2.

Note 2: An alternative would be to have the fourth process, "stack," create the data, with stack being a part of the parent job.

1.1.12.1 Capture Text Only

The first way captures text only. This may be a way to "dump" the information from a reel header (which often contains, among other things, a description of the processing) into Epicentre.

The restriction is that the description attribute is 2000 characters long. Furthermore, many loaders restrict the special characters that can be in the string. For example, many loaders cannot handle line feeds and carriage returns. So the method shown here may have to be altered from a straight data dump to an intelligent data dump.

----> Continue Example: 2D Seismic Line

2dline = SEISMIC_GEOMETRY_SET { (* continuation *)
   seismic_processing_activity <-- SET( @fullstack ); };

stackdata = SEISMIC_DATA_SET { (* continuation *)
   seismic_processing_activity --> @fullstack; };

fullstack = SEISMIC_PROCESSING_ACTIVITY {
  ref_existence_kind(M,K) --> @PRV_actual;
  name(K) --> 'Process to stack, MD-1-88';
  description --> 'Filter 8-70 (0-1800), 12-55 (1800-4000); 
                   Decon operator length = 160 msec, no gap, 
                       wiener-levinson, 10% whitening;
                   NMO; 
                   stack';
(* I have stuffed the processes and their parameters into this description.
  This is in general not recommended, because it is better to keep the
  semantics out of the description. But, it is certainly acceptable,
  and it may be all that is known. *)

   seismic_geometry_set(K) --> @2dline;
   seismic_data_set <-- SET( @stackdata ); };

----> Pause Example: 2D Seismic Line

1.1.12.2 Process Model

To set this up, we will go both directions in the processing hierarchy. The previous section created a second-level processing activity. It will be useful to create a first-level activity that will include all processing activities.

For example, I may have two other seismic_data_sets. One is a post stack migrated data set that takes the stack data set and migrates it. I would then have another seismic_processing_activity - @poststackmigrated - whose processing would be a single process attached to the list already given. The other data set I would have may be a prestack migrated data set. This would have yet another seismic_processing_activity - @prestackmigrated - that would detail all the processing steps from the beginning. In order to group these three together, and to give their relationships to each other, I will use a first-level activity.

I will also create third-level processing activities. For the detail I wish to store, I will get to the processing module level. I will create a processing activity for each module I run, and record the input parameters to the level desired. I can then put them together using a schedule. Each second-level grouping will correspond to the output of a single seismic_data_set.

For this example, I will create only one second-level grouping. It will be the same one already instantiated in the previous section. The description attribute may alter, but the other attributes are still appropriate.

The order of the processes will be given by controlling the input and output data to each processing activity. For example, the filter activity will have a process_data attribute, which points to the "online output" data, filterout. This online output is then tied to the input parameter for the next process, deconvolution. Thus, the data flow can be followed by tracking the online outputs and inputs.

But there are three loose ends to this tracking. There is no input to the first process, no output to the last process, and, for this example, no velocity function input to the NMO. These can all be handled. In this case, it was assumed these were unknown - so they weren't given. But it is possible that I have a seismic_data_set, with the data registered in a pty_geometry... entity, I can use this as the input data (or mention it as the output data). Likewise, if I have the velocity function stored in the data store, I can point to its pty_geometry... as the velocity function input data. So these loose ends can be tied, if the data is available.

The first step in using the process model is to build a framework of modules and parameters. This is typically only done once by a data center, and can be reused many times.

----> Continue Example: 2D Seismic Line

filter = TYPICAL_ACTIVITY {
   name(M,K) --> 'Filter';
   description --> 'Generic time varying filter application.';
(* It is also possible to develop typical_activities for in-house
   specific modules. This is for a generic module with generic
   parameters. These would be what might appear on a side label. *)
   typical_activity_classification <-- 
(* This gives an opportunity to classify this activity. For example,
   this module might be classified as 'generic', 'filter',
   'seismic processing', 'software module', etc. *)
   process_parameter <-- SET(@highcut, @lowcut, @winmin, @winmax);};

decon = TYPICAL_ACTIVITY {
   name(M,K) --> 'Wiener-Levinson Deconvolution';
   description --> 'Generic Wiener-Levinson deconvolution application.';
   typical_activity_classification <-- (* Same comment as above. *)
   process_parameter <-- SET(@oplen, @gap, @whitelevel1); };

nmo = TYPICAL_ACTIVITY{
   name(M,K) --> 'Normal Moveout';
   description --> 'Generic Normal Moveout application.';
   typical_activity_classification <-- (* Same comment as above. *) };

stack = TYPICAL_ACTIVITY{
   name(M,K) --> 'Stack';
   description --> 'Generic trace stacking application.';
   typical_activity_classification <-- (* Same comment as above. *)};

(* The four processes have been defined (as typical). Now define
   the parameter sets that go with these processes *)

highcut = PROCESS_PARAMETER {
   name(M,K) --> 'highcut';
   description --> 'The point at the high end of the filter spectrum
             that corresponds to 6db attenuation from the maximum.
             The accompanying integer value defines which window this
             highcut is used for.';
   typical_activity(K) --> @filter;
   source(M) --> @RV_MyCompany; };

lowcut = PROCESS_PARAMETER {
   name(M,K) --> 'lowcut';
   description --> 'The point at the low end of the filter spectrum
             that corresponds to 6db attenuation from the maximum.
             The accompanying integer value defines which window this
             lowcut is used for.';
   typical_activity(K) --> @filter;
   source(M) --> @RV_MyCompany; };

winmin = PROCESS_PARAMETER {
   name(M,K) --> 'window minimum';
   description --> 'The minimum time value for which this filter is
                    to be applied.';
   typical_activity(K) --> @filter;
   source(M) --> @RV_MyCompany;};

winmax = PROCESS_PARAMETER{
   name(M,K) --> 'window maximum';
   description --> 'The maximum time value for which this filter is
                    to be applied.';
   typical_activity(K) --> @filter;
   source(M) --> @RV_MyCompany;};

filterinput = PROCESS_PARAMETER{
   name(M,K) --> 'input';
   description --> 'The input data for which this filter is to be applied.';
   typical_activity(K) --> @filter;
   source(M) --> @RV_MyCompany;};

filteroutput = PROCESS_PARAMETER {
   name(M,K) --> 'output';
   description --> 'The output data to which this filter has been applied.';
   typical_activity(K) --> @filter;
   source(M) --> @RV_MyCompany;};

oplen = PROCESS_PARAMETER{
   name(M,K) --> 'operator length';
   description --> 'The length of the operator in the time domain.';
   typical_activity(K) --> @decon;
   source(M) --> @RV_MyCompany;};

gap = PROCESS_PARAMETER {
   name(M,K) --> 'gap';
   description --> 'The time gap in the operator prediction.';
   typical_activity(K) --> @decon;
   source(M) --> @RV_MyCompany;};

whitelevel = PROCESS_PARAMETER {
   name(M,K) --> 'whitening';
   description --> 'The percent of whitening to add to the diagonal';
   typical_activity(K) --> @decon;
   source(M) --> @RV_MyCompany;};

deconinput = PROCESS_PARAMETER {
   name(M,K) --> 'input';
   description --> 'The input data for which deconvolution is
                    to be applied.';
   typical_activity(K) --> @decon;
   source(M) --> @RV_MyCompany;};

deconoutput = PROCESS_PARAMETER {
   name(M,K) --> 'output';
   description --> 'The output data to which deconvolution has been applied.';
   typical_activity(K) --> @decon;
   source(M) --> @RV_MyCompany;};

nmoinput = PROCESS_PARAMETER {
   name(M,K) --> 'input';
   description --> 'The input seismic data for which nmo is to be applied.';
   typical_activity(K) --> @nmo;
   source(M) --> @RV_MyCompany;};

nmovelinput = PROCESS_PARAMETER {
   name(M,K) --> 'velocity function input';
   description --> 'The input velocity function for use in nmo.';
   typical_activity(K) --> @nmo;
   source(M) --> @RV_MyCompany;};

nmooutput = PROCESS_PARAMETER {
   name(M,K) --> 'output';
   description --> 'The output data to which nmo has been applied.';
   typical_activity(K) --> @nmo;
   source(M) --> @RV_MyCompany;};

stackinput = PROCESS_PARAMETER {
   name(M,K) --> 'input';
   description --> 'The input data for which stack is to be applied.';
   typical_activity(K) --> @stack;
   source(M) --> @RV_MyCompany;};

stackoutput = PROCESS_PARAMETER {
   name(M,K) --> 'output';
   description --> 'The output data which has been stacked.';
   typical_activity(K) --> @stack;
   source(M) --> @RV_MyCompany;};

(* The above instances are examples of how processes and their parameters
   can be stored in the database. It is assumed that this information is
   preloaded by someone, and can be used many times to specify the actual
   values that are applied in any specific process. I.e., you do the above
   ONCE for all you seismic processes. The instances below are specific to
   particular datasets. *)
(* In the portion in section 1.1.12.1, I used the overall process I named
   fullstack. The following five activities (seismic_processing_activity)
   will be contained in that overall process. With each activity will be 
   recorded the actual value of the parameters. (process_data_item and
   interprocess_data) *)
(* First, record the filter process and its parameter values *)

actfilter = SEISMIC_PROCESSING_ACTIVITY {
   ref_existence_kind(M,K) --> @PRV_actual;
   typical_activity(K) --> @filter;
   containing_activity --> @fullstack;
   process_data_item <-- SET( @acthighcut1, @actlowcut1, @actwinmin1,
                              @actwinmax1, @acthighcut2, @actlowcut2,
                              @actwinmin2, @actwinmax2 );
   process_data <-- SET(@filterout);}; (* data created by this process *)

filterout = INTERPROCESS_DATA {
   activity(M,K) --> @actfilter; (* which activity created this *)
   process_parameter --> @filteroutput;
   description --> 'The online output, which may be used directly
                    as input to another process';};

highcutval1 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 70.0'
      ref_unit_of_measure --> @PRV_Hz;
      ref_quantity_property --> @PRV_frequency; };
   integer_vaue --> 1;
   process_data_item <-- (@acthighcut1);};

acthighcut1 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @highcut; (* in this role *)
   process_data(K) --> @highcutval1; }; (* with this value *)

lowcutval1 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 80.0'
      ref_unit_of_measure --> @PRV_Hz;
      ref_quantity_property --> @PRV_frequency; };
   integer_value --> 1;
   process_data_item <-- (@actlowcut1);};

actlowcut1 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @lowcut; (* in this role *)
   process_data(K) --> @lowcutval1;}; (* with this value *)

winminval1 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 0.0'
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   integer_value --> 1;
   process_data_item <-- (@actwinmin1);};

actwinmin1 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @winmin; (* in this role *)
   process_data(K) --> @winminval1; }; (* with this value *)

winmaxval1 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 1800.0'
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   integer_value --> 1;
   process_data_item <-- (@actwinmax1);};

actwinmax1 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @winmax; (* in this role *)
   process_data(K) --> @winmaxval1;}; (* with this value *)

highcutval2 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 55.0'
      ref_unit_of_measure --> @PRV_Hz;
      ref_quantity_property --> @PRV_frequency; };
   integer_vaue --> 2;
   process_data_item <-- (@acthighcut2);};

acthighcut2 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @highcut; (* in this role *)
   process_data(K) --> @highcutval2; }; (* with this value *)

lowcutval2 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 12.0'
      ref_unit_of_measure --> @PRV_Hz;
      ref_quantity_property --> @PRV_frequency; };
   integer_value --> 2;
   process_data_item <-- (@actlowcut2);};

actlowcut2 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @lowcut; (* in this role *)
   process_data(K) --> @lowcutval2;}; (* with this value *)

winminval2 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 1800.0'
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   integer_value --> 2;
  process_data_item <-- (@actwinmin2);};

actwinmin2 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @winmin; (* in this role *)
   process_data(K) --> @winminval2; }; (* with this value *)

winmaxval2 = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 4000.0'
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic; };
   integer_value --> 2;
   process_data_item <-- (@actwinmax2);};

actwinmax2 = PROCESS_DATA_ITEM {
   activity(M,K) --> @actfilter; (* used by this activity *)
   process_parameter(K) --> @winmax; (* in this role *)
   process_data(K) --> @winmaxval2;}; (* with this value *)

(* Second, record the decon process and its parameter values *)

actdecon SEISMIC_PROCESSING_ACTIVITY {
   ref_existence_kind(M,K) --> @PRV_actual;
   typical_activity(K) --> @decon;
   containing_activity --> @fullstack;
   process_data_item <-- SET( @actgap, @actoplen, @actwiten, @deconin);
(* Note that the decon input data is a parameter. The next entity (below)
   will tie this to the output from the filter. *)
   process_data <-- SET(@deconout);}; (* this is the output data *)

deconin = PROCESS_DATA_ITEM {
   activity(M,K) --> @actdecon; (* used by this activity *)
   process_parameter(K) --> @deconinput; (* this is the input data *)
   process_data(K) --> @filterout;}; (* which is the output
                                      from the previous module *)

deconout = INTERPROCESS_DATA {
   activity(M,K) --> @actdecon; (* which activity created this *)
  process_parameter --> @deconoutput;
   description --> 'The online output, which may be used directly
                    as input to another process';};

oplenval = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 160.0'
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   process_data_item <-- (@actoplen);};

actoplen = PROCESS_DATA_ITEM {
   activity(M,K) --> @actdecon;
   process_parameter(K) --> @oplen;
   process_data(K) --> @oplenval;};

gapval = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 0.0'
      ref_unit_of_measure --> @PRV_ms;
      ref_quantity_property --> @PRV_seismic_time; };
   process_data_item <-- (@actgap);};

actgap = PROCESS_DATA_ITEM {
   activity(M,K) --> @actdecon;
   process_parameter(K) --> @gap;
   process_data(K) --> @gapval;};

whiteval = INTERPROCESS_DATA {
   quantity_value --> ANYQUANTITY {
      real_value --> 10.0'
      ref_unit_of_measure --> @PRV_%;
      ref_quantity_property --> @PRV_ratio; };
   process_data_item <-- (@actwhite);};

actwhite = PROCESS_DATA_ITEM {
   activity(M,K) --> @actdecon;
   process_parameter(K) --> @whitelevel;
  process_data(K) --> @whiteval;};

(* Third, record the normal moveout process *)

actnmo SEISMIC_PROCESSING_ACTIVITY {
   ref_existence_kind(M,K) --> @PRV_actual;
   typical_activity(K) --> @nmo;
   containing_activity --> @fullstack;
   process_data_item <-- SET(@nmoin); 
(* the data is the only input (known) to this process *)
   process_data <-- SET(@nmoout);};

nmoin = PROCESS_DATA_ITEM {
   activity(M,K) --> @actnmo; (* used by this activity *)
   process_parameter(K) --> @nmoinput; (* this is the input data *)
   process_data(K) --> @deconout;}; (* which is the output from the previous module *)

nmoout = INTERPROCESS_DATA {
   activity(M,K) --> @actnmo; (* which activity created this *)
   process_parameter --> @nmooutput;
   description --> 'The online output, which may be used directly as 
                    input to another process';};

(* Fourth, record the stack process *)

actstack SEISMIC_PROCESSING_ACTIVITY{
   ref_existence_kind(M,K) --> @PRV_actual;
   typical_activity(K) --> @stack;
   containing_activity --> @fullstack;
   process_data_item <-- SET(@stackin); }; (
* the data is the only input to this process *)

stackin = PROCESS_DATA_ITEM {
   activity(M,K) --> @actstack; (* used by this activity *)
   process_parameter(K) --> @stackinput; (* this is the input data *)
  process_data(K) --> @nmoout; (* which is the output from the previous module *)};

----> End Example: 2D Seismic Line


[Seismic Example Table of Contents]
Last modified: 29 December 1997
© Copyright 1997 POSC. All rights reserved.