我正在编写一个使用Microsoft Scientific Data-Set读取NetCDF文件的C#程序.
using System;
using System.IO;
using sds = Microsoft.Research.Science.Data;
using Microsoft.Research.Science.Data.Imperative;
namespace NetCDFConsoleApp
{
class Program
{
static void Main(string[] args)
{
// Gets dataset from file.
var dataset = sds.DataSet.Open("E:\\Temp\\test.nc?openMode=readOnly");
// Get the starting DateTime from the meta data.
string dt = (string)dataset.Metadata["START_DATE"];
//load dataset into array
Single[,,] dataValues = dataset.GetData<float[,,]>("ACPR");
//Get DateTime from Metadata fields.
DateTime dt2 = DateTime.ParseExact(dt, "yyyy-MM-dd_HH:mm:ss", null);
// Latitude grid ranges from = 0 to 215; East Cape is ~ 125-144
for (int iLatitude = 137; iLatitude < 138; iLatitude++)
{
//Longitude ranges from 0 to 165; East Cape is ~ 125-150
for (int iLongitude = 133; iLongitude < 134; iLongitude++)
{
//There is normally 85 hours worth of data in a file. But not always...
for (int iTime = 0; iTime < 65; iTime++)
{
// Get each data point
float? thisValue = dataValues[iTime,iLatitude,iLongitude];
//Burp it out to the Console. Increment the datetime while im at it.
Console.WriteLine(dt.ToString() + ',' + dt2.ToString() + ',' + iTime.ToString() + ',' + dt2.AddHours(iTime) );
}
}
}
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这些文件包含地图网格(X,Y)上的预测降雨量数据.每个网格参考应该有85小时的数据.
E:\temp>sds list test.nc
[2] ACPR of type Single (Time:85) (south_north:213) (west_east:165)
[1] Times of type SByte (Time:85) (DateStrLen:19)
Run Code Online (Sandbox Code Playgroud)
但偶尔他们可能会少(比如60-70小时).当发生这种情况时,我的C#程序在导入数据时失败.
var dataset = sds.DataSet.Open("test.nc?openMode=readOnly");
Single[,,] dataValues = dataset.GetData<Single[,,]>("ACPR");
Run Code Online (Sandbox Code Playgroud)
我可以使用命令行重现错误.
在这里,我可以成功地为网格XY提取小时数60-65:125,130.我在此文件中的最后一个值是Time = 69.
E:\temp>sds data test.nc ACPR[60:65,125:125,130:130]
[2] ACPR of type Single (Time:85) (south_north:213) (west_east:165)
Name = ACPR
description = ACCUMULATED TOTAL GRID SCALE PRECIPITATION
MemoryOrder = XY
coordinates = XLONG XLAT XTIME
stagger =
FieldType = 104
units = mm
[60,125,130] 13.4926
[61,125,130] 15.24556
[62,125,130] 16.3638
[63,125,130] 17.39618
[64,125,130] 20.00507
[65,125,130] 23.57192
Run Code Online (Sandbox Code Playgroud)
如果我尝试阅读过去的69小时,我会收到以下错误.
E:\temp>sds data test.nc ACPR[60:70,125:125,130:130]
[2] ACPR of type Single (Time:85) (south_north:213) (west_east:165)
Name = ACPR
description = ACCUMULATED TOTAL GRID SCALE PRECIPITATION
MemoryOrder = XY
coordinates = XLONG XLAT XTIME
stagger =
FieldType = 104
units = mm
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at nc_get_vara_float(Int32 , Int32 , UInt64* , UInt64* , Single* )
at NetCDFInterop.NetCDF.nc_get_vara_float(Int32 ncid, Int32 varid, IntPtr[] start, IntPtr[] count, Single[] data)
at Microsoft.Research.Science.Data.NetCDF4.NetCdfVariable`1.ReadData(Int32[] origin, Int32[] shape)
at sdsutil.Program.PrintData(Variable v, String range, String format)
at sdsutil.Program.DoData(String uri, String[] args)
at sdsutil.Program.Main(String[] args)
E:\temp>
Run Code Online (Sandbox Code Playgroud)
如果文件包含完整的85小时,我可以请求时间0-100,它仍然给我85个值而没有错误.
我确信该问题是NULL /缺失数据.在导入变量不为空的数据时,是否有某些方法可以指定?或者使用一些try/catch?
Single[,,] dataValues = dataset.GetData<Single[,,]>("ACPR")>> where it's not blank thanks. ;
Run Code Online (Sandbox Code Playgroud)
编辑:我开始怀疑文件没有正确形成.使用SDS查看器良好文件的元数据与坏看起来像这样;
然而,命令行显示元数据对于两者都是相同的.
E:\temp>sds good.nc
[2] ACPR of type Single (Time:85) (south_north:213) (west_east:165)
[1] Times of type SByte (Time:85) (DateStrLen:19)
E:\temp>sds bad.nc
[2] ACPR of type Single (Time:85) (south_north:213) (west_east:165)
[1] Times of type SByte (Time:85) (DateStrLen:19)
E:\temp>
Run Code Online (Sandbox Code Playgroud)
小智 3
彼得,
由于错误位于 ReadData(Int32[] origin, Int32[] shape) (您指出了相同);我看到两种可能的解决方案:
在深入研究解决方案之前,您需要决定是否可以将缺失数据视为 0.0,或者是否需要将其视为缺失。如果 Missing 不同于 0.0,则如果 null 不可接受,则可能的 Missing 可以编码为 -1.0。对于缺失的数据,建议使用 -1.0 值,这是假设负降雨值是不可能的。
如果结果dataValues包含空值,您可能需要做的就是用 float 替换 float?在行中:
float thisValue = dataValues[iTime,iLatitude,iLongitude];
Run Code Online (Sandbox Code Playgroud)
成为:
float? thisValue = dataValues[iTime,iLatitude,iLongitude];
Run Code Online (Sandbox Code Playgroud)
如果您有空回家,float?那么这是一个愉快的解决方案。(您仍然需要决定如何处理空值。)
否则可能的解决方案1)
调用后,请确保Single[,,] dataValues = dataset.GetData<Single[,,]>("ACPR");数组的最后一个索引大小dataValues为 85。GetData(..) 可能不会填充所有 85 个字段,特别是当第一行数据包含的字段少于 85 个时。然后,如果需要,手动将空值替换为 0 或 -1.0。
然后,当您检索数据时,您可以适当地处理空值、0 或 -1.0:
float? thisValue = dataValues[iTime,iLatitude,iLongitude];
// determine what to do with a null/0.0/-1.0 as a thisValue[..] value,
// .. potentially continue with the next iteration
Run Code Online (Sandbox Code Playgroud)
可能的解决方案2)
如果您拥有 GetData(..) 方法,那么Single[,,] dataValues = dataset.GetData<Single[,,]>("ACPR");您可以确保它GetData(..)能够提供所有 85 个值,并且缺失值以 null/0/-1.0 的形式给出。然后,当您检索数据时,您可以适当地处理空值、0 或 -1.0。
干杯,
阿维
| 归档时间: |
|
| 查看次数: |
418 次 |
| 最近记录: |