org.geoserver.wcs.responses.GHRSSTWCSTest.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.wcs.responses.GHRSSTWCSTest.java

Source

/* (c) 2018 Open Source Geospatial Foundation - all rights reserved
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.wcs.responses;

import org.apache.commons.io.FileUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.CoverageView;
import org.geoserver.catalog.DimensionPresentation;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.data.test.CiteTestData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.wcs2_0.kvp.WCSKVPTestSupport;
import org.geoserver.web.netcdf.NetCDFSettingsContainer;
import org.geoserver.web.netcdf.layer.NetCDFLayerSettingsContainer;
import org.geotools.imageio.netcdf.utilities.NetCDFUtilities;
import org.junit.Assume;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import ucar.ma2.DataType;
import ucar.nc2.Attribute;
import ucar.nc2.Variable;
import ucar.nc2.dataset.NetcdfDataset;

import javax.xml.namespace.QName;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

/**
 * Base support class for NetCDF wcs tests.
 *
 * @author Daniele Romagnoli, GeoSolutions
 */
public class GHRSSTWCSTest extends WCSKVPTestSupport {

    public static QName SST = new QName(CiteTestData.WCS_URI, "sst", CiteTestData.WCS_PREFIX);

    @Override
    protected void setUpTestData(SystemTestData testData) throws Exception {
        // no extra data needed
    }

    @Override
    protected void onSetUp(SystemTestData testData) throws Exception {
        super.onSetUp(testData);
        Catalog cat = getCatalog();

        // setup the NetCDF
        testData.addRasterLayer(SST, "sst-orbit053.nc", null, null, this.getClass(), cat);

        // build a view putting toghether all bands
        CoverageStoreInfo storeInfo = cat.getCoverageStores().get(0);
        final CoverageView coverageView = buildSstView();
        final CatalogBuilder builder = new CatalogBuilder(cat);
        builder.setStore(storeInfo);
        final CoverageInfo coverageInfo = coverageView.createCoverageInfo(SST.getLocalPart(), storeInfo, builder);
        cat.add(coverageInfo);
        LayerInfo layer = builder.buildLayer(coverageInfo);
        cat.add(layer);

        // enable time
        setupRasterDimension(getLayerId(SST), ResourceInfo.TIME, DimensionPresentation.LIST, null);

        // setup GHRSST output mode
        CoverageInfo coverage = cat.getCoverageByName("wcs:sst");
        NetCDFLayerSettingsContainer settings = new NetCDFLayerSettingsContainer();
        settings.setCopyAttributes(true);
        settings.setCopyGlobalAttributes(true);
        settings.getMetadata().put(GHRSSTEncoder.SETTINGS_KEY, Boolean.TRUE);
        coverage.getMetadata().put(NetCDFSettingsContainer.NETCDFOUT_KEY, settings);
        cat.save(coverage);
    }

    private CoverageView buildSstView() {
        String[] bandNames = new String[] { "pixels_per_bin", "sea_surface_temperature", "sst_dtime",
                "quality_level", "wind_speed", "wind_speed_dtime_from_sst", "sea_ice_fraction",
                "sea_ice_fraction_dtime_from_sst", "sses_bias", "sses_standard_deviation" };

        List<CoverageView.CoverageBand> coverageBands = new ArrayList<>();
        for (int i = 0; i < bandNames.length; i++) {
            String bandName = bandNames[i];
            final CoverageView.CoverageBand band = new CoverageView.CoverageBand(
                    Arrays.asList(new CoverageView.InputCoverageBand(bandName, "0")), bandName, i,
                    CoverageView.CompositionType.BAND_SELECT);
            coverageBands.add(band);
        }
        final CoverageView coverageView = new CoverageView(SST.getLocalPart(), coverageBands);
        return coverageView;
    }

    /**
     * Test NetCDF output from a coverage view having the required GHRSST bands/variables
     */
    @Test
    public void testGHRSST() throws Exception {
        MockHttpServletResponse response = getAsServletResponse("ows?request=GetCoverage&service=WCS&version=2.0.1"
                + "&coverageid=" + getLayerId(SST).replace(":", "__") + "&format=application/x-netcdf");
        assertEquals(200, response.getStatus());
        assertEquals("application/x-netcdf", response.getContentType());

        // hope the file name structure is correct, not 100% sure 
        String contentDispostion = response.getHeader("Content-disposition");
        assertEquals("inline; filename=19121213214553-EUR-L3U_GHRSST-SSTint-AVHRR_METOP_A-v02.0-fv01.0.nc",
                contentDispostion);
        byte[] responseBytes = getBinary(response);
        File file = File.createTempFile("ghrsst", ".nc", new File("./target"));
        FileUtils.writeByteArrayToFile(file, responseBytes);
        try (NetcdfDataset dataset = NetcdfDataset.openDataset(file.getAbsolutePath(), true, null)) {
            assertNotNull(dataset);

            // check global attributes
            Map<String, Attribute> globalAttributes = getGlobalAttributeMap(dataset);
            assertNotNull(globalAttributes.get("uuid"));
            UUID.fromString(globalAttributes.get("uuid").getStringValue());
            assertNotNull(globalAttributes.get("date_created"));
            assertNotNull(globalAttributes.get("spatial_resolution"));
            // input test file is a freak that really has this resolution, as verified with gdalinfo
            // e.g. gdalinfo NETCDF:"sst-orbit053.nc":"sea_surface_temperature"
            assertEquals("179.9499969482422 degrees", globalAttributes.get("spatial_resolution").getStringValue());
            // likewise, it really has time time
            assertNotNull(globalAttributes.get("start_time"));
            assertNotNull(globalAttributes.get("time_coverage_start"));
            assertEquals("19121213T204553Z", globalAttributes.get("start_time").getStringValue());
            assertEquals("19121213T204553Z", globalAttributes.get("time_coverage_start").getStringValue());
            assertNotNull(globalAttributes.get("stop_time"));
            assertNotNull(globalAttributes.get("time_coverage_end"));
            assertEquals("19121213T204553Z", globalAttributes.get("stop_time").getStringValue());
            assertEquals("19121213T204553Z", globalAttributes.get("time_coverage_end").getStringValue());
            // and these bounds
            double EPS = 1e-3;
            assertNotNull(globalAttributes.get("northernmost_latitude"));
            assertNotNull(globalAttributes.get("southernmost_latitude"));
            assertNotNull(globalAttributes.get("westernmost_longitude"));
            assertNotNull(globalAttributes.get("easternmost_longitude"));
            assertEquals(119.925, globalAttributes.get("northernmost_latitude").getNumericValue().doubleValue(),
                    EPS);
            assertEquals(-119.925, globalAttributes.get("southernmost_latitude").getNumericValue().doubleValue(),
                    EPS);
            assertEquals(-269.925, globalAttributes.get("westernmost_longitude").getNumericValue().doubleValue(),
                    EPS);
            assertEquals(269.925, globalAttributes.get("easternmost_longitude").getNumericValue().doubleValue(),
                    EPS);
            // resolution, take 2
            assertNotNull(globalAttributes.get("geospatial_lat_units"));
            assertNotNull(globalAttributes.get("geospatial_lon_units"));
            assertEquals("degrees", globalAttributes.get("geospatial_lat_units").getStringValue());
            assertEquals("degrees", globalAttributes.get("geospatial_lon_units").getStringValue());

            // sea surface temperature
            Variable sst = dataset.findVariable("sea_surface_temperature");
            assertNotNull(sst);
            assertEquals(DataType.SHORT, sst.getDataType());
            assertNotNull(sst.findAttribute("scale_factor"));
            assertNotNull(sst.findAttribute("add_offset"));
            assertAttributeValue(sst, "comment", "Marine skin surface temperature");
            assertAttributeValue(sst, "long_name", "sea surface skin temperature");
            assertAttributeValue(sst, "standard_name", "sea_surface_skin_temperature");
            assertAttributeValue(sst, "units", "kelvin");
            assertAttributeValue(sst, "depth", "10 micrometres");

            // wind speed
            Variable windSpeed = dataset.findVariable("wind_speed");
            assertNotNull(windSpeed);
            assertEquals(DataType.BYTE, windSpeed.getDataType());
            assertNotNull(windSpeed.findAttribute("scale_factor"));
            assertNotNull(windSpeed.findAttribute("add_offset"));
            assertAttributeValue(windSpeed, "comment",
                    "Typically represents surface winds (10 meters above the sea " + "surface)");
            assertAttributeValue(windSpeed, "long_name", "wind speed");
            assertAttributeValue(windSpeed, "standard_name", "wind_speed");
            assertAttributeValue(windSpeed, "units", "m s-1");

            // enable ehancing to check values
            dataset.enhance(NetcdfDataset.getEnhanceAll());
            assertValues(dataset, "sea_surface_temperature",
                    new double[] { 301, 302, 303, 304, 305, 306, 307, 308, 309 }, 2e-3);
            assertValues(dataset, "wind_speed", new double[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 0.2);
        } finally {
            // FileUtils.deleteQuietly(file);
        }
    }

    private Map<String, Attribute> getGlobalAttributeMap(NetcdfDataset dataset) {
        return dataset.getGlobalAttributes().stream()
                .collect(Collectors.toMap(Attribute::getShortName, Function.identity()));
    }

    private void assertValues(NetcdfDataset dataset, String variableName, double[] expectedValues, double tolerance)
            throws IOException {
        Variable variable = dataset.findVariable(variableName);
        double[] values = (double[]) variable.read().copyTo1DJavaArray();
        assertArrayEquals(values, expectedValues, tolerance);
    }

    private void assertAttributeValue(Variable variable, String name, Object value) {
        Attribute attribute = variable.findAttribute(name);
        if (value == null) {
            assertNull(attribute);
        } else {
            assertNotNull(attribute);
            assertEquals(value, attribute.getValue(0));
        }
    }

    /**
     * Test NetCDF output from a coverage view having the required GHRSST bands/variables
     */
    @Test
    public void testGHRSSTSubset() throws Exception {
        // test requires NetCDF-4 native libs to be available
        Assume.assumeTrue(NetCDFUtilities.isNC4CAvailable());

        // this used to crash
        MockHttpServletResponse response = getAsServletResponse("ows?request=GetCoverage&service=WCS&version=2.0.1"
                + "&coverageid=" + getLayerId(SST).replace(":", "__") + "&subset=Long(-10,10)&subset=Lat(-10,10)"
                + "&format=application/x-netcdf4");
        assertEquals(200, response.getStatus());
        assertEquals("application/x-netcdf4", response.getContentType());
    }

}