From 3d353fa79ca93222fd76e35939c5463b89d5ba00 Mon Sep 17 00:00:00 2001 From: rzinke Date: Wed, 20 Aug 2025 06:37:08 +0000 Subject: [PATCH 1/5] Added interferogram masking based on geometry watermask --- .../Transient_Requirement_Validation.ipynb | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/methods/transient/Transient_Requirement_Validation.ipynb b/methods/transient/Transient_Requirement_Validation.ipynb index 3a66661..29272f1 100644 --- a/methods/transient/Transient_Requirement_Validation.ipynb +++ b/methods/transient/Transient_Requirement_Validation.ipynb @@ -37,8 +37,9 @@ "[**1. Download and Prepare Interferograms**](#prep_ifg)\n", "[Executed in ARIA_prep]\n", "\n", - "[**2. Generate Interferogram Stack**](#transient_gen_ifg)\n", + "[**2. Selection of Interferograms**](#transient_select_ifg)\n", "- [2.1. Validate/Modify Interferogram Network](#transient_crop_ifg)\n", + "- [2.2. Modify Reference Point](#transient_ref_pt)\n", "\n", "[**3. Optional Corrections**](#opt_correction)\n", "- [3.1. Solid Earth Tide Correction](#solid_earth)\n", @@ -141,7 +142,7 @@ "dataset = 'ARIA_S1_new' # For Sentinel-1 testing with aria-tools\n", "aria_gunw_version = \"3_0_1\"\n", "\n", - "rundate = \"20240909\" # Date of this Cal/Val run\n", + "rundate = \"20250623\" # Date of this Cal/Val run\n", "version = \"1\" # Version of this Cal/Val run\n", "custom_sites = \"/home/jovyan/my_sites.txt\" # Path to custom site metadata\n", "\n", @@ -209,6 +210,7 @@ " # === Set Expected MintPy Filenames ===\n", " ifgs_file = os.path.join(mintpy_dir, \"inputs/ifgramStack.h5\")\n", " geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", + " msk_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", " config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" ] }, @@ -243,8 +245,8 @@ "
\n", "
\n", "\n", - "\n", - "## 2. Generation of Time Series from Interferograms" + "\n", + "## 2. Selection of Interferograms" ] }, { @@ -509,7 +511,7 @@ "source": [ "# Visualize the corrections\n", "if site_info.get('do_iono') != \"False\":\n", - " view.main([iono_stack_file, '-c', 'RdBu_r'])\n", + " view.main([iono_stack_file, '-c', 'RdBu_r', '-m', msk_file])\n", "else: \n", " print('#'*10, 'Ionosphere Correction set to False', '#'*10)" ] @@ -522,7 +524,7 @@ "source": [ "# Visualize the corrected interferograms\n", "if site_info.get('do_iono') != \"False\":\n", - " view.main([ifgs_file, '-c', 'RdBu_r'])\n", + " view.main([ifgs_file, '-c', 'RdBu_r', '-m', msk_file])\n", "else: \n", " print('#'*10, 'Ionosphere Correction set to False', '#'*10)" ] @@ -590,7 +592,14 @@ "source": [ "# Create stack of troposphere correction layer pairs following the above sign convention\n", "if site_info.get('do_tropo')!= \"False\":\n", - " tropo_stack_file = pairwise_stack_from_timeseries(ifgs_file, tropo_cor_file)" + " try:\n", + " # Attempt to create a pairwise stack of tropo files\n", + " tropo_stack_file = pairwise_stack_from_timeseries(ifgs_file, tropo_cor_file)\n", + " except:\n", + " print(\"Tropo stack generation failed. Setting tropo correction to False\")\n", + "\n", + " # Stack creation failed, set tropo correction to false\n", + " site_info['do_tropo'] = \"False\"" ] }, { @@ -619,7 +628,7 @@ "source": [ "# Visualize the corrections\n", "if site_info.get('do_tropo') != \"False\":\n", - " view.main([tropo_stack_file, '-c', 'RdBu_r'])\n", + " view.main([tropo_stack_file, '-c', 'RdBu_r', '-m', msk_file])\n", "else: \n", " print('#'*10, 'Troposphere Correction set to False', '#'*10)" ] @@ -632,7 +641,7 @@ "source": [ "# Visualize the corrected interferograms\n", "if site_info.get('do_tropo') != \"False\":\n", - " view.main([ifgs_file, '-c', 'RdBu_r'])\n", + " view.main([ifgs_file, '-c', 'RdBu_r', '-m', msk_file])\n", "else: \n", " print('#'*10, 'Troposphere Correction set to False', '#'*10)" ] @@ -709,7 +718,14 @@ "# Convert displacement units from m to mm\n", "insar_displacement = insar_displacement * 1000.\n", "\n", + "# Read 2D mask array\n", + "msk, _ = readfile.read(msk_file, datasetName=\"waterMask\")\n", + "\n", + "# Repeat mask array for each interferogram\n", + "msk = np.stack([msk] * insar_displacement.shape[0], axis=0)\n", + " \n", "# Set masked pixels to NaN\n", + "insar_displacement[msk == 0] = np.nan\n", "insar_displacement[insar_displacement==0.0] = np.nan\n", "\n", "# Clean up phase-only IFGs to avoid future confusion\n", @@ -1564,7 +1580,14 @@ "# Convert displacement units from m to mm\n", "insar_displacement = insar_displacement * 1000.\n", "\n", + "# Read 2D mask array\n", + "msk, _ = readfile.read(msk_file, datasetName=\"waterMask\")\n", + "\n", + "# Repeat mask array for each interferogram\n", + "msk = np.stack([msk] * insar_displacement.shape[0], axis=0)\n", + " \n", "# Set masked pixels to NaN\n", + "insar_displacement[msk == 0] = np.nan\n", "insar_displacement[insar_displacement==0.0] = np.nan\n", "\n", "# Clean up phase-only IFGs to avoid future confusion\n", From a3451f9156c1d2e6b378b151d75c502e621d11fd Mon Sep 17 00:00:00 2001 From: rzinke Date: Wed, 20 Aug 2025 07:36:41 +0000 Subject: [PATCH 2/5] Reference points now applied to ifgrams and correction layers. --- .../Transient_Requirement_Validation.ipynb | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/methods/transient/Transient_Requirement_Validation.ipynb b/methods/transient/Transient_Requirement_Validation.ipynb index 29272f1..4316695 100644 --- a/methods/transient/Transient_Requirement_Validation.ipynb +++ b/methods/transient/Transient_Requirement_Validation.ipynb @@ -117,6 +117,7 @@ "from solid_utils.sampling import load_geo, samp_pair\n", "from solid_utils.plotting import display_validation_table, \\\n", " display_coseismic_validation as display_transient_validation\n", + "from solid_utils.configs import update_reference_point\n", "from solid_utils.corrections import run_cmd, pairwise_stack_from_timeseries\n", "from solid_utils.saving import save_results" ] @@ -405,6 +406,39 @@ "insar_coherence, _ = readfile.read(ifgs_file, datasetName=coherenceName)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.2. Generate Quality Control Mask \n", + "\n", + "Not implemented. Interferogram masking currently relies on the water mask embedded in the `geometryGeo.h5` file." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3. Reference Interferograms To Common Lat/Lon " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if site_info.get('reference_lalo') != 'auto':\n", + " new_lat = site_info.get('reference_lalo').split(',')[0]\n", + " new_lon = site_info.get('reference_lalo').split(',')[1]\n", + " update_reference_point(config_file, new_lat, new_lon) # updates the reference point in MintPy config file\n", + " \n", + "# Now reference interferograms to common lat/lon\n", + "command = 'smallbaselineApp.py ' + str(config_file) + ' --dostep reference_point'\n", + "process = subprocess.run(command, shell=True)\n", + "os.system('info.py inputs/ifgramStack.h5 | egrep \"REF_\"');" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -485,6 +519,22 @@ "The `ionStack.h5` dataset is written using the convention ref_repeat and is stored in units of radians. Therefore, the ionosphere correction layers can be directly subtracted from the ifgramStack.h5 unwrapped phase values to apply the ionosphere correction." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set reference point of ionosphere file\n", + "if site_info.get('do_iono')!= \"False\":\n", + " # Run difference\n", + " run_cmd(f\"reference_point.py {iono_stack_file} -t {config_file}\",\n", + " desc=\"Apply iono correction to IFG stack\")\n", + "\n", + "else:\n", + " print('#'*10, 'Ionosphere Correction set to False', '#'*10)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -602,6 +652,22 @@ " site_info['do_tropo'] = \"False\"" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set reference point of troposphere file\n", + "if site_info.get('do_tropo')!= \"False\":\n", + " # Run difference\n", + " run_cmd(f\"reference_point.py {tropo_stack_file} -t {config_file}\",\n", + " desc=\"Apply tropo correction to IFG stack\")\n", + "\n", + "else:\n", + " print('#'*10, 'Troposphere Correction set to False', '#'*10)" + ] + }, { "cell_type": "code", "execution_count": null, From 3d4ae64b52167ea1a66f3c7fa54848a7862bf04e Mon Sep 17 00:00:00 2001 From: "katia.tymofyeyeva" Date: Wed, 20 Aug 2025 11:57:44 +0000 Subject: [PATCH 3/5] Fixed: msk_file definition, ref point issues, subplot issues, tropo correction exception issue --- .../Transient_Requirement_Validation.ipynb | 32 +++++++++++++++---- prep/ARIA_prep.ipynb | 12 +++++-- solid_utils/corrections.py | 13 ++++++-- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/methods/transient/Transient_Requirement_Validation.ipynb b/methods/transient/Transient_Requirement_Validation.ipynb index 4316695..4775ba4 100644 --- a/methods/transient/Transient_Requirement_Validation.ipynb +++ b/methods/transient/Transient_Requirement_Validation.ipynb @@ -143,7 +143,7 @@ "dataset = 'ARIA_S1_new' # For Sentinel-1 testing with aria-tools\n", "aria_gunw_version = \"3_0_1\"\n", "\n", - "rundate = \"20250623\" # Date of this Cal/Val run\n", + "rundate = \"20250820\" # Date of this Cal/Val run\n", "version = \"1\" # Version of this Cal/Val run\n", "custom_sites = \"/home/jovyan/my_sites.txt\" # Path to custom site metadata\n", "\n", @@ -211,14 +211,16 @@ " # === Set Expected MintPy Filenames ===\n", " ifgs_file = os.path.join(mintpy_dir, \"inputs/ifgramStack.h5\")\n", " geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", - " msk_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", + " msk_file = os.path.join(work_dir, \"mask\", \"esa_world_cover_2021.msk\")\n", " config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [], "source": [ "configs = readfile.read_template(config_file)\n", @@ -425,7 +427,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [], "source": [ "if site_info.get('reference_lalo') != 'auto':\n", @@ -439,6 +443,19 @@ "os.system('info.py inputs/ifgramStack.h5 | egrep \"REF_\"');" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize the original interferograms\n", + "if site_info.get('do_iono') != \"False\":\n", + " view.main([ifgs_file, '-c', 'RdBu_r', '-m', msk_file])\n", + "else: \n", + " print('#'*10, 'Ionosphere Correction set to False', '#'*10)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -528,8 +545,9 @@ "# Set reference point of ionosphere file\n", "if site_info.get('do_iono')!= \"False\":\n", " # Run difference\n", - " run_cmd(f\"reference_point.py {iono_stack_file} -t {config_file}\",\n", + " run_cmd(f\"reference_point.py {iono_stack_file} -r {ifgs_file}\",\n", " desc=\"Apply iono correction to IFG stack\")\n", + " \n", "\n", "else:\n", " print('#'*10, 'Ionosphere Correction set to False', '#'*10)" @@ -661,7 +679,7 @@ "# Set reference point of troposphere file\n", "if site_info.get('do_tropo')!= \"False\":\n", " # Run difference\n", - " run_cmd(f\"reference_point.py {tropo_stack_file} -t {config_file}\",\n", + " run_cmd(f\"reference_point.py {tropo_stack_file} -r {ifgs_file}\",\n", " desc=\"Apply tropo correction to IFG stack\")\n", "\n", "else:\n", @@ -1176,7 +1194,7 @@ "# Loop through interferograms\n", "gnss_insar_figs = []\n", "for ifg_ndx in displacement.index.get_level_values(0).unique():\n", - " fig, ax = plt.subplots()\n", + " fig, ax = plt.subplots(figsize = (8,8))\n", " img1 = ax.imshow(insar_displacement[ifg_ndx],\n", " cmap=cmap_obj, vmin=vmin, vmax=vmax, interpolation='nearest',\n", " extent=(W, E, S, N))\n", diff --git a/prep/ARIA_prep.ipynb b/prep/ARIA_prep.ipynb index 05965f8..87a09d0 100644 --- a/prep/ARIA_prep.ipynb +++ b/prep/ARIA_prep.ipynb @@ -95,11 +95,11 @@ "source": [ "# === Basic Configuration ===\n", "site = \"test\" # Cal/Val location ID\n", - "requirement = \"Secular\" # Options: 'Secular', 'Coseismic', 'Transient'\n", + "requirement = \"Transient\" # Options: 'Secular', 'Coseismic', 'Transient'\n", "dataset = \"ARIA_S1_new\" # Dataset type: 'ARIA_S1', 'ARIA_S1_new'\n", "aria_gunw_version = \"3_0_1\"\n", "\n", - "rundate = \"20250623\" # Date of this Cal/Val run\n", + "rundate = \"20250820\" # Date of this Cal/Val run\n", "version = \"1\" # Version of this Cal/Val run\n", "custom_sites = \"/home/jovyan/my_sites.txt\" # Path to custom site metadata\n", "\n", @@ -661,6 +661,14 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e9678ca-dd7d-43fb-903e-a2ce39664238", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/solid_utils/corrections.py b/solid_utils/corrections.py index b0518a1..8be9a2f 100644 --- a/solid_utils/corrections.py +++ b/solid_utils/corrections.py @@ -7,6 +7,7 @@ import h5py from mintpy.utils import readfile, writefile, plot from mintpy.objects import ifgramStack, timeseries +import warnings ## Correction application def run_cmd(command, desc=None, check=True): @@ -90,10 +91,13 @@ def pairwise_stack_from_timeseries(ifgs_file:str, tropo_cor_file:str): for date_pair in ifg_datepairList: ifg_dates.extend(date_pair.split("_")) ifg_dates = list(set(ifg_dates)) - + + badlist = [] for date in ifg_dates: if date not in tropo_dateList: - raise Exception(f"No tropo correction layer for {date}") + #raise Exception(f"No tropo correction layer for {date}") + warnings.warn("No tropo correction layer for date " + date + " Interferograms with this scene will not be corrected for troposphere.") + badlist.append(date) # Read tropo metadata tropo_metadata = readfile.read_attribute(tropo_cor_file, @@ -121,6 +125,11 @@ def pairwise_stack_from_timeseries(ifgs_file:str, tropo_cor_file:str): for i, datepair in enumerate(ifg_datepairList): # Parse dates - for MintPy convention, the more recent date is the reference ref_date, sec_date = datepair.split("_") + + if ref_date in badlist or sec_date in badlist: + tropo_diff = np.zeros((ifgs_shape[1],ifgs_shape[2])) + tropo_diff_stack[i,...] = tropo_diff + continue # Retrieve tropo layers tropo_ref, _ = readfile.read(tropo_cor_file, From 144ba3ac990241399eeb60036122f586f3078f3c Mon Sep 17 00:00:00 2001 From: rzinke Date: Wed, 20 Aug 2025 16:32:44 +0000 Subject: [PATCH 4/5] Site file definitions should not be indented --- .../transient/Transient_Requirement_Validation.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/methods/transient/Transient_Requirement_Validation.ipynb b/methods/transient/Transient_Requirement_Validation.ipynb index 4775ba4..be33c85 100644 --- a/methods/transient/Transient_Requirement_Validation.ipynb +++ b/methods/transient/Transient_Requirement_Validation.ipynb @@ -208,11 +208,11 @@ "else:\n", " os.chdir(mintpy_dir)\n", "\n", - " # === Set Expected MintPy Filenames ===\n", - " ifgs_file = os.path.join(mintpy_dir, \"inputs/ifgramStack.h5\")\n", - " geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", - " msk_file = os.path.join(work_dir, \"mask\", \"esa_world_cover_2021.msk\")\n", - " config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" + "# === Set Expected MintPy Filenames ===\n", + "ifgs_file = os.path.join(mintpy_dir, \"inputs/ifgramStack.h5\")\n", + "geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", + "msk_file = os.path.join(work_dir, \"mask\", \"esa_world_cover_2021.msk\")\n", + "config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" ] }, { From b13c19b0bf790fbda6fc2642c3be608fe202a448 Mon Sep 17 00:00:00 2001 From: "katia.tymofyeyeva" Date: Wed, 20 Aug 2025 17:04:26 +0000 Subject: [PATCH 5/5] Method 2 results for transient were not saved. Added functionality to also save reports to the home directory for each user --- .../Coseismic_Requirement_Validation.ipynb | 27 ++++++--- .../Secular_Requirement_Validation.ipynb | 44 +++++++++++---- .../Transient_Requirement_Validation.ipynb | 56 ++++++++++++++----- 3 files changed, 97 insertions(+), 30 deletions(-) diff --git a/methods/coseismic/Coseismic_Requirement_Validation.ipynb b/methods/coseismic/Coseismic_Requirement_Validation.ipynb index dc4c4a4..d990640 100644 --- a/methods/coseismic/Coseismic_Requirement_Validation.ipynb +++ b/methods/coseismic/Coseismic_Requirement_Validation.ipynb @@ -146,7 +146,7 @@ "dataset = \"ARIA_S1_new\" # Dataset type: 'ARIA_S1', 'ARIA_S1_new'\n", "aria_gunw_version = \"3_0_1\"\n", "\n", - "rundate = \"20250512\" # Date of this Cal/Val run\n", + "rundate = \"20250820\" # Date of this Cal/Val run\n", "version = \"1\" # Version of this Cal/Val run\n", "custom_sites = \"/home/jovyan/my_sites.txt\" # Path to custom site metadata\n", "\n", @@ -198,6 +198,11 @@ "mintpy_dir = os.path.join(work_dir, \"MintPy\")\n", "weather_dir = os.path.join(site_dir)\n", "\n", + "# === Home directory for saving reports ===\n", + "home_dir = os.path.join(\"/home/jovyan/validation/\", site, requirement, rundate, f\"v{version}\")\n", + "if not os.path.exists(home_dir):\n", + " os.makedirs(home_dir)\n", + "\n", "# === Log Directory Paths ===\n", "print(f\" Work directory: {work_dir}\")\n", "print(f\" GUNW directory: {gunw_dir}\")\n", @@ -211,12 +216,12 @@ "else:\n", " os.chdir(mintpy_dir)\n", "\n", - " # === Set Expected MintPy Filenames ===\n", - " geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", - " msk_file = os.path.join(mintpy_dir, \"maskTempCoh.h5\") # alt: maskConnComp.h5\n", - " ts_file = os.path.join(mintpy_dir, \"timeseries.h5\")\n", - " vel_file = os.path.join(mintpy_dir, \"velocity.h5\")\n", - " config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" + "# === Set Expected MintPy Filenames ===\n", + "geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", + "msk_file = os.path.join(mintpy_dir, \"maskTempCoh.h5\") # alt: maskConnComp.h5\n", + "ts_file = os.path.join(mintpy_dir, \"timeseries.h5\")\n", + "vel_file = os.path.join(mintpy_dir, \"velocity.h5\")\n", + "config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" ] }, { @@ -1487,6 +1492,10 @@ " 'validation_table': validation_table_method1,\n", " 'ts_functions': ts_functions,\n", "}\n", + "save_results(**save_params)\n", + "\n", + "# Save the report in the home directory as well\n", + "save_params['save_dir'] = home_dir\n", "save_results(**save_params)" ] }, @@ -1784,6 +1793,10 @@ " 'validation_table': validation_table_method2,\n", " 'ts_functions': ts_functions,\n", "}\n", + "save_results(**save_params)\n", + "\n", + "# Save the report in the home directory as well\n", + "save_params['save_dir'] = home_dir\n", "save_results(**save_params)" ] }, diff --git a/methods/secular/Secular_Requirement_Validation.ipynb b/methods/secular/Secular_Requirement_Validation.ipynb index 923adc3..6257a6d 100644 --- a/methods/secular/Secular_Requirement_Validation.ipynb +++ b/methods/secular/Secular_Requirement_Validation.ipynb @@ -149,7 +149,7 @@ "dataset = \"ARIA_S1_new\" # Dataset type: 'ARIA_S1', 'ARIA_S1_new'\n", "aria_gunw_version = \"3_0_1\"\n", "\n", - "rundate = \"20250602\" # Date of this Cal/Val run\n", + "rundate = \"20250820\" # Date of this Cal/Val run\n", "version = \"1\" # Version of this Cal/Val run\n", "custom_sites = \"/home/jovyan/my_sites.txt\" # Path to custom site metadata\n", "\n", @@ -204,6 +204,11 @@ "mintpy_dir = os.path.join(work_dir, \"MintPy\")\n", "weather_dir = os.path.join(site_dir)\n", "\n", + "# === Home directory for saving reports ===\n", + "home_dir = os.path.join(\"/home/jovyan/validation/\", site, requirement, rundate, f\"v{version}\")\n", + "if not os.path.exists(home_dir):\n", + " os.makedirs(home_dir)\n", + "\n", "# === Log Directory Paths ===\n", "print(f\" Work directory: {work_dir}\")\n", "print(f\" GUNW directory: {gunw_dir}\")\n", @@ -217,12 +222,12 @@ "else:\n", " os.chdir(mintpy_dir)\n", "\n", - " # === Set Expected MintPy Filenames ===\n", - " geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", - " msk_file = os.path.join(mintpy_dir, \"maskTempCoh.h5\") # alt: maskConnComp.h5\n", - " ts_file = os.path.join(mintpy_dir, \"timeseries.h5\")\n", - " vel_file = os.path.join(mintpy_dir, \"velocity.h5\")\n", - " config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" + "# === Set Expected MintPy Filenames ===\n", + "geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", + "msk_file = os.path.join(mintpy_dir, \"maskTempCoh.h5\") # alt: maskConnComp.h5\n", + "ts_file = os.path.join(mintpy_dir, \"timeseries.h5\")\n", + "vel_file = os.path.join(mintpy_dir, \"velocity.h5\")\n", + "config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" ] }, { @@ -517,7 +522,7 @@ " \"-c\", cmap_str,\n", " \"-u\", \"mm\",\n", " \"-v\", str(vmin), str(vmax),\n", - " \"--title\", velocity_filename.split('/')[-1],\n", + " \"--title\", 'Velocity after correction for SET',\n", " \"--noverbose\"\n", " ]\n", " view.main(view_opts)\n", @@ -626,6 +631,10 @@ "source": [ "# Visualize velocity\n", "if site_info.get('do_iono') != \"False\":\n", + " \n", + " if site_info.get('do_SET') != \"False\":\n", + " titlestr = 'Velocity after correcting for SET and iono'\n", + " \n", " view_opts = [\n", " velocity_filename, \"velocity\",\n", " \"-m\", msk_file,\n", @@ -637,7 +646,7 @@ " \"-c\", cmap_str,\n", " \"-u\", \"mm\",\n", " \"-v\", str(vmin), str(vmax),\n", - " \"--title\", velocity_filename.split('/')[-1],\n", + " \"--title\", titlestr,\n", " \"--noverbose\"\n", " ]\n", " view.main(view_opts)\n", @@ -745,6 +754,13 @@ "source": [ "# Visualize velocity\n", "if site_info.get('do_tropo') != \"False\":\n", + " if site_info.get('do_iono') == \"True\" and site_info.get('do_SET') == \"True\":\n", + " titlestr = 'Velocity after correcting for SET, iono, and tropo'\n", + " elif site_info.get('do_iono') == \"True\":\n", + " titlestr = 'Velocity after correcting for iono and tropo'\n", + " elif site_info.get('do_SET') == \"True\":\n", + " titlestr = 'Velocity after correcting for SET and tropo'\n", + " \n", " view_opts = [\n", " velocity_filename, \"velocity\",\n", " \"-m\", msk_file,\n", @@ -756,7 +772,7 @@ " \"-c\", cmap_str,\n", " \"-u\", \"mm\",\n", " \"-v\", str(vmin), str(vmax),\n", - " \"--title\", velocity_filename.split('/')[-1],\n", + " \"--title\", titlestr,\n", " \"--noverbose\"\n", " ]\n", " view.main(view_opts)\n", @@ -1534,6 +1550,10 @@ " 'validation_table': validation_table_method1,\n", " 'ts_functions': ts_functions,\n", "}\n", + "save_results(**save_params)\n", + "\n", + "# Save the report in the home directory as well\n", + "save_params['save_dir'] = home_dir\n", "save_results(**save_params)" ] }, @@ -1714,6 +1734,10 @@ " 'validation_table': validation_table_method2,\n", " 'ts_functions': ts_functions,\n", "}\n", + "save_results(**save_params)\n", + "\n", + "# Save the report in the home directory as well\n", + "save_params['save_dir'] = home_dir\n", "save_results(**save_params)" ] }, diff --git a/methods/transient/Transient_Requirement_Validation.ipynb b/methods/transient/Transient_Requirement_Validation.ipynb index 4775ba4..9352e97 100644 --- a/methods/transient/Transient_Requirement_Validation.ipynb +++ b/methods/transient/Transient_Requirement_Validation.ipynb @@ -195,6 +195,11 @@ "mintpy_dir = os.path.join(work_dir, \"MintPy\")\n", "weather_dir = os.path.join(site_dir)\n", "\n", + "# === Home directory for saving reports ===\n", + "home_dir = os.path.join(\"/home/jovyan/validation/\", site, requirement, rundate, f\"v{version}\")\n", + "if not os.path.exists(home_dir):\n", + " os.makedirs(home_dir)\n", + "\n", "# === Log Directory Paths ===\n", "print(f\" Work directory: {work_dir}\")\n", "print(f\" GUNW directory: {gunw_dir}\")\n", @@ -208,11 +213,11 @@ "else:\n", " os.chdir(mintpy_dir)\n", "\n", - " # === Set Expected MintPy Filenames ===\n", - " ifgs_file = os.path.join(mintpy_dir, \"inputs/ifgramStack.h5\")\n", - " geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", - " msk_file = os.path.join(work_dir, \"mask\", \"esa_world_cover_2021.msk\")\n", - " config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" + "# === Set Expected MintPy Filenames ===\n", + "ifgs_file = os.path.join(mintpy_dir, \"inputs/ifgramStack.h5\")\n", + "geom_file = os.path.join(mintpy_dir, \"inputs\", \"geometryGeo.h5\")\n", + "msk_file = os.path.join(work_dir, \"mask\", \"esa_world_cover_2021.msk\")\n", + "config_file = os.path.join(mintpy_dir, site_info.get('calval_location') + '.cfg')" ] }, { @@ -1069,7 +1074,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "If there are less than 3 GNSS stations, don't conduct comparison:" + "If there are fewer than 3 GNSS stations, don't conduct comparison:" ] }, { @@ -1080,7 +1085,7 @@ }, "outputs": [], "source": [ - "# Drop IFGs with less than three stations\n", + "# Drop IFGs with fewer than three stations\n", "drop_index = []\n", "for i in displacement.index.get_level_values(0).unique():\n", " if len(displacement.loc[i]) < 3:\n", @@ -1597,6 +1602,10 @@ " 'validation_table': validation_table_method1,\n", " 'summary': method_summary\n", "}\n", + "save_results(**save_params)\n", + "\n", + "# Save the report in the home directory as well\n", + "save_params['save_dir'] = home_dir\n", "save_results(**save_params)" ] }, @@ -1950,13 +1959,14 @@ "\n", "\n", "# Loop through interferograms\n", + "method2_validation_figs = []\n", "for ifg_ndx in displacement.index.get_level_values(0).unique():\n", " # Start and end dates as strings\n", " start_date = ifgs_date[ifg_ndx,0].strftime('%Y%m%d')\n", " end_date = ifgs_date[ifg_ndx,1].strftime('%Y%m%d')\n", "\n", " # Validation figure and assessment\n", - " display_transient_validation(dist[ifg_ndx], rel_measure[ifg_ndx],\n", + " _, validation_fig_method2 = display_transient_validation(dist[ifg_ndx], rel_measure[ifg_ndx],\n", " site, start_date, end_date,\n", " requirement=transient_threshold_rqmt,\n", " distance_rqmt=transient_distance_rqmt,\n", @@ -1964,7 +1974,9 @@ " threshold=threshold,\n", " sensor='Sentinel-1',\n", " validation_type=requirement.lower(),\n", - " validation_data='GNSS')" + " validation_data='GNSS')\n", + "\n", + " method2_validation_figs.append(validation_fig_method2)" ] }, { @@ -2064,12 +2076,12 @@ "outputs": [], "source": [ "# Stylized pandas table\n", - "s = ratio_pd.style\n", - "s.set_table_styles([ # create internal CSS classes\n", + "validation_table_method2 = ratio_pd.style\n", + "validation_table_method2.set_table_styles([ # create internal CSS classes\n", " {'selector': '.true', 'props': 'background-color: #e6ffe6;'},\n", " {'selector': '.false', 'props': 'background-color: #ffe6e6;'},\n", "], overwrite=False)\n", - "s.set_td_classes(success_or_fail_pd)" + "validation_table_method2.set_td_classes(success_or_fail_pd)" ] }, { @@ -2117,7 +2129,25 @@ "source": [ "# Save Method 2 results to file\n", "save_fldr = f\"{dt.now().strftime('%Y%m%dT%H%M%S')}-Transient-Method2\"\n", - "save_dir = os.path.join(mintpy_dir, save_fldr)" + "save_dir = os.path.join(mintpy_dir, save_fldr)\n", + "\n", + "save_params = {\n", + " 'save_dir': save_dir,\n", + " 'run_date': run_date,\n", + " 'requirement': requirement,\n", + " 'site': site,\n", + " 'method': '2',\n", + " 'sitedata': sitedata['sites'][site],\n", + " 'gnss_insar_figs': gnss_insar_figs,\n", + " 'validation_figs': method2_validation_figs,\n", + " 'validation_table': validation_table_method2,\n", + " 'summary': method_summary\n", + "}\n", + "save_results(**save_params)\n", + "\n", + "# Save the report in the home directory as well\n", + "save_params['save_dir'] = home_dir\n", + "save_results(**save_params)" ] }, {