From 2a5bb67bda02ddf8e42647a544dcc45a0a2e68e3 Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Sat, 12 Nov 2022 16:41:10 -0800 Subject: [PATCH 1/2] move add_attribute.py to legacy dir move `mintpy/add_attribute.py` to the `mintpy/legacy` directory because: 1. it's rarely used (it was designed as a quick hack to fix unexpected metadata problems) 2. it does not have the argparse usage to be included in the "mintpy/cli" sub-module, making it inconvenient to maintain 3. its functionality can be covered in Python using `mintpy.utils.utils.add_attribute()` API and in command line by adding extra metadata in the custom template file during data loading process. --- src/mintpy/{ => legacy}/add_attribute.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/mintpy/{ => legacy}/add_attribute.py (100%) diff --git a/src/mintpy/add_attribute.py b/src/mintpy/legacy/add_attribute.py similarity index 100% rename from src/mintpy/add_attribute.py rename to src/mintpy/legacy/add_attribute.py From ebf4ca9652dd93d6353ef07ae27175ff9a79fc0c Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Sat, 12 Nov 2022 14:07:43 -0800 Subject: [PATCH 2/2] plate_motion: add --plate option to use built-in tables add --plate option to grab the built-in rotation parameters from ITRF2014-PMM (Altamimi et al., 2017), for easy usage. --- src/mintpy/cli/plate_motion.py | 59 +++++++++++++++++++++++++++----- src/mintpy/objects/euler_pole.py | 5 +++ src/mintpy/plate_motion.py | 35 +++---------------- tests/objects/euler_pole.py | 2 +- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/mintpy/cli/plate_motion.py b/src/mintpy/cli/plate_motion.py index eee860a62..cfb30aaf8 100755 --- a/src/mintpy/cli/plate_motion.py +++ b/src/mintpy/cli/plate_motion.py @@ -6,11 +6,37 @@ ############################################################ +import collections import os import sys from mintpy.utils.arg_utils import create_argument_parser +# ITRF2014-PMM defined in Altamimi et al. (2017) +Tag = collections.namedtuple('Tag', 'name num_site omega_x omega_y omega_z omega wrms_e wrms_n') +ITRF2014_PMM = { + 'ANTA' : Tag('Antartica' , 7, -0.248, -0.324, 0.675, 0.219, 0.20, 0.16), + 'ARAB' : Tag('Arabia' , 5, 1.154, -0.136, 1.444, 0.515, 0.36, 0.43), + 'AUST' : Tag('Australia' , 36, 1.510, 1.182, 1.215, 0.631, 0.24, 0.20), + 'EURA' : Tag('Eurasia' , 97, -0.085, -0.531, 0.770, 0.261, 0.23, 0.19), + 'INDI' : Tag('India' , 3, 1.154, -0.005, 1.454, 0.516, 0.21, 0.21), + 'NAZC' : Tag('Nazca' , 2, -0.333, -1.544, 1.623, 0.629, 0.13, 0.19), + 'NOAM' : Tag('N. America' , 72, 0.024, -0.694, -0.063, 0.194, 0.23, 0.28), + 'NUBI' : Tag('Nubia' , 24, 0.099, -0.614, 0.733, 0.267, 0.28, 0.36), + 'PCFC' : Tag('Pacific' , 18, -0.409, 1.047, -2.169, 0.679, 0.36, 0.31), + 'SOAM' : Tag('S. America' , 30, -0.270, -0.301, -0.140, 0.119, 0.34, 0.35), + 'SOMA' : Tag('Somalia' , 3, -0.121, -0.794, 0.884, 0.332, 0.32, 0.30), +} +PMM_UNIT = { + 'omega' : 'deg/Ma', # degree per megayear or one-million-year + 'omega_x' : 'mas/yr', # milli-arcsecond per year + 'omega_y' : 'mas/yr', # milli-arcsecond per year + 'omega_z' : 'mas/yr', # milli-arcsecond per year + 'wrms_e' : 'mm/yr', # milli-meter per year, weighted root mean scatter + 'wrms_n' : 'mm/yr', # milli-meter per year, weighted root mean scatter +} + + ######################################### Usage ############################################## REFERENCE = """reference: Stephenson, O. L., Liu, Y. K., Yunjun, Z., Simons, M., Rosen, P. and Xu, X., (2022), @@ -31,10 +57,14 @@ """ EXAMPLE = """example: + # Use build-in plate motion model of Table 1 from Altamimi et al. (2017) + plate_motion.py -g inputs/geometryGeo.h5 --plate ARAB + plate_motion.py -g inputs/geometryRadar.h5 --plate EURA + # Cartesian form of Euler pole rotation in [wx, wy, wz] in unit of mas/year [milli arc second per year] # e.g., Arabia plate in ITRF14-PMM (Table 1 in Altamimi et al., 2017) - plate_motion.py -g inputs/geometryGeo.h5 --om-cart 1.154 -0.136 1.444 -v velocity.h5 plate_motion.py -g inputs/geometryRadar.h5 --om-cart 1.154 -0.136 1.444 + plate_motion.py -g inputs/geometryGeo.h5 --om-cart 1.154 -0.136 1.444 -v velocity.h5 plate_motion.py -g inputs/geometryRadar.h5 --om-cart 1.154 -0.136 1.444 --comp en2az # Simple constant local ENU translation (based on one GNSS vector) in [ve, vn, vu] in unit of m/year @@ -68,21 +98,26 @@ def create_parser(subparsers=None): help='Input velocity file to be corrected.') parser.add_argument('-o', '--output', dest='cor_vel_file', type=str, help='Output velocity file after the correction, default: add "_ITRF14" suffix.') + + # plate motion calculation parser.add_argument('--comp', dest='pmm_comp', choices={'enu2los', 'en2az'}, default='enu2los', help='Convert the ENU components into the component of interest for radar (default: %(default)s).') + parser.add_argument('--step','--pmm-step', dest='pmm_step', type=float, default=10., + help='Ground step/resolution in km for computing PMM to ENU velocity (default: %(default)s).') # plate motion configurations - pmm = parser.add_mutually_exclusive_group(required=True) - pmm.add_argument('--om-cart', dest='omega_cart', type=float, nargs=3, metavar=('WX', 'WY', 'WZ'), default=None, + pmm = parser.add_argument_group('plate motion model') + pmg = pmm.add_mutually_exclusive_group(required=True) + pmg.add_argument('--plate', dest='plate_name', type=str, choices=ITRF2014_PMM.keys(), default=None, + help='Tectonic plate in ITRF14 (Table 1 in Altamimi et al., 2017) as below:\n' + + '\n'.join(f'{key} for {val.name}' for key, val in ITRF2014_PMM.items())) + pmg.add_argument('--om-cart', dest='omega_cart', type=float, nargs=3, metavar=('WX', 'WY', 'WZ'), default=None, help='Cartesian form of Euler Pole rotation (unit: mas/yr) (default: %(default)s).') - pmm.add_argument('--om-sph', dest='omega_sph', type=float, nargs=3, metavar=('LAT', 'LON', 'W'), default=None, + pmg.add_argument('--om-sph', dest='omega_sph', type=float, nargs=3, metavar=('LAT', 'LON', 'W'), default=None, help='Spherical form of Euler Pole rotation (unit: deg, deg, deg/Ma) (default: %(default)s).') - pmm.add_argument('--enu', dest='const_vel_enu', type=float, nargs=3, metavar=('VE', 'VN', 'VU'), default=None, + pmg.add_argument('--enu', dest='const_vel_enu', type=float, nargs=3, metavar=('VE', 'VN', 'VU'), default=None, help='Constant local ground translation (unit: m/year) (default: %(default)s).') - parser.add_argument('--step','--pmm-step', dest='pmm_step', type=float, default=10., - help='Ground step/resolution in km for computing PMM to ENU velocity (default: %(default)s).') - return parser @@ -102,6 +137,14 @@ def cmd_line_parse(iargs=None): vbase = os.path.splitext(inps.vel_file)[0] inps.cor_vel_file = os.path.abspath(f'{vbase}_ITRF14.h5') + # check: --plate option (and convert to --om-cart) + if inps.plate_name: + plate = ITRF2014_PMM[inps.plate_name] + inps.omega_cart = [plate.omega_x, plate.omega_y, plate.omega_z] + msg = f'get rotation parameters for {inps.plate_name} plate from Table 1 in Altamimi et al. (2017): ' + msg += f'wx, wy, wz = {plate.omega_x}, {plate.omega_y}, {plate.omega_z} mas/yr' + print(msg) + return inps diff --git a/src/mintpy/objects/euler_pole.py b/src/mintpy/objects/euler_pole.py index 54c41894e..780cb8bfc 100644 --- a/src/mintpy/objects/euler_pole.py +++ b/src/mintpy/objects/euler_pole.py @@ -14,6 +14,8 @@ # Palo Alto. DOI: 10.4236/ojapps.2015.54016. Page 145-156. # Navipedia, Transformations between ECEF and ENU coordinates. [Online]. # https://gssc.esa.int/navipedia/index.php/Transformations_between_ECEF_and_ENU_coordinates +# Goudarzi, M. A., Cocard, M. & Santerre, R. (2014), EPC: Matlab software to estimate Euler +# pole parameters, GPS Solutions, 18, 153-162, doi: 10.1007/s10291-013-0354-4 import numpy as np @@ -178,6 +180,9 @@ def get_velocity_xyz(self, lat, lon, alt=0.0, ellps=True, print_msg=True): poi_shape = lat.shape if isinstance(lat, np.ndarray) else None # convert lat/lon into x/y/z + # Note: the conversion assumes either a spherical or spheroidal Earth, tests show that + # using a ellipsoid as defined in WGS84 produce results closer to the UNAVCO website + # calculator, which also uses the WGS84 ellipsoid. if ellps: if print_msg: print('assume a spheroidal Earth as defined in WGS84') diff --git a/src/mintpy/plate_motion.py b/src/mintpy/plate_motion.py index 852247c74..732e4d4ae 100644 --- a/src/mintpy/plate_motion.py +++ b/src/mintpy/plate_motion.py @@ -10,12 +10,7 @@ # Stephenson, O. L., Liu, Y. K., Yunjun, Z., Simons, M., Rosen, P. and Xu, X., (2022), # The Impact of Plate Motions on Long-Wavelength InSAR-Derived Velocity Fields, # Geophys. Res. Lett. 49, e2022GL099835, doi:10.1029/2022GL099835. -# -# To-Do List (updated 2022.10.12 Yuan-Kai Liu): -# + Use built-in PMM table ITRF2014_PMM for easier/automatic user input string input - -import collections import numpy as np from skimage.transform import resize @@ -25,31 +20,6 @@ from mintpy.objects.resample import resample from mintpy.utils import readfile, utils as ut, writefile -# ITRF2014-PMM defined in Altamimi et al. (2017) -Tag = collections.namedtuple('Tag', 'name num_site omega_x omega_y omega_z omega wrms_e wrms_n') -ITRF2014_PMM = { - 'ANTA' : Tag('Antartica' , 7, -0.248, -0.324, 0.675, 0.219, 0.20, 0.16), - 'ARAB' : Tag('Arabia' , 5, 1.154, -0.136, 1.444, 0.515, 0.36, 0.43), - 'AUST' : Tag('Australia' , 36, 1.510, 1.182, 1.215, 0.631, 0.24, 0.20), - 'EURA' : Tag('Eurasia' , 97, -0.085, -0.531, 0.770, 0.261, 0.23, 0.19), - 'INDI' : Tag('India' , 3, 1.154, -0.005, 1.454, 0.516, 0.21, 0.21), - 'NAZC' : Tag('Nazca' , 2, -0.333, -1.544, 1.623, 0.629, 0.13, 0.19), - 'NOAM' : Tag('N. America' , 72, 0.024, -0.694, -0.063, 0.194, 0.23, 0.28), - 'NUBI' : Tag('Nubia' , 24, 0.099, -0.614, 0.733, 0.267, 0.28, 0.36), - 'PCFC' : Tag('Pacific' , 18, -0.409, 1.047, -2.169, 0.679, 0.36, 0.31), - 'SOAM' : Tag('S. America' , 30, -0.270, -0.301, -0.140, 0.119, 0.34, 0.35), - 'SOMA' : Tag('Somalia' , 3, -0.121, -0.794, 0.884, 0.332, 0.32, 0.30), -} -PMM_UNIT = { - 'omega' : 'deg/Ma', # degree per megayear or one-million-year - 'omega_x' : 'mas/yr', # milli-arcsecond per year - 'omega_y' : 'mas/yr', # milli-arcsecond per year - 'omega_z' : 'mas/yr', # milli-arcsecond per year - 'wrms_e' : 'mm/yr', # milli-meter per year, weighted root mean scatter - 'wrms_n' : 'mm/yr', # milli-meter per year, weighted root mean scatter -} - - ####################################### Major Function ########################################### def calc_plate_motion(geom_file, omega_cart=None, omega_sph=None, const_vel_enu=None, @@ -143,6 +113,9 @@ def calc_plate_motion(geom_file, omega_cart=None, omega_sph=None, const_vel_enu= vn = const_vel_enu[1] * np.ones(shape_geo, dtype=np.float32) vu = const_vel_enu[2] * np.ones(shape_geo, dtype=np.float32) + else: + raise ValueError('No plate motion configuration (--om-cart/sph or --enu) found!') + # radar-code the plate motion if input geometry is in radar coordinates atr = readfile.read_attribute(geom_file) @@ -197,6 +170,7 @@ def calc_plate_motion(geom_file, omega_cart=None, omega_sph=None, const_vel_enu= def run_plate_motion(inps): """Calculate and/or correct for the rigid motion from tectonic plates.""" + # calculate plate motion calc_plate_motion( geom_file=inps.geom_file, omega_cart=inps.omega_cart, @@ -208,6 +182,7 @@ def run_plate_motion(inps): pmm_step=inps.pmm_step, ) + # correct plate motion from input velocity if inps.vel_file and inps.pmm_file and inps.cor_vel_file: print('-'*50) print('Correct input velocity for the rigid plate motion') diff --git a/tests/objects/euler_pole.py b/tests/objects/euler_pole.py index d214f52c0..8fc5e0c2b 100755 --- a/tests/objects/euler_pole.py +++ b/tests/objects/euler_pole.py @@ -6,8 +6,8 @@ import collections import math +from mintpy.cli.plate_motion import ITRF2014_PMM from mintpy.objects.euler_pole import MASY2DMY, EulerPole -from mintpy.plate_motion import ITRF2014_PMM # validation against the UNAVCO Plate Motion Calculator # https://www.unavco.org/software/geodetic-utilities/plate-motion-calculator/plate-motion-calculator.html