mirror of
https://github.com/meteoinfo/MeteoInfo.git
synced 2025-12-08 20:36:05 +00:00
support SA/SB, SC, PA, CC radar data files
This commit is contained in:
parent
ec4e09f946
commit
da789f25be
@ -221,10 +221,10 @@ public class GraphicFactory {
|
|||||||
PolylineShape pls;
|
PolylineShape pls;
|
||||||
List<PointD> points;
|
List<PointD> points;
|
||||||
double x, y;
|
double x, y;
|
||||||
IndexIterator xIter = xdata.getIndexIterator();
|
|
||||||
IndexIterator yIter = ydata.getIndexIterator();
|
|
||||||
ColorBreak cb;
|
ColorBreak cb;
|
||||||
if (xdata.getRank() == 1) {
|
if (xdata.getRank() == 1) {
|
||||||
|
IndexIterator xIter = xdata.getIndexIterator();
|
||||||
|
IndexIterator yIter = ydata.getIndexIterator();
|
||||||
points = new ArrayList<>();
|
points = new ArrayList<>();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (xIter.hasNext()) {
|
while (xIter.hasNext()) {
|
||||||
@ -265,14 +265,16 @@ public class GraphicFactory {
|
|||||||
int[] shape = xdata.getShape();
|
int[] shape = xdata.getShape();
|
||||||
int yn = shape[0];
|
int yn = shape[0];
|
||||||
int xn = shape[1];
|
int xn = shape[1];
|
||||||
for (int j = 0; j < yn; j++) {
|
Index2D xIndex = (Index2D) xdata.getIndex();
|
||||||
|
Index2D yIndex = (Index2D) ydata.getIndex();
|
||||||
|
for (int i = 0; i < xn; i++) {
|
||||||
points = new ArrayList<>();
|
points = new ArrayList<>();
|
||||||
cb = cbs.get(j);
|
cb = cbs.get(i);
|
||||||
for (int i = 0; i < xn; i++) {
|
for (int j = 0; j < yn; j++) {
|
||||||
x = xIter.getDoubleNext();
|
xIndex.set(j, i);
|
||||||
y = yIter.getDoubleNext();
|
yIndex.set(j, i);
|
||||||
//x = xdata.getDouble(j * xn + i);
|
x = xdata.getDouble(xIndex);
|
||||||
//y = ydata.getDouble(j * xn + i);
|
y = ydata.getDouble(yIndex);
|
||||||
if (Double.isNaN(y) || Double.isNaN(x)) {
|
if (Double.isNaN(y) || Double.isNaN(x)) {
|
||||||
if (points.isEmpty()) {
|
if (points.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -67,7 +67,7 @@ import java.util.zip.ZipInputStream;
|
|||||||
public static String getVersion(){
|
public static String getVersion(){
|
||||||
String version = GlobalUtil.class.getPackage().getImplementationVersion();
|
String version = GlobalUtil.class.getPackage().getImplementationVersion();
|
||||||
if (version == null || version.equals("")) {
|
if (version == null || version.equals("")) {
|
||||||
version = "3.8.9";
|
version = "3.8.10";
|
||||||
}
|
}
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,9 +39,6 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.meteoinfo.data.meteodata.numpy.NumpyDataInfo;
|
|
||||||
import org.meteoinfo.data.meteodata.radar.CMARadarBaseDataInfo;
|
|
||||||
import org.meteoinfo.data.meteodata.radar.RadarDataType;
|
|
||||||
import org.meteoinfo.data.meteodata.radar.RadarDataUtil;
|
import org.meteoinfo.data.meteodata.radar.RadarDataUtil;
|
||||||
import org.meteoinfo.ndarray.math.ArrayMath;
|
import org.meteoinfo.ndarray.math.ArrayMath;
|
||||||
import org.meteoinfo.projection.ProjectionInfo;
|
import org.meteoinfo.projection.ProjectionInfo;
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import org.meteoinfo.ndarray.*;
|
|||||||
import org.meteoinfo.ndarray.math.ArrayMath;
|
import org.meteoinfo.ndarray.math.ArrayMath;
|
||||||
import org.meteoinfo.ndarray.math.ArrayUtil;
|
import org.meteoinfo.ndarray.math.ArrayUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -27,8 +29,8 @@ public abstract class BaseRadarDataInfo extends DataInfo {
|
|||||||
protected Dimension radialDim, scanDim, gateRDim, gateVDim;
|
protected Dimension radialDim, scanDim, gateRDim, gateVDim;
|
||||||
protected float antennaHeight = 0;
|
protected float antennaHeight = 0;
|
||||||
protected float beamWidthVert = 1.f;
|
protected float beamWidthVert = 1.f;
|
||||||
protected int logResolution = 1000;
|
protected float logResolution = 1000;
|
||||||
protected int dopplerResolution = 1000;
|
protected float dopplerResolution = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get record map
|
* Get record map
|
||||||
@ -56,6 +58,23 @@ public abstract class BaseRadarDataInfo extends DataInfo {
|
|||||||
return velocityGroup.contains(product);
|
return velocityGroup.contains(product);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readDataInfo(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
try {
|
||||||
|
InputStream inputStream = RadarDataUtil.getInputStream(fileName);
|
||||||
|
readDataInfo(inputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data info
|
||||||
|
* @param is The InputStream
|
||||||
|
*/
|
||||||
|
abstract void readDataInfo(InputStream is);
|
||||||
|
|
||||||
protected void makeRefVariables(RadialRecord refRadialRecord) {
|
protected void makeRefVariables(RadialRecord refRadialRecord) {
|
||||||
Dimension[] dimensions = new Dimension[]{scanDim, radialDim, gateRDim};
|
Dimension[] dimensions = new Dimension[]{scanDim, radialDim, gateRDim};
|
||||||
for (RadialRecord radialRecord : this.recordMap.values()) {
|
for (RadialRecord radialRecord : this.recordMap.values()) {
|
||||||
@ -293,6 +312,12 @@ public abstract class BaseRadarDataInfo extends DataInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attribute mvAttr = variable.findAttribute("missing_value");
|
||||||
|
if (mvAttr != null) {
|
||||||
|
Number missingValue = mvAttr.getNumericValue();
|
||||||
|
ArrayMath.missingToNaN(dataArray, missingValue);
|
||||||
|
}
|
||||||
|
|
||||||
Attribute aoAttr = variable.findAttribute("add_offset");
|
Attribute aoAttr = variable.findAttribute("add_offset");
|
||||||
Attribute sfAttr = variable.findAttribute("scale_factor");
|
Attribute sfAttr = variable.findAttribute("scale_factor");
|
||||||
if (aoAttr != null || sfAttr != null) {
|
if (aoAttr != null || sfAttr != null) {
|
||||||
|
|||||||
@ -13,123 +13,118 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class CCRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo {
|
public class CCRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo {
|
||||||
|
|
||||||
|
private List<CutConfig> cutConfigs;
|
||||||
|
private int radarHeaderSize = 1024;
|
||||||
|
private int perRadialSize = 3000;
|
||||||
|
private int messageHeaderSize = 28;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidFile(java.io.RandomAccessFile raf) {
|
public boolean isValidFile(java.io.RandomAccessFile raf) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setScaleOffset(RadialRecord record, int vResolution) {
|
void setScaleOffset(RadialRecord record) {
|
||||||
switch (record.product) {
|
switch (record.product) {
|
||||||
case "dBZ":
|
case "dBZ":
|
||||||
record.scale = 0.5f;
|
|
||||||
record.offset = -33.f;
|
|
||||||
break;
|
|
||||||
case "V":
|
case "V":
|
||||||
if (vResolution == 2) {
|
|
||||||
record.scale = 0.5f;
|
|
||||||
record.offset = -64.5f;
|
|
||||||
} else {
|
|
||||||
record.scale = 1.f;
|
|
||||||
record.offset = -129.f;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "W":
|
case "W":
|
||||||
record.scale = 0.5f;
|
record.scale = 0.1f;
|
||||||
record.offset = -64.5f;
|
record.offset = 0.f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readDataInfo(String fileName) {
|
|
||||||
this.fileName = fileName;
|
|
||||||
if (fileName.endsWith(".bz2")) {
|
|
||||||
try {
|
|
||||||
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void readDataInfo(InputStream is) {
|
void readDataInfo(InputStream is) {
|
||||||
try {
|
try {
|
||||||
int index = 0;
|
byte[] headerBytes = new byte[this.radarHeaderSize];
|
||||||
byte[] rhBytes = new byte[SABRadarDataInfo.RadialHeader.length];
|
is.read(headerBytes);
|
||||||
while (is.read(rhBytes) != -1) {
|
byte[] bytes = Arrays.copyOf(headerBytes, RadarHeader.length);
|
||||||
SABRadarDataInfo.RadialHeader radialHeader = new SABRadarDataInfo.RadialHeader(rhBytes);
|
RadarHeader radarHeader = new RadarHeader(bytes);
|
||||||
if (index == 0) {
|
|
||||||
this.logResolution = radialHeader.gateSizeOfReflectivity;
|
int sweepN = radarHeader.getSweepNumber();
|
||||||
this.dopplerResolution = radialHeader.gateSizeOfDoppler;
|
cutConfigs = new ArrayList<>();
|
||||||
|
int idx = RadarHeader.length;
|
||||||
|
for (int i = 0; i < sweepN; i++) {
|
||||||
|
bytes = Arrays.copyOfRange(headerBytes, idx, idx + CutConfig.length);
|
||||||
|
idx += CutConfig.length;
|
||||||
|
CutConfig cutConfig = new CutConfig(bytes);
|
||||||
|
cutConfigs.add(cutConfig);
|
||||||
|
if (i == 0) {
|
||||||
|
this.logResolution = cutConfig.usBindWidth;
|
||||||
|
this.dopplerResolution = cutConfig.usBindWidth;
|
||||||
}
|
}
|
||||||
if (!radialHeader.hasReflectivityData()) {
|
}
|
||||||
is.read(new byte[460]);
|
|
||||||
}
|
idx = 878;
|
||||||
for (String product : radialHeader.getProducts()) {
|
bytes = Arrays.copyOfRange(headerBytes, idx, idx + RadarHeader2.length);
|
||||||
RadialRecord record;
|
RadarHeader2 radarHeader2 = new RadarHeader2(bytes);
|
||||||
if (this.recordMap.containsKey(product)) {
|
|
||||||
record = this.recordMap.get(product);
|
List<String> products = new ArrayList<>(Arrays.asList("dBZ", "V", "W"));
|
||||||
} else {
|
for (String product : products) {
|
||||||
record = new RadialRecord(product);
|
RadialRecord record = new RadialRecord(product);
|
||||||
record.setBinLength(1);
|
record.setRadarDataType(RadarDataType.CC);
|
||||||
setScaleOffset(record, radialHeader.resolutionOfVelocity);
|
record.setBinLength(2);
|
||||||
this.recordMap.put(product, record);
|
record.setDataType(DataType.SHORT);
|
||||||
}
|
setScaleOffset(record);
|
||||||
if (radialHeader.radialNumber == 1) {
|
this.recordMap.put(product, record);
|
||||||
record.fixedElevation.add(radialHeader.getElevation());
|
}
|
||||||
record.elevation.add(new ArrayList<>());
|
|
||||||
record.azimuth.add(new ArrayList<>());
|
for (int i = 0; i < sweepN; i++) {
|
||||||
record.azimuthMinIndex.add(0);
|
CutConfig cutConfig = cutConfigs.get(i);
|
||||||
if (isVelocityGroup(record)) {
|
int radialN = cutConfig.usBinNumber;
|
||||||
record.disResolution.add(radialHeader.gateSizeOfDoppler);
|
float azimuth = 0;
|
||||||
record.distance.add(ArrayUtil.arrayRange1(radialHeader.rangeToFirstGateOfDop,
|
float aDelta = 360.f / cutConfig.usRecordNumber;
|
||||||
radialHeader.gatesNumberOfDoppler, radialHeader.gateSizeOfDoppler));
|
for (int j = 0; j < cutConfig.usRecordNumber; j++) {
|
||||||
} else {
|
bytes = new byte[this.perRadialSize];
|
||||||
record.disResolution.add(radialHeader.gateSizeOfReflectivity);
|
|
||||||
record.distance.add(ArrayUtil.arrayRange1(radialHeader.rangeToFirstGateOfRef,
|
|
||||||
radialHeader.gatesNumberOfReflectivity, radialHeader.gateSizeOfReflectivity));
|
|
||||||
}
|
|
||||||
record.newScanData();
|
|
||||||
}
|
|
||||||
record.elevation.get(record.elevation.size() - 1).add(radialHeader.getElevation());
|
|
||||||
record.addAzimuth(radialHeader.getAzimuth());
|
|
||||||
int dataLength = isVelocityGroup(record) ? radialHeader.gatesNumberOfDoppler : radialHeader.gatesNumberOfReflectivity;
|
|
||||||
byte[] bytes = new byte[dataLength];
|
|
||||||
is.read(bytes);
|
is.read(bytes);
|
||||||
record.addDataBytes(bytes);
|
idx = 0;
|
||||||
if (isVelocityGroup(record)) {
|
for (String product : products) {
|
||||||
if (dataLength < 920) {
|
RadialRecord record = this.recordMap.get(product);
|
||||||
is.read(new byte[920 - dataLength]);
|
if (j == 0) {
|
||||||
|
record.fixedElevation.add(cutConfig.getAngle());
|
||||||
|
record.elevation.add(new ArrayList<>());
|
||||||
|
record.azimuth.add(new ArrayList<>());
|
||||||
|
record.azimuthMinIndex.add(0);
|
||||||
|
record.disResolution.add((float) cutConfig.usBindWidth);
|
||||||
|
record.distance.add(ArrayUtil.arrayRange1(300,
|
||||||
|
radialN, cutConfig.usBindWidth));
|
||||||
|
record.newScanData();
|
||||||
}
|
}
|
||||||
} else {
|
record.elevation.get(record.elevation.size() - 1).add(cutConfig.getAngle());
|
||||||
if (dataLength < 460) {
|
record.addAzimuth(azimuth);
|
||||||
is.read(new byte[460 - dataLength]);
|
byte[] data = Arrays.copyOfRange(bytes, idx, idx + 2 * radialN);
|
||||||
|
idx += 2 * radialN;
|
||||||
|
Array dataArray = Array.factory(record.getDataType(), new int[]{radialN});
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
for (int k = 0; k < radialN; k++) {
|
||||||
|
dataArray.setShort(k, byteBuffer.getShort());
|
||||||
}
|
}
|
||||||
|
record.addDataArray(dataArray);
|
||||||
}
|
}
|
||||||
|
azimuth += aDelta;
|
||||||
}
|
}
|
||||||
if (!radialHeader.hasDopplerData()) {
|
|
||||||
is.read(new byte[920 + 920]);
|
|
||||||
}
|
|
||||||
is.read(new byte[4]);
|
|
||||||
index += 1;
|
|
||||||
}
|
}
|
||||||
is.close();
|
is.close();
|
||||||
|
|
||||||
|
this.addAttribute(new Attribute("Country", radarHeader.cCountry));
|
||||||
|
this.addAttribute(new Attribute("Province", radarHeader.cProvince));
|
||||||
|
this.addAttribute(new Attribute("StationName", radarHeader.cStation));
|
||||||
|
this.addAttribute(new Attribute("StationCode", radarHeader.cStationNumber));
|
||||||
|
this.addAttribute(new Attribute("StationLongitude", radarHeader.getLongitude()));
|
||||||
|
this.addAttribute(new Attribute("StationLatitude", radarHeader.getLatitude()));
|
||||||
|
this.addAttribute(new Attribute("AntennaHeight", radarHeader.getHeight()));
|
||||||
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
||||||
this.addAttribute(new Attribute("DataType", "Radial"));
|
this.addAttribute(new Attribute("DataType", "Radial"));
|
||||||
|
this.addAttribute(new Attribute("RadarDataType", "CC"));
|
||||||
|
|
||||||
//Add dimensions and variables
|
//Add dimensions and variables
|
||||||
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
||||||
@ -165,111 +160,287 @@ public class CCRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo
|
|||||||
return RadarDataType.CC;
|
return RadarDataType.CC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class RadialHeader {
|
/**
|
||||||
public static int length = 128;
|
* Radar header inner class
|
||||||
public int mSecond; // collection time for this radial, msecs since midnight
|
*/
|
||||||
public short julianDate; // prob "collection time"
|
static class RadarHeader {
|
||||||
public short uRange; // unambiguous range
|
public static int length = 218;
|
||||||
public int azimuth; // azimuth angle
|
public String cFileType; //16 bytes CINRADC
|
||||||
public short radialNumber; // radial number within the elevation
|
public String cCountry; //30 bytes, country name
|
||||||
public short radialStatus;
|
public String cProvince; //20 bytes, province name
|
||||||
public short elevation;
|
public String cStation; //40 bytes, station name
|
||||||
public short elNumber; // elevation number
|
public String cStationNumber; //10 bytes, station ID
|
||||||
public int rangeToFirstGateOfRef; // range to first gate of reflectivity (m) may be negative
|
public String cRadarType; //20 bytes, radar type
|
||||||
public int rangeToFirstGateOfDop; // range to first gate of doppler (m) may be negative
|
public String cLongitude; //16 bytes, longitude string
|
||||||
public int gateSizeOfReflectivity; // reflectivity data gate size (m)
|
public String cLatitude; //16 bytes, latitude string
|
||||||
public int gateSizeOfDoppler; // doppler data gate size (m)
|
public int lLongitudeValue; //longitude
|
||||||
public int gatesNumberOfReflectivity; // number of reflectivity gates
|
public int lLatitudeValue; //latitude
|
||||||
public int gatesNumberOfDoppler; // number of velocity or spectrum width gates
|
public int lHeight; //height
|
||||||
public short cutSectorNumber;
|
public short sMaxAngle;
|
||||||
public int calibrationConst;
|
public short sOptAngle;
|
||||||
public short ptrOfReflectivity;
|
public short ucSYear1;
|
||||||
public short ptrOfVelocity;
|
public short ucSYear2;
|
||||||
public short ptrOfSpectrumWidth;
|
public short ucSMonth;
|
||||||
public int resolutionOfVelocity;
|
public short ucSDay;
|
||||||
public short vcpNumber;
|
public short ucSHour;
|
||||||
public short nyquist;
|
public short ucSMinute;
|
||||||
|
public short ucSSecond;
|
||||||
|
public short ucTimeFrom;
|
||||||
|
public short ucEYear1;
|
||||||
|
public short ucEYear2;
|
||||||
|
public short ucEMonth;
|
||||||
|
public short ucEDay;
|
||||||
|
public short ucEHour;
|
||||||
|
public short ucEMinute;
|
||||||
|
public short ucESecond;
|
||||||
|
public short ucScanMode;
|
||||||
|
public int ulSmilliSecond;
|
||||||
|
public short usRHIA;
|
||||||
|
public short sRHIL;
|
||||||
|
public short sRHIH;
|
||||||
|
public int usEchoType;
|
||||||
|
public int usProdCode;
|
||||||
|
public short ucCalibration;
|
||||||
|
public byte[] remain1; //3 bytes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param is InputStream
|
* @param bytes The byte array
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public RadialHeader(byte[] inBytes) throws IOException {
|
public RadarHeader(byte[] bytes) throws IOException {
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(inBytes);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
byteBuffer.position(28);
|
bytes = new byte[16];
|
||||||
mSecond = byteBuffer.getInt();
|
byteBuffer.get(bytes);
|
||||||
julianDate = byteBuffer.getShort();
|
cFileType = new String(bytes);
|
||||||
uRange = byteBuffer.getShort();
|
bytes = new byte[30];
|
||||||
azimuth = DataType.unsignedShortToInt(byteBuffer.getShort());
|
byteBuffer.get(bytes);
|
||||||
radialNumber = byteBuffer.getShort();
|
cCountry = new String(bytes, "GB2312");
|
||||||
radialStatus = byteBuffer.getShort();
|
bytes = new byte[20];
|
||||||
elevation = byteBuffer.getShort();
|
byteBuffer.get(bytes);
|
||||||
elNumber = byteBuffer.getShort();
|
cProvince = new String(bytes, "GB2312");
|
||||||
rangeToFirstGateOfRef = byteBuffer.getShort();
|
bytes = new byte[40];
|
||||||
rangeToFirstGateOfDop = byteBuffer.getShort();
|
byteBuffer.get(bytes);
|
||||||
gateSizeOfReflectivity = byteBuffer.getShort();
|
cStation = new String(bytes, "GB2312");
|
||||||
gateSizeOfDoppler = byteBuffer.getShort();
|
bytes = new byte[10];
|
||||||
gatesNumberOfReflectivity = byteBuffer.getShort();
|
byteBuffer.get(bytes);
|
||||||
gatesNumberOfDoppler = byteBuffer.getShort();
|
cStationNumber = new String(bytes, "GB2312");
|
||||||
cutSectorNumber = byteBuffer.getShort();
|
bytes = new byte[20];
|
||||||
calibrationConst = byteBuffer.getShort();
|
byteBuffer.get(bytes);
|
||||||
ptrOfReflectivity = byteBuffer.getShort();
|
cRadarType = new String(bytes, "GB2312");
|
||||||
ptrOfVelocity = byteBuffer.getShort();
|
bytes = new byte[16];
|
||||||
ptrOfSpectrumWidth = byteBuffer.getShort();
|
byteBuffer.get(bytes);
|
||||||
resolutionOfVelocity = byteBuffer.getShort();
|
cLongitude = new String(bytes, "GB2312");
|
||||||
vcpNumber = byteBuffer.getShort();
|
bytes = new byte[16];
|
||||||
byteBuffer.position(byteBuffer.position() + 14);
|
byteBuffer.get(bytes);
|
||||||
nyquist = byteBuffer.getShort();
|
cLatitude = new String(bytes, "GB2312");
|
||||||
}
|
lLongitudeValue = byteBuffer.getInt();
|
||||||
|
lLatitudeValue = byteBuffer.getInt();
|
||||||
/**
|
lHeight = byteBuffer.getInt();
|
||||||
* Has reflectivity data or not
|
sMaxAngle = byteBuffer.getShort();
|
||||||
* @return Has reflectivity data
|
sOptAngle = byteBuffer.getShort();
|
||||||
*/
|
ucSYear1 = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
public boolean hasReflectivityData() {
|
ucSYear2 = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
return gatesNumberOfReflectivity > 0;
|
ucSMonth = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
}
|
ucSDay = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
|
ucSHour = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
/**
|
ucSMinute = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
* Has doppler data or not
|
ucSSecond = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
* @return Has doppler data
|
ucTimeFrom = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
*/
|
ucEYear1 = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
public boolean hasDopplerData() {
|
ucEYear2 = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
return gatesNumberOfDoppler > 0;
|
ucEMonth = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
}
|
ucEDay = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
|
ucEHour = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
/**
|
ucEMinute = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
* Get product names
|
ucESecond = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
* @return Product names
|
ucScanMode = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
*/
|
if (ucScanMode < 100 && ucScanMode != 10) {
|
||||||
public List<String> getProducts() {
|
throw new IOException("Error reading CINRAD CC data: Unsupported product: RHI/FFT");
|
||||||
List<String> products = new ArrayList<>();
|
|
||||||
if (hasReflectivityData()) {
|
|
||||||
products.add("dBZ");
|
|
||||||
}
|
|
||||||
if (hasDopplerData()) {
|
|
||||||
products.add("V");
|
|
||||||
products.add("W");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return products;
|
ulSmilliSecond = byteBuffer.getInt();
|
||||||
|
usRHIA = byteBuffer.getShort();
|
||||||
|
sRHIL = byteBuffer.getShort();
|
||||||
|
sRHIH = byteBuffer.getShort();
|
||||||
|
usEchoType = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
if (usEchoType != 0x408a) // only support vppi at this moment
|
||||||
|
throw new IOException("Error reading CINRAD CC data: Unsupported level 2 data");
|
||||||
|
|
||||||
|
usProdCode = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
if (usProdCode != 0x8003) // only support vppi at this moment
|
||||||
|
throw new IOException("Error reading CINRAD CC data: Unsupported product: RHI/FFT");
|
||||||
|
|
||||||
|
ucCalibration = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get azimuth
|
* Get longitude
|
||||||
* @return Azimuth
|
* @return Longitude
|
||||||
*/
|
*/
|
||||||
public float getAzimuth() {
|
public float getLongitude() {
|
||||||
return azimuth / 8.f * 180.f / 4096.f;
|
return lLongitudeValue / 3600000.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get elevation
|
* Get latitude
|
||||||
* @return Elevation
|
* @return Latitude
|
||||||
*/
|
*/
|
||||||
public float getElevation() {
|
public float getLatitude() {
|
||||||
return elevation / 8.f * 180.f / 4096.f;
|
return lLatitudeValue / 3600000.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get height
|
||||||
|
* @return Height
|
||||||
|
*/
|
||||||
|
public float getHeight() {
|
||||||
|
return lHeight / 1000.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get start time
|
||||||
|
* @return Start time
|
||||||
|
*/
|
||||||
|
public LocalDateTime getStartTime() {
|
||||||
|
int sYear = ucSYear1 * 100 + ucSYear2;
|
||||||
|
return LocalDateTime.of(sYear, ucSMonth, ucSDay, ucSHour, ucSMinute, ucSSecond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get end time
|
||||||
|
* @return end time
|
||||||
|
*/
|
||||||
|
public LocalDateTime getEndTime() {
|
||||||
|
int eYear = ucEYear1 * 100 + ucEYear2;
|
||||||
|
return LocalDateTime.of(eYear, ucEMonth, ucEDay, ucEHour, ucEMinute, ucESecond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sweep number
|
||||||
|
* @return Sweep number
|
||||||
|
*/
|
||||||
|
public int getSweepNumber() {
|
||||||
|
int sweepN = 0;
|
||||||
|
if (ucScanMode == 10) {
|
||||||
|
sweepN = 1;
|
||||||
|
} else if (ucScanMode >= 100) {
|
||||||
|
sweepN = ucScanMode - 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sweepN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cut configure inner class
|
||||||
|
*/
|
||||||
|
static class CutConfig {
|
||||||
|
public static int length = 22;
|
||||||
|
public int usMaxV;
|
||||||
|
public int usMaxL;
|
||||||
|
public int usBindWidth;
|
||||||
|
public int usBinNumber;
|
||||||
|
public int usRecordNumber;
|
||||||
|
public int usArotate;
|
||||||
|
public int usPrf1;
|
||||||
|
public int usPrf2;
|
||||||
|
public int usSpulseW;
|
||||||
|
public short usAngle;
|
||||||
|
public short cSweepStatus;
|
||||||
|
public short cAmbiguousp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param bytes The byte array
|
||||||
|
*/
|
||||||
|
public CutConfig(byte[] bytes) throws IOException {
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
usMaxV = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usMaxL = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usBindWidth = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usBinNumber = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usRecordNumber = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usArotate = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usPrf1 = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usPrf2 = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usSpulseW = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usAngle = byteBuffer.getShort();
|
||||||
|
cSweepStatus = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
|
cAmbiguousp = DataType.unsignedByteToShort(byteBuffer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get angle
|
||||||
|
* @return Angle
|
||||||
|
*/
|
||||||
|
public float getAngle() {
|
||||||
|
return usAngle / 100.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Radar header 2 inner class
|
||||||
|
*/
|
||||||
|
static class RadarHeader2 {
|
||||||
|
public static int length = 146;
|
||||||
|
public byte[] remain2; //2 bytes
|
||||||
|
public int lAntennaG;
|
||||||
|
public int lPower;
|
||||||
|
public int lWavelength;
|
||||||
|
|
||||||
|
public int usBeamH;
|
||||||
|
public int usBeamL;
|
||||||
|
public int usPolarization;
|
||||||
|
public int usLogA;
|
||||||
|
public int usLineA;
|
||||||
|
public int usAGCP;
|
||||||
|
public int usFreqMode;
|
||||||
|
public int usFreqRepeat;
|
||||||
|
public int usPPPPulse;
|
||||||
|
public int usFFTPoint;
|
||||||
|
public int usProcessType;
|
||||||
|
|
||||||
|
public short ucClutterT;
|
||||||
|
public short cSidelobe;
|
||||||
|
public short ucVelocityT;
|
||||||
|
public short ucFilderP;
|
||||||
|
public short ucNoiseT;
|
||||||
|
public short ucSQIT;
|
||||||
|
public short ucIntensityC;
|
||||||
|
public short ucIntensityR;
|
||||||
|
public short ucCalNoise;
|
||||||
|
public short ucCalPower;
|
||||||
|
public short ucCalPulseWidth;
|
||||||
|
public short ucCalWorkFreq;
|
||||||
|
public short ucCalLog;
|
||||||
|
|
||||||
|
public byte[] remain3; //92 bytes
|
||||||
|
public int liDataOffset;
|
||||||
|
public byte[] remain4; //1 byte
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param bytes The byte array
|
||||||
|
*/
|
||||||
|
public RadarHeader2(byte[] bytes) throws IOException {
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
byteBuffer.position(2);
|
||||||
|
lAntennaG = byteBuffer.getInt();
|
||||||
|
lPower = byteBuffer.getInt();
|
||||||
|
lWavelength = byteBuffer.getInt();
|
||||||
|
|
||||||
|
usBeamH = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usBeamL = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usPolarization = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usLogA = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usLineA = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usAGCP = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usFreqMode = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
usFreqRepeat = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,496 +0,0 @@
|
|||||||
package org.meteoinfo.data.meteodata.radar;
|
|
||||||
|
|
||||||
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
|
||||||
import org.meteoinfo.common.DataConvert;
|
|
||||||
import org.meteoinfo.data.GridArray;
|
|
||||||
import org.meteoinfo.data.GridData;
|
|
||||||
import org.meteoinfo.data.dimarray.Dimension;
|
|
||||||
import org.meteoinfo.data.dimarray.DimensionType;
|
|
||||||
import org.meteoinfo.data.meteodata.*;
|
|
||||||
import org.meteoinfo.ndarray.*;
|
|
||||||
import org.meteoinfo.ndarray.math.ArrayMath;
|
|
||||||
import org.meteoinfo.ndarray.math.ArrayUtil;
|
|
||||||
|
|
||||||
import java.awt.image.ImagingOpException;
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class CMARadarBaseDataInfo extends BaseRadarDataInfo implements IRadarDataInfo {
|
|
||||||
|
|
||||||
private GenericHeader genericHeader;
|
|
||||||
private SiteConfig siteConfig;
|
|
||||||
private TaskConfig taskConfig;
|
|
||||||
private List<CutConfig> cutConfigs;
|
|
||||||
private List<RadialHeader> radialHeaders;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
public CMARadarBaseDataInfo() {
|
|
||||||
this.meteoDataType = MeteoDataType.RADAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get radar data type
|
|
||||||
* @return Radar data type
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public RadarDataType getRadarDataType() {
|
|
||||||
return RadarDataType.STANDARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get generic header
|
|
||||||
* @return Generic header
|
|
||||||
*/
|
|
||||||
public GenericHeader getGenericHeader() {
|
|
||||||
return this.genericHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get site config
|
|
||||||
* @return Site config
|
|
||||||
*/
|
|
||||||
public SiteConfig getSiteConfig() {
|
|
||||||
return this.siteConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get task config
|
|
||||||
* @return Task config
|
|
||||||
*/
|
|
||||||
public TaskConfig getTaskConfig() {
|
|
||||||
return this.taskConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get cut config list
|
|
||||||
* @return Cut config list
|
|
||||||
*/
|
|
||||||
public List<CutConfig> getCutConfigs() {
|
|
||||||
return this.cutConfigs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get radial header list
|
|
||||||
* @return Radial header list
|
|
||||||
*/
|
|
||||||
public List<RadialHeader> getRadialHeaders() {
|
|
||||||
return this.radialHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidFile(RandomAccessFile raf) {
|
|
||||||
try {
|
|
||||||
raf.seek(0);
|
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
raf.read(bytes);
|
|
||||||
int magic = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
|
||||||
if (magic == 1297371986) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the data file format
|
|
||||||
* @param fileName Data file name
|
|
||||||
* @return Boolean
|
|
||||||
*/
|
|
||||||
public static boolean canOpen(String fileName) {
|
|
||||||
try {
|
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
if (fileName.endsWith("bz2")) {
|
|
||||||
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
inputStream.read(bytes);
|
|
||||||
inputStream.close();
|
|
||||||
} else {
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(fileName, "r");
|
|
||||||
raf.seek(0);
|
|
||||||
raf.read(bytes);
|
|
||||||
raf.close();
|
|
||||||
}
|
|
||||||
int magic = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
|
||||||
if (magic == 1297371986) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readDataInfo(String fileName) {
|
|
||||||
this.fileName = fileName;
|
|
||||||
if (fileName.endsWith(".bz2")) {
|
|
||||||
try {
|
|
||||||
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
//RandomAccessFile raf = new RandomAccessFile(fileName, "r");
|
|
||||||
//readDataInfo(raf);
|
|
||||||
BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void readDataInfo(InputStream raf) {
|
|
||||||
try {
|
|
||||||
genericHeader = new GenericHeader(raf);
|
|
||||||
siteConfig = new SiteConfig(raf);
|
|
||||||
this.antennaHeight = siteConfig.antennaHeight;
|
|
||||||
this.beamWidthVert = siteConfig.beamWidthVert;
|
|
||||||
|
|
||||||
//Add global attributes
|
|
||||||
this.addAttribute(new Attribute("StationCode", siteConfig.siteCode));
|
|
||||||
this.addAttribute(new Attribute("StationName", siteConfig.siteName));
|
|
||||||
this.addAttribute(new Attribute("StationLatitude", siteConfig.latitude));
|
|
||||||
this.addAttribute(new Attribute("StationLongitude", siteConfig.longitude));
|
|
||||||
this.addAttribute(new Attribute("AntennaHeight", siteConfig.antennaHeight));
|
|
||||||
this.addAttribute(new Attribute("GroundHeight", siteConfig.groundHeight));
|
|
||||||
this.addAttribute(new Attribute("RadarType", siteConfig.getRadarType()));
|
|
||||||
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
|
||||||
this.addAttribute(new Attribute("DataType", "Radial"));
|
|
||||||
|
|
||||||
//Read task configuration
|
|
||||||
taskConfig = new TaskConfig(raf);
|
|
||||||
this.addAttribute(new Attribute("TaskName", taskConfig.taskName));
|
|
||||||
this.addAttribute(new Attribute("TaskDescription", taskConfig.taskDescription));
|
|
||||||
|
|
||||||
//Read radial data
|
|
||||||
cutConfigs = new ArrayList<>();
|
|
||||||
CutConfig cutConfig;
|
|
||||||
for (int i = 0; i < taskConfig.cutNumber; i++) {
|
|
||||||
cutConfig = new CutConfig(raf);
|
|
||||||
cutConfigs.add(cutConfig);
|
|
||||||
if (i == 0) {
|
|
||||||
this.logResolution = cutConfig.logResolution;
|
|
||||||
this.dopplerResolution = cutConfig.dopplerResolution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
radialHeaders = new ArrayList<>();
|
|
||||||
byte[] rhBytes = new byte[RadialHeader.length];
|
|
||||||
while (raf.read(rhBytes) != -1) {
|
|
||||||
RadialHeader radialHeader = new RadialHeader(rhBytes);
|
|
||||||
for (int i = 0; i < radialHeader.momentNumber; i++) {
|
|
||||||
MomentHeader momentHeader = new MomentHeader(raf);
|
|
||||||
String product = this.productMap.get(momentHeader.dataType);
|
|
||||||
RadialRecord record;
|
|
||||||
if (this.recordMap.containsKey(product)) {
|
|
||||||
record = this.recordMap.get(product);
|
|
||||||
} else {
|
|
||||||
record = new RadialRecord(product);
|
|
||||||
record.setBinLength(momentHeader.binLength);
|
|
||||||
record.scale = 1.f / momentHeader.scale;
|
|
||||||
record.offset = -momentHeader.offset / (float) momentHeader.scale;
|
|
||||||
this.recordMap.put(product, record);
|
|
||||||
}
|
|
||||||
if (radialHeader.radialNumber == 1) {
|
|
||||||
record.fixedElevation.add(cutConfigs.get(radialHeader.elevationNumber - 1).elevation);
|
|
||||||
record.elevation.add(new ArrayList<>());
|
|
||||||
record.azimuth.add(new ArrayList<>());
|
|
||||||
record.azimuthMinIndex.add(0);
|
|
||||||
if (isVelocityGroup(record)) {
|
|
||||||
record.disResolution.add(cutConfigs.get(radialHeader.elevationNumber - 1).dopplerResolution);
|
|
||||||
record.distance.add(ArrayUtil.arrayRange1(0, momentHeader.dataLength / momentHeader.binLength,
|
|
||||||
cutConfigs.get(radialHeader.elevationNumber - 1).dopplerResolution));
|
|
||||||
} else {
|
|
||||||
record.disResolution.add(cutConfigs.get(radialHeader.elevationNumber - 1).logResolution);
|
|
||||||
record.distance.add(ArrayUtil.arrayRange1(0, momentHeader.dataLength / momentHeader.binLength,
|
|
||||||
cutConfigs.get(radialHeader.elevationNumber - 1).logResolution));
|
|
||||||
}
|
|
||||||
record.newScanData();
|
|
||||||
}
|
|
||||||
record.elevation.get(record.elevation.size() - 1).add(radialHeader.elevation);
|
|
||||||
record.addAzimuth(radialHeader.azimuth);
|
|
||||||
byte[] bytes = new byte[momentHeader.dataLength];
|
|
||||||
raf.read(bytes);
|
|
||||||
record.addDataBytes(bytes);
|
|
||||||
}
|
|
||||||
radialHeaders.add(radialHeader);
|
|
||||||
}
|
|
||||||
raf.close();
|
|
||||||
|
|
||||||
//Add dimensions and variables
|
|
||||||
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
|
||||||
radialDim = new Dimension();
|
|
||||||
radialDim.setName("radial");
|
|
||||||
radialDim.setLength(refRadialRecord.getMaxRadials());
|
|
||||||
this.addDimension(radialDim);
|
|
||||||
scanDim = new Dimension();
|
|
||||||
scanDim.setName("scan");
|
|
||||||
scanDim.setLength(refRadialRecord.getScanNumber());
|
|
||||||
this.addDimension(scanDim);
|
|
||||||
gateRDim = new Dimension();
|
|
||||||
gateRDim.setName("gateR");
|
|
||||||
gateRDim.setLength(refRadialRecord.getGateNumber(0));
|
|
||||||
this.addDimension(gateRDim);
|
|
||||||
makeRefVariables(refRadialRecord);
|
|
||||||
|
|
||||||
RadialRecord velRadialRecord = this.recordMap.get("V");
|
|
||||||
gateVDim = new Dimension();
|
|
||||||
gateVDim.setName("gateV");
|
|
||||||
gateVDim.setLength(velRadialRecord.getGateNumber(0));
|
|
||||||
this.addDimension(gateVDim);
|
|
||||||
makeVelVariables(velRadialRecord);
|
|
||||||
|
|
||||||
/*Dimension xyzDim = new Dimension(DimensionType.OTHER);
|
|
||||||
xyzDim.setShortName("xyz");
|
|
||||||
xyzDim.setDimValue(Array.factory(DataType.INT, new int[]{3}, new int[]{1,2,3}));
|
|
||||||
this.addDimension(xyzDim);
|
|
||||||
for (String product : this.recordMap.keySet()) {
|
|
||||||
this.recordMap.get(product).makeVariables(this, xyzDim);
|
|
||||||
}*/
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get scan elevations
|
|
||||||
* @return Scan elevations
|
|
||||||
*/
|
|
||||||
public List<Float> getElevations() {
|
|
||||||
List<Float> elevations = new ArrayList<>();
|
|
||||||
for (CutConfig cutConfig : this.cutConfigs) {
|
|
||||||
if (!elevations.contains(cutConfig.elevation))
|
|
||||||
elevations.add(cutConfig.elevation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return elevations;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Attribute> getGlobalAttributes() {
|
|
||||||
return this.attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read grid ppi data
|
|
||||||
* @param varName Variable name
|
|
||||||
* @param scanIdx Scan index
|
|
||||||
* @param xa X coordinates array
|
|
||||||
* @param ya Y coordinates array
|
|
||||||
* @param h Radar height
|
|
||||||
* @return Grid ppi data
|
|
||||||
*/
|
|
||||||
public Array readGridData(String varName, int scanIdx, Array xa, Array ya, Float h) {
|
|
||||||
RadialRecord record = this.recordMap.get(varName);
|
|
||||||
if (h == null) {
|
|
||||||
h = (float) siteConfig.antennaHeight;
|
|
||||||
}
|
|
||||||
Array[] rr = Transform.cartesianToAntennaElevation(xa, ya, record.fixedElevation.get(scanIdx), h);
|
|
||||||
Array azimuth = rr[0];
|
|
||||||
Array ranges = rr[1];
|
|
||||||
Array data = Array.factory(DataType.FLOAT, xa.getShape());
|
|
||||||
IndexIterator iterA = azimuth.getIndexIterator();
|
|
||||||
IndexIterator iterR = ranges.getIndexIterator();
|
|
||||||
IndexIterator iterData = data.getIndexIterator();
|
|
||||||
float v;
|
|
||||||
while (iterData.hasNext()) {
|
|
||||||
v = record.interpolateValue(scanIdx, iterA.getFloatNext(), iterR.getFloatNext());
|
|
||||||
iterData.setFloatNext(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read CR data
|
|
||||||
* @param varName Variable name
|
|
||||||
* @param xa X coordinates array - 2D
|
|
||||||
* @param ya Y coordinates array - 2D
|
|
||||||
* @param h Radar height
|
|
||||||
* @return CR data
|
|
||||||
*/
|
|
||||||
public Array getCRData(String varName, Array xa, Array ya, Float h) {
|
|
||||||
RadialRecord record = this.recordMap.get(varName);
|
|
||||||
int nScan = record.getScanNumber();
|
|
||||||
if (h == null) {
|
|
||||||
h = (float) siteConfig.antennaHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] shape = xa.getShape();
|
|
||||||
int ny = shape[0];
|
|
||||||
int nx = shape[1];
|
|
||||||
Array data = Array.factory(DataType.FLOAT, shape);
|
|
||||||
Index2D index2D = (Index2D) data.getIndex();
|
|
||||||
float v;
|
|
||||||
for (int s = 0; s < nScan; s++) {
|
|
||||||
Array[] rr = Transform.cartesianToAntennaElevation(xa, ya, record.fixedElevation.get(s), h);
|
|
||||||
Array azimuth = rr[0];
|
|
||||||
Array ranges = rr[1];
|
|
||||||
IndexIterator iterA = azimuth.getIndexIterator();
|
|
||||||
IndexIterator iterR = ranges.getIndexIterator();
|
|
||||||
if (s == 0) {
|
|
||||||
for (int i = 0; i < ny; i++) {
|
|
||||||
for (int j = 0; j < nx; j++) {
|
|
||||||
v = record.interpolateValue(s, iterA.getFloatNext(), iterR.getFloatNext());
|
|
||||||
data.setFloat(index2D.set(i, j), v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
float v1;
|
|
||||||
for (int i = 0; i < ny; i++) {
|
|
||||||
for (int j = 0; j < nx; j++) {
|
|
||||||
v = record.interpolateValue(s, iterA.getFloatNext(), iterR.getFloatNext());
|
|
||||||
index2D.set(i, j);
|
|
||||||
v1 = data.getFloat(index2D);
|
|
||||||
if (Float.isNaN(v1) || (v > v1))
|
|
||||||
data.setFloat(index2D, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read CAPPI data
|
|
||||||
* @param varName Variable name
|
|
||||||
* @param xa X coordinates array
|
|
||||||
* @param ya Y coordinates array
|
|
||||||
* @param z Z coordinates value
|
|
||||||
* @param h Radar height
|
|
||||||
* @return Grid ppi data
|
|
||||||
*/
|
|
||||||
public Array getCAPPIData(String varName, Array xa, Array ya, float z, Float h) {
|
|
||||||
RadialRecord record = this.recordMap.get(varName);
|
|
||||||
if (h == null) {
|
|
||||||
h = (float) siteConfig.antennaHeight;
|
|
||||||
}
|
|
||||||
Array[] rr = Transform.cartesianToAntenna(xa, ya, z, h);
|
|
||||||
Array azimuth = rr[0];
|
|
||||||
Array ranges = rr[1];
|
|
||||||
Array elevation = rr[2];
|
|
||||||
Array data = Array.factory(DataType.FLOAT, xa.getShape());
|
|
||||||
IndexIterator iterA = azimuth.getIndexIterator();
|
|
||||||
IndexIterator iterR = ranges.getIndexIterator();
|
|
||||||
IndexIterator iterE = elevation.getIndexIterator();
|
|
||||||
IndexIterator iterData = data.getIndexIterator();
|
|
||||||
float v;
|
|
||||||
float halfBeamWidth = this.siteConfig.beamWidthVert / 2;
|
|
||||||
while (iterData.hasNext()) {
|
|
||||||
v = record.interpolateValue(iterE.getFloatNext(), iterA.getFloatNext(),
|
|
||||||
iterR.getFloatNext(), halfBeamWidth);
|
|
||||||
iterData.setFloatNext(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read grid 3d data
|
|
||||||
* @param varName Variable name
|
|
||||||
* @param xa X coordinates array
|
|
||||||
* @param ya Y coordinates array
|
|
||||||
* @param z Z coordinates array
|
|
||||||
* @param h Radar height
|
|
||||||
* @return Grid ppi data
|
|
||||||
*/
|
|
||||||
public Array getGrid3DData(String varName, Array xa, Array ya, Array za, Float h) {
|
|
||||||
RadialRecord record = this.recordMap.get(varName);
|
|
||||||
if (h == null) {
|
|
||||||
h = (float) siteConfig.antennaHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nz = (int) za.getSize();
|
|
||||||
int[] shape2D = xa.getShape();
|
|
||||||
int[] shape3D = new int[]{nz, shape2D[0], shape2D[1]};
|
|
||||||
Array data = Array.factory(DataType.FLOAT, shape3D);
|
|
||||||
IndexIterator iterData = data.getIndexIterator();
|
|
||||||
IndexIterator iterZ = za.getIndexIterator();
|
|
||||||
float halfBeamWidth = this.siteConfig.beamWidthVert / 2;
|
|
||||||
while(iterZ.hasNext()) {
|
|
||||||
float z = iterZ.getFloatNext();
|
|
||||||
Array[] rr = Transform.cartesianToAntenna(xa, ya, z, h);
|
|
||||||
Array azimuth = rr[0];
|
|
||||||
Array ranges = rr[1];
|
|
||||||
Array elevation = rr[2];
|
|
||||||
IndexIterator iterA = azimuth.getIndexIterator();
|
|
||||||
IndexIterator iterR = ranges.getIndexIterator();
|
|
||||||
IndexIterator iterE = elevation.getIndexIterator();
|
|
||||||
float v;
|
|
||||||
while (iterA.hasNext()) {
|
|
||||||
v = record.interpolateValue(iterE.getFloatNext(), iterA.getFloatNext(),
|
|
||||||
iterR.getFloatNext(), halfBeamWidth);
|
|
||||||
iterData.setFloatNext(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get VCS data
|
|
||||||
* @param varName Variable name
|
|
||||||
* @param startX Start x, km
|
|
||||||
* @param startY Start y, km
|
|
||||||
* @param endX End x, km
|
|
||||||
* @param endY End y, km
|
|
||||||
* @return VCS data
|
|
||||||
*/
|
|
||||||
public Array[] getVCSData(String varName, float startX, float startY, float endX, float endY) {
|
|
||||||
RadialRecord record = this.recordMap.get(varName);
|
|
||||||
int nScan = record.getScanNumber();
|
|
||||||
float halfBeamWidth = this.siteConfig.beamWidthVert / 2;
|
|
||||||
float binRes = this.cutConfigs.get(0).logResolution;
|
|
||||||
float height = this.siteConfig.antennaHeight;
|
|
||||||
float startEndDistance = (float) Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
|
|
||||||
int nPoints = (int) (startEndDistance * 1000 / binRes + 1);
|
|
||||||
Array xa = ArrayUtil.lineSpace(startX, endX, nPoints);
|
|
||||||
Array ya = ArrayUtil.lineSpace(startY, endY, nPoints);
|
|
||||||
Array aa = Transform.xyToAzimuth(xa, ya);
|
|
||||||
int[] shape = new int[]{nScan, 2, nPoints};
|
|
||||||
Array data = Array.factory(DataType.FLOAT, shape);
|
|
||||||
Array meshXY = Array.factory(DataType.FLOAT, shape);
|
|
||||||
Array meshZ = Array.factory(DataType.FLOAT, shape);
|
|
||||||
Index dataIndex = data.getIndex();
|
|
||||||
Index meshXYIndex = meshXY.getIndex();
|
|
||||||
Index meshZIndex = meshZ.getIndex();
|
|
||||||
float x, y, z1, z2, dis, azi, v, ele;
|
|
||||||
for (int i = 0; i < nScan; i++) {
|
|
||||||
ele = record.fixedElevation.get(i);
|
|
||||||
for (int j = 0; j < nPoints; j++) {
|
|
||||||
x = xa.getFloat(j);
|
|
||||||
y = ya.getFloat(j);
|
|
||||||
dis = (float) Math.sqrt(x * x + y * y);
|
|
||||||
azi = aa.getFloat(j);
|
|
||||||
v = record.getValue(i, azi, dis * 1000);
|
|
||||||
z1 = Transform.toCartesianZ(dis * 1000, (float) Math.toRadians(ele -
|
|
||||||
halfBeamWidth), height) / 1000.f;
|
|
||||||
z2 = Transform.toCartesianZ(dis * 1000, (float) Math.toRadians(ele +
|
|
||||||
halfBeamWidth), height) / 1000.f;
|
|
||||||
for (int k = 0; k < 2; k++) {
|
|
||||||
data.setFloat(dataIndex.set(i, k, j), v);
|
|
||||||
meshXY.setFloat(meshXYIndex.set(i, k, j), dis);
|
|
||||||
}
|
|
||||||
meshZ.setFloat(meshZIndex.set(i, 0, j), z1);
|
|
||||||
meshZ.setFloat(meshZIndex.set(i, 1, j), z2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Array[]{data, meshXY, meshZ};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,14 @@
|
|||||||
package org.meteoinfo.data.meteodata.radar;
|
package org.meteoinfo.data.meteodata.radar;
|
||||||
|
|
||||||
import org.meteoinfo.common.DataConvert;
|
import org.meteoinfo.common.DataConvert;
|
||||||
|
import org.meteoinfo.ndarray.DataType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class GenericHeader {
|
public class GenericHeader {
|
||||||
public static int length = 32;
|
public static int length = 32;
|
||||||
@ -59,4 +62,18 @@ public class GenericHeader {
|
|||||||
reserved = new byte[16];
|
reserved = new byte[16];
|
||||||
in.read(reserved);
|
in.read(reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param inBytes The input bytes
|
||||||
|
*/
|
||||||
|
public GenericHeader(byte[] inBytes) throws IOException {
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(inBytes);
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
magicNumber = byteBuffer.getInt();
|
||||||
|
majorVersion = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
minorVersion = DataType.unsignedShortToInt(byteBuffer.getShort());
|
||||||
|
genericType = byteBuffer.getInt();
|
||||||
|
productType = byteBuffer.getInt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,612 @@
|
|||||||
|
package org.meteoinfo.data.meteodata.radar;
|
||||||
|
|
||||||
|
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
||||||
|
import org.meteoinfo.common.DataConvert;
|
||||||
|
import org.meteoinfo.data.dimarray.Dimension;
|
||||||
|
import org.meteoinfo.data.meteodata.Attribute;
|
||||||
|
import org.meteoinfo.data.meteodata.MeteoDataType;
|
||||||
|
import org.meteoinfo.ndarray.*;
|
||||||
|
import org.meteoinfo.ndarray.math.ArrayUtil;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PARadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo {
|
||||||
|
|
||||||
|
private GenericHeader genericHeader;
|
||||||
|
private SiteConfig siteConfig;
|
||||||
|
private TaskConfig taskConfig;
|
||||||
|
private List<BeamConfig> beamConfigs;
|
||||||
|
private List<CutConfig> cutConfigs;
|
||||||
|
private List<RadialHeader> radialHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public PARadarDataInfo() {
|
||||||
|
this.meteoDataType = MeteoDataType.RADAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get radar data type
|
||||||
|
* @return Radar data type
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public RadarDataType getRadarDataType() {
|
||||||
|
return RadarDataType.PA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get generic header
|
||||||
|
* @return Generic header
|
||||||
|
*/
|
||||||
|
public GenericHeader getGenericHeader() {
|
||||||
|
return this.genericHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get site config
|
||||||
|
* @return Site config
|
||||||
|
*/
|
||||||
|
public SiteConfig getSiteConfig() {
|
||||||
|
return this.siteConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get task config
|
||||||
|
* @return Task config
|
||||||
|
*/
|
||||||
|
public TaskConfig getTaskConfig() {
|
||||||
|
return this.taskConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cut config list
|
||||||
|
* @return Cut config list
|
||||||
|
*/
|
||||||
|
public List<CutConfig> getCutConfigs() {
|
||||||
|
return this.cutConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get radial header list
|
||||||
|
* @return Radial header list
|
||||||
|
*/
|
||||||
|
public List<RadialHeader> getRadialHeaders() {
|
||||||
|
return this.radialHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidFile(RandomAccessFile raf) {
|
||||||
|
try {
|
||||||
|
raf.seek(0);
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
raf.read(bytes);
|
||||||
|
int magic = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
if (magic == 1297371986) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the data file format
|
||||||
|
* @param fileName Data file name
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
public static boolean canOpen(String fileName) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
if (fileName.endsWith("bz2")) {
|
||||||
|
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
||||||
|
inputStream.read(bytes);
|
||||||
|
inputStream.close();
|
||||||
|
} else {
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(fileName, "r");
|
||||||
|
raf.seek(0);
|
||||||
|
raf.read(bytes);
|
||||||
|
raf.close();
|
||||||
|
}
|
||||||
|
int magic = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
if (magic == 1297371986) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void readDataInfo(InputStream raf) {
|
||||||
|
try {
|
||||||
|
genericHeader = new GenericHeader(raf);
|
||||||
|
siteConfig = new SiteConfig(raf);
|
||||||
|
this.antennaHeight = siteConfig.antennaHeight;
|
||||||
|
|
||||||
|
//Add global attributes
|
||||||
|
this.addAttribute(new Attribute("StationCode", siteConfig.siteCode));
|
||||||
|
this.addAttribute(new Attribute("StationName", siteConfig.siteName));
|
||||||
|
this.addAttribute(new Attribute("StationLatitude", siteConfig.latitude));
|
||||||
|
this.addAttribute(new Attribute("StationLongitude", siteConfig.longitude));
|
||||||
|
this.addAttribute(new Attribute("AntennaHeight", siteConfig.antennaHeight));
|
||||||
|
this.addAttribute(new Attribute("GroundHeight", siteConfig.groundHeight));
|
||||||
|
this.addAttribute(new Attribute("RadarType", siteConfig.getRadarType()));
|
||||||
|
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
||||||
|
this.addAttribute(new Attribute("DataType", "Radial"));
|
||||||
|
this.addAttribute(new Attribute("RadarDataType", "PA"));
|
||||||
|
|
||||||
|
//Read task configuration
|
||||||
|
taskConfig = new TaskConfig(raf);
|
||||||
|
this.addAttribute(new Attribute("TaskName", taskConfig.taskName));
|
||||||
|
this.addAttribute(new Attribute("TaskDescription", taskConfig.taskDescription));
|
||||||
|
|
||||||
|
//Read scan beam configuration
|
||||||
|
beamConfigs = new ArrayList<>();
|
||||||
|
BeamConfig beamConfig;
|
||||||
|
for (int i = 0; i < taskConfig.beamNumber; i++) {
|
||||||
|
beamConfig = new BeamConfig(raf);
|
||||||
|
beamConfigs.add(beamConfig);
|
||||||
|
if (i == 0) {
|
||||||
|
this.beamWidthVert = beamConfig.txBeamWidthV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read cut configuration
|
||||||
|
cutConfigs = new ArrayList<>();
|
||||||
|
CutConfig cutConfig;
|
||||||
|
for (int i = 0; i < taskConfig.cutNumber; i++) {
|
||||||
|
cutConfig = new CutConfig(raf);
|
||||||
|
cutConfigs.add(cutConfig);
|
||||||
|
if (i == 0) {
|
||||||
|
this.logResolution = cutConfig.logResolution;
|
||||||
|
this.dopplerResolution = cutConfig.dopplerResolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read radial data
|
||||||
|
radialHeaders = new ArrayList<>();
|
||||||
|
byte[] rhBytes = new byte[RadialHeader.length];
|
||||||
|
while (raf.read(rhBytes) != -1) {
|
||||||
|
RadialHeader radialHeader = new RadialHeader(rhBytes);
|
||||||
|
for (int i = 0; i < radialHeader.momentNumber; i++) {
|
||||||
|
MomentHeader momentHeader = new MomentHeader(raf);
|
||||||
|
String product = this.productMap.get(momentHeader.dataType);
|
||||||
|
RadialRecord record;
|
||||||
|
if (this.recordMap.containsKey(product)) {
|
||||||
|
record = this.recordMap.get(product);
|
||||||
|
} else {
|
||||||
|
record = new RadialRecord(product);
|
||||||
|
record.setBinLength(momentHeader.binLength);
|
||||||
|
record.scale = 1.f / momentHeader.scale;
|
||||||
|
record.offset = -momentHeader.offset / (float) momentHeader.scale;
|
||||||
|
this.recordMap.put(product, record);
|
||||||
|
}
|
||||||
|
if (radialHeader.radialNumber == 1) {
|
||||||
|
record.fixedElevation.add(cutConfigs.get(radialHeader.elevationNumber - 1).elevation);
|
||||||
|
record.elevation.add(new ArrayList<>());
|
||||||
|
record.azimuth.add(new ArrayList<>());
|
||||||
|
record.azimuthMinIndex.add(0);
|
||||||
|
if (isVelocityGroup(record)) {
|
||||||
|
record.disResolution.add(cutConfigs.get(radialHeader.elevationNumber - 1).dopplerResolution);
|
||||||
|
record.distance.add(ArrayUtil.arrayRange1(0, momentHeader.dataLength / momentHeader.binLength,
|
||||||
|
cutConfigs.get(radialHeader.elevationNumber - 1).dopplerResolution));
|
||||||
|
} else {
|
||||||
|
record.disResolution.add(cutConfigs.get(radialHeader.elevationNumber - 1).logResolution);
|
||||||
|
record.distance.add(ArrayUtil.arrayRange1(0, momentHeader.dataLength / momentHeader.binLength,
|
||||||
|
cutConfigs.get(radialHeader.elevationNumber - 1).logResolution));
|
||||||
|
}
|
||||||
|
record.newScanData();
|
||||||
|
}
|
||||||
|
record.elevation.get(record.elevation.size() - 1).add(radialHeader.elevation);
|
||||||
|
record.addAzimuth(radialHeader.azimuth);
|
||||||
|
byte[] bytes = new byte[momentHeader.dataLength];
|
||||||
|
raf.read(bytes);
|
||||||
|
record.addDataBytes(bytes);
|
||||||
|
}
|
||||||
|
radialHeaders.add(radialHeader);
|
||||||
|
}
|
||||||
|
raf.close();
|
||||||
|
|
||||||
|
//Add dimensions and variables
|
||||||
|
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
||||||
|
radialDim = new Dimension();
|
||||||
|
radialDim.setName("radial");
|
||||||
|
radialDim.setLength(refRadialRecord.getMaxRadials());
|
||||||
|
this.addDimension(radialDim);
|
||||||
|
scanDim = new Dimension();
|
||||||
|
scanDim.setName("scan");
|
||||||
|
scanDim.setLength(refRadialRecord.getScanNumber());
|
||||||
|
this.addDimension(scanDim);
|
||||||
|
gateRDim = new Dimension();
|
||||||
|
gateRDim.setName("gateR");
|
||||||
|
gateRDim.setLength(refRadialRecord.getGateNumber(0));
|
||||||
|
this.addDimension(gateRDim);
|
||||||
|
makeRefVariables(refRadialRecord);
|
||||||
|
|
||||||
|
RadialRecord velRadialRecord = this.recordMap.get("V");
|
||||||
|
gateVDim = new Dimension();
|
||||||
|
gateVDim.setName("gateV");
|
||||||
|
gateVDim.setLength(velRadialRecord.getGateNumber(0));
|
||||||
|
this.addDimension(gateVDim);
|
||||||
|
makeVelVariables(velRadialRecord);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get scan elevations
|
||||||
|
* @return Scan elevations
|
||||||
|
*/
|
||||||
|
public List<Float> getElevations() {
|
||||||
|
List<Float> elevations = new ArrayList<>();
|
||||||
|
for (CutConfig cutConfig : this.cutConfigs) {
|
||||||
|
if (!elevations.contains(cutConfig.elevation))
|
||||||
|
elevations.add(cutConfig.elevation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elevations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attribute> getGlobalAttributes() {
|
||||||
|
return this.attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Site configure inner class
|
||||||
|
*/
|
||||||
|
static class SiteConfig {
|
||||||
|
public static int length = 128;
|
||||||
|
public String siteCode;
|
||||||
|
public String siteName;
|
||||||
|
public float latitude;
|
||||||
|
public float longitude;
|
||||||
|
public int antennaHeight;
|
||||||
|
public int groundHeight;
|
||||||
|
public float frequency;
|
||||||
|
public int antennaType;
|
||||||
|
public int TRNumber;
|
||||||
|
public int RADVersion;
|
||||||
|
public short radarType;
|
||||||
|
public byte[] reserved;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param raf InputStream object
|
||||||
|
*/
|
||||||
|
public SiteConfig(InputStream raf) throws IOException {
|
||||||
|
byte[] bytes = new byte[8];
|
||||||
|
raf.read(bytes);
|
||||||
|
siteCode = new String(bytes).trim();
|
||||||
|
bytes = new byte[32];
|
||||||
|
raf.read(bytes);
|
||||||
|
siteName = new String(bytes).trim();
|
||||||
|
bytes = new byte[4];
|
||||||
|
raf.read(bytes);
|
||||||
|
latitude = DataConvert.bytes2Float(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
longitude = DataConvert.bytes2Float(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
antennaHeight = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
groundHeight = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
frequency = DataConvert.bytes2Float(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
antennaType = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
TRNumber = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
RADVersion = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
bytes = new byte[2];
|
||||||
|
raf.read(bytes);
|
||||||
|
radarType = DataConvert.bytes2Short(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
reserved = new byte[54];
|
||||||
|
raf.read(reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get radar type string
|
||||||
|
* @return Radar type string
|
||||||
|
*/
|
||||||
|
public String getRadarType() {
|
||||||
|
switch (radarType) {
|
||||||
|
case 7:
|
||||||
|
return "SPAR";
|
||||||
|
case 8:
|
||||||
|
return "SPARD";
|
||||||
|
case 43:
|
||||||
|
return "CPAR";
|
||||||
|
case 44:
|
||||||
|
return "CPARD";
|
||||||
|
case 69:
|
||||||
|
return "XPAR";
|
||||||
|
case 70:
|
||||||
|
return "XPARD";
|
||||||
|
default:
|
||||||
|
return "UNDEFINE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task configure inner class
|
||||||
|
*/
|
||||||
|
static class TaskConfig {
|
||||||
|
public static int length = 256;
|
||||||
|
public String taskName;
|
||||||
|
public String taskDescription;
|
||||||
|
public int polarizationType;
|
||||||
|
public int scanType;
|
||||||
|
public int beamNumber;
|
||||||
|
public int cutNumber;
|
||||||
|
public int rayOrder;
|
||||||
|
public LocalDateTime scanStartTime;
|
||||||
|
public byte[] reserves;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param raf InputStream object
|
||||||
|
*/
|
||||||
|
public TaskConfig(InputStream raf) throws IOException {
|
||||||
|
byte[] bytes = new byte[32];
|
||||||
|
raf.read(bytes);
|
||||||
|
taskName = new String(bytes).trim();
|
||||||
|
bytes = new byte[128];
|
||||||
|
raf.read(bytes);
|
||||||
|
taskDescription = new String(bytes).trim();
|
||||||
|
bytes = new byte[4];
|
||||||
|
raf.read(bytes);
|
||||||
|
polarizationType = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
scanType = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
beamNumber = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
cutNumber = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
raf.read(bytes);
|
||||||
|
rayOrder = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
bytes = new byte[8];
|
||||||
|
raf.read(bytes);
|
||||||
|
long seconds = DataConvert.bytes2Long(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
LocalDateTime dt = LocalDateTime.of(1970, 1, 1, 0, 0);
|
||||||
|
scanStartTime = dt.plusSeconds(seconds);
|
||||||
|
reserves = new byte[68];
|
||||||
|
raf.read(reserves);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan beam configure inner class
|
||||||
|
*/
|
||||||
|
static class BeamConfig {
|
||||||
|
public static int length = 640;
|
||||||
|
public int beamIndex;
|
||||||
|
public int beamType;
|
||||||
|
public int subPulseNumber;
|
||||||
|
public float txBeamDirection;
|
||||||
|
public float txBeamWidthH;
|
||||||
|
public float txBeamWidthV;
|
||||||
|
public float txBeamGain;
|
||||||
|
public byte[] reserves1; //100 bytes
|
||||||
|
|
||||||
|
public int subPulseStrategy;
|
||||||
|
public int subPulseModulation;
|
||||||
|
public float subPulseFrequency;
|
||||||
|
public float subPulseBandWidth;
|
||||||
|
public int subPulseWidth;
|
||||||
|
public byte[] reserves2; //492 bytes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param inputStream The input steam
|
||||||
|
*/
|
||||||
|
public BeamConfig(InputStream inputStream) throws IOException {
|
||||||
|
byte[] inBytes = new byte[BeamConfig.length];
|
||||||
|
inputStream.read(inBytes);
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(inBytes);
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
beamIndex = byteBuffer.getInt();
|
||||||
|
beamType = byteBuffer.getInt();
|
||||||
|
subPulseNumber = byteBuffer.getInt();
|
||||||
|
txBeamDirection = byteBuffer.getFloat();
|
||||||
|
txBeamWidthH = byteBuffer.getFloat();
|
||||||
|
txBeamWidthV = byteBuffer.getFloat();
|
||||||
|
txBeamGain = byteBuffer.getFloat();
|
||||||
|
byteBuffer.position(byteBuffer.position() + 100);
|
||||||
|
|
||||||
|
subPulseStrategy = byteBuffer.getInt();
|
||||||
|
subPulseModulation = byteBuffer.getInt();
|
||||||
|
subPulseFrequency = byteBuffer.getFloat();
|
||||||
|
subPulseBandWidth = byteBuffer.getFloat();
|
||||||
|
subPulseWidth = byteBuffer.getInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cut configuration inner class
|
||||||
|
*/
|
||||||
|
static class CutConfig {
|
||||||
|
public static int length = 256;
|
||||||
|
public short cutIndex;
|
||||||
|
public short txBeamIndex;
|
||||||
|
public float elevation;
|
||||||
|
public float txBeamGain;
|
||||||
|
public float rxBeamWidthH;
|
||||||
|
public float rxBeamWidthV;
|
||||||
|
public float rxBeamGain;
|
||||||
|
public int processMode; // 1-PPP 2-FFT
|
||||||
|
public int waveForm;
|
||||||
|
public float N1_PRF_1;
|
||||||
|
public float N1_PRF_2;
|
||||||
|
public float N2_PRF_1;
|
||||||
|
public float N2_PRF_2;
|
||||||
|
public int unfoldMode;
|
||||||
|
public float azimuth;
|
||||||
|
public float startAngle;
|
||||||
|
public float endAngle;
|
||||||
|
public float angleResolution;
|
||||||
|
public float scanSpeed;
|
||||||
|
public float logResolution;
|
||||||
|
public float dopplerResolution;
|
||||||
|
public int maximumRange;
|
||||||
|
public int maximumRange2;
|
||||||
|
public int startRange;
|
||||||
|
public int sample_1;
|
||||||
|
public int sample_2;
|
||||||
|
public int phaseMode;
|
||||||
|
public float atmosphericLoss;
|
||||||
|
public float nyquistSpeed;
|
||||||
|
public long momentsMask;
|
||||||
|
public long momentsSizeMask;
|
||||||
|
public int miscFilterMask;
|
||||||
|
public float SQIThreshold;
|
||||||
|
public float SIGThreshold;
|
||||||
|
public float CSRThreshold;
|
||||||
|
public float LOGThreshold;
|
||||||
|
public float CPAThreshold;
|
||||||
|
public float PMIThreshold;
|
||||||
|
public float DPLOGThreshold;
|
||||||
|
public byte[] thresholdsReserved; // 4 bytes
|
||||||
|
public int dBTMask;
|
||||||
|
public int dBZMask;
|
||||||
|
public int velocity;
|
||||||
|
public int spectrumWidthMask;
|
||||||
|
public int ZDRMask;
|
||||||
|
public byte[] maskReserved; // 12 bytes
|
||||||
|
public int scanSync;
|
||||||
|
public int direction;
|
||||||
|
public short groundClutterClassifierType;
|
||||||
|
public short groundClutterFilterType;
|
||||||
|
public short groundClutterFilterNotchWidth;
|
||||||
|
public short groundClutterFilterWindow;
|
||||||
|
public byte[] reserved; // 44 bytes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param inputStream The input stream
|
||||||
|
*/
|
||||||
|
public CutConfig(InputStream inputStream) throws IOException {
|
||||||
|
byte[] bytes = new byte[CutConfig.length];
|
||||||
|
inputStream.read(bytes);
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
cutIndex = byteBuffer.getShort();
|
||||||
|
txBeamIndex = byteBuffer.getShort();
|
||||||
|
elevation = byteBuffer.getFloat();
|
||||||
|
txBeamGain = byteBuffer.getFloat();
|
||||||
|
rxBeamWidthH = byteBuffer.getFloat();
|
||||||
|
rxBeamWidthV = byteBuffer.getFloat();
|
||||||
|
rxBeamGain = byteBuffer.getFloat();
|
||||||
|
processMode = byteBuffer.getInt();
|
||||||
|
waveForm = byteBuffer.getInt();
|
||||||
|
N1_PRF_1 = byteBuffer.getFloat();
|
||||||
|
N1_PRF_2 = byteBuffer.getFloat();
|
||||||
|
N2_PRF_1 = byteBuffer.getFloat();
|
||||||
|
N2_PRF_2 = byteBuffer.getFloat();
|
||||||
|
unfoldMode = byteBuffer.getInt();
|
||||||
|
azimuth = byteBuffer.getFloat();
|
||||||
|
startAngle = byteBuffer.getFloat();
|
||||||
|
endAngle = byteBuffer.getFloat();
|
||||||
|
angleResolution = byteBuffer.getFloat();
|
||||||
|
scanSpeed = byteBuffer.getFloat();
|
||||||
|
logResolution = byteBuffer.getFloat();
|
||||||
|
dopplerResolution = byteBuffer.getFloat();
|
||||||
|
maximumRange = byteBuffer.getInt();
|
||||||
|
maximumRange2 = byteBuffer.getInt();
|
||||||
|
startRange = byteBuffer.getInt();
|
||||||
|
sample_1 = byteBuffer.getInt();
|
||||||
|
sample_2 = byteBuffer.getInt();
|
||||||
|
phaseMode = byteBuffer.getInt();
|
||||||
|
atmosphericLoss = byteBuffer.getFloat();
|
||||||
|
nyquistSpeed = byteBuffer.getFloat();
|
||||||
|
momentsMask = byteBuffer.getLong();
|
||||||
|
momentsSizeMask = byteBuffer.getLong();
|
||||||
|
miscFilterMask = byteBuffer.getInt();
|
||||||
|
SQIThreshold = byteBuffer.getFloat();
|
||||||
|
SIGThreshold = byteBuffer.getFloat();
|
||||||
|
CSRThreshold = byteBuffer.getFloat();
|
||||||
|
LOGThreshold = byteBuffer.getFloat();
|
||||||
|
CPAThreshold = byteBuffer.getFloat();
|
||||||
|
PMIThreshold = byteBuffer.getFloat();
|
||||||
|
DPLOGThreshold = byteBuffer.getFloat();
|
||||||
|
byteBuffer.getInt();
|
||||||
|
|
||||||
|
dBTMask = byteBuffer.getInt();
|
||||||
|
dBZMask = byteBuffer.getInt();
|
||||||
|
velocity = byteBuffer.getInt();
|
||||||
|
spectrumWidthMask = byteBuffer.getInt();
|
||||||
|
ZDRMask = byteBuffer.getInt();
|
||||||
|
byteBuffer.position(byteBuffer.position() + 12);
|
||||||
|
|
||||||
|
scanSync = byteBuffer.getInt();
|
||||||
|
direction = byteBuffer.getInt();
|
||||||
|
groundClutterClassifierType = byteBuffer.getShort();
|
||||||
|
groundClutterFilterType = byteBuffer.getShort();
|
||||||
|
groundClutterFilterNotchWidth = byteBuffer.getShort();
|
||||||
|
groundClutterFilterWindow = byteBuffer.getShort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Radial header inner class
|
||||||
|
*/
|
||||||
|
static class RadialHeader {
|
||||||
|
public static int length = 128;
|
||||||
|
public int radialState;
|
||||||
|
public int spotBlank;
|
||||||
|
public int sequenceNumber;
|
||||||
|
public int radialNumber;
|
||||||
|
public int elevationNumber;
|
||||||
|
public float azimuth;
|
||||||
|
public float elevation;
|
||||||
|
public long seconds;
|
||||||
|
public int microSeconds;
|
||||||
|
public int lengthOfData;
|
||||||
|
public int momentNumber;
|
||||||
|
public short scanBeamIndex;
|
||||||
|
public short horizontalEstimatedNoise;
|
||||||
|
public short verticalEstimatedNoise;
|
||||||
|
public int PRFFLAG;
|
||||||
|
public byte[] reserved04; //70 bytes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param inputStream The input stream
|
||||||
|
*/
|
||||||
|
public RadialHeader(byte[] bytes) {
|
||||||
|
ByteBuffer bf = ByteBuffer.wrap(bytes);
|
||||||
|
bf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
radialState = bf.getInt();
|
||||||
|
spotBlank = bf.getInt();
|
||||||
|
sequenceNumber = bf.getInt();
|
||||||
|
radialNumber = bf.getInt();
|
||||||
|
elevationNumber = bf.getInt();
|
||||||
|
azimuth = bf.getFloat();
|
||||||
|
elevation = bf.getFloat();
|
||||||
|
seconds = bf.getLong();
|
||||||
|
microSeconds = bf.getInt();
|
||||||
|
lengthOfData = bf.getInt();
|
||||||
|
momentNumber = bf.getInt();
|
||||||
|
scanBeamIndex = bf.getShort();
|
||||||
|
horizontalEstimatedNoise = bf.getShort();
|
||||||
|
verticalEstimatedNoise = bf.getShort();
|
||||||
|
PRFFLAG = bf.getInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,19 @@
|
|||||||
package org.meteoinfo.data.meteodata.radar;
|
package org.meteoinfo.data.meteodata.radar;
|
||||||
|
|
||||||
|
import org.apache.commons.compress.compressors.FileNameUtil;
|
||||||
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
||||||
|
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.meteoinfo.common.DataConvert;
|
import org.meteoinfo.common.DataConvert;
|
||||||
import org.meteoinfo.data.meteodata.DataInfo;
|
import org.meteoinfo.data.meteodata.DataInfo;
|
||||||
|
|
||||||
import java.io.RandomAccessFile;
|
import java.io.*;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
public class RadarDataUtil {
|
public class RadarDataUtil {
|
||||||
|
|
||||||
@ -53,6 +58,25 @@ public class RadarDataUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get InputStream from file name.
|
||||||
|
*
|
||||||
|
* @param fileName The file name
|
||||||
|
* @return The InputStream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static InputStream getInputStream(String fileName) throws IOException {
|
||||||
|
String fileExtent = FilenameUtils.getExtension(fileName).toLowerCase();
|
||||||
|
switch (fileExtent) {
|
||||||
|
case "bz2":
|
||||||
|
return new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
||||||
|
case "gz":
|
||||||
|
return new GzipCompressorInputStream(new FileInputStream(fileName));
|
||||||
|
default:
|
||||||
|
return new BufferedInputStream(Files.newInputStream(Paths.get(fileName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get radar data type
|
* Get radar data type
|
||||||
* @param fileName Data file name
|
* @param fileName Data file name
|
||||||
@ -60,21 +84,24 @@ public class RadarDataUtil {
|
|||||||
*/
|
*/
|
||||||
public static RadarDataType getRadarDataType(String fileName) {
|
public static RadarDataType getRadarDataType(String fileName) {
|
||||||
try {
|
try {
|
||||||
|
InputStream inputStream = getInputStream(fileName);
|
||||||
byte[] bytes = new byte[136];
|
byte[] bytes = new byte[136];
|
||||||
if (fileName.endsWith("bz2")) {
|
inputStream.read(bytes);
|
||||||
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
inputStream.close();
|
||||||
inputStream.read(bytes);
|
|
||||||
inputStream.close();
|
|
||||||
} else {
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(fileName, "r");
|
|
||||||
raf.seek(0);
|
|
||||||
raf.read(bytes);
|
|
||||||
raf.close();
|
|
||||||
}
|
|
||||||
byte[] magicBytes = Arrays.copyOf(bytes, 4);
|
byte[] magicBytes = Arrays.copyOf(bytes, 4);
|
||||||
int magic = DataConvert.bytes2Int(magicBytes, ByteOrder.LITTLE_ENDIAN);
|
int magic = DataConvert.bytes2Int(magicBytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
if (magic == 1297371986) {
|
if (magic == 1297371986) {
|
||||||
return RadarDataType.STANDARD;
|
byte[] inBytes = Arrays.copyOf(bytes, GenericHeader.length);
|
||||||
|
GenericHeader genericHeader = new GenericHeader(inBytes);
|
||||||
|
switch (genericHeader.genericType) {
|
||||||
|
case 1:
|
||||||
|
return RadarDataType.STANDARD;
|
||||||
|
case 16:
|
||||||
|
return RadarDataType.PA;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String radarT = new String(bytes);
|
String radarT = new String(bytes);
|
||||||
@ -86,14 +113,17 @@ public class RadarDataUtil {
|
|||||||
return RadarDataType.CC20;
|
return RadarDataType.CC20;
|
||||||
}
|
}
|
||||||
|
|
||||||
magicBytes = Arrays.copyOfRange(bytes, 14, 16);
|
magicBytes = Arrays.copyOf(bytes, 128);
|
||||||
if (Arrays.equals(magicBytes, new byte[]{1, 0})) {
|
SABRadarDataInfo.RadialHeader radialHeader = new SABRadarDataInfo.RadialHeader(magicBytes);
|
||||||
return RadarDataType.SAB;
|
if (radialHeader.messageType != 1) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
if (radialHeader.mSecond > 86400000) {
|
||||||
magicBytes = Arrays.copyOfRange(bytes, 8, 12);
|
return null;
|
||||||
if (Arrays.equals(magicBytes, new byte[]{16, 0, 0, 0})) {
|
}
|
||||||
return RadarDataType.PA;
|
LocalDateTime dateTime = radialHeader.getDateTime();
|
||||||
|
if (dateTime.getYear() >= 1990 && dateTime.getYear() <= LocalDateTime.now().getYear()) {
|
||||||
|
return RadarDataType.SAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -114,11 +144,13 @@ public class RadarDataUtil {
|
|||||||
} else {
|
} else {
|
||||||
switch (radarDataType) {
|
switch (radarDataType) {
|
||||||
case STANDARD:
|
case STANDARD:
|
||||||
return new CMARadarBaseDataInfo();
|
return new StandardRadarDataInfo();
|
||||||
|
case PA:
|
||||||
|
return new PARadarDataInfo();
|
||||||
case SAB:
|
case SAB:
|
||||||
return new SABRadarDataInfo();
|
return new SABRadarDataInfo();
|
||||||
/*case CC:
|
case CC:
|
||||||
return new CCRadarDataInfo();*/
|
return new CCRadarDataInfo();
|
||||||
case SC:
|
case SC:
|
||||||
return new SCRadarDataInfo();
|
return new SCRadarDataInfo();
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -10,12 +10,14 @@ import org.meteoinfo.ndarray.DataType;
|
|||||||
import org.meteoinfo.ndarray.Index;
|
import org.meteoinfo.ndarray.Index;
|
||||||
import org.meteoinfo.ndarray.math.ArrayUtil;
|
import org.meteoinfo.ndarray.math.ArrayUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class RadialRecord {
|
public class RadialRecord {
|
||||||
public String product;
|
public String product;
|
||||||
|
private RadarDataType radarDataType = RadarDataType.STANDARD;
|
||||||
private int binLength;
|
private int binLength;
|
||||||
private DataType dataType;
|
private DataType dataType;
|
||||||
private int fillValue;
|
private int fillValue;
|
||||||
@ -26,7 +28,7 @@ public class RadialRecord {
|
|||||||
public List<List<Float>> azimuth = new ArrayList<>();
|
public List<List<Float>> azimuth = new ArrayList<>();
|
||||||
public List<Integer> azimuthMinIndex = new ArrayList<>();
|
public List<Integer> azimuthMinIndex = new ArrayList<>();
|
||||||
public List<Array> distance = new ArrayList<>();
|
public List<Array> distance = new ArrayList<>();
|
||||||
public List<Integer> disResolution = new ArrayList<>();
|
public List<Float> disResolution = new ArrayList<>();
|
||||||
private final List<List<Array>> data = new ArrayList<>();
|
private final List<List<Array>> data = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +39,22 @@ public class RadialRecord {
|
|||||||
this.product = product;
|
this.product = product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get radar data type
|
||||||
|
* @return Radar data type
|
||||||
|
*/
|
||||||
|
public RadarDataType getRadarDataType() {
|
||||||
|
return this.radarDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set radar data type
|
||||||
|
* @param radarDataType Radar data type
|
||||||
|
*/
|
||||||
|
public void setRadarDataType(RadarDataType radarDataType) {
|
||||||
|
this.radarDataType = radarDataType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set bin length and update DataType
|
* Set bin length and update DataType
|
||||||
* @param value Bin length
|
* @param value Bin length
|
||||||
@ -55,6 +73,14 @@ public class RadialRecord {
|
|||||||
return this.dataType;
|
return this.dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set data type
|
||||||
|
* @param dataType Data type
|
||||||
|
*/
|
||||||
|
public void setDataType(DataType dataType) {
|
||||||
|
this.dataType = dataType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an azimuth value
|
* Add an azimuth value
|
||||||
* @param a Azimuth value
|
* @param a Azimuth value
|
||||||
@ -265,6 +291,9 @@ public class RadialRecord {
|
|||||||
}
|
}
|
||||||
variable.addAttribute(new Attribute("scale_factor", this.scale));
|
variable.addAttribute(new Attribute("scale_factor", this.scale));
|
||||||
variable.addAttribute(new Attribute("add_offset", this.offset));
|
variable.addAttribute(new Attribute("add_offset", this.offset));
|
||||||
|
if (this.radarDataType == RadarDataType.CC) {
|
||||||
|
variable.addAttribute(new Attribute("missing_value", -32768));
|
||||||
|
}
|
||||||
dataInfo.addVariable(variable);
|
dataInfo.addVariable(variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,6 +328,9 @@ public class RadialRecord {
|
|||||||
variable.addDimension(disDim);
|
variable.addDimension(disDim);
|
||||||
variable.addAttribute(new Attribute("scale_factor", this.scale));
|
variable.addAttribute(new Attribute("scale_factor", this.scale));
|
||||||
variable.addAttribute(new Attribute("add_offset", this.offset));
|
variable.addAttribute(new Attribute("add_offset", this.offset));
|
||||||
|
if (this.radarDataType == RadarDataType.CC) {
|
||||||
|
variable.addAttribute(new Attribute("missing_value", -32768));
|
||||||
|
}
|
||||||
dataInfo.addVariable(variable);
|
dataInfo.addVariable(variable);
|
||||||
|
|
||||||
variable = new Variable();
|
variable = new Variable();
|
||||||
@ -493,7 +525,7 @@ public class RadialRecord {
|
|||||||
public float getValue(int ei, float a, float r) {
|
public float getValue(int ei, float a, float r) {
|
||||||
List<Array> sData = this.data.get(ei);
|
List<Array> sData = this.data.get(ei);
|
||||||
int aziIdx = getAzimuthIndex(ei, a);
|
int aziIdx = getAzimuthIndex(ei, a);
|
||||||
int disRes = this.disResolution.get(ei);
|
float disRes = this.disResolution.get(ei);
|
||||||
int disIdx = (int) (r / disRes);
|
int disIdx = (int) (r / disRes);
|
||||||
Array rData = sData.get(aziIdx);
|
Array rData = sData.get(aziIdx);
|
||||||
float v;
|
float v;
|
||||||
@ -522,7 +554,7 @@ public class RadialRecord {
|
|||||||
*/
|
*/
|
||||||
public float interpolateValue(int ei, int ai, float r) {
|
public float interpolateValue(int ei, int ai, float r) {
|
||||||
List<Array> sData = this.data.get(ei);
|
List<Array> sData = this.data.get(ei);
|
||||||
int disRes = this.disResolution.get(ei);
|
float disRes = this.disResolution.get(ei);
|
||||||
float v;
|
float v;
|
||||||
Array rData = sData.get(ai);
|
Array rData = sData.get(ai);
|
||||||
float disIdx = r / disRes;
|
float disIdx = r / disRes;
|
||||||
|
|||||||
@ -17,6 +17,9 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -51,25 +54,6 @@ public class SABRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInf
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readDataInfo(String fileName) {
|
|
||||||
this.fileName = fileName;
|
|
||||||
if (fileName.endsWith(".bz2")) {
|
|
||||||
try {
|
|
||||||
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void readDataInfo(InputStream is) {
|
void readDataInfo(InputStream is) {
|
||||||
try {
|
try {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@ -99,11 +83,11 @@ public class SABRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInf
|
|||||||
record.azimuth.add(new ArrayList<>());
|
record.azimuth.add(new ArrayList<>());
|
||||||
record.azimuthMinIndex.add(0);
|
record.azimuthMinIndex.add(0);
|
||||||
if (isVelocityGroup(record)) {
|
if (isVelocityGroup(record)) {
|
||||||
record.disResolution.add(radialHeader.gateSizeOfDoppler);
|
record.disResolution.add((float) radialHeader.gateSizeOfDoppler);
|
||||||
record.distance.add(ArrayUtil.arrayRange1(radialHeader.rangeToFirstGateOfDop,
|
record.distance.add(ArrayUtil.arrayRange1(radialHeader.rangeToFirstGateOfDop,
|
||||||
radialHeader.gatesNumberOfDoppler, radialHeader.gateSizeOfDoppler));
|
radialHeader.gatesNumberOfDoppler, radialHeader.gateSizeOfDoppler));
|
||||||
} else {
|
} else {
|
||||||
record.disResolution.add(radialHeader.gateSizeOfReflectivity);
|
record.disResolution.add((float) radialHeader.gateSizeOfReflectivity);
|
||||||
record.distance.add(ArrayUtil.arrayRange1(radialHeader.rangeToFirstGateOfRef,
|
record.distance.add(ArrayUtil.arrayRange1(radialHeader.rangeToFirstGateOfRef,
|
||||||
radialHeader.gatesNumberOfReflectivity, radialHeader.gateSizeOfReflectivity));
|
radialHeader.gatesNumberOfReflectivity, radialHeader.gateSizeOfReflectivity));
|
||||||
}
|
}
|
||||||
@ -135,6 +119,7 @@ public class SABRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInf
|
|||||||
|
|
||||||
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
||||||
this.addAttribute(new Attribute("DataType", "Radial"));
|
this.addAttribute(new Attribute("DataType", "Radial"));
|
||||||
|
this.addAttribute(new Attribute("RadarDataType", "SA/SB"));
|
||||||
|
|
||||||
//Add dimensions and variables
|
//Add dimensions and variables
|
||||||
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
||||||
@ -172,6 +157,7 @@ public class SABRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInf
|
|||||||
|
|
||||||
static class RadialHeader {
|
static class RadialHeader {
|
||||||
public static int length = 128;
|
public static int length = 128;
|
||||||
|
public short messageType;
|
||||||
public int mSecond; // collection time for this radial, msecs since midnight
|
public int mSecond; // collection time for this radial, msecs since midnight
|
||||||
public short julianDate; // prob "collection time"
|
public short julianDate; // prob "collection time"
|
||||||
public short uRange; // unambiguous range
|
public short uRange; // unambiguous range
|
||||||
@ -202,6 +188,8 @@ public class SABRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInf
|
|||||||
public RadialHeader(byte[] inBytes) throws IOException {
|
public RadialHeader(byte[] inBytes) throws IOException {
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(inBytes);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(inBytes);
|
||||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
byteBuffer.position(14);
|
||||||
|
messageType = byteBuffer.getShort();
|
||||||
byteBuffer.position(28);
|
byteBuffer.position(28);
|
||||||
mSecond = byteBuffer.getInt();
|
mSecond = byteBuffer.getInt();
|
||||||
julianDate = byteBuffer.getShort();
|
julianDate = byteBuffer.getShort();
|
||||||
@ -228,6 +216,15 @@ public class SABRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInf
|
|||||||
nyquist = byteBuffer.getShort();
|
nyquist = byteBuffer.getShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get date time
|
||||||
|
* @return Date time
|
||||||
|
*/
|
||||||
|
public LocalDateTime getDateTime() {
|
||||||
|
long total = ((long) (julianDate - 1)) * 24 * 3600 * 1000 + mSecond;
|
||||||
|
return LocalDateTime.ofInstant(Instant.ofEpochMilli(total), ZoneId.systemDefault());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has reflectivity data or not
|
* Has reflectivity data or not
|
||||||
* @return Has reflectivity data
|
* @return Has reflectivity data
|
||||||
|
|||||||
@ -44,25 +44,6 @@ public class SCRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readDataInfo(String fileName) {
|
|
||||||
this.fileName = fileName;
|
|
||||||
if (fileName.endsWith(".bz2")) {
|
|
||||||
try {
|
|
||||||
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(Paths.get(fileName)));
|
|
||||||
readDataInfo(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void readDataInfo(InputStream is) {
|
void readDataInfo(InputStream is) {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = new byte[SCRadarDataInfo.RadarHeader.length];
|
byte[] bytes = new byte[SCRadarDataInfo.RadarHeader.length];
|
||||||
@ -94,7 +75,7 @@ public class SCRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo
|
|||||||
record.elevation.add(new ArrayList<>());
|
record.elevation.add(new ArrayList<>());
|
||||||
record.azimuth.add(new ArrayList<>());
|
record.azimuth.add(new ArrayList<>());
|
||||||
record.azimuthMinIndex.add(0);
|
record.azimuthMinIndex.add(0);
|
||||||
record.disResolution.add(layerParam.binWidth / 10);
|
record.disResolution.add(layerParam.binWidth / 10.f);
|
||||||
record.distance.add(ArrayUtil.arrayRange1(0,
|
record.distance.add(ArrayUtil.arrayRange1(0,
|
||||||
gateNum, layerParam.binWidth / 10));
|
gateNum, layerParam.binWidth / 10));
|
||||||
record.newScanData();
|
record.newScanData();
|
||||||
@ -121,6 +102,7 @@ public class SCRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo
|
|||||||
this.addAttribute(new Attribute("AntennaHeight", radarHeader.getHeight()));
|
this.addAttribute(new Attribute("AntennaHeight", radarHeader.getHeight()));
|
||||||
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
||||||
this.addAttribute(new Attribute("DataType", "Radial"));
|
this.addAttribute(new Attribute("DataType", "Radial"));
|
||||||
|
this.addAttribute(new Attribute("RadarDataType", "SC"));
|
||||||
|
|
||||||
//Add dimensions and variables
|
//Add dimensions and variables
|
||||||
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
||||||
|
|||||||
@ -0,0 +1,256 @@
|
|||||||
|
package org.meteoinfo.data.meteodata.radar;
|
||||||
|
|
||||||
|
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
||||||
|
import org.meteoinfo.common.DataConvert;
|
||||||
|
import org.meteoinfo.data.dimarray.Dimension;
|
||||||
|
import org.meteoinfo.data.meteodata.*;
|
||||||
|
import org.meteoinfo.ndarray.*;
|
||||||
|
import org.meteoinfo.ndarray.math.ArrayUtil;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class StandardRadarDataInfo extends BaseRadarDataInfo implements IRadarDataInfo {
|
||||||
|
|
||||||
|
private GenericHeader genericHeader;
|
||||||
|
private SiteConfig siteConfig;
|
||||||
|
private TaskConfig taskConfig;
|
||||||
|
private List<CutConfig> cutConfigs;
|
||||||
|
private List<RadialHeader> radialHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public StandardRadarDataInfo() {
|
||||||
|
this.meteoDataType = MeteoDataType.RADAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get radar data type
|
||||||
|
* @return Radar data type
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public RadarDataType getRadarDataType() {
|
||||||
|
return RadarDataType.STANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get generic header
|
||||||
|
* @return Generic header
|
||||||
|
*/
|
||||||
|
public GenericHeader getGenericHeader() {
|
||||||
|
return this.genericHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get site config
|
||||||
|
* @return Site config
|
||||||
|
*/
|
||||||
|
public SiteConfig getSiteConfig() {
|
||||||
|
return this.siteConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get task config
|
||||||
|
* @return Task config
|
||||||
|
*/
|
||||||
|
public TaskConfig getTaskConfig() {
|
||||||
|
return this.taskConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cut config list
|
||||||
|
* @return Cut config list
|
||||||
|
*/
|
||||||
|
public List<CutConfig> getCutConfigs() {
|
||||||
|
return this.cutConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get radial header list
|
||||||
|
* @return Radial header list
|
||||||
|
*/
|
||||||
|
public List<RadialHeader> getRadialHeaders() {
|
||||||
|
return this.radialHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidFile(RandomAccessFile raf) {
|
||||||
|
try {
|
||||||
|
raf.seek(0);
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
raf.read(bytes);
|
||||||
|
int magic = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
if (magic == 1297371986) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the data file format
|
||||||
|
* @param fileName Data file name
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
public static boolean canOpen(String fileName) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
if (fileName.endsWith("bz2")) {
|
||||||
|
BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName)));
|
||||||
|
inputStream.read(bytes);
|
||||||
|
inputStream.close();
|
||||||
|
} else {
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(fileName, "r");
|
||||||
|
raf.seek(0);
|
||||||
|
raf.read(bytes);
|
||||||
|
raf.close();
|
||||||
|
}
|
||||||
|
int magic = DataConvert.bytes2Int(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
if (magic == 1297371986) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void readDataInfo(InputStream raf) {
|
||||||
|
try {
|
||||||
|
genericHeader = new GenericHeader(raf);
|
||||||
|
siteConfig = new SiteConfig(raf);
|
||||||
|
this.antennaHeight = siteConfig.antennaHeight;
|
||||||
|
this.beamWidthVert = siteConfig.beamWidthVert;
|
||||||
|
|
||||||
|
//Add global attributes
|
||||||
|
this.addAttribute(new Attribute("StationCode", siteConfig.siteCode));
|
||||||
|
this.addAttribute(new Attribute("StationName", siteConfig.siteName));
|
||||||
|
this.addAttribute(new Attribute("StationLatitude", siteConfig.latitude));
|
||||||
|
this.addAttribute(new Attribute("StationLongitude", siteConfig.longitude));
|
||||||
|
this.addAttribute(new Attribute("AntennaHeight", siteConfig.antennaHeight));
|
||||||
|
this.addAttribute(new Attribute("GroundHeight", siteConfig.groundHeight));
|
||||||
|
this.addAttribute(new Attribute("RadarType", siteConfig.getRadarType()));
|
||||||
|
this.addAttribute(new Attribute("featureType", "RADIAL"));
|
||||||
|
this.addAttribute(new Attribute("DataType", "Radial"));
|
||||||
|
this.addAttribute(new Attribute("RadarDataType", "CMA Standard"));
|
||||||
|
|
||||||
|
//Read task configuration
|
||||||
|
taskConfig = new TaskConfig(raf);
|
||||||
|
this.addAttribute(new Attribute("TaskName", taskConfig.taskName));
|
||||||
|
this.addAttribute(new Attribute("TaskDescription", taskConfig.taskDescription));
|
||||||
|
|
||||||
|
//Read radial data
|
||||||
|
cutConfigs = new ArrayList<>();
|
||||||
|
CutConfig cutConfig;
|
||||||
|
for (int i = 0; i < taskConfig.cutNumber; i++) {
|
||||||
|
cutConfig = new CutConfig(raf);
|
||||||
|
cutConfigs.add(cutConfig);
|
||||||
|
if (i == 0) {
|
||||||
|
this.logResolution = cutConfig.logResolution;
|
||||||
|
this.dopplerResolution = cutConfig.dopplerResolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
radialHeaders = new ArrayList<>();
|
||||||
|
byte[] rhBytes = new byte[RadialHeader.length];
|
||||||
|
while (raf.read(rhBytes) != -1) {
|
||||||
|
RadialHeader radialHeader = new RadialHeader(rhBytes);
|
||||||
|
for (int i = 0; i < radialHeader.momentNumber; i++) {
|
||||||
|
MomentHeader momentHeader = new MomentHeader(raf);
|
||||||
|
String product = this.productMap.get(momentHeader.dataType);
|
||||||
|
RadialRecord record;
|
||||||
|
if (this.recordMap.containsKey(product)) {
|
||||||
|
record = this.recordMap.get(product);
|
||||||
|
} else {
|
||||||
|
record = new RadialRecord(product);
|
||||||
|
record.setBinLength(momentHeader.binLength);
|
||||||
|
record.scale = 1.f / momentHeader.scale;
|
||||||
|
record.offset = -momentHeader.offset / (float) momentHeader.scale;
|
||||||
|
this.recordMap.put(product, record);
|
||||||
|
}
|
||||||
|
if (radialHeader.radialNumber == 1) {
|
||||||
|
record.fixedElevation.add(cutConfigs.get(radialHeader.elevationNumber - 1).elevation);
|
||||||
|
record.elevation.add(new ArrayList<>());
|
||||||
|
record.azimuth.add(new ArrayList<>());
|
||||||
|
record.azimuthMinIndex.add(0);
|
||||||
|
if (isVelocityGroup(record)) {
|
||||||
|
record.disResolution.add((float) cutConfigs.get(radialHeader.elevationNumber - 1).dopplerResolution);
|
||||||
|
record.distance.add(ArrayUtil.arrayRange1(0, momentHeader.dataLength / momentHeader.binLength,
|
||||||
|
cutConfigs.get(radialHeader.elevationNumber - 1).dopplerResolution));
|
||||||
|
} else {
|
||||||
|
record.disResolution.add((float) cutConfigs.get(radialHeader.elevationNumber - 1).logResolution);
|
||||||
|
record.distance.add(ArrayUtil.arrayRange1(0, momentHeader.dataLength / momentHeader.binLength,
|
||||||
|
cutConfigs.get(radialHeader.elevationNumber - 1).logResolution));
|
||||||
|
}
|
||||||
|
record.newScanData();
|
||||||
|
}
|
||||||
|
record.elevation.get(record.elevation.size() - 1).add(radialHeader.elevation);
|
||||||
|
record.addAzimuth(radialHeader.azimuth);
|
||||||
|
byte[] bytes = new byte[momentHeader.dataLength];
|
||||||
|
raf.read(bytes);
|
||||||
|
record.addDataBytes(bytes);
|
||||||
|
}
|
||||||
|
radialHeaders.add(radialHeader);
|
||||||
|
}
|
||||||
|
raf.close();
|
||||||
|
|
||||||
|
//Add dimensions and variables
|
||||||
|
RadialRecord refRadialRecord = this.recordMap.get("dBZ");
|
||||||
|
radialDim = new Dimension();
|
||||||
|
radialDim.setName("radial");
|
||||||
|
radialDim.setLength(refRadialRecord.getMaxRadials());
|
||||||
|
this.addDimension(radialDim);
|
||||||
|
scanDim = new Dimension();
|
||||||
|
scanDim.setName("scan");
|
||||||
|
scanDim.setLength(refRadialRecord.getScanNumber());
|
||||||
|
this.addDimension(scanDim);
|
||||||
|
gateRDim = new Dimension();
|
||||||
|
gateRDim.setName("gateR");
|
||||||
|
gateRDim.setLength(refRadialRecord.getGateNumber(0));
|
||||||
|
this.addDimension(gateRDim);
|
||||||
|
makeRefVariables(refRadialRecord);
|
||||||
|
|
||||||
|
RadialRecord velRadialRecord = this.recordMap.get("V");
|
||||||
|
gateVDim = new Dimension();
|
||||||
|
gateVDim.setName("gateV");
|
||||||
|
gateVDim.setLength(velRadialRecord.getGateNumber(0));
|
||||||
|
this.addDimension(gateVDim);
|
||||||
|
makeVelVariables(velRadialRecord);
|
||||||
|
|
||||||
|
/*Dimension xyzDim = new Dimension(DimensionType.OTHER);
|
||||||
|
xyzDim.setShortName("xyz");
|
||||||
|
xyzDim.setDimValue(Array.factory(DataType.INT, new int[]{3}, new int[]{1,2,3}));
|
||||||
|
this.addDimension(xyzDim);
|
||||||
|
for (String product : this.recordMap.keySet()) {
|
||||||
|
this.recordMap.get(product).makeVariables(this, xyzDim);
|
||||||
|
}*/
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get scan elevations
|
||||||
|
* @return Scan elevations
|
||||||
|
*/
|
||||||
|
public List<Float> getElevations() {
|
||||||
|
List<Float> elevations = new ArrayList<>();
|
||||||
|
for (CutConfig cutConfig : this.cutConfigs) {
|
||||||
|
if (!elevations.contains(cutConfig.elevation))
|
||||||
|
elevations.add(cutConfig.elevation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elevations;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,13 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<MeteoInfo File="milconfig.xml" Type="configurefile">
|
<MeteoInfo File="milconfig.xml" Type="configurefile">
|
||||||
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\plot">
|
<Path OpenPath="D:\Working\MIScript\Jython\mis\io\radar">
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe\series"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe\series"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\radar"/>
|
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\radar\cinrad"/>
|
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\image"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\image"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
|
||||||
@ -16,17 +14,19 @@
|
|||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\gridshow"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\gridshow"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\plot"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\plot"/>
|
||||||
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\radar\cinrad"/>
|
||||||
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\radar"/>
|
||||||
</Path>
|
</Path>
|
||||||
<File>
|
<File>
|
||||||
<OpenedFiles>
|
<OpenedFiles>
|
||||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\test_read_SC.py"/>
|
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\radar_pa_1.py"/>
|
||||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\radar_cc_1.py"/>
|
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\radar_cc_1.py"/>
|
||||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\plot\plot_2darray_1.py"/>
|
<OpenedFile File="D:\Working\MIScript\Jython\mis\io\radar\radar_cma_base_vcs.py"/>
|
||||||
</OpenedFiles>
|
</OpenedFiles>
|
||||||
<RecentFiles>
|
<RecentFiles>
|
||||||
<RecentFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\test_read_SC.py"/>
|
<RecentFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\radar_pa_1.py"/>
|
||||||
<RecentFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\radar_cc_1.py"/>
|
<RecentFile File="D:\Working\MIScript\Jython\mis\io\radar\cinrad\radar_cc_1.py"/>
|
||||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\plot\plot_2darray_1.py"/>
|
<RecentFile File="D:\Working\MIScript\Jython\mis\io\radar\radar_cma_base_vcs.py"/>
|
||||||
</RecentFiles>
|
</RecentFiles>
|
||||||
</File>
|
</File>
|
||||||
<Font>
|
<Font>
|
||||||
@ -34,5 +34,5 @@
|
|||||||
</Font>
|
</Font>
|
||||||
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
|
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
|
||||||
<Figure DoubleBuffering="true"/>
|
<Figure DoubleBuffering="true"/>
|
||||||
<Startup MainFormLocation="-7,0" MainFormSize="1415,864"/>
|
<Startup MainFormLocation="-7,0" MainFormSize="1340,820"/>
|
||||||
</MeteoInfo>
|
</MeteoInfo>
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@ -35,7 +35,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<revision>3.8.9</revision>
|
<revision>3.8.10</revision>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
<maven.compiler.release>8</maven.compiler.release>
|
<maven.compiler.release>8</maven.compiler.release>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user