
org.meteoinfo.data.meteodata.arl.ARLDataInfo Maven / Gradle / Ivy
/* Copyright 2012 Yaqiang Wang,
* [email protected]
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This library 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 GNU Lesser
* General Public License for more details.
*/
package org.meteoinfo.data.meteodata.arl;
import org.locationtech.proj4j.proj.Projection;
import org.meteoinfo.common.DataConvert;
import org.meteoinfo.common.MIMath;
import org.meteoinfo.common.util.GlobalUtil;
import org.meteoinfo.common.util.JDateUtil;
import org.meteoinfo.data.GridArray;
import org.meteoinfo.data.GridData;
import org.meteoinfo.data.meteodata.*;
import org.meteoinfo.ndarray.*;
import org.meteoinfo.ndarray.math.ArrayMath;
import org.meteoinfo.ndarray.util.BigDecimalUtil;
import org.meteoinfo.projection.KnownCoordinateSystems;
import org.meteoinfo.projection.ProjectionInfo;
import org.meteoinfo.projection.ProjectionNames;
import org.meteoinfo.projection.Reproject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Template
*
* @author Yaqiang Wang
*/
public class ARLDataInfo extends DataInfo implements IGridDataInfo {
//
//private FileStream _fs = null;
//private BinaryWriter _bw = null;
///
/// Is Lat/Lon
///
public Boolean isLatLon;
///
/// Projection info
///
//public ProjectionInfo projInfo;
///
/// Data head
///
public DataHead dataHead;
// ///
// /// Time list
// ///
// public List times;
///
/// Record length
///
public long recLen;
private long indexLen;
///
/// Record number per time
///
public int recsPerTime;
///
/// Variable list
///
public List> LevelVarList;
// ///
// /// Variables
// ///
// public List Variables = new ArrayList();
///
/// Level number
///
public int levelNum;
///
/// Level list
///
public List levels;
/////
///// Variable-levle list
/////
//public List varLevList;
///
/// Undefine data
///
public double missingValue;
///
/// X array
///
public double[] X;
///
/// Y array
///
public double[] Y;
///
/// Is global
///
public boolean isGlobal;
//private DataOutputStream _bw = null;
private RandomAccessFile _bw = null;
private long indexRecPos = 0;
//
//
/**
* Constructor
*/
public ARLDataInfo() {
isLatLon = false;
LevelVarList = new ArrayList<>();
levelNum = 0;
levels = new ArrayList<>();
//varLevList = new List();
missingValue = -9999;
isGlobal = false;
//projInfo = KnownCoordinateSystems.geographic.world.WGS1984;
this.meteoDataType = MeteoDataType.ARL_GRID;
}
//
//
/**
* Set X
*
* @param value X value
*/
public void setX(List value) {
this.X = new double[value.size()];
for (int i = 0; i < value.size(); i++) {
this.X[i] = value.get(i).doubleValue();
}
}
/**
* Set X
*
* @param value X value
*/
public void setY(List value) {
this.Y = new double[value.size()];
for (int i = 0; i < value.size(); i++) {
this.Y[i] = value.get(i).doubleValue();
}
}
/**
* If is large grid sizes
*
* @return Boolean
*/
public boolean isLargeGrid() {
if (this.X.length >= 1000 || this.Y.length >= 1000) {
return true;
} else {
return false;
}
}
// /**
// * Get variable name list
// *
// * @return Variable names
// */
// @Override
// public List getVariableNames() {
// List vNames = new ArrayList();
// for (Variable aVar : Variables) {
// vNames.add(aVar.getName());
// }
//
// return vNames;
// }
//
//
//
/**
* If can open as ARL data
*
* @param fileName File name
* @return Boolean
*/
public static boolean canOpen(String fileName) {
try {
RandomAccessFile br = new RandomAccessFile(fileName, "r");
DataLabel dl = readDataLabel(br);
br.close();
LocalDateTime t = dl.getTimeValue();
return t != null;
} catch (FileNotFoundException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}
/**
* Read data info
*
* @param fileName File path
*/
@Override
public void readDataInfo(String fileName) {
this.setFileName(fileName);
try {
RandomAccessFile br = new RandomAccessFile(fileName, "r");
int i, j, vNum;
String vName;
List vList = new ArrayList<>();
//open file to decode the standard label (50) plus the
//fixed portion (108) of the extended header
DataLabel aDL = readDataLabel(br);
DataHead aDH = this.readDataHead(br);
if (aDL.XGPT) {
int xn = aDL.IGC.charAt(0) - 64;
int yn = aDL.IGC.charAt(1) - 64;
aDH.NX = aDH.NX + xn * 1000;
aDH.NY = aDH.NY + yn * 1000;
}
int NXY = aDH.NX * aDH.NY;
int LEN = NXY + 50;
recLen = LEN;
int indexRecNum = 1;
indexLen = recLen;
int recNum = 0;
byte[] bytes;
if (aDH.LENH > NXY) {
bytes = new byte[NXY - 108];
br.read(bytes);
List byteList = new ArrayList<>();
for (byte b : bytes) {
byteList.add(b);
}
for (i = 0; i < 100; i++) {
aDL = readDataLabel(br);
if (!aDL.getVarName().equalsIgnoreCase("INDX")) {
break;
}
bytes = new byte[NXY];
br.read(bytes);
for (byte b : bytes) {
byteList.add(b);
}
}
indexRecNum = i + 1;
indexLen += i * recLen;
bytes = new byte[byteList.size()];
for (i = 0; i < byteList.size(); i++) {
bytes[i] = byteList.get(i);
}
byte[] nbytes;
int idx = 0;
int n;
for (i = 0; i < aDH.NZ; i++) {
n = 6;
nbytes = Arrays.copyOfRange(bytes, idx, idx + n);
idx += n;
String lstr = new String(nbytes);
levels.add(Double.parseDouble(lstr.trim()));
n = 2;
nbytes = Arrays.copyOfRange(bytes, idx, idx + n);
vNum = Integer.parseInt(new String(nbytes).trim());
idx += n;
for (j = 0; j < vNum; j++) {
n = 4;
nbytes = Arrays.copyOfRange(bytes, idx, idx + n);
idx += n;
vName = new String(nbytes).trim();
vList.add(vName);
recNum += 1;
idx += 4;
}
LevelVarList.add(new ArrayList<>(vList));
vList.clear();
}
} else {
for (i = 0; i < aDH.NZ; i++) {
bytes = new byte[6];
br.read(bytes);
String lstr = new String(bytes);
levels.add(Double.parseDouble(lstr.trim()));
bytes = new byte[2];
br.read(bytes);
vNum = Integer.parseInt(new String(bytes).trim());
bytes = new byte[4];
for (j = 0; j < vNum; j++) {
br.read(bytes);
vName = new String(bytes).trim();
vList.add(vName);
recNum += 1;
br.read(bytes);
}
LevelVarList.add(new ArrayList<>(vList));
vList.clear();
}
}
levelNum = aDH.NZ;
recsPerTime = recNum + indexRecNum;
// if (!aDL.Variable.equals("INDX")) {
// //ErrorStr = "WARNING Old format meteo data grid!" + Environment.NewLine + aDL.Variable;
// return;
// }
//Decide projection
dataHead = aDH;
if (aDH.SIZE == 0) {
isLatLon = true;
X = new double[aDH.NX];
Y = new double[aDH.NY];
double xmin = BigDecimalUtil.toDouble(aDH.SYNC_LON);
double xdelta = BigDecimalUtil.toDouble(aDH.REF_LON);
X[0] = xmin;
for (i = 1; i < aDH.NX; i++) {
X[i] = BigDecimalUtil.add(X[i-1], xdelta);
}
if (X[aDH.NX - 1] + aDH.REF_LON - X[0] == 360) {
isGlobal = true;
}
double ymin = BigDecimalUtil.toDouble(aDH.SYNC_LAT);
double ydelta = BigDecimalUtil.toDouble(aDH.REF_LAT);
Y[0] = ymin;
for (i = 1; i < aDH.NY; i++) {
Y[i] = BigDecimalUtil.add(Y[i-1], ydelta);
}
} else {
//Identify projection
isLatLon = false;
String ProjStr;
ProjectionInfo theProj;
if (aDH.POLE_LAT == 90 || aDH.POLE_LAT == -90) {
if (aDH.TANG_LAT == 90 || aDH.TANG_LAT == -90) {
ProjStr = "+proj=stere"
+ "+lat_ts=" + String.valueOf(aDH.REF_LAT)
+ "+lat_0=" + String.valueOf(aDH.TANG_LAT)
+ "+lon_0=" + String.valueOf(aDH.REF_LON + aDH.ORIENT);
} else if (aDH.TANG_LAT == 0) {
ProjStr = "+proj=merc"
+ "+lon_0=" + String.valueOf(aDH.REF_LON + aDH.ORIENT);
} else {
ProjStr = "+proj=lcc"
+ "+lat_0=" + String.valueOf(aDH.REF_LAT)
+ "+lat_1=" + String.valueOf(aDH.TANG_LAT)
+ "+lat_2=" + String.valueOf(aDH.TANG_LAT)
+ "+lon_0=" + String.valueOf(aDH.REF_LON + aDH.ORIENT);
}
} else if (aDH.TANG_LAT == 0) {
ProjStr = "+proj=tmerc"
+ "+lat_0=" + String.valueOf(aDH.POLE_LAT)
+ "+lon_0=" + String.valueOf(aDH.REF_LON + aDH.ORIENT);
} else {
ProjStr = "+proj=lcc"
+ "+lat_0=" + String.valueOf(aDH.REF_LAT)
+ "+lat_1=" + String.valueOf(aDH.TANG_LAT)
+ "+lat_2=" + String.valueOf(aDH.TANG_LAT)
+ "+lon_0=" + String.valueOf(aDH.REF_LON + aDH.ORIENT);
}
theProj = ProjectionInfo.factory(ProjStr);
this.setProjectionInfo(theProj);
//Set X Y
X = new double[aDH.NX];
Y = new double[aDH.NY];
getProjectedXY(theProj, aDH.SIZE * 1000, aDH.SYNC_XP, aDH.SYNC_YP, aDH.SYNC_LON,
aDH.SYNC_LAT, X, Y);
}
Dimension xDim = new Dimension(DimensionType.X);
xDim.setValues(X);
this.setXDimension(xDim);
this.addDimension(xDim);
Dimension yDim = new Dimension(DimensionType.Y);
yDim.setValues(Y);
this.setYDimension(yDim);
this.addDimension(yDim);
//Reopen
LocalDateTime aTime, oldTime;
int timeNum = 0;
br.seek(0);
int year = aDL.getYear();
if (year < 50) {
year = 2000 + year;
} else {
year = 1900 + year;
}
oldTime = LocalDateTime.of(year, aDL.getMonth(), aDL.getDay(), aDL.getHour(), 0, 0);
List times = new ArrayList<>();
times.add(oldTime);
int sameTimeNum = 1;
do {
if (br.getFilePointer() >= br.length() - recsPerTime * recLen) {
break;
}
//Seek to next time
br.seek(br.getFilePointer() + recsPerTime * recLen);
//Read label
aDL = readDataLabel(br);
//Rad data head
DataHead dh = this.readDataHead(br);
//Seek back
br.seek(br.getFilePointer() - 50 - 108);
aTime = LocalDateTime.of(year, aDL.getMonth(), aDL.getDay(), aDL.getHour(), dh.MN, 0);
/*if (aTime.equals(oldTime)) {
sameTimeNum += 1;
}*/
times.add(aTime);
timeNum += 1;
} while (true);
br.close();
/*//Update times
if (sameTimeNum > 1) {
int minutes = 60 / sameTimeNum;
int idx = 0;
List newTimes = new ArrayList<>();
LocalDateTime baseTime = times.get(0);
for (LocalDateTime time : times) {
if (time.equals(baseTime)) {
if (idx > 0)
time = baseTime.plusMinutes(minutes * idx);
idx += 1;
} else {
baseTime = time;
idx = 1;
}
newTimes.add(time);
}
times = newTimes;
}*/
//Set dimensions
List values = new ArrayList<>();
for (LocalDateTime t : times) {
values.add(JDateUtil.toOADate(t));
}
Dimension tDim = new Dimension(DimensionType.T);
tDim.setValues(values);
this.setTimeDimension(tDim);
this.addDimension(tDim);
Variable aVar;
vList.clear();
int varIdx;
List variables = new ArrayList<>();
for (i = 0; i < LevelVarList.size(); i++) {
for (j = 0; j < LevelVarList.get(i).size(); j++) {
vName = LevelVarList.get(i).get(j);
if (!vList.contains(vName)) {
vList.add(vName);
aVar = new Variable();
aVar.setName(vName);
aVar.setDataType(DataType.FLOAT);
aVar.addAttribute("long_name", vName);
aVar.getLevels().add(levels.get(i));
aVar.getLevelIdxs().add(i);
aVar.getVarInLevelIdxs().add(j);
variables.add(aVar);
} else {
varIdx = vList.indexOf(vName);
aVar = variables.get(varIdx);
aVar.getLevels().add(levels.get(i));
aVar.getLevelIdxs().add(i);
aVar.getVarInLevelIdxs().add(j);
//variables.set(varIdx, aVar);
}
}
}
List zdims = new ArrayList<>();
Dimension zDim;
int len;
for (Variable var : variables) {
var.setDimension(this.getTimeDimension());
len = var.getLevels().size();
if (len > 1){
zDim = null;
for (Dimension dim : zdims){
if (dim.getLength() == len){
zDim = dim;
break;
}
}
if (zDim == null){
zDim = new Dimension(DimensionType.Z);
zDim.setName("Z_" + String.valueOf(len));
zDim.setValues(var.getLevels());
zdims.add(zDim);
this.addDimension(zDim);
}
var.setDimension(zDim);
}
var.setDimension(this.getYDimension());
var.setDimension(this.getXDimension());
}
this.setTimes(times);
this.setVariables(variables);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static DataLabel readDataLabel(RandomAccessFile br) {
try {
DataLabel aDL = new DataLabel();
byte[] bytes = new byte[2];
br.read(bytes);
aDL.setYear(Short.parseShort(new String(bytes).trim()));
br.read(bytes);
aDL.setMonth(Short.parseShort(new String(bytes).trim()));
br.read(bytes);
aDL.setDay(Short.parseShort(new String(bytes).trim()));
br.read(bytes);
aDL.setHour(Short.parseShort(new String(bytes).trim()));
br.read(bytes);
aDL.setForecast(Short.parseShort(new String(bytes).trim()));
br.read(bytes);
aDL.setLevel(Short.parseShort(new String(bytes).trim()));
br.read(bytes);
String gridStr = new String(bytes).trim();
if (MIMath.isNumeric(gridStr)) {
aDL.setGrid(Short.parseShort(gridStr));
} else {
aDL.XGPT = true;
aDL.IGC = gridStr;
}
bytes = new byte[4];
br.read(bytes);
aDL.setVarName(new String(bytes).trim());
br.read(bytes);
aDL.setExponent(Integer.parseInt(new String(bytes).trim()));
bytes = new byte[14];
br.read(bytes);
aDL.setPrecision(Double.parseDouble(new String(bytes).trim()));
br.read(bytes);
aDL.setValue(Double.parseDouble(new String(bytes).trim()));
return aDL;
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
private DataHead readDataHead(RandomAccessFile br) {
try {
DataHead aDH = new DataHead();
byte[] bytes = new byte[4];
br.read(bytes);
aDH.MODEL = new String(bytes).trim();
bytes = new byte[3];
br.read(bytes);
aDH.ICX = Integer.parseInt(new String(bytes).trim());
bytes = new byte[2];
br.read(bytes);
aDH.MN = Short.parseShort(new String(bytes).trim());
bytes = new byte[7];
br.read(bytes);
aDH.POLE_LAT = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.POLE_LON = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.REF_LAT = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.REF_LON = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.SIZE = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.ORIENT = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.TANG_LAT = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.SYNC_XP = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.SYNC_YP = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.SYNC_LAT = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.SYNC_LON = Float.parseFloat(new String(bytes).trim());
br.read(bytes);
aDH.DUMMY = Float.parseFloat(new String(bytes).trim());
bytes = new byte[3];
br.read(bytes);
aDH.NX = Integer.parseInt(new String(bytes).trim());
br.read(bytes);
aDH.NY = Integer.parseInt(new String(bytes).trim());
br.read(bytes);
aDH.NZ = Integer.parseInt(new String(bytes).trim());
bytes = new byte[2];
br.read(bytes);
aDH.K_FLAG = Short.parseShort(new String(bytes).trim());
bytes = new byte[4];
br.read(bytes);
aDH.LENH = Integer.parseInt(new String(bytes).trim());
return aDH;
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
private void getProjectedXY(ProjectionInfo projInfo, float size,
float sync_XP, float sync_YP, float sync_Lon, float sync_Lat,
double[] X, double[] Y) {
//Get sync X/Y
ProjectionInfo fromProj = KnownCoordinateSystems.geographic.world.WGS1984;
double sync_X, sync_Y;
double[][] points = new double[1][];
points[0] = new double[]{new BigDecimal(String.valueOf(sync_Lon)).doubleValue(),
new BigDecimal(String.valueOf(sync_Lat)).doubleValue()};
Reproject.reprojectPoints(points, fromProj, projInfo, 0, 1);
sync_X = points[0][0];
sync_Y = points[0][1];
//Get integer sync X/Y
int i_XP, i_YP;
double i_X, i_Y;
i_XP = (int) sync_XP;
if (sync_XP == i_XP) {
i_X = sync_X;
} else {
i_X = sync_X - (sync_XP - i_XP) * size;
}
i_YP = (int) sync_YP;
if (sync_YP == i_YP) {
i_Y = sync_Y;
} else {
i_Y = sync_Y - (sync_YP - i_YP) * size;
}
//Get left bottom X/Y
int nx, ny;
nx = X.length;
ny = Y.length;
double xlb, ylb;
xlb = i_X - (i_XP - 1) * size;
ylb = i_Y - (i_YP - 1) * size;
//Get X Y with orient 0
int i;
for (i = 0; i < nx; i++) {
X[i] = xlb + i * size;
}
for (i = 0; i < ny; i++) {
Y[i] = ylb + i * size;
}
}
/**
* Get global attributes
*
* @return Global attributes
*/
@Override
public List getGlobalAttributes() {
return new ArrayList<>();
}
private double[][] unpackARLGridData(byte[] dataBytes, int xNum, int yNum, DataLabel aDL) {
double[][] gridData = new double[yNum][xNum];
double SCALE = Math.pow(2.0, (7 - aDL.getExponent()));
double VOLD = aDL.getValue();
int INDX = 0;
int i, j;
for (j = 0; j < yNum; j++) {
for (i = 0; i < xNum; i++) {
gridData[j][i] = ((int) (DataConvert.byte2Int(dataBytes[INDX])) - 127) / SCALE + VOLD;
INDX += 1;
VOLD = gridData[j][i];
}
VOLD = gridData[j][0];
}
return gridData;
}
private float[] unpackARLData(byte[] dataBytes, int xNum, int yNum, DataLabel aDL) {
int n = dataBytes.length;
float[] data = new float[n];
float SCALE = (float) Math.pow(2.0, (7 - aDL.getExponent()));
float VOLD = (float) aDL.getValue();
float init = VOLD;
float v;
int INDX = 0;
int i, j;
for (j = 0; j < yNum; j++) {
for (i = 0; i < xNum; i++) {
v = ((int) (DataConvert.byte2Int(dataBytes[INDX])) - 127) / SCALE + VOLD;
data[INDX] = v;
if (i == 0) {
init = v;
}
INDX += 1;
VOLD = v;
}
VOLD = init;
}
return data;
}
/**
* Read array data of a variable
*
* @param varName Variable name
* @return Array data
*/
@Override
public Array read(String varName) {
Variable var = this.getVariable(varName);
int n = var.getDimNumber();
int[] origin = new int[n];
int[] size = new int[n];
int[] stride = new int[n];
for (int i = 0; i < n; i++) {
origin[i] = 0;
size[i] = var.getDimLength(i);
stride[i] = 1;
}
Array r = read(varName, origin, size, stride);
return r;
}
/**
* Read array data of the variable
*
* @param varName Variable name
* @param origin The origin array
* @param size The size array
* @param stride The stride array
* @return Array data
*/
@Override
public Array read(String varName, int[] origin, int[] size, int[] stride) {
try {
Variable var = this.getVariable(varName);
Section section = new Section(origin, size, stride);
Array dataArray = Array.factory(DataType.FLOAT, section.getShape());
int rangeIdx = 0;
Range timeRange = section.getRank() > 2 ? section
.getRange(rangeIdx++)
: new Range(0, 0);
Range levRange = var.getLevelNum() > 0 ? section
.getRange(rangeIdx++)
: new Range(0, 0);
Range yRange = section.getRange(rangeIdx++);
Range xRange = section.getRange(rangeIdx);
IndexIterator ii = dataArray.getIndexIterator();
for (int timeIdx = timeRange.first(); timeIdx <= timeRange.last();
timeIdx += timeRange.stride()) {
int levelIdx = levRange.first();
for (; levelIdx <= levRange.last();
levelIdx += levRange.stride()) {
readXY(varName, timeIdx, levelIdx, yRange, xRange, ii);
}
}
return dataArray;
} catch (InvalidRangeException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
private void readXY(String varName, int timeIdx, int levelIdx, Range yRange, Range xRange, IndexIterator ii) {
try {
int varIdx = this.getVariableNames().indexOf(varName);
int xNum, yNum;
xNum = dataHead.NX;
yNum = dataHead.NY;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
//Update level and variable index
Variable aVar = this.getVariables().get(varIdx);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (int i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
br.close();
float[] data = unpackARLData(dataBytes, xNum, yNum, aDL);
for (int y = yRange.first(); y <= yRange.last();
y += yRange.stride()) {
for (int x = xRange.first(); x <= xRange.last();
x += xRange.stride()) {
int index = y * xNum + x;
ii.setFloatNext(data[index]);
}
}
} catch (FileNotFoundException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Get grid data
*
* @param varName Variable name
* @return Grid data
*/
@Override
public GridArray getGridArray(String varName) {
return null;
}
@Override
public GridData getGridData_LonLat(int timeIdx, String varName, int levelIdx) {
try {
int xNum, yNum;
xNum = dataHead.NX;
yNum = dataHead.NY;
double[][] theData;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
//Update level and variable index
Variable aVar = this.getVariable(varName);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
int varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (int i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
br.close();
theData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
return new GridData(theData, X, Y, missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_TimeLat(int lonIdx, String varName, int levelIdx) {
try {
int xNum, yNum, tNum, t;
xNum = dataHead.NX;
yNum = dataHead.NY;
tNum = this.getTimeNum();
double[][] theData;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
double[][] newGridData = new double[tNum][yNum];
//Update level and variable index
Variable aVar = this.getVariable(varName);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
int varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
for (t = 0; t < tNum; t++) {
br.seek(t * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (int i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
theData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
for (int i = 0; i < yNum; i++) {
newGridData[t][i] = theData[i][lonIdx];
}
}
br.close();
double[] yArray = new double[tNum];
for (int i = 0; i < tNum; i++) {
yArray[i] = JDateUtil.toOADate(this.getTimes().get(i));
}
return new GridData(newGridData, Y, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_TimeLon(int latIdx, String varName, int levelIdx) {
try {
int xNum, yNum, tNum, t;
xNum = dataHead.NX;
yNum = dataHead.NY;
tNum = this.getTimeNum();
double[][] theData;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
double[][] newGridData = new double[tNum][xNum];
//Update level and variable index
Variable aVar = this.getVariable(varName);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
int varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
for (t = 0; t < tNum; t++) {
br.seek(t * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (int i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
theData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
for (int j = 0; j < xNum; j++) {
newGridData[t][j] = theData[latIdx][j];
}
}
br.close();
double[] yArray = new double[tNum];
for (int i = 0; i < tNum; i++) {
yArray[i] = JDateUtil.toOADate(this.getTimes().get(i));
}
return new GridData(newGridData, X, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_LevelLat(int lonIdx, String varName, int timeIdx) {
try {
int xNum, yNum, lNum, nvarIdx, levIdx;
xNum = dataHead.NX;
yNum = dataHead.NY;
Variable var = this.getVariable(varName);
lNum = var.getLevelNum();
double[][] theData;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
double[][] newGridData = new double[lNum][yNum];
long aLevPosition;
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
aLevPosition = br.getFilePointer();
//levIdx = this.getVariables().get(varIdx).getLevelIdxs().get(0);
for (int i = 0; i < lNum; i++) {
nvarIdx = var.getVarInLevelIdxs().get(i);
levIdx = var.getLevelIdxs().get(i);
br.seek(aLevPosition);
for (int j = 0; j < levIdx; j++) {
br.seek(br.getFilePointer() + LevelVarList.get(j).size() * recLen);
}
br.seek(br.getFilePointer() + nvarIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
theData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
for (int j = 0; j < yNum; j++) {
newGridData[i][j] = theData[j][lonIdx];
}
}
br.close();
double[] yArray = new double[lNum];
for (int i = 0; i < lNum; i++) {
yArray[i] = var.getLevels().get(i);
}
return new GridData(newGridData, Y, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_LevelLon(int latIdx, String varName, int timeIdx) {
try {
int xNum, yNum, lNum, nvarIdx, levIdx;
xNum = dataHead.NX;
yNum = dataHead.NY;
Variable var = this.getVariable(varName);
lNum = var.getLevelNum();
double[][] theData;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
double[][] newGridData = new double[lNum][xNum];
long aLevPosition;
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
aLevPosition = br.getFilePointer();
//levIdx = Variables[cvarIdx].LevelIdxs[0];
for (int i = 0; i < lNum; i++) {
nvarIdx = var.getVarInLevelIdxs().get(i);
levIdx = var.getLevelIdxs().get(i);
br.seek(aLevPosition);
for (int j = 0; j < levIdx; j++) {
br.seek(br.getFilePointer() + LevelVarList.get(j).size() * recLen);
}
br.seek(br.getFilePointer() + nvarIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
theData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
for (int j = 0; j < xNum; j++) {
newGridData[i][j] = theData[latIdx][j];
}
}
br.close();
double[] yArray = new double[lNum];
for (int i = 0; i < lNum; i++) {
yArray[i] = var.getLevels().get(i);
}
return new GridData(newGridData, X, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_LevelTime(int latIdx, String varName, int lonIdx) {
try {
int xNum, yNum, lNum, nvarIdx, levIdx, t, tNum;
xNum = dataHead.NX;
yNum = dataHead.NY;
Variable var = this.getVariable(varName);
lNum = var.getLevelNum();
tNum = this.getTimeNum();
double[][] theData;
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
double[][] newGridData = new double[lNum][tNum];
long aLevPosition;
for (t = 0; t < tNum; t++) {
br.seek(t * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
aLevPosition = br.getFilePointer();
//levIdx = this.getVariables().get(varIdx).getLevelIdxs().get(0);
for (int i = 0; i < lNum; i++) {
nvarIdx = var.getVarInLevelIdxs().get(i);
levIdx = var.getLevelIdxs().get(i);
br.seek(aLevPosition);
for (int j = 0; j < levIdx; j++) {
br.seek(br.getFilePointer() + LevelVarList.get(j).size() * recLen);
}
br.seek(br.getFilePointer() + nvarIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
theData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
newGridData[i][t] = theData[latIdx][lonIdx];
}
}
br.close();
double[] xArray = new double[tNum];
for (int i = 0; i < tNum; i++) {
xArray[i] = JDateUtil.toOADate(this.getTimes().get(i));
}
double[] yArray = new double[lNum];
for (int i = 0; i < lNum; i++) {
yArray[i] = var.getLevels().get(i);
}
return new GridData(newGridData, xArray, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_Time(int lonIdx, int latIdx, String varName, int levelIdx) {
try {
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
int xNum, yNum, t;
xNum = dataHead.NX;
yNum = dataHead.NY;
double[][] gridData;
double aValue;
double[] xArray = new double[this.getTimeNum()];
double[] yArray = new double[1];
yArray[0] = 0;
double[][] data = new double[1][this.getTimeNum()];
//Update level and variable index
Variable aVar = this.getVariable(varName);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
int varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
for (t = 0; t < this.getTimeNum(); t++) {
br.seek(t * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (int i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
gridData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
aValue = gridData[latIdx][lonIdx];
xArray[t] = JDateUtil.toOADate(this.getTimes().get(t));
data[0][t] = aValue;
}
br.close();
return new GridData(data, xArray, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_Level(int lonIdx, int latIdx, String varName, int timeIdx) {
try {
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
int xNum, yNum, nvarIdx, levIdx, lNum;
xNum = dataHead.NX;
yNum = dataHead.NY;
Variable var = this.getVariable(varName);
lNum = var.getLevelNum();
double[][] gridData;
double aValue;
double[] xArray = new double[lNum];
double[] yArray = new double[1];
yArray[0] = 0;
double[][] data = new double[1][lNum];
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
long aLevPosition = br.getFilePointer();
//levIdx = this.getVariables().get(varIdx).getLevelIdxs().get(0);
for (int i = 0; i < lNum; i++) {
nvarIdx = var.getVarInLevelIdxs().get(i);
levIdx = var.getLevelIdxs().get(i);
br.seek(aLevPosition);
for (int j = 0; j < levIdx; j++) {
br.seek(br.getFilePointer() + LevelVarList.get(j).size() * recLen);
}
br.seek(br.getFilePointer() + nvarIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
gridData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
aValue = gridData[latIdx][lonIdx];
xArray[i] = levels.get(levIdx);
data[0][i] = aValue;
}
br.close();
return new GridData(data, xArray, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_Lon(int timeIdx, int latIdx, String varName, int levelIdx) {
try {
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
int xNum, yNum, i;
xNum = dataHead.NX;
yNum = dataHead.NY;
double[][] gridData;
double aValue;
double[] yArray = new double[1];
double[][] data = new double[1][X.length];
//Update level and variable index
Variable aVar = this.getVariable(varName);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
int varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
gridData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
for (i = 0; i < xNum; i++) {
aValue = gridData[latIdx][i];
data[0][i] = aValue;
}
br.close();
return new GridData(data, X, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
@Override
public GridData getGridData_Lat(int timeIdx, int lonIdx, String varName, int levelIdx) {
try {
RandomAccessFile br = new RandomAccessFile(this.getFileName(), "r");
byte[] dataBytes;
DataLabel aDL;
int xNum, yNum, i;
xNum = dataHead.NX;
yNum = dataHead.NY;
double[][] gridData;
double aValue;
double[] yArray = new double[1];
double[][] data = new double[1][Y.length];
//Update level and variable index
Variable aVar = this.getVariable(varName);
if (aVar.getLevelNum() > 1) {
levelIdx += 1;
}
int varIdx = LevelVarList.get(levelIdx).indexOf(aVar.getName());
br.seek(timeIdx * recsPerTime * recLen);
br.seek(br.getFilePointer() + indexLen);
for (i = 0; i < levelIdx; i++) {
br.seek(br.getFilePointer() + LevelVarList.get(i).size() * recLen);
}
br.seek(br.getFilePointer() + varIdx * recLen);
//Read label
aDL = ARLDataInfo.readDataLabel(br);
//Read Data
dataBytes = new byte[(int)recLen - 50];
br.read(dataBytes);
gridData = unpackARLGridData(dataBytes, xNum, yNum, aDL);
for (i = 0; i < yNum; i++) {
aValue = gridData[i][lonIdx];
data[0][i] = aValue;
}
br.close();
return new GridData(data, Y, yArray, this.missingValue);
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
//
//
/**
* Create ARL binary data file
*
* @param fileName File name
*/
public void createDataFile(String fileName) {
try {
//_bw = new DataOutputStream(new FileOutputStream(new File(fileName)));
_bw = new RandomAccessFile(fileName, "rw");
} catch (FileNotFoundException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Close the data file created by previos step
*/
public void closeDataFile() {
try {
_bw.close();
_bw = null;
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Get data header of index record
*
* @param projInfo Projection info
* @param model Data source
* @param kFlag Level flag
* @param icx Forecasting hour
* @param mn Minutes
* @return The data header
*/
public DataHead getDataHead(ProjectionInfo projInfo, String model, int kFlag, int icx, short mn) {
this.setIndexRecPos();
int i;
DataHead aDH = new DataHead();
aDH.MODEL = model;
aDH.ICX = icx;
aDH.MN = mn;
aDH.K_FLAG = (short) kFlag;
aDH.LENH = 108;
for (i = 0; i < levels.size(); i++) {
aDH.LENH += this.LevelVarList.get(i).size() * 8 + 8;
}
aDH.DUMMY = 0;
aDH.NX = X.length;
aDH.NY = Y.length;
aDH.NZ = levels.size();
if (projInfo.getProjectionName() == ProjectionNames.LongLat) {
aDH.POLE_LAT = 90;
aDH.POLE_LON = 0;
aDH.REF_LAT = (float) (Y[1] - Y[0]);
aDH.REF_LON = (float) (X[1] - X[0]);
aDH.SIZE = 0;
aDH.ORIENT = 0;
aDH.TANG_LAT = 0;
aDH.SYNC_XP = 1;
aDH.SYNC_YP = 1;
aDH.SYNC_LAT = (float) Y[0];
aDH.SYNC_LON = (float) X[0];
} else {
float sync_x, sync_y;
double sync_lon, sync_lat;
sync_x = 1;
sync_y = 1;
double x = X[0];
double y = Y[0];
double[][] points = new double[1][];
points[0] = new double[]{x, y};
ProjectionInfo toProj = KnownCoordinateSystems.geographic.world.WGS1984;
Reproject.reprojectPoints(points, projInfo, toProj, 0, 1);
sync_lon = points[0][0];
sync_lat = points[0][1];
Projection aProj = projInfo.getCoordinateReferenceSystem().getProjection();
double tanLat = this.eqvlat(aProj.getProjectionLatitude1Degrees(),
aProj.getProjectionLatitude2Degrees());
tanLat = Double.parseDouble(String.format("%.2f", tanLat));
switch (projInfo.getProjectionName()) {
case Lambert_Conformal_Conic:
aDH.POLE_LAT = (float) tanLat;
//aDH.POLE_LAT = 90;
aDH.POLE_LON = (float) aProj.getProjectionLongitudeDegrees();
//aDH.POLE_LON = 0;
//aDH.REF_LAT = (float) tanLat;
aDH.REF_LAT = (float) aProj.getProjectionLatitudeDegrees();
aDH.REF_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.SIZE = (float) (X[1] - X[0]) / 1000;
aDH.ORIENT = 0;
aDH.TANG_LAT = (float) tanLat;
aDH.SYNC_XP = sync_x;
aDH.SYNC_YP = sync_y;
aDH.SYNC_LAT = (float) sync_lat;
aDH.SYNC_LON = (float) sync_lon;
break;
case Mercator:
aDH.POLE_LAT = 0;
aDH.POLE_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.REF_LAT = (float) tanLat;
aDH.REF_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.SIZE = (float) (X[1] - X[0]) / 1000;
aDH.ORIENT = 0;
aDH.TANG_LAT = (float) tanLat;
aDH.SYNC_XP = sync_x;
aDH.SYNC_YP = sync_y;
aDH.SYNC_LAT = (float) sync_lat;
aDH.SYNC_LON = (float) sync_lon;
break;
case North_Polar_Stereographic_Azimuthal:
aDH.POLE_LAT = 90;
aDH.POLE_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.REF_LAT = (float) tanLat;
aDH.REF_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.SIZE = (float) (X[1] - X[0]) / 1000;
aDH.ORIENT = 0;
aDH.TANG_LAT = (float) aProj.getProjectionLatitude2Degrees();
aDH.SYNC_XP = sync_x;
aDH.SYNC_YP = sync_y;
aDH.SYNC_LAT = (float) sync_lat;
aDH.SYNC_LON = (float) sync_lon;
break;
case South_Polar_Stereographic_Azimuthal:
aDH.POLE_LAT = -90;
aDH.POLE_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.REF_LAT = (float) tanLat;
aDH.REF_LON = (float) aProj.getProjectionLongitudeDegrees();
aDH.SIZE = (float) (X[1] - X[0]) / 1000;
aDH.ORIENT = 0;
aDH.TANG_LAT = (float) aProj.getProjectionLatitude2Degrees();
aDH.SYNC_XP = 1;
aDH.SYNC_YP = 1;
aDH.SYNC_LAT = (float) sync_lat;
aDH.SYNC_LON = (float) sync_lon;
break;
}
}
return aDH;
}
private double eqvlat(double lat1, double lat2) {
double RADPDEG = Math.PI / 180.0;
double DEGPRAD = 180.0 / Math.PI;
double slat1, slat2, al1, al2;
slat1 = Math.sin(RADPDEG * lat1);
slat2 = Math.sin(RADPDEG * lat2);
/* reorder, slat1 larger */
if (slat1 < slat2) {
double temp = slat1;
slat1 = slat2;
slat2 = temp;
}
/* Take care of special cases first */
if (slat1 == slat2) {
return Math.asin(slat1) * DEGPRAD;
}
if (slat1 == -slat2) {
return 0.0;
}
if (slat1 >= 1.0) {
return 90.0;
}
if (slat2 <= -1.0) {
return -90.0;
}
/**
* *****************************************************
*/
double FSM = 1.0e-3;
/* Compute al1 = log((1. - slat1)/(1. - slat2))/(slat1 - slat2) */
{
double tau = (slat1 - slat2) / (2.0 - slat1 - slat2);
if (tau > FSM) {
al1 = Math.log((1.0 - slat1) / (1.0 - slat2)) / (slat1 - slat2);
} else {
tau *= tau;
al1 = -2.0 / (2.0 - slat1 - slat2)
* (1.0 + tau
* (1.0 / 3.0 + tau
* (1.0 / 5.0 + tau
* (1.0 / 7.0 + tau))));
}
}
/* Compute al2 = log((1. + slat1)/(1. + slat2))/(slat1 - slat2) */
{
double tau = (slat1 - slat2) / (2.0 + slat1 + slat2);
if (tau > FSM) {
al2 = Math.log((1.0 + slat1) / (1.0 + slat2)) / (slat1 - slat2);
} else {
tau *= tau;
al2 = 2.0 / (2.0 + slat1 + slat2)
* (1.0 + tau
* (1.0 / 3.0 + tau
* (1.0 / 5.0 + tau
* (1.0 / 7.0 + tau))));
}
}
double eqvlat = Math.asin((al1 + al2) / (al1 - al2)) * DEGPRAD;
return eqvlat;
}
private double eqvlat_bak(double lat1, double lat2) {
// WRITTEN ON 3/31/94 BY Dr. Albion Taylor NOAA / OAR / ARL
double RADPDG = Math.PI / 180.;
double SINL1 = Math.sin(lat1 * RADPDG);
double SINL2 = Math.sin(lat2 * RADPDG);
double AL1, AL2;
if (Math.abs(SINL1 - SINL2) > .001) {
AL1 = Math.log((1. - SINL1) / (1. - SINL2));
AL2 = Math.log((1. + SINL1) / (1. + SINL2));
} else {
// CASE LAT1 NEAR OR EQUAL TO LAT2
double TAU = -(SINL1 - SINL2) / (2. - SINL1 - SINL2);
TAU = TAU * TAU;
AL1 = 2. / (2. - SINL1 - SINL2) * (1. + TAU
* (1. / 3. + TAU
* (1. / 5. + TAU
* (1. / 7.))));
TAU = (SINL1 - SINL2) / (2. + SINL1 + SINL2);
TAU = TAU * TAU;
AL2 = -2. / (2. + SINL1 + SINL2) * (1. + TAU
* (1. / 3. + TAU
* (1. / 5. + TAU
* (1. / 7.))));
}
double EQVLAT = Math.asin((AL1 + AL2) / (AL1 - AL2)) / RADPDG;
return EQVLAT;
}
private String padNumStr(String str, int n) {
String nstr = str;
if (nstr.indexOf('.') < 0) {
nstr = nstr + ".";
}
if (nstr.length() > n) {
nstr = nstr.substring(0, n);
}
return GlobalUtil.padRight(nstr, n, '0');
}
/**
* Set index record position
*/
public void setIndexRecPos() {
if (_bw != null) {
try {
this.indexRecPos = this._bw.getFilePointer();
} catch (IOException ex) {
Logger.getLogger(ARLDataInfo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* Write standard data label
* @param time The time
*/
private void writeSDL(LocalDateTime time) throws IOException {
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyMMddHH");
String dateStr = format.format(time);
_bw.writeBytes(dateStr);
_bw.writeBytes("00");
_bw.writeBytes("00");
if (this.isLargeGrid()) {
String igc = this.getIGC();
_bw.writeBytes(igc);
} else {
_bw.writeBytes("99");
}
_bw.writeBytes("INDX");
_bw.writeBytes(" 0");
_bw.writeBytes(" 0.0000000E+00");
_bw.writeBytes(" 0.0000000E+00");
}
/**
* Write index record
*
* @param time The time
* @param aDH The data header
* @param ksums Checksum list
* @throws IOException
*/
public void writeIndexRecord(LocalDateTime time, DataHead aDH, List> ksums) throws IOException {
_bw.seek(this.indexRecPos);
//write the standard label (50) plus the
writeSDL(time);
//fixed portion (108) of the extended header
_bw.writeBytes(GlobalUtil.padRight(aDH.MODEL, 4, '1'));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.ICX), 3, ' '));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.MN), 2, ' '));
_bw.writeBytes(padNumStr(String.valueOf(aDH.POLE_LAT), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.POLE_LON), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.REF_LAT), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.REF_LON), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.SIZE), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.ORIENT), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.TANG_LAT), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.SYNC_XP), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.SYNC_YP), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.SYNC_LAT), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.SYNC_LON), 7));
_bw.writeBytes(padNumStr(String.valueOf(aDH.DUMMY), 7));
if (aDH.NX >= 1000){
String str = String.valueOf(aDH.NX);
str = str.substring(str.length() - 3);
_bw.writeBytes(str);
} else
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.NX), 3, ' '));
if (aDH.NY >= 1000){
String str = String.valueOf(aDH.NY);
str = str.substring(str.length() - 3);
_bw.writeBytes(str);
} else
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.NY), 3, ' '));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.NZ), 3, ' '));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.K_FLAG), 2, ' '));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDH.LENH), 4, ' '));
//Write levels and variables
String levStr, ksumStr;
ByteBuffer bb = ByteBuffer.allocate(aDH.LENH - 108);
for (int i = 0; i < aDH.NZ; i++) {
levStr = padNumStr(String.valueOf(levels.get(i)), 6);
//_bw.writeBytes(levStr);
bb.put(levStr.getBytes());
int vNum = LevelVarList.get(i).size();
//_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(vNum), 2, ' '));
bb.put(GlobalUtil.padLeft(String.valueOf(vNum), 2, ' ').getBytes());
for (int j = 0; j < vNum; j++) {
//_bw.writeBytes(GlobalUtil.padRight(LevelVarList.get(i).get(j), 4, '1'));
bb.put(GlobalUtil.padRight(LevelVarList.get(i).get(j), 4, '1').getBytes());
if (ksums == null) {
//_bw.writeBytes("226");
bb.put("226".getBytes());
} else {
ksumStr = GlobalUtil.padLeft(ksums.get(i).get(j).toString(), 3, ' ');
//_bw.writeBytes(ksumStr);
bb.put(ksumStr.getBytes());
}
//_bw.writeBytes(" ");
bb.put(" ".getBytes());
}
}
int nxy = aDH.NX * aDH.NY;
if (nxy >= aDH.LENH)
_bw.write(bb.array());
else {
byte[] bytes = bb.array();
int idx = 0;
_bw.write(Arrays.copyOfRange(bytes, idx, idx + (nxy - 108)));
idx += (nxy - 108);
while (idx < bytes.length) {
this.writeSDL(time);
_bw.write(Arrays.copyOfRange(bytes, idx, idx + nxy));
idx += nxy;
}
}
((Buffer)bb).clear();
if (nxy > aDH.LENH)
_bw.write(new byte[aDH.NY * aDH.NX - aDH.LENH]);
_bw.seek(_bw.length());
}
/**
* Write grid data
*
* @param aDL The data label
* @param gridData The grid data
* @throws IOException
*/
public void writeGridData(DataLabel aDL, GridData gridData) throws IOException {
byte[] dataBytes = packARLGridData(gridData, aDL);
//write data label
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyMMddHH");
String dateStr = format.format(aDL.getTime());
_bw.writeBytes(dateStr);
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getForecast()), 2, ' '));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getLevel()), 2, ' '));
if (aDL.XGPT){
_bw.writeBytes(aDL.IGC);
} else
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getGrid()), 2, ' '));
_bw.writeBytes(GlobalUtil.padRight(aDL.getVarName(), 4, '1'));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getExponent()), 4, ' '));
DecimalFormat dformat = new DecimalFormat("0.0000000E00");
String preStr = dformat.format(aDL.getPrecision());
if (!preStr.contains("E-")) {
preStr = preStr.replace("E", "E+");
}
_bw.writeBytes(GlobalUtil.padLeft(preStr, 14, ' '));
preStr = dformat.format(aDL.getValue());
if (!preStr.contains("E-")) {
preStr = preStr.replace("E", "E+");
}
_bw.writeBytes(GlobalUtil.padLeft(preStr, 14, ' '));
//Write data
_bw.write(dataBytes);
}
/**
* Calculate difference between the original and the packed data array.
* @param a The original array.
* @return Difference array (original - packed).
*/
public Array diffOriginPack(Array a) {
DataLabel dl = new DataLabel();
return diffOriginPack(a, dl);
}
/**
* Calculate difference between the original and the packed data array.
* @param a The original array.
* @param dl The data label.
* @return Difference array (original - packed).
*/
public Array diffOriginPack(Array a, DataLabel dl) {
Object[] p = packARLGridData(a, dl);
byte[] dataBytes = (byte[]) p[0];
int[] shape = a.getShape();
int ny = shape[0];
int nx = shape[1];
float[] up = this.unpackARLData(dataBytes, nx, ny, dl);
Array b = Array.factory(DataType.FLOAT, shape, up);
Array diff = ArrayMath.sub(a, b);
return diff;
}
/**
* Write grid data
*
* @param aDL The data label
* @param a The data array
* @return Check sum
* @throws IOException
*/
public int writeGridData(DataLabel aDL, Array a) throws IOException {
Object[] r = packARLGridData(a, aDL);
byte[] dataBytes = (byte[]) r[0];
int ksum = (int) r[1];
//write data label
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyMMddHH");
String dateStr = format.format(aDL.getTime());
_bw.writeBytes(dateStr);
String fcst = GlobalUtil.padLeft(String.valueOf(aDL.getForecast()), 2, ' ');
if (fcst.length() > 2) {
fcst = fcst.substring(fcst.length() - 2);
}
_bw.writeBytes(fcst);
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getLevel()), 2, ' '));
if (aDL.XGPT){
_bw.writeBytes(aDL.IGC);
} else {
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getGrid()), 2, ' '));
}
_bw.writeBytes(GlobalUtil.padRight(aDL.getVarName(), 4, '1'));
_bw.writeBytes(GlobalUtil.padLeft(String.valueOf(aDL.getExponent()), 4, ' '));
DecimalFormat dformat = new DecimalFormat("0.0000000E00");
String preStr = dformat.format(aDL.getPrecision());
if (!preStr.contains("E-")) {
preStr = preStr.replace("E", "E+");
}
_bw.writeBytes(GlobalUtil.padLeft(preStr, 14, ' '));
preStr = dformat.format(aDL.getValue());
if (!preStr.contains("E-")) {
preStr = preStr.replace("E", "E+");
}
_bw.writeBytes(GlobalUtil.padLeft(preStr, 14, ' '));
//Write data
_bw.write(dataBytes);
return ksum;
}
/**
* Write grid data
*
* @param time The time
* @param levelIdx The level index
* @param varName Variable name
* @param forecast The forecast hour
* @param grid The grid id
* @param gridData The grid data
* @throws IOException IOException
*/
public void writeGridData(LocalDateTime time, int levelIdx, String varName, int forecast, int grid, GridData gridData) throws IOException {
DataLabel aDL = new DataLabel(time);
aDL.setLevel(levelIdx);
aDL.setVarName(varName);
aDL.setGrid(grid);
if (this.isLargeGrid()) {
aDL.XGPT = true;
aDL.IGC = this.getIGC();
}
aDL.setForecast(forecast);
writeGridData(aDL, gridData);
}
/**
* Write grid data
*
* @param time The time
* @param levelIdx The level index
* @param varName Variable name
* @param forecast The forecast hour
* @param grid The grid id
* @param gridData The grid data
* @return Checksum
* @throws IOException IOException
*/
public int writeGridData(LocalDateTime time, int levelIdx, String varName, int forecast, int grid, Array gridData) throws IOException {
DataLabel aDL = new DataLabel(time);
aDL.setLevel(levelIdx);
aDL.setVarName(varName);
aDL.setGrid(grid);
if (this.isLargeGrid()) {
aDL.XGPT = true;
aDL.IGC = this.getIGC();
}
aDL.setForecast(forecast);
int ksum = writeGridData(aDL, gridData);
return ksum;
}
private String getIGC() {
int xn = X.length / 1000;
int yn = Y.length / 1000;
char xc = (char) (xn + 64);
char yc = (char) (yn + 64);
return new String(new char[]{xc, yc});
}
private byte[] packARLGridData(GridData gridData, DataLabel aDL) {
int nx = gridData.getXNum();
int ny = gridData.getYNum();
double var1 = gridData.getDoubleValue(0, 0);
double rold = var1;
double rmax = 0.0;
int i, j;
//Find the maximum difference between adjacent elements
for (i = 0; i < ny; i++) {
for (j = 0; j < nx; j++) {
//Compute max difference between elements along row
rmax = Math.max(Math.abs(gridData.getDoubleValue(i, j) - rold), rmax);
rold = gridData.getDoubleValue(i, j);
}
rold = gridData.getDoubleValue(i, 0);
}
double sexp = 0.0;
//Compute the required scaling exponent
if (rmax != 0.0) {
sexp = Math.log(rmax) / Math.log(2.0);
}
int nexp = (int) sexp;
//Positive or whole number scaling round up for lower precision
if (sexp >= 0.0 || sexp % 1.0 == 0.0) {
nexp += 1;
}
//Precision range is -127 to 127 or 254
double prec = Math.pow(2.0, nexp) / 254.0;
byte[] dataBytes = new byte[ny * nx];
double SCALE = Math.pow(2.0, (7 - nexp));
double VOLD = var1;
double rcol = var1;
int ksum = 0;
int INDX = 0;
int ival;
for (j = 0; j < ny; j++) {
VOLD = rcol;
for (i = 0; i < nx; i++) {
ival = (int) ((gridData.getDoubleValue(j, i) - VOLD) * SCALE + 127.5);
dataBytes[INDX] = (byte) ival;
VOLD = (float) (ival - 127) / SCALE + VOLD;
if (i == 0) {
rcol = VOLD;
}
//maintain fotatin checksum
ksum += ival;
//if sum carries over the eight bit add one
if (ksum >= 256) {
ksum = ksum - 255;
}
INDX += 1;
//VOLD = gridData.Data[j, i];
}
//VOLD = gridData.Data[j, 0];
}
aDL.setExponent(nexp);
aDL.setPrecision(prec);
aDL.setValue(var1);
return dataBytes;
}
private Object[] packARLGridData(Array a, DataLabel aDL) {
int nx = a.getShape()[1];
int ny = a.getShape()[0];
double var1 = a.getDouble(0);
double rold = var1;
double rmax = 0.0;
int i, j;
//Find the maximum difference between adjacent elements
for (i = 0; i < ny; i++) {
for (j = 0; j < nx; j++) {
//Compute max difference between elements along row
rmax = Math.max(Math.abs(a.getDouble(i * nx + j) - rold), rmax);
rold = a.getDouble(i * nx + j);
}
rold = a.getDouble(i * nx);
}
double sexp = 0.0;
//Compute the required scaling exponent
if (rmax != 0.0) {
sexp = Math.log(rmax) / Math.log(2.0);
}
int nexp = (int) sexp;
//Positive or whole number scaling round up for lower precision
if (sexp >= 0.0 || sexp % 1.0 == 0.0) {
nexp += 1;
}
//Precision range is -127 to 127 or 254
double prec = Math.pow(2.0, nexp) / 254.0;
byte[] dataBytes = new byte[ny * nx];
double SCALE = Math.pow(2.0, (7 - nexp));
double VOLD = var1;
double rcol = var1;
int ksum = 0;
int INDX = 0;
int ival;
for (j = 0; j < ny; j++) {
VOLD = rcol;
for (i = 0; i < nx; i++) {
ival = (int) ((a.getDouble(j * nx + i) - VOLD) * SCALE + 127.5);
dataBytes[INDX] = (byte) ival;
VOLD = (float) (ival - 127) / SCALE + VOLD;
if (i == 0) {
rcol = VOLD;
}
//maintain fotatin checksum
ksum += ival;
//if sum carries over the eight bit add one
if (ksum >= 256) {
ksum = ksum - 255;
}
INDX += 1;
//VOLD = gridData.Data[j, i];
}
//VOLD = gridData.Data[j, 0];
}
aDL.setExponent(nexp);
aDL.setPrecision(prec);
aDL.setValue(var1);
return new Object[]{dataBytes, ksum};
}
//
//
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy