The notes here describe the use of Antelope's Datascope database system with Fortran90. Antelope is a product of Boulder Real-Time technologies, Inc. www.brtt.com. Here I show some examples for using F90 and how you are supposed to write your codes.
How do I write a Makefile?How do I define Antelope variables?
How do I open a database?
How do I open a specific table from a database?
How many records has my table?
How do I sort a table?
How do I make a subset of a table?
How do I join two tables?
How do I create a database out of my joined view?
How do I get some values from the tables?
How do I put some value in a given table?
How do I put new values (new line) in a table?
What if I want to delete a row from a table?
top
How do I write a Makefile?
This is sometimes difficult to do. Sometimes it can create all the problems in your coding.
------------- Example 1 ------------- BIN = program_name cflags = -g fflags = -g ldlibs = $(STOCKLIBS) $(TRLIBS) $(DBLIBS) include $(ANTELOPEMAKE) DIRS= OBJS = program_name.o $(BIN) : $(OBJS) $(RM) $@ $(FC) $(FFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS) --------------------------------------------------------------------- ------------- Example 2 ------------- BIN = program_name2 cflags = -g fflags = -g ldlibs = $(STOCKLIBS) $(TRLIBS) $(DBLIBS) include $(ANTELOPEMAKE) DIRS= OBJS = program_name1.o $(BIN) : $(OBJS) $(RM) $@ $(FC) $(FFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS) OBJS2 = program_name2.o program_name2 : $(OBJS2) $(RM) $@ $(FC) $(FFLAGS) -o $@ $(OBJS2) $(LDFLAGS) $(LDLIBS) ------------------------------------------------------------------------top
How do I define Antelope variables?
Using antelope, there are some issues defining variables 1.- The db tables, or in this case, db pointers are defined integer :: db(4), db_origin(4), db_wfdisc 2.- All reals in Antelope are real(8). real(8) :: yyyy, xxxxx 3.- Include the appropiate libraries include "/home/gprieto/fortran/antelope/include/db.i" include "/home/gprieto/fortran/antelope/include/coords.i" Here, note that I'm not linking to the $ANTELOPE libraries for fortran, since they don't work with F90 (due to the last commented line starting with c ... ; where the date and copyright is typed). The copies I have here have the last line removed. 4.- Use the appropiate length for characters. Very important. character (len=8) :: net, phase character (len=6) :: magtype, sta character (len=15) :: auth ---------------------------------------------------------------------top
How do I open a database?
To open a database just use
---------- if ( dbopen ( 'database_name',"r+", db) /= 0 ) then write(6,'(a)') 'Bad, problem when opening database' endif ----------
The value "db" will be the one used later in the code.
Note that dbopen is not called, as a subroutine. It returns an integer, which should be zero when it succeeds. A different number means an error.
This code prints out when there is a problem, but won't stop the program.
---------------------------------------------------------------------------
topHow do I open a specific table from a database?
This is quite simple, using this idea
---------- call dblookup (db__origin, db, "", "origin", "","") call dblookup (db__stamag, db, "", "stamag", "","") call dblookup (db__xxxxxx, db, "", "xxxxxx", "","") ----------
Note all the empty spaces. ALL of them are needed.
In matlab there is a easier approach "dblookup_table", which I think its not available for Fortran.
---------------------------------------------------------------------------
topHow many records has my table?
These here is to get the number of lines in a given table (arrival, event, etc) or even subsetted or joined tables.
---------- call dbquery(db_origin, dbRECORD_COUNT, nrecords) print *, 'Origin table with ', nrecords ---------- --------------------------------------------------------------------------top
How do I sort a table?
Here, one can sort tables using the default keys; or you could assign the keys to be used.
Also you have to chance to
- Reverse sorting
- Unique sorting
In general the syntax is integer :: db(4) integer :: keys, flag call dbsort(db,db, keys, flag,"comment")
The keys, when you leave them out (I think leave a zero) will use dbsort with standard keys. You should use, or define the keys anyway, to avoid problems.
The flag, is use to set the way dbsort works. When flag=0, the usual dbsort works. If flag=1, a reverse order dbsort is called, and if flag=2, a unique sort is used.
------------- Example 1 ------------- Defining the Primary keys call dbquery ( db, dbPRIMARY_KEY, keys ) call dbsort ( db, db, keys, 0, "sort_origin" ) Note here, the Primary keys are used. --------------------------------------------------------------------- ------------- Example 2 ------------- call strtbl (keys,"origin.time","origin.orid","origin.lat", & 'origin.lon','origin.depth',0) call dbsort(dbj, db_origin, keys, 2,"") ! the 2 means unique sort Here, I fixed the keys that are going to be used to sort the table. ---------------------------------------------------------------------top
How do I make a subset of a table?
Here is a simple example. Note that the syntax of the subset is the one of Antelope, not of Fortran. This means that not equal isn't .ne. or /=. In C syntax, this would be !=.
------------- Example 1 ------------- character (len=XXX) == txtsubset integer :: db(4) write(txtsubset,*) trim(txtsubset)//' && prefor==orid' call dbsubset( db, db, trim(txtsubset), "comment") call dbquery(dbj, dbRECORD_COUNT, nrecords) print *, 'Lines after subsetting table with ', nrecords ------------- Example 2 ------------- character (len=50) :: expression integer :: db(4) write ( expression, * ) "evid ==", evid call dbsubset ( db, db, expression , "event") ----------------------------------------------------------------------top
How do I join two tables?
To join two tables, first one has to open them, of course, and use dbjoin
the syntax isinteger :: dbout(4), db1(4), db2(4) integer :: keys1, keys2 call strtbl(keys1,"sta","yyyyyyy.time",0) ! keys for table db1 call strtbl(keys2,"sta","xxxxxxx.time",0) ! keys for table db2 call dbjoin(dbout,db1,db1,keys1,keys2,0,0,"")
If you want Datascope to select the appropiate keys, set keys=0 like example 1.
------------- Example 1 ------------- integer :: db_netmag(4), db_stamag(4), db_netsta(4), dbj(4) integer :: n_netsta ! ! Open main table ! if ( dbopen ( 'all_data',"r", db) /= 0 ) then write(6,'(a)') 'Bad, problem when opening database' endif ! ! Open individual tables ! call dblookup (db_stamag, db, "", "stamag", "","") call dblookup (db_netmag, db, "", "netmag", "","") ! ! Join tables ! call dbjoin(db_netsta,db_netmag,db_stamag,0,0,0,0,"") call dbquery(db_netsta, dbRECORD_COUNT, n_netsta) print *, 'Rows netmag table with ', n_netsta ----------------------------
However, sometimes, you want to join tables that are not symmetrical. For example, if you go
event/origin/assoc/arrival/wfdiscit might give you a different result than going
wfdisc/arrival/assoc/origin/event
But you don't want to start with wfdisc, because it might be too big to handle. This discrepancy comes from the fact that since you start with event-origin the join KEYS are going to be origin.time and others. And when you want to join wfdisc, the origin.time isn't necessarily in the wfdisc.time::endtime range.
So it won't join.To correct this, before you make the last join, you have to change the JOIN KEYS to arrival.time wfdisc.time::endtime. Note however, that if you set a new key, you have to set ALL keys again. If you do not do that it would join ONLY with the time keys, and you might want to use the station as well.
Here is the example to do this.Assuming dbj is the join of
event/origin/assoc/arrival ------------- Example 2 ------------- call dbquery(dbj, dbRECORD_COUNT, nrecords) print *, 'Event/Origin/Assoc/Arrival table with ', nrecords ! ! Define the parameter to do the last join ! call strtbl(keys1,"sta","arrival.time",0) call strtbl(keys2,"sta","time::endtime",0) ! ! Open wfdiisc table ! call dblookup (db_wf, db, "", "wfdisc","","") call dbquery(db_wf, dbRECORD_COUNT, nrecords) print *, 'Lines in the wfdisc table ', nrecords ! ! Do the final join, event/origin/assoc/arrival/wfdisc ! call dbjoin(dboutput,dbj,db_wf, keys1, keys2,0,0,"") call dbquery(dboutput, dbRECORD_COUNT, nrecords) print *, 'Final join ev/or/assoc/arr,wfdisc table with ', nrecords ----------------------------------------------------------------------top
How do I create a database out of my joined view?
If you want to save a database from a joined and subsetted view that comes from your fortran code, you use dbunjoin
Assuming dboutput is the joined and subsetted table you want to save
------------- Example 1 ------------- integer :: dboutput(4) if (dbunjoin( dboutput, 'new_database',0) /= 0) then write (6,'(a)') 'Error saving the database table' endif ------------------------------------------------------------------------top
How do I get some values from the tables?
This helps you to get values from db tables. It can be used in single tables or joined tables.
Remember that for C/Datascope the first line is actually the zeroth term
Remember to set all the values to the right denomination, remember reals are always real(8). If you would like to get a vector, like a matlab code would do, use this example.
Assuming you know the number of lines in your table------------- Example 1 ------------- integer :: db(4) integer :: iget, nrecords, i allocate(time(nrecords)) allocate(lat(nrecords)) allocate(lon(nrecords)) allocate(depth(nrecords)) allocate(orid(nrecords)) allocate(evid(nrecords)) allocate(ml(nrecords)) allocate(mlid(nrecords)) allocate(auth(nrecords)) do i = 1,nrecords db(4) = i-1 iget = dbgetv (db,0, & "origin.time", time(i), & "origin.lat", lat(i), & "origin.lon", lon(i), & "origin.depth", depth(i), & "origin.orid", orid(i), & "origin.evid", evid(i), & "origin.ml", ml(i), & "origin.auth", auth(i), & 0) enddo ---------------------------------------------------------------------
If you actually don't want a vector of the values, and want to use the values inside the loop, use this code here. Remember the i-1 factor always.
------------- Example 2 ------------- do i = 1,nrecords k = i-1 db(4) = k iget = dbgetv (db,0, & "origin.time", time, & "origin.lat", lat, & "origin.lon", lon, & "origin.depth", depth, & "origin.orid", orid, & "origin.evid", evid, & "origin.ml", ml, & "origin.auth", auth, & 0) !!!! Do something with the individual values enddo ---------------------------------------------------------------------top
How do I put some value in a given table?
If for example you measured a magnitude, say mb, ml, and you want to put that value in the database, because is -999.00 (the default), you use dbputv.
Be EXTREMELY careful, dbputv doesn't work very intuitevely if you use it on sorted tables.
dbputv only works in individual tables, and in the syntax you are supposed to especify whihc table you are editing.
Again, be extremely careful, this does NOT tell you if you are replacing an existing value. Do not use it on sorted tables.
Also, always use dbnextid to avoid repeating id values (mlid, wfid, etc)-------------- Example 1 -------------- integer :: db(4) integer :: j, idml real(8) :: ml ! remember real(8) ml = 5.0 (or any value from anywhere) do j = 1,nrecords idml = dbnextid(db, 'mlid') iput = dbputv (db,"origin", & "origin.ml", ml, & "origin.mlid", idml, & 0) enddo ---------------------------------------------------------------------------top
How do I put new values (new line) in a table?
Say you have a new waveform, or new netmag line, with couple of stamag lines. You need to add a new line at the end of the appropiate table. You use dbaddv.
dbaddv adds a NEW line, creating empty (actually the appropiate null values are put in with the dbSCRATCH).
The advantage of dbaddv is that it checks to ensure that you do not repeat Primary keys, and that id's are new (mlid, wfid, orid, etc).
------------------- Example 1 ------------------- db(4) = dbaddv (db,"table_name", & "magid", magid, & "sta", sta, & "arid", arid, & "orid", orid, & "evid", evid, & "phase", phase, & "magtype", magtype, & "magnitude", magnitude, & "uncertainty", uncertainty, & "auth", auth, & "commid", commid, & 0) -----------------------------
Note, how dbaddv (as well as dbputv, dbgetv) returns an integer. Zero is success. Note also the pairwise syntax. Remember the real(8) and the appropiate description of each of the variables. Do not put a character in mlid (who knows what comes out).
"table_name" can be wfdisc, event, origin, stamag, netmag, etc. You can only put values that belong to that table, do not use in joined tables. This wouldn't work and it would give an error. This example is for the "stamag" table.
---------------------------------------------top
What if I want to delete a row from a table?
Say for example, you would like to delete some rows of a given table. For example you only want a table with a given orid's, which are not sequential.
You can loop through each line (I don't know if this is the most efficient way to do it, but works for me) and test whether that orid is what you want, and if not, delete that row.
Remember you need to open the database with permission, or you save a new database with dbunjoin.
This works with single tables or joined ones. The idea is to use it on joined ones, or to later join the "chopped" table to others.
Note how the loop is read backwards. Everytime you remove a row, the rows move up one step. So you have to do it backwards to avoid removing lines you actually want, or making the ith loop to be larger than the number of lines in the chopped table.
---------- Example 1 ---------- ! ! Read the table in reverse order (Thus last entry is obeyed) ! do i = nrecords, 1, -1 dbj(4) = i - 1 ievid = dbgetv(dbj,0,"evid",evidid,0) isave = 0 do k = 1,nx if (evidid == evid(k)) then isave = 1 exit endif enddo if (isave == 0) then idel = dbdelete(dbj) endif enddo call dbquery(dbj, dbRECORD_COUNT, nrecords) print *, 'Lines after event table subset ', nrecords if (dbunjoin( dbj, 'new_databse_name',0) /= 0) then write (6,'(a)') 'Error saving the database table' -------------------------------------------------------------------