#include /*I "petscpc.h" I*/ typedef struct { PetscReal lambda; /* damping parameter */ PetscBool symmetric; /* apply the projections symmetrically */ } PC_Kaczmarz; static PetscErrorCode PCDestroy_Kaczmarz(PC pc) { PetscFunctionBegin; PetscCall(PetscFree(pc->data)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCApply_Kaczmarz(PC pc, Vec x, Vec y) { PC_Kaczmarz *jac = (PC_Kaczmarz *)pc->data; PetscInt xs, xe, ys, ye, ncols, i, j; const PetscInt *cols; const PetscScalar *vals, *xarray; PetscScalar r; PetscReal anrm; PetscScalar *yarray; PetscReal lambda = jac->lambda; PetscFunctionBegin; PetscCall(MatGetOwnershipRange(pc->pmat, &xs, &xe)); PetscCall(MatGetOwnershipRangeColumn(pc->pmat, &ys, &ye)); PetscCall(VecSet(y, 0.)); PetscCall(VecGetArrayRead(x, &xarray)); PetscCall(VecGetArray(y, &yarray)); for (i = xs; i < xe; i++) { /* get the maximum row width and row norms */ PetscCall(MatGetRow(pc->pmat, i, &ncols, &cols, &vals)); r = xarray[i - xs]; anrm = 0.; for (j = 0; j < ncols; j++) { if (cols[j] >= ys && cols[j] < ye) r -= yarray[cols[j] - ys] * vals[j]; anrm += PetscRealPart(PetscSqr(vals[j])); } if (anrm > 0.) { for (j = 0; j < ncols; j++) { if (cols[j] >= ys && cols[j] < ye) yarray[cols[j] - ys] += vals[j] * lambda * r / anrm; } } PetscCall(MatRestoreRow(pc->pmat, i, &ncols, &cols, &vals)); } if (jac->symmetric) { for (i = xe - 1; i >= xs; i--) { PetscCall(MatGetRow(pc->pmat, i, &ncols, &cols, &vals)); r = xarray[i - xs]; anrm = 0.; for (j = 0; j < ncols; j++) { if (cols[j] >= ys && cols[j] < ye) r -= yarray[cols[j] - ys] * vals[j]; anrm += PetscRealPart(PetscSqr(vals[j])); } if (anrm > 0.) { for (j = 0; j < ncols; j++) { if (cols[j] >= ys && cols[j] < ye) yarray[cols[j] - ys] += vals[j] * lambda * r / anrm; } } PetscCall(MatRestoreRow(pc->pmat, i, &ncols, &cols, &vals)); } } PetscCall(VecRestoreArray(y, &yarray)); PetscCall(VecRestoreArrayRead(x, &xarray)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSetFromOptions_Kaczmarz(PC pc, PetscOptionItems PetscOptionsObject) { PC_Kaczmarz *jac = (PC_Kaczmarz *)pc->data; PetscFunctionBegin; PetscOptionsHeadBegin(PetscOptionsObject, "Kaczmarz options"); PetscCall(PetscOptionsReal("-pc_kaczmarz_lambda", "relaxation factor (0 < lambda)", "", jac->lambda, &jac->lambda, NULL)); PetscCall(PetscOptionsBool("-pc_kaczmarz_symmetric", "apply row projections symmetrically", "", jac->symmetric, &jac->symmetric, NULL)); PetscOptionsHeadEnd(); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCView_Kaczmarz(PC pc, PetscViewer viewer) { PC_Kaczmarz *jac = (PC_Kaczmarz *)pc->data; PetscBool isascii; PetscFunctionBegin; PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); if (isascii) PetscCall(PetscViewerASCIIPrintf(viewer, " lambda = %g\n", (double)jac->lambda)); PetscFunctionReturn(PETSC_SUCCESS); } /*MC PCKACZMARZ - Kaczmarz iteration {cite}`kaczmarz1937angenaherte` Options Database Keys: + -pc_kaczmarz_lambda - Sets damping parameter defaults to 1.0 - -pc_kaczmarz_symmetric - Apply the row projections symmetrically Level: beginner Note: In parallel this is block-Jacobi with Kaczmarz inner solve on each processor. .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCJACOBI`, `PCBJACOBI` M*/ PETSC_EXTERN PetscErrorCode PCCreate_Kaczmarz(PC pc) { PC_Kaczmarz *jac; PetscFunctionBegin; PetscCall(PetscNew(&jac)); pc->ops->apply = PCApply_Kaczmarz; pc->ops->setfromoptions = PCSetFromOptions_Kaczmarz; pc->ops->setup = NULL; pc->ops->view = PCView_Kaczmarz; pc->ops->destroy = PCDestroy_Kaczmarz; pc->data = (void *)jac; jac->lambda = 1.0; jac->symmetric = PETSC_FALSE; PetscFunctionReturn(PETSC_SUCCESS); }