coveralls: ## Pull Request Test Coverage Report for [Build 1278](https://coveralls.io/builds/27259303)

* **3** of **3**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.02%**) to **90.786%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/27259303/badge)](https://coveralls.io/builds/27259303) |
| :-- | --: |
| Change from base [Build 1260](https://coveralls.io/builds/27178478): |  0.02% |
| Covered Lines: | 3094 |
| Relevant Lines: | 3408 |

---
##### 💛  - [Coveralls](https://coveralls.io)

aulemahal: Added the atmos indicator. However, I add to hack the `Indicator.missing()` method. Right now it only checks for missing days in the data. But that doesn't make sense for not-resampling indicators, like this one. So I return "no missing values" if "freq" is not an argument. This could be modified if we add non-resampling missing value checks later on.
huard: Another option would be to subclass the missing method with a function that returns False. 
That being said, I think we should add a test to check that when a tasmin is missing but not a tasmax, the result is a NaN. 
aulemahal: 1) You mean like:
```python
class TasminTasmaxNoResample(TasminTasmax):
    @staticmethod
    def missing *args, **kwds):
        return False
```
? Seems a very specific solver for a more general problem, no?

Also, xarray already does the check for an addition:
```python
a = xr.DataArray([1, np.nan, 1], dims=('x',), coords={'x': [0, 1, 2]})
b = xr.DataArray([1, 2, 1, 1], dims=('x',), coords={'x': [0, 1, 2, 3]})
a + b
```
gives: `xarray.DataArray (x: 3)> array([ 2., nan,  2.])  Coordinates:   * x        (x) int64 0 1 2`
So, missing values are omitted and NaNs are propagated.
huard: Yes exactly. To me this communicates better what is going on to readers. Happy to be convinced otherwise. @tlvu Any opinion on this ? 

Perfect ! Just want to make sure that as these inputs go through all the Indicator methods, the same is true. They should in theory, but in practice theory is different from practice. 
tlvu: > Another option would be to subclass the missing method with a function that returns False.
> That being said, I think we should add a test to check that when a tasmin is missing but not a tasmax, the result is a NaN.
> Yes exactly. To me this communicates better what is going on to readers. Happy to be convinced otherwise. @tlvu Any opinion on this ?

Having a static method that always return False is weird to me but if that's how the API/library behave/expect then fine by me.

tlogan2000: > To be used as a WPS service, we have to expose an indicator in atmos. I think that was what Travis was looking for. Can be another PR.

Yes. The problem for many of our datasets is that we often estimate 'tas' from 'tasmin' and 'tasmax'.  Using ```xclim``` / ```xarray``` we can do this on the fly and then calculate any index requiring tas as input .  However calling the same calculation via the finch wps server requires the resource netcdf to have the input variable already.

We might want to think about creating/writing to disk the a set of 'tas' .nc files for our own datasets on the thredds server.  However a vision of remotely connecting to other nodes will likely result in a similar issue so this will still be of use I think
aulemahal: I see!
Here I come with another proposition. @huard , it goes to your first comment and as the __add__ of xarray already does this, it's kinda useless for this specific case. But, as long as atmos requires input to be daily, I think giving a default `freq='D'` to the missing check makes sense. And as it flags values missing from the input dataset, still does what we expect it to.
So I am pushing away the issue to the future, when we want to make atmos more general :).
diff --git a/HISTORY.rst b/HISTORY.rst
index 4994460e..3ff1c54d 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -8,7 +8,7 @@ History
 * Added a `tolerance` argument to `subset_gridpoint` raising an error if distance to closest point is larger than tolerance.
 * Created land module for standardized access to streamflow indices.
 * Enhancement to utils.Indicator to have more dynamic attributes using callables.
-* Added indice `heat_wave_total_length`.
+* Added indices `heat_wave_total_length` and `tas` / `tg`.
 * Fixed a bug with typed call signatures that caused downstream failures on library import.
 
 0.11.x-beta (2019-10-17)
