PETCs - 应该如何初始化 PetscRandom?

计算科学 宠物 C 随机数生成
2021-12-01 10:48:55

PETSc 的文档显示了一个使用示例:

  PetscRandomCreate(PETSC_COMM_SELF,&r);
  PetscRandomSetType(r,PETSCRAND48);
  PetscRandomGetValue(r,&value1);
  PetscRandomGetValueReal(r,&value2);
  PetscRandomDestroy(&r);

在示例 random 1 中,我们还可以找到 PetscRandomSeed 的使用。

但是,将 PetscRandom 变量附加到对象似乎还不够。

以下代码适用于任意数量的 proc:

#undef __FUNCT__
#define __FUNCT__ "TSInjectCreate"
PetscErrorCode  TSInjectCreate(MPI_Comm comm,TSInject *ininject){
  PetscErrorCode ierr;
  size_t         t;
  PetscInt       i;
  PetscReal       r;
  TSInject       inject;

  PetscFunctionBegin;
  PetscValidPointer(ininject,1);
  *ininject = NULL;
  ierr                       = PetscClassIdRegister("TSInject",&TSINJECT_CLASSID);CHKERRQ(ierr);
  ierr = PetscHeaderCreate(inject,TSINJECT_CLASSID,"TSInject","Injection of SDC","TS",comm,TSInjectDestroy, TSInjectView);CHKERRQ(ierr);
  ierr = PetscRandomCreate( comm,&inject->ran);CHKERRQ(ierr);
  ierr = PetscRandomSetType(inject->ran, PETSCRAND48);CHKERRQ(ierr);
  ierr = PetscRandomSeed(inject->ran);CHKERRQ(ierr);
  ierr = PetscRandomGetValue(inject->ran, &r);CHKERRQ(ierr);
  *ininject = inject;

  PetscFunctionReturn(0);
}

但是,一旦我PetscRandomGetValue(inject->ran, &r);在另一个函数中使用,它仅在使用一个 proc 启动 mpi 时才有效。

为什么?

编辑:

错误完全(而且奇怪地)来自比较:

PetscErrorCode  TSInjection(TSInject inject, Vec X)
{
  PetscReal       r,err;
  Vec             Y;
  PetscErrorCode ierr;

  PetscFunctionBegin;
  ierr = PetscRandomGetValue(inject->ran, &r);CHKERRQ(ierr);
ierr = VecView(X, 0);CHKERRQ(ierr);    // works
  if(r  > inject->proba){ PetscFunctionReturn(0);}
        ierr = VecView(X, 0);CHKERRQ(ierr);      // stucks the execution
 ...          
  PetscFunctionReturn(0);
}

r例如,如果我用 0.1 替换,一切正常。更令人惊讶的是,显示 r 并没有卡住执行。

1个回答

为了解决这个问题,一个变通方法也是使用 DIY 随机函数。在我的上下文中,我已经放弃了 PetscRandom 来写:

PetscErrorCode TSInjectRandInt(TSInject inject, PetscInt *r)  // RAND_MAX assumed to be 32767
{
    PetscFunctionBegin;
    inject->next = inject->next * 1103515245 + 12345;
    *r = PetscAbs((PetscInt)(inject->next/65536) % 32768);
    PetscFunctionReturn(0);
}


PetscErrorCode TSInjectRandReal(TSInject inject, PetscReal *r)  {
  PetscInt i;

  PetscFunctionBegin;
  TSInjectRandInt(inject, &i);
  *r = ((PetscReal)i)/32767.0;
  PetscFunctionReturn(0);
}

PetscErrorCode TSInjectRandSeed(TSInject inject, PetscInt seed)
{
    PetscFunctionBegin;
    inject->next = seed;
    PetscFunctionReturn(0);
}

但是,应该注意到 RAND_MAX 是固定的,并且生成器显然非常简单。它具有工作的唯一优势。