1
1
import numpy as np
2
2
import inspect # Used for storing the input
3
3
from .aquifer import AquiferData
4
- from .aquifer_parameters import param_maq
4
+ from .aquifer_parameters import param_maq , param_3d
5
+ from .element import Element
5
6
from .constant import ConstantInside , ConstantStar
6
7
from .intlinesink import IntHeadDiffLineSink , IntFluxDiffLineSink , IntFluxLineSink
7
8
from .controlpoints import controlpoints
12
13
class PolygonInhom (AquiferData ):
13
14
tiny = 1e-8
14
15
15
- def __init__ (self , model , xy , kaq , c , z , npor , ltype , hstar ,
16
- order , ndeg , recharge ):
16
+ def __init__ (self , model , xy , kaq , c , z , npor , ltype , hstar , N ,
17
+ order , ndeg ):
17
18
# All input variables except model should be numpy arrays
18
19
# That should be checked outside this function):
19
20
AquiferData .__init__ (self , model , kaq , c , z , npor , ltype )
20
21
self .order = order
21
22
self .ndeg = ndeg
22
23
self .hstar = hstar
23
- self .recharge = recharge
24
+ self .N = N
24
25
self .inhom_number = self .model .aq .add_inhom (self )
25
26
self .z1 , self .z2 = compute_z1z2 (xy )
26
27
zcenter = np .sum (self .z1 ) / len (self .z1 ) # center of inhom
@@ -30,9 +31,11 @@ def __init__(self, model, xy, kaq, c, z, npor, ltype, hstar,
30
31
Zin = 1e-6j
31
32
Zout = - 1e-6j
32
33
self .zcin = 0.5 * (self .z2 - self .z1 ) * Zin + 0.5 * (
33
- self .z1 + self .z2 ) # points at center on inside
34
+ self .z1 + self .z2 ) # point at center on inside
34
35
self .zcout = 0.5 * (self .z2 - self .z1 ) * Zout + 0.5 * (
35
- self .z1 + self .z2 ) # points at center on outside
36
+ self .z1 + self .z2 ) # point at center on outside
37
+ self .zcenter = np .mean (self .z1 )
38
+ self .xcenter , self .ycenter = self .zcenter .real , self .zcenter .imag
36
39
self .x = np .hstack ((self .z1 .real , self .z2 [- 1 ].real ))
37
40
self .y = np .hstack ((self .z1 .imag , self .z2 [- 1 ].imag ))
38
41
self .xmin = min (self .x )
@@ -83,9 +86,9 @@ def create_elements(self):
83
86
if aqin .ltype [0 ] == 'a' : # add constant on inside
84
87
c = ConstantInside (self .model , self .zcin .real , self .zcin .imag )
85
88
c .inhomelement = True
86
- if self .recharge is not None :
87
- AreaSinkInhom (self .model , self .xcenter , self .ycenter , recharge = self . recharge , \
88
- layer = 0 , aqin = self )
89
+ if self .N is not None :
90
+ a = AreaSinkInhom (self .model , self .N , self .xcenter , aq = aqin )
91
+ a . inhomelement = True
89
92
if aqin .ltype [0 ] == 'l' :
90
93
assert self .hstar is not None , 'Error: hstar needs to be set'
91
94
c = ConstantStar (self .model , self .hstar , aq = aqin )
@@ -101,9 +104,8 @@ class PolygonInhomMaq(PolygonInhom):
101
104
model to which the element is added
102
105
xy : array or list
103
106
list or array of (x,y) pairs of coordinates of corners of the
104
- inhomogeneity
105
- polygonal boundary is automatically closed (so first point
106
- is not repeated)
107
+ inhomogeneity. polygonal boundary is automatically closed (so first
108
+ point is not repeated)
107
109
kaq : float, array or list
108
110
hydraulic conductivity of each aquifer from the top down
109
111
if float, hydraulic conductivity is the same in all aquifers
@@ -128,6 +130,9 @@ class PolygonInhomMaq(PolygonInhom):
128
130
semi-confined ('semi')
129
131
hstar : float or None (default is None)
130
132
head value above semi-confining top, only read if topboundary='semi'
133
+ N : float or None (default is None)
134
+ infiltration rate (L/T) inside inhomogeneity. Only possible if
135
+ topboundary='conf'
131
136
order : int
132
137
polynomial order of flux along each segment
133
138
ndeg : int
@@ -138,12 +143,81 @@ class PolygonInhomMaq(PolygonInhom):
138
143
139
144
tiny = 1e-8
140
145
141
- def __init__ (self , model , xy , kaq = 1 , z = [1 , 0 ], c = [], npor = 0.3 , topboundary = 'conf' ,
142
- hstar = None , order = 3 , ndeg = 3 , recharge = None ):
146
+ def __init__ (self , model , xy , kaq = 1 , z = [1 , 0 ], c = [], npor = 0.3 ,
147
+ topboundary = 'conf' , hstar = None , N = None , order = 3 , ndeg = 3 ):
148
+ if N is not None :
149
+ assert topboundary [:4 ] == 'conf' , \
150
+ "Error: infiltration can only be added if topboundary='conf'"
143
151
self .storeinput (inspect .currentframe ())
144
152
kaq , c , npor , ltype , = param_maq (kaq , z , c , npor , topboundary )
145
153
PolygonInhom .__init__ (self , model , xy , kaq , c , z , npor , ltype ,
146
- hstar , order , ndeg , recharge )
154
+ hstar , N , order , ndeg )
155
+
156
+ class PolygonInhom3D (PolygonInhom ):
157
+ """
158
+ Model3D Class to create a multi-layer model object consisting of
159
+ many aquifer layers. The resistance between the layers is computed
160
+ from the vertical hydraulic conductivity of the layers.
161
+
162
+ Parameters
163
+ ----------
164
+ model : Model object
165
+ model to which the element is added
166
+ xy : array or list
167
+ list or array of (x,y) pairs of coordinates of corners of the
168
+ inhomogeneity. polygonal boundary is automatically closed (so first
169
+ point is not repeated)
170
+ kaq : float, array or list
171
+ hydraulic conductivity of each layer from the top down
172
+ if float, hydraulic conductivity is the same in all aquifers
173
+ z : array or list
174
+ elevation of top of system followed by bottoms of all layers
175
+ from the top down
176
+ bottom of layer is automatically equal to top of layer below it
177
+ length is number of aquifer layers + 1
178
+ kzoverkh : float
179
+ vertical anisotropy ratio vertical k divided by horizontal k
180
+ if float, value is the same for all layers
181
+ length is number of layers
182
+ npor : float, array or list
183
+ porosity of all aquifer layers
184
+ from the top down
185
+ if float, porosity is the same for all layers
186
+ if topboundary='conf': length is number of layers
187
+ if topboundary='semi': length is number of layers + 1
188
+ topboundary : string, 'conf' or 'semi' (default is 'conf')
189
+ indicating whether the top is confined ('conf') or
190
+ semi-confined ('semi')
191
+ topres : float
192
+ resistance of top semi-confining layer (read if topboundary='semi')
193
+ topthick: float
194
+ thickness of top semi-confining layer (read if topboundary='semi')
195
+ hstar : float or None (default is None)
196
+ head value above semi-confining top (read if topboundary='semi')
197
+ N : float or None (default is None)
198
+ infiltration rate (L/T) inside inhomogeneity. Only possible if
199
+ topboundary='conf'
200
+ order : int
201
+ polynomial order of flux along each segment
202
+ ndeg : int
203
+ number of points used between two segments to numerically
204
+ integrate normal discharge
205
+
206
+ """
207
+
208
+ def __init__ (self , model , xy , kaq = 1 , z = [1 , 0 ], kzoverkh = 1 , npor = 0.3 ,
209
+ topboundary = 'conf' , topres = 0 , topthick = 0 , hstar = 0 ,
210
+ N = None , order = 3 , ndeg = 3 ):
211
+ if N is not None :
212
+ assert topboundary [:4 ] == 'conf' , \
213
+ "Error: infiltration can only be added if topboundary='conf'"
214
+ self .storeinput (inspect .currentframe ())
215
+ kaq , c , npor , ltype = param_3d (kaq , z , kzoverkh , npor , topboundary ,
216
+ topres )
217
+ if topboundary == 'semi' :
218
+ z = np .hstack ((z [0 ] + topthick , z ))
219
+ PolygonInhom .__init__ (self , model , xy , kaq , c , z , npor , ltype ,
220
+ hstar , N , order , ndeg )
147
221
148
222
149
223
def compute_z1z2 (xy ):
@@ -310,3 +384,48 @@ def create_elements(self):
310
384
assert self .hstar is not None , 'Error: hstar needs to be set'
311
385
c = ConstantStar (self .model , self .hstar , aq = aqin )
312
386
c .inhomelement = True
387
+
388
+ class AreaSinkInhom (Element ):
389
+ def __init__ (self , model , N , xc , \
390
+ name = 'AreaSinkInhom' , label = None , aq = None ):
391
+ Element .__init__ (self , model , nparam = 1 , nunknowns = 0 , layers = 0 , \
392
+ name = name , label = label )
393
+ self .N = N
394
+ self .xc = xc # x-center of area-sink
395
+ #self.nparam = 1 # Defined here and not in Element as other elements can have multiple parameters per layers
396
+ #self.nunknowns = 0
397
+ self .aq = aq
398
+ self .model .add_element (self )
399
+
400
+ def __repr__ (self ):
401
+ return self .name
402
+
403
+ def initialize (self ):
404
+ assert self .aq is not None , 'Error: no aquifer passed'
405
+ self .aq .add_element (self )
406
+ self .plabsq = self .aq .coef [self .layers , 1 :] * self .aq .lab [1 :] ** 2
407
+ self .parameters = np .atleast_2d (self .N )
408
+
409
+ def potinf (self , x , y , aq = None ):
410
+ if aq is None : aq = self .model .aq .find_aquifer_data (x , y )
411
+ rv = np .zeros ((1 , aq .naq ))
412
+ if aq == self .aq :
413
+ rv [0 , 0 ] = - 0.5 * (x - self .xc ) ** 2
414
+ rv [0 , 1 :] = self .plabsq
415
+ return rv
416
+
417
+ def disvecinf (self , x , y , aq = None ):
418
+ if aq is None : aq = self .model .aq .find_aquifer_data (x , y )
419
+ rv = np .zeros ((2 , self .nparam , aq .naq ))
420
+ if aq == self .aq :
421
+ rv [0 , 0 , 0 ] = x - self .xc
422
+ return rv
423
+
424
+ def qztop (self , x , y , aq = None ):
425
+ if aq is None : aq = self .model .aq .find_aquifer_data (x , y )
426
+ rv = 0.0
427
+ if aq == self .aq :
428
+ rv = - self .parameters [0 , 0 ]
429
+ return rv
430
+
431
+
0 commit comments