当前位置:   article > 正文

利用GRACE和地表质量模型计算地球弹性负荷变形实验笔记_如何通过grace数据导出位移

如何通过grace数据导出位移

1.背景和意义

由于地球的弹性结构,地球大尺度的质量迁移会导致地球产生负荷变形。地球的环境负载如大气、海洋、陆地水等的变化会使得固体地球产生明显的位移变化,为了准确研究有关地球物理信号,需要对弹性的负荷变形进行有效计算并扣除。通常利用格林函数法和球谐函数法,两者在数学上是等价的。

早期研究采用一维模型来表征地球内部结构及密度和速度等特征,当前进行负荷位移建模也普遍采用一维地球模型。

2.利用不同的地球模型计算love数和green函数

(1)地球模型的下载与处理

3.1 Earth’s Layers: Crust, Mantle, and Core – Physical Geology, First ...

 

本文选择了PREM、STW105和AK135地球模型。地球模型的下载网址为

http://ds.iris.edu/ds/products/emc-ak135-f/

不同地球模型的示意图

ak135-F average model

 

The anisotropic Reference Earth Model STW105 plotted with PREM and ak135

 

(2)计算love数(CF参考系)

本文使用Martens et al. (2019)提供的LoadDef程序中的run_ln.py函数计算了PREM、STW105和AK135模型10000阶次的负荷勒夫 数,并将该结果作为输入数据,使用run_gf.py函数计算了 相应的负荷格林函数。所有的用于数据输入的地球模型包含地球半径(r)、Vp、Vs和密度p四个参数。前期的模型处理:如下图,由于部分的地球模型,比如ak135和是stw105,地表包含水体等,为了计算负荷love数,需要将这部分密度进行替换,通常是用地下5km部分的密度进行替换。

 修改好的地球模型

 采用LoadDef代码进行计算,得到不同地球模型的love数,可以看到三个地球模型得到的结果还是比较接近。

(3)计算位移格林函数(CF参考系)

使用run_gf.py函数计算了 相应的负荷格林函数

 (4)准备负荷源

(4.1)GFZ提供的负荷产品

这里主要的负荷产品有:

这里我以HYDL Hydrological Loading产品为例进行读取,其时间分辨率为24 h.

  1. file = 'ESMGFZ_HYDL_cf_v1.3_24h_2023.nc';
  2. ncdisp(file)
  3. lon = ncread(file,'lon');
  4. lat = ncread(file,'lat');
  5. duV = ncread(file,'duV');
  6. time = ncread(file,'time');
  7. [lon,lat] = meshgrid(lon,lat);
  8. O.lon = lon;
  9. O.lat = lat;
  10. O.rg = duV(:,:,12)';
  11. rg_plot(O)

读取结果,单位:m。

 (4.2)选择GRACE数据作为负荷源

将球谐系数转成格网值,代码:

  1. clear;
  2. %% envirionment setting
  3. addpath functions
  4. %% read in data
  5. a = load('data/csr06_gsm_2004-12_2005-02.mat'); % SH
  6. SH0 = cSH(a.SH); % convert to the data format used here.
  7. SH0 = SH0(3); % only use the first month
  8. %% filter
  9. os_smooth.iGauss=300D3; %km
  10. os_smooth.iPxMy=1;
  11. [SH_filter] = CS_smooth (SH0,os_smooth);
  12. %% check the results
  13. % compare your figures with these in the check/ folder.
  14. figure('position',[1,1,1000,600]);
  15. imon = 1;
  16. SH_t0 = SH0(imon);
  17. SH_t1 = SH_filter(imon);
  18. cran = [-50,50];
  19. %%
  20. [LLZ]=LLZ_forward_ns(SH_t1, 'to', 'ewh','resolution',1);
  21. wzq_plot(LLZ)
  22. caxis(cran);

 进行球谐函数积分可以得到以下的结果:左图:质量变化 ,cm;右图:垂直位移,mm

进行格林函数积分得到的结果:左图:质量变化,cm;右图:垂直位移,mm.

 

或者使用GRACE mascon数据,下载链接

下面是2005年10月的JPL GRACE mascon的质量变化信号

  1. file = 'convgf_grace_rmTM1False_rmSM2False_20051001-20061001_GRACE_Tellus_RL06_JPL_ScalingFalse_20051016000000.nc';
  2. ncdisp(file)
  3. lon = ncread(file,'longitude');
  4. lat = ncread(file,'latitude');
  5. duV = ncread(file,'amplitude');
  6. O.lon = reshape(lon,720,360);
  7. O.lat = reshape(lat,720,360);
  8. O.rg = reshape(duV,720,360).*100;
  9. rg_plot(O)
  10. caxis([-50,50])

结果:单位:cm

3. 进行格林函数卷积计算

原理:全球的格林函数,使用在地球的形状中心作为地球的参考系(CF)和地球的质心(CM)处计算的全球Green函数,基于弹性地球模型"AK135"(Kennett et al.,1995)给出的负荷 Love数值,由Wang(2012)提供,生成了以"cf"或"cm"命名的负荷love数。下面提供了基于ak135地球模型计算的负荷love数:

http://rz-vm115.gfz-potsdam.de:8080/repository/entry/show?entryid=2f0ff1d8-b0bb-4591-a5ea-44cea2d0baad

一阶的负荷love数定义如下,下表给出了各个不同参考系下的转换关系:

CE   CM CF    
h(1)   =   -0.28954527CE -1.02/3(h-l)  = -0.26310049
l(1)   =    0.10510547CE -1.0-1/3(h-l)  =  0.13155025  
k(1)   =    0.0CE -1.0    -1/3h-2/3l =  0.02644478 

而且当阶趋于无穷时,有

  1. h(inf) = -5.4630734
  2. l(inf) = 0.000041954371
  3. k(inf) = -0.000056284140

计算垂直位移

(1)利用Martens提供的LoadDef包,可以计算负荷变形,但是第一步需要准备负荷源。需要运行的函数为:gen_grace_tellus_rl06.py,位于【..\LoadDef-main\LoadDef-main\GRDGEN\load_files 】目录下,点击运行后,可以在目录【..\LoadDef-main\LoadDef-main\output\Grid_Files\nc\GRACE】得到每个月的负荷源,名称为【convgf_grace_rmTM1False_rmSM2False_20051001-20061001_GRACE_Tellus_RL06_JPL_ScalingFalse_20051016000000

注意:使用的负荷源是GRACE mascon的质量变化,当然也可以根据需要换成其他的负荷源。

本文中计算的是全球的格网点,分辨率为181*361。为了计算所需要的计算点,可以将坐标点数据存放在一个txt文件中,并存放于文件目录下:【..\LoadDef-main\LoadDef-main\input\Station_Locations】

