class_docstr: Class implementing the MTG FCI L1c Filehandler.
  
  This class implements the Meteosat Third Generation (MTG) Flexible
  Combined Imager (FCI) Level-1c NetCDF reader.
  It is designed to be used through the :class:`~satpy.Scene`
  class using the :mod:`~satpy.Scene.load` method with the reader
  ``"fci_l1c_nc"``.
docstr: Calculate area extent for a dataset.
docstr_tok: ["Calculate","area","extent","for","a","dataset","."]
code: def calc_area_extent(self, key):
      """Calculate area extent for a dataset."""
      # if a user requests a pixel quality or index map before the channel data, the
      # yaml-reader will ask the area extent of the pixel quality/index map field,
      # which will ultimately end up here
      channel_name = _get_channel_name_from_dsname(key["name"])
      # Get metadata for given dataset
      measured = self.get_channel_measured_group_path(channel_name)
      # Get start/end line and column of loaded swath.
      nlines, ncols = self[measured + "/effective_radiance/shape"]
  
      logger.debug(
          "Channel {} resolution: {}".format(channel_name, ncols)
      )
      logger.debug("Row/Cols: {} / {}".format(nlines, ncols))
  
      # Calculate full globe line extent
      h = float(
          self.get_and_cache_npxr(
              "data/mtg_geos_projection/attr/perspective_point_height"
          )
      )
  
      extents = {}
      for coord in "xy":
          coord_radian = self.get_and_cache_npxr(
              measured + "/{:s}".format(coord)
          )
  
          # TODO remove this check when old versions of IDPF test data (<v4) are deprecated.
          if coord == "x" and coord_radian.attrs["scale_factor"] > 0:
              coord_radian.attrs["scale_factor"] *= -1
  
          # TODO remove this check when old versions of IDPF test data (<v5) are deprecated.
          if type(coord_radian.attrs["scale_factor"]) is np.float32:
              coord_radian.attrs["scale_factor"] = coord_radian.attrs[
                  "scale_factor"
              ].astype("float64")
          if type(coord_radian.attrs["add_offset"]) is np.float32:
              coord_radian.attrs["add_offset"] = coord_radian.attrs[
                  "add_offset"
              ].astype("float64")
  
          coord_radian_num = (
              coord_radian[:] * coord_radian.attrs["scale_factor"]
              + coord_radian.attrs["add_offset"]
          )
  
          # FCI defines pixels by centroids (see PUG), while pyresample
          # defines corners as lower left corner of lower left pixel, upper right corner of upper right pixel
          # (see https://pyresample.readthedocs.io/en/latest/geo_def.html).
          # Therefore, half a pixel (i.e. half scale factor) needs to be added in each direction.
  
          # The grid origin is in the South-West corner.
          # Note that the azimuth angle (x) is defined as positive towards West (see PUG - Level 1c Reference Grid)
          # The elevation angle (y) is defined as positive towards North as per usual convention. Therefore:
          # The values of x go from positive (West) to negative (East) and the scale factor of x is negative.
          # The values of y go from negative (South) to positive (North) and the scale factor of y is positive.
  
          # South-West corner (x positive, y negative)
          first_coord_radian = (
              coord_radian_num[0]
              - coord_radian.attrs["scale_factor"] / 2
          )
          # North-East corner (x negative, y positive)
          last_coord_radian = (
              coord_radian_num[-1]
              + coord_radian.attrs["scale_factor"] / 2
          )
  
          # convert to arc length in m
          first_coord = first_coord_radian * h  # arc length in m
          last_coord = last_coord_radian * h
  
          # the .item() call is needed with the h5netcdf backend, see
          # https://github.com/pytroll/satpy/issues/972#issuecomment-558191583
          # but we need to compute it first if this is dask
          try:
              first_coord = first_coord.compute()
              last_coord = last_coord.compute()
          except AttributeError:  # not a dask.array
              pass
  
          extents[coord] = (first_coord.item(), last_coord.item())
  
      # For the final extents, take into account that the image is upside down (lower line is North), and that
      # East is defined as positive azimuth in Proj, so we need to multiply by -1 the azimuth extents.
  
      # lower left x: west-ward extent: first coord of x, multiplied by -1 to account for azimuth orientation
      # lower left y: north-ward extent: last coord of y
      # upper right x: east-ward extent: last coord of x, multiplied by -1 to account for azimuth orientation
      # upper right y: south-ward extent: first coord of y
      area_extent = (
          -extents["x"][0],
          extents["y"][1],
          -extents["x"][1],
          extents["y"][0],
      )
  
      return area_extent, nlines, ncols
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from datetime import timedelta
  from functools import cached_property
  import dask.array
  import numpy
  import xarray
  from netCDF4 import default_fillvals
  from pyresample import geometry
  from satpy.readers._geos_area import get_geos_area_naming
  from satpy.readers.eum_base import get_service_mode
  from .netcdf_utils import NetCDF4FsspecFileHandler
label_desc: Use image node_id 19 for calling the FCIL1cNCFileHandler obj's underlying member method code with example usage: obj.calc_area_extent(key) and returns: area_extent,  nlines,  ncols