See discussions, stats, and author profiles for this publication at: https://www.researchgate.net/publication/296579538 Seismic petrophysics: Part 2 Article in The Leading Edge · June 2015 DOI: 10.1190/tle34060700.1 CITATIONS READS 2 534 1 author: Alessandro Amato del Monte Eni 16 PUBLICATIONS 14 CITATIONS SEE PROFILE Some of the authors of this publication are also working on these related projects: Leading Edge tutorials View project All content following this page was uploaded by Alessandro Amato del Monte on 02 March 2016. The user has requested enhancement of the downloaded file. G E O P H Y S I C A L T U T O R I A L — C O O R D I N AT E D Seismic petrophysics: Part 2 BY M AT T H A L L Downloaded 06/03/15 to 151.96.3.241. Redistribution subject to SEG license or copyright; see Terms of Use at http://library.seg.org/ Alessandro Amato del Monte 1 n Part 1 of this tutorial in the April 2015 issue of TLE, we loaded some logs and used a data framework called Pandas to manage them. We made a lithology-fluid-class (LFC) log and used it to color a crossplot. This month, we take the workflow further with fluid-replacement modeling based on Gassmann’s equation. This is just an introduction; see Wang (2001) and Smith et al. (2003) for comprehensive overviews. Fluid-replacement modeling is used to predict the response of elastic logs (VP , VS , and density) in different fluid conditions. In that way, we can see how much a rock would change in terms of velocity (or impedance) if it was filled with gas instead of brine, for example. It also brings all elastic logs to a common fluid “denominator,” enabling us to disregard fluid effects and focus only on lithologic variations. # Forward Gassmann k _ s2 = k _ d + (1 - (k _ d/k0))**2 /\ ((phi/k_f2) + ((1-phi)/k0) - (k _ d/k0**2)) I # New properties rho2 = rho1-phi * rho_f1+phi * rho _ f2 mu2 = mu1 vp2 = np.sqrt(((k_s2+(4./3)*mu2))/rho2) vs2 = np.sqrt((mu2/rho2)) return vp2*1000, vs2*1000, rho2, k _s2 This function takes the following parameters: • vp1, vs1, rho1: measured VP, VS , and density — satu- • • • • rho_ f1, k _ f1: density and bulk modulus of fluid 1 rho_ f2, k _ f2: density and bulk modulus of fluid 2 k0: mineral bulk modulus phi: porosity Creating new logs rated with fluid 1 The inputs to fluid-replacement modeling are Ks and μs (saturated bulk and shear moduli, which we can obtain from recorded VP, VS , and density logs), Kd and μd (dry-rock bulk and shear moduli), K 0 (mineral bulk modulus), K f (fluid bulk modulus), and porosity, φ. Reasonable estimates of mineral and fluid bulk moduli and porosity are computed easily. The real unknowns, arguably the core issue of rock physics, are the dry-rock moduli. To find the bulk modulus of a rock with the new fluid, we first use an inverse form of Gassmann’s equation to compute the dry-rock bulk modulus and then apply the direct form: Kd Ks = Kd + ( 1− K0 2 ) φ 1−φ Kd + − 2 Kf K 0 K0 . We can put all the steps together into a Python function (see the IPython notebook for details, available online at github. com/seg), calculating the elastic parameters for fluid 2, given the parameters for fluid 1, along with some other data about the fluids: def frm(vp1, vs1, rho1, rho _ f1, k _ f1, rho _ f2, k _ f2, k0, phi): # Original properties vp1 = vp1 / 1000. vs1 = vs1 / 1000. mu1 = rho1 * vs1**2. k_s1 = rho1 * vp1**2 - (4./3.)*mu1 and returns VP , VS , density, and bulk modulus of the rock with fluid 2. Velocities are in meters per second, and densities are in grams per cubic centimeter. This is how we can create gas sands that we discussed in Part 1 of this tutorial. In the IPython notebook, I go into more detail to show how to compute mineral moduli and mixed-fluid moduli. I also demonstrate how to put all the results together in a Python container for later use and how to update the LFC log we created last time to reflect the newly available gas sands. Results The final result is shown in Figure 1, highlighting a detail of the reservoir section between 2150 m and 2200 m with acoustic impedance (I P ) and VP /VS ratio for the in situ case (gray curve), brine case (blue), and gas case (red). The LFC log on the right is still the original one computed on the in situ case (gray curve). The same data are shown in the I P versus VP /VS domain in Figure 2. We can make a few qualitative observations from these crossplots: • • 1 700 Shales are overall quite different from sands thus are potentially easy to identify. Brine sands have higher I P and VP /VS than hydrocarbonbearing sands have. Oil and gas cases are not very different from each other. Further investigation could be done on the shale intervals that overlap with brine sands. # Inverse Gassmann k_d = (k _s1 * ((phi*k0)/k_f1+1-phi)-k0) /\ ((phi*k0)/k_f1+(k _s1/k0)-1-phi) • • Milan, Italy. http://dx.doi.org/10.1190/tle34060700.1. THE LEADING EDGE June 2015 Downloaded 06/03/15 to 151.96.3.241. Redistribution subject to SEG license or copyright; see Terms of Use at http://library.seg.org/ Moving away from well logs Fluid-replacement modeling has allowed us to create an augmented data set. Now we will move away from the intricacies and local irregularities of the real data to create a fully synthetic data set that represents an idealized version of the reservoir. We do this by analyzing the data through simple statistical techniques in terms of tendency, dispersion, and correlation among certain elastic properties for each lithofluid class. Central tendency is described by calculating the mean values of some desired elastic property for all the existing classes. Dispersion and correlation are summarized with the covariance matrix, which can be written like this (for two generic variables X and Y ): [ var _ X [ cov _ XY cov _ XY ] var _ Y ] Figure 1. Results of fluid-replacement modeling. With three variables instead, we would have [ var _X [ cov _ XY [ cov _ XZ cov _ XY var _ Y cov _ YZ cov _ XZ ] cov _YZ ] var_Z ], where var_X is the variance of property X, i.e., a measure of dispersion about the mean, whereas the covariance cov _XY is a measure of similarity between two properties X and Y. We will study the data set using only two properties (I P and VP /VS ) and store everything in the DataFrame stat: LFC I P _mean VP /VS _mean IP _var 1 2 6790 2.11 199721 6185 2.01 337593 3 5816 1.94 360001 4 6088 2.32 492525 LFC IP _VPVS _cov VPVS _var Samples 1 –27.95 0.0205 1546 2 –16.72 0.0234 974 3 8.67 0.0204 840 4 –98.02 0.0563 4512 There are four rows, one for each lithofluid class: shale, brine, oil, and gas sands. For each class, we store the mean values, the variances, and the covariance. The number of samples that is a metric on the robustness of the analysis, i.e., too few samples, points to a potential unreliability of the statistical information. Once again, it is easy to get information out of stat; e.g., the average I P of brine sands (a value of 2 in the LFC log) is >>> print stat.ix[stat.LFC==2,'Ip _ mean'] 6184.985 To display the same information graphically, this command produces Figure 3: >>> pd.scatter _ matrix(ww[ww.LFC==2].drop('LFC',1), diagonal='kde') Figure 2. Crossplots of IP and VP /VS of fluid-replaced data. 702 THE LEADING EDGE June 2015 We can now use this information to create a brand-new synthetic data set that will replicate the average behavior of the reservoir complex and at the same time overcome typical problems when using real data such as undersampling of a certain class, presence of outliers, or spurious occurrence of anomalies. The technique is a Monte Carlo simulation that relies on multivariate normal distribution to draw samples that are random but correlated in the elastic domain of choice (I P and VP /VS ). First we define how many samples per class to create (e.g., 100) and then create an empty Pandas DataFrame (called mc) with as many columns as the chosen elastic logs (in this case, three: LFC, Downloaded 06/03/15 to 151.96.3.241. Redistribution subject to SEG license or copyright; see Terms of Use at http://library.seg.org/ >>> >>> >>> Figure 3. Scatter matrix of (a) IP and (b) VP /VS for lithofluid class 2. sigma = np.reshape(stat.loc[i-1, covs[0]:covs[-1]].values, (nlogs, nlogs)) m = multivariate_normal(mean, sigma, NN) mc.ix[mc.LFC==i,1:] = m The synthetic data set is therefore a copy of my original data set in which we have added all the modifications obtained through fluid-replacement modeling and have subtracted the local discrepancies and outliers that often plague our understanding of the situation, leading us to see separation between lithologies where they are absent or similarity between fluids that are different. See Figure 4, in which the synthetic data set is compared with the augmented data set. This procedure also can be used as the basis for more advanced work, for example, modeling the progressive argillization of a reservoir or the reduction in porosity resulting from burial depth or modeling lithologic rather than fluid changes. See the discussion on training data in Avseth et al. (2005), p. 126. Conclusions With this tutorial, I have shown two ways to create new data for a reservoir system, progressively increasing the distance from the real situation encountered to allow us to make conjectures and play with more data than we normally have. We have used Python to also demonstrate how easy it is to move away from a “black-box” approach, making it possible to adjust every part of the workflow. Figure 4. Crossplots of IP and VP /VS of (a) augmented and (b) synthetic data. Corresponding author: [email protected] References I P , and VP /VS ) and rows equal to the number of samples multiplied by the number of classes (100 × 4 = 400): >>> mc = pd.DataFrame(data=None, columns=lognames0, index=np.arange(100*nlfc), dtype='float') Avseth, P., T. Mukerji, and G. Mavko, 2005, Quantitative seismic interpretation: Applying rock physics rules to reduce interpretation risk: Cambridge University Press. Smith, T. M., C. H. Sondergeld, and C. S. Rai, 2003, Gassmann fluid substitutions: A tutorial: Geophysics, 68, no. 2, 430–440, http://dx.doi.org/10.1190/1.1567211. Wang, Z., 2001, Fundamentals of seismic rock physics: Geophysics, 66, no. 2, 398–412, http://dx.doi.org/10.1190/1.1444931. Then we fill in the LFC column with the numbers assigned to each class: >>> for i in range(1, nlfc+1): >>> mc.loc[NN*i-NN:NN*i-1, 'LFC'] = i Finally, for each class, we extract the average value mean and the covariance matrix sigma from the stat DataFrame and then put them into Python’s np.random.multivariate_normal function to draw randomly selected samples from the continuous and correlated distributions of the properties I P and VP /VS: >>> for i in range(1, nlfc+1): >>> mean = stat.loc[i-1, means[0]:means[-1]].values 704 THE LEADING EDGE View publication stats June 2015 © The Author(s). Published by the Society of Exploration Geophysicists. All article content, except where otherwise noted (including republished material), is licensed under a Creative Commons Attribution 3.0 Unported License (CC BY-SA). See http://creativecommons.org/licenses/by/3.0/. Distribution or reproduction of this work in whole or in part commercially or noncommercially requires full attribution of the original publication, including its digital object identifier (DOI). Derivatives of this work must carry the same license.