NAME
EV - BRTT utility for earthquake event view formation
SYNOPSIS
-lbrttutil
#include "EV.h"
DESCRIPTION
There are two fundamental classes,
EVServer and
EVClient,
that implement complete views of earthquake event information
from underlying databases. They are intended to be dynamic in response to
changing databases. Information from events, origins, origin errors, associations,
arrivals, detections, stations, magnitudes
and moment tensors are joined in a set of views that can be
returned through a set of specialized structures.
The underlying database is monitored and the views are made by a single EVServer
object. The views are refreshed automatically by EVServer objects whenever any of the
database file modification times have changed. EVServer makes
all of the joins though calls to dbmatches(3) only, without using the various
other Datascope view generation routines, such as dbjoin(3). Most Datascope
view generation routines cannot track dynamic changes in the underlying database.
By only using dbmatches(3), which is designed to track certain changes in the
underlying database, EVServer objects can track changes in the database and recompute
the various view structures as required. All calls to dbmatches(3), dbget(3)
or dbgetv(3) made
by EVServer objects trap error returns, which could be caused by changes in the database
during EVServer processing. When dbget(3), dbgetv(3) or dbmatches(3)
return errors, the EVServer object will automatically close the database, reopen it,
free all dbmatches(3) hooks, and reform the various views. This will also happen
automatically whenever the database files shrink in size.
Once an EVServer object has been created and configured, it will continuously monitor
a database and compute the various event views whenever necessary. Interactions with these
views are accomplished through EVClient objects. Whereas only one EVServer object
should be created for a particular database, any number of EVClient objects can provide
independent interfaces to the event view server. Each EVClient object can run safely on
separate threads. The EVServer object notifies each of its clients through callback
procedures whenever the various views have changed. The EVClient objects can then obtain
copies of the changed views from the EVServer object through a set of client methods.
All information in the event views are copies of the original views kept be the EVServer
object. There are no pointers back to information that could become stale as the views are
updated.
EVServer objects can also serve more generic views of various database tables that are not
offered in the event views. Specifically, views of wfdisc tables can be requested by a client.
In addition views of arrival and detection tables that are not event oriented
and not served up as components within event views can be requested by a client.
These tables can be monitored by EVServer in the same manner as with the event views
with automatic notifications through client callback procedures whenever the tables change.
This provides an alternate way to acquire arrival and detection rows that are
completely unassociated with any events. Safe EVServer-based versions
of generic dbsubset, dbmatches and dbnextid are supported for these tables.
As well, EVServer supports safe writing of these tables through EVServer side dbput
and dbadd.
EVENT VIEWS
The various event views are returned as c++ structures. The fundamental event view
structure,
EVEvent, is defined below.
struct EVEvent {
EVEvent () {
recno_event = -1;
evid = -1;
prefor = -1;
order = -1;
lddate_event = 0.0;
lddate_view = 0.0;
access_time = 0.0;
prefor_time = 0.0;
magnitude = -999.0;
strcpy (magtype, "");
pref_origin = -1;
pref_magnitude_origin = -1;
pref_moment_origin = -1;
}
long recno_event; /* record number of event row */
char record_event[154]; /* copy of event row */
long evid; /* event row evid value */
long prefor; /* event row prefor value */
long order; /* order of event row */
double lddate_event; /* event row lddate value */
double lddate_view; /* largest view lddate value */
double access_time; /* last access time */
double prefor_time; /* time of preferred origin */
double magnitude; /* event preferred magnitude */
char magtype[8]; /* event preferred magnitude type */
int pref_origin; /* preferred origin index */
int pref_magnitude; /* preferred magnitude index */
int pref_moment; /* preferred moment index */
int pref_moment_origin; /* preferred moment origin index */
Table<EVOrigin> origins; /* vector of associated origin views */
};
Each EVEvent structure represents a single row in the database event table
along with all of its associated EVOrigin views (i.e. origin relation
values with the same evid as the event row). The recno_event
structure element is the ordinal record number of the event table.
The record_event structure element is a copy of the complete event row.
The evid and prefor structure elements are copies of the event
row evid and prefor values. The database lddate values are copied
into lddate_event, the event row lddate value, and lddate_view,
which is the largest of all of the database lddate values from
the origin, netmag, and mt database rows associated with the event.
All of the associated EVOrigin views are stored in the origins Table.
There is a built-in algorithm for determining a preferred magnitude from the various origin
preferred magnitude values and those are reported in magnitude and magtype.
The current preferred magnitude algorithm looks at the preferred magnitudes for each origin and
choses the one according to the following rules. Magnitudes for each origin are ranked according
to importance based on a list of magnitude types and minimum and maximum magnitude ranges.
The current ranking is as follows.
preferred_magnitudes &Tbl{
mww 7.0
mwp 6.0
mwc 6.0 8.0
mwb 4.0 7.0
mwr 3.0 7.0
mw 4.0 7.0
ml -1.0 5.0
mb 3.0 6.0
ms 5.0 7.0
mww
mwp
mwc
mwb
mwr
mw
ml
mb
ms
}
The magnitude type is obtained from the USNEIC reported magnitude types. Magnitude
minimum and maximum ranges can follow optionally. The higher in the list, the higher the
ranking. The ranking is obtained by taking a particular magnitude type and determining if
it is within the magnitude range. If it fails the magnitude range then it will go down
to the next entry until a ranking can be found. As an example, a magnitude of type mwp
with magnitude 6.5 would have a higher ranking than a magnitude of type mwb
with a magnitude of 3.5.
Individual epicenters are returned in EVOrigin structures as defined below.
struct EVOrigin {
EVOrigin () {
recno_origin = -1;
orid = -1;
lddate_origin = 0.0;
lddate_origin_view = 0.0;
time = 0.0;
preferred = 0;
magnitude = -999.0;
strcpy (magtype, "");
recno_origerr = -1;
pref_magnitude = -1;
pref_moment = -1;
}
long recno_origin; /* record number of origin row */
char record_origin[288]; /* copy of origin row */
long orid; /* origin row orid value */
double lddate_origin; /* origin row lddate value */
double lddate_origin_view; /* largest view lddate value */
double time; /* origin row time value */
long recno_origerr; /* record number of origerr row */
char record_origerr[268]; /* copy of origerr row */
double magnitude; /* origin preferred magnitude */
char magtype[8]; /* origin preferred magnitude type */
int preferred; /* is this the preferred origin? */
Table<EVMagnitude> magnitudes; /* vector of origin magnitude views */
Table<EVMoment> moments; /* vector of origin moment views */
Table<EVDetection> detections; /* vector of origin detection views */
Table<EVAssociation> associations; /* vector of origin associatiln views */
int pref_magnitude; /* preferred magnitude magnitudes index */
int pref_moment; /* preferred moment moments index */
};
Each EVOrigin structure represents a single row in the database origin table
along with all of its associated EVMagnitude, EVMoment, EVDetection
and EVAssociation views. The recno_origin
structure element is the ordinal record number of the origin table.
The record_origin structure element is a copy of the complete origin row.
The orid and time structure elements are copies of the origin
row orid and time values. The database lddate values are copied
into lddate_origin, the origin row lddate value, and lddate_origin_view,
which is the largest of all of the database lddate values from
the netmag, and mt database rows associated with the origin.
If there is an associated origerr row for this origin row, then its record number
and a copy of the origerr row are stored in recno_origerr and record_origerr.
All of the associated EVMagnitude views are stored in the magnitudes Table.
All of the associated EVMoment views are stored in the moments Table.
All of the associated EVDetection views are stored in the detections Table.
All of the associated EVAssociation views are stored in
the associations Table. The EVDetection views return rows from
the detection table for which the detection times are approximately equal to the
predicted P-arrival times for those stations, whether or not they were promoted
to arrival rows in the association process. The preferred magnitude and magnitude type
across all magnitudes for this origin are stored in magnitude and magtype
using the same ranking described previously.
Event origins can be returned in either abbreviated or expanded forms. In abbreviated forms
the information related to associated stations are not returned, which results in
empty detections and associations vectors.
Individual network magnitudes are returned in EVMagnitude structures as defined below.
struct EVMagnitude {
EVMagnitude () {
recno_netmag = -1;
lddate_netmag = 0.0;
magnitude = -999.0;
strcpy (magtype, "");
}
long recno_netmag; /* record number of netmag row */
char record_netmag[144]; /* copy of netmag row */
double lddate_netmag; /* lddate of netmag row */
double magnitude; /* netmag magnitude */
char magtype[8]; /* netmag magnitude type */
Table<EVStamag> stamags; /* Individual station magnitudes */
};
Each EVMagnitude structure represents a single row in the database netmag table.
Individual station magnitude magnitudes are returned in EVStamag structures as defined below.
struct EVStamag {
EVStamag () {
recno_stamag = -1;
lddate_stamag = 0.0;
arid = -1;
magnitude = -999.0;
strcpy (magtype, "");
}
long recno_stamag; /* record number of stamag row */
char record_stamag[168]; /* copy of stamag row */
double lddate_stamag; /* lddate of stamag row */
long arid; /* arid corresponding to this stamag */
double magnitude; /* stamag magnitude */
char magtype[8]; /* stamag magnitude type */
};
Each EVStamag structure represents a single row in the database stamag table.
Individual moment tensors are returned in EVMoment structures as defined below.
struct EVMoment {
EVMoment () {
recno_mt = -1;
lddate_mt = 0.0;
}
long recno_mt; /* record number of mt row */
char record_mt[564]; /* copy of mt row */
double lddate_mt; /* lddate of netmag row */
};
Each EVMoment structure represents a single row in the database mt table.
Individual detections are returned in EVDetection structures as defined below.
struct EVDetection {
EVDetection () {
recno_detection = -1;
lddate_detection = 0.0;
recno_site = -1;
presidual = -999.0;
sresidual = -999.0;
delta = -999.0;
}
long recno_detection; /* record number of detection row */
char record_detection[204]; /* copy of detection row */
double lddate_detection; /* lddate of detection row */
long recno_site; /* record number of site row */
char record_site[202]; /* copy of site row */
double presidual; /* P-arrival time residual */
double sresidual; /* S-arrival time residual */
double delta; /* origin-site distance */
};
Each EVDetection structure represents a single row in the database detection table.
Also, the associated station site row is stored in recno_site and record_site.
When a detection is associated with an origin, the origin to site distance is stored
in delta, the residual time relative to the predicted P-arrival time is stored
in presidual
and the residual time relative to the predicted S-arrival time is stored
in sresidual.
Individual arrival associations are returned in EVAssociation structures as defined below.
struct EVAssociation {
EVAssociation () {
recno_assoc = -1;
lddate_assoc = 0.0;
recno_arrival = -1;
lddate_arrival = 0.0;
recno_site = -1;
defining = 0;
}
long recno_assoc; /* record number of assoc row */
char record_assoc[190]; /* copy of assoc row */
double lddate_assoc; /* lddate of assoc row */
long recno_arrival; /* record number of arrival row */
char record_arrival[274]; /* copy of arrival row */
double lddate_arrival; /* lddate of arrival row */
long recno_site; /* record number of site row */
char record_site[202]; /* copy of site row */
int defining; /* Is this arrival defining? */
};
Each EVAssociation structure represents a single row in the database assoc table.
Also, the associated arrival arrival row is stored in recno_arrival
and record_arrival and the
associated station site row is stored in recno_site and record_site.
EVSERVER PROCESSING
The
EVServer objects keep up-to-date and complete lists of all database events as
a Table of
EVEvent structures. In order to save memory, the complete events
lists are always composed of abbreviated versions of the
EVOrigin structures.
The complete events vector can be querried by each of the
EVClient objects as
desired. These querries return copies of the events vector so that client-side processing
will not be effected by underlying database changes.
In addition to the events list maintained by EVServer objects, a list of recent
detections, within the last hour relative to system time or relative to the most recent
event time, is also maintained by EVServer objects as a Table of EVDetection
structures. These vectors can also be querried by client objects and returned as copies.
Note that the most recent detections list contains detections that have not been associated
with origins and therefore the delta and residual values are set to NULL values.
In addition to these lists, EVServer objects keep track of a set of particular events
as "expanded" events which are composed of EVEvent structures with expanded versions
of the EVOrigin structures that contain all of the detection and association
information. Clients can request expanded events by specifying their evid values.
Also, EVServer objects always keep track of the most recently modified event and
automatically promotes that event into the expanded event list.
By subclassing the EVClient class and defining the virtual responseCallback
method, client objects can be notified by the EVServer objects whenever the underlying
database changed drastically and had to be closed and re-opened, or the complete events
list has changed, or the detections list has changed, or any of the expanded events have
changed, or the most recently modified event has changed.
EVSERVER CONSTRUCTOR
EVServer(std::string dbname, int age_ref_now = 1, int max_events = -1, int check_nfs = 1)
With the following constructor arguments:
-
dbname
The name of the database to serve.
-
age_ref_now
If this flag is set then the age reference for processing the recent detections list
is relative to the system time. Otherwise it is relative to the most recent event time.
-
max_events
This determines the maximum number of events to process. If it is set to -1, then
all events will be processed. The last max_events events in the event
table will be processed.
-
check_nfs
If this is set to non-zero, then all of the database table files will be checked to insure
they are locally mounted. If any, other than the site table, are not locally mounted,
then the constructor will throw an error.
When the object is created the refreshEvents method is called once to initialize
the internal views.
EVSERVER METHODS
-
int refreshEvents (int force=0)
Will refresh all of the events. If force is non-zero, then the refresh
will force reprocessing of all database tables even if their modification dates have not
changed.
-
void autoRefreshEvents (double interval)
Sets the automatic views refresh interval to interval seconds. The refreshEvents
method will subsequently be called every interval seconds in a separate thread.
If interval is less than or equal to 0.0, then the automatic refreshing will
be disabled. For static databases it is not necessary to call this method.
-
void autoCheckDatabase (double interval)
Sets the automatic database table refresh interval to interval seconds.
This applies to the wfdisc, arrival and detection tables independent
of any event views. The tables
will subsequently be checked every interval seconds in a separate thread
and any changes will create client notifications through the EVClient::checkDatabaseCallback
method defined below.
If interval is less than or equal to 0.0, then the automatic database refreshing will
be disabled. For static databases it is not necessary to call this method.
-
std::string getDbname ();
This will return the database name of the database being managed by this server.
-
std::string getSchema ();
This will return the schema name of the database being managed by this server.
-
void setAgeRefNow (int value)
This sets the age reference for processing the recent detections list, as described in
the constructor.
-
void setMaxEvents (int max_events)
This sets the maximum events for processing the events list, as described in
the constructor.
-
int setPreferredMagnitudes (char *pf_string)
-
int setPreferredMagnitudes (Pf *pf)
These will set the preferred magnitude rankings according to a parameter
file as described previously.
-
static int findEvid (Table<EVEvent> *events, long evid)
This is a static method that will return the index within an events table
corresponding to the evid value evid or -1 if the evid value
is not within the table.
-
static long getSize (Table<EVEvent> *events)
this is a static method that will return the total byte size of an events vector
specified by events.
-
static long getSize (EVEvent *event)
this is a static method that will return the total byte size of a single event view
structure specified by event.
-
static long getSize (Table<EVDetection> *detections)
this is a static method that will return the total byte size of a detections vector
specified by detections.
-
static long getSize (EVDetection *detection)
this is a static method that will return the total byte size of a single detection view
structure specified by detection.
-
static long getSize (EVOrigin *origin)
this is a static method that will return the total byte size of a single origin view
structure specified by origin.
-
static long getSize (EVAssociation *association)
this is a static method that will return the total byte size of a single association view
structure specified by association.
-
static long getSize (EVMagnitude *magnitude)
this is a static method that will return the total byte size of a single magnitude view
structure specified by magnitude.
-
static long getSize (EVMoment *moment)
this is a static method that will return the total byte size of a single moment tensor view
structure specified by moment.
-
static int isEqual (EVEvent *event1, EVEvent *event2)
this is a static method that will return 1 if event1 is equal to event2,
or 0 otherwise.
-
static int isEqual (EVOrigin *origin1, EVOrigin *origin2)
this is a static method that will return 1 if origin1 is equal to origin2,
or 0 otherwise.
-
static int isEqual (EVMagnitude *magnitude1, EVMagnitude *magnitude2)
this is a static method that will return 1 if magnitude1 is equal
to magnitude2, or 0 otherwise.
-
static int isEqual (EVMoment *moment1, EVMoment *moment2)
this is a static method that will return 1 if moment1 is equal
to moment2, or 0 otherwise.
-
static int isEqual (EVAssociation *association1, EVAssociation *association2)
this is a static method that will return 1 if association1 is equal
to association2, or 0 otherwise.
-
static int isEqual (EVDetection *detection1, EVDetection *detection2)
this is a static method that will return 1 if detection1 is equal
to detection2, or 0 otherwise.
-
static void print (EVEvent *event, std::string pre=)
-
static void print (EVOrigin *origin, std::string pre=)
-
static void print (EVMagnitude *magnitude, std::string pre=)
-
static void print (EVMoment *moment, std::string pre=)
-
static void print (EVAssociation *association, std::string pre=)
-
static void print (EVDetection *detection, std::string pre=)
-
static void print (Table<EVEvent> *events, std::string pre=)
-
static void print (Table<EVOrigin> *origins, std::string pre=)
-
static void print (Table<EVMagnitude> *magnitudes, std::string pre=)
-
static void print (Table<EVMoment> *moments, std::string pre=)
-
static void print (Table<EVAssociation> *associations, std::string pre=)
-
static void print (Table<EVDetection> *detections, std::string pre=)
-
static void print (EVEvent *event1, EVEvent *event2, std::string pre=)
-
static void print (EVOrigin *origin1, EVOrigin *origin2, std::string pre=)
-
static void print (EVMagnitude *magnitude1, EVMagnitude *magnitude2, std::string pre=)
-
static void print (EVMoment *moment1, EVMoment *moment2, std::string pre=)
-
static void print (EVAssociation *association1, EVAssociation *association2, std::string pre=)
-
static void print (EVDetection *detection1, EVDetection *detection2, std::string pre=)
-
static void print (Table<EVEvent> *events1, Table<EVEvent> *events2, std::string pre=)
-
static void print (Table<EVOrigin> *origins1, Table<EVOrigin> *origins2, std::string pre=)
-
static void print (Table<EVMagnitude> *magnitudes1, Table<EVMagnitude> *magnitudes2, std::string pre=)
-
static void print (Table<EVMoment> *moments1, Table<EVMoment> *moments2, std::string pre=)
-
static void print (Table<EVAssociation> *associations1, Table<EVAssociation> *associations2, std::string pre=)
-
static void print (Table<EVDetection> *detections1, Table<EVDetection> *detections2, std::string pre=)
These are static debugging methods for printing out the contents of the various event
view structures plus vectors of structures and printing out the differences between
two event view structures and vectors of event view structures. The pre argument
is a string that is prefixed to each print line.
EVCLIENT CONSTRUCTOR
EVClient(EVServer *ev)
With the following constructor arguments:
-
ev
The event view server to use.
EVCLIENT METHODS
-
void refreshEvents (int wait_flagfP=0)
This will cause the server's refreshEvents method to be scheduled for execution
in the server's own thread.
If wait_flag is 0, then the actual execution on the server side will happen asynchronously with
this call at a time when the server is idle and this method will always return immediately.
If wait_flag is set, then the actual execution on the server side will happen synchronously with
this call and this method will block until the refresh has completed.
Notification of changes in the event views due to a refresh occur through
the EVClient::responseCallback method described below.
-
void refreshEventsForce (int wait_flagfP=0)
This is like refreshEvents but it forces reprocessing of all server database tables
even if their modification times have not changed.
-
void checkDatabase ()
This will check the wfdisc, arrival and detection tables, within the EVServer thread, independent
of any event views, for any changes. This method will block until the checking is complete.
Any changes will create client notifications through the EVClient::checkDatabaseCallback
method defined below.
-
void grabEventsLock ()
This will grab a mutex lock that the server uses whenever it is rewriting its event
view vectors. When the server refreshes its views, it holds the refreshed views in
temporary storage until all of the database processing has been done. When the view
structures are complete, the server replaces its internal object view structures and
vectors with the temporary structures and vectors all at once. During this replacement
the server grabs the events lock
so that clients who may be trying to access the view structures will not copy while
the server is in the middle of replacing its internal view structures. Client objects
should always grab the events lock before any attempts to access/copy server view structures
and vectors.
-
void releaseEventsLock ()
This will release the events mutex lock. Clients should always release the events lock
after they are done copying over new event view structures, otherwise the server and
other clients will be locked out of changing or accessing the server's internal event
view structures and vectors. A well behaved client will grab the lock, call the various
event view access methods it needs to call, then immediately release the lock before it
goes off to do other processing.
-
int eventsNumber ()
This returns the total number of events currently in the server's internal events views
vector.
-
long getEventsSize ()
This returns the total number of bytes of the events views currently in the server's internal
events views vector.
-
int detectionsNumber ()
This returns the total number of detections currently in the server's internal detections views
vector.
-
long getDetectionsSize ()
This returns the total number of bytes of the detections views currently in the
server's internal detections views vector.
-
int expandedNumber ()
This returns the total number of expanded events currently in the server's internal
expanded events views vector.
-
long getExpandedSize ()
This returns the total number of bytes of the expanded events views currently in the
server's expanded events views vector.
-
EVOrigin *findOrid (EVEvent *event, long orid)
This returns a pointer to the EVOrigin structure within an event, event,
corresponding to orid value orid or NULL if the orid value is not present in the event.
-
std::shared<Table<EVEvent>> getEvents ()
This returns a complete copy of the current server's events views vector containing all
events in the database through a shared pointer object.
-
int getEvent (int index, EVEvent &event)
This will copy the single event into event from the current
server's events views vector at index index.
-
int getEvent (long evid, EVEvent &event)
This will copy the single event with evid evid into event from the current
server's events views vector.
-
Table<EVDetection> getDetections ()
This returns a complete copy of the current server's detections views vector containing
detections within the last hour.
-
int containsExpandedEvent (long evid)
This returns 1 if the event with evid evid is currently in the server's
expanded events views vector, or 0 if it is not.
-
int getExpandedEvent (long evid, EVEvent &event)
This will copy the expanded event with evid evid into event. If the evid
is not in the server's expanded events vector, then it will be added. Returns 1
with success or 0 if the evid could not be found in the server's expanded
events views vector and also could not be found in the server's total events views vector.
-
int getLastModifiedEvent (EVEvent &event)
This will copy the server's last modified event into event. Returns 1
if there is a last modified event or 0 otherwise.
-
long getLastModifiedEvid ()
Returns server's last modified event evid value, or -1 if there is no
last modified event.
-
int getMostRecentEvent (EVEvent &event)
This will copy the server's most recent event into event. Returns 1
if there is a most recent event or 0 otherwise.
-
long getMostRecentEvid ()
Returns server's most recent event evid value, or -1 if there is no
last modified event.
-
Table<EVArrival> getArrivals (std::string sta, std::string chan, double t1, double t2)
This will return all of the arrival table rows for station sta, channel chan, between
epoch times t1 and t2. The arrival rows will be determined within the EVServer thread.
This method blocks until the arrival rows have been processed. The arrivals returned are independent
of event associations, if any.
The EVArrival structure is defined below.
/I>
struct EVArrival {
EVArrival () {
recno_arrival = -1;
lddate_arrival = 0.0;
link_to_any_assoc = 0;
link_to_any_stamag = 0;
link_to_any_wfmeas = 0;
}
long recno_arrival;
char record_arrival[274];
double lddate_arrival;
int link_to_any_assoc; # set if there are any links to the assoc table
int link_to_any_stamag; # set if there are any links to the stamag table
int link_to_any_wfmeas; # set if there are any links to the wfmeas table
};
/I>
-
Table<EVTableRecord> getWfdiscs (std::string sta, std::string chan, double t1, double t2, int calib_from_db)
This will return all of the wfdisc table rows for station sta, channel chan, between
epoch times t1 and t2. The wfdisc rows will be determined within the EVServer thread.
This method blocks until the wfdisc rows have been processed.
If calib_from_db is set to EVENTVIEW_CALIB_FROM_DB_YES or EVENTVIEW_CALIB_FROM_DB_NULLONLY,
then an attempt is made, within the EVServer thread, to join the
output wfdisc rows with the calibration table, using dbmatches(3). The calib, calper
and segtype from the joined calibration rows are then copied over to the output wfdisc rows,
unless calib_from_db is set to EVENTVIEW_CALIB_FROM_DB_NULLONLY and the original wfdisc
row calib value is not NULL (0.0).
If calib_from_db is set to EVENTVIEW_CALIB_FROM_DB_NO, then
no calib, calper or segtype substitutions are done.
The EVTableRecord structure is a generic structure for containing database row records and is defined below.
struct EVTableRecord {
EVTableRecord () {
recno = -1;
}
long recno;
std::string record;
};
-
std::string getWfdiscPath ()
This will return the absolute directory path of the wfdisc table which can be used to
compose external file absolute file names.
-
Table<EVTableRecord> getRawDetections (std::string sta, std::string chan, double t1, double t2)
This will return all of the detection table rows for station sta, channel chan, between
epoch times t1 and t2. The detection rows will be determined within the EVServer thread.
This method blocks until the detection rows have been processed. The detections returned are independent
of event associations, if any.
-
EVTableRecord getSite (std::string sta, double time)
This will return the site table row for station sta and
epoch time time. The site row will be determined within the EVServer thread.
This method blocks until the site row has been processed.
-
Table<EVStaChan> scanWfdisc (std::string sta_expr=std::string(),
std::string chan_expr=std::string(), double t1=-1.e30, double t2=1.e30)
This will scan all wfdisc table rows within the EVServer thread for rows where sta
matches sta_expr, chan matches chan_expr and time is less than t2
or endtime is greater than t1. If sta_expr or chan_expr are empty, then
all stations or channels match. This method blocks until the wfdisc is processed.
The output is a table of matches in EVStaChan structures as defined below.
struct EVStaChan {
EVStaChan () {
memset (this, 0, sizeof(EVStaChan));
}
char sta[32];
char chan[32];
double time; # overall start time for this sta, chan
double endtime; # overall end start time for this sta, chan
};
-
Table<EVTableRecord> dbmatches (std::string dbk_table, std::string dbk_record,
std::string dbt_table, Tbl **kpattern, Tbl **tpattern, Hook **hook)
This will perform a dbmatches(3) in the EVServer thread. The dbmatches(3) dbk database
pointer is set to the dbk_table table, scratch record, with the scratch record set to dbk_record.
The dbmatches(3) dbt database pointer is set to the dbt_table table.
The kpattern, tpattern and hook arguments are the same as in dbmatches(3).
The matches are returned as a table of EVTableRecord structures corresponding to the rows
in the dbt_table table that match.
This method blocks until all EVServer processing is done.
-
Table<EVTableRecord> dbsubset (std::string table_name, std::string subset_expr)
This will perform a dbsubset(3) in the EVServer thread. The dbsubset(3) db database
pointer is set to the table_name table.
The dbmatches(3) s subset expression is set to subset_expr.
The subset is returned as a table of EVTableRecord structures corresponding to the rows
in the table_name table that match the subset expression.
This method blocks until all EVServer processing is done.
-
int dbputrecord (std::string table_name, long recno, long id, std::string record)
This will perform a dbput(3) or dbadd(3) in the EVServer thread. The table name to add or put
is specified by table_name. If recno is < 0, then dbadd(3) is called in the EVServer thread,
otherwise dbput(3) is called in the EVServer thread and the database pointer record is set to recno.
If id >= 0 and the table name is arrival, origin or event and recno is >= 0, then
the arid, orid or evid values from the existing database rows are checked against id
as a consistency check.
The database record to add or put is specified in record.
This method blocks until all EVServer processing is done.
Errors are indicated by a return value of -1.
Note that in this method care is taken to force file modification time changes when executing dbput(3) so
that database callbacks will get executed.
-
long dbnextid (std::string id_name)
This will return the next database id by running dbnextid(3) in the EVServer thread for id
name id_name (e.g. arid, orid, etc.).
This method blocks until all EVServer processing is done.
-
int getDbptr (EVEvent *event, Dbptr *dbptr_event)
This will fill in a proper Datascope database pointer into dbptr_event, if it
is not NULL, from the event view structure event. A temporary empty database is created
when the EVClient is created using the server's database schema. The database
pointer returned here points to that temporary database with the table set to event
and the scratch record copied from the event row record in the EVEvent event
structure. Normal Datascope dbgetv(3) can then be used to access the record fields as well
as dbex_eval(3) for evaluating expressions.
-
int getDbptr (EVOrigin *origin, Dbptr *dbptr_origin, Dbptr *dbptr_origerr=NULL)
This will fill in a proper Datascope database pointer into dbptr_origin, if it
is not NULL, from the origin view structure origin. A temporary empty database is created
when the EVClient is created using the server's database schema. The database
pointer returned here points to that temporary database with the table set to origin
and the scratch record copied from the origin row record in
the EVOrigin origin
structure. Normal Datascope dbgetv(3) can then be used to access the record fields as well
as dbex_eval(3) for evaluating expressions.
In addition, if dbptr_origerr is not NULL, then it will be filled in with the scratch
record of the origerr row record in the EVOrigin origin structure.
-
int getDbptr (EVMagnitude *magnitude, Dbptr *dbptr_netmag)
This will fill in a proper Datascope database pointer into dbptr_netmag, if it
is not NULL, from the magnitude view structure magnitude. A temporary empty
database is created
when the EVClient is created using the server's database schema. The database
pointer returned here points to that temporary database with the table set to netmag
and the scratch record copied from the netmag row record in
the EVMagnitude magnitude
structure. Normal Datascope dbgetv(3) can then be used to access the record fields as well
as dbex_eval(3) for evaluating expressions.
-
int getDbptr (EVMoment *moment, Dbptr *dbptr_mt)
This will fill in a proper Datascope database pointer into dbptr_mt, if it
is not NULL, from the moment view structure moment. A temporary empty
database is created
when the EVClient is created using the server's database schema. The database
pointer returned here points to that temporary database with the table set to mt
and the scratch record copied from the mt row record in
the EVMoment moment
structure. Normal Datascope dbgetv(3) can then be used to access the record fields as well
as dbex_eval(3) for evaluating expressions.
-
int getDbptr (EVAssociation *association, Dbptr *dbptr_assoc, Dbptr *dbptr_arrival=NULL, Dbptr *dbptr_site]fB=NULL)
This will fill in a proper Datascope database pointer into dbptr_assoc, if it
is not NULL, from the association view structure associaiton. A temporary empty database is created
when the EVClient is created using the server's database schema. The database
pointer returned here points to that temporary database with the table set to assoc
and the scratch record copied from the assoc row record in
the EVAssociation association
structure. Normal Datascope dbgetv(3) can then be used to access the record fields as well
as dbex_eval(3) for evaluating expressions.
In addition, if dbptr_arrival is not NULL, then it will be filled in with the scratch
record of the arrival row record in the EVAssociation association structure
and similar for the dbptr_site and the site record.
-
int getDbptr (EVDetection *detection, Dbptr *dbptr_detection, Dbptr *dbptr_site=NULL)
This will fill in a proper Datascope database pointer into dbptr_detection, if it
is not NULL, from the detection view structure detection. A temporary empty database
is created
when the EVClient is created using the server's database schema. The database
pointer returned here points to that temporary database with the table set to detection
and the scratch record copied from the detection row record in
the EVDetection detection
structure. Normal Datascope dbgetv(3) can then be used to access the record fields as well
as dbex_eval(3) for evaluating expressions.
In addition, if dbptr_site is not NULL, then it will be filled in with the scratch
record of the site row record in the EVDetection detection structure.
-
int getDbptr (std::string table, char *record, Dbptr *dbptr)
This is a utility method that will take a database table row record in record and
put it into the scratch record of the table table and return a database pointer in
dbpr.
-
void printDifferences (Table<EVEvent> *events)
This is a debugging method which will print out all of the differences between the
server's total events view vector and another vector specified by events.
-
static EVOrigin *getPreferredOrigin (EVEvent *event)
This is a static method that will return the preferred origin as an origin view structure
for the event view event.
-
static EVMoment *getPreferredMoment (EVEvent *event)
This is a static method that will return the preferred moment as a moment view structure
for the event view event.
-
static EVMoment *getPreferredMoment (EVOrigin *origin)
This is a static method that will return the preferred moment as a moment view structure
for the origin view origin.
-
static void getOrigin (EVEvent *event, long orid, EVOrigin &origin)
This is a static method that will fill in the origin view structure origin for the
origin with orid orid from event view event.
-
virtual void responseCallback (EVResponse response)
This is protected virtual method that should be implemented in EVClient
subclasses. This method will be called by EVServer objects whenever any of the underlying
event views have changed. This method is called with a single argument response.
The EVResponse structure is defined below.
/B>
struct EVResponse {
EVResponse () {
database_reset = 0;
events_changed = 0;
detections_changed = 0;
last_modified_event_changed = 0;
last_modified_event_evid = -1;
most_recent_event_changed = 0;
most_recent_event_evid = -1;
}
int database_reset;
int events_changed;
int detections_changed;
int last_modified_event_changed;
long last_modified_event_evid;
int most_recent_event_changed;
long most_recent_event_evid;
Table<long> expanded_events_changed;
Table<long> expanded_events_erased;
};
/B>
-
If the database has been reset due to access errors or files shrinking,
then database_reset is set.
If the server's internal complete list of events
has changed, then events_changed is set.
If the server's internal list of detections
has changed, then detections_changed is set.
If the server's last modified event
has changed, then last_modified_event_changed is set.
The most recent evid value of the last
modified event is set in last_modified_event_evid.
If the server's most recent event
has changed, then most_recent_event_changed is set.
The evid value of the most recent event is set in most_recent_event_evid.
A Table containing the evid values of all of the expanded events that have changed
is in expanded_events_changed.
A Table containing the evid values of all of the expanded events that were removed
is in expanded_events_erased.
-
Note that this callback by necessity is executed in the EVServer thread.
It will usually be advisable for any client actions that are a result of this callback
to be executed in the client's thread. It is the responsibility of the application programmer
to arrange for this to happen.
-
virtual void checkDatabaseCallback (Array<std::string, int> changes)
This is protected virtual method that should be implemented in EVClient
subclasses. This method will be called by EVServer objects whenever any of
the wfdisc, arrival or detection tables change regardless of their event associations.
This method is called with a single argument changes which is an associative array whose keys
are database table names and values are integers that are EVENTVIEW_TABLE_UNCHANGED,
if the table is unchanged, or EVENTVIEW_TABLE_BIGGER,
if the table has increased in size, or EVENTVIEW_TABLE_SMALLER,
if the table has decreased in size, or EVENTVIEW_TABLE_MODIFIED,
if the table is the same size but has been changed.
-
Note that this callback by necessity is executed in the EVServer thread.
It will usually be advisable for any client actions that are a result of this callback
to be executed in the client's thread. It is the responsibility of the application programmer
to arrange for this to happen.
-
int getValue (Table<EVEvent> *events, std::string query, int *type, void *value)
This provides a method for retrieving values from the EVEvent and EVOrigin structure lists using
string queries. This is mainly useful for interpreter extension.
In this method events refers to a table of EVEvent structures, query is the query string
and the value and type of value are returned in value and type.
An example of the query syntax for this method is as follows.
-
int getValue (Table<EVEvent> *events, std::string query, int *type, void *value)
This provides a method for retrieving values from the EVEvent and EVOrigin structure lists using
string queries. This is mainly useful for interpreter extension.
In this method events refers to a table of EVEvent structures, query is the query string
and the value and type of value are returned in value and type.
An example of the query syntax for this method is as follows.
-
events[0].origins[0].record_origin{lat}
-
This query refers to a complete list of events (events), with the single event at the 0th index ([0]),
with the single origin at the 0th index of all origins for this event (origins[0]), using the Datascope complete
row record for that origin (record_origin) and evaluating the Datascope expression lat for that
record ({lat}). This particular expression would return the double latitude of that origin
in *value and set *type to EVENTVIEW_TYPE_DOUBLE.
The parameter values for a single event (EVEvent structure) are
defined as follows.
-
origins[<index>]
The list of origins corresponding to the event. This must be accompanied by an index, <index>, to chose the particular
origin. The <index> value may be an integer index number, or it may be the keyword pref_origin, in which
case the index for the preferred origin for this event will be substituted.
If there are no further fields in the query, then *value is returned as a pointer to the EVOrigin
structure and *type is set to EVENTVIEW_TYPE_EVORIGIN_PTR. If there are further fields
then this act as the reference origin for further evaluations.
-
norigins
This is the number of origins for this event.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
record_event
The Datascope complete character string record for this event.
The event record string is copied into *value
and *type is set to EVENTVIEW_TYPE_STRINGPTR.
-
recno_event
The row number in the Datascope event table for this event.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
evid
The evid attribute for this event
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
prefor
The prefor attribute for this event
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
lddate_event
The lddate attribute for this event
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
lddate_view
The maximum lddate attribute for all of the origins and all joined assoc, arrival,
netmag, stamag, mt and detection tables for this event.
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
magnitude
This is the overall event preferred magnitude.
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
magtype
This is the overall event preferred magnitude type.
The magnitude type string is copied into *value
and *type is set to EVENTVIEW_TYPE_STRINGPTR.
-
pref_origin
This is the index within the origins list corresponding to the preferred origin for this event.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
pref_magnitude_origin
This is the index within the origins list corresponding to the origin with the preferred magnitude for this event.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
pref_moment_origin
This is the index within the origins list corresponding to the origin with the preferred moment tensor for this event.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
Expressions within a single origin structure are evaluated as follows
-
nmagnitudes
This is the number of magnitudes for this origin.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
nmoments
This is the number of moment tensors for this origin.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
nassociations
This is the number of arrival associations for this origin.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
ndetections
This is the number of detections associated with this origin.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
record_origin
The origin record string is copied into *value
and *type is set to EVENTVIEW_TYPE_STRINGPTR.
The Datascope complete character string record for this origin.
-
recno_origin
The row number in the Datascope origin table for this origin.
-
record_origerr
The Datascope complete character string record for the origerr corresponding to this origin.
The origerr record string is copied into *value
and *type is set to EVENTVIEW_TYPE_STRINGPTR.
-
recno_origerr
The row number in the Datascope origerr table corresponding to this origin.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
orid
The orid attribute for this origin.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
preferred
This flag is set if the origin is the preferred origin for the event.
The *value is returned as a long int
and *type is set to EVENTVIEW_TYPE_LONG.
-
lddate_origin
The lddate attribute for this origin.
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
lddate_origin_view
The maximum lddate attribute for this origin and all of the joined assoc, arrival,
netmag, stamag, mt and detection tables for this origin.
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
time
The time attribute for this origin.
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
magnitude
This is the overall origin preferred magnitude.
The *value is returned as a double
and *type is set to EVENTVIEW_TYPE_DOUBLE.
-
magtype
This is the overall origin preferred magnitude type.
The magnitude type string is copied into *value
and *type is set to EVENTVIEW_TYPE_STRINGPTR.
Whenever a single Datascope complete record string is at the end of the expression it can be follow
by {<dbexpr>}. When this is done the regular Datascope expression <dbexpr> is evaluated against the record.
-
int getValue (Table<EVOrigin> *origins, std::string query, int *type, void *value)
This is like the EVEvent list method except it applies to lists of EVOrigin structures.
When using this method the query string should start with origins.
The following methods apply to the manipulation of sorting tab lists that can be used to
implement indirect referencing into lists of EVEvent and EVOrigin structures. These
provide high performance methods for rearranging event and origin lists to, for instance,
display sorted lists in spreadsheet applications.
-
static void setEventsTabs(EVEventsTab *view, Table<int> *sort_tab=NULL)
This static method will set a previously allocated EVEventsTab structure according
to a sort_tab list which should contain the sorted indexes from a particular list
of EVEvent structures. If sort_tab is NULL, then the sorting index reference values
are the same as the index values. EVEventsTab structure should be created and initialized by the
following constructors.
-
EVEventsTab (EVClient *evclient)
This will create an EvEVentsTab structure and initialize it with a fresh
copy of the EVEvent list from an EVClient object. The EVServer
events lock is not used in this constructor so the application code should lock and release the server
events lock as needed.
-
EVEventsTab (std::shared_ptr<Table<EVEvent>> ptr)
In this version of the constructor a shared pointer, ptr to a list of EVEvent structures
has already been determined and is used to initialize the EVEventsTab structure.
-
static void setOriginsTabs(EVOriginsTab *view, Table<int> *sort_tab=NULL)
This static method will set a previously allocated EVOriginsTab structure according
to a sort_tab list which should contain the sorted indexes from a particular list
of EVOrigin structures. If sort_tab is NULL, then the sorting index reference values
are the same as the index values. EVOriginsTab structure should be created and initialized by the
following constructors.
EVOriginsTab (Table<EVOrigin> *origins)
This will create an EVOriginsTab structure and initialize it with
the EVOrigin list from origins.
-
void sort (EVEventsTab *view, std::string query, int reverse)
-
void sort (EVOriginsTab *view, std::string query, int reverse)
These EVClient object methods will sort lists of EVEvent structures or EVOrigin structures,
defined within the EVEventsTab and EVOriginsTab structures, using the string query
evaluation expression. If reverse is non-zero, then the sort order is reversed. The EVEventsTab
and EVOriginsTab structures must be previously allocated and initialized using the constructors
defined previously. The syntax of query is as defined previously with the getValue methods,
except that the initial events[<index>]. or origins[<index>]. should
be omitted since the list indexing is manipulated automatically during the sort processing. Note
that the expression value types will determine how the sort is conducted; i.e. numerical types will sort
using numerical comparisons and string types will sort using string comparisons. The results of
the sorting are returned within the EVEventsTab and EVOriginsTab structures.
-
Table<int> sort (Table<EVEvent> *events, std::string query, int reverse)
-
Table<int> sort (Table<EVOrigin> *origins, std::string query, int reverse)
This is a second form of the sorting methods defined previously. In this form the lists of EVEvent
or EVOrigin structures is input directly, through events or origins, and the
sorted indexes into the input lists are returned as tables of integers. The returned tables of integers
could then be used by the setEventsTabs and setOriginsTabs static methods to set the
sort order into EVEventsTab and EVOriginsTab structures.
-
static int getRow (EVEventsTab *view, int index)
-
static int getRow (EVOriginsTab *view, int index)
These static methods will return the row corresponding to the list index index for
sorted EVEvent and EVOrigin lists. By "index" we mean the index within the
original unsorted lists and by "row" we mean the sorted order of that index, for instance a
row in a sorted spreadsheet.
-
static int getIndex (EVEventsTab *view, int row)
-
static int getIndex (EVOriginsTab *view, int row)
These static methods will return the index corresponding to the sorted row row for
sorted EVEvent and EVOrigin lists. By "index" we mean the index within the
original unsorted lists and by "row" we mean the sorted order of that index, for instance a
row in a sorted spreadsheet.
-
static int findEvidRow (EVEventsTab *view, long evid)
This static method will return the sorted row corresponding to the EVEvent structure
with evid evid.
-
static int findEvidIndex (EVEventsTab *view, long evid)
This static method will return the original list index corresponding to the EVEvent structure
with evid evid.
-
static int findOridRow (EVOriginsTab *view, long orid)
This static method will return the sorted row corresponding to the EVOrigin structure
with orid orid.
-
static int findOridIndex (EVOriginsTab *view, long orid)
This static method will return the original list index corresponding to the EVOrigin structure
with orid orid.
EXAMPLE
Following is a simple c++ example code that will monitor a database. The
event view structures are printed out when the EVServer
first opens and
reads the database and then differences are printed out whenever the database
changes (this requires setting the refresh_interval program argument to a positive
number).
/B>
/* A test for the EV classes. */
#include "EV.h"
class MyEVClient : public EVClient {
public:
MyEVClient (EVServer *ev) : EVClient (ev) {}
Table<EVEvent> events;
Table<EVDetection> detections;
EVEvent last_modified_event;
EVEvent most_recent_event;
protected:
void responseCallback (EVResponse response);
};
void MyEVClient::responseCallback (EVResponse response) {
printf ("MyEVClient::processEVCallback");
if (response.database_reset) printf (" database_reset");
if (response.events_changed) printf (" events_changed");
if (response.detections_changed) printf (" detections_changed");
if (response.last_modified_event_changed) printf (" last_modified_event_changed");
if (response.most_recent_event_changed) printf (" most_recent_event_changed");
printf ("\n");
Table<EVEvent> events_tmp;
Table<EVDetection> detections_tmp;
EVEvent last_modified_event_tmp;
EVEvent most_recent_event_tmp;
grabEventsLock();
if (response.events_changed) {
events_tmp = getEvents();
}
if (response.detections_changed) {
detections_tmp = getDetections();
}
if (response.last_modified_event_changed) {
getLastModifiedEvent (last_modified_event_tmp);
}
if (response.most_recent_event_changed) {
getMostRecentEvent (most_recent_event_tmp);
}
releaseEventsLock();
if (response.events_changed) {
printf ("events changes:\n");
EVServer::print (&events, &events_tmp);
events = events_tmp;
}
if (response.detections_changed) {
printf ("detections changes:\n");
EVServer::print (&detections, &detections_tmp);
detections = detections_tmp;
}
if (response.last_modified_event_changed) {
printf ("last_modified_event changes:\n");
EVServer::print (&last_modified_event, &last_modified_event_tmp);
last_modified_event = last_modified_event_tmp;
}
if (response.most_recent_event_changed) {
printf ("most_recent_event changes:\n");
EVServer::print (&most_recent_event, &most_recent_event_tmp);
most_recent_event = most_recent_event_tmp;
}
}
int
main (int argc, char **argv)
{
if (argc != 1 && argc != 2 && argc != 3) {
fprintf (stderr, "usage:ev_test [dbname [refresh_interval]]\n");
exit (1);
}
char *dbname;
if (argc == 1) {
dbname = (char *) "/opt/antelope/data/db/demo/demo";
} else {
dbname = argv[1];
}
double interval = 0.0;
if (argc == 3) interval = atof(argv[2]);
EVServer *ev;
if (interval > 0.0) {
ev = new EVServer ( dbname );
} else {
ev = new EVServer ( dbname, 0 );
}
MyEVClient *evcl = new MyEVClient ( ev );
evcl->grabEventsLock();
evcl->events = evcl->getEvents();
evcl->detections = evcl->getDetections();
evcl->getLastModifiedEvent (evcl->last_modified_event);
evcl->getMostRecentEvent (evcl->most_recent_event);
evcl->releaseEventsLock();
printf ("Events:\n");
EVServer::print (&(evcl->events), " ");
printf ("\nDetections:\n");
EVServer::print (&(evcl->detections), " ");
printf ("\nLast Modified Event:\n");
EVServer::print (&(evcl->last_modified_event));
printf ("\nMost Recent Event:\n");
EVServer::print (&(evcl->most_recent_event));
if (interval <= 0.0) exit (0);
ev->autoRefreshEvents ( interval );
printf ("refreshing every %f seconds\n", interval);
pause();
exit (0);
}
/B>
BUGS AND CAVEATS
In this implementation of the EV classes, all of the objects are in the same address space.
In the future we plan on expanding this so that the server and clients can be in different
address spaces (processes) linked by ORB-based or TCP/IP based communications links.
Because the current implementation puts all servers and clients in the same address
space and because Datascope is not thread safe and it shares resources for a single database
across all database opens within the same address space, it is dangerous for clients to
try any direct database accesses to the database managed by the event view servers. Client
threads should not use any Datascope routines other than dbgetv(3) and dbex_eval(3)
and only those routines with the temporary database pointers returned by the various
server getDbptr methods.
SEE ALSO
Table(3)
AUTHOR
Danny Harvey, BRTT