首页 > 解决方案 > 尝试用 Java 编写 FITS BinaryTable(或 AsciiTable)时出现奇怪的维度

问题描述

第一个功能是直接从 nom-tam-fits 网站窃取的:https ://nom-tam-fits.github.io/nom-tam-fits/intro.html

private static void dataTableToBinaryFitsDummy() throws Exception {
    BufferedFile bf = new BufferedFile("table.fits", "rw");

     BasicHDU.getDummyHDU().write(bf);  // Write an initial null HDU

     double[] ra = {1.};
     double[] dec = {2.};
     String[] name = {"          "}; // maximum length will be 10 characters

     Object[] row = {ra, dec, name};
     long rowSize = ArrayFuncs.computeLSize(row);

     BinaryTable table = new BinaryTable();

     table.addRow(row);

     Header header = new Header();
     table.fillHeader(header);

     BinaryTableHDU bhdu = new BinaryTableHDU(header, table);

     bhdu.setColumnName(0, "ra", null);
     bhdu.setColumnName(1, "dec", null);
     bhdu.setColumnName(2, "name", null);

     bhdu.getHeader().setNaxis(2, 1000);  // set the header to the actual number of rows we write
     bhdu.getHeader().write(bf);

     ByteBuffer buffer = ByteBuffer.allocate((int) rowSize);

     for (int event = 0; event < 1000; event ++){
         buffer.clear();

         // update ra, dec and name here

         buffer.putDouble(event);
         buffer.putDouble(dec[0]);
         buffer.put(("event "+event).getBytes());

         buffer.flip();
         bf.write(buffer.array());
     }

     FitsUtil.pad(bf, rowSize * 1000);
     bf.close();
}

作为起点,我希望能够传入原始双精度数组的任意集合。这是我的尝试,IMO 不应该与原来的特别不同。

private static void dataTableToBinaryFitsDummyWithArgsDoublesOnlyWrapper() {
    int nRows = 100;
    
    double [] rowA = new double[nRows];
    double [] rowB = new double[nRows];
    double [] rowC = new double[nRows];
    double [] rowD = new double[nRows];
    
    Random random = new Random();
    for (int i=0;i<nRows;i++) {
        rowA[i] = i;
        rowB[i] = 2*i;
        rowC[i] = random.nextGaussian();
        rowD[i] = rowC[i] * -1;
    }
    
    ImmutableList<double[]> columns = ImmutableList.of(rowA, rowB, rowC, rowD);
    ImmutableList<String> names = ImmutableList.of("ints", "double ints", "randos", "neg randos");
    
    try {
        dataTableToBinaryFitsDummyWithArgsDoublesOnly(columns, names, 4, nRows);
    } catch (Exception e) {
        e.printStackTrace();
    }
    
}
private static void dataTableToBinaryFitsDummyWithArgsDoublesOnly(ImmutableList<double[]> columns,
        ImmutableList<String> names, int nCols, int nRows) throws Exception {
    BufferedFile bf = new BufferedFile("tableWithArgs.fits", "rw");

     BasicHDU.getDummyHDU().write(bf);  // Write an initial null HDU
     Object[] row = new Object[nCols];
     for (int i=0;i<nCols;i++) {
         row[i] = columns.get(i);
     }
     long rowSize = ArrayFuncs.computeLSize(row);
     
     BinaryTable table = new BinaryTable();
     table.addRow(row);
     
     Header header = new Header();
     table.fillHeader(header);
     
     BinaryTableHDU bhdu = new BinaryTableHDU(header, table);
     
     for (int i=0;i<nCols;i++) {
         bhdu.setColumnName(i, names.get(i), null);
     }
     
     bhdu.getHeader().setNaxis(2, nRows);
     bhdu.getHeader().write(bf);
     
     ByteBuffer buffer = ByteBuffer.allocate((int) rowSize);

     for (int i = 0; i < nRows; i ++){
         buffer.clear();

         // update ra, dec and name here

         for (double[] column : columns) {
             buffer.putDouble(column[i]);
         }
         
         buffer.flip();
         bf.write(buffer.array());
     }

     FitsUtil.pad(bf, rowSize * nRows);
     bf.close();
}

但是,我得到的看起来非常不同。我希望行看起来像

ints, double ints, randos, neg randos
0.0, 0.0, 0.66938, -0.66938
1.0, 2.0, 0.53482, -0.53482
2.0, 4.0, 0.66825, -0.66825
...

但相反我得到

ints, double ints, randos, neg randos
(0.0, 0.0, 0.66938, -0.66938, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...)
(1.0, 2.0, 0.53482, -0.53482, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...)

看起来我没有得到 4 列和 100 行的数字,而是得到 4 列和 100 行的 100 个数字列表。我尽可能地遵循规范示例,为什么会发生这种情况?

虽然我在这里,但我也希望这是一个 AsciiTable 和 AsciiTableHDU,但我看到的唯一示例是 BinaryTables、BinaryTableHDUs 和 ByteBuffers。

标签: javafits

解决方案


我不是很熟悉nom.tam.fits,但根据文档BinaryTable.addRow采用基元数组数组(这是因为 FITS 二进制表的单个单元格中的数据本身可以是多维数组)。

这就是您引用的原始示例从 1 元素数组的数组中创建一行的原因:

     double[] ra = {1.};
     double[] dec = {2.};
     String[] name = {"          "}; // maximum length will be 10 characters

     Object[] row = {ra, dec, name};

在您的代码中,您似乎混淆了行和列:

    double [] rowA = new double[nRows];
    double [] rowB = new double[nRows];
    double [] rowC = new double[nRows];
    double [] rowD = new double[nRows];

在这里,这些数组中的每一个都代表一整数据(这就是它们的长度为 的原因nRows)。

那么这里

     Object[] row = new Object[nCols];
     for (int i=0;i<nCols;i++) {
         row[i] = columns.get(i);
     }

您创建一个“行”,其中包含该行中整个列的值。您缺少一些外部 for 循环 over nRows

还有一个BinaryTable.addColumn可能更有效地一次添加整个列(特别是如果您预先指定列的数量和类型)。

原始示例的主要用例(一次写入一行)可能是如果您有一些长时间运行的观察或事件记录过程,其中一行以流方式一次附加到表中。


推荐阅读