将Fortran multiD阵列传输到C

时间:2016-07-06 20:21:33

标签: c arrays fortran

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

FORTRAN:

  ! 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编程来加速已有的代码,但我对编程仍然相对较新,所以请考虑到这一点。

提前致谢!

2 个答案:

答案 0 :(得分:0)

Why is the function name in the FORTRAN program not the same? I would use the same name in both programs but perhaps this is FORTRAN-related. I will use the C function name you wrote for this answer and yes, I agree that this is quite a task for a beginner. This will not be a complete solution but should steer you in the right direction (hopefully). First... arrays in C have fixed dimensions determined at compile time. So your function declaration will not compile. If your intention is to dereference the dimension pointers in the array dimention parameters, this will not work because it's not executable code; those are parameter declarations used only for compilation.

Second, it seems like you want to pass arrays that can have different dimensions from one call to another or that you don't know in advance how many elements will be in your arrays. Assuming this, you need only pass the address of your arrays (assuming your dimensions are always the right ones). Your function prototype could then be:

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

Your function could be implemented as follow (so to show you the pointer arithmetic):

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;
}

Of course, you need to test this example thoroughly to make sure that this is what you really intend on doing and that I did map the 3D array properly (I mapped it over a one-dimentional array assuming that this is how it is implemented in your FORTRAN program; otherwise, you will have to come up with the proper pointer arithmitic but the principle will be the same as in the examples). I did very superficial testing of this code and be warned that pointer manipulation is tricky and error prone! Good luck.

Now, and this is of secondary importance but I feel the point should be made. I don't see why you want to pass the array dimensions as pointers; perhaps it's a requirement for FORTRAN (that is maybe you cannot pass parameters by value/copy). If you can pass parameters by copy (as opposed to by reference), then I suggest the following change:

// 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;

      }

    }

  }

}

答案 1 :(得分:0)

我能想到的最简单的方法是将数组作为一维数组传递。然后在c函数中创建具有适当尺寸的新3D阵列,然后使用传递的1 D阵列填充它们。我设置修改后的数组以与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++;
               }
          }
     }

如果有人对此解决方案有任何意见,请随时发表评论。我确信有更好的方法可以在那里的某个地方做到这一点!