Computer Labs Post
Computer Labs Post
Computer laboratories
Contents
Part I: Python 1 Calculating heads 1.1 Solution methods . . . . . . . . . . . . . . . . . 1.1.1 Gauss-Seidel iteration using a spreadsheet 1.1.2 Gauss-Seidel iteration using Python . . . 1.1.3 Successive over relaxation . . . . . . . . 1.1.4 Direct solution . . . . . . . . . . . . . . 1.2 Regional ow example . . . . . . . . . . . . . . 1.2.1 No-ow boundaries . . . . . . . . . . . . 1 5 5 5 6 8 8 9 10 13 13 14 17 17 19 21 27 29 33 37 39 39 40
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
2 Calculating ows 2.1 Water budgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Abstraction well . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Transient simulations 3.1 Abstraction well (transient) . . . . . . . . . . . . . . . . . . . . . Part II: MODFLOW 4 Well eld in a river valley Part III: MicroFEM 5 Well in a semi-conned aquifer 6 Inltration canal Part IV: Linear algebra 7 Systems of linear equations 7.1 Linear equations . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Systems of linear equations . . . . . . . . . . . . . . . . . . . . . 3
8 Matrices 8.1 Denition . . . . . 8.2 Special matrices . . 8.3 Operations . . . . . 8.4 Determinant . . . . 8.5 Cramers rule . . . 8.6 Inverse of a matrix References
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
45 45 45 46 48 50 51 53
Introduction
Nowadays, a wide selection of very powerful groundwater ow models is available. For almost every problem there is a code that suits your needs. But sometimes, the code at hand is not just what you want. It may be that it doesnt handle a specic boundary condition or you want the output to be in a slightly different format to make the post-processing easier. Wouldnt it be convenient then if you have the skills to modify the original code a bit, or even to create your own model? Moreover, if you have made (simple) models yourself, you also better understand how existing codes work. This may be helpful in a situation where the model crashes or behaves unexpectedly in a different way. Fewer and fewer hydrologists possess the skills to modify or write computer codes. So, learning to write your own models will give you an advantage. In order to do so, you also need to learn a programming language. A programming language is a set of functions and statements that allow you to pass commands on to the computer. There are dozens of different programming languages available. Examples include Visual Basic, Pascal, C, FORTRAN, Python and many, many more. In this course we will use Python. Python is a so-called command-line interpreter: you type in the commands that are subsequently executed. These commands can be combined into a program which we call a script. The advantage of using Python is that lots of the things you would normally have to worry about as a programmer have already been done for you. For example, creating plots and charts is extremely easy because the statements to send graphics to the screen have already been programmed. You can simply use the commands included in Python and its libraries like matplotlib instead of guring out all this complicated stuff yourself. Another advantage of Python is that it is becoming widely used in various parts of the scientic community. Popular geographic information systems like ArcGIS and GRASS also have Python functionality. In the groundwater industry, MATLAB, another interpreted programming language, is still the standard, although that also slowly starts to change. The reason that we do not use MATLAB in this course is that (i) Python is just as good and sometimes even better than MATLAB and (ii) Python is open-source software. The latter means that there are no licensing issues and that you can install and work with Python on any computer, for example at your home or on a laptop during your eldwork. So, in short, being able to write your own modeling code helps you to better understand what you are doing if you are using an existing model. Also, it gives 3
Chapter 0
you the ability to modify and improve models or create custom-made models. In the learning process, you will become familiar with the basics of programming languages, which you can apply to other areas outside groundwater ow modeling. It is assumed that you are familiar with the basics of Python. If not, or if you want to refresh your memory, then rst familiarize yourself by going through the Python tutorial, which is available from your instructor.
Chapter 1
Calculating heads
1.1 Solution methods
During the lectures we have looked at the solution of unknown heads at the interior nodes of a grid for which the heads at the boundary nodes are known (Dirichlet boundary condition). We have seen that by moving the so-called ve-star operator through the grid, the head at each node could be calculated as a function of the heads in the neighboring nodes. Calculating the heads once, however, was not enough to obtain the nal solution. Instead, we started with an initial guess and then repeated the calculations until the heads no longer changed signicantly (iteration).
1.1.1
Such calculations are easily done by computers. Before creating a program in Python, lets look at how we can use a spreadsheet to do these calculations. Suppose we have a grid as in gure 1.1 with the heads given for each cell on the model boundary.
Figure 1.1: Simple mesh with heads xed on the boundaries. We can easily imagine the cells of a spreadsheet to coincide with the nodes of the model mesh. To do the calculations, proceed as follows: Open your spreadsheet program. 5
Chapter 1
Type in the xed head values at the cells representing the model boundary. Type a formula in the upper left interior cells that calculates the average of the heads in the 4 neighboring cells (see gure 1.2). Copy this formula to the remaining interior cells.
Figure 1.2: Entering the formula for Gauss-Seidel iteration in Excel. It is that easy! The only thing is that, depending on the spreadsheet you use, you may need to iterate manually. In Microsoft Excel, this is done automatically if you select Tools Options and then on the Calculations tab enable the Iteration option.
1.1.2
The advantage of using a spreadsheet is that it is easier to envisage the model structure because, like a nite-difference model, a spreadsheet consists of cells. In the remainder of the exercises, however, we will use Python because of its much greater exibility. As an example, take a look at the following Python-script, which does exactly the same as what we did before in our spreadsheet.
from numpy import array h = array([[4., [4., [4., [4., 5., 0., 0., 5., 6., 0., 0., 6., 7.], 7.], 7.], 7.]])
Python
dummy = h.shape nrow = dummy[0] ncol = dummy[1] print Head matrix is a , nrow, by , ncol, matrix. ni = 1 conv_crit = 1e-3 converged = False while (not converged): max_err = 0 for r in range(1, nrow - 1): for c in range(1, ncol - 1): h_old = h[r, c] h[r, c] = (h[r - 1, c] + h[r + 1, c] + h[r, c - 1] + h[r, c + 1]) / 4. diff = h[r, c] - h_old if (diff > max_err): max_err = diff if (max_err < conv_crit): converged = True ni = ni + 1 print Number of iterations = , ni - 1 print h
At rst sight, this may look incomprehensibly complicated. It is certainly more complicated than entering the formulas in a spreadsheet. But if you get used to programming it will become much easier to read such scripts. Note how indentation is used to structure the script. In fact, you have to indent in Python, otherwise it will complain! Try if you can understand what is going on here and then answer the following questions: What is the purpose of the variable converged? What values does the shape variable return? Can you think of a reason why it is better to use shape to dene the number of rows and columns rather than just assigning xed values to these variables yourself? What is the name of the variable that is used to store the number of iterations? How does the program know that it only needs to calculate the interior nodes? Exercise: The script is available on Blackboard. Download it to a local disk and open it in Python (simply by clicking File Open and selecting it). The script is opened in the script editor and can be run by pressing F5. Investigate the effects of the convergence criterion and initial head guess on the number of iterations. Set the convergence criterion to different values and note the number of iterations. Do the same for the initial heads of the interior nodes. 7
Chapter 1
1.1.3
A way to speed up the convergence is to use Gauss-Seidel iteration in combination with successive over relaxation (SOR). In this method, the difference between the calculated value at the new iteration interval and that of the previous iteration interval c = hm+1 hm is multiplied by a relaxation factor . The new value of i,j i,j hm+1 becomes: i,j hm+1 = hm + c (1.1) i,j i,j This equation can be written as: hm+1 i,j = (1 )hm i,j + hm+1 + hm+1 + hm hm i+1,j i,j+1 i1,j i,j1 4 (1.2)
Exercise: Open the example script of Gauss-Seidel iteration and modify it in such a way that it can incorporate SOR. What extra variable(s) are needed? Note that max err can become negative with SOR and that you need to take care that you compare the absolute value of max err to the convergence criterion. Use a value of = 1.1. The number of iterations is now . . . . . . . Increase the value of and run the script again. Note that when > 1.25 the number of iterations increases compared to the script without SOR! This is because for high values of the calculated heads during the rst iterations overshoot the nal true values and it takes some time to converge back towards these values.
1.1.4
Direct solution
The previous exercise shows that the heads at the interior nodes are readily calculated using Gauss-Seidel iteration, either with or without SOR. Iterative solutions, however, are not the most efcient way to solve the system of nite difference equations. Direct solution methods are an alternative, more efcient way and are easily applied in Python. Remember that a system of linear equations (such as the nite-difference expressions for this problem) can be written in matrix form: [A]h = f (1.3)
where [A] is a coefcient matrix, h a column vector of unknown heads and f a column vector containing all known values. h follows from: h = [A]1 f (1.4)
where [A]1 is the so-called inverse of [A]. For the problem presented above, write down a nite-difference expression for each unknown head at the interior nodes. The result is a system of 4 linear equations with 4 unknowns. Transfer all known values (the heads at the boundaries) to the right-hand side and express the system of equations in matrix format. Then 8
Python
use Numpys linear algebra package to solve for h (see page 19 20 of the Python tutorial on how to do this). Did you get the same result as before? Although direct solution methods are more efcient than iterative methods they require large amounts of computer memory for real-world numerical models. Therefore, most codes use solution schemes that combine the best of both worlds of iterative and direct solution techniques.
where A1 and A2 are the amplitudes of the respective waves, k = 2 n/L, n is the wave number and L is the width of the model. Modify the script to include the parameters L, A1 , A2 , n1 , n2 , k1 and k2 . Set the values of A1 = A2 = 5.0 m and n1 = 1 and n2 = 2. Equation 1.5 contains the variable x, so we need to know x for each column in the grid. Try to nd the right statements to accomplish this and then implement equation 1.5 in the script. Once you have done this, youre almost ready to start the calculations. As a nal step, include this statement at the beginning of the script: 9
Chapter 1
from numpy import *
Include the following statements at the end of the script to produce graphical output:
close() f = figure() [X, Z] = meshgrid(linspace(0, L, ncol), linspace(0, -L, nrow)) contourf(X, Z, h) colorbar() [dhz, dhx] = gradient(h) quiver(X, Z, -dhx, dhz, color = w)
Look up what these functions do. Can you understand what they mean? If you do youre now ready to start calculating your rst real-world, self-made groundwater ow model!
1.2.1
No-ow boundaries
Note that we didnt worry about the no-ow boundary at the bottom of the model in the previous exercise. How can you see from the contour lines of the hydraulic heads that the bottom boundary is not a no-ow model? In the next exercise we will implement the no-ow boundary. We only need to make a few adjustments. Remember from the lectures that a way to incorporate no-ow boundaries is to add imaginary nodes outside the model domain. The type of grid determines how the no-ow boundary is implemented. For a mesh-centered grid, the gradient across the boundary becomes zero (the condition for no-ow) if hi,j+1 = hi,j1 , where hi,j+1 the head at the the imaginary node outside the model domain and hi,j1 is the head at rst node inside the model boundary. We will expand our matrix at the bottom with one additional row, representing the imaginary nodes. To do so, change the declaration of matrix h. Then implement the no-ow boundary by adding the following line:
h[-1, :] = h[-3, :]
Specifying -1 at the row index is short in Python for the last row; -3 indicates the third-last row. The colon at the column index means all columns. So this statement assigns the heads of the third-last row to the heads of the last row, for all columns. Where would you insert this line into our script? If you add it your script is almost ready to handle the no-ow boundary. Before you start the calculation though, you need to make some minor changes to the statements that produce the graphics. These prevent the imaginary cells from being displayed. The correct syntax is:
10
Python
close() f = figure() [X, Z] = meshgrid(linspace(0, L, ncol), linspace(0, -L, nrow - 1)) contourf(X, Z, h[:-1, :]) colorbar() [dhz, dhx] = gradient(h[:-1, :]) quiver(X, Z, -dhx, dhz, color = w)
Only 3 lines are different. Study the differences and make sure you know what they mean. Then start the calculations and pay particular attention to the head contours near the bottom boundary. What has changed?
11
Chapter 2
Calculating ows
2.1 Water budgets
In the previous examples the convergence criterion controls the accuracy of the solution. As a second check on the accuracy, a water balance can be set up. Remember from the lectures that for a 2D model with square grid cells: Q = k h x = kh x (2.1)
Assume that the hydraulic conductivity (k) is 10 m/d. Extend the script of the regional ow example to calculate the water balance of the whole model domain. Calculate inow and outow of each model boundary except for the bottom boundary. Make sure to adopt a sign-convention for inow (+) and outow (-). Fill in the table below. Table 2.1: Water budget for regional ow example ow component qlef t qright qtop qbottom qtotal magnitude ... ... ... ... ...
Compare the net inow (inow - outow) to the magnitude of the inow/outow. Is the error in the water balance acceptable? Note that the net ow over the top model boundary is basically zero but that the inow and outow components themselves over this boundary are not. What are the magnitudes of the inow and outow over the top boundary? 13
Chapter 2
where T is the transmissivity (m2 /day) and R is the volume of recharge/discharge per unit time per unit surface area. R and Q are related by (for square grid cells, so x = y): Q R= (2.3) x2 Transmissivity is T = 300 m2 /day. The well is located at x = 0, y = 0 and has a discharge of Q = 2000 m3 /day. The value of R is for the innitesimal volume around the well (gure 2.1). Outside this volume R = 0.
Figure 2.1: Finite difference grid for abstraction well exercise. Modied from Wang and Anderson (1982). Because the equipotential lines will be cylindrical around the well, the problem is symmetric and we only need to consider one quarter of the problem domain. Lets model the lower-right quardrant so the left and upper boundary are the noow boundaries (gure 2.1). The analytical solution for this problem is given by the Thiem equation: Q r ln (2.4) 2T rmax where h0 is the head before pumping and rmax is the radius of inuence of the pumping well. Assume for this exercise that rmax = 2000 m. Note that although time is not in this formula, this is actually not a steady-state problem: The h = h0 + 14
Python
Thiem equation calculates the heads for a given rmax . Check your lecture notes of Groundwater hydraulics to see how rmax varies with time. As before, take the script for Gauss-Seidel iteration with SOR as your starting point. Set the value of omega to = 1.8 and set the convergence criterion to 1 103 . Use a (mesh-centered) grid of 12 rows by 12 columns (of which the rst row and column are imaginary nodes!). Use x = y = 200 m. Make the following modications to the script (not all of them are straightforward, so ask for help if you dont succeed yourself): Calculate the distance of each node to the well and nd the nodes whose distance most closely match the radius of inuence (rmax = 2000 m). Set the heads of these nodes and of those outside the radius to h = 10 m. Set the starting heads of all remaining nodes to h = 5 m. Include lines to make the left and upper boundaries no-ow boundaries. Modify the statements that perform the Gauss-Seidel iteration in such a way that they can take into account the abstraction well (equation 2.2). Make sure that the heads are only calculated for the nodes that are part of the area of inuence of the well. In other words, dont calculate the heads of the nodes that you have set to h = 10 m. You will have to think of a smart trick to accomplish this. Include the options for graphical output at the end. Finally, add a program line to calculate the analytical solution with the Thiem equation so you can compare it to the numerical result. You will nd that the analytical and numerical results agree very well. You could include a water balance calculation but that involves quite a bit of administration since the inow here is not simply through the right and bottom grid boundaries but across the circumference formed by the sides of the cells that are mark the radius of inuence.
15
Chapter 3
Transient simulations
3.1 Abstraction well (transient)
The previous exercises all assumed steady-state conditions. In this exercise the well-drawdown problem will be expanded to a transient simulation. As before, only the lower-left quadrant, measuring 2000 by 2000 m, is considered but now all the boundaries are no-ow boundaries and the cell size is x = y = 100 m. The numerical results will be compared to the analytical solution by Theis that calculates the drawdown at a radius (r) from the well: h0 h = where
Q W (u) 4T e d
(3.1)
W (u) =
u
(3.2)
r2 S (3.3) 4T t W (u) is called the well functions and is usually tabulated in textbooks. It is also implemented in Python so there is no need to look it up: you simply calculate it with Python! The input le for this exercise has been prepared for you (it is available via Blackboard). Study it and answer the following questions: u= 1. What is the function of the parameters alpha and n steps? 2. What is the size of the time steps? 3. See if you can nd the lines that calculate the analytical solution. What is the Python equivalent of the well function W (u)? 4. At what distance are the analytical solution and the numerical solution compared? 17
and
Chapter 3
After you have studied the script, run it and observe the graph that is produced. It compares the t between the analytical and numerical results. 1. At what time do they start to deviate and why is this? 2. What causes the smaller deviations before this time? 3. Modify the script to have it perform fully-implicit calculations. What is the effect on the number of iterations? 4. Then change to a fully-explicit formulation. What happens? To prevent this, only one line of the code needs to be changed. Which one? And how would you change it? Make the change and discuss the implications. To nish, uncomment the lines that produce the 3D graph of the heads during the calculations. A movie will be displayed on the screen that shows the change in heads over time. In a relatively short time you have mastered Python, learned to program your own modelling codes and became a movie producer. Not bad, dont you think?!
18
Chapter 4
Problem description
A river ows through a valley, which is bounded to the north and south by impermeable granite intrusions (gure 4.1). The hydraulic heads in the valley at the upstream and downstream model boundaries are known. The river forms part of a phreatic aquifer, which overlies a conned aquifer of a variable thickness. A silty layer with a thickness of 0.5m separates the two aquifers. A well eld consisting of 3 pumping wells is to be installed, which will be abstracting groundwater at a proposed rate of Q = 500 m3 /day from the conned aquifer. The question is how that well eld will affect the discharge of the river, which provides water to a valuable ecosystem downstream. The relevant hydraulic parameters of the aquifer system are listed in table 4.1.
Model setup
Several les are available on Blackboard with information on the geometry and the heads of the aquifer system. Start by downloading these les and put them in your working directory. We will initially simulate the system with a quasi-3D model (steady-state). That means that the silt layer is not explicitly included in the model. Instead, we enter an appropriate value of the vertical leakance. Hence, the head in the silt layer is not calculated but the exchange of water between the upper and the lower aquifer through the silt layer is. To set up the model, proceed as follows:
Chapter 4
Figure 4.1: Conguration of the model Create a new model in PMWIN and lay out the grid. Use 2 model layers (each representing a single aquifer), 20 rows and 27 columns. You can nd the model extent from gure 4.1. Load the basemap for this exercise by going to Options Map in the grid editor. Right click on the DXF File eld and open the le basemap.dxf (which you just copied from Blackboard). Make sure you check the box in front of the lename. The map will be loaded but it is shifted relative to the grid. You can move the grid by selecting Options Environment and entering Xo = 200 and Yo = 6000 in the Coordinate System tab. You can already rene the grid at the location of the well eld. To do so, leave the Grid Editor and enter it again. Then halve the widths of the columns 8 through 14 and rows 7 through 12 by repeatedly right-clicking each of them and specifying the appropriate renement factor (= 2). Your grid will look like the one in gure 4.2. Set the appropriate layer properties (conned or unconned) under Grid Layer property. Select User dened for the Transmissivity and Leakance. Set the boundary conditions. The granite hills will be represented by inactive grid cells. Use the Polygon feature of the PMWIN editor to accurately delineate the hills. You can copy the inactive cells to the second model layer by activating the Layer copy button on the toolbar. The boundary condtition 22
MODFLOW
Table 4.1: Aquifer system parameters for river valley exercise Parameter magnitude units m/day m/day
Aquifer 1 (phreatic) Horizontal hydraulic conductivity (kh ) 5 Vertical hydraulic conductivity (kv ) 0.5 Porosity (n) 0.2 Silt layer (conning unit) Horizontal hydraulic conductivity (kh ) 0.5 Vertical hydraulic conductivity (kv ) 0.05 Porosity (n) 0.25 Aquifer 2 (conned) Horizontal hydraulic conductivity (kh ) 2 Vertical hydraulic conductivity (kv ) 1 Porosity (n) 0.25 River Stage (upstream/downstream) 19.4/17 Bottom elevation (upstream/downstream) 17.4/15 Width 100 River bed hydr. conductivity 2 River bed thickness 1
m/day m/day
m/day m/day
m m m m/day m
at the upstream and downstream valley boundaries will be xed heads. The values of the xed heads (which you need to enter later under Grid Initial and prescribed heads) are in the le xed heads.dat. Specify the layer top elevations by going to Grid Top of Layers and loading the les top1.dat and top3.dat. Specify the layer bottom elevations by going to Grid Bottom of layers. Do not accept the option for determining the bottom elevations from the top elevations of the underlying layers. Set the bottom elevation of layer 1 to the elevation of the top of the silt layer, which is stored in the le top2.dat. Set the bottom of layer 2 to a constant value of 0 m. Select Parameters Time and set the time units to days and specify that this will be a steady-state simulation. Specify the transmissivity, vertical leakance, horizontal hydraulic conductivity and effective porosity. You can calculate these number with the data from table 4.1 and the thicknesses of the layers (look these up in the model). Take care of the following: 1. Note that the thickness of the conned aquifer is not constant. Therefore, the transmissivity of this layer varies. You can calculate it au23
Chapter 4
tomatically by using a trick. First, set the hydraulic conductivity to 2 m/day in each cell (use the Reset matrix function). Then load the le top3.dat which contains the aquifer top elevation. Since the bottom elevation is 0 everywhere, the numbers in this le equal the thickness of the aquifer. Before pressing the Ok button to load the le, select the option multiply. The numbers currently in the grid will be multiplied with the numbers in the le. 2. The vertical leakance is only dened for the rst model layer. It is not dened for the bottom model layer (you can check this in the MODFLOW input le later). It is dependent on the thicknesses of all 3 hydrostratigraphic units. It is a bit harder to calculate than the transmissivity so the le has been prepared for you. It is called vcont1.dat. Check if you understand how these values have been calculated. Do this by calculating the value for a particular cell by hand. Add the river. MODFLOW requires that the river data (i.e. stage, bottom elevation, and riverbed conductance) are specied for each grid cell that the river intersects. Go to Models MODFLOW Flow packages River. Use the Polyline input method to accurately trace the river. Vertices are added by left-clicking; dening the polyline is cancelled by right-cliking. To complete the polyline, left-click the last vertex you specied again. Then right-click the leftmost (upstream) vertex and enter the data for this river node (the values are in table 4.1). Do the same for the rightmost (downstream) vertex. You do not need to enter the values for the other vertices: PMWIN interpolates between the two outer vertices, which makes life a bit easier. After entering all the data make sure that you did not forget anything. Checking the input is an important step in groundwater modelling, especially if you are running models that take a couple of hours to nish. Then run MODFLOW. Graphical user interfaces like PMWIN are great in that they tremendously facilitate data entry. The drawback is that a lot of the action takes place behind the scenes and remains hidden from the user. For example, PMWIN generates all the input les that MODFLOW needs. Usually, there is no need to edit these input les yourself but as an academic you are naturally curious of how they look. Moreover, sometimes a graphical user interface does not support all the options of a code and you may need to modify the input les directly. Therefore, before proceeding, go to your working directory that contains all the les of this model. Look up the le that has the extension .nam. It contains a list of the lenames that are used by MODFLOW. Look up these les and try to nd out what their purpose is and what data they contain. Then plot the hydraulic head distribution using Tools 2D Visualization. Also check the water balance. You can use either the water budget option of PMWIN or open the le output.dat in a text editor. How much water enters the model domain 24
MODFLOW
Figure 4.2: Model grid through the upstream valley boundary? And how much water leaves through the downstream boundary? The river is both a source and a sink of water to the aquifer. But on the whole, is this a losing or a gaining river? Note that the water balance error is basically zero. Write down the numbers as we will compare them to the model with groundwater abstraction later. Then run the model again but with the 3 wells in place in the conned aquifer. Each withdraws water at a rate of 500 m3 /day from layer 3, which is entered under Models MODFLOW Flow packages Well. Again, observe the head distribution. This time, also use PMPATH to draw ow lines. Then check the water budget again. What percentage of the pumped water derives from groundwater and how much is inltrated river water? By how much has the river discharge decreased at the downstream model boundary compared to the natural situation? Then change the model from a quasi-3D to a full 3D model. The easiest way to do this is to: go to Grid Mesh size and subdivide the second model layer into 2 layers. Do this by pressing PgDn to go to the second model layer. Then you can right-click on any cell and type 2 in the Layer renement eld. set the appropriate layer properties under Grid Layer property. Select Calculated for the Transmissivity and Leakance. This means that the values of these parameters will be calculated by MODFLOW using the hydraulic conductivities and layer top and bottom elevations. 25
Chapter 4
set the boundary conditions. The values for the two aquifers remain the same as before. The inactive cells of the second model layer (the silt layer) are the same as for the aquifers, but the boundaries on the upstream and downstream valley boundaries are no-ow boundaries (we assume that ow is purely vertical in the silt layer so there is no ow over the boundary). set the layer top and bottom elevations using the values from the les you used earlier. set the horizontal and vertical hydraulic conductivity and effective porosity to the values from table 4.1. If you run the model you will get basically the same results as with the quasi3D model. Check this by comparing the head distribution and the water balance. As a nal exercise, do a sensitivity analysis for the hydraulic conductivity of the river bed. As you can imagine, this parameter is extremely difcult to quantify and it will also probably be quite variable along the streambed. We have used a value of 1 m/day but why could they not range between 0.5 to 2 m/day? Re-run the model using these extremes and investigate the effect on the hydraulic head distribution and the water budget. Dont let these result make you lose faith in models but consider them a lesson in critical thinking.
26
Chapter 5
Chapter 5
Figure 5.1: Rectangular model area with short east- and western and long northern and southern boundaries. mode. Look up the meaning of this parameter in the help le! What are the model dimensions? 3. We start with a conned aquifer so the vertical resistance of the rst model layer should be set to 0 (which is interpreted as innite by MicroFEM). The transmissivity is T = kD = 800 m2 /day. These parameters are entered in the input mode. 4. Groundwater ow is in a WSW direction parallel to the long sides of the model. The head at the eastern boundary is 20 m and the hydraulic gradient is 0.001. Assign head values to all model nodes by marking the east model boundary in the walking mode and using a formula that calculates the head as a function of the head on the eastern boundary, the gradient and the variable d (which represents the distance to the nearest marked node). 5. Make a contour map in the drawing mode to check that the heads were entered correctly. Double-check by going to the western boundary: the head should be 7.631 m here. 6. Go to the xed node that contains the well (coordinates 4500, 3000). Note that it has the label xed node 5 so it is easily found by using the Jump to node function in the walking mode. Press F12 or the Jump to node button, select Next label and choose xed node 5 from the pull-down list. Make sure that you ended up in the right node (check the coordinates as well as the label in the lower-right corner of the screen) and then assign the well discharge to this node in the input mode. Well discharge has a positive value in MicroFEM, contrary to MODFLOW! Also change the name (= the value of the parameter label1) of this node from xed node 5 to Well. 30
MicroFEM
7. Run the model by going to Calculate Go calculate. Why is there no convergence? 8. Restore the natural hydraulic head situation by repeating step 4. Then x the heads on the eastern and western model boundaries. Mark the nodes on these boundaries and make sure that the head of the rst aquifer is selected in the parameter list. Then use the Toggle heads for marked nodes function to x the heads: The word xed will appear in the parameter list for the marked nodes. 9. Run the model again by going to Calculate Go calculate. This time, a solution is found. Why? 10. Draw the hydraulic head contours in the drawing mode. You can overlay a set of ow vectors to visualize the ow. Explore the options of the drawing mode by clicking around a bit. 11. Go to the node that contains the well to draw the owlines to delineate the capture zone of the well. Specify a number of 12 owlines, a timestep of 100 years, layer thickness of 40 m and a porosity of 30 %. What is the width of the capture zone? Why are the isochrons curved? 12. Set up a water balance for the entire model. You can nd the water balance options in the walking mode. What is the inow through the eastern model boundary? And what is the outow over the western boundary? 13. We will now change the model from a conned aquifer with a well to a semi-conned aquifer without a well. Moreover, we set the transmissivity downstream of the well to 300 m2 /day. The groundwater table (h0) is set to the original hydraulic heads under natural conditions. Make sure to make the following changes: Assign a hydraulic resistance (= parameter c1) of 2500 days to the conning unit. Set the groundwater table by marking the eastern boundary and entering the formula (as in step 4 but now for h0 instead of h1): 20-0.001*d. Change the transmissivity downstream of the well from 800 m2 /day to 300 m2 /day. Do this by marking the appropriate nodes and assigning the value of 300 m2 /day to the marked nodes only in the input mode. Remove the well from the model (i.e. set the discharge to 0). 14. Calculate the heads. Also make a contour plot of h1-h0 through the following steps: Go to Project Project Manager to add an extra variable for each node that can be used to hold intermediate results. A window will appear with a list of all MicroFEM les for this model. 31
Chapter 5
Click the button with the bright-green + sign, select Xtra worksheet, check New in the Create data from eld (otherwise you will be asked for a le to read the data from) and click OK. You can choose to have as many registers (= new input elds) as you like, but 1 will be enough for our purposes. Note that the project manager is also the place to add special types of boundaries. Close the project manager and note that an new tab has been created that is called Xtra. It contains an edit eld for a variable x1. This variable can contain any value we assign to it without affecting the calculations. Since we are interested in the head difference across the semi-conning unit we assign the result of the formula h1-h0 to all nodes. The positive values of the head difference indicate that there is upward seepage in the whole model domain. Check the water balance. How much is the upward seepage through the semi-conning unit? 15. Then activate the well again. Calculate the model and check the water balance. Indicate the zones of upward seepage and inltration by drawing the difference between h0 and h1. Calculate the volumetric rate of upward seepage/inltration (in m3 /day) for each node (in the Xtra worksheet). Check your calculation by comparing it to the water balance. 16. What proportion of the well discharge inltrates through the semi-conning unit and what proportion derives from regional groundwater ow?
32
Chapter 6
Inltration canal
This problem serves to demonstrate the supremacy of nite element models over nite difference models when it comes to grid design. A shallow inltration canal loses water to two fully penetrating drains. The drains are 120 m apart, with water levels at 40 and 35 m (left and right side, respectively) above an impervious base. The water level of the 5 m deep and 25 m wide inltration canal is 55 m (see gure 6.1). The aquifer is homogeneous and isotropic, with hydraulic conductivity k = 25 m/day. We will simulate this problem as a prole model. A hollow groundwater table will develop between the inltration canal and the drains. The grid must be deformed in order to represent the saturated part of the model domain. Remember that at the groundwater table the pressure of the water P = Pabs Patm = 0 so P that the hydraulic head h = z + g = z, where z is the so-called elevation head. In other words, the elevation of a water table node above a reference level (in this case the impermeable base) needs to be equal to the calculated head. The mesh needs to be adjusted after each calculation so that the top model boundary coincides with the groundwater table. 1. In order to save you some time, the conguration of the network has already been prepared and can be found on Blackboard. The xed nodes, triangles and quadrangles that make up the mesh are stored in the le prole model.fen. Open this le in MicroFEM by going to Files New Grid and pressing OK. A le selector window appears. Open the fen le and check how the FemMesh network has been dened. 2. Create the network and go to MicroFEM. Select 1 as the number of layers. A prole model is implemented in MicroFEM by assigning an innite resistance to the upper conning unit (i.e., c1 = 0) and entering the hydraulic conductivity (k-value) instead of the transmissivity. 3. Then set up the model: assign xed heads to the nodes that represent the canal and the drains and set the appropriate values for h1. Enter the transmissivity (= hydraulic conductivty). As a preparation for subsequent steps
Chapter 6
Figure 6.1: Conguration of the ow problem of the inltration canal give the nodes that sit between the canal and the drains the label water table. 4. You are now ready to calculate the model for the rst time. New heads will be calculated, which provide a rst estimate of the shape of the groundwater table. We can use these to relocate the nodes at the top of the model domain. Take the following steps and follow these carefully (otherwise MicroFEM could crash): Go to Export Special ASCII les and select CSV-le. For each node all the model parameters, together with the x- and y-coordinates, will be exported. The trick is now to change the y-coordinates of the water table nodes and set these equal to the head we just calculated (parameter h1). You could in theory do this in Excel but its a pain. Python is much better suited for this purpose. Remember also that this is only a small le but the output from a real-world model may not even t in Excels datasheet. A le called read csv le.py is available on Blackboard. Download it to the same directory where you saved the csv le. The comments in the le explain in detail what it does. Inspect the le and make sure that you understand what is going on. Then run it. Return to MicroFEM and select Import Special ASCII les. Select CSV-le and open the le you just saved in Excel. The new coordinates will be read and the nodes on the upper model boundary have shifted downwards. The grid has been deformed and now is a better approximation of the shape of the saturated part of the model domain. With the nodes shifted, the shape of the elements is not necessarily ideal. Therefore we will let MicroFEM optimize the shape of the net34
MicroFEM
work. In the Walking mode, mark all nodes. Then go to the Alter grid mode and press F10 (Relocate marked nodes). You can see the network being optimized. It doensnt hurt to do this 2 more times to get the most optimal grid. Now calculate the heads again and repeat the steps above until the shape of the grid (or the position of the groundwater table) no longer changes. The ow problem is then solved. In this example, the shape of the grid depends on the calculated heads. The exibility of nite element methods and the powerful capabilities of MicroFEM allow you to solve this problem. Solving the same type of problem in MODFLOW is not so easy! 5. Draw owlines starting at all nodes of the inltration canal bed. Hint: give these nodes the same label (e.g. canal). 6. Set up a water balance. How much water is lost to each drain? 7. If you have time left, you can play around with the hydraulic conductivity and see what effect it has. For example, change use a value of k = 1 m/day and note the effect on the head contours and the water balances. Or you could introduce anisotropy (e.g. kh = 25 and kv = 1 m/day).
35
Chapter 7
(7.1)
where h is the dependent variable, x is the independent variable, A is the slope or gradient and B is the intercept, i.e. the value of h when x = 0. 39
Chapter 7
h0
qx
h1
x0 x
x1
Figure 7.1: Schematic cross-section depicting a conned aquifer with onedimensional horizontal ow.
= h0 = h1
(7.3) (7.4)
x=x1
Combining conditions 7.3 and 7.4 with Equation 7.1 and yields a system of two linear equations: h0 = Ax0 + B h1 = Ax1 + B (7.5) (7.6)
in which A and B are the unknowns and x0 , x1 , h0 and h1 are known constants. If we wish to nd the numerical values of A and B we must nd the solution to this 40
Linear equations
system of linear equations. This means nding the values of A and B so that both Equation 7.5 and 7.6 are satised. Assume that h0 = 10, h1 = 9, x0 = 50 and x1 = 1501 . Let B now be the dependent and A be the independent variable so that we have: B = 10 50A B = 9 150A (7.7) (7.8)
One way to nd the solution is to plot Equations 7.7 and 7.8 in a graph and to look up the point where they intersect. This is shown in Figure 7.2. Obviously, this method can be inaccurate when the graph is drawn by hand and is not suitable for systems of equations with more than 2 variables. Exercise: Find the graphical solution to Equations 7.5 and 7.6 for A and B assuming x0 = 0 and the other parameters as listed above. A better way would be to use the method of substitution. This involves reducing the number of unknowns by expressing A as a function of B using either one of the Equations 7.7 or 7.8 and substituting the result into the other. The equation obtained this way can be solved for B. The value of A is subsequently found by substituting the calculated value of B in either Equations 7.7 or 7.8 and solving for A. Exercise: Find the solution of Equations 7.7 and 7.8 by the method of substitution. Verify that your answer is the same as in Figure 7.2. Note that the solution is written as {(A, B)}, i.e. a set containing an ordered pair. For the system described by Equations 7.7 or 7.8 there is one solution and therefore it is called a consistent system. An inconsistent system on the other hand has no solution. For example, the linear system: 50A + B = 10 50A + B = 9 (7.9) (7.10)
represents two parallel lines and therefore has no solution. This is denoted by a null or an empty set: or {}. Note that substitution would yield 10 = 9, which is a contradiction from which it is clear that there can be no solution. A system of two linear equations with two variables will have an innite number of solutions when the two lines coincide. This occurs if the equations are a multiple of each other. For example: 50A + B = 10 100A + 2B = 20
1
(7.11) (7.12)
41
Chapter 7
20 15 10 5
( 0. 01,10. 5) B = 10 50A
B = 9 150A
-0.050
-0.025
0.000 A
0.025
0.050
Figure 7.2: Graphical representation of Equations 7.7 and 7.8. represent the same line in a plot of A versus B. This is called a dependent system and the solution is either of these two equations: {(A, B) | 50A + B = 10}.
Linear equations
that can be written as a system of linear equations with three variables: 2h2 h3 = 10 h2 + 2h3 h4 = 0 h3 + 2h4 = 6
(7.15)
This system system of equations can be solved for h2 , h3 and h4 by an algorithm called Gaussian elimination. It uses elementary row operations to transform the linear equations into a form that is easily solved. Application of these operations does not change the solution of the system of linear equations. The operations are: 1. Equations can be interchanged 2. An equation can be multiplied with a non-zero constant 3. An equation can be multiplied by a constant and added to another equation As an example, rst reverse the rst and second equation in the system dened by Equation 7.15 (Operation 1): h2 + 2h3 h4 = 0 2h2 h3 = 10 h3 + 2h4 = 6
(7.16)
Then add 2 times the rst equation to the second equation (Operation 3): h2 + 2h3 h4 = 0 3h3 2h4 = 10 h3 + 2h4 = 6
(7.17)
Finally, multiply the third equation by 3 (Operation 2) and add the second equation (Operation 3): h2 + 2h3 h4 = 0 3h3 2h4 = 10 4h4 = 28
(7.18)
This form of the system of equations is called echelon form (or row echelon form), meaning that that the rst non-zero leading coefcient in an equation is to the right of the rst leading coefcient in the equation above it. A system is in reduced-echelon form when the rst coefcient in an equation is always one. To transform the system of equations into reduced-echelon form, equation 1 is multiplied by -1, equation 2 by 1/3 and equation 3 by 1/4: h2 2h3 + h4 = 0 h3 2/3h4 = 10/3 h4 = 7
(7.19)
43
Chapter 7
which immediately yields h4 = 7. The values of h2 and h3 are subsequently found by substitution. Exercise: Find the values of h2 and h3 by back-substitution.
Exercise: Find the values of A and B in Equations 7.7 and 7.8 by Gaussian elimination.
44
Chapter 8
Matrices
8.1 Denition
A matrix is a rectangular array of numbers. It consists of m rows and n columns, which are written between square or round brackets. For example, the matrix A: A= 1 3 5 2 4 6 (8.1)
This matrix has 2 rows and 3 columns. Its order is therefore 2 3. Each number in the matrix is called an element. Elements can be real or complex numbers. Elements are denoted by ar,c whereby subscripts r and c refer to the row and column number, respectively. For example, a2,3 refers to the number in the second row and third column, i.e. a2,3 = 6. Sometimes the comma between the row and column indexes is omitted but this may lead to ambiguity when m 10 or n 10. Two matrices are equal if their order is the same and when all the corresponding elements in both matrices are the same. The transpose of a matrix is obtained when its rows and columns are interchanged. The transpose of A is denoted by AT and is dened as AT = (ac,r ), for 1 r m and 1 c n. The order of AT is n m. For example: 1 2 AT = 3 4 (8.2) 5 6 Exercise: Dene A in Python and nd AT .
Chapter 8
matrix when AT = A. For a skew-symmetric matrix AT = A. The elements ar,c of a square matrix A for which r = c together form the principal or main diagonal. The sum of these elements is called the trace. If a square matrix A has ar,c = 0 when r = c then this matrix is called a diagonal matrix. A triangular matrix is a square matrix that has only non-zero values on or on one side of the principal diagonal. An upper triangular matrix has all non-zero elements on the principal diagonal or above it. All elements below its principal diagonal are zero. A lower triangular matrix has all non-zero elements on or below the principal diagonal and only zero elements above it. A diagonal matrix of which all elements ar,c = 1 when r = c is called an unit or identity matrix, which is denoted by I. For example, an identity matrix of size 3: 1 0 0 (8.3) I= 0 1 0 0 0 1 A matrix whose elements all equal zero is called a zero matrix, which, unlike an identity matrix, is not necessarily square. It is usually denoted by O or 0. Zero and identity matrices play the same role as the numbers 0 and 1 in ordinary algebra. Exercise: Use the standard Numpy commands to create a diagonal matrix, a zero matrix and an identity matrix, all of order 3 3.
8.3 Operations
Addition
If two matrices A and B are of the same order, their individual elements can be added. Their sum is dened as A + B = (ar,c + br,c ), for 1 r m and 1 c n. For example: B= 7 9 11 8 10 12 7 9 11 8 10 12 8 12 16 10 14 18 (8.4)
A+B =
1 3 5 2 4 6
(8.5)
Matrix addition is both commutative: A + B = B + A and associative: A + (B + C) = (A + B) + C. For a zero matrix of the same order as A it holds that A + O = O + A = A. 46
Matrices
Subtraction
Similarly, matrices A and B can be subtracted. The difference is dened as A B = (ar,c br,c ), for 1 r m and 1 c n. So: 1 3 5 2 4 6 7 9 11 8 10 12 6 6 6 6 6 6
AB =
(8.6)
Scalar multiplication
Multiplying each element of a matrix A with a scalar number gives the scalar product A = A = (ar,c ), for 1 r m and 1 c n. For example: 2A=2 1 3 5 2 4 6 = 2 6 10 4 8 12 (8.7)
Matrix multiplication
A matrix can also be multiplied with another matrix provided that the left matrix has the same number of rows as the number of columns of the right matrix. The result is called the matrix product. If A has order m n and C has order n p then the product
n
AC =D =
i=1
ar,i ci,c
(8.8)
(8.9)
AC =
1 7 + 3 9 + 5 11 1 8 + 3 10 + 5 12 2 7 + 4 9 + 6 11 2 8 + 4 10 + 6 12
89 98 116 128
(8.10)
Matrix multiplication is not commutative, i.e. AB = BA, because the dimensions may not agree if the order is reversed. Just like for real numbers, matrix 47
Chapter 8
multiplication is both associative, i.e. (AB)C = A(BC) and distributive, i.e. (A + B)C = AC + BC and C(A + B) = CA + CB. The result of a multiplication of a matrix A by a zero matrix O is A O = O = 0. Multiplying a matrix A with an identity matrix I gives A I = A. For square matrices it holds that A I = I A = A and A O = O A = O. Note that matrix division is undened. So if A C = D then there is no such thing as C = D/A. If A and D are give, C can be found, however, by multiplying D with the so-called inverse of A (A has to be square). Before discussing this concept, it is necessary to introduce another matrix property, the determinant.
8.4 Determinant
Every square matrix has a real number associated with it which is called the determinant. The determinant of matrix A is denoted by det A or sometimes |A|. It is not so easy to explain what a determinant is in words so lets just consider its mathematical denition and start with the determinant of a 2 2 matrix. It is dened as the product of the elements on the principal diagonal minus the product of the elements off the principal diagonal: det a1,1 a1,2 a2,1 a2,2 = a1,1 a2,2 a1,2 a2,1 (8.11)
For square matrices of size 3 and more, a technique called Laplace expansion can be used to determine the determinant. It is based on the expansion of a matrix in minors and cofactors.
Minor
Suppose we have square matrix A. For every element ar,c in A there exists a quantity called minor which is the determinant of the matrix that results when the row r and column c are deleted from the original matrix. For example: 1 1 1 (8.12) A = 2 4 3 3 6 5 then for a1,1 the minor M1,1 is: M1,1 = det 4 3 6 5 = 4 5 3 6 = 2 (8.13)
Cofactor
The cofactor is the minor Mr,c multiplied by (1)r+c : Cr,c = (1)r+c Mr,c 48 (8.14)
Matrices
where Cr,c is the cofactor. The factor (1)r+c effectively determines the sign of the minor depending on its position within the matrix. So if r + c is positive, the sign of the minor does not change. If r+c is negative the sign of the minor reverses. Exercise: Calculate the cofactors C1,1 , C1,2 and C1,3 .
With the minor and cofactor dened, the determinant of a matrix can be found from:
n
det A =
c=1
ar,c Cr,c
(8.15)
for any row r. In words this formula reads: The determinant of a matrix is the sum of the product of the elements in a particular row multiplied by their cofactors. For example: 1 1 1 (8.16) det A = det 2 4 3 = a1,1 C1,1 + a1,2 C1,2 + a1,3 C1,3 3 6 5 Inserting the numbers gives: det A = 1 2 + 1 1 + 1 0 = 1 (8.17)
The same approach can be applied by selecting a particular column rather than a row. The determinant is the calculated from:
m
det A =
r=1
ar,c Cr,c
(8.18)
For square matrices of size 4 and higher, the approach is the same. The work involved can be substantial: For a 4 4 matrix, four cofactors must be calculated, each requiring three 2 2 determinants to be calculated, i.e. a total of twelve 2 2 determinants. For any size n the number of 2 2 determinants to be calculated is n!/2. In practice this number can be less if the matrix contains zero elements: Because the cofactor is multiplied with the value of the element, there is no need 49
Chapter 8
to calculate the cofactor if it is multiplied by a zero anyway. Consider a matrix Z which contains 2 zero elements in column c = 2: 6 4 0 2 8 0 2 4 (8.19) Z= 6 0 4 2 18 4 6 2 Expanding along column c = 2 will halve the number of calculations involved since there is no point in calculating the cofactors C2,2 and C3,2 because these are multiplied with z2,2 = 0 and z2,3 = 0. Exercise: Use Python to calculate the determinant of Z.
Transposing a square matrix does not change it determinant, i.e. det A = det AT . If any two rows or columns are interchanged the numerical value of the determinant remains the same but its sign changes. If a matrix is multiplied by a scalar, then the determinant is also multiplied by this scalar, i.e. det A = det A. For matrix multiplication it holds that when A and B are square and of the same order, det AB = det A det B
(8.20)
(8.21)
Matrices
for 1 r m and c = r. Ac is the matrix that is obtained when column c in A is replaced by column vector R. For example, to nd x1 , the rst step is to calculate det A1 , which is: 9 1 1 (8.24) det A1 = det 1 4 3 = 7 0 6 5
The determinant of A was calculated earlier (Equation 8.17). Inserting these values into Equation 8.23 gives: 7 x1 = =7 (8.25) 1
The determinant of a matrix can be zero if an entire row is zero or if a row (or column) is a multiple of another row (or column). This also includes rows (or columns) which are the same (i.e. the multiplier is 1). If the determinant of a matrix is zero, it is called a singular matrix. Since det A appears in the denominator of Equation 8.23, Cramers rule can not be applied when a matrix is singular. Several conditions may apply depending on the values of the determinants of A and R. These are summarized in table 8.1. A hydrological application of Cramers rule is in the derivation of the nite element approximation of the groundwater equation.
Table 8.1: Possible solutions for systems of linear equations depending on the values of det A and det R. det A = 0 det A = 0 det R = 0 unique solution innite number of solutions det R = 0 X = 0 (trivial solution) innite number of solutions if det Ac = 0, 1 c m 51
Chapter 8
in which C is a matrix of cofactors of A and its transpose C T is the so-called adjugate of A. From Equation 8.27 it follows that the inverse can only exist if det A = 0. If this is the case then A is called a non-singular matrix (as opposed to a singular matrix). For matrix A in Equation 8.12, C is: 2 1 0 (8.28) C = 11 8 3 7 5 2 so: 2 11 7 2 11 7 1 1 1 8 5 = 1 8 5 = CT = det A 1 0 3 2 0 3 2
A1
(8.29)
Exercise: Express the system of linear equations dened by Equation 7.15 in matrix form, i.e., Ah = R. Find h by calculating A1 and applying Equation 8.26. Obviously, calculating the inverse of a matrix by hand can be a lot of work and mistakes are easily made. Computers are much better at these sorts of calculations than humans. Exercise: Use Python to calculate A1 and A1 R = X.
52
References
Chiang, W. H., 2005. 3D-Groundwater modeling with PMWIN. Springer, Berlin Heidelberg, Germany. Wang, H. F., Anderson, M. P. 1982. Introduction to Groundwater Modeling: Finite Difference and Finite Element Methods. W. H. Freeman and Co, Gordonsville, Virginia, USA.
53