在 Trilinos 中重塑 MultiVector

计算科学 并行计算 mpi 特里诺斯
2021-12-18 01:13:35

我正在使用 Trilinos 解决问题,并且我有一个Epetra_MultiVector具有 1 个长度向量的对象m*n*nFrames我需要把它变成一个长度为的Epetra_MultiVector对象第一个条目需要进入第一个向量,第二个进入第二个向量,依此类推。nFramesm*nm*n

我只需一个过程就可以正常工作。我正在做的是将所有数据提取到进程 0 上的标准 C++ 数组,将其重塑为 2D 标准 C++ 数组(实际上是一个指针数组),然后Epetra_MultiVector用我的 2D 数组创建一个新数组。

但是,由于有多个进程,因为一切都在进程 0 上,所以当我创建新进程时Epetra_MultiVector,另一个进程的所有数据都是无意义的(我猜是访问未定义的内存)。

所以我的问题最终是:如何Epetra_MultiVector通过多个流程正确地重塑 Trilinos?

2个回答

重塑数组是一些特定于 Matlab 的东西——大多数其他环境(包括 Trilinos、PETSc 等)允许您创建向量或矩阵,但不允许您将其重新解释为其他东西。您需要手动将元素复制到不同大小的矩阵中。

我写了一个函数来完成它。它没有到位,也没有写得特别好,但为了后代,我会添加我的解决方案。我意识到我真的不需要重塑标准 C++ 数组,但我会把它留在那里,直到它成为我的问题。

int ReshapeMultiVector(Epetra_MultiVector *&reshapedMultiVec, const int length, const int numVecs, const Epetra_MultiVector &originalMultiVec, Epetra_MpiComm &comm){

    /* Function to reshape a multivector. Does it by copying the values, so additional memory will be required.
     * Note that this function does NOT delete the original vector.
     * INPUTS
     *  reshapedMultiVec - This is a reference to a null pointer that will point to the
     *             new (reshaped) multivector.
     *  length       - Global length of the new multivector
     *  numVecs      - The number of vectors in the new multivector.
     *  originalMultiVec - The original multivector that is being reshaped.
     *  comm         - MPI communicator
     * OUTPUT
     *  int      - Error flag
     */

    int err;

    int numVecsOrig = originalMultiVec.NumVectors();
    int lengthOrig = originalMultiVec.GlobalLength();

    //extract phase_gradx and phase_grady as standard arrays so that we can reshape them.
    double** originalMultiVec_std = new double*[numVecsOrig];
    for(int i=0;i<numVecsOrig;++i){
        originalMultiVec_std[i] = new double[lengthOrig];
    }
    err = MultiVectorToArray(originalMultiVec_std, originalMultiVec, false);
    if(err) return err;

    // Copy the values to all the processors after extracting them.
    for(int i=0;i<numVecsOrig;++i){
        comm.Broadcast(originalMultiVec_std[i], lengthOrig, 0);
    }


    double** reshaped_std = new double*[numVecs];
    for(int i=0;i<numVecs;++i){
        reshaped_std[i] = new double[length];
    }
    err = Reshape2DArray(originalMultiVec_std, lengthOrig, numVecsOrig, reshaped_std, length, numVecs);
    if(err) return err;


    Epetra_Map reshapedMap(length,0,comm);

    //Initialize the vector
    int numMyElements = reshapedMap.NumMyElements();
    int* myGlobalElements = reshapedMap.MyGlobalElements(); 


    reshapedMultiVec = new Epetra_MultiVector(reshapedMap,numVecs);
    double ** Ap = reshapedMultiVec->Pointers();

    for (int j=0; j<numVecs; ++j)
    {
        double * v = Ap[j];

        // Fill it
        for (int i=0; i<numMyElements; ++i)
        {
            v[i] = reshaped_std[j][myGlobalElements[i]];
        }
    }


    // free memory
    for(int i=0;i<numVecsOrig;++i){
        delete[] originalMultiVec_std[i];
    }
    delete[] originalMultiVec_std;
    for(int i=0;i<numVecs;++i){
        delete[] reshaped_std[i];
    }
    delete[] reshaped_std;


    return(EXIT_SUCCESS);
}