# 3. Reconstructions based on given paleocoordinates (online)

Source:`vignettes/3_online_reconstrution_forward.Rmd`

`3_online_reconstrution_forward.Rmd`

The GPlates Web Service (GWS) (**online**) implements reverse reconstruction: rather than calculating the paleocoordinates of present-day positions given an *age* and a *model*, you can calculate the present-day positions of paleocoordinates.

## Present-day positions of paleocoordinates

Let’s work with the Triassic (at 220Ma) using the default `"MERDITH2021"`

model! We can reconstruct the positions of present-day coastlines as we saw earlier

```
coast220 <- reconstruct("coastlines", age=220)
coast220
#> Simple feature collection with 2219 features and 0 fields
#> Geometry type: POLYGON
#> Dimension: XY
#> Bounding box: xmin: -179.99 ymin: -82.3516 xmax: 179.99 ymax: 89.99
#> Geodetic CRS: WGS 84
#> First 10 features:
#> geometry
#> 1 POLYGON ((164.7667 58.5746,...
#> 2 POLYGON ((171.5001 53.1643,...
#> 3 POLYGON ((162.0057 55.6797,...
#> 4 POLYGON ((160.0406 54.5613,...
#> 5 POLYGON ((162.1421 56.2415,...
#> 6 POLYGON ((174.0752 53.7632,...
#> 7 POLYGON ((162.533 56.3312, ...
#> 8 POLYGON ((161.9085 56.184, ...
#> 9 POLYGON ((158.8934 55.3449,...
#> 10 POLYGON ((158.0967 55.2248,...
```

We can also plot this the same way:

```
# the background map
plot(coast220$geometry, col="gray", border=NA)
```

Working with this reconstruction often involves defining points in this paleocoordinate system: either because they represent notable geographic positions, or they are results of geometric transformations.

```
# the coordinates
one <- c(-15, -25)
two <- c(100, -45)
three <- c(-60, 30)
# make it a matrix
posMat <- rbind(one, two, three)
# add column names (optional)
colnames(posMat) <- c("paleolong", "paleolat")
posMat
#> paleolong paleolat
#> one -15 -25
#> two 100 -45
#> three -60 30
```

Since the map above is using the `WGS84`

Coordinate Reference System (CRS), we can visualize the positions with `points()`

:

`points(posMat, col="red", pch=3)`

You can calculate the present-day positions of these points with the `reconstruct()`

function - you only have to indicate that the coordinates are **from** a given age, in our case **220Ma**:

```
presentPoints <- reconstruct(posMat, from=220)
#> Warning in gwsReconstructPoints(coords = x[bPresent, , drop = FALSE], time = from, : Identical coordinates returned as present-day positions (4 digits):
#> - Some points are probably off the partitioning polygons.
#> - Returning NAs for these.
```

