Skip to content

Commit

Permalink
DOC: provide the code and documentation for an interactive events web…
Browse files Browse the repository at this point in the history
… map
  • Loading branch information
luca-s committed Aug 30, 2021
1 parent c7062e8 commit 37b882c
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 12 deletions.
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,22 +363,21 @@ Catalog:
events share the same id, subsequent
events will be discarded.
```
#### Examples

### 1.6 A continuously updated multi-event relocated catalog

Thanks to the integration in SeisComP it is quite easy to use `scrtdd` to periodically generate a double-difference catalog of a region, so that recent events are continuously included in the double-difference inversion. This is not only useful for having up-to-date snapshots of high quality earthquakes locations for a region, but it is crucial for real-time double-difference inversion, where new origins are relocated against a reference (background) catalog: the more updated the background catalog is, the better the results. This is especially important when monitoring regions where the historical seismicity unknown. For this purpose it might come in handy the `generate-background-catalog.sh` script in [this folder](/data/scripts/), that can be easily adapted to the specific use case and it is useful to periodically generate a multi-event relocated catalog.

### Examples

Here are two catalogs before and after `scrtdd` relocation:
Here are a few catalogs before and after `scrtdd` relocation:

![Relocation example picture](/data/img/multiEventRelocationExample.png?raw=true "Relocation example")


The unit testing folder contains the code to generate some tests with synthetic data:

![Synthetic Data Relocation example picture](/data/img/multiEventRelocationSyntDataExample.png?raw=true "Synthetic Data Relocation example")

### 1.6 A continuously updated multi-event relocated catalog

Thanks to the integration in SeisComP it is quite easy to use `scrtdd` to periodically generate a double-difference catalog of a region, so that recent events are continuously included in the double-difference inversion. This is not only useful for having up-to-date snapshots of high quality earthquakes locations for a region, but it is crucial for real-time double-difference inversion, where new origins are relocated against a reference (background) catalog: the more updated the background catalog is, the better the results. This is especially important when monitoring regions where the historical seismicity unknown. For this purpose it might come in handy the `generate-background-catalog.sh` script in [this folder](/data/scripts/), that can be easily adapted to the specific use case and it is useful to periodically generate a multi-event relocated catalog, which can be also displayed in an interactive map, given a web server is available.

![Relocation example picture](/data/img/multiEventRelocationContinuousExample.png?raw=true "Continuously updated relocation example")

## 2. Real-time single-event relocation

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified data/img/multiEventRelocationExample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 27 additions & 4 deletions data/scripts/generate-background-catalog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ CATALOG_DB="dbtype://user:password@host/database"
# Database to which import the relocated catalog (if empty -> no import)
DESTINATION_DB=""

# Folder to which copy the relocated catalog, the real-time rtDD configuration
# should point to this catalog (if empty -> no copy)
# The real-time rtDD configuration folder to which copy the relocated catalog,
# the real-time rtDD profile should point to this catalog (if empty -> no copy)
RTDD_BGCAT_DIR=""

# Folder to which copy the data for the web page intereactive map (empty -> no copy)
# You need a web server to visualize the page on a browser unless you run a browser
# on the same machine
WEB_DIR=""

RTDD_PROFILE="myProfile"

LOGFLAG="--console=1 --verbosity=3"
Expand Down Expand Up @@ -61,10 +66,12 @@ if [ $? -ne 0 ] || [ ! -f $ID_FILE ]; then
exit 1
fi

echo "Done: created file $ID_FILE"

#
# Relocate catalog
#
echo "Relocating events..."
echo "Relocating events with profile $RTDD_PROFILE..."

#depending on the size of the logs, many files will be generated in the form scrtdd.log scrtdd.log.1 scrtdd.log.2 ...
RTDDLOG_FILE=scrtdd.log
Expand All @@ -81,6 +88,8 @@ if [ $? -ne 0 ] || [ ! -f reloc-event.csv ] || [ ! -f reloc-phase.csv ] || [ ! -
exit 1
fi

echo "Done: created files $XMLRELOC_FILE and reloc-event.csv,reloc-phase.csv,reloc-station.csv"

#
# Copy relocated catalog to real-time rtDD configuration
#
Expand All @@ -95,15 +104,27 @@ if [ -n "${RTDD_BGCAT_DIR}" ]; then
fi

# Force scrtdd to reload the profile background catalog
echo "Send message to scrtdd forcing a reloading of the background catalog for profile $RTDD_PROFILE"
$seiscomp_exec scrtdd --send-reload-profile-msg $RTDD_PROFILE --user rtddBgCatUpdate $LOGFLAG
fi

#
# Copy the relocated catalog into the web folder
#
if [ -n "${WEB_DIR}" ]; then
cp -f event.csv $WEB_DIR/event.csv
cp -f station.csv $WEB_DIR/station.csv
cp -f reloc-event.csv $WEB_DIR/me-dd-event.csv
cp -f ../main.html $WEB_DIR/
date > $WEB_DIR/LAST_RUN
fi

#
# Import the relocated catalog into the destination database
#
if [ -n "${DESTINATION_DB}" ]; then

if [ $? -ne 0 ] || [ ! -f $XMLRELOC_FILE ]; then
if [ ! -f $XMLRELOC_FILE ]; then
echo "Cannot find the relocated XML catalog $XMLRELOC_FILE: stop here"
exit 1
fi
Expand All @@ -122,6 +143,8 @@ if [ -n "${DESTINATION_DB}" ]; then
if [ $? -ne 0 ]; then
echo "Errors while importing the relocated catalog into database"
fi

echo "Done: imported $XMLRELOC_FILE into $DESTINATION_DB"
fi

#
Expand Down
219 changes: 219 additions & 0 deletions data/scripts/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Switzerland ME-DD</title>

<!-- Load Leaflet -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v6.js"></script>
</head>
<body onload="loadData();">
<center style="margin-bottom: 20px;margin-top: 40px;" >
<font size='+2' >Multi Event Double Difference</font>
</center>
<center>
<div>
<table>
<tr><td>
<input type="checkbox" class="checkbox" value="abs-events" checked><label>Catalog Events</label>
<input type="checkbox" class="checkbox" value="medd-events" checked><label>ME-DD Events</label>
<input type="checkbox" class="checkbox" value="event-links" ><label>Events links</label>
<input type="checkbox" class="checkbox" value="stations" ><label>Stations</label>
</td><tr>
</tr><td>
From <input type="date" class="date" id="start-date">
to <input type="date" class="date" id="end-date">
</td></tr>
</table>
</div>
<div id="mapid" style="height: 80%; width: 90%"></div>
</center>
<table width='99%' cellpaddding='2' cellspacing='1' border='0'>
<tr>
<td align="left">Last update: <iframe style="border:none; width:300px; height: 50px; display:block; " src="LAST_RUN"></iframe></td>
</tr>
</table>
</body>
</html>


<script>

// mapid is the id of the div where the map will appear
var map = L.map('mapid').setView([46.7, 8.3], 8);

L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a>',
}).addTo(map);

var markerSize = d3.scalePow()
.exponent(2)
.domain([0,5]) // What's in the data
.range([ 4, 25]) // Size in pixel

var markerColor = d3.scaleOrdinal()
.domain(["abs-events", "medd-events", "event-links", "stations" ])
.range([ "red", "blue", "red", "yellow"]);

var markerLayer = d3.scaleOrdinal()
.domain(["abs-events", "medd-events", "event-links", "stations" ])
.range([ L.layerGroup(), L.layerGroup(), L.layerGroup(), L.layerGroup()]);

d3.selectAll(".checkbox").on("change", updateVisibleLayers);

function updateVisibleLayers() {

// For each check box:
d3.selectAll(".checkbox").each(function(d){
cb = d3.select(this);
grp = cb.property("value")

if(cb.property("checked")){ // If the box is check, I show the group
markerLayer(grp).addTo(map);
} else { // Otherwise I hide it
markerLayer(grp).remove();
}
});
}

var absEvents = null;
var meddEvents = null;

d3.selectAll(".date").on("change", updateVisibleEvents);

function updateVisibleEvents() {
// check all data has been loaded
if (absEvents != null && meddEvents != null)
{
markerLayer("abs-events").clearLayers();
markerLayer("medd-events").clearLayers();
markerLayer("event-links").clearLayers();
buildEventsLayer(absEvents);
buildEventsLayer(meddEvents);
buildEventLinksLayer(absEvents, meddEvents)
}
}

function eventDateFilter() {
var startDate = new Date(document.getElementById("start-date").value);
var endDate = new Date(document.getElementById("end-date").value);
return function(ev) {
if ( (!isNaN(startDate) && ev.time < startDate) ||
(!isNaN(endDate) && ev.time > endDate) )
{
return false;
}
return true;
};
}

function buildEventsLayer(evData) {
evData.filter( eventDateFilter() ).forEach(ev => {
var circle = L.circleMarker([ev.lat, ev.lon], {
color: markerColor(ev.group),
fillColor: markerColor(ev.group),
fillOpacity: 0.5,
weight : 1,
radius: markerSize(ev.magnitude)
});
circle.bindPopup(ev.desc);
circle.addTo(markerLayer(ev.group));
});
}

function buildEventLinksLayer(absEvents, meddEvents) {
evLinks = new Map();
meddEvents.filter( eventDateFilter() ).forEach(ev => {
evLinks.set(ev.id, new Array(2));
evLinks.get(ev.id)[0]= [ev.lat, ev.lon];
});
absEvents.filter( eventDateFilter() ).filter( ev => evLinks.has(ev.id) ).forEach(ev => {
evLinks.get(ev.id)[1]= [ev.lat, ev.lon];
});
evLinks.forEach((value, key) => {
var polyline = L.polyline(value, {
color: markerColor("event-links"),
weight : 1
});
polyline.addTo(markerLayer("event-links"));
});
}


function buildStationsLayer(stData) {
stData.forEach(st => {
var circle = L.circleMarker([st.lat, st.lon], {
color: markerColor(st.group),
fillColor: markerColor(st.group),
fillOpacity: 0.3,
radius: 10
});
circle.bindTooltip(st.desc);
circle.addTo(markerLayer(st.group));
});
}

function loadData() {

d3.csv("./event.csv", function(data) {
return {
id : +data.id,
time : new Date(data.isotime),
lat : +data.latitude,
lon : +data.longitude,
magnitude : +data.magnitude,
desc : new Date(data.isotime).toUTCString()
+ "<br>Mag " + data.magnitude
+ "<br>Depth km " + data.depth,
group : "abs-events"
};
}).then(function(data){
absEvents = data;
updateVisibleEvents();
updateVisibleLayers();
});

d3.csv("./me-dd-event.csv", function(data) {
return {
id : +data.id,
time : new Date(data.isotime),
lat : +data.latitude,
lon : +data.longitude,
magnitude : +data.magnitude,
desc : new Date(data.isotime).toUTCString()
+ "<br>Mag " + data.magnitude
+ "<br>Depth km " + data.depth
+ "<br>Depth change km " + data.depthChange
+ "<br>Epicenter change km " + data.locChange
+ "<br>Rms change sec " + (parseFloat(data.rms) - parseFloat(data.startRms)).toFixed(3)
+ "<br>Used phases P " + data.ph_usedP + " S " + data.ph_usedS
+ "<br>Used neighbours " + data.numNeighbours,
group : "medd-events"
};
}).then(function(data){
meddEvents = data;
updateVisibleEvents();
updateVisibleLayers();
});

d3.csv("./station.csv", function(data) {
return {
lat : +data.latitude,
lon : +data.longitude,
desc : data.id,
group : "stations"
};
}).then(function(data){
buildStationsLayer(data);
updateVisibleLayers();
});
}

</script>

0 comments on commit 37b882c

Please sign in to comment.