Dear all,
I have created a first implementation. For now it must be called after setting the fields, eventually I would like to move it to the setup phase. The implementation seems clean, but it is giving me some memory errors (free() corrupted unsorted chunks).
You may find the code below. After some work with gdb, I found out that the errors appears when calling the ISDestroy(&is_coords) line, which to me is not very clear, as I am indeed within the while scope creating and then destroying the is_coords object. I would greatly appreciate it if you could give me a hint on what the problem is.
After debugging this, and working on your suggestion, I will open a PR.
Best regards,
NB
----- CODE ------
static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[])
{
PetscErrorCode ierr;
PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
PC_FieldSplitLink ilink_current = jac->head;
PC pc_current;
PetscInt nmin, nmax, ii, ndofs;
PetscInt *owned_dofs; // Indexes owned by this processor
PetscReal *coords_block; // Coordinates to be given to the current PC
IS is_owned;
PetscFunctionBegin;
// Extract matrix ownership range to then compute subindexes for coordinates. This results in an IS object (is_owned).
// TODO: This would be simpler with a general MatGetOwnershipIS (currently supported only by Elemental and BLAS matrices).
ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr);
ndofs = nmax - nmin;
ierr = PetscMalloc1(ndofs, &owned_dofs); CHKERRQ(ierr);
for(PetscInt i=nmin;i<ndofs;++i)
owned_dofs[i] = nmin + i;
ierr = ISCreateGeneral(MPI_COMM_WORLD, ndofs, owned_dofs, PETSC_OWN_POINTER, &is_owned); CHKERRQ(ierr);
// For each IS, embed it to get local coords indces and then set coordinates in the subPC.
ii=0;
while(ilink_current)
{
IS is_coords;
PetscInt ndofs_block;
const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block
ierr = ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords); CHKERRQ(ierr); // Setting drop to TRUE, although it should make no difference.
ierr = PetscMalloc1(ndofs_block, &coords_block); CHKERRQ(ierr);
ierr = ISGetLocalSize(is_coords, &ndofs_block); CHKERRQ(ierr);
ierr = ISGetIndices(is_coords, &block_dofs_enumeration); CHKERRQ(ierr);
// Having the indices computed and the memory allocated, we can copy the relevant coords and set them to the subPC.
for(PetscInt dof=0;dof<ndofs_block;++dof)
for(PetscInt d=0;d<dim;++d)
{
coords_block[dim*dof + d] = coords[dim * block_dofs_enumeration[dof] + d];
// printf("Dof: %d, Global: %f\n", block_dofs_enumeration[dof], coords[dim * block_dofs_enumeration[dof] + d]);
}
ierr = ISRestoreIndices(is_coords, &block_dofs_enumeration); CHKERRQ(ierr);
ierr = ISDestroy(&is_coords); CHKERRQ(ierr);
ierr = KSPGetPC(ilink_current->ksp, &pc_current); CHKERRQ(ierr);
ierr = PCSetCoordinates(pc_current, dim, ndofs_block, coords_block); CHKERRQ(ierr);
ierr = PetscFree(coords_block); CHKERRQ(ierr);
if(!pc_current)
SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Setting coordinates to PCFIELDSPLIT but a subPC is null.");
ilink_current = ilink_current->next;
++ii;
}
ierr = PetscFree(owned_dofs); CHKERRQ(ierr);
PetscFunctionReturn(0);
}