diff --git a/xclim/atmos/_temperature.py b/xclim/atmos/_temperature.py
index 9f645479..642e5094 100644
--- a/xclim/atmos/_temperature.py
+++ b/xclim/atmos/_temperature.py
@@ -13,6 +13,7 @@ __all__ = [
     "heat_wave_frequency",
     "heat_wave_max_length",
     "heat_wave_index",
+    "tg",
     "tg_mean",
     "tg10p",
     "tg90p",
@@ -186,6 +187,16 @@ heat_wave_index = Tasmax(
     compute=indices.heat_wave_index,
 )
 
+tg = TasminTasmax(
+    identifier="tg",
+    units="K",
+    standard_name="air_temperature",
+    long_name="Daily mean temperature",
+    description="Estimated mean temperature from maximum and minimum temperatures",
+    cell_methods="",
+    compute=indices.tas,
+)
+
 tg_mean = Tas(
     identifier="tg_mean",
     units="K",
diff --git a/xclim/indices/_multivariate.py b/xclim/indices/_multivariate.py
index a2671e7f..78d7e145 100644
--- a/xclim/indices/_multivariate.py
+++ b/xclim/indices/_multivariate.py
@@ -33,6 +33,7 @@ __all__ = [
     "liquid_precip_ratio",
     "precip_accumulation",
     "rain_on_frozen_ground_days",
+    "tas",
     "tg90p",
     "tg10p",
     "tn90p",
@@ -801,6 +802,27 @@ def fraction_over_precip_thresh(
     return over / total
 
 
+@declare_units("K", tasmin="[temperature]", tasmax="[temperature]")
+def tas(tasmin: xarray.DataArray, tasmax: xarray.DataArray) -> xarray.DataArray:
+    """Average temperature from minimum and maximum temperatures.
+
+    We assume a symmetrical distribution for the temperature and retrieve the average value as Tg = (Tx + Tn) / 2
+
+    Parameters
+    ----------
+    tasmin : xarray.DataArray
+        Minimum (daily) temperature [℃] or [K]
+    tasmax : xarray.DataArray
+        Maximum (daily) temperature [℃] or [K]
+
+    Returns
+    -------
+    xarray.DataArray
+        Mean (daily) temperature [°C]
+    """
+    return (tasmax + tasmin) / 2
+
+
 @declare_units("days", tas="[temperature]", t90="[temperature]")
 def tg90p(
     tas: xarray.DataArray, t90: xarray.DataArray, freq: str = "YS"
diff --git a/xclim/utils.py b/xclim/utils.py
index 4f9a7f35..17e7f445 100644
--- a/xclim/utils.py
+++ b/xclim/utils.py
@@ -958,7 +958,8 @@ class Indicator:
         """Return whether an output is considered missing or not."""
         from functools import reduce
 
-        freq = kwds.get("freq")
+        freq = kwds.get("freq", "D")
+
         miss = (checks.missing_any(da, freq) for da in args)
         return reduce(np.logical_or, miss)
 

Indicator for average temperature based on tasmin and tasmax
### Description
<!--Describe what you were trying to get done.
Tell us what happened, what went wrong, and what you expected to happen.-->
Create a new indicator computing the daily average temperature from the daily min and max temperature. 

diff --git a/tests/test_indices.py b/tests/test_indices.py
index 5573b9ce..7df3a3f0 100644
--- a/tests/test_indices.py
+++ b/tests/test_indices.py
@@ -748,6 +748,16 @@ class TestTGXN90p:
         assert out[5] == 25
 
 
+class TestTas:
+    def test_tas(self, tasmin_series, tasmax_series, tas_series):
+        tas = tas_series(np.ones(10))
+        tasmin = tasmin_series(np.zeros(10))
+        tasmax = tasmax_series(np.ones(10) * 2)
+
+        tas_xc = xci.tas(tasmin, tasmax)
+        xr.testing.assert_equal(tas, tas_xc)
+
+
 class TestTxMin:
     @staticmethod
     def time_series(values):
diff --git a/tests/test_temperature.py b/tests/test_temperature.py
index 4cfce560..776a6c77 100644
--- a/tests/test_temperature.py
+++ b/tests/test_temperature.py
@@ -175,13 +175,16 @@ class TestETR:
 
 
 class TestTmean:
-    nc_file = os.path.join(
-        TESTS_DATA, "NRCANdaily", "nrcan_canada_daily_tasmax_1990.nc"
+    nc_files = (
+        os.path.join(TESTS_DATA, "NRCANdaily", "nrcan_canada_daily_tasmax_1990.nc"),
+        os.path.join(TESTS_DATA, "NRCANdaily", "nrcan_canada_daily_tasmin_1990.nc"),
     )
 
     def test_Tmean_3d_data(self):
-        tas = xr.open_dataset(self.nc_file).tasmax
-        tas_C = xr.open_dataset(self.nc_file).tasmax
+        ds_tmax = xr.open_dataset(self.nc_files[0])
+        ds_tmin = xr.open_dataset(self.nc_files[1])
+        tas = atmos.tg(ds_tmin.tasmin, ds_tmax.tasmax)
+        tas_C = atmos.tg(ds_tmin.tasmin, ds_tmax.tasmax)
         tas_C.values -= K2C
         tas_C.attrs["units"] = "C"
         # put a nan somewhere

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov flake8
apt-get update apt-get install -y gcc
3.6
requirements_dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
bleach==4.1.0
bokeh==2.3.3
boltons==23.1.1
Bottleneck==1.2.1
bump2version==1.0.1
bumpversion==0.6.0
certifi==2021.5.30
cffi==1.15.1
cfgv==3.3.1
cftime==1.0.3.4
charset-normalizer==2.0.12
click==8.0.4
cloudpickle==2.2.1
colorama==0.4.5
contextvars==2.4
coverage==6.2
cryptography==40.0.2
dask==2021.3.0
distlib==0.3.9
distributed==2021.3.0
docutils==0.18.1
filelock==3.4.1
flake8==5.0.4
fsspec==2022.1.0
HeapDict==1.0.1
identify==2.4.4
idna==3.10
immutables==0.19
importlib-metadata==4.2.0
importlib-resources==5.2.3
iniconfig==1.1.1
jeepney==0.7.1
Jinja2==3.0.3
joblib==1.1.1
keyring==23.4.1
locket==1.0.0
MarkupSafe==2.0.1
mccabe==0.7.0
msgpack==1.0.5
netCDF4==1.6.1
nodeenv==1.6.0
numpy==1.19.5
packaging==21.3
pandas==1.1.5
partd==1.2.0
Pillow==8.4.0
Pint==0.17
pkginfo==1.10.0
platformdirs==2.4.0
pluggy==1.0.0
pre-commit==2.17.0
psutil==7.0.0
py==1.11.0
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.14.0
pyparsing==3.1.4
pyproj==2.4.1
pytest==7.0.1
pytest-cov==4.0.0
pytest-runner==5.3.2
python-dateutil==2.9.0.post0
pytz==2025.2
PyYAML==6.0.1
readme-renderer==34.0
requests==2.27.1
requests-toolbelt==1.0.0
rfc3986==1.5.0
scikit-learn==0.24.2
scipy==1.5.4
SecretStorage==3.3.3
six==1.17.0
sortedcontainers==2.4.0
tblib==1.7.0
threadpoolctl==3.1.0
toml==0.10.2
tomli==1.2.3
toolz==0.12.0
tornado==6.1
tox==3.28.0
tqdm==4.64.1
twine==3.8.0
typing_extensions==4.1.1
urllib3==1.26.20
virtualenv==20.16.2
watchdog==2.3.1
webencodings==0.5.1
xarray==0.13.0
-e git+https://github.com/Ouranosinc/xclim.git@5860a492a4b27bdc0b89ad912b955ac963b854cc#egg=xclim
zict==2.1.0
zipp==3.6.0

name: xclim
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - bleach==4.1.0
      - bokeh==2.3.3
      - boltons==23.1.1
      - bottleneck==1.2.1
      - bump2version==1.0.1
      - bumpversion==0.6.0
      - cffi==1.15.1
      - cfgv==3.3.1
      - cftime==1.0.3.4
      - charset-normalizer==2.0.12
      - click==8.0.4
      - cloudpickle==2.2.1
      - colorama==0.4.5
      - contextvars==2.4
      - coverage==6.2
      - cryptography==40.0.2
      - dask==2021.3.0
      - distlib==0.3.9
      - distributed==2021.3.0
      - docutils==0.18.1
      - filelock==3.4.1
      - flake8==5.0.4
      - fsspec==2022.1.0
      - heapdict==1.0.1
      - identify==2.4.4
      - idna==3.10
      - immutables==0.19
      - importlib-metadata==4.2.0
      - importlib-resources==5.2.3
      - iniconfig==1.1.1
      - jeepney==0.7.1
      - jinja2==3.0.3
      - joblib==1.1.1
      - keyring==23.4.1
      - locket==1.0.0
      - markupsafe==2.0.1
      - mccabe==0.7.0
      - msgpack==1.0.5
      - netcdf4==1.6.1
      - nodeenv==1.6.0
      - numpy==1.19.5
      - packaging==21.3
      - pandas==1.1.5
      - partd==1.2.0
      - pillow==8.4.0
      - pint==0.17
      - pkginfo==1.10.0
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - pre-commit==2.17.0
      - psutil==7.0.0
      - py==1.11.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pyproj==2.4.1
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-runner==5.3.2
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.1
      - readme-renderer==34.0
      - requests==2.27.1
      - requests-toolbelt==1.0.0
      - rfc3986==1.5.0
      - scikit-learn==0.24.2
      - scipy==1.5.4
      - secretstorage==3.3.3
      - six==1.17.0
      - sortedcontainers==2.4.0
      - tblib==1.7.0
      - threadpoolctl==3.1.0
      - toml==0.10.2
      - tomli==1.2.3
      - toolz==0.12.0
      - tornado==6.1
      - tox==3.28.0
      - tqdm==4.64.1
      - twine==3.8.0
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - virtualenv==20.16.2
      - watchdog==2.3.1
      - webencodings==0.5.1
      - xarray==0.13.0
      - zict==2.1.0
      - zipp==3.6.0
prefix: /opt/conda/envs/xclim

tests/test_indices.py::TestTas::test_tas
tests/test_indices.py::TestTGXN10p::test_doy_interpolation tests/test_temperature.py::TestTmean::test_Tmean_3d_data tests/test_temperature.py::TestTx::test_TX_3d_data tests/test_temperature.py::TestTn::test_TN_3d_data tests/test_temperature.py::TestT90p::test_tg90p_simple tests/test_temperature.py::TestT90p::test_tn90p_simple tests/test_temperature.py::TestT90p::test_tx90p_simple tests/test_temperature.py::TestT10p::test_tg10p_simple tests/test_temperature.py::TestT10p::test_tn10p_simple tests/test_temperature.py::TestT10p::test_tx10p_simple
tests/test_indices.py::TestBaseFlowIndex::test_simple tests/test_indices.py::TestMaxNDayPrecipitationAmount::test_single_max tests/test_indices.py::TestMaxNDayPrecipitationAmount::test_sumlength_max tests/test_indices.py::TestMaxNDayPrecipitationAmount::test_multi_max tests/test_indices.py::TestMax1DayPrecipitationAmount::test_single_max tests/test_indices.py::TestMax1DayPrecipitationAmount::test_multi_max tests/test_indices.py::TestMax1DayPrecipitationAmount::test_uniform_max tests/test_indices.py::TestColdSpellDurationIndex::test_simple tests/test_indices.py::TestColdSpellDays::test_simple tests/test_indices.py::TestConsecutiveFrostDays::test_one_freeze_day tests/test_indices.py::TestConsecutiveFrostDays::test_no_freeze tests/test_indices.py::TestConsecutiveFrostDays::test_all_year_freeze tests/test_indices.py::TestCoolingDegreeDays::test_no_cdd tests/test_indices.py::TestCoolingDegreeDays::test_cdd tests/test_indices.py::TestDailyFreezeThawCycles::test_simple tests/test_indices.py::TestDailyFreezeThawCycles::test_zeroed_thresholds tests/test_indices.py::TestDailyPrIntensity::test_simple tests/test_indices.py::TestDailyPrIntensity::test_mm tests/test_indices.py::TestDaysOverPrecipThresh::test_simple tests/test_indices.py::TestDaysOverPrecipThresh::test_quantile tests/test_indices.py::TestDaysOverPrecipThresh::test_nd tests/test_indices.py::TestFreshetStart::test_simple tests/test_indices.py::TestFreshetStart::test_no_start tests/test_indices.py::TestGrowingDegreeDays::test_simple tests/test_indices.py::TestGrowingSeasonLength::test_simple tests/test_indices.py::TestHeatingDegreeDays::test_simple tests/test_indices.py::TestHeatWaveIndex::test_simple tests/test_indices.py::TestHeatWaveFrequency::test_1d tests/test_indices.py::TestHeatWaveMaxLength::test_1d tests/test_indices.py::TestHeatWaveTotalLength::test_1d tests/test_indices.py::TestTnDaysBelow::test_simple tests/test_indices.py::TestTxDaysAbove::test_simple tests/test_indices.py::TestLiquidPrecipitationRatio::test_simple tests/test_indices.py::TestMaximumConsecutiveDryDays::test_simple tests/test_indices.py::TestMaximumConsecutiveDryDays::test_run_start_at_0 tests/test_indices.py::TestMaximumConsecutiveTxDays::test_simple tests/test_indices.py::TestPrecipAccumulation::test_simple tests/test_indices.py::TestPrecipAccumulation::test_yearly tests/test_indices.py::TestPrecipAccumulation::test_mixed_phases tests/test_indices.py::TestRainOnFrozenGround::test_simple tests/test_indices.py::TestRainOnFrozenGround::test_small_rain tests/test_indices.py::TestRainOnFrozenGround::test_consecutive_rain tests/test_indices.py::TestTGXN10p::test_tg10p_simple tests/test_indices.py::TestTGXN10p::test_tx10p_simple tests/test_indices.py::TestTGXN10p::test_tn10p_simple tests/test_indices.py::TestTGXN90p::test_tg90p_simple tests/test_indices.py::TestTGXN90p::test_tx90p_simple tests/test_indices.py::TestTGXN90p::test_tn90p_simple tests/test_indices.py::TestTxMean::test_attrs tests/test_indices.py::TestTxMax::test_simple tests/test_indices.py::TestTgMaxTgMinIndices::test_static_daily_temperature_range tests/test_indices.py::TestTgMaxTgMinIndices::test_static_variable_daily_temperature_range tests/test_indices.py::TestTgMaxTgMinIndices::test_static_extreme_temperature_range tests/test_indices.py::TestTgMaxTgMinIndices::test_uniform_freeze_thaw_cycles tests/test_indices.py::TestTgMaxTgMinIndices::test_static_freeze_thaw_cycles tests/test_indices.py::TestWarmDayFrequency::test_1d tests/test_indices.py::TestWarmNightFrequency::test_1d tests/test_indices.py::TestTxTnDaysAbove::test_1d tests/test_indices.py::TestWarmSpellDurationIndex::test_simple tests/test_indices.py::TestWinterRainRatio::test_simple tests/test_temperature.py::TestCSDI::test_simple tests/test_temperature.py::TestCSDI::test_convert_units tests/test_temperature.py::TestCSDI::test_nan_presence tests/test_temperature.py::TestDTR::test_DTR_3d_data_with_nans tests/test_temperature.py::TestDTRVar::test_dtr_var_3d_data_with_nans tests/test_temperature.py::TestETR::test_dtr_var_3d_data_with_nans tests/test_temperature.py::TestConsecutiveFrostDays::test_one_freeze_day tests/test_temperature.py::TestConsecutiveFrostDays::test_three_freeze_day tests/test_temperature.py::TestConsecutiveFrostDays::test_two_equal_freeze_day tests/test_temperature.py::TestConsecutiveFrostDays::test_two_events_freeze_day tests/test_temperature.py::TestConsecutiveFrostDays::test_convert_units_freeze_day tests/test_temperature.py::TestConsecutiveFrostDays::test_one_nan_day tests/test_temperature.py::TestColdSpellDays::test_simple tests/test_temperature.py::TestColdSpellDays::test_convert_units tests/test_temperature.py::TestColdSpellDays::test_nan_presence tests/test_temperature.py::TestFrostDays::test_3d_data_with_nans tests/test_temperature.py::TestIceDays::test_3d_data_with_nans tests/test_temperature.py::TestCoolingDegreeDays::test_3d_data_with_nans tests/test_temperature.py::TestCoolingDegreeDays::test_convert_units tests/test_temperature.py::TestHeatingDegreeDays::test_3d_data_with_nans tests/test_temperature.py::TestHeatingDegreeDays::test_convert_units tests/test_temperature.py::TestGrowingDegreeDays::test_3d_data_with_nans tests/test_temperature.py::TestHeatWaveFrequency::test_1d tests/test_temperature.py::TestHeatWaveMaxLength::test_1d tests/test_temperature.py::TestHeatWaveIndex::test_simple tests/test_temperature.py::TestHeatWaveIndex::test_convert_units tests/test_temperature.py::TestHeatWaveIndex::test_nan_presence tests/test_temperature.py::TestDailyFreezeThaw::test_3d_data_with_nans tests/test_temperature.py::TestDailyFreezeThaw::test_convert_units tests/test_temperature.py::TestGrowingSeasonLength::test_single_year tests/test_temperature.py::TestGrowingSeasonLength::test_convert_units tests/test_temperature.py::TestGrowingSeasonLength::test_nan_presence tests/test_temperature.py::TestGrowingSeasonLength::test_multiyear tests/test_temperature.py::TestTnDaysBelow::test_3d_data_with_nans tests/test_temperature.py::TestTxDaysAbove::test_3d_data_with_nans tests/test_temperature.py::TestTropicalNights::test_3d_data_with_nans tests/test_temperature.py::TestTxTnDaysAbove::test_3d_data_with_nans tests/test_temperature.py::test_freshet_start
HISTORY.rst xclim/indices/_multivariate.py xclim/atmos/_temperature.py xclim/utils.py
HISTORY.rst xclim/indices/_multivariate.py xclim/atmos/_temperature.py xclim/utils.py