@Override
  public IObservation[] createRainfall(
      final Feature[] catchmentFeatures,
      final IStringResolver variables,
      final ILog log,
      IProgressMonitor monitor)
      throws CoreException {
    /* Monitor. */
    if (monitor == null) monitor = new NullProgressMonitor();

    /* Monitor. */
    monitor.beginTask(
        Messages.getString("InverseDistanceRainfallGenerator_7"), 1000); // $NON-NLS-1$
    monitor.subTask(Messages.getString("InverseDistanceRainfallGenerator_8")); // $NON-NLS-1$

    /* Update the log. */
    LogUtilities.logQuietly(
        log,
        new Status(
            IStatus.INFO,
            KalypsoModelRcmActivator.PLUGIN_ID,
            Messages.getString("InverseDistanceRainfallGenerator_9"),
            null)); //$NON-NLS-1$

    /* Get the needed properties. */
    final Feature ombrometerCollection = getProperty(MEMBER_ombrometerCollection, Feature.class);
    final String collectionPath = getProperty(PROPERTY_ombrometerFeaturePath, String.class);
    final String linkPath = getProperty(PROPERTY_timeseriesLinkPath, String.class);
    final String stationLocationPath = getProperty(PROPERTY_stationLocationPath, String.class);
    final BigInteger numberOmbrometers = getProperty(PROPERTY_numberOmbrometers, BigInteger.class);
    final String catchmentAreaPath = getProperty(PROPERTY_catchmentAreaPath, String.class);

    /* Create the paths. */
    final GMLXPath collectionXPath =
        new GMLXPath(collectionPath, getWorkspace().getNamespaceContext());
    final GMLXPath linkXPath = new GMLXPath(linkPath, getWorkspace().getNamespaceContext());
    final GMLXPath stationLocationXPath =
        new GMLXPath(stationLocationPath, getWorkspace().getNamespaceContext());
    final GMLXPath catchmentAreaXPath =
        new GMLXPath(catchmentAreaPath, getWorkspace().getNamespaceContext());

    /* Monitor. */
    monitor.worked(100);
    monitor.subTask(Messages.getString("InverseDistanceRainfallGenerator_10")); // $NON-NLS-1$

    try {
      /* Get the ombrometers. */
      final FeatureList ombrometerList =
          (FeatureList) GMLXPathUtilities.query(collectionXPath, ombrometerCollection);

      /* Convert to an array. */
      final List<Feature> featureList = new ArrayList<>(ombrometerList.size());
      final GMLWorkspace workspace = ombrometerList.getOwner().getWorkspace();
      for (final Object object : ombrometerList) {
        final Feature feature = FeatureHelper.getFeature(workspace, object);
        if (feature != null) {
          // TODO Should be in the generator gml (rcm) ...
          final Boolean active = (Boolean) feature.getProperty(IOmbrometer.QNAME_PROP_ISUSED);
          if (active != null && active.booleanValue() == true) featureList.add(feature);
        }
      }

      /* Convert to an array. */
      final Feature[] ombrometerFeatures = featureList.toArray(new Feature[featureList.size()]);

      /* Monitor. */
      monitor.worked(100);
      monitor.subTask(Messages.getString("InverseDistanceRainfallGenerator_11")); // $NON-NLS-1$

      /* Convert to zml observations . */
      final IZmlFilter[] filters = getFilters().toArray(new IZmlFilter[] {});
      final DateRange range = getPeriod(variables);
      final IObservation[] ombrometerObservations =
          RainfallGeneratorUtilities.readObservations(
              ombrometerFeatures, linkXPath, filters, range);

      /* Monitor. */
      monitor.worked(100);
      monitor.subTask(Messages.getString("InverseDistanceRainfallGenerator_12")); // $NON-NLS-1$

      /* Get the station locations. */
      final GM_Point[] ombrometerStations =
          FeatureHelper.getProperties(
              ombrometerFeatures, stationLocationXPath, new GM_Point[ombrometerFeatures.length]);

      /* Convert to JTS geometries. */
      final Point[] ombrometerPoints = new Point[ombrometerStations.length];
      final IGeoTransformer transformer =
          GeoTransformerFactory.getGeoTransformer(
              KalypsoDeegreePlugin.getDefault().getCoordinateSystem());
      for (int i = 0; i < ombrometerStations.length; i++) {
        final GM_Point ombrometerPoint = ombrometerStations[i];
        final GM_Object ombrometerTransformed = transformer.transform(ombrometerPoint);
        ombrometerPoints[i] = (Point) JTSAdapter.export(ombrometerTransformed);

        /* Monitor. */
        monitor.worked(200 / ombrometerStations.length);
      }

      /* Monitor. */
      monitor.subTask(Messages.getString("InverseDistanceRainfallGenerator_13")); // $NON-NLS-1$

      /* Get all catchment areas. */
      final GM_MultiSurface[] areas =
          RainfallGeneratorUtilities.findCatchmentAreas(catchmentFeatures, catchmentAreaXPath);

      /* Monitor. */
      monitor.worked(100);
      monitor.subTask(Messages.getString("InverseDistanceRainfallGenerator_14")); // $NON-NLS-1$

      /* Iterate through all catchments. */
      final IObservation[] result = new IObservation[areas.length];
      for (int i = 0; i < areas.length; i++) {
        /* Monitor. */
        monitor.subTask(
            String.format(
                Messages.getString("InverseDistanceRainfallGenerator_15"),
                i + 1,
                areas.length)); // $NON-NLS-1$

        /* Get the catchment. */
        final GM_MultiSurface area = areas[i];
        if (area == null) {
          monitor.worked(400 / areas.length);
          continue;
        }

        /* Convert to a JTS geometry. */
        final Geometry areaGeometry = JTSAdapter.export(area);

        /* Get the weights. */
        final double[] weights =
            InverseDistanceUtilities.getWeights(
                areaGeometry, ombrometerPoints, numberOmbrometers.intValue());

        /* Combine the observations. */
        result[i] =
            RainfallGeneratorUtilities.combineObses(
                ombrometerObservations, weights, "ombrometer://inverse.distance"); // $NON-NLS-1$

        /* Monitor. */
        monitor.worked(400 / areas.length);
      }

      /* Update the log. */
      LogUtilities.logQuietly(
          log,
          new Status(
              IStatus.OK,
              KalypsoModelRcmActivator.PLUGIN_ID,
              Messages.getString("InverseDistanceRainfallGenerator_17"),
              null)); //$NON-NLS-1$

      return result;
    } catch (final GM_Exception e) {
      /* Update the log. */
      LogUtilities.logQuietly(
          log,
          new Status(
              IStatus.ERROR,
              KalypsoModelRcmActivator.PLUGIN_ID,
              String.format(
                  Messages.getString("InverseDistanceRainfallGenerator_18"),
                  e.getLocalizedMessage()),
              e)); //$NON-NLS-1$

      throw new CoreException(
          new Status(
              IStatus.ERROR,
              KalypsoModelRcmActivator.PLUGIN_ID,
              "Failed to convert Geometrie: " + e.toString(),
              e)); //$NON-NLS-1$
    } catch (final SensorException e) {
      /* Update the log. */
      LogUtilities.logQuietly(
          log,
          new Status(
              IStatus.ERROR,
              KalypsoModelRcmActivator.PLUGIN_ID,
              String.format(
                  Messages.getString("InverseDistanceRainfallGenerator_20"),
                  e.getLocalizedMessage()),
              e)); //$NON-NLS-1$

      throw new CoreException(
          new Status(
              IStatus.ERROR,
              KalypsoModelRcmActivator.PLUGIN_ID,
              "Failed to combine Observations: " + e.toString(),
              e)); //$NON-NLS-1$
    } catch (final Exception e) {
      /* Update the log. */
      LogUtilities.logQuietly(
          log,
          new Status(
              IStatus.ERROR,
              KalypsoModelRcmActivator.PLUGIN_ID,
              String.format(
                  Messages.getString("InverseDistanceRainfallGenerator_22"),
                  e.getLocalizedMessage()),
              e)); //$NON-NLS-1$

      throw new CoreException(
          new Status(
              IStatus.ERROR,
              KalypsoModelRcmActivator.PLUGIN_ID,
              Messages.getString("InverseDistanceRainfallGenerator_23") + e.toString(),
              e)); //$NON-NLS-1$
    } finally {
      /* Update the log. */
      LogUtilities.logQuietly(
          log,
          new Status(
              IStatus.INFO,
              KalypsoModelRcmActivator.PLUGIN_ID,
              Messages.getString("InverseDistanceRainfallGenerator_24"),
              null)); //$NON-NLS-1$

      /* Monitor. */
      monitor.done();
    }
  }