科学计算编程中3D数组的调试技巧

涉及科学计算或者仿真的程序的编写,总是绕不开大规模的数组,其中比较常见又折磨人的大约就是三维数组了,动辄512x512x1024的数组,各种微分算法下各种下标来回倒腾,某些情况下(例如CUDA)还被迫用一维数组来代替,要自己负责坐标转换。万一出错(其实不出错才是万一)几乎没法调试,只知道结果很奇怪,但是即使断点进去,也只是看到一个个独立的数字,很多时候相邻的元素都不在一起。这个时候,写C/C++的人就会无比怀念MATLAB——可以任意时候对一个数组的一个剖面surf()一下看看趋势。

不过,其实是有办法很方便的将C++的数组搞进MATLAB画图的。

材料:

  • MATLAB 2015 稍微老一点的版本应该也行
  • Excel 2016 老版本不一定行
  • 任意文本编辑器
  • 你的源码

第一步要把3D数组数据转移到磁盘文件,这一步最慢,但是磨刀不误砍柴工。放一个我调试CUDA的例子:

void   DebugPrintThrustDevice3DArrayAlong ( thrust :: device_vector < real > & devVector ,
     uint3   meshdim ,  DebugOutputInfo  & DebugInfo ,  std :: string   ArrayName )
{
     if  (! DebugInfo . DebugOutput )  return ;
     DebugInfo . FileOutputStream  <<  std :: setprecision (4); // << std::setiosflags(std::ios::scientific);
     DebugInfo . FileOutputStream  <<  std :: endl  <<  "#"  <<  ArrayName  <<  ":"  <<  std :: endl ;
     thrust :: host_vector < real >  Value ( devVector );
 
     for  ( size_t   x  = 0;  x  <  meshdim . x ;  x  +=  DebugInfo . PrintGap )
    {
         for  ( size_t   y  = 0;  y  <  meshdim . y ;  y  +=  DebugInfo . PrintGap )
        {
             for  ( size_t   z  = 0;  z  <  meshdim . z ;  z  +=  DebugInfo . PrintGap )
            {
                 if  ( DebugInfo . OutputToFile )
                {
                     DebugInfo . FileOutputStream  <<  std :: setfill ( ' ' ) <<  std :: setw (10) <<  Value [ Axyz2idx ( make_uint3 ( x ,  y ,  z ),  meshdim )];
                }
                 else
                {
                     std :: cout  <<  std :: setw (6) <<  Value [ Axyz2idx ( make_uint3 ( x ,  y ,  z ),  meshdim )] <<  " " ;
                }
            }
             if  ( DebugInfo . OutputToFile )
            {
                 DebugInfo . FileOutputStream  <<  std :: endl ;
            }
             else
            {
                 std :: cout  <<  std :: endl ;
            }
        }
         if  ( DebugInfo . OutputToFile )
        {
             DebugInfo . FileOutputStream  <<  std :: endl  <<  std :: endl ;
        }
         else
        {
             std :: cout  <<  std :: endl  <<  std :: endl ;
        }
    }
     std :: cout  <<  "# Array "  <<  ArrayName  <<  "debug output finished. #"  <<  std :: endl ;
}

这是一个 CUDA Thrust 3D 数组的输出函数,基本操作跟 vector 一样。DebugInfo . FileOutputStream 里面已经封装好了一个打开的文件。 如果有些奇怪的数组,自己用奇怪的方式转换。上面的函数输出格式是一个切片一个切片地输出。

这一步主要是利用Excel对文本的处理能力,用文本编辑器打开,复制你想要查看的数据,到Excel中,粘贴——按Ctrl键,这时候会弹出“文本导入向导”,就跟导入txt文件一样,只不过数据源换成了剪贴板。选择固定宽度,或者上面输出函数里你用了逗号什么的也可以用分隔符。我选择固定宽度主要是文本好看。 在Excel 2016之前没注意这个“文本导入向导”是否出现在“选择性粘贴”之中。起码2003肯定是没有的……

接下来就简单了,复制,到MATLAB里面随意新建一个变量,双击,会出现跟Excel类似的表格编辑器,贴进去,surf()一下,啥都看清楚了。 表格式编辑器好像是在MATLAB 2012左右的时候引入的,再老的版本应该不行。

写完记得发给我……

  • 最后更改: 2019/05/28 13:59