support SA/SB, SC, PA, CC radar data files

This commit is contained in:
wyq 2024-06-01 13:30:43 +08:00
parent ec4e09f946
commit da789f25be
15 changed files with 1388 additions and 761 deletions

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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) {

View File

@ -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());
} }
} }
} }

View File

@ -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};
}
}

View File

@ -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();
}
} }

View File

@ -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();
}
}
}

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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");

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>