Repository: ouranosinc/xclim
Issue: BUG: indexer doesn't work with DataArray where "time" dimension is missing (percentiles DataArray)

### Setup Information

- Xclim version: '0.36.3-beta'
- Python version: n/a
- Operating System: n/a

### Description

Percentile based indicators such as `atmos.days_over_precip_thresh` should be able to benefit from indexer as they are not computed on spells.

The issue is in `_preprocess_and_checks` method of `ResamplingIndicatorWithIndexing` class.
`select_time` is called for each DataArray, however DataArrays where "time" dimension is missing should be excluded from this loop.

DataArrays without "time" are usually the ones which either where computed with percentile_doy (case of tx90p) or with np.percentile or similar (case of days_over_precip_thresh/R75p).

### Steps To Reproduce

```
def test_days_over_precip_thresh_season__with_indexer():
    pr = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc").pr
    per = pr.quantile(0.8, "time", keep_attrs=True)
   
    out = atmos.days_over_precip_thresh(pr, per, freq="AS-DEC", date_bounds=("01-10", "12-31") )

# throws `AttributeError: 'DataArray' object has no attribute 'time'`
# from xclim/core/calendar.py", line 1287, in select_time `mask = da.time.dt.month.isin(month)`
```

### Additional context

I would also like to enable indexer in T(G|N|X)(90|10)p.

### Contribution

- [X] I would be willing/able to open a Pull Request to address this bug.

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

Changed files:
xclim/indicators/atmos/_temperature.py, xclim/testing/tests/test_temperature.py, xclim/testing/tests/test_precip.py, xclim/core/indicator.py

diff --git a/xclim/core/indicator.py b/xclim/core/indicator.py
index 1677fcc1..7d7803a6 100644
--- a/xclim/core/indicator.py
+++ b/xclim/core/indicator.py
@@ -1390,13 +1390,14 @@ class ResamplingIndicatorWithIndexing(ResamplingIndicator):
             )
         ]
 
-    def _preprocess_and_checks(self, das, params):
+    def _preprocess_and_checks(self, das: dict[str, DataArray], params: dict[str, Any]):
         """Perform parent's checks and also check if freq is allowed."""
         das, params = super()._preprocess_and_checks(das, params)
 
         indxr = params.get("indexer")
         if indxr:
-            das = {k: select_time(da, **indxr) for k, da in das.items()}
+            for k, da in filter(lambda kda: "time" in kda[1].coords, das.items()):
+                das.update({k: select_time(da, **indxr)})
         return das, params
 
 
diff --git a/xclim/indicators/atmos/_temperature.py b/xclim/indicators/atmos/_temperature.py
index e950e4be..75be9972 100644
--- a/xclim/indicators/atmos/_temperature.py
+++ b/xclim/indicators/atmos/_temperature.py
@@ -748,7 +748,7 @@ tropical_nights = TempWithIndexing(
     parameters={"thresh": {"default": "20.0 degC"}},
 )
 
-tg90p = Temp(
+tg90p = TempWithIndexing(
     identifier="tg90p",
     units="days",
     standard_name="days_with_air_temperature_above_threshold",
@@ -760,7 +760,7 @@ tg90p = Temp(
     compute=indices.tg90p,
 )
 
-tg10p = Temp(
+tg10p = TempWithIndexing(
     identifier="tg10p",
     units="days",
     standard_name="days_with_air_temperature_below_threshold",
@@ -772,7 +772,7 @@ tg10p = Temp(
     compute=indices.tg10p,
 )
 
-tx90p = Temp(
+tx90p = TempWithIndexing(
     identifier="tx90p",
     units="days",
     standard_name="days_with_air_temperature_above_threshold",
@@ -784,7 +784,7 @@ tx90p = Temp(
     compute=indices.tx90p,
 )
 
-tx10p = Temp(
+tx10p = TempWithIndexing(
     identifier="tx10p",
     units="days",
     standard_name="days_with_air_temperature_below_threshold",
@@ -796,7 +796,7 @@ tx10p = Temp(
     compute=indices.tx10p,
 )
 
-tn90p = Temp(
+tn90p = TempWithIndexing(
     identifier="tn90p",
     units="days",
     standard_name="days_with_air_temperature_above_threshold",
@@ -808,7 +808,7 @@ tn90p = Temp(
     compute=indices.tn90p,
 )
 
-tn10p = Temp(
+tn10p = TempWithIndexing(
     identifier="tn10p",
     units="days",
     standard_name="days_with_air_temperature_below_threshold",
diff --git a/xclim/testing/tests/test_precip.py b/xclim/testing/tests/test_precip.py
index d6bc4471..2f828f75 100644
--- a/xclim/testing/tests/test_precip.py
+++ b/xclim/testing/tests/test_precip.py
@@ -419,6 +419,18 @@ def test_days_over_precip_thresh():
     )
 
 
+def test_days_over_precip_thresh__seasonal_indexer():
+    # GIVEN
+    pr = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc").pr
+    per = pr.quantile(0.8, "time", keep_attrs=True)
+    # WHEN
+    out = atmos.days_over_precip_thresh(
+        pr, per, freq="AS", date_bounds=("01-10", "12-31")
+    )
+    # THEN
+    np.testing.assert_almost_equal(out[0], np.array([82.0, 66.0, 66.0, 74.0]))
+
+
 def test_fraction_over_precip_doy_thresh():
     pr = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc").pr
     per = percentile_doy(pr, window=5, per=80)
diff --git a/xclim/testing/tests/test_temperature.py b/xclim/testing/tests/test_temperature.py
index 66abc593..ba684325 100644
--- a/xclim/testing/tests/test_temperature.py
+++ b/xclim/testing/tests/test_temperature.py
@@ -1098,6 +1098,18 @@ class TestT90p:
         assert np.isnan(out[1])
         assert out[5] == 25
 
+    def test_tx90p__seasonal_indexer(self, tasmax_series):
+        # GIVEN
+        arr = np.asarray(np.arange(366), "float")
+        tas = tasmax_series(arr, start="1/1/2000")
+        t90 = percentile_doy(tas, window=1, per=90).sel(percentiles=90)
+        # create cold spell in june
+        tas[175:180] = 1
+        # WHEN
+        out = atmos.tx90p(tas, t90, freq="AS", season="JJA")
+        # THEN
+        assert out[0] == 87  # non regression test
+
 
 class TestT10p:
     def test_tg10p_simple(self, tas_series):