class Well(object): """ generic well :var WATER: phase identifier for water well :var GAS: phase identifier for gas well """ WATER="Water" GAS="Gas" def __init__(self, name, domain, Q=[0.], schedule=[0.], phase="Water", BHP_limit=1.*U.atm, X0=[0.,0.,0.], *args, **kwargs): """ set up well """ if not len(schedule) == len(Q): raise ValueError("length of schedule and Q must match.") self.__schedule=schedule self.__Q = Q self.__phase=phase self.__BHP_limit=BHP_limit self.name=name self.domain=domain self.locator=Locator(DiracDeltaFunctions(self.domain),X0[:self.domain.getDim()]) self.X0=self.locator.getX() def getLocation(self): return self.X0 def getProductivityIndex(self): """ returns the productivity index of the well. typically a Gaussian profile around the location of the well. :note: needs to be overwritten """ raise NotImplementedError def getFlowRate(self,t): """ returns the flow rate """ out=0. for i in range(len(self.__schedule)): if t <= self.__schedule[i]: out=self.__Q[i] break return out def getBHPLimit(self): """ return bottom-hole pressure limit :note: needs to be overwritten """ return self.__BHP_limit def getPhase(self): """ returns the pahse the well works on """ return self.__phase
def subsample(u, nx=50, ny=50): """ subsamples ```u``` over an ```nx``` x ```ny``` grid and returns ``numpy`` arrays for the values and locations used for subsampling. """ xx = u.getDomain().getX() # points of the domain x0 = inf(xx[0]) y0 = inf(xx[1]) dx = (sup(xx[0]) - x0) / nx # x spacing dy = (sup(xx[1]) - y0) / ny # y spacing grid = [] for j in range(0, ny - 1): for i in range(0, nx - 1): grid.append([x0 + dx / 2 + dx * i, y0 + dy / 2 + dy * j]) uLoc = Locator(u.getFunctionSpace(), grid) subu = uLoc(u) # get data of u at sample points closests to grid points usublocs = uLoc.getX() #returns actual locations from data return np.array(usublocs), np.array(subu)
def subsample(u, nx=50, ny=50): """ subsamples ```u``` over an ```nx``` x ```ny``` grid and returns ``numpy`` arrays for the values and locations used for subsampling. """ xx=u.getDomain().getX() # points of the domain x0=inf(xx[0]) y0=inf(xx[1]) dx = (sup(xx[0])-x0)/nx # x spacing dy = (sup(xx[1])-y0)/ny # y spacing grid = [ ] for j in range(0,ny-1): for i in range(0,nx-1): grid.append([x0+dx/2+dx*i,y0+dy/2+dy*j]) uLoc = Locator(u.getFunctionSpace(),grid) subu= uLoc(u) # get data of u at sample points closests to grid points usublocs = uLoc.getX() #returns actual locations from data return np.array(usublocs), np.array(subu)
if s > 0: rho=(1-m)*rho+m*1./s else: rho=(1-m)*rho+m*0. # arbitray number as air_layer is backed out in TM mode. z_top, m_top=z_top-l, m2 print("sigma =", sigma) print("rho =", rho) # # ... create Locator to get impedance at position of observations: # stationX=np.linspace(OFFSET_STATION, WIDTH-OFFSET_STATION, num=NUM_STATION, endpoint=True) loc=Locator(ReducedFunction(domain), [ (s, DEPTH-DEPTH_STATIONS) for s in stationX]) print("position of observation stations %s:"%(NUM_STATION//2,), loc.getX()[NUM_STATION//2]) # moved to the next element center!!! #================================================================================================ FRQ=1./PERIODS #================================================================================================ print("Start TM mode ...") model=MT2DTMModel(domain, airLayer=DEPTH-L_AIR) model.setResistivity(rho, rho_boundary=1/SIGMA0) # rho can be interpolated to the boundary (e.g. when conductivity is given on node) rho_boundary can be omited. # collects app. rho and phase for the frequencies: arho_TM=[] phase_TM=[] for frq in FRQ: Zyx = model.getImpedance(f=frq) arho=model.getApparentResitivity(frq, Zyx) phi=model.getPhase(frq, Zyx)
for l in range(len(layers)): m=whereNonPositive(z-z_top)*wherePositive(z-(z_top-layers[l])) V_P = V_P * (1-m) + v_P[l] * m V_S = V_S * (1-m) + v_S[l] * m Delta = Delta * (1-m) + delta[l]* m Eps = Eps * (1-m) + eps[l] * m Tilt = Tilt * (1-m) + tilt[l] * m Rho = Rho * (1-m) + rho[l] * m z_top-=layers[l] sw=TTIWave(domain, V_P, V_S, wl, src_tags[0], source_vector = src_dir, eps=Eps, delta=Delta, rho=Rho, theta=Tilt, absorption_zone=absorption_zone, absorption_cut=1e-2, lumping=lumping) srclog=Locator(domain, [ (r , depth) for r in receiver_line ] ) grploc=[ (x[0], 0.) for x in srclog.getX() ] tracer_x=SimpleSEGYWriter(receiver_group=grploc, source=srcloc, sampling_interval=sampling_interval, text='x-displacement') tracer_z=SimpleSEGYWriter(receiver_group=grploc, source=srcloc, sampling_interval=sampling_interval, text='z-displacement') if not tracer_x.obspy_available(): print("\nWARNING: obspy not available, SEGY files will not be written\n") elif getMPISizeWorld() > 1: print("\nWARNING: SEGY files cannot be written with multiple processes\n") t=0. mkDir('output') n=0 k_out=0 print("calculation starts @ %s"%(time.asctime(),)) while t < t_end:
class TestSeismic2D(unittest.TestCase): # grid spacing in DX = 10. NEx = 200 Order = 2 VP = 2000 NE_PML = 40 # PML thickness in term of number of elements NE_STATION0 = 70 # first station offset in term of number of elements Amplitude = 1 S0 = 1000 TESTTOL = 1e-2 def setUp(self): Width = self.DX * self.NEx Center = self.NEx // 2 * self.DX self.domain = Rectangle(self.NEx, self.NEx, l0=Width, l1=Width, diracPoints=[(Center, Center)], diracTags=["src"], order=self.Order, fullOrder=True) numStation = (self.NEx // 2 - 3 - self.NE_STATION0 - 1) stations = [((self.NE_STATION0 + i) * self.DX, Center) for i in range(numStation)] self.loc = Locator(Solution(self.domain), stations) self.source = Scalar(0j, DiracDeltaFunctions(self.domain)) self.source.setTaggedValue("src", self.Amplitude) self.sourceX = (Center, Center) def tearDown(self): del self.domain del self.loc del self.source del self.sourceX def test_RadialWaveLowF(self): Frequency = 0.01 k = Frequency / self.VP * 2 * np.pi assert k * self.DX < 1 L_PML = self.DX * self.NE_PML pml_condition = PMLCondition(sigma0=self.S0, Lleft=[L_PML, L_PML], Lright=[L_PML, L_PML], m=4) # sonic wave model wave = SonicWaveInFrequencyDomain(self.domain, vp=self.VP, pml_condition=pml_condition) wave.setFrequency(Frequency) # set source and get wave response: u = wave.getWave(self.source) r = np.array([ sqrt((x[0] - self.sourceX[0])**2 + (x[1] - self.sourceX[1])**2) for x in self.loc.getX() ]) uu2 = -scipy.special.hankel2(0, k * r) * 1j / 4 uu = np.array(self.loc(u)) errorA = max(abs(uu2 - uu)) A = max(abs(uu2)) self.assertLessEqual(errorA, A * self.TESTTOL) def test_RadialWaveMediumF(self): Frequency = 1. k = Frequency / self.VP * 2 * np.pi assert k * self.DX < 1 L_PML = self.DX * self.NE_PML pml_condition = PMLCondition(sigma0=self.S0, Lleft=[L_PML, L_PML], Lright=[L_PML, L_PML], m=4) # sonic wave model wave = SonicWaveInFrequencyDomain(self.domain, vp=self.VP, pml_condition=pml_condition) wave.setFrequency(Frequency) # set source and get wave response: u = wave.getWave(self.source) r = np.array([ sqrt((x[0] - self.sourceX[0])**2 + (x[1] - self.sourceX[1])**2) for x in self.loc.getX() ]) uu2 = -scipy.special.hankel2(0, k * r) * 1j / 4 uu = np.array(self.loc(u)) errorA = max(abs(uu2 - uu)) A = max(abs(uu2)) self.assertLessEqual(errorA, A * self.TESTTOL) def test_RadialWaveHighF(self): Frequency = 10. k = Frequency / self.VP * 2 * np.pi assert k * self.DX < 1 L_PML = self.DX * self.NE_PML pml_condition = PMLCondition(sigma0=self.S0, Lleft=[L_PML, L_PML], Lright=[L_PML, L_PML], m=4) # sonic wave model wave = SonicWaveInFrequencyDomain(self.domain, vp=self.VP, pml_condition=pml_condition) wave.setFrequency(Frequency) # set source and get wave response: u = wave.getWave(self.source) r = np.array([ sqrt((x[0] - self.sourceX[0])**2 + (x[1] - self.sourceX[1])**2) for x in self.loc.getX() ]) uu2 = -scipy.special.hankel2(0, k * r) * 1j / 4 uu = np.array(self.loc(u)) errorA = max(abs(uu2 - uu)) A = max(abs(uu2)) self.assertLessEqual(errorA, A * self.TESTTOL)
# save to file: saveSilo("solution", velocity=vp, amplitude=amps, phase=phase, pmlzone=pml_condition.getPMLMask(domain)) print("solution saved to file ...") # get the amplitude and phase at geophones: import matplotlib.pyplot as plt fig = plt.gcf() ax1 = plt.gca() geophoneX = [x[0] for x in geophones.getX()] color = 'tab:red' ax1.set_xlabel('offset') ax1.set_ylabel('amplitude', color=color) ax1.plot(geophoneX, geophones(amps), color=color) ax1.tick_params(axis='y', labelcolor=color) ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis color = 'tab:blue' ax2.set_ylabel('phase [deg]', color=color) # we already handled the x-label with ax1 ax2.plot(geophoneX, geophones(phase), color=color, marker=".") ax2.tick_params(axis='y', labelcolor=color) fig.tight_layout() # otherwise the right y-label is slightly clipped
sw = TTIWave(domain, V_P, V_S, wl, src_tags[0], source_vector=src_dir, eps=Eps, delta=Delta, rho=Rho, theta=Tilt, absorption_zone=absorption_zone, absorption_cut=1e-2, lumping=lumping) srclog = Locator(domain, [(r, depth) for r in receiver_line]) grploc = [(x[0], 0.) for x in srclog.getX()] tracer_x = SimpleSEGYWriter(receiver_group=grploc, source=srcloc, sampling_interval=sampling_interval, text='x-displacement') tracer_z = SimpleSEGYWriter(receiver_group=grploc, source=srcloc, sampling_interval=sampling_interval, text='z-displacement') if not tracer_x.obspy_available(): print( "\nWARNING: obspy not available, SEGY files will not be written\n") elif getMPISizeWorld() > 1: print(