Skip to content

Commit

Permalink
Add support for float16 datatypes (#179)
Browse files Browse the repository at this point in the history
* Add support for float16 datatypes
* Add tests for compound and array of float16 values
  • Loading branch information
byrnHDF authored May 3, 2024
1 parent e26dd99 commit a4394b0
Show file tree
Hide file tree
Showing 14 changed files with 603 additions and 101 deletions.
12 changes: 6 additions & 6 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -831,11 +831,11 @@
</sequential>
</macrodef>

<target name="runauitest" description="Runs the test you specify on the command line with -Dtest=" depends="jar, clean-junit-uitest, compile-test, ensure-test5-name, ensure-test4-name, jacoco">
<target name="runauitest" description="Runs the test you specify on the command line with -Dtest=" depends="deploy,jar, clean-junit-uitest, compile-test, ensure-test5-name, ensure-test4-name, jacoco">
<mkdir dir="${report.dir}" />

<run-ui-junit
rootdir="${basedir}/${uitestclasses.dir}"
rootdir="${basedir}/${jar.dir}"
workdir="${basedir}/${uitestclasses.dir}/uitest"
propfile="${basedir}/${uitestclasses.dir}/.hdfview${app.version}"
includes="**/${uitestclasses.dir}/${test}.class"
Expand All @@ -851,7 +851,7 @@
<mkdir dir="${report.dir}" />

<run-ui-junit
rootdir="${basedir}/${uitestclasses.dir}"
rootdir="${basedir}/${jar.dir}"
workdir="${basedir}/${uitestclasses.dir}/uitest"
propfile="${basedir}/${uitestclasses.dir}/.hdfview${app.version}"
includes="**/${uitestclasses.dir}/${test}.class"
Expand All @@ -865,7 +865,7 @@

<!-- Run the top-level HDF4 UI tests -->
<run-ui-junit
rootdir="${basedir}/${hdf4uitestclasses.dir}"
rootdir="${basedir}/${jar.dir}"
workdir="${basedir}/${hdf4uitestclasses.dir}"
propfile="${basedir}/${uitestclasses.dir}/.hdfview${app.version}"
includes="**/${hdf4uitestclasses.dir}/${test}.class"
Expand All @@ -879,7 +879,7 @@

<!-- Run the top-level HDF5 UI tests -->
<run-ui-junit
rootdir="${basedir}/${hdf5uitestclasses.dir}"
rootdir="${basedir}/${jar.dir}"
workdir="${basedir}/${hdf5uitestclasses.dir}"
propfile="${basedir}/${uitestclasses.dir}/.hdfview${app.version}"
includes="${hdf5uitestclasses.dir}/${test}.class"
Expand All @@ -891,7 +891,7 @@
<mkdir dir="${report.dir}" />

<run-ui-junit
rootdir="${basedir}/${testclasses.dir}"
rootdir="${basedir}/${jar.dir}"
workdir="${basedir}/${testclasses.dir}/modules"
includes="**/modules/*Test*"
excludes="**/modules/*$*"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ private static class NumericalDataDisplayConverter extends HDFDisplayConverter {
private final StringBuilder buffer;
private final long typeSize;
private final boolean isUINT64;
private final boolean isFLT16;

NumericalDataDisplayConverter(final Datatype dtype) throws Exception
{
Expand All @@ -727,6 +728,7 @@ private static class NumericalDataDisplayConverter extends HDFDisplayConverter {

typeSize = dtype.getDatatypeSize();
isUINT64 = dtype.isUnsigned() && (typeSize == 8);
isFLT16 = dtype.isFloat() && (typeSize == 2);
}

@Override
Expand Down
112 changes: 88 additions & 24 deletions src/org.hdfgroup.hdfview/hdf/view/TableView/DataProviderFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ private static final HDFDataProvider getDataProvider(final Datatype dtype, final
final boolean dataTransposed) throws Exception
{
HDFDataProvider dataProvider = null;
log.debug("getDataProvider(): Datatype is {}", dtype.getDescription());

try {
if (dtype.isCompound())
Expand Down Expand Up @@ -375,30 +376,24 @@ public void setDataValue(int columnIndex, int rowIndex, Object newValue)
}

/**
* When a CompoundDataProvider wants to pass a List of data down to a nested
* CompoundDataProvider, or when a top-level container DataProvider (such as an
* ArrayDataProvider) wants to hand data down to a base CompoundDataProvider, we
* need to pass down a List of data and the new value, plus a field and row
* index. This method is for facilitating this behavior.
* When a CompoundDataProvider wants to pass a List of data down to a nested CompoundDataProvider, or
* when a top-level container DataProvider (such as an ArrayDataProvider) wants to hand data down to a
* base CompoundDataProvider, we need to pass down a List of data and the new value, plus a field and
* row index. This method is for facilitating this behavior.
*
* In general, all "container" DataProviders that have a "container" base
* DataProvider should call down into their base DataProvider(s) using this
* method, in order to ensure that buried CompoundDataProviders get handled
* correctly. When their base DataProvider is not a "container" type, the method
* setDataValue(index, Object, Object) should be used instead.
* In general, all "container" DataProviders that have a "container" base DataProvider should call
* down into their base DataProvider(s) using this, method, in order to ensure that buried
* CompoundDataProviders get handled correctly. When their base DataProvider is not a "container"
* type, the method setDataValue(index, Object, Object) should be used instead.
*
* For atomic type DataProviders, we treat this method as directly calling into
* setDataValue(index, Object, Object) using the passed rowIndex. However, this
* method should, in general, not be called by atomic type DataProviders.
* For atomic type DataProviders, we treat this method as directly calling into setDataValue(index,
* Object, Object) using the passed rowIndex. However, this method should, in general, not be called
* by atomic type DataProviders.
*
* @param columnIndex
* the column
* @param rowIndex
* the row
* @param bufObject
* the data object
* @param newValue
* the new data object
* @param columnIndex the column
* @param rowIndex the row
* @param bufObject the data object
* @param newValue the new data object
*/
public void setDataValue(int columnIndex, int rowIndex, Object bufObject, Object newValue)
{
Expand Down Expand Up @@ -1623,7 +1618,7 @@ private static class NumericalDataProvider extends HDFDataProvider {
private static final Logger log = LoggerFactory.getLogger(NumericalDataProvider.class);

private final boolean isUINT64;

private final boolean isFLT16;
private final long typeSize;

NumericalDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed)
Expand All @@ -1633,6 +1628,7 @@ private static class NumericalDataProvider extends HDFDataProvider {

typeSize = dtype.getDatatypeSize();
isUINT64 = dtype.isUnsigned() && (typeSize == 8);
isFLT16 = dtype.isFloat() && (typeSize == 2);
}

@Override
Expand All @@ -1641,7 +1637,9 @@ public Object getDataValue(int columnIndex, int rowIndex)
super.getDataValue(columnIndex, rowIndex);

try {
if (isUINT64)
if (isFLT16)
theValue = Float.float16ToFloat((short)theValue);
else if (isUINT64)
theValue = Tools.convertUINT64toBigInt(Long.valueOf((long)theValue));
}
catch (Exception ex) {
Expand All @@ -1660,7 +1658,9 @@ public Object getDataValue(Object obj, int index)
super.getDataValue(obj, index);

try {
if (isUINT64)
if (isFLT16)
theValue = Float.float16ToFloat((short)theValue);
else if (isUINT64)
theValue = Tools.convertUINT64toBigInt(Long.valueOf((long)theValue));
}
catch (Exception ex) {
Expand All @@ -1672,6 +1672,70 @@ public Object getDataValue(Object obj, int index)

return theValue;
}

/**
* update the data value of a type.
*
* @param columnIndex the column
* @param rowIndex the row
* @param newValue the new data value object
*/
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue)
{
log.trace("setDataValue({}, {})=({}): start", rowIndex, columnIndex, newValue);
try {
if (isFLT16) {
// must convert string from float to short first
float fValue = Float.parseFloat((String)newValue);
short sValue = Float.floatToFloat16(fValue);
// setDataValue requires a String, so convert short to String
String strValue = Short.toString(sValue);
super.setDataValue(columnIndex, rowIndex, strValue);
}
else
super.setDataValue(columnIndex, rowIndex, newValue);
}
catch (Exception ex) {
log.debug("setDataValue({}, {})=({}): failure: ", rowIndex, columnIndex, newValue, ex);
theValue = DataFactoryUtils.errStr;
}
}

/**
* When a parent HDFDataProvider (such as an ArrayDataProvider) wants to set a data value by routing
* the operation through its base HDFDataProvider, the parent HDFDataProvider will generally know the
* direct index to have the base provider use. This method is to facilitate this kind of behavior.
*
* Note that this method takes two Object parameters, one which is the object that the method should
* set its data inside of and one which is the new value to set. This is to be able to nicely support
* nested compound DataProviders.
*
* @param index the index into the data array
* @param bufObject the data object
* @param newValue the new data object
*/
public void setDataValue(int index, Object bufObject, Object newValue)
{
log.trace("setDataValue({}: {})=({}): start", index, bufObject, newValue);
try {
if (isFLT16) {
// must convert string from float to short first
float fValue = Float.parseFloat((String)newValue);
short sValue = Float.floatToFloat16(fValue);
// setDataValue requires a String, so convert short to String
String strValue = Short.toString(sValue);
super.setDataValue(index, bufObject, strValue);
}
else
super.setDataValue(index, bufObject, newValue);
}
catch (Exception ex) {
log.debug("setDataValue({}, {})=({}): updateAtomicValue failure: ", index, bufObject,
newValue, ex);
}
log.trace("setDataValue({}, {})=({}): finish", index, bufObject, newValue);
}
}

private static class EnumDataProvider extends HDFDataProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -636,19 +636,27 @@ public boolean validate(int colIndex, int rowIndex, Object newValue)
break;

case 2:
if (datasetDatatype.isUnsigned()) {
/*
* First try to parse as a larger type in order to catch a NumberFormatException
*/
Integer intValue = Integer.parseInt((String)newValue);
if (intValue < 0)
throw new NumberFormatException("Invalid negative value for unsigned datatype");
if (datasetDatatype.isInteger()) {
if (datasetDatatype.isUnsigned()) {
/*
* First try to parse as a larger type in order to catch a NumberFormatException
*/
Integer intValue = Integer.parseInt((String)newValue);
if (intValue < 0)
throw new NumberFormatException(
"Invalid negative value for unsigned datatype");

if (intValue > (Short.MAX_VALUE * 2) + 1)
throw new NumberFormatException("Value out of range. Value:\"" + newValue + "\"");
if (intValue > (Short.MAX_VALUE * 2) + 1)
throw new NumberFormatException("Value out of range. Value:\"" + newValue +
"\"");
}
else {
Short.parseShort((String)newValue);
}
}
else {
Short.parseShort((String)newValue);
/* Floating-point type */
Float.parseFloat((String)newValue);
}
break;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@ public class NewCompoundAttributeDialog extends NewDataObjectDialog {
"unsigned short (16-bit)", // 4
"unsigned int (32-bit)", // 5
"long (64-bit)", // 6
"float", // 7
"double", // 8
"float (32-bit)", // 7
"double (64-bit)", // 8
"string", // 9
"enum", // 10
"unsigned long (64-bit)" // 11
"unsigned long (64-bit)", // 11
"float16 (16-bit)", // 12
"long double (128-bit)" // 13
};

private Combo nFieldBox, templateChoice;
Expand Down Expand Up @@ -465,6 +467,14 @@ else if (DATATYPE_NAMES[11].equals(typeName)) {
type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 8, Datatype.NATIVE,
Datatype.SIGN_NONE);
}
else if (DATATYPE_NAMES[12].equals(typeName)) {
type =
fileFormat.createDatatype(Datatype.CLASS_FLOAT, 2, Datatype.NATIVE, Datatype.NATIVE);
}
else if (DATATYPE_NAMES[13].equals(typeName)) {
type =
fileFormat.createDatatype(Datatype.CLASS_FLOAT, 16, Datatype.NATIVE, Datatype.NATIVE);
}
else {
throw new IllegalArgumentException("Invalid data type.");
}
Expand Down
Loading

0 comments on commit a4394b0

Please sign in to comment.