Multi-layer well screen in Flopy - multi-layer

I want to implement wells that screen several layers in the model domain. However, when setting up the wel package in Flopy, only one layer can be entered in the stress period data of each well, as shown in the Flopy example below:
# Create the well package
pumping_rate = -500.0
wel_sp = [[0, nrow / 2 - 1, ncol / 2 - 1, pumping_rate]]
stress_period_data = {0: wel_sp}
wel = flopy.modflow.ModflowWel(mf, stress_period_data=stress_period_data)
One solution to this problem is the implementation of a second well in the layer below and halving the pumping rate:
# Create the well package
pumping_rate = -500.0
wel_sp1 = [[0, nrow / 2 - 1, ncol / 2 - 1, pumping_rate/2]]
wel_sp2 = [[1, nrow / 2 - 1, ncol / 2 - 1, pumping_rate/2]]
stress_period_data = {0: wel_sp1, 1: wel_sp2}
wel = flopy.modflow.ModflowWel(mf, stress_period_data=stress_period_data)
This, however, is not justifiable, as soon as the layers differ in transmissivity. Is there a (built-in) way of spanning a well over several layers in Flopy?

I don't see anything wrong with your solution, except perhaps having to half the pumping rate; however, that may be necessary for your specific application.
That being said, there appears to be an implementation issue.
You mention multiple layers, but not multiple stress periods.
You are, however, implementing two distinct stress periods (well_sp1 and well_sp2).
It seems that you intend to define a single stress period with multiple cells affected by a well.
According to Flopy's documentation, it should look like this:
wel_sp = [[0, nrow / 2 - 1, ncol / 2 - 1, pumping_rate], [1, nrow / 2 - 1, ncol / 2 - 1, pumping_rate]]
I believe this is the best solution for you. If you have any doubts, you could create a multi-layer model in, say, ModelMuse and load it into Flopy to inspect the stress period data and wells to see if they match your implementation.
I hope this helps!

Related

Clustering within a single time series (detecting process changes)

