gsl openmp集成失败

时间:2014-06-30 16:59:47

标签: c parallel-processing openmp gsl

这是我在这里的第一篇文章,所以对我来说很容易! 我有一个非常奇怪的问题。我编写了一个将粒子数据转换为网格数据的c代码(数据来自宇宙学模拟)。为了进行这种转换,我使用的是gsl Monte Carlo vegas积分器。当我连续运行它时,它运行得很好并给我正确的答案(尽管很慢)。为了加快速度,我尝试了openmp。问题是,当我并行运行时,积分超时(我在积分循环中设置了一个MAX_ITER变量,以避免由于缺乏收敛而产生无限循环)。在并行代码块之前设置并初始化随机数生成器。我检查并仔细检查,并且所有关于它并行失败的粒子的数据(x,y和z位置以及传递给积分器的积分边界)在串行和并行中是相同的。我也尝试将MAX_ITER变量从100增加到1000,但这没有做任何事情;它只需要更长的时间才能失败。

我的问题是,如果有人知道为什么代码会以串行方式运行,但在使用完全相同的粒子时会并行超时?

另外,如果你需要它,有问题的粒子的数字是:x = 0.630278,y = 24.952896,z = 3.256376,h = 3(这是粒子的平滑长度,用于“涂抹”超出粒子的质量,因为模拟的目标是使用粒子对流体进行采样。这是sph方法),x积分边界(下,上)= {0,630278},y bounds = {21.952896,27.952896}和z bounds = {0.256376,6.256375}

转换背后的想法是粒子的质量包含在半径为h的“平滑球体”内,并以粒子本身为中心。这个质量不是均匀分布的,而是根据sph内核完成的(这是我正在集成的函数)。因此,取决于球体如何放置在其“家庭细胞”内,只有球体的一部分实际上可能在该细胞内。然后,目标是获得适当的集成界限并将它们传递给集成商。积分器(下面的代码)有一个检查,如果蒙特卡洛积分器给它的点位于球体之外,它返回0(这是因为获得每个可能情况的精确集成限制是一个巨大的痛苦)。

我的循环代码在这里:

// Loop over every particle
#pragma omp parallel shared(M_P, m_header, NumPartTot, num_grid_elements, cxbounds,
cybounds, czbounds, master_cell) private(index, x, y, z, i, j, k, h, tid, cell,
corners) 
{
tid = omp_get_thread_num();

  // Set up cell struct. Allocate memory!
  cell = set_up_cell();

  #pragma omp for
  for(index = 1; index <= NumPartTot; index++)
  {    
     printf("\n\n\n************************************\n");
     printf("Running particle: %d on thread: %d\n", index, tid);
     printf("x = %f  y = %f   z = %f\n", M_P[index].Pos[0], M_P[index].Pos[1], M_P[index].Pos[2]);
     printf("**************************************\n\n\n");
     fflush(stdout);
     // Set up convenience variables
     x = M_P[index].Pos[0];
     y = M_P[index].Pos[1];
     z = M_P[index].Pos[2];

     // Figure out which cell the particle is in
     i = (int)((x / m_header.BoxSize) * num_grid_elements);
     j = (int)((y / m_header.BoxSize) * num_grid_elements);
     k = (int)((z / m_header.BoxSize) * num_grid_elements);

     corners = get_corners(i, j, k);

     // Check to see what type of particle we're dealing with
     if(M_P[index].Type == 0)
     {    
        h = M_P[index].hsml;
        convert_gas(i, j, k, x, y, z, h, index, cell, corners);
     }    

     else 
     {    
        update_cell_non_gas_properties(index, i, j, k, cell);
     }    
  }    

  // Copy each thread's version of cell to cell_master
  #ifdef _OPENMP
     copy_to_master_cell(cell);
     free_cell(cell);
  #endif
} /*-- End of parallel region --*/

问题出现在convert_gas函数中。有问题的部分在这里(在家庭单元块中):

 // Case 6: Left face
if(((x + h) < cxbounds[i][j][k].hi) && ((x - h) < cxbounds[i][j][k].lo) &&
((y + h) < cybounds[i][j][k].hi) && ((y - h) >= cybounds[i][j][k].lo) &&
((z + h) < czbounds[i][j][k].hi) && ((z - h) >= czbounds[i][j][k].lo))
{
  printf("Using case 6\n");
  fflush(stdout);

  // Home cell
  ixbounds.lo = cxbounds[i][j][k].lo;
  ixbounds.hi = x + h;
  iybounds.lo = y - h;
  iybounds.hi = y + h;
  izbounds.lo = z - h;
  izbounds.hi = z + h;

  kernel = integrate(ixbounds, iybounds, izbounds, h, index, i, j, k);

  update_cell_gas_properties(kernel, i, j, k, index, cell);

  // Left cell
  ixbounds.lo = x - h;
  ixbounds.hi = cxbounds[i][j][k].lo;
  iybounds.lo = y - h; // Not actual bounds. See note above.
  iybounds.hi = y + h;
  izbounds.lo = z - h;
  izbounds.hi = z + h;

  kernel = integrate(ixbounds, iybounds, izbounds, h, index, i - 1, j, k);

  update_cell_gas_properties(kernel, i - 1, j, k, index, cell);

  return;

}

我目前使用的数据是测试数据,因此我确切知道粒子应该在哪里以及它们应该具有哪些集成边界。使用gdb时,我发现所有这些数字都是正确的。函数集成中的集成循环在这里(TOLERANCE为0.2,WARM_CALLS为10000,N_CALLS为100000):

 gsl_monte_vegas_init(monte_state);
  // Warm up
  gsl_monte_vegas_integrate(&monte_function, lower_bounds, upper_bounds, 3,
                            WARM_CALLS, random_generator, monte_state, &result, &error);

  // Actual integration
  do
  {
     gsl_monte_vegas_integrate(&monte_function, lower_bounds, upper_bounds, 3,
                               N_CALLS, random_generator, monte_state, &result, &error);
     iter++;

  } while(fabs(gsl_monte_vegas_chisq(monte_state) - 1.0) > TOLERANCE && iter < MAX_ITER);



  if(iter >= MAX_ITER)
  {
     fprintf(stdout, "ERROR!!! Max iterations %d exceeded!!!\n"
             "See M_P[%d].id : %d   (%f %f %f)\n"
             "lower bnds : (%f %f %f)   upper bnds : (%f %f %f)\n"
              "trying to integrate in cell %d %d %d\n\n", MAX_ITER, pind, M_P[pind].id,
              M_P[pind].Pos[0], M_P[pind].Pos[1], M_P[pind].Pos[2],
              ixbounds.lo, iybounds.lo, izbounds.lo, ixbounds.hi, iybounds.hi, izbounds.hi, i, j, k);
     fflush(stdout);
     exit(1);
  }

同样,这个确切的代码(但没有openmp,我将该编译时选项作为makefile中的一个选项传递)与完全相同的数字串行运行,但不是并行运行。我确定这是一件很蠢的事情,我已经完成了,目前根本看不到(至少,我希望!)无论如何,感谢您的帮助!

0 个答案:

没有答案