/*
* Copyright 1998-2014 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package thredds.server.ncss.dataservice;
import java.util.ArrayList;
import java.util.List;
import ucar.ma2.Array;
import ucar.ma2.ArrayDouble;
import ucar.ma2.ArrayObject;
import ucar.ma2.DataType;
import ucar.ma2.StructureData;
import ucar.ma2.StructureDataW;
import ucar.ma2.StructureMembers;
import ucar.nc2.constants.CDM;
import ucar.nc2.dataset.CoordinateAxis1D;
import ucar.nc2.dataset.VerticalCT;
import ucar.nc2.dt.GridDataset;
import ucar.nc2.dt.GridDatatype;
import ucar.unidata.geoloc.LatLonPoint;
import ucar.unidata.geoloc.vertical.VerticalTransform;
public final class StructureDataFactory {
private static StructureDataFactory INSTANCE;
private StructureDataFactory() {
}
public static StructureDataFactory getFactory() {
if (INSTANCE == null) {
INSTANCE = new StructureDataFactory();
}
return INSTANCE;
}
public StructureData createStructureDataWithVerticalLevels(GridDataset gds, LatLonPoint point, List<String> vars, List<Double> vertLevels, int arrLen, CoordinateAxis1D zAxis) {
StructureMembers members = new StructureMembers("");
int vertLevelsLen = vertLevels.size();
int[] dimShape = new int[1];
int[] dataShape = new int[2];
int[] coordsShape = new int[3];
StructureMembers.Member timeMember = members.addMember("date", null, null, DataType.STRING, dimShape);
ArrayObject.D1 timeData = new ArrayObject.D1(String.class, arrLen);
timeMember.setDataArray(timeData);
StructureMembers.Member vertCoordMember = members.addMember("vertCoord", null, zAxis.getUnitsString(), DataType.DOUBLE, coordsShape);
ArrayDouble.D3 vertData = new ArrayDouble.D3(arrLen, vertLevelsLen, vars.size());
vertCoordMember.setDataArray(vertData);
StructureMembers.Member latMember = members.addMember("lat", null, CDM.LAT_UNITS, DataType.DOUBLE, coordsShape);
ArrayDouble.D3 latData = new ArrayDouble.D3(arrLen, vertLevelsLen, vars.size());
latMember.setDataArray(latData);
StructureMembers.Member lonMember = members.addMember("lon", null, CDM.LON_UNITS, DataType.DOUBLE, coordsShape);
ArrayDouble.D3 lonData = new ArrayDouble.D3(arrLen, vertLevelsLen, vars.size());
lonMember.setDataArray(lonData);
StructureDataW sdata = new StructureDataW(members);
sdata.setMemberData(timeMember, timeData);
sdata.setMemberData(vertCoordMember, timeData);
sdata.setMemberData(latMember, latData);
sdata.setMemberData(lonMember, lonData);
// add the grid members
for (String varName : vars) {
GridDatatype grid = gds.findGridDatatype(varName);
StructureMembers.Member m = members.addMember(grid.getVariable().getShortName(), null, grid.getUnitsString(), grid.getDataType(), dataShape);
ArrayDouble.D2 data = new ArrayDouble.D2(arrLen, vertLevelsLen);
m.setDataArray(data);
sdata.setMemberData(m, data);
}
return sdata;
}
public StructureData createStructureData(GridDataset gds, LatLonPoint point, List<String> vars, int arrLen) {
StructureMembers members = new StructureMembers("");
// int[] scalarShape = new int[0];
int[] dataShape = new int[1];
ArrayObject.D0 stnData = new ArrayObject.D0(String.class);
StructureMembers.Member timeMember = members.addMember("date", null, null, DataType.STRING, dataShape);
ArrayObject.D1 timeData = new ArrayObject.D1(String.class, arrLen);
timeMember.setDataArray(timeData);
StructureMembers.Member latMember = members.addMember("lat", null, CDM.LAT_UNITS, DataType.DOUBLE, dataShape);
ArrayDouble.D1 latData = new ArrayDouble.D1(arrLen);
latMember.setDataArray(latData);
StructureMembers.Member lonMember = members.addMember("lon", null, CDM.LON_UNITS, DataType.DOUBLE, dataShape);
ArrayDouble.D1 lonData = new ArrayDouble.D1(arrLen);
lonMember.setDataArray(lonData);
StructureDataW sdata = new StructureDataW(members);
// sdata.setMemberData(stnMember, stnData);
sdata.setMemberData(timeMember, timeData);
sdata.setMemberData(latMember, latData);
sdata.setMemberData(lonMember, lonData);
// for now, we only have one point = one station ???
String stnName = "GridPoint";
String desc = "Grid Point at lat/lon=" + point.getLatitude() + ","
+ point.getLongitude();
ucar.unidata.geoloc.Station s = new ucar.unidata.geoloc.StationImpl(
stnName, desc, "", point.getLatitude(), point.getLongitude(),
Double.NaN);
List<ucar.unidata.geoloc.Station> stnList = new ArrayList<>();
stnList.add(s);
stnData.set(stnName);
// add the grid members
for (String varName : vars) {
GridDatatype grid = gds.findGridDatatype(varName);
StructureMembers.Member m = members.addMember(grid.getVariable()
.getShortName(), null, grid.getUnitsString(), grid
.getDataType(), dataShape);
// Array data = Array.factory(grid.getDataType(), dataShape);
ArrayDouble.D1 data = new ArrayDouble.D1(arrLen);
m.setDataArray(data);
sdata.setMemberData(m, data);
}
return sdata;
}
/**
* Creates a StructureData that holds the variable values for a single time and vertical level
*/
public StructureData createSingleStructureData(GridDataset gds, LatLonPoint point, List<String> vars, boolean hasTime) {
// construct the StructureData
StructureMembers members = new StructureMembers("");
int[] scalarShape = new int[0];
StructureMembers.Member stnMember = members.addMember("station", null, null, DataType.STRING, scalarShape);
//StructureMembers.Member stnMember = members.addMember("profileId", null, null, DataType.STRING, scalarShape);
ArrayObject.D0 stnData = new ArrayObject.D0(String.class);
stnMember.setDataArray(stnData);
//StructureMembers.Member timeMember = members.addMember("date", null, null, DataType.STRING, scalarShape);
//ArrayObject.D0 timeData = new ArrayObject.D0(String.class);
//timeMember.setDataArray(timeData);
//StructureMembers.Member latMember = members.addMember("latitude", null, "degrees_north", DataType.DOUBLE, scalarShape);
//ArrayDouble.D0 latData = new ArrayDouble.D0();
//latMember.setDataArray(latData);
//StructureMembers.Member lonMember = members.addMember("longitude", null, "degrees_east", DataType.DOUBLE, scalarShape);
//ArrayDouble.D0 lonData = new ArrayDouble.D0();
//lonMember.setDataArray(lonData);
StructureDataW sdata = new StructureDataW(members);
sdata.setMemberData(stnMember, stnData);
if (hasTime) {
StructureMembers.Member timeMember = members.addMember("time", null, null, DataType.DOUBLE, scalarShape);
ArrayDouble.D0 timeData = new ArrayDouble.D0();
timeMember.setDataArray(timeData);
sdata.setMemberData(timeMember, timeData);
}
//sdata.setMemberData(latMember, latData);
//sdata.setMemberData(lonMember, lonData);
// add the grid members
for (String varName : vars) {
GridDatatype grid = gds.findGridDatatype(varName);
StructureMembers.Member m = members.addMember(grid.getVariable().getShortName(), null, grid.getUnitsString(), grid.getDataType(), scalarShape);
Array data = Array.factory(grid.getDataType(), scalarShape);
m.setDataArray(data);
sdata.setMemberData(m, data);
}
String stnName = "GridPoint";
stnData.set(stnName);
return sdata;
}
public StructureData createSingleStructureData(GridDataset gds, LatLonPoint point, List<String> vars, CoordinateAxis1D zAxis, boolean hasTime) {
int[] scalarShape = new int[0];
StructureDataW sd = (StructureDataW) createSingleStructureData(gds, point, vars, hasTime);
// add vertical
ArrayDouble.D0 zData = new ArrayDouble.D0();
StructureMembers.Member zMember = sd.getStructureMembers().addMember(zAxis.getShortName(), null, zAxis.getUnitsString(), DataType.DOUBLE, scalarShape);
zMember.setDataArray(zData);
sd.setMemberData(zMember, zData);
for (String v : vars) {
VerticalCT vct = gds.findGridByShortName(v).getCoordinateSystem().getVerticalCT();
if (vct != null) { //Variables are grouped by vertical levels, so just one vertical transform is expected.
VerticalTransform vt = gds.findGridByShortName(v).getCoordinateSystem().getVerticalTransform();
ArrayDouble.D0 vData = new ArrayDouble.D0();
StructureMembers.Member vMember = sd.getStructureMembers().addMember(vct.getName(), null, vt.getUnitString(), DataType.DOUBLE, scalarShape);
vMember.setDataArray(vData);
sd.setMemberData(vMember, vData);
}
}
return sd;
}
public StructureData createSingleStructureData(GridDataset gds, LatLonPoint point, List<String> vars, String zUnits, boolean hasTime) {
int[] scalarShape = new int[0];
StructureDataW sd = (StructureDataW) createSingleStructureData(gds, point, vars, hasTime);
// add vertical
ArrayDouble.D0 zData = new ArrayDouble.D0();
StructureMembers.Member zMember = sd.getStructureMembers().addMember("vertCoord", null, zUnits, DataType.DOUBLE, scalarShape);
zMember.setDataArray(zData);
sd.setMemberData(zMember, zData);
return sd;
}
}