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: More advanced support of localization grids having different dimensions than the data variable.
Date Mon, 18 Feb 2019 20:12:45 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 140595a  More advanced support of localization grids having different dimensions
than the data variable.
140595a is described below

commit 140595a60899204e8f61427413170ae2914a2e51
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Mon Feb 18 21:12:05 2019 +0100

    More advanced support of localization grids having different dimensions than the data
variable.
---
 .../org/apache/sis/internal/netcdf/Dimension.java  |   2 +-
 .../java/org/apache/sis/internal/netcdf/Grid.java  |  15 ++
 .../org/apache/sis/internal/netcdf/Variable.java   | 201 +++++++++++++--------
 .../apache/sis/internal/netcdf/impl/GridInfo.java  |  14 ++
 .../sis/internal/netcdf/impl/VariableInfo.java     |  17 +-
 .../sis/internal/netcdf/ucar/DimensionWrapper.java |  11 ++
 .../sis/internal/netcdf/ucar/GridWrapper.java      |  72 ++++++--
 .../sis/internal/netcdf/ucar/VariableWrapper.java  |  22 ++-
 8 files changed, 261 insertions(+), 93 deletions(-)

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 0923667..07db07e 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
@@ -83,7 +83,7 @@ public abstract class Dimension extends NamedElement {
      */
     @Override
     public String toString() {
-        final StringBuilder buffer = new StringBuilder(getName());
+        final StringBuilder buffer = new StringBuilder().append(getName());     // Name may
be null.
         writeLength(buffer);
         if (isUnlimited()) {
             buffer.append(" (unlimited)");
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 24928f3..ae12a62 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
@@ -105,6 +105,21 @@ 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(Decoder)} when the localization
grids created
+     * by {@link Decoder} subclasses are not sufficient and must be tailored for a particular
variable.
+     *
+     * <p>The length of the given array shall be equal to {@link #getSourceDimensions()}
and the array
+     * shall contain all elements contained in {@link #getDimensions()}. If those elements
are in same
+     * order, then this method returns {@code this}. Otherwise if a grid can not be derived
for the
+     * given dimensions, then this method returns {@code null}.</p>
+     *
+     * @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}.
+     */
+    protected abstract Grid derive(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>.
      *
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 c8b6b84..a6480c2 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
@@ -16,12 +16,15 @@
  */
 package org.apache.sis.internal.netcdf;
 
+import java.util.Set;
 import java.util.Map;
+import java.util.HashSet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Collection;
 import java.util.List;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Locale;
 import java.util.regex.Pattern;
 import java.io.IOException;
@@ -297,58 +300,39 @@ 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 default implementation searches for a grid in the following ways:
+     *
+     * <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[])}
+     *     method will be invoked for reordering dimensions in the right order.</li>
+     *
+     *   <li><b>Grid of different dimension than this variable:</b>
+     *     if no localization grid has been found above, inspect {@linkplain Decoder#getVariables()
all variables}
+     *     that may potentially be an axis for this variable even if they do not use the
same netCDF dimensions.
+     *     Grids of different dimensions may exist if the netCDF files provides a decimated
localization grid,
+     *     for example where the longitudes and latitudes variables specify the values of
only 1/10 of cells.
+     *     This method tries to map the grid dimensions to variables dimensions through the
mechanism documented in
+     *     {@link Convention#nameOfDimension(Variable, int)}. This method considers that
we have a mapping when two
+     *     dimensions have the same "name" — not the usual {@linkplain Dimension#getName()
name encoded in netCDF format},
+     *     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>
+     * </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.
      *
      * @param  decoder  the decoder to use for constructing the grid geometry if needed.
      * @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 abstract Grid getGrid(Decoder decoder) throws IOException, DataStoreException;
-
-    /**
-     * Returns the dimensions of this variable in the order they are declared in the netCDF
file.
-     * The dimensions are those of the grid, not the dimensions of the coordinate system.
-     * 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).
-     *
-     * @see Grid#getDimensions()
-     */
-    public abstract List<Dimension> getGridDimensions();
-
-    /**
-     * Returns the dimensions of the grid used with this variable, or {@code null} if it
can not be determined.
-     * Usually this is the same as {@link #getGridDimensions()} and this method does not
need to be invoked.
-     * This method is useful only if the localization grid does not use the same dimensions
than this variable.
-     * It happens if the netCDF files provides a decimated localization grid, for example
where the longitudes
-     * and latitudes variables specify the values of only 1/10 of cells.
-     *
-     * <p>This method is invoked if we failed to build a localization grid with the
usual CF-conventions.
-     * In that case, {@code axes} should list all variables that may potentially an axis
for this variable
-     * even if they do not use the same dimensions. If this method can map all dimensions
of this variable
-     * to dimensions of the given {@code axes}, then the corresponding axis dimensions are
returned in the
-     * order they would have if they were dimensions of this variable. If a mapping can not
be established
-     * for all dimensions, this method return {@code null}.</p>
-     *
-     * <p>This method considers that we have a mapping when two dimensions have the
same "name". That name
-     * is not the usual {@link Dimension#getName()} string encoded in netCDF format, but
rather the value
-     * of one of the attributes. That name is defined by {@link Convention#nameOfDimension(Variable,
int)};
-     * see its javadoc for examples.</p>
-     *
-     * @param  axes        the variables that may define axes of the grid, in no particular
order.
-     *                     This collection may contain more axes than necessary.
-     * @param  convention  the convention to use for assigning names to dimensions.
-     * @return dimensions of the grid in netCDF order, or {@code null} if some dimensions
could not be mapped.
-     *         If non-null, all dimensions come from {@code axes} variables.
-     *
-     * @see Convention#nameOfDimension(Variable, int)
-     */
-    final List<Dimension> getGridDimensions(final Collection<Variable> axes,
final Convention convention) {
+    public Grid getGrid(final Decoder decoder) throws IOException, DataStoreException {
+        final Convention convention = decoder.convention();
         /*
          * Collect all axis dimensions, in no particular order. We use this map for determining
          * if a dimension of this variable can be used as-is, without the need to search
for an
@@ -356,57 +340,124 @@ public abstract class Variable extends NamedElement {
          * the variable has a vertical or temporal axis which has not been decimated contrarily
          * to longitude and latitude axes. Note that this map is recycled later for other
use.
          */
-        final Map<Object,Dimension> domain = new HashMap<>(axes.size() * 3);
-        for (final Variable axis : axes) {
-            for (final Dimension dim : axis.getGridDimensions()) {
-                domain.put(dim, dim);
+        final List<Variable> axes = new ArrayList<>();
+        final Map<Object,Dimension> domain = new HashMap<>();
+        for (final Variable candidate : decoder.getVariables()) {
+            if (convention.roleOf(candidate) == VariableRole.AXIS) {
+                axes.add(candidate);
+                for (final Dimension dim : candidate.getGridDimensions()) {
+                    domain.put(dim, dim);
+                }
             }
         }
         /*
-         * Get all dimensions of this variable in netCDF order, then set to null the dimensions
-         * that are not a dimension of the given axes. The non-null dimensions are removed
from
-         * 'domain', so we do not try to use them twice.
+         * Get all dimensions of this variable in netCDF order, then replace them by dimensions
from an axis variable.
+         * If we are in the situation #1 documented in javadoc, 'isIncomplete' will be 'false'
after execution of this
+         * loop and all dimensions should be the same than the values returned by 'Variable.getGridDimensions()'.
          */
         boolean isIncomplete = false;
         final Dimension[] dimensions = CollectionsExt.toArray(getGridDimensions(), Dimension.class);
         for (int i=0; i<dimensions.length; i++) {
-            isIncomplete |= (dimensions[i] = domain.remove(dimensions[i])) == null;
+            isIncomplete |= ((dimensions[i] = domain.remove(dimensions[i])) == null);
         }
         /*
-         * If there is at least one variable dimension that we did not found directly in
the axes dimensions,
-         * check if we can relate two dimensions together by their name. Following code is
actually the main
-         * purpose of this method, otherwise the result is identical to 'getGridDimensions()'.
+         * If there is at least one variable dimension that we did not found directly among
axis dimensions, check if
+         * we can relate dimensions indirectly by Convention.nameOfDimension(…). This is
the situation #2 in javadoc.
+         * We do not merge this loop with above loop because we want all dimensions recognized
by situation #1 to be
+         * removed before we attempt those indirect associations.
          */
         if (isIncomplete) {
-            for (final Variable axis : axes) {
-                final List<Dimension> gd = axis.getGridDimensions();
-                for (int i=gd.size(); --i >= 0;) {
-                    final Dimension dim = gd.get(i);
-                    if (domain.containsKey(dim)) {
-                        final String name = convention.nameOfDimension(axis, i);
-                        if (name != null) {
-                            final Dimension existing = domain.put(name, dim);
-                            if (existing != null && !existing.equals(dim)) {
-                                return null;                                        // Name
collision.
+            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) {
+                                    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 {
+                                                return null;
+                                            }
+                                        }
+                                    }
+                                }
                             }
                         }
                     }
                 }
-            }
-            for (int i=0; i<dimensions.length; i++) {
-                if (dimensions[i] == null) {
-                    final String label = convention.nameOfDimension(this, i);       // May
be null.
-                    if ((dimensions[i] = domain.remove(label)) != null) {
-                        continue;
-                    }
+                if ((dimensions[i] = domain.remove(label)) == null) {
                     return null;        // Can not to relate that variable dimension to a
grid dimension.
                 }
             }
         }
-        return Arrays.asList(dimensions);
+        /*
+         * 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.
+         */
+        final List<Dimension> list = Arrays.asList(dimensions);
+        for (final Grid grid : decoder.getGrids()) {
+            final List<Dimension> cd = grid.getDimensions();
+            if (cd.size() == dimensions.length && list.containsAll(cd)) {
+                return grid.derive(dimensions);
+            }
+        }
+        return null;
     }
 
     /**
+     * Returns the dimensions of this variable in the order they are declared in the netCDF
file.
+     * The dimensions are those of the grid, not the dimensions of the coordinate system.
+     * 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).
+     *
+     * @see Grid#getDimensions()
+     */
+    public abstract List<Dimension> getGridDimensions();
+
+    /**
      * Returns the names of all attributes associated to this variable.
      *
      * @return names of all attributes associated to this variable.
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 265abd9..1079e1e 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,6 +108,20 @@ 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(Decoder)} when the localization
grids created
+     * by {@link Decoder} subclasses are not sufficient and must be tailored for a particular
variable.
+     * Returns {@code null} if a grid can not be inferred for the given dimensions.
+     */
+    @Override
+    protected Grid derive(final Dimension[] dimensions) {
+        if (Arrays.equals(domain, dimensions)) {
+            return this;
+        }
+        return null;        // Not yet implemented.
+    }
+
+    /**
      * Returns the name of the netCDF file containing this grid geometry, or {@code null}
if unknown.
      */
     private String getFilename() {
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 4c22f59..b48f028 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
@@ -157,6 +157,15 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
     GridInfo grid;
 
     /**
+     * For disambiguation of the case where {@link #grid} has been computed and the result
still null.
+     * The that {@link #grid} may be determined and non-null even if this flag is {@code
false}.
+     *
+     * @see #grid
+     * @see #getGrid(Decoder)
+     */
+    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.
@@ -475,8 +484,12 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
      */
     @Override
     public Grid getGrid(final Decoder decoder) throws IOException, DataStoreException {
-        if (grid == null) {
-            decoder.getGrids();            // Force calculation of grid geometries if not
already done.
+        if (grid == null && !gridDetermined) {
+            gridDetermined = true;                            // Set first for avoiding other
attempts in case of failure.
+            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(decoder);     // 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/DimensionWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DimensionWrapper.java
index e2949ba..74cf5a8 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DimensionWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DimensionWrapper.java
@@ -41,6 +41,17 @@ final class DimensionWrapper extends org.apache.sis.internal.netcdf.Dimension
{
     }
 
     /**
+     * Unwraps all given dimensions.
+     */
+    static Dimension[] unwrap(final org.apache.sis.internal.netcdf.Dimension[] dimensions)
{
+        final Dimension[] ncd = new Dimension[dimensions.length];
+        for (int i=0; i<ncd.length; i++) {
+            ncd[i] = ((DimensionWrapper) dimensions[i]).netcdf;
+        }
+        return ncd;
+    }
+
+    /**
      * The netCDF dimension object.
      */
     private final Dimension netcdf;
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 816faaf..fe29062 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
@@ -29,6 +29,7 @@ import ucar.nc2.dataset.CoordinateSystem;
 import org.apache.sis.internal.netcdf.Axis;
 import org.apache.sis.internal.netcdf.Grid;
 import org.apache.sis.internal.netcdf.Decoder;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.ArraysExt;
 
@@ -91,29 +92,76 @@ final class GridWrapper extends Grid {
         netcdfCS  = parent.netcdfCS;
         domain    = dimensions;
         reordered = parent.reordered;
+        assert netcdfCS.getDomain().containsAll(dimensions);
+    }
+
+    /**
+     * Returns a localization grid having the same dimensions than this grid but in a different
order.
+     * This method is invoked by {@link VariableWrapper#getGrid(Decoder)} when the localization
grids created
+     * by {@link Decoder} subclasses are not sufficient and must be tailored for a particular
variable.
+     * Returns {@code null} if a grid can not be inferred for the given dimensions.
+     */
+    @Override
+    protected Grid derive(final org.apache.sis.internal.netcdf.Dimension[] dimensions) {
+        return derive(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.
+     *
+     * @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}.
+     */
+    private GridWrapper derive(final List<Dimension> dimensions) {
+        if (domain.equals(dimensions)) {
+            return this;
+        }
+        return reordered.computeIfAbsent(dimensions, k -> {
+            // Want same set of dimensions in different order.
+            if (domain.size() == k.size() && domain.containsAll(k)) {
+                return new GridWrapper(this, k);
+            }
+            return null;
+        });
     }
 
     /**
      * Returns the grid to use for the given variable. This method is needed because the
order of dimensions declared
      * in the {@link CoordinateSystem} may not be the same order than the dimensions of the
given variable.
+     *
+     * @param  variable  the variable for which to get its grid.
+     * @param  systems   the coordinate systems of the given variable.
+     * @return grid for the given variable, or {@code null} if none.
      */
-    GridWrapper forVariable(final VariableIF variable, final List<CoordinateSystem>
cs) {
-        if (cs.contains(netcdfCS)) {
-            final List<Dimension> source = variable.getDimensions();
-            if (domain.equals(source)) {
-                return this;
-            }
-            return reordered.computeIfAbsent(source, k -> {
-                if (domain.size() == k.size() && domain.containsAll(k)) {
-                    return new GridWrapper(this, k);
-                }
-                return null;
-            });
+    final GridWrapper forVariable(final VariableIF variable, final List<CoordinateSystem>
systems, final String[] axisNames) {
+        if (systems.contains(netcdfCS) && filterForNamedAxes(axisNames)) {
+            return derive(variable.getDimensions());
         }
         return null;
     }
 
     /**
+     * Returns {@code true} if this grid contains all axes having the specified names. This
is used for filtering
+     * coordinate systems according the names specified by {@code Convention.namesOfAxisVariables(Variable)}.
+     * If the given array is null, then no filtering is applied and this method returns {@code
true}.
+     */
+    final boolean filterForNamedAxes(final String[] axisNames) {
+        if (axisNames != null) {
+next:       for (final String name : axisNames) {
+                for (final CoordinateAxis axis : netcdfCS.getCoordinateAxes()) {
+                    if (name.equalsIgnoreCase(axis.getShortName())) {
+                        continue next;
+                    }
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns a name for this grid geometry, for information purpose only.
      */
     @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 6dad48e..eccae11 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
@@ -246,17 +246,33 @@ final class VariableWrapper extends Variable {
     public Grid getGrid(final Decoder decoder) 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.
+             */
+            final String[] axisNames = decoder.convention().namesOfAxisVariables(this); 
   // Null if no filtering.
             if (variable instanceof Enhancements) {
                 final List<CoordinateSystem> systems = ((Enhancements) variable).getCoordinateSystems();
-                if (!systems.isEmpty()) {
+                if (!systems.isEmpty()) {           // For avoiding useless call to decoder.getGrids().
                     for (final Grid candidate : decoder.getGrids()) {
-                        grid = ((GridWrapper) candidate).forVariable(variable, systems);
+                        grid = ((GridWrapper) candidate).forVariable(variable, systems, axisNames);
                         if (grid != null) {
-                            break;
+                            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(decoder);
+            if (grid != null && !grid.filterForNamedAxes(axisNames)) {
+                grid = null;
+            }
         }
         return grid;
     }


Mime
View raw message