Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enhance Bufr data support including multi-category messages in a sing…
Browse files Browse the repository at this point in the history
…le data file, so that prepbufr was supported. Also CMA bufr tables were added.
Yaqiang committed Nov 27, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 7f24638 commit c54869c
Showing 12 changed files with 1,472 additions and 36 deletions.
6 changes: 6 additions & 0 deletions bufr/src/main/java/ucar/nc2/iosp/bufr/BufrConfig.java
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ static BufrConfig openFromMessage(RandomAccessFile raf, Message m, Element iospP
}

private String filename;
private Message message;
private StandardFields.StandardFieldsFromMessage standardFields;
private FieldConverter rootConverter;
private int messHash;
@@ -86,6 +87,7 @@ private BufrConfig(RandomAccessFile raf) {

private BufrConfig(RandomAccessFile raf, Message m) throws IOException {
this.filename = raf.getLocation();
this.message = m;
this.messHash = m.hashCode();
this.rootConverter = new FieldConverter(m.ids.getCenterId(), m.getRootDataDescriptor());
standardFields = StandardFields.extract(m);
@@ -95,6 +97,10 @@ public String getFilename() {
return filename;
}

public Message getMessage() {
return this.message;
}

public FieldConverter getRootConverter() {
return rootConverter;
}
128 changes: 104 additions & 24 deletions bufr/src/main/java/ucar/nc2/iosp/bufr/BufrIosp2.java
Original file line number Diff line number Diff line change
@@ -5,10 +5,8 @@
package ucar.nc2.iosp.bufr;

import java.io.IOException;
import java.util.Formatter;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.*;

import org.jdom2.Element;
import ucar.ma2.Array;
import ucar.ma2.ArraySequence;
@@ -46,9 +44,11 @@ public static void setDebugFlags(ucar.nc2.util.DebugFlags debugFlag) {
debugIter = debugFlag.isSet("Bufr/iter");
}

private Structure obsStructure;
private Message protoMessage; // prototypical message: all messages in the file must be the same.
//private Structure obsStructure;
//private Message protoMessage; // prototypical message: all messages in the file must be the same.
private MessageScanner scanner;
private List<Message> protoMessages; // prototypical messages: the messages with different category.
private List<RootVariable> rootVariables;
private HashSet<Integer> messHash;
private boolean isSingle;
private BufrConfig config;
@@ -69,25 +69,57 @@ public void build(RandomAccessFile raf, Group.Builder rootGroup, CancelTask canc
super.open(raf, rootGroup.getNcfile(), cancelTask);

scanner = new MessageScanner(raf);
protoMessage = scanner.getFirstDataMessage();
Message protoMessage = scanner.getFirstDataMessage();
if (protoMessage == null)
throw new IOException("No data messages in the file= " + raf.getLocation());
if (!protoMessage.isTablesComplete())
throw new IllegalStateException("BUFR file has incomplete tables");

// get all prototype messages - contains different message category in a Bufr data file
protoMessages = new ArrayList<>();
protoMessages.add(protoMessage);
int category = protoMessage.ids.getCategory();
while (scanner.hasNext()) {
Message message = scanner.next();
if (message.ids.getCategory() != category) {
protoMessages.add(message);
category = message.ids.getCategory();
}
}

// just get the fields
config = BufrConfig.openFromMessage(raf, protoMessage, iospParam);

// this fills the netcdf object
new BufrIospBuilder(protoMessage, config, rootGroup, raf.getLocation());
if (this.protoMessages.size() == 1) {
new BufrIospBuilder(protoMessage, config, rootGroup, raf.getLocation());
} else {
List<BufrConfig> configs = new ArrayList<>();
for (Message message : protoMessages) {
configs.add(BufrConfig.openFromMessage(raf, message, iospParam));
}
new BufrIospBuilder(protoMessage, configs, rootGroup, raf.getLocation());
}
isSingle = false;
}

@Override
public void buildFinish(NetcdfFile ncfile) {
obsStructure = (Structure) ncfile.findVariable(obsRecordName);
// The proto DataDescriptor must have a link to the Sequence object to read nested Sequences.
connectSequences(obsStructure.getVariables(), protoMessage.getRootDataDescriptor().getSubKeys());
// support multiple root variables in one Bufr data file
this.rootVariables = new ArrayList<>();
if (this.protoMessages.size() == 1) {
Structure obsStructure = (Structure) ncfile.findVariable(obsRecordName);
// The proto DataDescriptor must have a link to the Sequence object to read nested Sequences.
connectSequences(obsStructure.getVariables(), protoMessages.get(0).getRootDataDescriptor().getSubKeys());
this.rootVariables.add(new RootVariable(protoMessages.get(0), obsStructure));
} else {
for (int i = 0; i < this.protoMessages.size(); i++) {
Structure variable = (Structure) ncfile.getVariables().get(i);
Message message = protoMessages.get(i);
connectSequences(variable.getVariables(), message.getRootDataDescriptor().getSubKeys());
this.rootVariables.add(new RootVariable(message, variable));
}
}
}

private void connectSequences(List<Variable> variables, List<DataDescriptor> dataDescriptors) {
@@ -116,7 +148,7 @@ public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask)
super.open(raf, ncfile, cancelTask);

scanner = new MessageScanner(raf);
protoMessage = scanner.getFirstDataMessage();
Message protoMessage = scanner.getFirstDataMessage();
if (protoMessage == null)
throw new IOException("No data messages in the file= " + ncfile.getLocation());
if (!protoMessage.isTablesComplete())
@@ -127,7 +159,7 @@ public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask)

// this fills the netcdf object
Construct2 construct = new Construct2(protoMessage, config, ncfile);
obsStructure = construct.getObsStructure();
Structure obsStructure = construct.getObsStructure();
ncfile.finish();
isSingle = false;
}
@@ -136,7 +168,7 @@ public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask)
public void open(RandomAccessFile raf, NetcdfFile ncfile, Message single) throws IOException {
this.raf = raf;

protoMessage = single;
Message protoMessage = single;
protoMessage.getRootDataDescriptor(); // construct the data descriptors, check for complete tables
if (!protoMessage.isTablesComplete())
throw new IllegalStateException("BUFR file has incomplete tables");
@@ -145,7 +177,7 @@ public void open(RandomAccessFile raf, NetcdfFile ncfile, Message single) throws

// this fills the netcdf object
Construct2 construct = new Construct2(protoMessage, config, ncfile);
obsStructure = construct.getObsStructure();
Structure obsStructure = construct.getObsStructure();
isSingle = true;

ncfile.finish();
@@ -175,28 +207,67 @@ public Element getElem() {

@Override
public Array readData(Variable v2, Section section) {
findRootSequence();
return new ArraySequence(obsStructure.makeStructureMembers(), new SeqIter(), nelems);
RootVariable rootVariable = findRootSequence(v2);
Structure obsStructure = rootVariable.getVariable();
return new ArraySequence(obsStructure.makeStructureMembers(), new SeqIter(rootVariable), nelems);
}

@Override
public StructureDataIterator getStructureIterator(Structure s, int bufferSize) {
findRootSequence();
return isSingle ? new SeqIterSingle() : new SeqIter();
RootVariable rootVariable = findRootSequence(s);
return isSingle ? new SeqIterSingle(rootVariable) : new SeqIter(rootVariable);
}

private Structure findRootSequence() {
return (Structure) this.ncfile.findVariable(BufrIosp2.obsRecordName);
}

// find root sequence from root variable list
private RootVariable findRootSequence(Variable var) {
for (RootVariable rootVariable : this.rootVariables) {
if (rootVariable.getVariable().getShortName().equals(var.getShortName())) {
return rootVariable;
}
}
return null;
}

private void findRootSequence() {
this.obsStructure = (Structure) this.ncfile.findVariable(BufrIosp2.obsRecordName);
// root variable contains prototype message and corresponding variable
private class RootVariable {
private Message protoMessage;
private Structure variable;

public RootVariable(Message message, Structure variable) {
this.protoMessage = message;
this.variable = variable;
}

public Message getProtoMessage() {
return this.protoMessage;
}

public Structure getVariable() {
return this.variable;
}
}

private class SeqIter implements StructureDataIterator {
StructureDataIterator currIter;
int recnum;
// add its own prototype message and observation structure
Message protoMessage;
Structure obsStructure;

SeqIter() {
SeqIter(Message message, Structure structure) {
this.protoMessage = message;
this.obsStructure = structure;
reset();
}

SeqIter(RootVariable rootVariable) {
this(rootVariable.protoMessage, rootVariable.variable);
}

@Override
public StructureDataIterator reset() {
recnum = 0;
@@ -286,11 +357,20 @@ public void close() {
private class SeqIterSingle implements StructureDataIterator {
StructureDataIterator currIter;
int recnum;
// add its own prototype message and observation structure
Message protoMessage;
Structure obsStructure;

SeqIterSingle() {
SeqIterSingle(Message message, Structure structure) {
protoMessage = message;
obsStructure = structure;
reset();
}

SeqIterSingle(RootVariable rootVariable) {
this(rootVariable.protoMessage, rootVariable.variable);
}

@Override
public StructureDataIterator reset() {
recnum = 0;
@@ -350,7 +430,7 @@ public void close() {
public String getDetailInfo() {
Formatter ff = new Formatter();
ff.format("%s", super.getDetailInfo());
protoMessage.dump(ff);
protoMessages.get(0).dump(ff);
ff.format("%n");
config.show(ff);
return ff.toString();
76 changes: 75 additions & 1 deletion bufr/src/main/java/ucar/nc2/iosp/bufr/BufrIospBuilder.java
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ class BufrIospBuilder {
private static final boolean warnUnits = false;

private final Group.Builder rootGroup;
private final Sequence.Builder recordStructure;
private Sequence.Builder recordStructure;
private final Formatter coordinates = new Formatter();

private int tempNo = 1; // fishy
@@ -75,6 +75,42 @@ class BufrIospBuilder {
}
}

BufrIospBuilder(Message proto, List<BufrConfig> bufrConfigs, Group.Builder root, String location) {
this.rootGroup = root;

// global Attributes
AttributeContainerMutable atts = root.getAttributeContainer();
atts.addAttribute(CDM.HISTORY, "Read using CDM BufrIosp2");
atts.addAttribute("location", location);

atts.addAttribute("BUFR:categoryName", proto.getLookup().getCategoryName());
atts.addAttribute("BUFR:subCategoryName", proto.getLookup().getSubCategoryName());
atts.addAttribute("BUFR:centerName", proto.getLookup().getCenterName());
atts.addAttribute(BufrIosp2.centerId, proto.ids.getCenterId());
atts.addAttribute("BUFR:subCenter", proto.ids.getSubCenterId());
atts.addAttribute("BUFR:table", proto.ids.getMasterTableId());
atts.addAttribute("BUFR:tableVersion", proto.ids.getMasterTableVersion());
atts.addAttribute("BUFR:localTableVersion", proto.ids.getLocalTableVersion());
atts.addAttribute("Conventions", "BUFR/CDM");
atts.addAttribute("BUFR:edition", proto.is.getBufrEdition());

String header = proto.getHeader();
if (header != null && !header.isEmpty()) {
atts.addAttribute("WMO Header", header);
}

for (BufrConfig bufrConfig : bufrConfigs) {
String varName = proto.getLookup().getCategoryName(bufrConfig.getMessage().ids.getCategory());
Sequence.Builder rs = Sequence.builder().setName(varName);
this.rootGroup.addVariable(rs);
makeObsRecord(bufrConfig, rs);
String coordS = coordinates.toString();
if (!coordS.isEmpty()) {
rs.addAttribute(new Attribute("coordinates", coordS));
}
}
}

Sequence.Builder getObsStructure() {
return recordStructure;
}
@@ -117,6 +153,44 @@ private void makeObsRecord(BufrConfig bufrConfig) {
}
}

private void makeObsRecord(BufrConfig bufrConfig, Sequence.Builder rs) {
BufrConfig.FieldConverter root = bufrConfig.getRootConverter();
for (BufrConfig.FieldConverter fld : root.flds) {
DataDescriptor dkey = fld.dds;
if (!dkey.isOkForVariable()) {
continue;
}

if (dkey.replication == 0) {
addSequence(rootGroup, rs, fld);

} else if (dkey.replication > 1) {

List<BufrConfig.FieldConverter> subFlds = fld.flds;
List<DataDescriptor> subKeys = dkey.subKeys;
if (subKeys.size() == 1) { // only one member
DataDescriptor subDds = dkey.subKeys.get(0);
BufrConfig.FieldConverter subFld = subFlds.get(0);
if (subDds.dpi != null) {
addDpiStructure(rs, fld, subFld);

} else if (subDds.replication == 1) { // one member not a replication
Variable.Builder v = addVariable(rootGroup, rs, subFld, dkey.replication);
v.setSPobject(fld); // set the replicating field as SPI object

} else { // one member is a replication (two replications in a row)
addStructure(rootGroup, rs, fld, dkey.replication);
}
} else if (subKeys.size() > 1) {
addStructure(rootGroup, rs, fld, dkey.replication);
}

} else { // replication == 1
addVariable(rootGroup, rs, fld, dkey.replication);
}
}
}

private void addStructure(Group.Builder group, Structure.Builder parent, BufrConfig.FieldConverter fld, int count) {
DataDescriptor dkey = fld.dds;
String uname = findUniqueName(parent, fld.getName(), "struct");
5 changes: 4 additions & 1 deletion bufr/src/main/java/ucar/nc2/iosp/bufr/BufrTableLookup.java
Original file line number Diff line number Diff line change
@@ -127,11 +127,14 @@ public String getSubCategoryName() { // throws IOException {
return subcatName;
}


public String getCategoryName() {
return TableA.getDataCategory(getCategory());
}

public String getCategoryName(int cat) {
return TableA.getDataCategoryName(cat);
}

public String getCategoryNo() {
String result = getCategory() + "." + getSubCategory();
if (getLocalSubCategory() >= 0)
60 changes: 57 additions & 3 deletions bufr/src/main/java/ucar/nc2/iosp/bufr/EmbeddedTable.java
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.iosp.bufr.tables.TableA;
import ucar.nc2.iosp.bufr.tables.TableB;
import ucar.nc2.iosp.bufr.tables.TableD;
import ucar.nc2.iosp.bufr.tables.WmoXmlReader;
@@ -33,14 +34,16 @@ public class EmbeddedTable {

private List<Message> messages = new ArrayList<>();
private boolean tableRead;
private TableA a;
private TableB b;
private TableD d;
private Structure seq2, seq3, seq4;
private Structure seq1, seq2, seq3, seq4;
private TableLookup tlookup;

EmbeddedTable(Message m, RandomAccessFile raf) {
this.raf = raf;
this.ids = m.ids;
a = new TableA("embed", raf.getLocation());
b = new TableB("embed", raf.getLocation());
d = new TableD("embed", raf.getLocation());
}
@@ -51,10 +54,19 @@ public void addTable(Message m) {

private void read2() throws IOException {
Message proto = messages.get(0);

// make root sub key data descriptors name as null, so the following construct
// will have seq2 and seq3 variables
DataDescriptor root = proto.getRootDataDescriptor();
for (DataDescriptor ds : root.subKeys) {
ds.name = null;
}

BufrConfig config = BufrConfig.openFromMessage(raf, proto, null);
Construct2 construct = new Construct2(proto, config, new NetcdfFileSubclass());

Sequence obs = construct.getObsStructure();
seq1 = (Structure) obs.findVariable("seq1");
seq2 = (Structure) obs.findVariable("seq2");
seq3 = (Structure) obs.findVariable("seq3");
seq4 = (Structure) seq3.findVariable("seq4");
@@ -81,7 +93,12 @@ private void add(StructureData data) throws IOException {
if (showB)
System.out.printf("%s%n", m);
if (m.getDataType() == DataType.SEQUENCE) {
if (m.getName().equals("seq2")) {
if (m.getName().equals("seq1")) {
ArraySequence seq = data.getArraySequence(m);
StructureDataIterator iter = seq.getStructureDataIterator();
while (iter.hasNext())
addTableEntryA(iter.next());
} else if (m.getName().equals("seq2")) {
ArraySequence seq = data.getArraySequence(m);
StructureDataIterator iter = seq.getStructureDataIterator();
while (iter.hasNext())
@@ -96,6 +113,43 @@ private void add(StructureData data) throws IOException {
}
}

private void addTableEntryA(StructureData sdata) {
int scale = 0, refVal = 0, width = 0;
String entry = "", line1 = "", line2 = "";
List<StructureMembers.Member> members = sdata.getMembers();
List<Variable> vars = seq1.getVariables();
for (int i = 0; i < vars.size(); i++) {
Variable v = vars.get(i);
StructureMembers.Member m = members.get(i);
String data = sdata.getScalarString(m);
Attribute att = v.attributes().findAttribute(BufrIosp2.fxyAttName);
switch (att.getStringValue()) {
case "0-0-1":
entry = sdata.getScalarString(m);
break;
case "0-0-2":
line1 = sdata.getScalarString(m);
break;
case "0-0-3":
line2 = sdata.getScalarString(m);
break;
}
}

int code = Integer.parseInt(entry);

// split name and description from appended line 1 and 2
String desc = (line1 + line2).trim();
String name = "";
int pos = desc.indexOf(' ');
if (pos > 0) {
name = desc.substring(0, pos);
}

TableA.Descriptor d = a.addDescriptor(code, desc);
d.setName(name);
}

private void addTableEntryB(StructureData sdata) {
String name = "", units = "", signScale = null, signRef = null;
int scale = 0, refVal = 0, width = 0;
@@ -255,7 +309,7 @@ TableLookup getTableLookup() throws IOException {
if (!tableRead) {
read2();
tableRead = true;
tlookup = new TableLookup(ids, b, d);
tlookup = new TableLookup(ids, a, b, d);
}
return tlookup;
}
27 changes: 27 additions & 0 deletions bufr/src/main/java/ucar/nc2/iosp/bufr/TableLookup.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
package ucar.nc2.iosp.bufr;

import ucar.nc2.iosp.bufr.tables.BufrTables;
import ucar.nc2.iosp.bufr.tables.TableA;
import ucar.nc2.iosp.bufr.tables.TableB;
import ucar.nc2.iosp.bufr.tables.TableD;
import javax.annotation.concurrent.Immutable;
@@ -22,6 +23,7 @@ public class TableLookup {
private static final boolean showErrors = false;

/////////////////////////////////////////
private TableA localTableA = null;
private final TableB localTableB;
private final TableD localTableD;

@@ -53,10 +55,23 @@ public TableLookup(BufrIdentificationSection ids, TableB b, TableD d) throws IOE
this.mode = BufrTables.Mode.localOverride;
}

public TableLookup(BufrIdentificationSection ids, TableA a, TableB b, TableD d) throws IOException {
this.wmoTableB = BufrTables.getWmoTableB(ids.getMasterTableVersion());
this.wmoTableD = BufrTables.getWmoTableD(ids.getMasterTableVersion());
this.localTableA = a;
this.localTableB = b;
this.localTableD = d;
this.mode = BufrTables.Mode.localOverride;
}

public String getWmoTableBName() {
return wmoTableB.getName();
}

public String getLocalTableAName() {
return localTableA == null ? "none" : localTableA.getName();
}

public String getLocalTableBName() {
return localTableB == null ? "none" : localTableB.getName();
}
@@ -73,6 +88,10 @@ public BufrTables.Mode getMode() {
return mode;
}

public TableA getLocalTableA() {
return localTableA;
}

public TableB getLocalTableB() {
return localTableB;
}
@@ -81,6 +100,14 @@ public TableD getLocalTableD() {
return localTableD;
}

public TableA.Descriptor getDescriptorTableA(int code) {
if (localTableA != null) {
return localTableA.getDescriptor(code);
} else {
return null;
}
}

public TableB.Descriptor getDescriptorTableB(short fxy) {
TableB.Descriptor b = null;
boolean isWmoRange = Descriptor.isWmoRange(fxy);
109 changes: 104 additions & 5 deletions bufr/src/main/java/ucar/nc2/iosp/bufr/tables/TableA.java
Original file line number Diff line number Diff line change
@@ -16,7 +16,9 @@
public class TableA {
private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TableA.class);
private static final String TABLEA_FILENAME = "wmo/BUFR_37_0_0_TableA_en.xml";
private static Map<Integer, String> tableA;
private static Map<Integer, Descriptor> tableA;
private final String name;
private final String location;

/*
* <BUFR_19_1_1_TableA_en>
@@ -37,7 +39,7 @@ private static void init() {
String filename = BufrTables.RESOURCE_PATH + TABLEA_FILENAME;
try (InputStream is = CodeFlagTables.class.getResourceAsStream(filename)) {

HashMap<Integer, String> map = new HashMap<>(100);
HashMap<Integer, Descriptor> map = new HashMap<>(100);
SAXBuilder builder = new SAXBuilder();
builder.setExpandEntities(false);
org.jdom2.Document tdoc = builder.build(is);
@@ -51,7 +53,8 @@ private static void init() {

try {
int code = Integer.parseInt(codeS);
map.put(code, desc);
Descriptor descriptor = new Descriptor(code, desc);
map.put(code, descriptor);
} catch (NumberFormatException e) {
log.debug("NumberFormatException on line " + line + " in " + codeS);
}
@@ -64,6 +67,18 @@ private static void init() {
}
}

public TableA(String name, String location) {
this.name = name;
this.location = location;
tableA = new HashMap<>();
}

public Descriptor getDescriptor(int code) {
if (tableA == null)
init();
return tableA.get(code);
}

/**
* data category name, from table A
*
@@ -73,8 +88,92 @@ private static void init() {
public static String getDataCategory(int cat) {
if (tableA == null)
init();
String result = tableA.get(cat);
return result != null ? result : "Unknown category=" + cat;
Descriptor descriptor = tableA.get(cat);
return descriptor != null ? descriptor.getDescription() : "Unknown category=" + cat;
}

/**
* data category name, from table A
*
* @param cat data category
* @return category name, or null if not found
*/
public static String getDataCategoryName(int cat) {
if (tableA == null)
init();
Descriptor descriptor = tableA.get(cat);
return descriptor != null ? descriptor.getName() : "obs_" + cat;
}

public String getName() {
return name;
}

public String getLocation() {
return location;
}

public TableA.Descriptor addDescriptor(int code, String description) {
TableA.Descriptor d = new TableA.Descriptor(code, description);
tableA.put(code, d);
return d;
}

public static class Descriptor implements Comparable<Descriptor> {
private int code;
private String name;
private String description;
private boolean localOverride;

Descriptor(int code, String description) {
this.code = code;
this.description = description;
this.name = "obs_" + String.valueOf(code);
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return this.description;
}

/**
* Get code
*
* @return Code
*/
public int getCode() {
return this.code;
}

public String toString() {
return String.valueOf(code) + " " + getName() + " " +
this.description;
}

@Override
public int compareTo(Descriptor o) {
return code - o.getCode();
}

public boolean isLocal() {
return ((code >= 102) && (code <= 239));
}

public void setLocalOverride(boolean isOverride) {
this.localOverride = isOverride;
}

public boolean getLocalOverride() {
return localOverride;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
ClassNo,FXY,ElementName_cn,BUFR_Unit,BUFR_Scale,BUFR_ReferenceValue,BUFR_DataWidth_Bits,ElementName_en,No
1,1192,本地测站标识,CCITT IA5,0,0,72,,1
2,2192,探空仪生产厂家,Code table,0,0,7,,2
2,2200,气压的计算方法,Code table,0,0,4,,3
2,2193,施放计数,Numeric,0,0,8,,4
2,2194,附加物重量,kg,3,0,14,,5
2,2195,球与探空仪间实际绳长,m,1,0,10,,6
2,2196,总举力,kg,3,0,14,,7
2,2197,净举力,kg,3,0,14,,8
2,2198,平均升速,m/min,1,0,14,,9
10,10192,气压基测值,Pa,-1,0,14,,10
10,10193,气压仪器值,Pa,-1,0,14,,11
10,10194,气压偏差,Pa,-1,0,14,,12
12,12192,温度基测值,K,2,0,16,,13
12,12193,温度仪器值,K,2,0,16,,14
12,12194,温度偏差,K,2,0,16,,15
13,13192,相对湿度基测值,%,0,0,7,,16
13,13193,相对湿度仪器值,%,0,0,7,,17
13,13194,相对湿度偏差,%,0,0,7,,18
2,2199,仪器检测结论,Code table,0,0,2,,19
4,4192,时间差,s,0,-86400,18,,20
8,8192,时间含义标识,Code table,0,0,5,,21
20,20192,国内观测天气现象,Code table,0,0,7,,22
28,28192,采样时距离,Code table,0,0,19,,23
26,26192,国内观测天气现象,Code table,0,0,7,,24
2,2201,本地地面传感器标识,Code table,0,0,3,,25
20,20211,连续观测天气现象,CCITT IA5,0,0,960,,26
2,2207,日照时制方式,Code table,0,0,3,,27
12,12195,路面温度,K,1,0,12,,28
12,12196,10cm路基温度,K,1,0,12,,29
13,13195,雪压,g/cm2,0,0,11,,30
13,13196,蒸发水位,mm,0,0,6,,31
20,20193,冻土深度第一层上限值,m,2,0,10,,32
20,20194,冻土深度第一层下限值,m,2,0,10,,33
20,20195,冻土深度第二层上限值,m,2,0,10,,34
20,20196,冻土深度第二层下限值,m,2,0,10,,35
20,20197,龙卷、尘卷风距测站距离,m,-3,0,8,,36
20,20198,电线积冰-南北方向直径,m,3,0,10,,37
20,20199,电线积冰-南北方向厚度,m,3,0,10,,38
20,20200,电线积冰-南北方向重量,1g/m,0,0,14,,39
20,20201,电线积冰-东西方向直径,m,3,0,10,,40
20,20202,电线积冰-东西方向厚度,m,3,0,10,,41
20,20203,电线积冰-东西方向重量,1g/m,0,0,14,,42
20,20204,路面状况,Code table,0,0,5,,43
20,20205,路面雪层厚度,mm,0,0,12,,44
20,20206,路面水层厚度,mm,1,0,8,,45
20,20207,路面冰层厚度,mm,1,0,8,,46
20,20208,融雪剂浓度,%,0,0,5,,47
26,26195,现象出现时间的时,Hour,0,0,5,,48
26,26196,现象出现时间的分,Minute,0,0,6,,49
20,20212,小时连续观测天气现象,CCITT IA5,0,0,3600,,50
2,2202,本地辐射传感器标识,Code table,0,0,10,,51
14,14192,直射辐射辐照度,Wm-2,0,0,24,,52
14,14193,散射辐射辐照度,Wm-2,0,0,24,,53
14,14194,总辐射辐照度,Wm-2,0,0,24,,54
14,14195,反射辐射辐照度,Wm-2,0,0,24,,55
14,14196,大气长波辐射辐照度,Wm-2,0,0,24,,56
14,14197,地球长波辐射辐照度,Wm-2,0,0,24,,57
14,14198,紫外辐射(UVA)辐照度,Wm-2,2,0,24,,58
14,14199,紫外辐射(UVB)辐照度,Wm-2,2,0,24,,59
14,14200,光合有效辐射辐照度,umol/s.m-2,0,0,24,,60
14,14201,反射辐射曝辐量,MJm-2,2,0,15,,61
14,14202,大气长波辐射曝辐量,MJm-2,2,0,15,,62
14,14203,地球长波辐射曝辐量,MJm-2,2,0,15,,63
14,14204,紫外辐射(UVA) 曝辐量,MJm-2,3,0,15,,64
14,14205,紫外辐射(UVB) 曝辐量,MJm-2,3,0,15,,65
14,14206,净全辐射辐照度,Wm-2,0,-1000,24,,66
14,14207,紫外辐射辐照度,Wm-2,2,0,24,,67
14,14208,紫外辐射曝辐量,MJm-2,-3,0,15,,68
14,14209,大气浑浊度,,2,0,12,,69
20,20209,作用层情况,Code table,0,0,3,,70
20,20210,作用层状况,Code table,0,0,4,,71
2,2203,酸雨复测指示码,Code table,0,0,4,,72
2,2204,酸雨测量电导率的手动温度补偿功能指示码,Code table,0,0,1,,73
2,2205,酸雨样品延迟测量指示码,Code table,0,0,4,,74
2,2206,酸雨降水样品异常状况,Code table,0,0,3,,75
11,11235,,Code table,0,0,6,Turbulence index,76
21,21192,,dB,2,-5000,13,Radar back scatter,77
12,12197,24小时变温,K,1,-2732,12,,78
15,15192,K=0.4负离子值,个/cm3,-1,0,17,,79
15,15193,K=0.4正离子值,个/cm3,-1,0,17,,80
48,48192,计算机通信状态,Code table,0,0,2,,81
48,48193,设备断电报警,Code table,0,0,2,,82
49,49192,是否做异常数据剔除与外延,Code table,0,0,2,,83
49,49193,异常数据判断阈值倍数,Numeric,2,0,10,,84
33,33192,是否有异常数据,Code table,0,0,2,,85
33,33193,是否有数据缺失,Code table,0,0,2,,86
14,14210,太阳直接辐射辐照度,Wm-2,0,0,24,,87
14,14211,直射辐射曝辐量,MJm-2,2,0,15,,88
14,14212,散射辐射曝辐量,MJm-2,2,0,15,,89
14,14213,总辐射曝辐量,MJm-2,2,0,15,,90
14,14214,净全辐射曝辐量,MJm-2,2,-1000,15,,91
14,14215,光合有效曝辐量,MJm-2,2,0,15,,92
13,13205,谱图数据编号,Code table,0,0,12,,93
13,13206,雨滴个数,Numeric,0,0,16,,94
2,2240,雨滴谱的设备类型,Code table,0,0,4,,95
13,13162,Cloud liquid water,kg m-2,2,0,8,Cloud liquid water,96

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -71,3 +71,7 @@ EUMETSAT.19, 254, -1, -1, -1, -1, resource:/resources/bufrTables/l
#
# EUMETNET OPERA - using -1 !!!!
#255, 255, -1, 5, -1, resource:/resources/bufrTables/local/opera/localtabb_65535_5.csv, opera, resource:/resources/bufrTables/local/opera/localtabd_65535_5.csv, opera,
#
# CMA
# CMA Bufr table
CMA.23, 38, 0, 23, -1, -1, resource:/resources/bufrTables/local/cma/cma_bufr_tableb.csv, wmo_csv, resource:/resources/bufrTables/local/cma/cma_bufr_tabled.csv, wmo_csv
19 changes: 19 additions & 0 deletions cdm/core/src/main/java/ucar/ma2/ArraySequence.java
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
*/
package ucar.ma2;

import ucar.nc2.Sequence;
import ucar.nc2.util.Indent;
import java.io.IOException;
import java.util.ArrayList;
@@ -361,6 +362,24 @@ private Array extractMemberArrayFromIteration(StructureMembers.Member proxym, in
StructureMembers membersw = proxym.getStructureMembers().toBuilder(false).build();
return new ArrayStructureW(membersw, rshape, result.toArray(new StructureData[0]));
}

// add SEQUENCE data type
case SEQUENCE: {
ArrayList<ArraySequence> result = new ArrayList<>(initial);
while (sdataIter.hasNext()) {
StructureData sdata = sdataIter.next();
StructureMembers.Member realm = sdata.getStructureMembers().findMember(proxym.getName());
ArraySequence as = sdata.getArraySequence(realm);
result.add(as);
count++;
}
ArraySequence[] da = new ArraySequence[result.size()];
int i = 0;
for (ArraySequence d : result)
da[i++] = d;
dataArray = da;
break;
}
}
}

61 changes: 59 additions & 2 deletions cdm/core/src/main/java/ucar/nc2/Variable.java
Original file line number Diff line number Diff line change
@@ -789,8 +789,65 @@ public Array reallyRead(Variable client, CancelTask cancelTask) throws IOExcepti
List<String> memList = new ArrayList<>();
memList.add(this.getShortName());
Structure s = getParentStructure().select(memList);
ArrayStructure as = (ArrayStructure) s.read();
return as.extractMemberArray(as.findMember(getShortName()));

// s.read() may return an ArrayObject with sequence data type when the client is sequence.
// That's way we need the code to read the data array from it.
Array a = s.read();
if (a instanceof ArrayStructure) {
ArrayStructure as = (ArrayStructure) a;
return as.extractMemberArray(as.findMember(getShortName()));
} else {
IndexIterator iter = a.getIndexIterator();
List<Array> arrays = new ArrayList<>();
int len = 0;
DataType dataType1 = DataType.SEQUENCE;
while (iter.hasNext()) {
ArrayStructure as = (ArrayStructure) iter.getObjectNext();
if (as == null) {
arrays.add(null);
} else {
Array array = as.extractMemberArray(as.findMember(getShortName()));
if (len == 0) {
dataType1 = array.getDataType();
}
arrays.add(array);
len += (int) array.getSize();
}
}

if (arrays.size() == 1) {
return arrays.get(0);
} else {
Array r;
IndexIterator rIter;
switch (dataType1) {
case SEQUENCE:
case STRUCTURE:
len = arrays.size();
r = Array.factory(dataType1, new int[]{len});
for (int i = 0; i < len; i++) {
if (arrays.get(i).getSize() > 0)
r.setObject(i, arrays.get(i).getObject(0));
}
break;
default:
r = Array.factory(dataType1, new int[]{len});
rIter = r.getIndexIterator();
for (Array array : arrays) {
if (array != null) {
IndexIterator aIter = array.getIndexIterator();
while (aIter.hasNext()) {
if (rIter.hasNext()) {
rIter.setObjectNext(aIter.getObjectNext());
}
}
}
}
break;
}
return r;
}
}
}

try {

0 comments on commit c54869c

Please sign in to comment.