(2)进行全球的负荷卷积计算。下面本人经过修改的,可以计算全球区域负荷变形的python代码,计算垂直、东和北向的位移,需要添加到对应的目录下:【以下的计算使用的还是基于PREM地球模型计算得到的love数,如果需要比较不同地球模型的差异,可以替换程序读取的love数文件】

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Mon Jul 31 14:36:40 2023
  4. @author: 我是水怪的哥
  5. """
  6. # IMPORT PRINT FUNCTION
  7. from __future__ import print_function
  8. # IMPORT MPI MODULE
  9. from mpi4py import MPI
  10. # MODIFY PYTHON PATH TO INCLUDE 'LoadDef' DIRECTORY
  11. import sys
  12. import os
  13. sys.path.append(os.getcwd() + "/../")
  14. # IMPORT PYTHON MODULES
  15. import numpy as np
  16. # import scipy as sc
  17. import datetime
  18. # 此处是添加函数的意思,即把需要的函数添加进来
  19. from CONVGF.CN import load_convolution_region
  20. from CONVGF.utility import read_region
  21. # from CONVGF.utility import read_lsmask
  22. # --------------- SPECIFY USER INPUTS --------------------- #
  23. # Reference Frame (used for filenames) [Blewitt 2003]
  24. rfm = "cf"
  25. # Greens Function File
  26. # :: May be load Green's function file output directly from run_gf.py (norm_flag = False)
  27. # :: May be from a published table, normalized according to Farrell (1972) conventions [theta, u_norm, v_norm]
  28. pmod = "PREM" # you can change Greens function based on PREM|AK135|STW105
  29. grn_file = ("../output/Greens_Functions/" + rfm + "_" + pmod + ".txt")
  30. norm_flag = False
  31. # Full Path to Load Directory and Prefix of Filename
  32. loadfile_directory = ("../output/Grid_Files/nc/GRACE/")
  33. # Prefix for the Load Files (Load Directory will be Searched for all Files Starting with this Prefix)
  34. # :: Note: For Load Files Organized by Date, the End of Filename Name Must be in the Format yyyymmddhhmnsc.txt
  35. # :: Note: If not organized by date, files may be organized by tidal harmonic, for example (i.e. a unique filename ending)
  36. # :: Note: Output names (within output files) will be determined by extension following last underscore character (e.g., date/harmonic/model)
  37. loadfile_prefix = ("convgf_grace_rmTM1False_rmSM2False_20051001-20061001_GRACE_Tellus_RL06_JPL_ScalingFalse_20051016000000")
  38. # LoadFile Format: ["nc", "txt"]
  39. loadfile_format = "nc"
  40. # Are the Load Files Organized by Datetime?
  41. # :: If False, all Files that match the loadfile directory and prefix will be analyzed.
  42. time_series = True
  43. # Date Range for Computation (Year,Month,Day,Hour,Minute,Second)
  44. # :: Note: Only used if 'time_series' is True
  45. frst_date = [2005,10,1,0,0,0]
  46. last_date = [2005,11,1,0,0,0]
  47. # Are the load values on regular grids (speeds up interpolation); If unsure, leave as false.
  48. regular = True
  49. # Load Density
  50. # Recommended: 1025-1035 for oceanic loads (e.g., FES2014, ECCO2); 1 for atmospheric loads (e.g. ECMWF)
  51. ldens = 1000.0
  52. # region for calculation
  53. sta_file = ("../input/Station_Locations/region.txt")
  54. # Optional: Additional string to include in output filenames (e.g. "_2019")
  55. outstr = ("_" + pmod)
  56. # ------------------ END USER INPUTS ----------------------- #
  57. # -------------------- SETUP MPI --------------------------- #
  58. # Get the Main MPI Communicator That Controls Communication Between Processors
  59. comm = MPI.COMM_WORLD
  60. # Get My "Rank", i.e. the Processor Number Assigned to Me
  61. rank = comm.Get_rank()
  62. # Get the Total Number of Other Processors Used
  63. size = comm.Get_size()
  64. # ---------------------------------------------------------- #
  65. # -------------------- BEGIN CODE -------------------------- #
  66. # Ensure that the Output Directories Exist
  67. if (rank == 0):
  68. if not (os.path.isdir("../output/Convolution/")):
  69. os.makedirs("../output/Convolution/")
  70. # Check format of load files
  71. if not (loadfile_format == "nc"):
  72. if not (loadfile_format == "txt"):
  73. print(":: Error: Invalid format for load files. See scripts in the /GRDGEN/load_files/ folder. Acceptable formats: netCDF, txt.")
  74. # Read global grid
  75. lon,lat = read_region.main(sta_file)
  76. # Determine Number of Stations Read In
  77. if isinstance(lat,float) == True: # only 1 station
  78. numel = 1
  79. else:
  80. numel = len(lat)
  81. # Loop Through Each Station
  82. for jj in range(0,numel):
  83. # Remove Index If Only 1 Station
  84. if (numel == 1): # only 1 station read in
  85. my_lat = lat
  86. my_lon = lon
  87. else:
  88. my_lat = lat[jj]
  89. my_lon = lon[jj]
  90. # Output File Name
  91. cnv_out = loadfile_prefix + outstr + ".txt"
  92. # Convert Start and End Dates to Datetimes
  93. if (time_series == True):
  94. frstdt = datetime.datetime(frst_date[0],frst_date[1],frst_date[2],frst_date[3],frst_date[4],frst_date[5])
  95. lastdt = datetime.datetime(last_date[0],last_date[1],last_date[2],last_date[3],last_date[4],last_date[5])
  96. # Determine Number of Matching Load Files
  97. load_files = []
  98. if os.path.isdir(loadfile_directory):
  99. for mfile in os.listdir(loadfile_directory): # Filter by Load Directory
  100. if mfile.startswith(loadfile_prefix): # Filter by File Prefix
  101. if (time_series == True):
  102. if (loadfile_format == "txt"):
  103. mydt = datetime.datetime.strptime(mfile[-18:-4],'%Y%m%d%H%M%S') # Convert Filename String to Datetime
  104. elif (loadfile_format == "nc"):
  105. mydt = datetime.datetime.strptime(mfile[-17:-3],'%Y%m%d%H%M%S') # Convert Filename String to Datetime
  106. else:
  107. print(":: Error: Invalid format for load files. See scripts in the /GRDGEN/load_files/ folder. Acceptable formats: netCDF, txt.")
  108. if ((mydt >= frstdt) & (mydt <= lastdt)): # Filter by Date Range
  109. load_files.append(loadfile_directory + mfile) # Append File to List
  110. else:
  111. load_files.append(loadfile_directory + mfile) # Append File to List
  112. else:
  113. sys.exit('Error: The loadfile directory does not exist. You may need to create it. The /GRDGEN/load_files/ folder contains utility scripts to convert common models into LoadDef-compatible formats, and will automatically create a loadfile directory.')
  114. # Test for Load Files
  115. if not load_files:
  116. sys.exit('Error: Could not find load files. You may need to generate them. The /GRDGEN/load_files/ folder contains utility scripts to convert common models into LoadDef-compatible formats.')
  117. # Sort the Filenames
  118. load_files = np.asarray(load_files)
  119. fidx = np.argsort(load_files)
  120. load_files = load_files[fidx]
  121. # Set Lat/Lon/Name for Current Station
  122. slat = my_lat
  123. slon = my_lon
  124. # Determine the Chunk Sizes for the Convolution
  125. total_files = len(load_files)
  126. nominal_load = total_files // size # Floor Divide
  127. # Final Chunk Might Be Different in Size Than the Nominal Load
  128. if rank == size - 1:
  129. procN = total_files - rank * nominal_load
  130. else:
  131. procN = nominal_load
  132. # Perform the Convolution for Each Station
  133. if (rank == 0):
  134. eamp,epha,namp,npha,vamp,vpha = load_convolution_region.main(grn_file,norm_flag,load_files,regular,\
  135. slat,slon,cnv_out,loadfile_format,rank,procN,comm,load_density=ldens)
  136. # For Worker Ranks, Run the Code But Don't Return Any Variables
  137. else:
  138. load_convolution_region.main(grn_file,norm_flag,load_files,regular,\
  139. slat,slon,cnv_out,loadfile_format,rank,procN,comm,load_density=ldens)
  140. # out data
  141. cnv_file = ("../output/Convolution/GRACE_global" + cnv_out)
  142. # write results
  143. with open(cnv_file, "a", encoding="utf-8") as f:
  144. np.savetxt(f, np.c_[my_lon,my_lat,eamp,epha,namp,npha,vamp,vpha], fmt='%.8f', delimiter=' ')# 以写的格式打开先打开文件
  145. # Make Sure All Jobs Have Finished Before Continuing
  146. comm.Barrier()
  147. # --------------------- END CODE --------------------------- #

需要修改添加的函数如下,也可以在本人的资源处下载。

read_region.py [..\LoadDef-main\LoadDef-main\CONVGF\utility]
  1. # *********************************************************************
  2. # FUNCTION TO READ IN A STATION LOCATION FILE
  3. #
  4. # Copyright (c) 2014-2019: HILARY R. MARTENS, LUIS RIVERA, MARK SIMONS
  5. #
  6. # This file is part of LoadDef.
  7. #
  8. # LoadDef is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # any later version.
  12. #
  13. # LoadDef is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with LoadDef. If not, see <https://www.gnu.org/licenses/>.
  20. #
  21. # *********************************************************************
  22. import numpy as np
  23. def main(filename):
  24. lat,lon = np.loadtxt(filename,usecols=(0,1),unpack=True)
  25. sta = np.loadtxt(filename,usecols=(2,),dtype='U',unpack=True)
  26. return lat,lon,sta
perform_convolution_region.py [..\LoadDef-main\LoadDef-main\CONVGF\CN]
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Mon Jul 31 15:02:33 2023
  4. @author: 我是水怪的哥
  5. """
  6. # *********************************************************************
  7. # FUNCTION TO CONVOLVE LOAD GREEN'S FUNCTIONS WITH A MASS-LOAD MODEL
  8. #
  9. # Copyright (c) 2014-2019: HILARY R. MARTENS, LUIS RIVERA, MARK SIMONS
  10. #
  11. # This file is part of LoadDef.
  12. #
  13. # LoadDef is free software: you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation, either version 3 of the License, or
  16. # any later version.
  17. #
  18. # LoadDef is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. # GNU General Public License for more details.
  22. #
  23. # You should have received a copy of the GNU General Public License
  24. # along with LoadDef. If not, see <https://www.gnu.org/licenses/>.
  25. #
  26. # *********************************************************************
  27. import numpy as np
  28. import scipy as sc
  29. from scipy import interpolate
  30. from CONVGF.utility import read_AmpPha
  31. from CONVGF.CN import convolve_global_grid
  32. from CONVGF.CN import interpolate_load
  33. from CONVGF.CN import interpolate_lsmask
  34. from CONVGF.CN import coef2amppha
  35. from CONVGF.CN import mass_conservation
  36. import sys
  37. import os
  38. from math import pi
  39. import matplotlib.pyplot as plt
  40. import matplotlib.cm as cm
  41. def main(loadfile,ilat,ilon,iarea,load_density,ur,ue,un,mydt,regular,mass_cons,lf_format):
  42. # Check load file format
  43. if (lf_format == "bbox"): # list of cells, rather than traditional load files
  44. # Select the Appropriate Cell ID
  45. cslat = loadfile[0]
  46. cnlat = loadfile[1]
  47. cwlon = loadfile[2]
  48. celon = loadfile[3]
  49. yes_idx = np.where((ilat >= cslat) & (ilat <= cnlat) & (ilon >= cwlon) & (ilon <= celon)); yes_idx = yes_idx[0]
  50. print(':: Number of convolution grid points within load cell: ', len(yes_idx))
  51. # Find ilat and ilon within cell
  52. ic1 = np.zeros(len(ilat),)
  53. ic2 = np.zeros(len(ilat),)
  54. ic1[yes_idx] = 1. # Amplitude of 1 (ic1 = 1 only inside cell), phase of zero (keep ic2 = 0 everywhere)
  55. # Optionally plot the load cell
  56. #### Set flag to "False" to turn off plotting of the load cell; "True" to turn it on
  57. plot_fig = False
  58. if plot_fig:
  59. print(':: Plotting the load cell. [perform_convolution.py]')
  60. cslat_plot = cslat - 0.5
  61. cnlat_plot = cnlat + 0.5
  62. cwlon_plot = cwlon - 0.5
  63. celon_plot = celon + 0.5
  64. idx_plot = np.where((ilon >= cwlon_plot) & (ilon <= celon_plot) & (ilat >= cslat_plot) & (ilat <= cnlat_plot)); idx_plot = idx_plot[0]
  65. ilon_plot = ilon[idx_plot]
  66. ilat_plot = ilat[idx_plot]
  67. ic1_plot = ic1[idx_plot]
  68. plt.scatter(ilon_plot,ilat_plot,c=ic1_plot,s=1,cmap=cm.BuPu)
  69. plt.colorbar(orientation='horizontal')
  70. fig_name = ("../output/Figures/" + "_" + str(cslat) + "_" + str(cnlat) + "_" + str(cwlon) + "_" + str(celon) + ".png")
  71. plt.savefig(fig_name,format="png")
  72. #plt.show()
  73. plt.close()
  74. else: # traditional load file
  75. # Read the File
  76. llat,llon,amp,pha,llat1dseq,llon1dseq,amp2darr,pha2darr = read_AmpPha.main(loadfile,lf_format,regular_grid=regular)
  77. # Find Where Amplitude is NaN (if anywhere) and Set to Zero
  78. nanidx = np.isnan(amp); amp[nanidx] = 0.; pha[nanidx] = 0.
  79. # Convert Amp/Pha Arrays to Real/Imag
  80. real = np.multiply(amp,np.cos(np.multiply(pha,pi/180.)))
  81. imag = np.multiply(amp,np.sin(np.multiply(pha,pi/180.)))
  82. # Interpolate Load at Each Grid Point onto the Integration Mesh
  83. ic1,ic2 = interpolate_load.main(ilat,ilon,llat,llon,real,imag,regular)
  84. # Multiply the Load Heights by the Load Density
  85. ic1 = np.multiply(ic1,load_density)
  86. ic2 = np.multiply(ic2,load_density)
  87. # Enforce Mass Conservation
  88. if (mass_cons == True):
  89. print('here mass')
  90. # For Land and Whole-Globe Models (like atmosphere and continental water)
  91. print(':: Warning: Enforcing Mass Conservation Over Entire Globe.')
  92. ic1,ic2 = mass_conservation.main(ic1,ic2,iarea)
  93. # Perform the Convolution at Each Grid Point
  94. c1e,c2e,c1n,c2n,c1v,c2v = convolve_global_grid.main(ic1,ic2,ur,ue,un)
  95. # Sum Over All Grid Cells
  96. ec1 = np.sum(c1e)
  97. ec2 = np.sum(c2e)
  98. nc1 = np.sum(c1n)
  99. nc2 = np.sum(c2n)
  100. vc1 = np.sum(c1v)
  101. vc2 = np.sum(c2v)
  102. # Convert Coefficients to Amplitude and Phase
  103. # Note: Conversion to mm from meters also happens here!
  104. eamp,epha,namp,npha,vamp,vpha = coef2amppha.main(ec1,ec2,nc1,nc2,vc1,vc2)
  105. # Return Variables
  106. return eamp,epha,namp,npha,vamp,vpha
