From 9633fbe31791b5ecc0d0ce0ae5c0e2b8b1ad9f5c Mon Sep 17 00:00:00 2001 From: Diego Cammarano Date: Tue, 9 Jul 2024 13:44:58 +0200 Subject: [PATCH] Update esacci-soilmoisture(v08.1) downloader and CMORizer (Python version) (#3676) Co-authored-by: Manuel Schlund <32543114+schlunma@users.noreply.github.com> --- doc/sphinx/source/input.rst | 2 +- .../data/cmor_config/ESACCI-SOILMOISTURE.yml | 21 +++ esmvaltool/cmorizers/data/datasets.yml | 6 +- .../datasets/esacci_soilmoisture.py | 8 +- .../datasets/esacci_soilmoisture.ncl | 174 ------------------ .../datasets/esacci_soilmoisture.py | 149 +++++++++++++++ esmvaltool/cmorizers/data/utilities.py | 17 +- .../recipes/examples/recipe_check_obs.yml | 18 +- .../references/esacci-soilmoisture.bibtex | 124 +++++++++++-- 9 files changed, 312 insertions(+), 207 deletions(-) create mode 100644 esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml delete mode 100644 esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl create mode 100644 esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py diff --git a/doc/sphinx/source/input.rst b/doc/sphinx/source/input.rst index 20a417cfc6..798b2ceb27 100644 --- a/doc/sphinx/source/input.rst +++ b/doc/sphinx/source/input.rst @@ -308,7 +308,7 @@ A list of the datasets for which a CMORizers is available is provided in the fol +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | ESACCI-SEA-SURFACE-SALINITY | sos (Omon) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ -| ESACCI-SOILMOISTURE | dos, dosStderr, sm, smStderr (Lmon) | 2 | NCL | +| ESACCI-SOILMOISTURE | sm (Eday, Lmon), smStderr (Eday) | 2 | Python | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ | ESACCI-SST | ts, tsStderr (Amon) | 2 | NCL | +------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+ diff --git a/esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml b/esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml new file mode 100644 index 0000000000..f2b7a1053d --- /dev/null +++ b/esmvaltool/cmorizers/data/cmor_config/ESACCI-SOILMOISTURE.yml @@ -0,0 +1,21 @@ +attributes: + project_id: 'OBS' + dataset_id: 'ESACCI-SOILMOISTURE' + tier: 2 + modeling_realm: sat + institution: 'TU Wien (AUT); VanderSat B.V. (NL); Planet Labs (NL); CESBIO (FR), EODC Gmbh (AUT)' + reference: 'esacci-soilmoisture' + source: 'ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/' + title: 'ESA CCI Soil Moisture' + version: 'L3S-SSMV-COMBINED-v08.1' + comment: '' +variables: + sm: + mip: Eday + raw: sm + filename: ESACCI-SOILMOISTURE-L3S-SSMV-COMBINED-{year}????000000-fv08.1.nc + smStderr: + mip: Eday + raw: sm_uncertainty + filename: ESACCI-SOILMOISTURE-L3S-SSMV-COMBINED-{year}????000000-fv08.1.nc + \ No newline at end of file diff --git a/esmvaltool/cmorizers/data/datasets.yml b/esmvaltool/cmorizers/data/datasets.yml index 2ed387f55c..dabe314025 100644 --- a/esmvaltool/cmorizers/data/datasets.yml +++ b/esmvaltool/cmorizers/data/datasets.yml @@ -531,11 +531,11 @@ datasets: ESACCI-SOILMOISTURE: tier: 2 source: ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/ - last_access: 2019-02-01 + last_access: 2024-06-19 info: | Download the data from: - daily_files/COMBINED/v04.2/ - ancillary/v04.2/ + daily_files/COMBINED/v08.1/ + ancillary/v08.1/ Put all files under a single directory (no subdirectories with years). ESACCI-SEA-SURFACE-SALINITY: diff --git a/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py b/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py index d31f330497..0d29e96ff9 100644 --- a/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py +++ b/esmvaltool/cmorizers/data/downloaders/datasets/esacci_soilmoisture.py @@ -26,9 +26,9 @@ def download_dataset(config, dataset, dataset_info, start_date, end_date, Overwrite already downloaded files """ if start_date is None: - start_date = datetime(1979, 1, 1) + start_date = datetime(1978, 11, 1) if end_date is None: - end_date = datetime(2016, 1, 1) + end_date = datetime(2022, 12, 31) loop_date = start_date @@ -40,9 +40,9 @@ def download_dataset(config, dataset, dataset_info, start_date, end_date, ) downloader.ftp_name = 'soil_moisture' downloader.connect() - downloader.set_cwd('ancillary/v04.2/') + downloader.set_cwd('ancillary/v08.1/') downloader.download_folder('.') - downloader.set_cwd('daily_files/COMBINED/v04.2/') + downloader.set_cwd('daily_files/COMBINED/v08.1/') while loop_date <= end_date: year = loop_date.year downloader.download_year(f'{year}') diff --git a/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl b/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl deleted file mode 100644 index 96ebe7f648..0000000000 --- a/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.ncl +++ /dev/null @@ -1,174 +0,0 @@ -; ############################################################################# -; ESMValTool CMORizer for ESACCI-SOILMOISTURE data -; ############################################################################# -; -; Tier -; Tier 2: other freely-available dataset. -; -; Source -; ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/ -; -; Last access -; 20190201 -; -; Download and processing instructions -; Download the data from: -; daily_files/COMBINED/v04.2/ -; ancillary/v04.2/ -; Put all files under a single directory (no subdirectories with years). -; -; Modification history -; 20190201-righi_mattia: adapted to v2, use new input data version 4.2. -; 20160824-lauer_axel: added processing of volumetric soil moisture -; content (sm, smStderr). -; 20160721-lauer_axel: use daily files, added processing of uncertainty. -; 20150523-righi_mattia: written. -; -; ############################################################################# -loadscript(getenv("esmvaltool_root") + \ - "/data/formatters/interface.ncl") - -begin - - ; Script name (for logger) - DIAG_SCRIPT = "esacci_soilmoisture.ncl" - - ; Source name - OBSNAME = "ESACCI-SOILMOISTURE" - - ; Tier - TIER = 2 - - ; Period - YEAR1 = get_year(start_year, 1979) - YEAR2 = get_year(end_year, 2016) - - ; Selected variable (standard name) - VAR = (/"sm", "smStderr", "dos", "dosStderr"/) - - ; Name in the raw data - NAME = (/"sm", "sm_uncertainty", "sm", "sm_uncertainty"/) - - ; MIP - MIP = (/"Lmon", "Lmon", "Lmon", "Lmon"/) - - ; Frequency - FREQ = (/"mon", "mon", "mon", "mon"/) - - ; CMOR table - CMOR_TABLE = getenv("cmor_tables") + "/custom/CMOR_" + VAR + ".dat" - - ; Type - TYPE = "sat" - - ; Version - VERSION = "L3S-SSMV-COMBINED-v4.2" - - ; Global attributes - SOURCE = "ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/" - REF = \ - "Liu et al., Hydrol. Earth Syst. Sci., doi:10.5194/hess-15-425-2011, 2011." - COMMENT = "" - -end - -begin - - do vv = 0, dimsizes(VAR) - 1 - - log_info("Processing " + VAR(vv) + " (" + MIP(vv) + ")") - - do yy = YEAR1, YEAR2 - - ; Set list of files - files = systemfunc("ls " + input_dir_path + \ - "ESACCI-SOILMOISTURE-L3S-SSMV-" + \ - "COMBINED-" + yy + "????000000-fv04.2.nc") - f = addfiles(files, "r") - delete(files) - - ; Read data - xx = f[:]->$NAME(vv)$ - if (isatt(xx, "scale_factor")) then - tmp = tofloat(xx * xx@scale_factor) - copy_VarAtts(xx, tmp) - copy_VarCoords(xx, tmp) - delete(xx) - xx = tmp - delete(tmp) - end if - delete(f) - - ; Derive dos using porosity - if (any(VAR(vv).eq.(/"dos", "dosStderr"/))) then - g = addfile(input_dir_path + \ - "/ESACCI-SOILMOISTURE-POROSITY_V01.1.nc", "r") - zz = g->porosity - xx = xx * 100. / conform(xx, zz, (/1, 2/)) - delete(zz) - end if - - ; Add a minor time shift for correct extraction of monthly mean below - xx&time = xx&time + 0.1 - - ; Calculate monthly means - if (isStrSubset(VAR(vv), "Stderr")) then - xx2 = xx - xx2 = xx ^ 2 ; save metadata - tmp = calculate_monthly_values(xx2, "avg", 0, False) - delete(xx) - delete(xx2) - xx = sqrt(tmp) - copy_VarAtts(tmp, xx) - copy_VarCoords(tmp, xx) - delete(tmp) - else - tmp = calculate_monthly_values(xx, "avg", 0, False) - delete(xx) - xx = tmp - delete(tmp) - end if - - ; Append to time-series - if (.not.isdefined("output")) then - output = xx - else - output := array_append_record(output, xx, 0) - end if - delete(xx) - - end do - - ; Format coordinates - output!0 = "time" - output!1 = "lat" - output!2 = "lon" - format_coords(output, YEAR1 + "0101", YEAR2 + "1231", FREQ(vv)) - - ; Set variable attributes - tmp = format_variable(output, VAR(vv), CMOR_TABLE(vv)) - delete(output) - output = tmp - delete(tmp) - - ; Calculate coordinate bounds - bounds = guess_coord_bounds(output, FREQ(vv)) - - ; Set global attributes - gAtt = set_global_atts(OBSNAME, TIER, SOURCE, REF, COMMENT) - - ; Output file - DATESTR = YEAR1 + "01-" + YEAR2 + "12" - fout = output_dir_path + \ - str_join((/"OBS", OBSNAME, TYPE, VERSION, \ - MIP(vv), VAR(vv), DATESTR/), "_") + ".nc" - - ; Write variable - write_nc(fout, VAR(vv), output, bounds, gAtt) - delete(gAtt) - delete(output) - delete(bounds) - - end do - -end diff --git a/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py b/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py new file mode 100644 index 0000000000..66859b420b --- /dev/null +++ b/esmvaltool/cmorizers/data/formatters/datasets/esacci_soilmoisture.py @@ -0,0 +1,149 @@ +"""ESMValTool CMORizer for ESACCI-SOILMOISTURE data. + +Tier + Tier 2: other freely-available dataset. + +Source + ftp://anon-ftp.ceda.ac.uk/neodc/esacci/soil_moisture/data/ + +Last access + 20240626 + +Download and processing instructions + Download the data from: + daily_files/COMBINED/v08.1/ + ancillary/v08.1/ + Put all files under a single directory (no subdirectories with years). + in ${RAWOBS}/Tier2/ESACCI-SOILMOISTURE + +""" + +import glob +import logging +import os +from datetime import datetime +import iris +from esmvalcore.preprocessor import concatenate, monthly_statistics +from cf_units import Unit + +from ...utilities import ( + fix_var_metadata, + fix_dim_coordnames, + fix_bounds, + save_variable, + set_global_atts +) + +logger = logging.getLogger(__name__) + + +def fix_coords(cube): + """Fix coordinates to CMOR standards. + + Fixes coordinates eg time to have correct units, bounds etc; + longitude to be CMOR-compliant 0-360deg; fixes some attributes + and bounds - the user can avert bounds fixing by using supplied + arguments; if bounds are None they will be fixed regardless. + + Parameters + ---------- + cube: iris.cube.Cube + data cube with coordinates to be fixed. + + + Returns + ------- + cube: iris.cube.Cube + data cube with fixed coordinates. + """ + # First fix any completely missing coord var names + fix_dim_coordnames(cube) + + # Convert longitude from -180...180 to 0...360 + cube = cube.intersection(longitude=(0.0, 360.0)) + + # Fix individual coords + for cube_coord in cube.coords(): + # Fix time + if cube_coord.var_name == 'time': + logger.info("Fixing time...") + cube.coord('time').convert_units( + Unit('days since 1970-01-01T00:00:00+00:00', + calendar='proleptic_gregorian')) + + # Fix latitude + if cube_coord.var_name == 'lat': + logger.info("Fixing latitude...") + cube = iris.util.reverse(cube, cube_coord) + + # Fix bounds of all coordinates + fix_bounds(cube, cube_coord) + + return cube + + +def extract_variable(raw_info): + """Extract variables.""" + rawvar = raw_info['name'] + constraint = iris.Constraint(name=rawvar) + if rawvar == 'sm_uncertainty': + sm_cube = iris.load_cube(raw_info['file'], + iris.NameConstraint(var_name='sm')) + ancillary_var = sm_cube.ancillary_variable( + 'Volumetric Soil Moisture Uncertainty' + ) + cube = sm_cube.copy(ancillary_var.core_data()) + else: + cube = iris.load_cube(raw_info['file'], constraint) + + # Remove dysfunctional ancillary data without standard names + for ancillary_variable in cube.ancillary_variables(): + cube.remove_ancillary_variable(ancillary_variable) + + return cube + + +def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date): + """Cmorize data.""" + glob_attrs = cfg['attributes'] + if not start_date: + start_date = datetime(1978, 1, 1) + if not end_date: + end_date = datetime(2022, 12, 31) + + # run the cmorization + for var_name, vals in cfg['variables'].items(): + all_data_cubes = [] + if not isinstance(vals, dict): # Ensure vals is a dictionary + raise ValueError( + f"Invalid format for variable {var_name}: {type(vals)}" + ) + var_info = cfg['cmor_table'].get_variable(vals['mip'], var_name) + glob_attrs['mip'] = vals['mip'] + raw_info = {'name': vals['raw']} + inpfile_pattern = os.path.join(in_dir, vals['filename']) + logger.info("CMORizing var %s from file type %s", + var_name, inpfile_pattern) + + for year in range(start_date.year, end_date.year + 1): + year_inpfile_pattern = inpfile_pattern.format(year=year) + inpfiles = sorted(glob.glob(year_inpfile_pattern)) + for inpfile in inpfiles: + raw_info['file'] = inpfile + cube = extract_variable(raw_info) + all_data_cubes.append(cube) + final_cube = concatenate(all_data_cubes) + fix_var_metadata(final_cube, var_info) + final_cube = fix_coords(final_cube) + set_global_atts(final_cube, glob_attrs) + + save_variable(final_cube, var_name, out_dir, glob_attrs, + unlimited_dimensions=['time']) + + # For sm, also save monthly means + if var_name == 'sm': + monthly_mean_cube = monthly_statistics(final_cube, 'mean') + glob_attrs['mip'] = 'Lmon' + monthly_mean_cube.attributes.update(glob_attrs) + save_variable(monthly_mean_cube, var_name, out_dir, glob_attrs, + unlimited_dimensions=['time']) diff --git a/esmvaltool/cmorizers/data/utilities.py b/esmvaltool/cmorizers/data/utilities.py index 3620cee30e..82da07c12e 100644 --- a/esmvaltool/cmorizers/data/utilities.py +++ b/esmvaltool/cmorizers/data/utilities.py @@ -359,7 +359,7 @@ def save_variable(cube, var, outdir, attrs, **kwargs): def extract_doi_value(tags): """Extract doi(s) from a bibtex entry.""" reference_doi = [] - pattern = r'doi\ = {(.*?)\},' + pattern = r'doi\s*=\s*{([^}]+)}' if not isinstance(tags, list): tags = [tags] @@ -368,17 +368,18 @@ def extract_doi_value(tags): bibtex_file = REFERENCES_PATH / f'{tag}.bibtex' if bibtex_file.is_file(): reference_entry = bibtex_file.read_text() - if re.search("doi", reference_entry): - reference_doi.append( - f'doi:{re.search(pattern, reference_entry).group(1)}') + dois = re.findall(pattern, reference_entry) + if dois: + for doi in dois: + reference_doi.append(f'doi:{doi}') else: reference_doi.append('doi not found') - logger.warning('The reference file %s does not have a doi.', - bibtex_file) + logger.warning( + 'The reference file %s does not have a doi.', bibtex_file) else: reference_doi.append('doi not found') - logger.warning('The reference file %s does not exist.', - bibtex_file) + logger.warning( + 'The reference file %s does not exist.', bibtex_file) return ', '.join(reference_doi) diff --git a/esmvaltool/recipes/examples/recipe_check_obs.yml b/esmvaltool/recipes/examples/recipe_check_obs.yml index 10504a3692..b3cca9e028 100644 --- a/esmvaltool/recipes/examples/recipe_check_obs.yml +++ b/esmvaltool/recipes/examples/recipe_check_obs.yml @@ -297,14 +297,20 @@ diagnostics: ESACCI-SOILMOISTURE: description: ESACCI-SOILMOISTURE check variables: - dos: - dosStderr: - sm: + sm_daily: + short_name: sm + mip: Eday + frequency: day + sm_monthly: + short_name: sm + mip: Lmon + frequency: mon smStderr: + mip: Eday + frequency: day additional_datasets: - - {dataset: ESACCI-SOILMOISTURE, project: OBS, mip: Lmon, tier: 2, - type: sat, version: L3S-SSMV-COMBINED-v4.2, - start_year: 2005, end_year: 2011} + - {dataset: ESACCI-SOILMOISTURE, project: OBS, tier: 2, + type: sat, version: L3S-SSMV-COMBINED-v08.1, start_year: 1978, end_year: 2022} scripts: null diff --git a/esmvaltool/references/esacci-soilmoisture.bibtex b/esmvaltool/references/esacci-soilmoisture.bibtex index 59e275d6c4..7e4404a8f4 100644 --- a/esmvaltool/references/esacci-soilmoisture.bibtex +++ b/esmvaltool/references/esacci-soilmoisture.bibtex @@ -1,13 +1,115 @@ @article{esacci-soilmoisture, - doi = {10.5194/hess-15-425-2011}, - url = {https://doi.org/10.5194%2Fhess-15-425-2011}, - year = 2011, - month = {feb}, - publisher = {Copernicus {GmbH}}, - volume = {15}, - number = {2}, - pages = {425--436}, - author = {Y. Y. Liu and R. M. Parinussa and W. A. Dorigo and R. A. M. De Jeu and W. Wagner and A. I. J. M. van Dijk and M. F. McCabe and J. P. Evans}, - title = {Developing an improved soil moisture dataset by blending passive and active microwave satellite-based retrievals}, - journal = {Hydrology and Earth System Sciences} + doi = {10.5194/essd-11-717-2019}, + title = {Evolution of the {ESA} {CCI} Soil Moisture climate data records + and their underlying merging methodology}, + author = {Gruber, Alexander and Scanlon, Tracy and van der Schalie, Robin + and Wagner, Wolfgang and Dorigo, Wouter}, + abstract = {The European Space Agency's Climate Change Initiative + for Soil Moisture (ESA CCI SM) merging algorithm generates + consistent quality-controlled long-term (1978--2018) climate + data records for soil moisture, which serves thousands of + scientists and data users worldwide. It harmonises and merges + soil moisture retrievals from multiple satellites into (i) an + active-microwave-based-only product, (ii) a + passive-microwave-based-only product and (iii) a combined + active--passive product, which are sampled to daily global + images on a 0.25∘ regular grid. Since its first release in 2012 + the algorithm has undergone substantial improvements which have + so far not been thoroughly reported in the scientific + literature. This paper fills this gap by reviewing and + discussing the science behind the three major ESA CCI SM merging + algorithms, versions 2 + (https://doi.org/10.5285/3729b3fbbb434930bf65d82f9b00111c; + Wagner et al., 2018), 3 + (https://doi.org/10.5285/b810601740bd4848b0d7965e6d83d26c; + Dorigo et al., 2018) and 4 + (https://doi.org/10.5285/dce27a397eaf47e797050c220972ca0e; + Dorigo et al., 2019), and provides an outlook on the expected + improvements planned for the next algorithm, version 5.}, + journal = {Earth Syst. Sci. Data}, + publisher = {Copernicus GmbH}, + volume = {11}, + number = {2}, + pages = {717--739}, + month = {may}, + year = 2019 } + +@article{esacci-soilmoisture, + doi = {10.1016/j.rse.2017.07.001}, + title = {{ESA} {CCI} Soil Moisture for improved Earth system + understanding: State-of-the art and future directions}, + author = {Dorigo, Wouter and Wagner, Wolfgang and Albergel, Clement and + Albrecht, Franziska and Balsamo, Gianpaolo and Brocca, Luca and + Chung, Daniel and Ertl, Martin and Forkel, Matthias and Gruber, + Alexander and Haas, Eva and Hamer, Paul D and Hirschi, Martin + and Ikonen, Jaakko and de Jeu, Richard and Kidd, Richard and + Lahoz, William and Liu, Yi Y and Miralles, Diego and + Mistelbauer, Thomas and Nicolai-Shaw, Nadine and Parinussa, + Robert and Pratola, Chiara and Reimer, Christoph and van der + Schalie, Robin and Seneviratne, Sonia I and Smolander, Tuomo and + Lecomte, Pascal}, + abstract = {Climate Data Records of soil moisture are fundamental for + improving our understanding of long-term dynamics in the coupled + water, energy, and carbon cycles over land. To respond to this + need, in 2012 the European Space Agency (ESA) released the first + multi-decadal, global satellite-observed soil moisture (SM) + dataset as part of its Climate Change Initiative (CCI) program. + This product, named ESA CCI SM, combines various single-sensor + active and passive microwave soil moisture products into three + harmonised products: a merged ACTIVE, a merged PASSIVE, and a + COMBINED active + passive microwave product. Compared to the + first product release, the latest version of ESA CCI SM includes + a large number of enhancements, incorporates various new + satellite sensors, and extends its temporal coverage to the + period 1978--2015. In this study, we first provide a + comprehensive overview of the characteristics, evolution, and + performance of the ESA CCI SM products. Based on original + research and a review of existing literature we show that the + product quality has steadily increased with each successive + release and that the merged products generally outperform the + single-sensor input products. Although ESA CCI SM generally + agrees well with the spatial and temporal patterns estimated by + land surface models and observed in-situ, we identify surface + conditions (e.g., dense vegetation, organic soils) for which it + still has large uncertainties. Second, capitalising on the + results of > 100 research studies that made use of the ESA CCI + SM data we provide a synopsis of how it has contributed to + improved process understanding in the following Earth system + domains: climate variability and change, land-atmosphere + interactions, global biogeochemical cycles and ecology, + hydrological and land surface modelling, drought applications, + and meteorology. While in some disciplines the use of ESA CCI SM + is already widespread (e.g. in the evaluation of model soil + moisture states) in others (e.g. in numerical weather prediction + or flood forecasting) it is still in its infancy. The latter is + partly related to current shortcomings of the product, e.g., the + lack of near-real-time availability and data gaps in time and + space. This study discloses the discrepancies between current + ESA CCI SM product characteristics and the preferred + characteristics of long-term satellite soil moisture products as + outlined by the Global Climate Observing System (GCOS), and + provides important directions for future ESA CCI SM product + improvements to bridge these gaps.}, + journal = {Remote Sens. Environ.}, + publisher = {Elsevier BV", + volume = {203}, + pages = {185--215}, + month = {dec}, + year = 2017 +} + +@article{esacci-soilmoisture, + doi = {10.1109/TGRS.2020.3012896}, + title = {Homogenization of structural breaks in the global {ESA} {CCI} + soil moisture multisatellite climate data record}, + author = {Preimesberger, Wolfgang and Scanlon, Tracy and Su, Chun-Hsu and + Gruber, Alexander and Dorigo, Wouter}, + journal = {IEEE Trans. Geosci. Remote Sens.}, + publisher = {Institute of Electrical and Electronics Engineers (IEEE)}, + volume = {159}, + number = {14}, + pages = {12845--2862}, + month = {apr}, + year = 2021 +} \ No newline at end of file