【问题标题】:Transferring Fortran multiD arrays to C将 Fortran 多维数组传输到 C
【发布时间】:2016-11-09 00:58:15
【问题描述】:

我在将 3D 数组从 Fortran 传输到 C 时遇到问题。我有表示数组大小的变量(idim、jdim、kdim),但我很难编写 C 代码来接收大小为这些价值观。我将附上我现在拥有的 Fortran 和 C 代码。

福特兰:

  ! Transfer u,v,w to CPU

  idim = imax_ - imin_
  jdim = jmax_ - jmin_
  kdim = kmax_ - kmin_
  CALL CUDA(idim,jdim,kdim,u,v,w)

和C:

extern "C" void cuda_(int *idim, int *jdim, int *kdim, float U[*kdim][*jdim][*idim], float V[*kdim][*jdim][*idim], float W[*kdim][*jdim][*idim])
{

我正在努力使用 GPU 编程来加速现有的代码,但对编程还是比较陌生,所以请考虑到这一点。

提前致谢!

【问题讨论】:

  • 编程新手? Fortran 和 C 以及指针、malloc 和 free 的新手?有很多问题要问。
  • 说真的,如果您是编程新手,请先学会走路,然后才能慢跑。学习如何在所选语言中传递参数/参数,然后学习如何在 C 和 Fortran 之间传递实体,然后才将 CUDA 添加到组合中。从长远来看,这将为您节省很多痛苦。

标签: c arrays fortran


【解决方案1】:

为什么FORTRAN程序中的函数名不一样?我会在两个程序中使用相同的名称,但也许这与 FORTRAN 相关。我将使用您为此答案编写的 C 函数名称,是的,我同意这对于初学者来说是一项艰巨的任务。这不是一个完整的解决方案,但应该引导您朝着正确的方向前进(希望如此)。首先... C 中的数组具有在编译时确定的固定维度。所以你的函数声明不会编译。如果您的意图是取消引用数组维度参数中的维度指针,这将不起作用,因为它不是可执行代码;这些是仅用于编译的参数声明。

其次,您似乎希望将具有不同维度的数组从一个调用传递到另一个调用,或者您事先不知道数组中有多少元素。假设这一点,您只需要传递数组的地址(假设您的尺寸总是正确的)。你的函数原型可以是:

void cuda_(int *idim, int *jdim, int *kdim, float *U, float* V, float* W);

您的函数可以实现如下(以便向您展示指针算法):

void cuda_(int *idim, int *jdim, int *kdim, float* U, float* V, float* W)
{
  int i, j, k;

  // Assuming you want to process each individual array 
  // items one after the other; this to show pointer arithmetic

  for (i=0; i<*idim; i++)  {

    for (j=0; j<*jdim; j++)  {

      for (k=0; k<*kdim; k++)  {

          // Do whatever with the i,j,kth element;   
          // We assign unique values so you can check 
          // that this example accesses the right array elements            

          *(U + i * sizeof(float) + j * sizeof(float) + k) = i + j + k;        
          *(V + i * sizeof(float) + j * sizeof(float) + k) = 2*i + 2*j + 2*k;
          *(W + i * sizeof(float) + j * sizeof(float) + k) = 3*i + 3*j + 3*k;

      }

    }

  }

  return;
}

当然,您需要彻底测试这个示例,以确保这是您真正想要做的,并且我确实正确地映射了 3D 数组(我将它映射到一维数组上,假设它是这样的在您的 FORTRAN 程序中实现;否则,您将不得不提出正确的指针算法,但原理与示例中的相同)。我对这段代码进行了非常肤浅的测试,并被警告指针操作很棘手且容易出错!祝你好运。

现在,这是次要的,但我觉得应该说明这一点。我不明白为什么要将数组维度作为指针传递;也许这是 FORTRAN 的要求(也就是说,您可能无法通过值/副本传递参数)。如果您可以通过复制(而不是通过引用)传递参数,那么我建议进行以下更改:

// Prototype:

void cuda_(int idim, int jdim, int kdim, float* U, float* V, float* W);

// Implementation:

void cuda_(int idim, int jdim, int kdim, float* U, float* V, float* W)
{
  int i, j, k;


  for (i=0; i<idim; i++)  {

    for (j=0; j<jdim; j++)  {

      for (k=0; k<kdim; k++)  {

          *(U + i * sizeof(float) + j * sizeof(float) + k) = i + j + k;        
          *(V + i * sizeof(float) + j * sizeof(float) + k) = 2*i + 2*j + 2*k;
          *(W + i * sizeof(float) + j * sizeof(float) + k) = 3*i + 3*j + 3*k;

      }

    }

  }

}

【讨论】:

  • 嘿 clarasoft-it,感谢您的帮助。我最终也发布了我的解决方案。据我所知,Fortran 值是通过引用传递的,因此指针是必要的。函数名称后也需要下划线,因为这是互联网告诉我要做的:) 再次感谢!
【解决方案2】:

我能想到的最简单的方法是将数组作为一维数组传递。然后在 c 函数中创建具有适当尺寸的新 3D 数组,然后使用传递的 1D 数组填充它们。我将修改后的数组设置为以与 FORTRAN 数组相同的方式引用,以希望使访问数组更容易。我将在下面附上我的 C 解决方案:

extern "C" void cuda_(double *ptr_u, double *ptr_v, double *ptr_w, int *nx, int *ny, int *nz)
{


     //Creating new arrays for U,V,W
     int i,j,k,imax,jmax,kmax,ct=0;
     imax = *nx;
     jmax = *ny;
     kmax = *nz;

     double V[imax][jmax][kmax], W[imax][jmax][kmax], U[imax][jmax][kmax];

     for (k = 0; k < kmax; k++)
     {
          for (j = 0; j < jmax; j++)
          {
               for (i = 0; i < imax; i++)
               {
                    U[i][j][k] = ptr_u[ct];
                    V[i][j][k] = ptr_v[ct];
                    W[i][j][k] = ptr_w[ct];
                    ct++;
               }
          }
     }

如果有人对此解决方案有任何意见,请随时发表评论。我敢肯定在某处有更好的方法来做到这一点!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多