赞
踩
由于地球的弹性结构,地球大尺度的质量迁移会导致地球产生负荷变形。地球的环境负载如大气、海洋、陆地水等的变化会使得固体地球产生明显的位移变化,为了准确研究有关地球物理信号,需要对弹性的负荷变形进行有效计算并扣除。通常利用格林函数法和球谐函数法,两者在数学上是等价的。
早期研究采用一维模型来表征地球内部结构及密度和速度等特征,当前进行负荷位移建模也普遍采用一维地球模型。
本文选择了PREM、STW105和AK135地球模型。地球模型的下载网址为
http://ds.iris.edu/ds/products/emc-ak135-f/
不同地球模型的示意图
本文使用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数,可以看到三个地球模型得到的结果还是比较接近。
使用run_gf.py函数计算了 相应的负荷格林函数
这里主要的负荷产品有:
这里我以HYDL Hydrological Loading产品为例进行读取,其时间分辨率为24 h.
- file = 'ESMGFZ_HYDL_cf_v1.3_24h_2023.nc';
- ncdisp(file)
- lon = ncread(file,'lon');
- lat = ncread(file,'lat');
- duV = ncread(file,'duV');
- time = ncread(file,'time');
- [lon,lat] = meshgrid(lon,lat);
- O.lon = lon;
- O.lat = lat;
- O.rg = duV(:,:,12)';
- rg_plot(O)
读取结果,单位:m。
将球谐系数转成格网值,代码:
- clear;
- %% envirionment setting
- addpath functions
- %% read in data
- a = load('data/csr06_gsm_2004-12_2005-02.mat'); % SH
- SH0 = cSH(a.SH); % convert to the data format used here.
- SH0 = SH0(3); % only use the first month
- %% filter
- os_smooth.iGauss=300D3; %km
- os_smooth.iPxMy=1;
- [SH_filter] = CS_smooth (SH0,os_smooth);
- %% check the results
- % compare your figures with these in the check/ folder.
- figure('position',[1,1,1000,600]);
- imon = 1;
- SH_t0 = SH0(imon);
- SH_t1 = SH_filter(imon);
- cran = [-50,50];
- %%
- [LLZ]=LLZ_forward_ns(SH_t1, 'to', 'ewh','resolution',1);
- wzq_plot(LLZ)
- caxis(cran);
进行球谐函数积分可以得到以下的结果:左图:质量变化 ,cm;右图:垂直位移,mm
进行格林函数积分得到的结果:左图:质量变化,cm;右图:垂直位移,mm.
或者使用GRACE mascon数据,下载链接
下面是2005年10月的JPL GRACE mascon的质量变化信号
- file = 'convgf_grace_rmTM1False_rmSM2False_20051001-20061001_GRACE_Tellus_RL06_JPL_ScalingFalse_20051016000000.nc';
- ncdisp(file)
- lon = ncread(file,'longitude');
- lat = ncread(file,'latitude');
- duV = ncread(file,'amplitude');
- O.lon = reshape(lon,720,360);
- O.lat = reshape(lat,720,360);
- O.rg = reshape(duV,720,360).*100;
- rg_plot(O)
- caxis([-50,50])
结果:单位:cm
原理:全球的格林函数,使用在地球的形状中心作为地球的参考系(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.28954527 | CE -1.0 | 2/3(h-l) = -0.26310049 |
l(1) = 0.10510547 | CE -1.0 | -1/3(h-l) = 0.13155025 |
k(1) = 0.0 | CE -1.0 | -1/3h-2/3l = 0.02644478 |
而且当阶趋于无穷时,有
- h(inf) = -5.4630734
- l(inf) = 0.000041954371
- 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数文件】
- # -*- coding: utf-8 -*-
- """
- Created on Mon Jul 31 14:36:40 2023
- @author: 我是水怪的哥
- """
- # IMPORT PRINT FUNCTION
- from __future__ import print_function
- # IMPORT MPI MODULE
- from mpi4py import MPI
- # MODIFY PYTHON PATH TO INCLUDE 'LoadDef' DIRECTORY
- import sys
- import os
- sys.path.append(os.getcwd() + "/../")
- # IMPORT PYTHON MODULES
- import numpy as np
- # import scipy as sc
- import datetime
-
- # 此处是添加函数的意思,即把需要的函数添加进来
- from CONVGF.CN import load_convolution_region
- from CONVGF.utility import read_region
- # from CONVGF.utility import read_lsmask
-
-
- # --------------- SPECIFY USER INPUTS --------------------- #
- # Reference Frame (used for filenames) [Blewitt 2003]
- rfm = "cf"
- # Greens Function File
- # :: May be load Green's function file output directly from run_gf.py (norm_flag = False)
- # :: May be from a published table, normalized according to Farrell (1972) conventions [theta, u_norm, v_norm]
- pmod = "PREM" # you can change Greens function based on PREM|AK135|STW105
- grn_file = ("../output/Greens_Functions/" + rfm + "_" + pmod + ".txt")
- norm_flag = False
-
- # Full Path to Load Directory and Prefix of Filename
- loadfile_directory = ("../output/Grid_Files/nc/GRACE/")
-
- # Prefix for the Load Files (Load Directory will be Searched for all Files Starting with this Prefix)
- # :: Note: For Load Files Organized by Date, the End of Filename Name Must be in the Format yyyymmddhhmnsc.txt
- # :: Note: If not organized by date, files may be organized by tidal harmonic, for example (i.e. a unique filename ending)
- # :: Note: Output names (within output files) will be determined by extension following last underscore character (e.g., date/harmonic/model)
- loadfile_prefix = ("convgf_grace_rmTM1False_rmSM2False_20051001-20061001_GRACE_Tellus_RL06_JPL_ScalingFalse_20051016000000")
-
- # LoadFile Format: ["nc", "txt"]
- loadfile_format = "nc"
-
- # Are the Load Files Organized by Datetime?
- # :: If False, all Files that match the loadfile directory and prefix will be analyzed.
- time_series = True
-
- # Date Range for Computation (Year,Month,Day,Hour,Minute,Second)
- # :: Note: Only used if 'time_series' is True
- frst_date = [2005,10,1,0,0,0]
- last_date = [2005,11,1,0,0,0]
-
- # Are the load values on regular grids (speeds up interpolation); If unsure, leave as false.
- regular = True
-
- # Load Density
- # Recommended: 1025-1035 for oceanic loads (e.g., FES2014, ECCO2); 1 for atmospheric loads (e.g. ECMWF)
- ldens = 1000.0
-
- # region for calculation
- sta_file = ("../input/Station_Locations/region.txt")
-
- # Optional: Additional string to include in output filenames (e.g. "_2019")
- outstr = ("_" + pmod)
-
- # ------------------ END USER INPUTS ----------------------- #
-
- # -------------------- SETUP MPI --------------------------- #
-
- # Get the Main MPI Communicator That Controls Communication Between Processors
- comm = MPI.COMM_WORLD
- # Get My "Rank", i.e. the Processor Number Assigned to Me
- rank = comm.Get_rank()
- # Get the Total Number of Other Processors Used
- size = comm.Get_size()
-
- # ---------------------------------------------------------- #
-
- # -------------------- BEGIN CODE -------------------------- #
-
- # Ensure that the Output Directories Exist
- if (rank == 0):
- if not (os.path.isdir("../output/Convolution/")):
- os.makedirs("../output/Convolution/")
-
- # Check format of load files
- if not (loadfile_format == "nc"):
- if not (loadfile_format == "txt"):
- print(":: Error: Invalid format for load files. See scripts in the /GRDGEN/load_files/ folder. Acceptable formats: netCDF, txt.")
-
- # Read global grid
- lon,lat = read_region.main(sta_file)
-
- # Determine Number of Stations Read In
- if isinstance(lat,float) == True: # only 1 station
- numel = 1
- else:
- numel = len(lat)
-
- # Loop Through Each Station
- for jj in range(0,numel):
-
- # Remove Index If Only 1 Station
- if (numel == 1): # only 1 station read in
- my_lat = lat
- my_lon = lon
- else:
- my_lat = lat[jj]
- my_lon = lon[jj]
-
- # Output File Name
- cnv_out = loadfile_prefix + outstr + ".txt"
-
- # Convert Start and End Dates to Datetimes
- if (time_series == True):
- frstdt = datetime.datetime(frst_date[0],frst_date[1],frst_date[2],frst_date[3],frst_date[4],frst_date[5])
- lastdt = datetime.datetime(last_date[0],last_date[1],last_date[2],last_date[3],last_date[4],last_date[5])
-
- # Determine Number of Matching Load Files
- load_files = []
- if os.path.isdir(loadfile_directory):
- for mfile in os.listdir(loadfile_directory): # Filter by Load Directory
- if mfile.startswith(loadfile_prefix): # Filter by File Prefix
- if (time_series == True):
- if (loadfile_format == "txt"):
- mydt = datetime.datetime.strptime(mfile[-18:-4],'%Y%m%d%H%M%S') # Convert Filename String to Datetime
- elif (loadfile_format == "nc"):
- mydt = datetime.datetime.strptime(mfile[-17:-3],'%Y%m%d%H%M%S') # Convert Filename String to Datetime
- else:
- print(":: Error: Invalid format for load files. See scripts in the /GRDGEN/load_files/ folder. Acceptable formats: netCDF, txt.")
- if ((mydt >= frstdt) & (mydt <= lastdt)): # Filter by Date Range
- load_files.append(loadfile_directory + mfile) # Append File to List
- else:
- load_files.append(loadfile_directory + mfile) # Append File to List
- else:
- 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.')
-
- # Test for Load Files
- if not load_files:
- 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.')
-
- # Sort the Filenames
- load_files = np.asarray(load_files)
- fidx = np.argsort(load_files)
- load_files = load_files[fidx]
-
- # Set Lat/Lon/Name for Current Station
- slat = my_lat
- slon = my_lon
-
- # Determine the Chunk Sizes for the Convolution
- total_files = len(load_files)
- nominal_load = total_files // size # Floor Divide
- # Final Chunk Might Be Different in Size Than the Nominal Load
- if rank == size - 1:
- procN = total_files - rank * nominal_load
- else:
- procN = nominal_load
-
- # Perform the Convolution for Each Station
- if (rank == 0):
- eamp,epha,namp,npha,vamp,vpha = load_convolution_region.main(grn_file,norm_flag,load_files,regular,\
- slat,slon,cnv_out,loadfile_format,rank,procN,comm,load_density=ldens)
- # For Worker Ranks, Run the Code But Don't Return Any Variables
- else:
- load_convolution_region.main(grn_file,norm_flag,load_files,regular,\
- slat,slon,cnv_out,loadfile_format,rank,procN,comm,load_density=ldens)
-
-
- # out data
- cnv_file = ("../output/Convolution/GRACE_global" + cnv_out)
- # write results
- with open(cnv_file, "a", encoding="utf-8") as f:
- np.savetxt(f, np.c_[my_lon,my_lat,eamp,epha,namp,npha,vamp,vpha], fmt='%.8f', delimiter=' ')# 以写的格式打开先打开文件
-
- # Make Sure All Jobs Have Finished Before Continuing
- comm.Barrier()
-
- # --------------------- END CODE --------------------------- #
-
-
需要修改添加的函数如下,也可以在本人的资源处下载。
read_region.py [..\LoadDef-main\LoadDef-main\CONVGF\utility]
- # *********************************************************************
- # FUNCTION TO READ IN A STATION LOCATION FILE
- #
- # Copyright (c) 2014-2019: HILARY R. MARTENS, LUIS RIVERA, MARK SIMONS
- #
- # This file is part of LoadDef.
- #
- # LoadDef is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # any later version.
- #
- # LoadDef is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with LoadDef. If not, see <https://www.gnu.org/licenses/>.
- #
- # *********************************************************************
-
- import numpy as np
-
- def main(filename):
- lat,lon = np.loadtxt(filename,usecols=(0,1),unpack=True)
- sta = np.loadtxt(filename,usecols=(2,),dtype='U',unpack=True)
- return lat,lon,sta
-
perform_convolution_region.py [..\LoadDef-main\LoadDef-main\CONVGF\CN]
- # -*- coding: utf-8 -*-
- """
- Created on Mon Jul 31 15:02:33 2023
- @author: 我是水怪的哥
- """
- # *********************************************************************
- # FUNCTION TO CONVOLVE LOAD GREEN'S FUNCTIONS WITH A MASS-LOAD MODEL
- #
- # Copyright (c) 2014-2019: HILARY R. MARTENS, LUIS RIVERA, MARK SIMONS
- #
- # This file is part of LoadDef.
- #
- # LoadDef is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # any later version.
- #
- # LoadDef is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with LoadDef. If not, see <https://www.gnu.org/licenses/>.
- #
- # *********************************************************************
-
- import numpy as np
- import scipy as sc
- from scipy import interpolate
- from CONVGF.utility import read_AmpPha
- from CONVGF.CN import convolve_global_grid
- from CONVGF.CN import interpolate_load
- from CONVGF.CN import interpolate_lsmask
- from CONVGF.CN import coef2amppha
- from CONVGF.CN import mass_conservation
- import sys
- import os
- from math import pi
- import matplotlib.pyplot as plt
- import matplotlib.cm as cm
-
- def main(loadfile,ilat,ilon,iarea,load_density,ur,ue,un,mydt,regular,mass_cons,lf_format):
-
- # Check load file format
- if (lf_format == "bbox"): # list of cells, rather than traditional load files
-
- # Select the Appropriate Cell ID
- cslat = loadfile[0]
- cnlat = loadfile[1]
- cwlon = loadfile[2]
- celon = loadfile[3]
- yes_idx = np.where((ilat >= cslat) & (ilat <= cnlat) & (ilon >= cwlon) & (ilon <= celon)); yes_idx = yes_idx[0]
- print(':: Number of convolution grid points within load cell: ', len(yes_idx))
-
- # Find ilat and ilon within cell
- ic1 = np.zeros(len(ilat),)
- ic2 = np.zeros(len(ilat),)
- ic1[yes_idx] = 1. # Amplitude of 1 (ic1 = 1 only inside cell), phase of zero (keep ic2 = 0 everywhere)
-
- # Optionally plot the load cell
- #### Set flag to "False" to turn off plotting of the load cell; "True" to turn it on
- plot_fig = False
- if plot_fig:
- print(':: Plotting the load cell. [perform_convolution.py]')
- cslat_plot = cslat - 0.5
- cnlat_plot = cnlat + 0.5
- cwlon_plot = cwlon - 0.5
- celon_plot = celon + 0.5
- idx_plot = np.where((ilon >= cwlon_plot) & (ilon <= celon_plot) & (ilat >= cslat_plot) & (ilat <= cnlat_plot)); idx_plot = idx_plot[0]
- ilon_plot = ilon[idx_plot]
- ilat_plot = ilat[idx_plot]
- ic1_plot = ic1[idx_plot]
- plt.scatter(ilon_plot,ilat_plot,c=ic1_plot,s=1,cmap=cm.BuPu)
- plt.colorbar(orientation='horizontal')
- fig_name = ("../output/Figures/" + "_" + str(cslat) + "_" + str(cnlat) + "_" + str(cwlon) + "_" + str(celon) + ".png")
- plt.savefig(fig_name,format="png")
- #plt.show()
- plt.close()
-
- else: # traditional load file
-
- # Read the File
- llat,llon,amp,pha,llat1dseq,llon1dseq,amp2darr,pha2darr = read_AmpPha.main(loadfile,lf_format,regular_grid=regular)
-
- # Find Where Amplitude is NaN (if anywhere) and Set to Zero
- nanidx = np.isnan(amp); amp[nanidx] = 0.; pha[nanidx] = 0.
-
- # Convert Amp/Pha Arrays to Real/Imag
- real = np.multiply(amp,np.cos(np.multiply(pha,pi/180.)))
- imag = np.multiply(amp,np.sin(np.multiply(pha,pi/180.)))
-
- # Interpolate Load at Each Grid Point onto the Integration Mesh
- ic1,ic2 = interpolate_load.main(ilat,ilon,llat,llon,real,imag,regular)
-
- # Multiply the Load Heights by the Load Density
- ic1 = np.multiply(ic1,load_density)
- ic2 = np.multiply(ic2,load_density)
-
- # Enforce Mass Conservation
- if (mass_cons == True):
- print('here mass')
- # For Land and Whole-Globe Models (like atmosphere and continental water)
- print(':: Warning: Enforcing Mass Conservation Over Entire Globe.')
- ic1,ic2 = mass_conservation.main(ic1,ic2,iarea)
-
- # Perform the Convolution at Each Grid Point
- c1e,c2e,c1n,c2n,c1v,c2v = convolve_global_grid.main(ic1,ic2,ur,ue,un)
-
- # Sum Over All Grid Cells
- ec1 = np.sum(c1e)
- ec2 = np.sum(c2e)
- nc1 = np.sum(c1n)
- nc2 = np.sum(c2n)
- vc1 = np.sum(c1v)
- vc2 = np.sum(c2v)
-
- # Convert Coefficients to Amplitude and Phase
- # Note: Conversion to mm from meters also happens here!
- eamp,epha,namp,npha,vamp,vpha = coef2amppha.main(ec1,ec2,nc1,nc2,vc1,vc2)
-
- # Return Variables
- return eamp,epha,namp,npha,vamp,vpha
-
-
load_convolution_region.py [..\LoadDef-main\LoadDef-main\CONVGF\CN]
- # -*- coding: utf-8 -*-
- """
- Created on Mon Jul 31 15:01:13 2023
- @author: 我是水怪的哥
- """
- # Import Python Modules
- from __future__ import print_function
- from mpi4py import MPI
- import numpy as np
- import datetime
- import scipy as sc
- import netCDF4
- from scipy import interpolate
- from CONVGF.utility import read_greens_fcn_file
- from CONVGF.utility import read_greens_fcn_file_norm
- from CONVGF.utility import normalize_greens_fcns
- from CONVGF.CN import compute_specific_greens_fcns
- from CONVGF.CN import convolve_global_grid
- from CONVGF.CN import generate_integration_mesh
- from CONVGF.CN import intmesh2geogcoords
- from CONVGF.CN import integrate_greens_fcns
- from CONVGF.CN import interpolate_load
- from CONVGF.CN import compute_angularDist_azimuth
- from CONVGF.CN import coef2amppha
- from CONVGF.CN import perform_convolution_region
- from CONVGF.CN import interpolate_lsmask
- from CONVGF.utility import read_lsmask
- import sys
- import os
- from math import pi
-
- """
- Compute predicted surface displacements caused by surface mass loading by convolving
- displacement load Green's functions with a model for the surface mass load.
- Parameters
- ----------
- load_density : Density of the surface mass load (kg/m^3)
- Default is 1030.0
- rad : Mean Earth radius (m)
- Default is 6371000.
- # -- Mesh Paramters --
- delinc1 : angular distance (degrees) increment for inner zone
- Default is 0.0002
- delinc2 : angular distance (degrees) increment for zone 2
- Default is 0.001
- delinc3 : angluar distance (degrees) increment for zone 3
- Default is 0.01
- delinc4 : angluar distance (degrees) increment for zone 4
- Default is 0.1
- delinc5 : angluar distance (degrees) increment for zone 5
- Default is 0.5
- delinc6 : angular distance (degrees) increment for outer zone
- Default is 1.0
- izb : inner zone boundary (degrees; 0<izb<z2b)
- Default is 0.02
- z2b : zone 2 boundary (degrees; izb<z2b<z3b)
- Default is 0.1
- z3b : zone 3 boundary (degrees; z2b<z3b<z4b)
- Default is 1.0
- z4b : zone 4 boundary (degrees; z3b<z4b<z5b)
- Default is 10.0
- z5b : zone 5 boundary (degrees; z4b<z5b<180)
- Default is 90.0
- azminc : azimuthal increment # NOTE: Maybe should match azminc with delinc5 (i.e., keep azminc consistent with theta increment at 90 degrees from station,
- # where azimuth and theta increments are consistent in horizontal distance along planet's surface)
- # :: azminc*sin(theta) ~ delinc
- Default is 0.5
- mass_cons : option to enforce mass conservation by removing the spatial mean from the load grid
- Default is False
- """
-
- def main(grn_file,norm_flag,load_files,regular,rlat,rlon,cnv_out,loadfile_format,rank,procN,comm,\
- load_density=1030.0,rad=6371000.,delinc1=0.0002,delinc2=0.001,delinc3=0.01,delinc4=0.1,delinc5=0.5,delinc6=1.0,\
- izb=0.02,z2b=0.1,z3b=1.0,z4b=10.0,z5b=90.0,azminc=0.5,mass_cons=False):
-
- # Determine Number of Load Files
- if isinstance(load_files,float) == True:
- numel = 1
- else:
- numel = len(load_files)
-
- # Only the Main Processor Will Do This:
- if (rank == 0):
-
- # Print Number of Files Read In
- display = ':: Number of Files Read In: ' + repr(numel)
- print(display)
- print(" ")
-
- # Determine whether load file was supplied as a list of cells, or as traditional load files
- if (loadfile_format == "bbox"): # list of cells
- # Ensure only one file is read in for this format
- if (numel > 1):
- 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]")
- # Read in the file
- loadgrid = load_files[0]
- lcext = loadgrid[-2::]
- if (lcext == 'xt'):
- file_ids = np.loadtxt(loadgrid,usecols=(4,),unpack=True,dtype='U')
- slat,nlat,wlon,elon = np.loadtxt(loadgrid,usecols=(0,1,2,3),unpack=True)
- elif (lcext == 'nc'):
- f = netCDF4.Dataset(loadgrid)
- file_ids = f.variables['cell_ids'][:]
- slat = f.variables['slatitude'][:]
- nlat = f.variables['nlatitude'][:]
- wlon = f.variables['wlongitude'][:]
- elon = f.variables['elongitude'][:]
- f.close()
- # Ensure that Bounding Box Longitudes are in Range 0-360
- for yy in range(0,len(wlon)):
- if (wlon[yy] < 0.):
- wlon[yy] += 360.
- if (elon[yy] < 0.):
- elon[yy] += 360.
- # Generate an array of cell indices
- file_idx = np.linspace(0,len(file_ids),num=(len(file_ids)),endpoint=False)
- np.random.shuffle(file_idx)
- else:
- # Generate an Array of File Indices
- file_idx = np.linspace(0,numel,num=numel,endpoint=False)
- np.random.shuffle(file_idx)
- # Create Array of Filename Extensions
- file_ids = []
- for qq in range(0,numel):
- mfile = load_files[qq]
- str_components = mfile.split('_')
- cext = str_components[-1]
- if (loadfile_format == "txt"):
- file_ids.append(cext[0:-4])
- elif (loadfile_format == "nc"):
- file_ids.append(cext[0:-3])
- else:
- print(':: Error. Invalid file format for load models. [load_convolution.py]')
- sys.exit()
-
- # Initialize Arrays
- eamp = np.empty((len(file_ids),))
- epha = np.empty((len(file_ids),))
- namp = np.empty((len(file_ids),))
- npha = np.empty((len(file_ids),))
- vamp = np.empty((len(file_ids),))
- vpha = np.empty((len(file_ids),))
-
- # Read Greens Function File
- if norm_flag == True:
- theta,u,v,unormFarrell,vnormFarrell = read_greens_fcn_file_norm.main(grn_file,rad)
- else:
- theta,u,v,unormFarrell,vnormFarrell = read_greens_fcn_file.main(grn_file)
-
- # Normalize Greens Functions (Agnew Convention)
- unorm,vnorm = normalize_greens_fcns.main(theta,u,v,rad)
-
- # Interpolate Greens Functions
- tck_gfu = interpolate.splrep(theta,unorm,k=3)
- tck_gfv = interpolate.splrep(theta,vnorm,k=3)
- xr = np.linspace(0.0001,3.,1000)
-
- # Generate Integration Mesh
- print(':: Generating the Integration Mesh. Please Wait...')
- gldel,glazm,ldel,lazm,unit_area = generate_integration_mesh.main(delinc1,delinc2, \
- delinc3,delinc4,delinc5,delinc6,izb,z2b,z3b,z4b,z5b,azminc)
-
- # Integrate Greens Functions
- uint,vint = integrate_greens_fcns.main(gldel,glazm,ldel,lazm,tck_gfu,tck_gfv)
-
- # Compute Geographic Coordinates of Integration Mesh Cell Midpoints
- ilat,ilon,iarea = intmesh2geogcoords.main(rlat,rlon,ldel,lazm,unit_area)
-
- # Ensure that Station Location is in Range 0-360
- if (rlon < 0.):
- rlon += 360.
-
- # Determine the Land-Sea Mask: Interpolate onto Mesh
- # print(':: Interpolating the Land-Sea Mask. Please Wait...')
- # print(':: Number of Grid Points: %s | Size of LSMask: %s' %(str(len(ilat)), str(lsmask.shape)))
- # print(':: Finished LSMask Interpolation.')
-
- # Compute Angular Distance and Azimuth at Receiver Due to Load
- delta,haz = compute_angularDist_azimuth.main(rlat,rlon,ilat,ilon)
-
- # Compute Greens Functions Specific to Receiver and Grid (Geographic Coordinates)
- ur,ue,un = compute_specific_greens_fcns.main(haz,uint,vint)
-
- # If I'm a Worker, I Know Nothing About the Data
- else:
-
- file_idx = file_ids = eamp = epha = namp = npha = vamp = vpha = None
- ldel = lazm = uint = vint = ilat = ilon = iarea = delta = haz = ur = ue = un = None
- slat = nlat = wlon = elon = None
- # Create a Data Type for the Convolution Results
- cntype = MPI.DOUBLE.Create_contiguous(1)
- cntype.Commit()
- # Gather the Processor Workloads for All Processors
- sendcounts = comm.gather(procN, root=0)
- # Scatter the File Locations (By Index)
- d_sub = np.empty((procN,))
- comm.Scatterv([file_idx, (sendcounts, None), cntype], d_sub, root=0)
- # All Processors Get Certain Arrays and Parameters; Broadcast Them
- ilat = comm.bcast(ilat, root=0)
- ilon = comm.bcast(ilon, root=0)
- iarea = comm.bcast(iarea, root=0)
- ur = comm.bcast(ur, root=0)
- ue = comm.bcast(ue, root=0)
- un = comm.bcast(un, root=0)
- load_density = comm.bcast(load_density, root=0)
- file_ids = comm.bcast(file_ids, root=0)
- file_idx = comm.bcast(file_idx, root=0)
- if (loadfile_format == "bbox"):
- slat = comm.bcast(slat, root=0)
- nlat = comm.bcast(nlat, root=0)
- wlon = comm.bcast(wlon, root=0)
- elon = comm.bcast(elon, root=0)
- # Loop Through the Files
- eamp_sub = np.empty((len(d_sub),))
- epha_sub = np.empty((len(d_sub),))
- namp_sub = np.empty((len(d_sub),))
- npha_sub = np.empty((len(d_sub),))
- vamp_sub = np.empty((len(d_sub),))
- vpha_sub = np.empty((len(d_sub),))
- for ii in range(0,len(d_sub)):
- current_d = int(d_sub[ii]) # Index
- if (loadfile_format == "bbox"):
- cslat = slat[current_d]
- cnlat = nlat[current_d]
- cwlon = wlon[current_d]
- celon = elon[current_d]
- mfile = [cslat,cnlat,cwlon,celon]
- file_id = file_ids[current_d] # File Extension
- print(':: Working on Cell: %s | Number: %6d of %6d | Rank: %6d' %(file_id, (ii+1), len(d_sub), rank))
- else:
- mfile = load_files[current_d] # Vector-Format
- file_id = file_ids[current_d] # File Extension
- print(':: Working on File: %s | Number: %6d of %6d | Rank: %6d' %(file_id, (ii+1), len(d_sub), rank))
- # Check if Loadfile Exists
- if not (os.path.isfile(mfile)): # file does not exist
- eamp_sub[ii] = np.nan
- epha_sub[ii] = np.nan
- namp_sub[ii] = np.nan
- npha_sub[ii] = np.nan
- vamp_sub[ii] = np.nan
- vpha_sub[ii] = np.nan
- continue
- # Compute Convolution for Current File
- eamp_sub[ii],epha_sub[ii],namp_sub[ii],npha_sub[ii],vamp_sub[ii],vpha_sub[ii] = perform_convolution_region.main(\
- mfile,ilat,ilon,iarea,load_density,ur,ue,un,file_id,regular,mass_cons,loadfile_format)
-
-
- return eamp_sub,epha_sub,namp_sub,npha_sub,vamp_sub,vpha_sub
- else:
- # For Worker Ranks, Return Nothing
- return
- # # Gather Results
- # comm.Gatherv(eamp_sub, [eamp, (sendcounts, None), MPI.DOUBLE], root=0)
- # comm.Gatherv(epha_sub, [epha, (sendcounts, None), MPI.DOUBLE], root=0)
- # comm.Gatherv(namp_sub, [namp, (sendcounts, None), MPI.DOUBLE], root=0)
- # comm.Gatherv(npha_sub, [npha, (sendcounts, None), MPI.DOUBLE], root=0)
- # comm.Gatherv(vamp_sub, [vamp, (sendcounts, None), MPI.DOUBLE], root=0)
- # comm.Gatherv(vpha_sub, [vpha, (sendcounts, None), MPI.DOUBLE], root=0)
- # # Make Sure Everyone Has Reported Back Before Moving On
- # comm.Barrier()
- # # Free Data Type
- # cntype.Free()
- # # Print Output to Files and Return Variables
- # if (rank == 0):
- # # Re-organize Files
- # narr,nidx = np.unique(file_idx,return_index=True)
- # eamp = eamp[nidx]; namp = namp[nidx]; vamp = vamp[nidx]
- # epha = epha[nidx]; npha = npha[nidx]; vpha = vpha[nidx]
- # # Prepare Output Files
- # cnv_file = ("../output/Convolution/GRACE_global" + cnv_out)
- # cnv_head = ("../output/Convolution/"+str(np.random.randint(500))+"cn_head.txt")
- # cnv_body = ("../output/Convolution/"+str(np.random.randint(500))+"cn_body.txt")
-
- # # Prepare Data for Output (Create a Structured Array)
- # rlat_arr = np.ones((len(eamp),)) * rlat
- # rlon_arr = np.ones((len(eamp),)) * rlon
- # if (loadfile_format == "bbox"):
- # 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'), \
- # ('rlat_arr',float),('rlon_arr',float),('eamp',float),('epha',float),('namp',float),('npha',float), \
- # ('vamp',float),('vpha',float),('slat',float),('nlat',float),('wlon',float),('elon',float)])
- # else:
- # all_cnv_data = np.array(list(zip(file_ids,rlat_arr,rlon_arr,eamp,epha,namp,npha,vamp,vpha)), dtype=[('file_ids','U25'), \
- # ('rlat_arr',float),('rlon_arr',float),('eamp',float),('epha',float),('namp',float),('npha',float), \
- # ('vamp',float),('vpha',float)])
- # # Write Header Info to File
- # hf = open(cnv_head,'w')
- # if (loadfile_format == "bbox"):
- # 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'
- # else:
- # 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'
- # hf.write(cnv_str)
- # hf.close()
- # # Write Convolution Results to File
- # if (loadfile_format == "bbox"):
- # np.savetxt(cnv_body,all_cnv_data,fmt=["%s"] + ["%.8f",]*12,delimiter=" ")
- # else:
- # np.savetxt(cnv_body,all_cnv_data,fmt=["%s"] + ["%.8f",]*8,delimiter=" ")
- # # Combine Header and Body Files
- # filenames_cnv = [cnv_head, cnv_body]
- # with open(cnv_file,'w') as outfile:
- # for fname in filenames_cnv:
- # with open(fname) as infile:
- # outfile.write(infile.read())
- # # Remove Header and Body Files
- # os.remove(cnv_head)
- # os.remove(cnv_body)
- # Return Amplitude and Phase Response Values
- # return eamp,epha,namp,npha,vamp,vpha,comm
- # else:
- # # For Worker Ranks, Return Nothing
- # 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
李长海, 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。