{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Dubois surface inversion evaluation on UAVSAR C3 data\n",
    "\n",
    "In this notebook we run the Dubois surface inversion on the UAVSAR C3 product using the provided incidence-angle stream. The radar frequency is derived from the NetCDF metadata."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "import os\n",
    "import shutil\n",
    "from pathlib import Path\n",
    "\n",
    "import numpy as np\n",
    "import xarray as xr\n",
    "from dask.diagnostics import ProgressBar\n",
    "\n",
    "from polsarpro.dev.devtools import parse_psp_parameter_string\n",
    "from polsarpro.dev.io import read_psp_bin\n",
    "from polsarpro.dev.metrics import summarize_metrics, visualize_errors\n",
    "from polsarpro.io import open_netcdf_beam\n",
    "from polsarpro.physical_inversion import dubois_surface_inversion\n",
    "\n",
    "# change to your local C-PolSARpro install dir\n",
    "c_psp_dir = \"/home/c_psp/Soft/bin/\"\n",
    "os.environ[\"PATH\"] += os.pathsep + f\"{c_psp_dir}/data_process_sngl/\"\n",
    "os.environ[\"PATH\"] += os.pathsep + f\"{c_psp_dir}/data_convert/\"\n",
    "\n",
    "product_id = \"winnip_09002_12060_004_120714_L090_CX_02\"\n",
    "\n",
    "input_uavsar_nc = Path(f\"/data/psp/test_files/{product_id}_ML5X5.nc\")\n",
    "input_test_dir = Path(\"/data/psp/winnip_cpsp/C3\")\n",
    "output_test_dir = Path(\"/data/psp/res/dubois_c3/\")\n",
    "output_test_dir.mkdir(parents=True, exist_ok=True)\n",
    "\n",
    "incidence_angle_file = Path(f\"/data/psp/test_files/{product_id}.inc\")\n",
    "incidence_angle_c_file = Path(\"/data/psp/winnip_cpsp/incidence_angle_ml5x5_rad.bin\")\n",
    "file_out = Path(\"/data/psp/res/test_dubois_surface_inversion_uavsar.nc\")\n",
    "\n",
    "with xr.open_dataset(input_uavsar_nc) as raw_ds:\n",
    "    center_wavelength_cm = raw_ds[\"metadata\"].attrs[\"Annotation:CenterWavelength\"]\n",
    "\n",
    "# Dubois expects GHz; UAVSAR metadata stores the center wavelength in cm.\n",
    "freq_ghz = 29.9792458 / float(center_wavelength_cm)\n",
    "\n",
    "# thresh1_db = -5.0\n",
    "thresh1_db = 0\n",
    "thresh2_db = 0\n",
    "calibration_coeff = 1.0\n",
    "calibration_flag = 1\n",
    "angle_unit = 1  # C-PolSARpro: 0 = degrees, 1 = radians\n",
    "\n",
    "print(f\"Derived radar frequency: {freq_ghz:.6f} GHz\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load UAVSAR data and incidence angle raster"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "C3 = open_netcdf_beam(input_uavsar_nc)\n",
    "row_dim, col_dim = C3.dims\n",
    "\n",
    "# use lines from .ann file (infer from auxiliary file)\n",
    "# hgt.set_rows                         (pixels)        = 3767                   ; HGT Lines\n",
    "# hgt.set_cols                         (pixels)        = 11636                  ; HGT Samples\n",
    "nlines = 3767\n",
    "ncols = 11636\n",
    "\n",
    "# The incidence-angle file is a little-endian float32 stream in radians.\n",
    "# Read only the raster-sized prefix and reshape it to the UAVSAR grid.\n",
    "incidence_angle_values = np.fromfile(\n",
    "    incidence_angle_file,\n",
    "    dtype=\"<f4\",\n",
    "    count=nlines * ncols,\n",
    ")\n",
    "\n",
    "# reduce to the same dimensions as multilooked 5x5 image\n",
    "incidence_angle_values[incidence_angle_values == -10000] = np.nan\n",
    "incidence_angle = xr.DataArray(\n",
    "    incidence_angle_values.reshape(nlines, ncols),\n",
    "    dims=(row_dim, col_dim),\n",
    "    name=\"incidence_angle\",\n",
    ").coarsen(y=5, x=5, boundary=\"trim\").mean()\n",
    "\n",
    "# Write the multilooked incidence angle stream for the C run.\n",
    "if incidence_angle_c_file.exists():\n",
    "    incidence_angle_c_file.unlink()\n",
    "incidence_angle.astype(np.float32).values.tofile(incidence_angle_c_file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run the C version on the C3 input"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fnr, fnc = C3.sizes[row_dim], C3.sizes[col_dim]\n",
    "\n",
    "input_str = f\"\"\"id: {input_test_dir}\n",
    "od: {output_test_dir}\n",
    "iodf: C3\n",
    "ang: {incidence_angle_c_file}\n",
    "ofr: 0\n",
    "ofc: 0\n",
    "fnr: {fnr}\n",
    "fnc: {fnc}\n",
    "fr: {freq_ghz}\n",
    "un: {angle_unit}\n",
    "caf: {calibration_flag}\n",
    "cac: {calibration_coeff}\n",
    "th1: {thresh1_db}\n",
    "th2: {thresh2_db}\n",
    "errf: /tmp\"\"\"\n",
    "\n",
    "result = parse_psp_parameter_string(input_str)\n",
    "os.system(f\"surface_inversion_dubois.exe {result}\")\n",
    "\n",
    "# CPSP does not create another config file in output dir\n",
    "shutil.copy(input_test_dir / \"config.txt\", output_test_dir)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Apply the surface inversion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if file_out.exists():\n",
    "    file_out.unlink()\n",
    "\n",
    "with ProgressBar():\n",
    "    out_py = dubois_surface_inversion(\n",
    "        C3,\n",
    "        incidence_angle=incidence_angle,\n",
    "        freq_ghz=freq_ghz,\n",
    "        thresh1=thresh1_db,\n",
    "        thresh2=thresh2_db,\n",
    "        calibration_coeff=calibration_coeff,\n",
    "    ).to_netcdf(file_out)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspect results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "out_py = xr.open_dataset(file_out)\n",
    "out_py"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0004916e",
   "metadata": {},
   "source": [
    "## Numerical evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af669f5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# open python output (comment if using compute)\n",
    "out_py = xr.open_dataset(file_out)\n",
    "# open C-PolSARPro outputs\n",
    "out_c = {}\n",
    "out_names = (\n",
    "    \"dubois_er\",\n",
    "    \"dubois_mv\",\n",
    "    \"dubois_ks\",\n",
    "    \"dubois_mask_out\",\n",
    "    \"dubois_mask_in\",\n",
    "    \"dubois_mask_valid_in_out\",\n",
    ")\n",
    "for name in out_names:\n",
    "    file_name = output_test_dir / f\"{name}.bin\"\n",
    "    out_c[name] = read_psp_bin(file_name).T\n",
    "\n",
    "out_py = out_py.transpose(\"x\", \"y\")\n",
    "\n",
    "df = summarize_metrics(out_py, out_c, short_titles=False, verbose=False)\n",
    "df\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4c73149",
   "metadata": {},
   "outputs": [],
   "source": [
    "visualize_errors(out_py=out_py, out_c=out_c, sub_az=1, sub_rg=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from polsarpro.util import pauli_rgb\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "rgb = pauli_rgb(C3).transpose(\"x\", \"y\", \"band\")\n",
    "plt.figure(figsize=(15,10))\n",
    "plt.subplot(1,2,1)\n",
    "plt.imshow(rgb, interpolation=\"none\")\n",
    "plt.subplot(1,2,2)\n",
    "plt.imshow(out_py.dubois_mask_valid_in_out, interpolation=\"none\")\n",
    "plt.tight_layout()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
