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
No related branches found
No related tags found
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