Skip to content
Snippets Groups Projects
Commit c38735b7 authored by Tor-Einar Skog's avatar Tor-Einar Skog
Browse files

First version of the parser service for the Norwegian Meteorological

service's Thredds server
parent dfcf92c1
Branches
Tags
No related merge requests found
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
<no.nibio.vips.logic.weather.FIELDCLIMATE_API_PASSWORD>q22bspFVPwkaohImV21m</no.nibio.vips.logic.weather.FIELDCLIMATE_API_PASSWORD> <no.nibio.vips.logic.weather.FIELDCLIMATE_API_PASSWORD>q22bspFVPwkaohImV21m</no.nibio.vips.logic.weather.FIELDCLIMATE_API_PASSWORD>
<no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_ID>MetosDemo</no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_ID> <no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_ID>MetosDemo</no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_ID>
<no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_SECRET>aa8f4b62b72986bac7c84be78836c2c6</no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_SECRET> <no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_SECRET>aa8f4b62b72986bac7c84be78836c2c6</no.nibio.vips.logic.weather.FIELDCLIMATE_API_CLIENT_SECRET>
<no.nibio.vips.logic.weather.METNOTHREDDS_TMP_FILE_PATH>/home/treinar/prosjekter/vips/projects/2017_SpotIT/Task 3.2/</no.nibio.vips.logic.weather.METNOTHREDDS_TMP_FILE_PATH>
......
...@@ -19,8 +19,18 @@ ...@@ -19,8 +19,18 @@
<id>jitpack.io</id> <id>jitpack.io</id>
<url>https://jitpack.io</url> <url>https://jitpack.io</url>
</repository> </repository>
<repository>
<id>unidata-releases</id>
<name>Unidata Releases</name>
<url>https://artifacts.unidata.ucar.edu/content/repositories/unidata-releases/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency>
<groupId>edu.ucar</groupId>
<artifactId>cdm</artifactId>
<version>4.6.10</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.bjornharrtell</groupId> <groupId>com.github.bjornharrtell</groupId>
<!--groupId>org.wololo</groupId--> <!--groupId>org.wololo</groupId-->
......
...@@ -19,11 +19,15 @@ ...@@ -19,11 +19,15 @@
package no.nibio.vips.logic.service; package no.nibio.vips.logic.service;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
...@@ -35,6 +39,7 @@ import javax.ws.rs.PathParam; ...@@ -35,6 +39,7 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import no.nibio.vips.entity.PointWeatherObservationList;
import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.entity.WeatherObservation;
import no.nibio.vips.logic.util.SessionControllerGetter; import no.nibio.vips.logic.util.SessionControllerGetter;
import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.logic.util.SystemTime;
...@@ -46,6 +51,7 @@ import no.nibio.vips.util.weather.ParseWeatherDataException; ...@@ -46,6 +51,7 @@ import no.nibio.vips.util.weather.ParseWeatherDataException;
import no.nibio.vips.util.weather.USPestDataParser; import no.nibio.vips.util.weather.USPestDataParser;
import no.nibio.vips.util.weather.YrWeatherForecastProvider; import no.nibio.vips.util.weather.YrWeatherForecastProvider;
import no.nibio.vips.util.weather.dnmipointweb.DMIPointWebDataParser; import no.nibio.vips.util.weather.dnmipointweb.DMIPointWebDataParser;
import no.nibio.vips.util.weather.metnothredds.MetNoThreddsDataParser;
import org.jboss.resteasy.annotations.GZIP; import org.jboss.resteasy.annotations.GZIP;
/** /**
...@@ -287,4 +293,83 @@ public class WeatherProxyService { ...@@ -287,4 +293,83 @@ public class WeatherProxyService {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
} }
} }
@GET
@Path("metno/thredds/point/")
@GZIP
@Produces("application/json;charset=UTF-8")
public Response getMetNoThreddsPointData(
@QueryParam("longitude") Double longitude,
@QueryParam("latitude") Double latitude,
@QueryParam("timeZone") String timeZoneStr,
@QueryParam("startDate") String startDateStr,
@QueryParam("startTime") String startTimeStr,
@QueryParam("endDate") String endDateStr,
@QueryParam("endTime") String endTimeStr,
@QueryParam("elementMeasurementTypes") String[] elementMeasurementTypes
)
{
try
{
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH");
format.setTimeZone(timeZone);
startTimeStr = startTimeStr != null ? startTimeStr : "00";
endTimeStr = endTimeStr != null ? endTimeStr : "23";
Date startDate = format.parse(startDateStr + " " + startTimeStr);
Date endDate = format.parse(endDateStr + " " + endTimeStr);
MetNoThreddsDataParser dp = new MetNoThreddsDataParser();
List<WeatherObservation> retVal = dp.getPointData(longitude, latitude, startDate, endDate, Arrays.asList(elementMeasurementTypes));
Collections.sort(retVal);
return Response.ok().entity(retVal).build();
}
catch(ParseException pe)
{
return Response.status(Response.Status.BAD_REQUEST).entity(pe.getMessage()).build();
}
}
@GET
@Path("metno/thredds/grid/")
@GZIP
@Produces("application/json;charset=UTF-8")
public Response getMetNoThreddsGridData(
@QueryParam("north") Double north,
@QueryParam("south") Double south,
@QueryParam("east") Double east,
@QueryParam("west") Double west,
@QueryParam("timeZone") String timeZoneStr,
@QueryParam("startDate") String startDateStr,
@QueryParam("startTime") String startTimeStr,
@QueryParam("endDate") String endDateStr,
@QueryParam("endTime") String endTimeStr,
@QueryParam("elementMeasurementTypes") String[] elementMeasurementTypes
)
{
try
{
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH");
format.setTimeZone(timeZone);
startTimeStr = startTimeStr != null ? startTimeStr : "00";
endTimeStr = endTimeStr != null ? endTimeStr : "23";
Date startDate = format.parse(startDateStr + " " + startTimeStr);
Date endDate = format.parse(endDateStr + " " + endTimeStr);
MetNoThreddsDataParser dp = new MetNoThreddsDataParser();
// Creating an envelope with the given bounds
Envelope envelope = new Envelope(west, east, south, north);
GeometryFactory gf = new GeometryFactory();
List<PointWeatherObservationList> retVal = dp.getGridData(gf.toGeometry(envelope), startDate, endDate, Arrays.asList(elementMeasurementTypes));
return Response.ok().entity(retVal).build();
}
catch(ParseException pe)
{
return Response.status(Response.Status.BAD_REQUEST).entity(pe.getMessage()).build();
}
}
} }
/*
* Copyright (c) 2017 NIBIO <http://www.nibio.no/>.
*
* This file is part of VIPSLogic.
* VIPSLogic is free software: you can redistribute it and/or modify
* it under the terms of the NIBIO Open Source License as published by
* NIBIO, either version 1 of the License, or (at your option) any
* later version.
*
* VIPSLogic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* NIBIO Open Source License for more details.
*
* You should have received a copy of the NIBIO Open Source License
* along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
*
*/
package no.nibio.vips.util.weather.metnothredds;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Polygon;
import java.util.TimeZone;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import no.nibio.vips.entity.PointWeatherObservationList;
import no.nibio.vips.entity.WeatherObservation;
import no.nibio.vips.gis.SimpleWGS84Coordinate;
import no.nibio.vips.util.WeatherElements;
import no.nibio.vips.util.WeatherUtil;
import org.apache.commons.io.FileUtils;
import ucar.ma2.Array;
import ucar.ma2.ArrayDouble;
import ucar.ma2.ArrayFloat;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
/**
* Digging into the Thredds archive of the Norwegian Meteorological Institute,
* collecting
* @copyright 2017 <a href="http://www.nibio.no/">NIBIO</a>
* @author Tor-Einar Skog <tor-einar.skog@nibio.no>
*/
public class MetNoThreddsDataParser {
private final String BASE_URL = "http://thredds.met.no/thredds/";
private final String NCSS_URL = BASE_URL + "ncss/";
private final String MEPS25_PATH = "meps25detarchive/";
private final String MEPS25_FILEBASENAME = "meps_mbr0_extracted_2_5km_";
private final String NETCDF_EXT = ".nc";
private final String STANDARD_PARAMS = "?accept=netcdf&temporal=all&&horizStride=1&disableLLSubset=on&timeStride=1";
private Properties paramInfo;
private final String TMP_FILE_PATH;
private final List<String> accumulatedParams = Arrays.asList("Q0", "RR");
private final SimpleDateFormat pathFormat;
private final SimpleDateFormat fileTimeStampFormat;
private final WeatherUtil weatherUtil;
public MetNoThreddsDataParser()
{
paramInfo = new Properties();
try (InputStream in = this.getClass().getResourceAsStream("parametersources.properties")) {
paramInfo.load(in);
}
catch(IOException ex)
{
}
this.TMP_FILE_PATH = System.getProperty("no.nibio.vips.logic.weather.METNOTHREDDS_TMP_FILE_PATH");
this.weatherUtil = new WeatherUtil();
this.pathFormat = new SimpleDateFormat("yyyy/MM/dd/");
this.pathFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
this.fileTimeStampFormat = new SimpleDateFormat("yyyyMMdd'T'00'Z'");
this.fileTimeStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public List<PointWeatherObservationList> getGridData(Geometry geometry, Date dateFrom, Date dateTo, List<String> VIPSWeatherParameters)
{
Set<String> metParamNames = VIPSWeatherParameters.stream().map(
param -> paramInfo.getProperty(param)
).collect(Collectors.toSet());
List<Date> archiveDates = getArchiveDates(dateFrom, dateTo);
Collections.sort(archiveDates);
//new GeometryFactory().
Polygon gridBounds = (Polygon) geometry.getEnvelope();
System.out.println("geometryType=" + gridBounds.getGeometryType());
System.out.println("gridBounds=" + gridBounds);
Map<Coordinate, Map<Long, WeatherObservation>> tempRetVal = new HashMap<>();
archiveDates.stream().forEach(archiveDate -> {
File tmp = null;
NetcdfFile ncFile = null;
try
{
URL threddsURL = new URL(NCSS_URL + MEPS25_PATH +
this.pathFormat.format(archiveDate) +
MEPS25_FILEBASENAME +
this.fileTimeStampFormat.format(archiveDate) +
NETCDF_EXT + STANDARD_PARAMS +
"&north=" + this.getNorth(gridBounds) + "&west=" + this.getWest(gridBounds) + "&east=" + this.getEast(gridBounds) + "&south=" + this.getSouth(gridBounds) +
"&var=" + String.join(",", metParamNames) +
"&addLatLon=true");
System.out.println("URL: " + threddsURL.toString());
Long timestamp = new Date().getTime();
tmp = new File(this.TMP_FILE_PATH + timestamp + ".nc");
FileUtils.copyURLToFile(threddsURL, tmp);
ncFile = NetcdfFile.open(tmp.getAbsolutePath());
Variable time = ncFile.findVariable("time");
Array times = time.read();
Date[] timeMeasured = new Date[times.getShape()[0]];
for(int i=0; i<timeMeasured.length;i++)
{
timeMeasured[i] = new Date(times.getLong(i) * 1000);
}
// The points are in a matrix. Get the dims first
ArrayDouble.D2 longitude = (ArrayDouble.D2) ncFile.findVariable("lon").read();
ArrayDouble.D2 latitude = (ArrayDouble.D2) ncFile.findVariable("lat").read();
int[] latLonShape = longitude.getShape(); // Assuming they're identical!
Coordinate[][] coords = new Coordinate[latLonShape[0]][latLonShape[1]];
for(int y=0;y<latLonShape[0];y++)
{
for(int x=0;x<latLonShape[1];x++)
{
double lat = latitude.get(y, x);
double lon = longitude.get(y,x);
Coordinate c = new Coordinate(lon, lat);
coords[y][x] = c;
//System.out.println("lat/lon=" + lat + "/" + lon);
}
}
for(String metParamName:metParamNames)
{
String VIPSParamName = this.findVIPSParamNameFromMetParamName(metParamName);
Variable var = ncFile.findVariable(metParamName);
// All variables have the dims [time, height, y, x]. All
// variables represent only one height, and can therefore be reduced
// from 4 to three dimensions
// Assuming all weather parameters are of type "float"
ArrayFloat.D3 varArray = (ArrayFloat.D3) var.read().reduce();
// We always skip the two first timestamps, since the model needs
// a couple of hours to spin up
for(int i=2;i<timeMeasured.length;i++)
{
if(timeMeasured[i].compareTo(dateFrom) < 0 || timeMeasured[i].after(dateTo))
{
continue;
}
for(int y=0;y<latLonShape[0];y++)
{
for(int x=0;x<latLonShape[1];x++)
{
Map<Long, WeatherObservation> obsMapForPoint = tempRetVal.get(coords[y][x]);
if(obsMapForPoint == null)
{
obsMapForPoint = new HashMap<>();
tempRetVal.put(coords[y][x], obsMapForPoint);
}
Double value = new Double(varArray.get(i, y, x));
// For accumulated parameters, substract previous value in array
if(i>0 && this.accumulatedParams.contains(VIPSParamName))
{
value = value - new Double(varArray.get(i-1, y, x));
}
WeatherObservation newObs = new WeatherObservation(
timeMeasured[i],
VIPSParamName,
WeatherObservation.LOG_INTERVAL_ID_1H,
this.getConvertedValue(value, VIPSParamName)
);
obsMapForPoint.put(newObs.getValiditySignature(), newObs);
}
}
}
}
}
catch(IOException ioe)
{
}
finally {
if(ncFile != null)
{
try
{
ncFile.close();
}catch(IOException ex) {}
}
if(tmp != null)
{
tmp.delete();
}
}
});
List<PointWeatherObservationList> retVal = new ArrayList<>();
for(Coordinate c : tempRetVal.keySet())
{
Map<Long, WeatherObservation> hashedObsForPoint = tempRetVal.get(c);
List<WeatherObservation> obsList = new ArrayList(hashedObsForPoint.values());
Collections.sort(obsList);
PointWeatherObservationList obsForPoint = new PointWeatherObservationList(c,obsList);
retVal.add(obsForPoint);
}
return retVal;
}
public List<WeatherObservation> getPointData(Double longitude, Double latitude, Date dateFrom, Date dateTo, List<String> VIPSWeatherParameters)
{
Set<String> metParamNames = VIPSWeatherParameters.stream().map(
param -> paramInfo.getProperty(param)
).collect(Collectors.toSet());
List<Date> archiveDates = getArchiveDates(dateFrom, dateTo);
Collections.sort(archiveDates);
Map<Long, WeatherObservation> retVal = new HashMap<>();
archiveDates.stream().forEach(archiveDate -> {
File tmp = null;
NetcdfFile ncFile = null;
try
{
URL threddsURL = new URL(NCSS_URL + MEPS25_PATH +
this.pathFormat.format(archiveDate) +
MEPS25_FILEBASENAME +
this.fileTimeStampFormat.format(archiveDate) +
NETCDF_EXT + STANDARD_PARAMS + "&longitude=" + longitude + "&latitude=" + latitude
+ "&var=" + String.join(",", metParamNames));
System.out.println("URL: " + threddsURL.toString());
Long timestamp = new Date().getTime();
tmp = new File(this.TMP_FILE_PATH + timestamp + ".nc");
FileUtils.copyURLToFile(threddsURL, tmp);
ncFile = NetcdfFile.open(tmp.getAbsolutePath());
// Set up the array of timestamps
// Unfortunately, the time value is a Double
// Dimensions of the time array are [station, timestamp]. Since theres
// Only one station, we can reduce the array dims. The reduce() method
// Simply removes all dims with a length of 1. Handy!
ArrayDouble.D1 time = (ArrayDouble.D1) ncFile.findVariable("time").read().reduce();
int[] timeDims = time.getShape();
// Get the length of the timestamp dimension
Date[] timeMeasured = new Date[timeDims[0]];
// Iterate, create parallel array with Dates
for(int i=0;i<timeDims[0];i++)
{
timeMeasured[i] = new Date(Math.round(time.get(i) * 1000));
}
// The position variables have 1 dimension and one element. Simple!
SimpleWGS84Coordinate coordinate = new SimpleWGS84Coordinate(
((ArrayDouble.D1) ncFile.findVariable("latitude").read()).get(0),
((ArrayDouble.D1) ncFile.findVariable("longitude").read()).get(0)
);
// Can't use stream API here because the ncfile would need to be
// final and therefore not closeable in a try-finally statement
for(String metParamName:metParamNames)
{
String VIPSParamName = this.findVIPSParamNameFromMetParamName(metParamName);
Variable var = ncFile.findVariable(metParamName);
// The variables have two different dims. The variables that
// are height dependent (e.g. temperature) have [station, value, height]
// and the height independent (e.g. precipitation_amount) have
// [station, value]. Either way, all dims except value have a length
// of 1 and can be reduced.
// Assuming all weather parameters are of type "float"
try
{
ArrayFloat.D1 varArray = (ArrayFloat.D1) var.read().reduce();
// We always skip the two first timestamps, since the model needs
// a couple of hours to spin up
for(int i=2;i<timeMeasured.length;i++)
{
if(timeMeasured[i].compareTo(dateFrom) < 0 || timeMeasured[i].after(dateTo))
{
continue;
}
Double value = new Double(varArray.get(i));
// For accumulated parameters, substract previous value in array
if(i>0 && this.accumulatedParams.contains(VIPSParamName))
{
value = value - new Double(varArray.get(i-1));
}
WeatherObservation newObs = new WeatherObservation(
timeMeasured[i],
VIPSParamName,
WeatherObservation.LOG_INTERVAL_ID_1H,
this.getConvertedValue(value, VIPSParamName)
);
retVal.put(newObs.getValiditySignature(), newObs);
}
}catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
catch(IOException ioe)
{
}
finally {
if(ncFile != null)
{
try
{
ncFile.close();
}catch(IOException ex) {}
}
if(tmp != null)
{
tmp.delete();
}
}
});
return new ArrayList(retVal.values());
}
public String findVIPSParamNameFromMetParamName(String metParamName)
{
// Need to treat the Properties object as a map and search for a key that
// maps to the given met param name
Optional<Entry<Object,Object>> opt = this.paramInfo.entrySet().stream().filter(propEntry -> propEntry.getValue().equals(metParamName)).findFirst();
return opt.isPresent() ? (String) opt.get().getKey() : null;
}
/**
* Performing the correct transformations between Met params and VIPS params
* @param value
* @param VIPSParamName
* @return
*/
public double getConvertedValue(Double value, String VIPSParamName)
{
switch(VIPSParamName){
case WeatherElements.TEMPERATURE_MEAN:
case WeatherElements.TEMPERATURE_MAXIMUM:
case WeatherElements.TEMPERATURE_MINIMUM:
return this.weatherUtil.getCelciusFromKelvin(value);
case WeatherElements.RELATIVE_HUMIDITY_MEAN:
case WeatherElements.RELATIVE_HUMIDITY_INSTANTANEOUS:
return this.getPercentFromFraction(value);
case WeatherElements.PRECIPITATION:
return roundToDecimals(value, 1);
case WeatherElements.GLOBAL_RADIATION:
return Math.round(value/3600);
default:
return value;
}
}
public double getPercentFromFraction(Double value)
{
return value * 100;
}
public double roundToDecimals(Double value, Integer decimals)
{
return Math.round(value * Math.pow(10.0, decimals)) / Math.pow(10.0, decimals);
}
/**
* Provide the list of date paths in which we can find files that contain
* data for the given period
* @param dateFrom
* @param dateTo
* @return
*/
public List<Date> getArchiveDates(Date dateFrom, Date dateTo) {
Date today = new Date();
dateTo = dateTo.after(today) ? today : dateTo;
if(dateFrom.after(dateTo))
{
return null;
}
TimeZone UTC = TimeZone.getTimeZone("UTC");
// If the date is set at earlier than xx:02:00 UTC
// Going one day back in time from dateFrom, since we skip the two
// first runs of each model
Calendar cal = Calendar.getInstance(UTC);
cal.setTime(dateFrom);
if(cal.get(Calendar.HOUR_OF_DAY) < 2)
{
cal.add(Calendar.DATE, -1);
dateFrom = cal.getTime();
}
// Adjusting to UTC midnight so that the last date (dateTo) is not
// overstepped
dateFrom = this.weatherUtil.normalizeToExactDate(dateFrom, UTC);
List<Date> retVal = new ArrayList<>();
while(dateFrom.before(dateTo))
{
retVal.add(dateFrom);
cal.setTime(dateFrom);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.add(Calendar.DATE, 1);
dateFrom = cal.getTime();
}
return retVal;
}
public double getNorth(Polygon envelope)
{
return envelope.getCoordinates()[2].y;
}
public double getSouth(Polygon envelope)
{
return envelope.getCoordinates()[0].y;
}
public double getWest(Polygon envelope)
{
return envelope.getCoordinates()[0].x;
}
public double getEast(Polygon envelope)
{
return envelope.getCoordinates()[2].x;
}
}
# Copyright (c) 2017 NIBIO <http://www.nibio.no/>.
#
# This file is part of VIPSLogic.
# VIPSLogic is free software: you can redistribute it and/or modify
# it under the terms of the NIBIO Open Source License as published by
# NIBIO, either version 1 of the License, or (at your option) any
# later version.
#
# VIPSLogic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# NIBIO Open Source License for more details.
#
# You should have received a copy of the NIBIO Open Source License
# along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
#
TM=air_temperature_2m
TX=air_temperature_max
TN=air_temperature_min
UM=relative_humidity_2m
RR=precipitation_amount_acc
Q0=integral_of_surface_net_downward_shortwave_flux_wrt_time
\ No newline at end of file
/*
* Copyright (c) 2017 NIBIO <http://www.nibio.no/>.
*
* This file is part of VIPSLogic.
* VIPSLogic is free software: you can redistribute it and/or modify
* it under the terms of the NIBIO Open Source License as published by
* NIBIO, either version 1 of the License, or (at your option) any
* later version.
*
* VIPSLogic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* NIBIO Open Source License for more details.
*
* You should have received a copy of the NIBIO Open Source License
* along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
*
*/
package no.nibio.vips.util.weather.metnothredds;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import no.nibio.vips.entity.PointWeatherObservationList;
import no.nibio.vips.entity.WeatherObservation;
import no.nibio.vips.util.WeatherUtil;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author treinar
*/
public class MetNoThreddsDataParserTest {
public MetNoThreddsDataParserTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
//@Test
public void testGetGridData()
{
System.out.println("testGetGridData");
Coordinate[] coords = new Coordinate[5];
coords[0] = new Coordinate(10.31,59.91);
coords[1] = new Coordinate(11.07,59.91);
coords[2] = new Coordinate(11.07,59.52);
coords[3] = new Coordinate(10.31,59.52);
coords[4] = new Coordinate(10.31,59.91);
GeometryFactory gFac = new GeometryFactory();
Polygon pol = gFac.createPolygon(coords);
List<String> weatherParameters = Arrays.asList("TM","RR", "Q0", "TX","TN","UM");
MetNoThreddsDataParser instance = new MetNoThreddsDataParser();
Date start = new Date();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Oslo"));
cal.setTime(new Date());
//cal.add(Calendar.DATE, -2);
cal.set(Calendar.HOUR_OF_DAY, 5);
Date dateFrom = new WeatherUtil().normalizeToExactHour(cal.getTime(), TimeZone.getDefault());
cal.add(Calendar.DATE, 5);
Date dateTo = cal.getTime();
List<PointWeatherObservationList> result = instance.getGridData(pol, dateFrom, dateTo, weatherParameters);
assertNotNull(result);
Long timeSpent = new Date().getTime() - start.getTime();
System.out.println("Time spent=" + (new Double(timeSpent)/1000) + " seconds");
result.stream().forEach(mp->System.out.println(mp));
}
/**
* Test of getPointData method, of class MetNoThreddsDataParser.
*/
@Test
public void testGetPointData() {
System.out.println("getPointData");
Double longitude = 10.7946;
Double latitude = 59.6652;
List<String> weatherParameters = Arrays.asList("TM","RR", "Q0", "TX","TN","UM");
MetNoThreddsDataParser instance = new MetNoThreddsDataParser();
Date start = new Date();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Oslo"));
cal.setTime(new Date());
cal.add(Calendar.DATE, -20);
cal.set(Calendar.HOUR_OF_DAY, 1);
Date dateFrom = new WeatherUtil().normalizeToExactHour(cal.getTime(), TimeZone.getDefault());
cal.add(Calendar.DATE, 20);
Date dateTo = cal.getTime();
List<WeatherObservation> result = instance.getPointData(longitude, latitude, dateFrom, dateTo, weatherParameters);
Long timeSpent = new Date().getTime() - start.getTime();
System.out.println("Time spent=" + (new Double(timeSpent)/1000) + " seconds");
Collections.sort(result);
Long hoursIncluded = 1 + ((result.get(result.size()-1).getTimeMeasured().getTime() - result.get(0).getTimeMeasured().getTime()) / 3600000);
long expResult = weatherParameters.size() * hoursIncluded;
result.stream().forEach(obs->System.out.println(obs));
assertEquals(expResult, result.size());
assertTrue(result.size() > 10);
}
@Test
public void testFindVIPSParamNameFromMetParamName()
{
System.out.println("testFindVIPSParamNameFromMetParamName");
MetNoThreddsDataParser instance = new MetNoThreddsDataParser();
String expResult = "TM";
String result = instance.findVIPSParamNameFromMetParamName("air_temperature_2m");
assertEquals(expResult, result);
result = instance.findVIPSParamNameFromMetParamName("foo_bar_1000m");
assertNull(result);
}
@Test
public void testGetArchiveDates()
{
System.out.println("testGetArchiveDates");
MetNoThreddsDataParser instance = new MetNoThreddsDataParser();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Oslo"));
cal.setTime(new Date());
cal.add(Calendar.DATE, -2);
cal.set(Calendar.HOUR_OF_DAY, 0);
Date dateFrom = new WeatherUtil().normalizeToExactHour(cal.getTime(), TimeZone.getDefault());
cal.add(Calendar.DATE, 5);
List<Date> result = instance.getArchiveDates(dateFrom, cal.getTime());
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HHZ");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
result.stream().forEach(r->System.out.println(f.format(r)));
assertEquals(4,result.size());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment