sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Modify the way GridGeometry are created in order to prepare for future development where some variable dimensions are bands instead than spatiotemporal dimensions. The information about bands will be stored in a Variable field, based on additional temporary information to be carried by Variable.Adjustment in a future commit.
Date Sat, 16 Mar 2019 17:14:57 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 3e07d96  Modify the way GridGeometry are created in order to prepare for future development where some variable dimensions are bands instead than spatiotemporal dimensions. The information about bands will be stored in a Variable field, based on additional temporary information to be carried by Variable.Adjustment in a future commit.
3e07d96 is described below

commit 3e07d96e0c2a8b4401bc39d7bd4e30ba79b3d8ac
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Mar 16 18:12:59 2019 +0100

    Modify the way GridGeometry are created in order to prepare for future development where some variable dimensions are bands instead than spatiotemporal dimensions.
    The information about bands will be stored in a Variable field, based on additional temporary information to be carried by Variable.Adjustment in a future commit.
---
 .../org/apache/sis/internal/netcdf/Convention.java |   5 +-
 .../org/apache/sis/internal/netcdf/Dimension.java  |   2 +-
 .../java/org/apache/sis/internal/netcdf/Grid.java  |  44 ++-
 .../org/apache/sis/internal/netcdf/Variable.java   | 398 ++++++++++++++-------
 .../apache/sis/internal/netcdf/impl/GridInfo.java  |  18 +-
 .../sis/internal/netcdf/impl/VariableInfo.java     |  33 +-
 .../sis/internal/netcdf/ucar/GridWrapper.java      |  81 ++---
 .../sis/internal/netcdf/ucar/VariableWrapper.java  |  83 ++---
 8 files changed, 397 insertions(+), 267 deletions(-)

diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
index 0f7b8ff..0dfac3b 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
@@ -228,7 +228,10 @@ public class Convention {
      * This happen for example if a netCDF file defines two grids for the same dimensions.
      * The order in returned array will be the axis order in the Coordinate Reference System.
      *
-     * <p>The default implementation returns {@code null}.</p>
+     * <p>This information is normally provided by the {@value ucar.nc2.constants.CF#COORDINATES} attribute,
+     * which is processed by the UCAR library (which is why we do not read this attribute ourselves here).
+     * This method is provided as a fallback when no such attribute is found.
+     * The default implementation returns {@code null}.</p>
      *
      * @param  data  the variable for which the list of axis variables are desired, in CRS order.
      * @return names of the variables containing axis values, or {@code null} if this
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
index 0b13627..daece51 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
@@ -28,7 +28,7 @@ import org.apache.sis.util.resources.Vocabulary;
  * and {@code Dimension.equals(object)} must return {@code true} if two {@code Dimension}
  * instances represent the same netCDF dimensions. This may require subclasses to override
  * {@link #hashCode()} and {@link #equals(Object)} if uniqueness is not guaranteed.
- * This is needed by {@link Variable#getGrid()} default implementation.</p>
+ * This is needed by {@link Variable#getGrid} default implementation.</p>
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
index 07c5a1b..5d62a06 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
@@ -44,7 +44,10 @@ import org.apache.sis.util.NullArgumentException;
 
 /**
  * Information about the grid geometry and the conversion from grid coordinates to geodetic coordinates.
- * More than one variable may share the same grid.
+ * A grid is associated to all variables that are georeferenced coverages and the same grid may be shared
+ * by many variables. The {@linkplain #getSourceDimensions() number of source dimensions} is normally the
+ * number of {@linkplain Variable#getGridDimensions() netCDF dimensions in the variable}, but may be less
+ * if a variable dimensions should considered as bands instead than spatio-temporal dimensions.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
@@ -106,27 +109,32 @@ public abstract class Grid extends NamedElement {
 
     /**
      * Returns a localization grid having the same dimensions than this grid but in a different order.
-     * This method is invoked by {@link Variable#getGrid()} when the localization grids created by
+     * This method is invoked by {@link Variable#getGrid} when the localization grids created by
      * {@link Decoder} subclasses are not sufficient and must be tailored for a particular variable.
-     * Subclasses should verify that the given {@code dimensions} array meets the following conditions:
+     * Subclasses shall verify that the given {@code dimensions} array met the following conditions:
      *
      * <ul>
-     *   <li>The length of the given array should be equal to {@link #getSourceDimensions()}.</li>
-     *   <li>The array should contain all elements contained in {@link #getDimensions()}.</li>
+     *   <li>The length of the given array is equal or greater than {@link #getSourceDimensions()}.</li>
+     *   <li>The array contains all elements contained in {@link #getDimensions()}.
+     *       Additional elements, if any, are ignored (they may be considered as bands by the caller).</li>
      * </ul>
      *
      * If elements in the given array are in same order than elements in {@link #getDimensions()} list,
-     * then this method returns {@code this}. If the given dimensions are unknown to this grid,
-     * then this method returns {@code null}. Otherwise a grid with the given dimensions is returned.
+     * then this method returns {@code this}. If the given array does not contain all grid dimensions,
+     * then this method returns {@code null}. Otherwise a grid with reordered dimensions is returned.
+     * It is caller's responsibility to verify if the grid has less dimensions than the given argument.
      *
-     * @param  dimensions  the dimensions of this grid but potentially in a different order.
-     * @return localization grid with given dimension order (may be {@code this}), or {@code null}.
+     * @param  dimensions  the desired dimensions, in order. May contain more dimensions than this grid.
+     * @return localization grid with the exact same set of dimensions than this grid (no more and no less),
+     *         but in the order specified by the given array (ignoring dimensions not in this grid).
+     *         May be {@code this} or {@code null}.
      */
-    protected abstract Grid derive(Dimension[] dimensions);
+    protected abstract Grid forDimensions(Dimension[] dimensions);
 
     /**
      * Returns the number of dimensions of source coordinates in the <cite>"grid to CRS"</cite> conversion.
      * This is the number of dimensions of the <em>grid</em>.
+     * It should be equal to the size of {@link #getDimensions()} list.
      *
      * @return number of grid dimensions.
      */
@@ -135,7 +143,7 @@ public abstract class Grid extends NamedElement {
     /**
      * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion.
      * This is the number of dimensions of the <em>coordinate reference system</em>.
-     * It should be equal to the size of the array returned by {@link #getAxes(Decoder)},
+     * It should be equal to the length of the array returned by {@link #getAxes(Decoder)},
      * but caller should be robust to inconsistencies.
      *
      * @return number of CRS dimensions.
@@ -147,6 +155,18 @@ public abstract class Grid extends NamedElement {
      * contains the number of cells in the dimension, together with implementation-specific information.
      * The list length should be equal to {@link #getSourceDimensions()}.
      *
+     * <p>This list is usually equal to the {@link Variable#getGridDimensions()} list for all variables
+     * that are {@linkplain Variable#getGrid associated to this grid}. But those lists can also differ
+     * in the following aspects:</p>
+     *
+     * <ul>
+     *   <li>This grid may have less dimensions than the variable using this grid. In such case the additional
+     *       dimensions in the variable can be considered as bands instead than spatiotemporal dimensions.</li>
+     *   <li>The dimensions in this grid may have a different {@linkplain Dimension#length() length} than the
+     *       dimensions in the variable. In such case {@link Variable#getGridGeometry()} is responsible for
+     *       concatenating a scale factor to the "grid to CRS" transform.</li>
+     * </ul>
+     *
      * @return the source dimensions of this grid, in netCDF order.
      *
      * @see Variable#getGridDimensions()
@@ -303,7 +323,7 @@ public abstract class Grid extends NamedElement {
     /**
      * Returns an object containing the grid size, the CRS and the conversion from grid indices to CRS coordinates.
      * {@code GridGeometry} is the public object exposed to users. It uses the dimensions given by axes, which are
-     * usually the same dimensions that the ones of the variable using this grid geometry but not always.
+     * usually the same dimensions than the ones of the variable using this grid geometry but not always.
      * Caller may need to call {@link GridExtent#resize(long...)} for adjusting.
      *
      * @param   decoder   the decoder for which grid geometries are constructed.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
index c1c9466..dfb7c4b 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
@@ -112,15 +112,21 @@ public abstract class Variable extends NamedElement {
     private Map<Number,Object> nodataValues;
 
     /**
-     * Factors by which to multiply a grid index in order to get the corresponding data index, or {@code null} if none.
-     * This is usually null, meaning that there is an exact match between grid indices and data indices. This array may
-     * be non-null if the localization grid has smaller dimensions than the dimensions of this variable, as documented
-     * in {@link Convention#nameOfDimension(Variable, int)} javadoc.
+     * The grid associated to this variable, or {@code null} if none or not yet computed.
+     * The grid needs to be computed if {@link #gridDetermined} is {@code false}.
      *
-     * <p>Some values in this array may be {@link Double#NaN} if the {@code "resampling_interval"} attribute
-     * was not found.</p>
+     * @see #gridDetermined
+     * @see #getGridGeometry()
      */
-    private double[] gridToDataIndices;
+    private GridGeometry gridGeometry;
+
+    /**
+     * Whether {@link #gridGeometry} has been computed. Note that the result may still be {@code null}.
+     *
+     * @see #gridGeometry
+     * @see #getGridGeometry()
+     */
+    private boolean gridDetermined;
 
     /**
      * Creates a new variable.
@@ -319,16 +325,168 @@ public abstract class Variable extends NamedElement {
     protected abstract boolean isCoordinateSystemAxis();
 
     /**
+     * Contains information computed together with {@link Variable#getGrid(Adjustment)} but are still specific to
+     * the enclosing variable. Those information are kept in a class separated from {@link Grid} because the same
+     * {@code Grid} instance may apply to many variables while {@code Adjustment} may contain amendments that are
+     * specific to a particular {@link Variable} instance.
+     *
+     * <p>An instance of this class is created by {@link #getGridGeometry()} and updated by {@link #getGrid(Adjustment)}.
+     * Subclasses of {@link Variable} do not need to know the details of this class; they just need to pass it verbatim
+     * to their parent class.</p>
+     */
+    protected static final class Adjustment {
+        /**
+         * Factors by which to multiply a grid index in order to get the corresponding data index, or {@code null} if none.
+         * This is usually null, meaning that there is an exact match between grid indices and data indices. This array may
+         * be non-null if the localization grid has shorter dimensions than the dimensions of the variable, as documented
+         * in {@link Convention#nameOfDimension(Variable, int)} javadoc.
+         *
+         * <p>This array may be created by {@link #getGrid(Adjustment)} and is consumed by {@link #getGridGeometry()}.
+         * Some values in this array may be {@link Double#NaN} if the {@code "resampling_interval"} attribute was not found.
+         * This array may be longer than necessary.</p>
+         *
+         * @see #dataToGridIndices()
+         */
+        private double[] gridToDataIndices;
+
+        /**
+         * Only {@link Variable#getGridGeometry()} should instantiate this class.
+         */
+        private Adjustment() {
+        }
+
+        /**
+         * Builds a map of "dimension labels" to the actual {@link Dimension} instances of the grid.
+         * The dimension labels are not the dimension names, but some other convention-dependent identifiers.
+         * The mechanism is documented in {@link Convention#nameOfDimension(Variable, int)}.
+         * For example given a file with the following netCDF variables:
+         *
+         * {@preformat text
+         *     float Latitude(grid_y, grid_x)
+         *       dim0 = "Line grids"
+         *       dim1 = "Pixel grids"
+         *       resampling_interval = 10
+         *     float Longitude(grid_y, grid_x)
+         *       dim0 = "Line grids"
+         *       dim1 = "Pixel grids"
+         *       resampling_interval = 10
+         *     ushort SST(data_y, data_x)
+         *       dim0 = "Line grids"
+         *       dim1 = "Pixel grids"
+         * }
+         *
+         * this method will add the following entries in the {@code toGridDimensions} map, provided that
+         * the dimensions are not already keys in that map:
+         *
+         * {@preformat text
+         *     "Line grids"   →  Dimension[grid_x]
+         *     "Pixel grids"  →  Dimension[grid_y]
+         * }
+         *
+         * @param  variable          the variable for which a "label to grid dimensions" mapping is desired.
+         * @param  axes              all axes in the netCDF file (not only the variable axes).
+         * @param  toGridDimensions  in input, the dimensions to accept. In output, "label → grid dimension" entries.
+         * @param  convention        convention for getting dimension labels.
+         * @return {@code true} if the {@code Variable.getGrid(…)} caller should abort.
+         *
+         * @see Convention#nameOfDimension(Variable, int)
+         */
+        boolean mapLabelToGridDimensions(final Variable variable, final List<Variable> axes,
+                final Map<Object,Dimension> toGridDimensions, final Convention convention)
+        {
+            final Set<Dimension> requestedByConvention = new HashSet<>();                       // Only in case of ambiguities.
+            final String[] namesOfAxisVariables = convention.namesOfAxisVariables(variable);    // Only in case of ambiguities.
+            for (final Variable axis : axes) {
+                final boolean isRequested = ArraysExt.containsIgnoreCase(namesOfAxisVariables, axis.getName());
+                final List<Dimension> candidates = axis.getGridDimensions();
+                for (int j=candidates.size(); --j >= 0;) {
+                    final Dimension dim = candidates.get(j);
+                    if (toGridDimensions.containsKey(dim)) {
+                        /*
+                         * Found a dimension that has not already be taken by the 'dimensions' array.
+                         * If this dimension has a name defined by an attribute like "Dim0" or "Dim1",
+                         * make this dimension available for consideration by 'dimensions[i] = …' later.
+                         */
+                        final String name = convention.nameOfDimension(axis, j);
+                        if (name != null) {
+                            if (gridToDataIndices == null) {
+                                gridToDataIndices = new double[axes.size()];    // Conservatively use longest possible length.
+                            }
+                            gridToDataIndices[j] = convention.gridToDataIndices(axis);
+                            final boolean overwrite = isRequested && requestedByConvention.add(dim);
+                            final Dimension previous = toGridDimensions.put(name, dim);
+                            if (previous != null && !previous.equals(dim)) {
+                                /*
+                                 * The same name maps to two different dimensions. Given the ambiguity, we should give up.
+                                 * However we make an exception if only one dimension is part of a variable that has been
+                                 * explicitly requested. We identify this disambiguation in the following ways:
+                                 *
+                                 *   isRequested = true   →  ok if overwrite = true  →  keep the newly added dimension.
+                                 *   isRequested = false  →  if was previously in requestedByConvention, restore previous.
+                                 */
+                                if (!overwrite) {
+                                    if (!isRequested && requestedByConvention.contains(dim)) {
+                                        toGridDimensions.put(name, previous);
+                                    } else {
+                                        // Variable.getGridGeometry() is (indirectly) the caller of this method.
+                                        variable.error(Variable.class, "getGridGeometry", null, Errors.Keys.DuplicatedIdentifier_1, name);
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns the factors by which to multiply a data index in order to get the corresponding grid index,
+         * or {@code null} if none. This array may be non-null if the localization grid has shorter dimensions
+         * than the ones of the variable (see {@link #mapLabelToGridDimensions mapLabelToGridDimensions(…)}).
+         * Caller needs to verify that the returned array, if non-null, is long enough.
+         */
+        double[] dataToGridIndices() {
+            double[] dataToGridIndices = null;
+            if (gridToDataIndices != null) {
+                for (int i=gridToDataIndices.length; --i >= 0;) {
+                    final double s = gridToDataIndices[i];
+                    if (s > 0 && s != Double.POSITIVE_INFINITY) {
+                        if (dataToGridIndices == null) {
+                            dataToGridIndices = new double[i + 1];
+                        }
+                        dataToGridIndices[i] = 1 / s;
+                    } else {
+                        dataToGridIndices = null;
+                        // May return a shorter array.
+                    }
+                }
+            }
+            return dataToGridIndices;
+        }
+    }
+
+    /**
      * Returns a builder for the grid geometry of this variable, or {@code null} if this variable is not a data cube.
      * Not all variables have a grid geometry. For example collections of features do not have such grid.
-     * The same grid geometry may be shared by many variables.
-     * The default implementation searches for a grid in the following ways:
+     * This method should be invoked only once per variable, but the same builder may be returned by different variables.
+     * The grid may have fewer {@linkplain Grid#getDimensions() dimensions} than this variable,
+     * in which case the additional {@linkplain #getGridDimensions() variable dimensions} can be considered as bands.
+     * The dimensions of the grid may have different {@linkplain Dimension#length() lengths} than the dimensions of
+     * this variable, in which case {@link #getGridGeometry()} is responsible for concatenating a scale factor to the
+     * "grid to CRS" transform.
+     *
+     * <p>The default implementation provided in this {@code Variable} base class could be sufficient, but subclasses
+     * are encouraged to override with a more efficient implementation or by exploiting information not available to this
+     * base class (for example UCAR {@link ucar.nc2.dataset.CoordinateSystem} objects) and invoke {@code super.getGrid(…)}
+     * as a fallback. The default implementation tries to build a grid in the following ways:</p>
      *
      * <ol class="verbose">
      *   <li><b>Grid of same dimension than this variable:</b>
      *     iterate over {@linkplain Decoder#getGrids() all localization grids} and search for an element having the
      *     same dimensions than this variable, i.e. where {@link Grid#getDimensions()} contains the same elements
-     *     than {@link #getGridDimensions()} (not necessarily in the same order). The {@link Grid#derive(Dimension[])}
+     *     than {@link #getGridDimensions()} (not necessarily in the same order). The {@link Grid#forDimensions(Dimension[])}
      *     method will be invoked for reordering dimensions in the right order.</li>
      *
      *   <li><b>Grid of different dimension than this variable:</b>
@@ -342,17 +500,19 @@ public abstract class Variable extends NamedElement {
      *     but rather the value of some {@code "dim"} attribute. If this method can map all dimensions of this variable to
      *     dimensions of a grid, then that grid is returned.</li>
      *
-     *   <li>If a mapping can not be established for all dimensions, this method return {@code null}.</li>
+     *   <li>If a mapping can not be established for all dimensions, this method returns {@code null}.</li>
      * </ol>
      *
      * Subclasses should override this class with a more direct implementation and invoke this implementation only as a fallback.
      * Typically, subclasses will handle case #1 in above list and this implementation is invoked for case #2.
+     * This method should be invoked only once, so subclasses do not need to cache the value.
      *
+     * @param  adjustment  subclasses shall ignore and pass verbatim to {@code super.getGrid(adjustment)}.
      * @return the grid geometry for this variable, or {@code null} if none.
      * @throws IOException if an error occurred while reading the data.
      * @throws DataStoreException if a logical error occurred.
      */
-    protected Grid getGrid() throws IOException, DataStoreException {
+    protected Grid getGrid(final Adjustment adjustment) throws IOException, DataStoreException {
         final Convention convention = decoder.convention();
         /*
          * Collect all axis dimensions, in no particular order. We use this map for determining
@@ -389,84 +549,60 @@ public abstract class Variable extends NamedElement {
          */
         if (isIncomplete) {
             for (int i=0; i<dimensions.length; i++) {
-                if (dimensions[i] != null) {
-                    continue;
-                }
-                final String label = convention.nameOfDimension(this, i);
-                if (label == null) {
-                    return null;        // No information allowing us to relate that variable dimension to a grid dimension.
-                }
-                /*
-                 * The first time that we find a label that may allow us to associate this variable dimension with a
-                 * grid dimension, build a map of all labels associated to dimensions. We reuse the existing 'domain'
-                 * map; there is no confusion since the keys are not of the same class.
-                 */
-                if (isIncomplete) {
-                    isIncomplete = false;
-                    final Set<Dimension> requestedByConvention = new HashSet<>();
-                    final String[] namesOfAxisVariables = convention.namesOfAxisVariables(this);
-                    for (final Variable axis : axes) {
-                        final boolean isRequested = ArraysExt.containsIgnoreCase(namesOfAxisVariables, axis.getName());
-                        final List<Dimension> candidates = axis.getGridDimensions();
-                        for (int j=candidates.size(); --j >= 0;) {
-                            final Dimension dim = candidates.get(j);
-                            if (domain.containsKey(dim)) {
-                                /*
-                                 * Found a dimension that has not already be taken by the 'dimensions' array.
-                                 * If this dimension has a name defined by attribute (not Dimension.getName()),
-                                 * make this dimension available for consideration by 'dimensions[i] = …' later.
-                                 */
-                                final String name = convention.nameOfDimension(axis, j);
-                                if (name != null) {
-                                    if (gridToDataIndices == null) {
-                                        gridToDataIndices = new double[axes.size()];
-                                    }
-                                    gridToDataIndices[j] = convention.gridToDataIndices(axis);
-                                    final boolean overwrite = isRequested && requestedByConvention.add(dim);
-                                    final Dimension previous = domain.put(name, dim);
-                                    if (previous != null && !previous.equals(dim)) {
-                                        /*
-                                         * The same name maps to two different dimensions. Given the ambiguity, we should give up.
-                                         * However we make an exception if only one dimension is part of a variable that has been
-                                         * explicitly requested. We identify this disambiguation in the following ways:
-                                         *
-                                         *   isRequested = true   →  ok if overwrite = true  →  keep the newly added dimension.
-                                         *   isRequested = false  →  if was previously in requestedByConvention, restore previous.
-                                         */
-                                        if (!overwrite) {
-                                            if (!isRequested && requestedByConvention.contains(dim)) {
-                                                domain.put(name, previous);
-                                            } else {
-                                                error(Variable.class, "getGridGeometry", null, Errors.Keys.DuplicatedIdentifier_1, name);
-                                                return null;
-                                            }
-                                        }
-                                    }
-                                }
-                            }
+                if (dimensions[i] == null) {
+                    final String label = convention.nameOfDimension(this, i);
+                    if (label == null) {
+                        return null;  // No information allowing us to relate that variable dimension to a grid dimension.
+                    }
+                    /*
+                     * The first time that we find a label that may allow us to associate this variable dimension with a
+                     * grid dimension, build a map of all labels associated to dimensions. We reuse the existing 'domain'
+                     * map; there is no confusion since the keys are not of the same class.
+                     */
+                    if (isIncomplete) {
+                        isIncomplete = false;                                           // Execute this block only once.
+                        if (adjustment.mapLabelToGridDimensions(this, axes, domain, convention)) {
+                            return null;                               // Warning message already emitted by Adjustment.
                         }
                     }
-                }
-                if ((dimensions[i] = domain.remove(label)) == null) {
-                    warning(Variable.class, "getGridGeometry",        // Caller (indirectly) for this method.
-                            Resources.Keys.CanNotRelateVariableDimension_3, getFilename(), getName(), label);
-                    return null;        // Can not to relate that variable dimension to a grid dimension.
+                    if ((dimensions[i] = domain.remove(label)) == null) {
+                        warning(Variable.class, "getGridGeometry",        // Caller (indirectly) for this method.
+                                Resources.Keys.CanNotRelateVariableDimension_3, getFilename(), getName(), label);
+                        return null;
+                    }
                 }
             }
         }
         /*
          * At this point we finished collecting all dimensions to use in the grid. Search a grid containing
-         * all those dimensions, not necessarily in the same order. The 'Grid.derive(…)' method shall return
-         * a grid with the specified order.
+         * those dimensions in the same order (the order is enforced by Grid.forDimensions(…) method call).
+         * If we find a grid meting all criterion, we return it immediately. Otherwise select a fallback in
+         * the following precedence order:
+         *
+         *   1) grid having all axes requested by the customized convention (usually there is none).
+         *   2) grid having the greatest number of dimensions.
          */
         Grid fallback = null;
+        boolean fallbackMatches = false;
+        final String[] axisNames = convention.namesOfAxisVariables(this);       // Usually null.
         for (final Grid candidate : decoder.getGrids()) {
-            final Grid grid = candidate.derive(dimensions);
+            final Grid grid = candidate.forDimensions(dimensions);
             if (grid != null) {
-                if (grid.containsAllNamedAxes(convention.namesOfAxisVariables(this))) {
-                    return grid;
-                } else if (fallback == null) {
-                    fallback = grid;
+                final int     gridDimension = grid.getSourceDimensions();
+                final boolean gridMatches   = grid.containsAllNamedAxes(axisNames);
+                if (gridMatches && gridDimension == dimensions.length) {
+                    return grid;                                                // Full match: no need to continue.
+                }
+                if (gridMatches | !fallbackMatches) {
+                    /*
+                     * If the grid contains all axes, it has precedence over previous grid unless that previous grid
+                     * also contained all axes (gridMatches == fallbackMatches). In such case we keep the grid having
+                     * the largest number of dimensions.
+                     */
+                    if (gridMatches != fallbackMatches || fallback == null || gridDimension > fallback.getSourceDimensions()) {
+                        fallbackMatches = gridMatches;
+                        fallback = grid;
+                    }
                 }
             }
         }
@@ -477,56 +613,68 @@ public abstract class Variable extends NamedElement {
      * Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
      * Not all variables have a grid geometry. For example collections of features do not have such grid.
      * The same grid geometry may be shared by many variables.
+     * The grid may have fewer {@linkplain Grid#getDimensions() dimensions} than this variable,
+     * in which case the additional {@linkplain #getGridDimensions() variable dimensions} can be considered as bands.
      *
      * @return the grid geometry for this variable, or {@code null} if none.
      * @throws IOException if an error occurred while reading the data.
      * @throws DataStoreException if a logical error occurred.
      */
     public final GridGeometry getGridGeometry() throws IOException, DataStoreException {
-        final Grid info = getGrid();
-        if (info == null) {
-            return null;
-        }
-        GridGeometry grid = info.getGridGeometry(decoder);
-        /*
-         * Compare the size of the variable with the size of the localization grid.
-         * If they do not match, then there is a scale factor between the two that
-         * needs to be applied.
-         */
-        if (grid.isDefined(GridGeometry.EXTENT)) {
-            GridExtent extent = grid.getExtent();
-            final List<Dimension> dimensions = getGridDimensions();
-            final long[] sizes = new long[dimensions.size()];
-            boolean needsResize = false;
-            for (int i=sizes.length; --i >= 0;) {
-                final int d = (sizes.length - 1) - i;               // Convert "natural order" index into netCDF index.
-                sizes[i] = dimensions.get(d).length();
-                if (!needsResize) {
-                    needsResize = (sizes[i] != extent.getSize(i));
+        if (!gridDetermined) {
+            gridDetermined = true;                      // Set first so we don't try twice in case of failure.
+            final Adjustment adjustment = new Adjustment();
+            final Grid info = getGrid(adjustment);
+            if (info != null) {
+                /*
+                 * This variable may have more dimensions than the grid. We need to reduce the list to the same
+                 * dimensions than the ones in the grid.  We can not take Grid.getDimensions() directly because
+                 * those dimensions may not have the same length (this mismatch is handled in the next block).
+                 */
+                List<Dimension> dimensions = getGridDimensions();                       // In netCDF order.
+                if (dimensions.size() > info.getSourceDimensions()) {
+                    dimensions = new ArrayList<>(dimensions);
+                    final List<Dimension> toKeep = info.getDimensions();                // Also in netCDF order.
+                    for (int i=0; i<dimensions.size(); i++) {
+                        // TODO: check for indices out of bounds.
+                        final Dimension expected = toKeep.get(i);
+                        // TODO: map grid dimention -> data dimension here.
+                        while (!expected.equals(dimensions.get(i))) {
+                            dimensions.remove(i);
+                        }
+                    }
                 }
-            }
-            if (needsResize) {
-                double[] dataToGridIndices = null;
-                if (gridToDataIndices != null) {
-                    dataToGridIndices = new double[gridToDataIndices.length];
-                    for (int i=0; i<dataToGridIndices.length; i++) {
-                        final double s = gridToDataIndices[i];
-                        if (!(s > 0)) {
+                /*
+                 * Compare the size of the variable with the size of the localization grid.
+                 * If they do not match, then there is a scale factor between the two that
+                 * needs to be applied.
+                 */
+                GridGeometry grid = info.getGridGeometry(decoder);
+                if (grid.isDefined(GridGeometry.EXTENT)) {
+                    GridExtent extent = grid.getExtent();
+                    final long[] sizes = new long[extent.getDimension()];
+                    boolean needsResize = false;
+                    for (int i=sizes.length; --i >= 0;) {
+                        final int d = (sizes.length - 1) - i;               // Convert "natural order" index into netCDF index.
+                        sizes[i] = dimensions.get(d).length();
+                        if (!needsResize) {
+                            needsResize = (sizes[i] != extent.getSize(i));
+                        }
+                    }
+                    if (needsResize) {
+                        final double[] dataToGridIndices = adjustment.dataToGridIndices();
+                        if (dataToGridIndices == null || dataToGridIndices.length < sizes.length) {
                             warning(Variable.class, "getGridGeometry", Resources.Keys.ResamplingIntervalNotFound_2, getFilename(), getName());
                             return null;
                         }
-                        dataToGridIndices[i] = 1 / s;
+                        extent = extent.resize(sizes);
+                        grid = grid.derive().resize(extent, dataToGridIndices).build();
                     }
                 }
-                extent = extent.resize(sizes);
-                grid = grid.derive().resize(extent, dataToGridIndices).build();
-                /*
-                 * Note: the 'gridToDataIndices' array was computed as a side-effect of the call to 'getGrid(decoder)'.
-                 * This is one reason why we keep the call to 'getGrid(…)' inside this 'getGridGeometry(…)' method.
-                 */
+                gridGeometry = grid;
             }
         }
-        return grid;
+        return gridGeometry;
     }
 
     /**
@@ -535,11 +683,21 @@ public abstract class Variable extends NamedElement {
      * In ISO 19123 terminology, {@link Dimension#length()} on each dimension give the upper corner
      * of the grid envelope plus one. The lower corner is always (0, 0, …, 0).
      *
-     * <p>This information is used for completing ISO 19115 metadata, providing a default implementation of
-     * {@link Convention#roleOf(Variable)} method, or for building string representation of this variable
-     * among others.</p>
-     *
-     * @return all dimension of the grid, in netCDF order (reverse of "natural" order).
+     * <div class="note"><b>Usage:</b>
+     * this information is used for completing ISO 19115 metadata, providing a default implementation of
+     * {@link Convention#roleOf(Variable)} method or for building string representation of this variable
+     * among others. Those tasks are mostly for information purpose, except if {@code Variable} subclass
+     * failed to create a grid and we must rely on {@link #getGrid(Adjustment)} default implementation.
+     * For actual georeferencing, use {@link #getGridGeometry()} instead.</div>
+     *
+     * If {@link #getGrid(Adjustment)} returns a non-null value, then the list returned by this method should
+     * contain all dimensions returned by {@link Grid#getDimensions()}. It may contain more dimension however.
+     * Those additional dimensions can be considered as bands. Furthermore the dimensions of the {@code Grid}
+     * may have a different {@linkplain Dimension#length() length} than the dimensions returned by this method.
+     * If such length mismatch exists, then {@link #getGridGeometry()} will concatenate a scale factor to
+     * the "grid to CRS" transform.
+     *
+     * @return all dimensions of this variable, in netCDF order (reverse of "natural" order).
      *
      * @see Grid#getDimensions()
      */
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
index 8eae907..46bd7ca 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
@@ -108,17 +108,19 @@ final class GridInfo extends Grid {
     }
 
     /**
-     * Returns a localization grid having the same dimensions than this grid but in a different order.
-     * This method is invoked by {@link VariableInfo#getGrid()} when the localization grids created by
-     * {@link Decoder} subclasses are not sufficient and must be tailored for a particular variable.
-     * Returns {@code null} the the given dimensions are not members of this grid.
+     * Returns {@code this} if the dimensions in this grid appear in the same order than in the given array,
+     * or {@code null} otherwise. Current implementation does not apply the dimension reordering documented
+     * in parent class because reordering should not be needed for this SIS implementation of netCDF reader.
+     * Reordering is more needed for the implementation based on UCAR library.
      */
     @Override
-    protected Grid derive(final Dimension[] dimensions) {
-        if (Arrays.equals(domain, dimensions)) {
-            return this;
+    protected Grid forDimensions(final Dimension[] dimensions) {
+        int i = 0;
+        for (Dimension required : domain) {
+            do if (i >= dimensions.length) return null;
+            while (!required.equals(dimensions[i++]));
         }
-        return null;        // Not yet implemented.
+        return this;
     }
 
     /**
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
index d2d9f09..1d58f8a 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
@@ -147,24 +147,16 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo> {
     private final DataType dataType;
 
     /**
-     * The grid geometry associated to this variable,
-     * computed by {@link ChannelDecoder#getGrids()} when first needed.
-     * May stay {@code null} if the variable is not a data cube.
+     * The grid geometry associated to this variable, computed by {@link ChannelDecoder#getGrids()} when first needed.
+     * May stay {@code null} if the variable is not a data cube. We do not need disambiguation between the case where
+     * the grid has not yet been computed and the case where the computation has been done with {@code null} result,
+     * because {@link #getGrid(Adjustment)} should be invoked only once per variable.
      *
-     * @see #getGrid()
+     * @see #getGrid(Adjustment)
      */
     GridInfo grid;
 
     /**
-     * For disambiguation of the case where {@link #grid} has been computed and the result still null.
-     * Note that {@link #grid} may be determined and non-null even if this flag is {@code false}.
-     *
-     * @see #grid
-     * @see #getGrid()
-     */
-    private transient boolean gridDetermined;
-
-    /**
      * {@code true} if this variable seems to be a coordinate system axis, as determined by comparing its name
      * with the name of all dimensions in the netCDF file. This information is computed at construction time
      * because requested more than once.
@@ -478,20 +470,19 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo> {
     }
 
     /**
-     * Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
-     * The grid geometries are opportunistically cached in {@code VariableInfo} instances after they have
-     * been computed by {@link ChannelDecoder#getGrids()}.
-     * The same grid geometry may be shared by many variables.
+     * Returns a builder for the grid geometry of this variable, or {@code null} if this variable is not a data cube.
+     * The grid geometry builders are opportunistically cached in {@code VariableInfo} instances after they have been
+     * computed by {@link ChannelDecoder#getGrids()}. This method delegates to the super-class method only if the grid
+     * requires more analysis than the one performed by {@link ChannelDecoder}.
      *
      * @see ChannelDecoder#getGrids()
      */
     @Override
-    protected Grid getGrid() throws IOException, DataStoreException {
-        if (grid == null && !gridDetermined) {
-            gridDetermined = true;                            // Set first for avoiding other attempts in case of failure.
+    protected Grid getGrid(final Adjustment adjustment) throws IOException, DataStoreException {
+        if (grid == null) {
             decoder.getGrids();                               // Force calculation of grid geometries if not already done.
             if (grid == null) {                               // May have been computed as a side-effect of decoder.getGrids().
-                grid = (GridInfo) super.getGrid();            // Non-null if grid dimensions are different than this variable.
+                grid = (GridInfo) super.getGrid(adjustment);  // Non-null if grid dimensions are different than this variable.
             }
         }
         return grid;
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
index 0beb241..767d13e 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
@@ -20,7 +20,6 @@ import java.util.List;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.HashMap;
-import java.util.Objects;
 import java.io.IOException;
 import ucar.nc2.Dimension;
 import ucar.nc2.VariableIF;
@@ -84,7 +83,7 @@ final class GridWrapper extends Grid {
     GridWrapper(final CoordinateSystem cs) {
         netcdfCS  = cs;
         domain    = cs.getDomain();
-        reordered = new HashMap<>();
+        reordered = new HashMap<>(4);               // Will typically contain 0 or 1 entry.
     }
 
     /**
@@ -99,30 +98,35 @@ final class GridWrapper extends Grid {
 
     /**
      * Returns a localization grid having the same dimensions than this grid but in a different order.
-     * This method is invoked by {@link VariableWrapper#getGrid()} when the localization grids created
-     * by {@link Decoder} subclasses are not sufficient and must be tailored for a particular variable.
-     * Returns {@code null} the the given dimensions are not members of this grid.
+     * This method is invoked by {@link VariableWrapper#getGrid} when the localization grids created
+     * by {@link DecoderWrapper} are not sufficient and must be tailored for a particular variable.
+     * Returns {@code null} if this grid contains a dimension not in the given list.
      */
     @Override
-    protected Grid derive(final org.apache.sis.internal.netcdf.Dimension[] dimensions) {
-        return derive(UnmodifiableArrayList.wrap(DimensionWrapper.unwrap(dimensions)));
+    protected Grid forDimensions(final org.apache.sis.internal.netcdf.Dimension[] dimensions) {
+        return forDimensions(UnmodifiableArrayList.wrap(DimensionWrapper.unwrap(dimensions)));
     }
 
     /**
-     * Returns a localization grid wrapping the same coordinate system than this grid but with dimensions in different order.
-     * This is the implementation of {@link #derive(org.apache.sis.internal.netcdf.Dimension[])} after the Apache SIS objects
-     * have been unwrapped into UCAR objects. Returns {@code null} the the given dimensions are not members of this grid.
+     * Implementation of {@link #forDimensions(org.apache.sis.internal.netcdf.Dimension[])} after the Apache SIS objects
+     * have been unwrapped into UCAR objects.
      *
-     * @param  dimensions  the dimensions of this grid but potentially in a different order.
-     * @return localization grid with given dimension order (may be {@code this}), or {@code null}.
+     * @param  dimensions  the desired dimensions, in order. May contain more dimensions than this grid.
+     * @return localization grid with the exact same set of dimensions than this grid (no more and no less),
+     *         but in the order specified by the given array (ignoring dimensions not in this grid).
+     *         May be {@code this} or {@code null}.
      */
-    private GridWrapper derive(final List<Dimension> dimensions) {
-        if (containsAll(dimensions, true)) {
+    private GridWrapper forDimensions(List<Dimension> dimensions) {
+        if (dimensions.size() > domain.size()) {
+            dimensions = new ArrayList<>(dimensions);
+            dimensions.retainAll(domain);
+        }
+        if (domain.equals(dimensions)) {
             return this;
         }
         return reordered.computeIfAbsent(dimensions, k -> {
             // Want same set of dimensions in different order.
-            if (containsAll(k, false)) {
+            if (domain.size() == k.size() && domain.containsAll(k)) {
                 return new GridWrapper(this, k);
             }
             return null;
@@ -139,54 +143,12 @@ final class GridWrapper extends Grid {
      */
     final GridWrapper forVariable(final VariableIF variable, final List<CoordinateSystem> systems, final String[] axisNames) {
         if (systems.contains(netcdfCS) && containsAllNamedAxes(axisNames)) {
-            return derive(variable.getDimensions());
+            return forDimensions(variable.getDimensions());
         }
         return null;
     }
 
     /**
-     * Returns {@code true} if this grid contains all given dimensions. The {@code ordered} argument
-     * specifies whether the dimensions must be in exact same order or can be in any order.
-     */
-    private boolean containsAll(List<Dimension> dimensions, final boolean ordered) {
-        final int n = domain.size();
-        if (dimensions.size() != n) {
-            return false;
-        }
-        boolean copied = false;
-next:   for (int i=n; --i >= 0;) {
-            final Dimension d1 = domain.get(i);
-            if (ordered) {
-                if (equals(d1, dimensions.get(i))) {
-                    continue;
-                }
-            } else {
-                for (int j = dimensions.size(); --j >= 0;) {
-                    if (equals(d1, dimensions.get(j))) {
-                        if (!copied) {
-                            dimensions = new ArrayList<>(dimensions);
-                            copied = true;
-                        }
-                        dimensions.remove(j);
-                        continue next;
-                    }
-                }
-            }
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns {@code true} if the given dimensions are equal, comparing only names and lengths.
-     * This is different than {@link Dimension#equals(Object)} which compares more aspects like
-     * whether the dimension are unlimited.
-     */
-    private static boolean equals(final Dimension d1, final Dimension d2) {
-        return Objects.equals(d1.getShortName(), d2.getShortName()) && d1.getLength() == d2.getLength();
-    }
-
-    /**
      * Returns a name for this grid geometry, for information purpose only.
      */
     @Override
@@ -197,6 +159,7 @@ next:   for (int i=n; --i >= 0;) {
     /**
      * Returns the number of dimensions of source coordinates in the <cite>"grid to CRS"</cite> conversion.
      * This is the number of dimensions of the <em>grid</em>.
+     * It should be equal to the size of {@link #getDimensions()} list.
      */
     @Override
     public int getSourceDimensions() {
@@ -206,7 +169,7 @@ next:   for (int i=n; --i >= 0;) {
     /**
      * Returns the number of dimensions of target coordinates in the <cite>"grid to CRS"</cite> conversion.
      * This is the number of dimensions of the <em>coordinate reference system</em>.
-     * It should be equal to the size of the array returned by {@link #getAxes(Decoder)},
+     * It should be equal to the length of the array returned by {@link #getAxes(Decoder)},
      * but caller should be robust to inconsistencies.
      */
     @Override
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
index cb3b3f5..7ef2cd1 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
@@ -81,23 +81,6 @@ final class VariableWrapper extends Variable {
     private transient Vector values;
 
     /**
-     * The grid associated to this variable, or {@code null} if none or not yet computed.
-     * The grid needs to be computed if {@link #gridDetermined} is {@code false}.
-     *
-     * @see #gridDetermined
-     * @see #getGrid()
-     */
-    private transient GridWrapper grid;
-
-    /**
-     * Whether {@link #grid} has been computed. Note that the result may still null.
-     *
-     * @see #grid
-     * @see #getGrid()
-     */
-    private transient boolean gridDetermined;
-
-    /**
      * Creates a new variable wrapping the given netCDF interface.
      */
     VariableWrapper(final Decoder decoder, VariableIF v) {
@@ -244,42 +227,52 @@ final class VariableWrapper extends Variable {
     }
 
     /**
-     * Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
-     * This method searches for a grid previously computed by {@link DecoderWrapper#getGrids()}.
-     * The same grid geometry may be shared by many variables.
+     * Returns a builder for the grid geometry of this variable, or {@code null} if this variable is not a data cube.
+     * This method searches for a grid previously computed by {@link DecoderWrapper#getGrids()}, keeping in mind that
+     * the UCAR library sometime builds {@link CoordinateSystem} instances with axes in different order than what we
+     * would expect. This method delegates to the super-class method only if the grid requires a different analysis
+     * than the one performed by UCAR library.
+     *
+     * <p>This method should be invoked by {@link #getGridGeometry()} only once.
+     * For that reason, it does not need to cache the value.</p>
      *
      * @see DecoderWrapper#getGrids()
      */
     @Override
-    protected Grid getGrid() throws IOException, DataStoreException {
-        if (!gridDetermined) {
-            gridDetermined = true;                      // Set first so we don't try twice in case of failure.
-            /*
-             * In some netCDF files, more than one grid could be associated to a variable. If the names of the
-             * variables to use as coordinate system axes have been specified, use those names for filtering.
-             * Otherwise take the first grid.
-             */
-            if (variable instanceof Enhancements) {
-                final List<CoordinateSystem> systems = ((Enhancements) variable).getCoordinateSystems();
-                if (!systems.isEmpty()) {           // For avoiding useless call to decoder.getGrids().
-                    final String[] axisNames = decoder.convention().namesOfAxisVariables(this);
-                    for (final Grid candidate : decoder.getGrids()) {
-                        grid = ((GridWrapper) candidate).forVariable(variable, systems, axisNames);
-                        if (grid != null) {
-                            return grid;
-                        }
+    protected Grid getGrid(final Adjustment adjustment) throws IOException, DataStoreException {
+        /*
+         * In some netCDF files, more than one grid could be associated to a variable. If the names of the
+         * variables to use as coordinate system axes have been specified, use those names for filtering.
+         * Otherwise no filtering is applied (which is the common case). If more than one grid fit, take
+         * the first grid having the largest number of dimensions.
+         *
+         * This block duplicates work done in super.getGrid(…), except that it focuses on the set of coordinate
+         * systems identified by UCAR for this variable while super.getGrid(…) inspects all dimensions found in
+         * the file. Note that those coordinate systems may have been set by the user.
+         */
+        if (variable instanceof Enhancements) {
+            final List<CoordinateSystem> systems = ((Enhancements) variable).getCoordinateSystems();
+            if (!systems.isEmpty()) {           // For avoiding useless call to decoder.getGrids().
+                GridWrapper grid = null;
+                final String[] axisNames = decoder.convention().namesOfAxisVariables(this);
+                for (final Grid candidate : decoder.getGrids()) {
+                    final GridWrapper ordered = ((GridWrapper) candidate).forVariable(variable, systems, axisNames);
+                    if (ordered != null && (grid == null || ordered.getSourceDimensions() > grid.getSourceDimensions())) {
+                        grid = ordered;
                     }
                 }
+                if (grid != null) {
+                    return grid;
+                }
             }
-            /*
-             * If we reach this point, we did not found a grid using the dimensions of this variable.
-             * But maybe there is a grid using other dimensions (typically with a decimation) that we
-             * can map to the variable dimension using attribute values. This mechanism is described
-             * in Convention.nameOfDimension(…).
-             */
-            grid = (GridWrapper) super.getGrid();
         }
-        return grid;
+        /*
+         * If we reach this point, we did not found a grid using the dimensions of this variable.
+         * But maybe there is a grid using other dimensions (typically with a decimation) that we
+         * can map to the variable dimension using attribute values. This mechanism is described
+         * in Convention.nameOfDimension(…).
+         */
+        return (GridWrapper) super.getGrid(adjustment);
     }
 
     /**


Mime
View raw message