load_convolution_region.py [..\LoadDef-main\LoadDef-main\CONVGF\CN]
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Mon Jul 31 15:01:13 2023
  4. @author: 我是水怪的哥
  5. """
  6. # Import Python Modules
  7. from __future__ import print_function
  8. from mpi4py import MPI
  9. import numpy as np
  10. import datetime
  11. import scipy as sc
  12. import netCDF4
  13. from scipy import interpolate
  14. from CONVGF.utility import read_greens_fcn_file
  15. from CONVGF.utility import read_greens_fcn_file_norm
  16. from CONVGF.utility import normalize_greens_fcns
  17. from CONVGF.CN import compute_specific_greens_fcns
  18. from CONVGF.CN import convolve_global_grid
  19. from CONVGF.CN import generate_integration_mesh
  20. from CONVGF.CN import intmesh2geogcoords
  21. from CONVGF.CN import integrate_greens_fcns
  22. from CONVGF.CN import interpolate_load
  23. from CONVGF.CN import compute_angularDist_azimuth
  24. from CONVGF.CN import coef2amppha
  25. from CONVGF.CN import perform_convolution_region
  26. from CONVGF.CN import interpolate_lsmask
  27. from CONVGF.utility import read_lsmask
  28. import sys
  29. import os
  30. from math import pi
  31. """
  32. Compute predicted surface displacements caused by surface mass loading by convolving
  33. displacement load Green's functions with a model for the surface mass load.
  34. Parameters
  35. ----------
  36. load_density : Density of the surface mass load (kg/m^3)
  37. Default is 1030.0
  38. rad : Mean Earth radius (m)
  39. Default is 6371000.
  40. # -- Mesh Paramters --
  41. delinc1 : angular distance (degrees) increment for inner zone
  42. Default is 0.0002
  43. delinc2 : angular distance (degrees) increment for zone 2
  44. Default is 0.001
  45. delinc3 : angluar distance (degrees) increment for zone 3
  46. Default is 0.01
  47. delinc4 : angluar distance (degrees) increment for zone 4
  48. Default is 0.1
  49. delinc5 : angluar distance (degrees) increment for zone 5
  50. Default is 0.5
  51. delinc6 : angular distance (degrees) increment for outer zone
  52. Default is 1.0
  53. izb : inner zone boundary (degrees; 0<izb<z2b)
  54. Default is 0.02
  55. z2b : zone 2 boundary (degrees; izb<z2b<z3b)
  56. Default is 0.1
  57. z3b : zone 3 boundary (degrees; z2b<z3b<z4b)
  58. Default is 1.0
  59. z4b : zone 4 boundary (degrees; z3b<z4b<z5b)
  60. Default is 10.0
  61. z5b : zone 5 boundary (degrees; z4b<z5b<180)
  62. Default is 90.0
  63. azminc : azimuthal increment # NOTE: Maybe should match azminc with delinc5 (i.e., keep azminc consistent with theta increment at 90 degrees from station,
  64. # where azimuth and theta increments are consistent in horizontal distance along planet's surface)
  65. # :: azminc*sin(theta) ~ delinc
  66. Default is 0.5
  67. mass_cons : option to enforce mass conservation by removing the spatial mean from the load grid
  68. Default is False
  69. """
  70. def main(grn_file,norm_flag,load_files,regular,rlat,rlon,cnv_out,loadfile_format,rank,procN,comm,\
  71. load_density=1030.0,rad=6371000.,delinc1=0.0002,delinc2=0.001,delinc3=0.01,delinc4=0.1,delinc5=0.5,delinc6=1.0,\
  72. izb=0.02,z2b=0.1,z3b=1.0,z4b=10.0,z5b=90.0,azminc=0.5,mass_cons=False):
  73. # Determine Number of Load Files
  74. if isinstance(load_files,float) == True:
  75. numel = 1
  76. else:
  77. numel = len(load_files)
  78. # Only the Main Processor Will Do This:
  79. if (rank == 0):
  80. # Print Number of Files Read In
  81. display = ':: Number of Files Read In: ' + repr(numel)
  82. print(display)
  83. print(" ")
  84. # Determine whether load file was supplied as a list of cells, or as traditional load files
  85. if (loadfile_format == "bbox"): # list of cells
  86. # Ensure only one file is read in for this format
  87. if (numel > 1):
  88. sys.exit(":: Error: For load files in 'bbox' format (i.e., a list of bounding boxes), only one file can be read in at a time. [load_convolution.py]")
  89. # Read in the file
  90. loadgrid = load_files[0]
  91. lcext = loadgrid[-2::]
  92. if (lcext == 'xt'):
  93. file_ids = np.loadtxt(loadgrid,usecols=(4,),unpack=True,dtype='U')
  94. slat,nlat,wlon,elon = np.loadtxt(loadgrid,usecols=(0,1,2,3),unpack=True)
  95. elif (lcext == 'nc'):
  96. f = netCDF4.Dataset(loadgrid)
  97. file_ids = f.variables['cell_ids'][:]
  98. slat = f.variables['slatitude'][:]
  99. nlat = f.variables['nlatitude'][:]
  100. wlon = f.variables['wlongitude'][:]
  101. elon = f.variables['elongitude'][:]
  102. f.close()
  103. # Ensure that Bounding Box Longitudes are in Range 0-360
  104. for yy in range(0,len(wlon)):
  105. if (wlon[yy] < 0.):
  106. wlon[yy] += 360.
  107. if (elon[yy] < 0.):
  108. elon[yy] += 360.
  109. # Generate an array of cell indices
  110. file_idx = np.linspace(0,len(file_ids),num=(len(file_ids)),endpoint=False)
  111. np.random.shuffle(file_idx)
  112. else:
  113. # Generate an Array of File Indices
  114. file_idx = np.linspace(0,numel,num=numel,endpoint=False)
  115. np.random.shuffle(file_idx)
  116. # Create Array of Filename Extensions
  117. file_ids = []
  118. for qq in range(0,numel):
  119. mfile = load_files[qq]
  120. str_components = mfile.split('_')
  121. cext = str_components[-1]
  122. if (loadfile_format == "txt"):
  123. file_ids.append(cext[0:-4])
  124. elif (loadfile_format == "nc"):
  125. file_ids.append(cext[0:-3])
  126. else:
  127. print(':: Error. Invalid file format for load models. [load_convolution.py]')
  128. sys.exit()
  129. # Initialize Arrays
  130. eamp = np.empty((len(file_ids),))
  131. epha = np.empty((len(file_ids),))
  132. namp = np.empty((len(file_ids),))
  133. npha = np.empty((len(file_ids),))
  134. vamp = np.empty((len(file_ids),))
  135. vpha = np.empty((len(file_ids),))
  136. # Read Greens Function File
  137. if norm_flag == True:
  138. theta,u,v,unormFarrell,vnormFarrell = read_greens_fcn_file_norm.main(grn_file,rad)
  139. else:
  140. theta,u,v,unormFarrell,vnormFarrell = read_greens_fcn_file.main(grn_file)
  141. # Normalize Greens Functions (Agnew Convention)
  142. unorm,vnorm = normalize_greens_fcns.main(theta,u,v,rad)
  143. # Interpolate Greens Functions
  144. tck_gfu = interpolate.splrep(theta,unorm,k=3)
  145. tck_gfv = interpolate.splrep(theta,vnorm,k=3)
  146. xr = np.linspace(0.0001,3.,1000)
  147. # Generate Integration Mesh
  148. print(':: Generating the Integration Mesh. Please Wait...')
  149. gldel,glazm,ldel,lazm,unit_area = generate_integration_mesh.main(delinc1,delinc2, \
  150. delinc3,delinc4,delinc5,delinc6,izb,z2b,z3b,z4b,z5b,azminc)
  151. # Integrate Greens Functions
  152. uint,vint = integrate_greens_fcns.main(gldel,glazm,ldel,lazm,tck_gfu,tck_gfv)
  153. # Compute Geographic Coordinates of Integration Mesh Cell Midpoints
  154. ilat,ilon,iarea = intmesh2geogcoords.main(rlat,rlon,ldel,lazm,unit_area)
  155. # Ensure that Station Location is in Range 0-360
  156. if (rlon < 0.):
  157. rlon += 360.
  158. # Determine the Land-Sea Mask: Interpolate onto Mesh
  159. # print(':: Interpolating the Land-Sea Mask. Please Wait...')
  160. # print(':: Number of Grid Points: %s | Size of LSMask: %s' %(str(len(ilat)), str(lsmask.shape)))
  161. # print(':: Finished LSMask Interpolation.')
  162. # Compute Angular Distance and Azimuth at Receiver Due to Load
  163. delta,haz = compute_angularDist_azimuth.main(rlat,rlon,ilat,ilon)
  164. # Compute Greens Functions Specific to Receiver and Grid (Geographic Coordinates)
  165. ur,ue,un = compute_specific_greens_fcns.main(haz,uint,vint)
  166. # If I'm a Worker, I Know Nothing About the Data
  167. else:
  168. file_idx = file_ids = eamp = epha = namp = npha = vamp = vpha = None
  169. ldel = lazm = uint = vint = ilat = ilon = iarea = delta = haz = ur = ue = un = None
  170. slat = nlat = wlon = elon = None
  171. # Create a Data Type for the Convolution Results
  172. cntype = MPI.DOUBLE.Create_contiguous(1)
  173. cntype.Commit()
  174. # Gather the Processor Workloads for All Processors
  175. sendcounts = comm.gather(procN, root=0)
  176. # Scatter the File Locations (By Index)
  177. d_sub = np.empty((procN,))
  178. comm.Scatterv([file_idx, (sendcounts, None), cntype], d_sub, root=0)
  179. # All Processors Get Certain Arrays and Parameters; Broadcast Them
  180. ilat = comm.bcast(ilat, root=0)
  181. ilon = comm.bcast(ilon, root=0)
  182. iarea = comm.bcast(iarea, root=0)
  183. ur = comm.bcast(ur, root=0)
  184. ue = comm.bcast(ue, root=0)
  185. un = comm.bcast(un, root=0)
  186. load_density = comm.bcast(load_density, root=0)
  187. file_ids = comm.bcast(file_ids, root=0)
  188. file_idx = comm.bcast(file_idx, root=0)
  189. if (loadfile_format == "bbox"):
  190. slat = comm.bcast(slat, root=0)
  191. nlat = comm.bcast(nlat, root=0)
  192. wlon = comm.bcast(wlon, root=0)
  193. elon = comm.bcast(elon, root=0)
  194. # Loop Through the Files
  195. eamp_sub = np.empty((len(d_sub),))
  196. epha_sub = np.empty((len(d_sub),))
  197. namp_sub = np.empty((len(d_sub),))
  198. npha_sub = np.empty((len(d_sub),))
  199. vamp_sub = np.empty((len(d_sub),))
  200. vpha_sub = np.empty((len(d_sub),))
  201. for ii in range(0,len(d_sub)):
  202. current_d = int(d_sub[ii]) # Index
  203. if (loadfile_format == "bbox"):
  204. cslat = slat[current_d]
  205. cnlat = nlat[current_d]
  206. cwlon = wlon[current_d]
  207. celon = elon[current_d]
  208. mfile = [cslat,cnlat,cwlon,celon]
  209. file_id = file_ids[current_d] # File Extension
  210. print(':: Working on Cell: %s | Number: %6d of %6d | Rank: %6d' %(file_id, (ii+1), len(d_sub), rank))
  211. else:
  212. mfile = load_files[current_d] # Vector-Format
  213. file_id = file_ids[current_d] # File Extension
  214. print(':: Working on File: %s | Number: %6d of %6d | Rank: %6d' %(file_id, (ii+1), len(d_sub), rank))
  215. # Check if Loadfile Exists
  216. if not (os.path.isfile(mfile)): # file does not exist
  217. eamp_sub[ii] = np.nan
  218. epha_sub[ii] = np.nan
  219. namp_sub[ii] = np.nan
  220. npha_sub[ii] = np.nan
  221. vamp_sub[ii] = np.nan
  222. vpha_sub[ii] = np.nan
  223. continue
  224. # Compute Convolution for Current File
  225. eamp_sub[ii],epha_sub[ii],namp_sub[ii],npha_sub[ii],vamp_sub[ii],vpha_sub[ii] = perform_convolution_region.main(\
  226. mfile,ilat,ilon,iarea,load_density,ur,ue,un,file_id,regular,mass_cons,loadfile_format)
  227. return eamp_sub,epha_sub,namp_sub,npha_sub,vamp_sub,vpha_sub
  228. else:
  229. # For Worker Ranks, Return Nothing
  230. return
  231. # # Gather Results
  232. # comm.Gatherv(eamp_sub, [eamp, (sendcounts, None), MPI.DOUBLE], root=0)
  233. # comm.Gatherv(epha_sub, [epha, (sendcounts, None), MPI.DOUBLE], root=0)
  234. # comm.Gatherv(namp_sub, [namp, (sendcounts, None), MPI.DOUBLE], root=0)
  235. # comm.Gatherv(npha_sub, [npha, (sendcounts, None), MPI.DOUBLE], root=0)
  236. # comm.Gatherv(vamp_sub, [vamp, (sendcounts, None), MPI.DOUBLE], root=0)
  237. # comm.Gatherv(vpha_sub, [vpha, (sendcounts, None), MPI.DOUBLE], root=0)
  238. # # Make Sure Everyone Has Reported Back Before Moving On
  239. # comm.Barrier()
  240. # # Free Data Type
  241. # cntype.Free()
  242. # # Print Output to Files and Return Variables
  243. # if (rank == 0):
  244. # # Re-organize Files
  245. # narr,nidx = np.unique(file_idx,return_index=True)
  246. # eamp = eamp[nidx]; namp = namp[nidx]; vamp = vamp[nidx]
  247. # epha = epha[nidx]; npha = npha[nidx]; vpha = vpha[nidx]
  248. # # Prepare Output Files
  249. # cnv_file = ("../output/Convolution/GRACE_global" + cnv_out)
  250. # cnv_head = ("../output/Convolution/"+str(np.random.randint(500))+"cn_head.txt")
  251. # cnv_body = ("../output/Convolution/"+str(np.random.randint(500))+"cn_body.txt")
  252. # # Prepare Data for Output (Create a Structured Array)
  253. # rlat_arr = np.ones((len(eamp),)) * rlat
  254. # rlon_arr = np.ones((len(eamp),)) * rlon
  255. # if (loadfile_format == "bbox"):
  256. # all_cnv_data = np.array(list(zip(file_ids,rlat_arr,rlon_arr,eamp,epha,namp,npha,vamp,vpha,slat,nlat,wlon,elon)), dtype=[('file_ids','U25'), \
  257. # ('rlat_arr',float),('rlon_arr',float),('eamp',float),('epha',float),('namp',float),('npha',float), \
  258. # ('vamp',float),('vpha',float),('slat',float),('nlat',float),('wlon',float),('elon',float)])
  259. # else:
  260. # all_cnv_data = np.array(list(zip(file_ids,rlat_arr,rlon_arr,eamp,epha,namp,npha,vamp,vpha)), dtype=[('file_ids','U25'), \
  261. # ('rlat_arr',float),('rlon_arr',float),('eamp',float),('epha',float),('namp',float),('npha',float), \
  262. # ('vamp',float),('vpha',float)])
  263. # # Write Header Info to File
  264. # hf = open(cnv_head,'w')
  265. # if (loadfile_format == "bbox"):
  266. # cnv_str = 'Extension/Epoch Lat(+N,deg) Lon(+E,deg) E-Amp(mm) E-Pha(deg) N-Amp(mm) N-Pha(deg) V-Amp(mm) V-Pha(deg) S-Lat(deg) N-Lat(deg) W-Lon(deg) E-Lon(deg) \n'
  267. # else:
  268. # cnv_str = 'Extension/Epoch Lat(+N,deg) Lon(+E,deg) E-Amp(mm) E-Pha(deg) N-Amp(mm) N-Pha(deg) V-Amp(mm) V-Pha(deg) \n'
  269. # hf.write(cnv_str)
  270. # hf.close()
  271. # # Write Convolution Results to File
  272. # if (loadfile_format == "bbox"):
  273. # np.savetxt(cnv_body,all_cnv_data,fmt=["%s"] + ["%.8f",]*12,delimiter=" ")
  274. # else:
  275. # np.savetxt(cnv_body,all_cnv_data,fmt=["%s"] + ["%.8f",]*8,delimiter=" ")
  276. # # Combine Header and Body Files
  277. # filenames_cnv = [cnv_head, cnv_body]
  278. # with open(cnv_file,'w') as outfile:
  279. # for fname in filenames_cnv:
  280. # with open(fname) as infile:
  281. # outfile.write(infile.read())
  282. # # Remove Header and Body Files
  283. # os.remove(cnv_head)
  284. # os.remove(cnv_body)
  285. # Return Amplitude and Phase Response Values
  286. # return eamp,epha,namp,npha,vamp,vpha,comm
  287. # else:
  288. # # For Worker Ranks, Return Nothing
  289. # return

下面计算的2005年10月的GRACE mascon作为负荷源得到的三维地球弹性变形结果【三维位移的振幅图】:东西向水平位移最大振幅、南北向水平位移最大振幅、垂直位移最大振幅:单位:mm

目前还存在的问题:

(1)该计算过程非常地耗时,后续可以添加并行计算,提高运行效率;     
(2)计算的结果仅仅是三维位移的最大振幅,后续可计算其余的量。 

参考资料

SAGE: Data Services Products: EMC-STW105

Preliminary Reference Earth Model (PREM)

SAGE: Data Services Products: EMC-ak135-f

Home

3.1 Earth’s Layers: Crust, Mantle, and Core – Physical Geology, First University of Saskatchewan Edition (usask.ca)

李长海, et al. (2023). "不同地球模型对中国陆区大气负荷位移建模的影响." 地球物理学报.

Martens, H.R., Rivera, L., & Simons, M. (2019). LoadDef: A Python-based toolkit to model elastic deformation caused by surface mass loading on spherically symmetric bodies. Earth and Space Science, 6. https://doi.org/10.1029/2018ea000462.

Yi, S. and N. Sneeuw (2022). "A novel spatial filter to reduce north–south striping noise in GRACE spherical harmonic coefficients." Journal of Geodesy 96(4).
W.E Farrell. Deformation of the earth by surface loads. Rev. Geophys. and Spac. Phys., 10(3):751-797, 1972 
H. Wang et al. Load Love numbers and Green's functions for elastic Earth models PREM, iasp91, ak135, and modified models with refined crustal structure from Crust 2.0. Computers and Geosciences, 49, 190-199, 2012
B.L.N. Kennett et al. Constraints on seismic velocities in the Earth from travel times. Geophys. J. Int. 122, 108-124.

Wen, Z., et al. (2023). "Contribution of loading deformation to the GNSS vertical velocity field in the Chinese mainland." Geophysical Journal International.

Martens, H. R. (2016). "USING EARTH DEFORMATION CAUSED BY SURFACE MASS LOADING TO CONSTRAIN THE ELASTIC STRUCTURE OF THE CRUST AND MANTLE." California Institute of Technology.

Kennett B.L.N., E.R. Engdahl and R. Buland. 1995. “Constraints on seismic velocities in the earth from travel times” Geophys. J. Int. 122, 108–124. https://doi.org/10.1111/j.1365-246X.1995.tb03540.x

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/656376
推荐阅读
相关标签
  

闽ICP备14008679号