I have a single time series where you can clearly see a process change (denoted by the manually drawn lines). I am trying to detect and cluster these changes so that I can be notified when a new cluster is beginning. I have already attempted K-means clustering, agglomerative clustering and they do a decent job but do not seem to cluster based on time, only the value. I expect to have 6 clusters in the timeseries. You can see the algorithm typically ignores time.
I have googled a lot and discovered DTW however every article I read is comparing multiple time series instead of detecting changes within a single time series.
Does anyone have any references I can read up on this or have any solutions?
I am unable to provide actual data however here is some example data that you can use:
library(tidyverse)
example_data <- tibble(
date_seq = 1:300,
value = c(
rnorm(65, .1, .1),
rnorm(65, -.25, .1),
rnorm(20, 4, .25),
rnorm(80, -.25, .1),
rnorm(20, 4, .25),
rnorm(50, 0, .1)
)
)
Thank you!
I needed to solve a problem similar to yours. However, I used Markov to identify regime change moments instead of opting for a clustering method.
Here are good articles about it:
[RPubs by Majeed Simaan] [https://rpubs.com/simaan84/regime_switching]
[R-bloggers by Andrej Pivcevic] [https://www.r-bloggers.com/2019/02/switching-regressions-cluster-time-series-data-and-understand-your-development/]

Calculating the percentage of overlap between polytopes (n-dimensions)

I have to figure out the percentage of overlap between polytopes in n-dimensional spaces, where my only available source of reference is a set of randomly sampled points within those polytopes.
Assume that the following two R objects are two sets of randomly sampled points from two different polytopes in 5 dimensions:
one <- matrix(runif(5000, min = 0, max = 5), ncol = 5)
two <- matrix(runif(5000, min = 0, max = 4), ncol = 5)
In this example, I selected a smaller range for the second object, so we know that there should be less than 10% overlap. Let me know if I am wrong.
EDIT:
Just to make it really clear, the question is what is the percentage of overlap between those two objects?
I need a method that generalizes to n-dimensional spaces.
This stackoverflow question is somewhat similar to what I am trying to do, but I didn't manage to get it to work.
So, the most straightforward way is to use the hypervolume package.
library(hypervolume)
one <- hypervolume(matrix(runif(5000, min = 0, max = 5), ncol = 5))
two <- hypervolume(matrix(runif(5000, min = 0, max = 4), ncol = 5))
three = hypervolume_set(one, two, check.memory=FALSE)
get_volume(three)
This will get you the volume.
hypervolume_overlap_statistics(three)
This function will output four different metrics, one if which is the Jaccard Similarity Index.
The Jaccard Similarity is the proportion of overlap between the two sample sets (the intersection divided by the union).
Alternatives
Chris suggested volesti as an alternative. Another alternative would be the geometry package.
They do not calculate the proportion straight away. Here you need to find the intersection (e.g. intersectn in geometry, VpolytopeIntersection in volesti), then calculate the volume for the polytopes separately and also their intersection, then you need to divide the volume of the intersection with the sum of the volumes for the two polytopes.
Here, they are also using a different method to calculate the volume and it might be more appropriate for you if you are trying to construct convex hulls in an n-dimensional space. For me, hypervolume is a better solution, because I am doing something more akin to Hutchinson’s n-dimensional hypervolume concept from ecology and evolutionary biology.

Volume of a prolate spheroid

I have a dataset with the length and width of an prolate spheroid:
df <- data.frame(nr = c(1, 2, 3), length = c(4, 5, 3), width = c(2, 2, 1))
df
Now I want to make an extra column with the volume. I've used the formula V = 4/3*pi*a²b (with a and b = 1/2 length and width respectively):
df$volume <- (4/3)*pi*(df$length/2)^2*(df$width/2)
This works, but I want to know if there is maybe an inbuilt formula for this in R?
I'm not aware of such a function, and I'd be a bit surprised to see it implemented somewhere, just because it's a somewhat esoteric geometry thing. (Every esoteric stats concept has been implemented somewhere in R or in a package, but esoteric geometry concepts are much rarer since R is not a tool designed with geometric applications specifically in mind.)
That said: whether or not such a thing has already been implemented somewhere, why not just write a custom function using the code you gave?
spheroid_vol <- function(length, width){
4/3 * pi * (length/2)^2 * (width/2)^2
}
> spheroid_vol(df$length, df$width)
# 16.755161 26.179939 2.356194
You could also make this a better function by doing things like checking to make sure the inputs are nonempty, etc. -- but that may or may not be worth the effort depending on what you want to do with it.

What is an inch? Setting the length for arrows

Somewhat inexplicably, the length parameter in arrows is specified in inches (from ?arrows):
length length of the edges of the arrow head (in inches).
R source even goes so far as to explicitly make note that this measurement is in inches in a comment, highlighting how peculiar this design is.
That means the relative size of the arrows depends on dev.size(). What's not clear is how to translate inches into axis units (which are infinitely more useful in the first place). Here's a simplified version:
h = c(1, 2, 3)
xs = barplot(h, space = 0, ylim = c(0, 4))
arrows(xs, h - .5, xs, h + .5,
length = .5*mean(diff(xs)))
How this displays will depend on the device. E.g. here is the output on this device:
png('test.png', width = 5, height = 5)
And here it is on another:
png('test.png', width = 8, height = 8)
It's a bit of an optical illusion to tell on sight, but the arrows are indeed the same width in the two plots. How can I control this so that both plots (which convey the same data) display identically? More specifically, how can I make sure that the arrows are exactly .5 plot units in width?
I spent far too much time in the rabbit hole on this, but here goes. I'll document a bit of my journey first to aid others who happen upon this in the types of nooks and crannies to search when trying to pull yourself up by your bootstraps.
I started looking in the source of arrows, but to no avail, since it quickly dives into internal code. So I searched the R source for "C_arrows" to find what's happening; luckily, it's not too esoteric, as far as R internal code goes. Poking around it seems the workhorse is actually GArrow, but this was a dead end, as it seems the length parameter isn't really transformed there (IIUC this means the conversion to inches is done for the other coordinates and length is untouched). But I happened to notice some GConvert calls that looked closer to what I want and hoped to find some user-facing function that appeals to these directly.
This led me to go back to R and to simply run through the gamut of functions in the same package as arrows looking for anything that could be useful:
ls(envir = as.environment('package:grDevices'))
ls(envir = as.environment('package:graphics'))
Finally I found three functions in graphics: xinch, yinch, and xyinch (all found on ?xinch) are used for the opposite of my goal here -- namely, they take inches and convert them into device units (in the x, y, and x&y directions, respectively). Luckily enough, these functions are all very simple, e.g. the work horse of xinch is the conversion factor:
diff(par("usr")[1:2])/par("pin")[1L]
Examining ?par (for the 1,000,000th time), indeed pin and usr are exactly the graphical parameter we need (pin is new to me, usr comes up here and there):
pin The current plot dimensions, (width, height), in inches.
usr A vector of the form c(x1, x2, y1, y2) giving the extremes of the user coordinates of the plotting region.
Hence, we can convert from plot units to inches by inverting this function:
xinch_inv = function(dev_unit) {
dev_unit * par("pin")[1L]/diff(par("usr")[1:2])
}
h = c(1, 2, 3)
xs = barplot(h, space = 0, ylim = c(0, 4))
arrows(xs, h - .5, xs, h + .5,
# just convert plot units to inches
length = xinch_inv(.5*mean(diff(xs))))
Resulting in (5x5):
And (8x8):
One further note, it appears length is the length of each side of the arrow head -- using length = xinch_inv(.5), code = 3, angle = 90 results in segments as wide as the bars (i.e., 1).
On the off chance you're interested, I've packaged these in my package as xdev2in, etc.; GitHub only for now.

Move existing 2D points to newly generated 2D points in an optimized manner

I am trying to solve a problem where I have some existing points (P) that need to move to new location that is generated by some method, say (P`). I want to know if there is a optimization algorithm that finds the best mapping of points.
I tried to map by using the least distance between points choosing the best in a loop but the last ones ended up with worst deal. How can we determine the best mapping?
we are not trying for best time or space complexity since we only have handful of points to work with. Following is what we have till now.
getMapping <- function(originalX, originalY, newX, newY)
{
#Maps original index to new index
dimemsion <- length(originalX)
#this matrix will hold distance of each original point from each of the new points
dist.matrix <- matrix(nrow = dimemsion, ncol= dimemsion)
#this is a brute force method
for(i in 1:dimemsion) # i traverses over original data points
{
for(j in 1:dimemsion) # j traverses over new data points
{
distance <- sqrt((originalY[i] - newY[j])^2 + (originalX[i] - newX[j])^2)
dist.matrix[i,j] = distance
}
}
#Best way to find mapping ?????
..... Not sure how to do it right now
return(dist.matrix)
}
#Use Case 1
originalX = c( 1, 2, 3, 4, 5, 6)
originalY = c( 1, 2, 3, 4, 5, 6)
newX = c( 1, 1, 3, 4, 5, 6)
newY = c( 1, 1, 4, 3, 2, 1)
print(getMapping(originalX, originalY, newX , newY))
How can I find best combination from the summationMatrix? Or any algorithm/idea to approach this issue will be appreciated. We are using R as the language here.
Thanks
First, you better use the dist function to produce summationMatrix (the name summationMatrix is, imho, horrible, I would name it something like dist.matrix or dist.mat).
Second, what you need is called Hungarian algorithm.

Resources