Note the warning message! This reads a bit technical, but the key bit here is the first bullet point: **Some points are probably off the partitioning polygons.** This simply means that calculating the present-day positions is simply not possible because the paleocoordinates cannot be assigned to any of the plates that are present in the model at the time indicated by the **from** argument. These points are indicated with missing values (`NA`

s`) in the returned object of present-day coordinates.

```
presentPoints
#> long lat
#> one -57.5362 -12.9236
#> two 132.5350 -25.1888
#> three NA NA
```

This result indicates that the point named `"three"`

(with coordinates `-60`

`30`

) is probably off the plates. We can confirm this by looking at plates themselves (`static_polygons`

for the `"MERDITH2021"`

model). These can be queried with:

`pl220 <- reconstruct("static_polygons", age=220)`

… and plotted on top of the existing map with:

`plot(pl220$geometry, col="#00555522", add=TRUE, border="#00555533")`

The point in question indeed does not fall on any of the plates.

#### Off-plate points

Keeping these missing value points is highly beneficial - it helps us organize our data more efficiently. However, if you regularly work with coordinates that are off the plates, the warnings that you saw above might be somewhat disruptive. For example, if you want to find the present-day coordiantes of a bunch of points, such as these coming from the tropics of 220Ma:

```
# random points from the tropics, set seed to make them reproducible
set.seed(0)
# note that these are not uniformly distributed in space!
tropoints <- cbind(
paleolong=runif(200, -180, 180),
paleolat=runif(200, -30, 30)
)
```

Which you can visualize with

```
# static polygons from 220Ma
plot(pl220$geometry, col="#00555522", border="#00555533")
# points
points(tropoints, pch=3)
```

Then you can turn of the warnings for the no plate assignment with the `warn`

argument of `reconstruct()`

:

`tropoints0 <- reconstruct(tropoints, from=220, warn=FALSE)`

The missing values in this `matrix`

indicate the presence of points that are off the static polygons:

```
# which present-day longitude values are missing?
# Prvodide row indices
indMissing <- which(is.na(tropoints0[, 1]))
```

We can use these to visualize that the points are on or off the polygons - for example we ca circle them on our previously plotted map:

```
# circle off-polygon points
points(tropoints[indMissing,], pch=1, cex=2, col="red")
```

#### Present-day positions of the coordinates

Going back to the three points that we were inspecting earlier (`posMat`

): the present-day coordinates are given as longitude (`long`

) and latitude (`lat`

) values in the `presentPoints`

matrix object. We can visualize them on any map that has a `WGS84`

CRS. For instance we can grab the coaslines of the `"MERDITH2021"`

model, and plot them the usual way

```
# Present-day coastlines today
coast0 <- reconstruct("coastlines", age=0)
# Plot outlines
plot(coast0$geometry, col="gray", border="darkgray")
```

… and use points to put the positions on the map:

```
# Plot present-day positions of the points
points(presentPoints, col="red", pch=3)
```

Note that the missing values will not be rendered.

## Tracing points from paleocoordinates

If we can reconstruct the present-day positions of points of past paleocoordinates, that also means that we can reconstruct their positions at other points in time as well.

#### Paleocoordinates at other times

If we want to calculate the positions of the three points above (or at least those two that are on actual plates), for **10 million years earlier** (i.e. to 230Ma), all we need to do is to change the target `age`

of the reconstruction. This argument of `recontruct()`

defaults to `0`

: the date that represents the present. This is the same target `age`

that we normally use for calculating the paleocoordinates of present-day locations, but by providing a `from`

argument as well, we can indicate that the given coordinates actually represent paleocoordinates.

```
# paleocoordinates of 220Ma rotated to 230Ma
pm230 <- reconstruct(posMat, from=220, age=230, warn=FALSE)
```

You can visualize the offset of these points by calculating the positions of the coastlines (as earlier):

```
# paleocoordinates of 220Ma rotated to 230Ma
coast230 <- reconstruct("coastlines", age=230)
```

… and plotting the information from both the 220Ma and 230Ma time interval on the same figure, using different colors:

```
# 220Ma (gray and black)
plot(coast220$geometry, col="gray", border=NA)
points(posMat, col="black", pch=3)
# 230Ma (red) - use add to overlplot!
plot(coast230$geometry, col="#BB000022", border=NA, add=TRUE)
points(pm230, col="#BB0000", pch=3)
```

You can visually evaluate the offset between these two time intervals or you can use the coordinates in other calculations.

#### Tracing the points’ evolution to the present

If you can reconstruct the positions of paleocoordinates for single times, or you can do it for multiple target `age`

s by iterating the call to `reconstruct()`

. To make this easier, you can provide a set of dates in the `age`

argument, which will calculate all the paleo- (if `from`

is not `0`

) or recent (`from=0`

) coordinates for every given age. For instance, if you want to trace the positions of these points until the present day (say in steps of 10Ma), all you need to do is provide a vector with multiple target `age`

s:

```
# vector of target ages (steps of 10Ma)
allAges <- seq(220, 0, -10)
# run the reconstruction
# will take a couple seconds
pmHistoryList <- reconstruct(posMat, from=220, age=allAges, warn=FALSE)
```

The default behavior of the function is to return a `list`

of results: one for every target `age`

- as if you were running the `reconstruct()`

separately for these target `age`

s:

```
# first 6 elements of the list
head(pmHistoryList)
#> $`220`
#> paleolong paleolat
#> one -15 -25
#> two 100 -45
#> three NA NA
#>
#> $`210`
#> paleolong paleolat
#> one -13.8011 -23.8324
#> two 98.0900 -43.2016
#> three NA NA
#>
#> $`200`
#> paleolong paleolat
#> one -13.2429 -21.3120
#> two 96.4196 -44.1218
#> three NA NA
#>
#> $`190`
#> paleolong paleolat
#> one -13.1015 -19.5392
#> two 95.4666 -45.4731
#> three NA NA
#>
#> $`180`
#> paleolong paleolat
#> one -13.5507 -17.7555
#> two 95.1759 -48.7927
#> three NA NA
#>
#> $`170`
#> paleolong paleolat
#> one -14.4549 -16.2838
#> two 97.6837 -54.2356
#> three NA NA
```

The individual elements of the list are the same objects as the results of the previous calls of `reconstruct()`

. The `names`

of the list include the `target`

ages that the coordinates represent.

This might be the structure that is the most efficient for you - but there might also be cases when you would need to access the coordinates of the same point at different times quickly. For this purpose, an `array`

representation of the results might be better suited, which you can toggle by setting the `listout`

argument to `FALSE`

from the default (`listout=TRUE`

):

```
pmHistory <- reconstruct(posMat, from=220,
age=allAges, warn=FALSE, listout=FALSE)
```

Accessing the structure of this object is a simple way to inform yourself about how to access the desired subsets:

```
str(pmHistory)
#> num [1:23, 1:3, 1:2] -15 -13.8 -13.2 -13.1 -13.6 ...
#> - attr(*, "dimnames")=List of 3
#> ..$ : chr [1:23] "220" "210" "200" "190" ...
#> ..$ : chr [1:3] "one" "two" "three"
#> ..$ : chr [1:2] "paleolong" "paleolat"
```

This object is a three-dimensional `array`

of coordinates, with the target `age`

s given as the first dimension (rows), the points as the second (columns) and the coordinate type (`paleolong`

or `paleolat`

) as the third (planes).

For instance, if we want to access the history of point `one`

we can use character subscripts to have the coordinates and and the ages in a simple 2D `matrix`

:

```
# history of point 'one'
oneHistory <- pmHistory[, "one", ]
twoHistory <- pmHistory[, "two", ]
```

You can use these matrices to display the rotation history of these points from 220Ma to the present day:

```
# redraw 220ma map
plot(coast220$geometry, col="gray", border=NA)
# the 220Ma position of point 'two'
points(posMat, col="black", pch=3)
# present-day coastlines
plot(coast0$geometry, col="#0000DD22", border=NA, add=TRUE)
# the 220Ma positions
points(presentPoints, col="#0000DD", pch=3)
# tracing lines
lines(oneHistory, col="#0000DD99", type="o", cex=0.3, pch=16)
lines(twoHistory, col="#0000DD99", type="o", cex=0.3, pch=16)
```

This constitutes the overview of the **online method** of reconstruction.

## Advantages and disadvantages of the *online method*

Currenly, only this **online method** allows you to do reverse reconstructions (i.e. to use the paleocoordinates in calculations). This methods is also easy to set up, but it has several limitations. For more complete control over the backward rotations you might want to try out the **offline method** (see Tutorial 4 about the Offline Method).

If want to stick with the **online method**, you need to be aware of these limiting factors:

#### External models

Although the **online method** is easy to set up, it uses-pre defined models to actually execute the rotations. If you cwant to use customized, or other models, which are not yet implemented in the GWS, you will need to use the **offline** method.

#### Internet connection and reproducibility

Since the calculations are not performed on your computer, but by the servers that host the GWS, you cannot use this method if you have no internet connection. Also, if you think about reproducibility, it is easy to see that you have no control over whether this service remains usable in the future - and neither are we.

There are docker containers that allow you to instantiate the GWS, which might help with this issue - but if you really want to make sure that your code remains reproducible - you might want to try the **offline method instead**.