/*$Id: fdmatrix.c,v 1.59 2000/04/09 04:37:00 bsmith Exp bsmith $*/
/*
This is where the abstract matrix operations are defined that are
used for finite difference computations of Jacobians using coloring.
*/
#include "petsc.h"
#include "src/mat/matimpl.h" /*I "mat.h" I*/
#include "src/vec/vecimpl.h"
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringView_Draw"
static int MatFDColoringView_Draw(MatFDColoring fd,Viewer viewer)
{
int ierr,i,j,pause;
PetscTruth isnull;
Draw draw;
PetscReal xr,yr,xl,yl,h,w,x,y,xc,yc,scale = 0.0;
DrawButton button;
PetscFunctionBegin;
ierr = ViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
ierr = DrawIsNull(draw,&isnull);CHKERRQ(ierr); if (isnull) PetscFunctionReturn(0);
ierr = DrawSynchronizedClear(draw);CHKERRQ(ierr);
xr = fd->N; yr = fd->M; h = yr/10.0; w = xr/10.0;
xr += w; yr += h; xl = -w; yl = -h;
ierr = DrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr);
/* loop over colors */
for (i=0; incolors; i++) {
for (j=0; jnrows[i]; j++) {
y = fd->M - fd->rows[i][j] - fd->rstart;
x = fd->columnsforrow[i][j];
ierr = DrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);CHKERRQ(ierr);
}
}
ierr = DrawSynchronizedFlush(draw);CHKERRQ(ierr);
ierr = DrawGetPause(draw,&pause);CHKERRQ(ierr);
if (pause >= 0) { PetscSleep(pause); PetscFunctionReturn(0);}
ierr = DrawCheckResizedWindow(draw);CHKERRQ(ierr);
ierr = DrawSynchronizedGetMouseButton(draw,&button,&xc,&yc,0,0);CHKERRQ(ierr);
while (button != BUTTON_RIGHT) {
ierr = DrawSynchronizedClear(draw);CHKERRQ(ierr);
if (button == BUTTON_LEFT) scale = .5;
else if (button == BUTTON_CENTER) scale = 2.;
xl = scale*(xl + w - xc) + xc - w*scale;
xr = scale*(xr - w - xc) + xc + w*scale;
yl = scale*(yl + h - yc) + yc - h*scale;
yr = scale*(yr - h - yc) + yc + h*scale;
w *= scale; h *= scale;
ierr = DrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr);
/* loop over colors */
for (i=0; incolors; i++) {
for (j=0; jnrows[i]; j++) {
y = fd->M - fd->rows[i][j] - fd->rstart;
x = fd->columnsforrow[i][j];
ierr = DrawRectangle(draw,x,y,x+1,y+1,i+1,i+1,i+1,i+1);CHKERRQ(ierr);
}
}
ierr = DrawCheckResizedWindow(draw);CHKERRQ(ierr);
ierr = DrawSynchronizedGetMouseButton(draw,&button,&xc,&yc,0,0);CHKERRQ(ierr);
}
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringView"
/*@C
MatFDColoringView - Views a finite difference coloring context.
Collective on MatFDColoring
Input Parameters:
+ c - the coloring context
- viewer - visualization context
Level: intermediate
Notes:
The available visualization contexts include
+ VIEWER_STDOUT_SELF - standard output (default)
. VIEWER_STDOUT_WORLD - synchronized standard
output where only the first processor opens
the file. All other processors send their
data to the first processor to print.
- VIEWER_DRAW_WORLD - graphical display of nonzero structure
.seealso: MatFDColoringCreate()
.keywords: Mat, finite differences, coloring, view
@*/
int MatFDColoringView(MatFDColoring c,Viewer viewer)
{
int i,j,format,ierr;
PetscTruth isdraw,isascii;
PetscFunctionBegin;
PetscValidHeaderSpecific(c,MAT_FDCOLORING_COOKIE);
if (!viewer) viewer = VIEWER_STDOUT_(c->comm);
PetscValidHeaderSpecific(viewer,VIEWER_COOKIE);
PetscCheckSameComm(c,viewer);
ierr = PetscTypeCompare((PetscObject)viewer,DRAW_VIEWER,&isdraw);CHKERRQ(ierr);
ierr = PetscTypeCompare((PetscObject)viewer,ASCII_VIEWER,&isascii);CHKERRQ(ierr);
if (isdraw) {
ierr = MatFDColoringView_Draw(c,viewer);CHKERRQ(ierr);
} else if (isascii) {
ierr = ViewerASCIIPrintf(viewer,"MatFDColoring Object:\n");CHKERRQ(ierr);
ierr = ViewerASCIIPrintf(viewer," Error tolerance=%g\n",c->error_rel);CHKERRQ(ierr);
ierr = ViewerASCIIPrintf(viewer," Umin=%g\n",c->umin);CHKERRQ(ierr);
ierr = ViewerASCIIPrintf(viewer," Number of colors=%d\n",c->ncolors);CHKERRQ(ierr);
ierr = ViewerGetFormat(viewer,&format);CHKERRQ(ierr);
if (format != VIEWER_FORMAT_ASCII_INFO) {
for (i=0; incolors; i++) {
ierr = ViewerASCIIPrintf(viewer," Information for color %d\n",i);CHKERRQ(ierr);
ierr = ViewerASCIIPrintf(viewer," Number of columns %d\n",c->ncolumns[i]);CHKERRQ(ierr);
for (j=0; jncolumns[i]; j++) {
ierr = ViewerASCIIPrintf(viewer," %d\n",c->columns[i][j]);CHKERRQ(ierr);
}
ierr = ViewerASCIIPrintf(viewer," Number of rows %d\n",c->nrows[i]);CHKERRQ(ierr);
for (j=0; jnrows[i]; j++) {
ierr = ViewerASCIIPrintf(viewer," %d %d \n",c->rows[i][j],c->columnsforrow[i][j]);CHKERRQ(ierr);
}
}
}
ierr = ViewerFlush(viewer);CHKERRQ(ierr);
} else {
SETERRQ1(1,1,"Viewer type %s not supported for MatFDColoring",((PetscObject)viewer)->type_name);
}
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringSetParameters"
/*@
MatFDColoringSetParameters - Sets the parameters for the sparse approximation of
a Jacobian matrix using finite differences.
Collective on MatFDColoring
The Jacobian is estimated with the differencing approximation
.vb
F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
h = error_rel*u[i] if abs(u[i]) > umin
= +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
dx_{i} = (0, ... 1, .... 0)
.ve
Input Parameters:
+ coloring - the coloring context
. error_rel - relative error
- umin - minimum allowable u-value magnitude
Level: advanced
.keywords: Mat, finite differences, coloring, set, parameters
.seealso: MatFDColoringCreate()
@*/
int MatFDColoringSetParameters(MatFDColoring matfd,PetscReal error,PetscReal umin)
{
PetscFunctionBegin;
PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
if (error != PETSC_DEFAULT) matfd->error_rel = error;
if (umin != PETSC_DEFAULT) matfd->umin = umin;
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringSetFrequency"
/*@
MatFDColoringSetFrequency - Sets the frequency for computing new Jacobian
matrices.
Collective on MatFDColoring
Input Parameters:
+ coloring - the coloring context
- freq - frequency (default is 1)
Options Database Keys:
. -mat_fd_coloring_freq - Sets coloring frequency
Level: advanced
Notes:
Using a modified Newton strategy, where the Jacobian remains fixed for several
iterations, can be cost effective in terms of overall nonlinear solution
efficiency. This parameter indicates that a new Jacobian will be computed every
nonlinear iterations.
.keywords: Mat, finite differences, coloring, set, frequency
.seealso: MatFDColoringCreate(), MatFDColoringGetFrequency()
@*/
int MatFDColoringSetFrequency(MatFDColoring matfd,int freq)
{
PetscFunctionBegin;
PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
matfd->freq = freq;
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringGetFrequency"
/*@
MatFDColoringGetFrequency - Gets the frequency for computing new Jacobian
matrices.
Not Collective
Input Parameters:
. coloring - the coloring context
Output Parameters:
. freq - frequency (default is 1)
Options Database Keys:
. -mat_fd_coloring_freq - Sets coloring frequency
Level: advanced
Notes:
Using a modified Newton strategy, where the Jacobian remains fixed for several
iterations, can be cost effective in terms of overall nonlinear solution
efficiency. This parameter indicates that a new Jacobian will be computed every
nonlinear iterations.
.keywords: Mat, finite differences, coloring, get, frequency
.seealso: MatFDColoringSetFrequency()
@*/
int MatFDColoringGetFrequency(MatFDColoring matfd,int *freq)
{
PetscFunctionBegin;
PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
*freq = matfd->freq;
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringSetFunction"
/*@C
MatFDColoringSetFunction - Sets the function to use for computing the Jacobian.
Collective on MatFDColoring
Input Parameters:
+ coloring - the coloring context
. f - the function
- fctx - the optional user-defined function context
Level: intermediate
Notes:
In Fortran you must call MatFDColoringSetFunctionSNES() for a coloring object to
be used with the SNES solvers and MatFDColoringSetFunctionTS() if it is to be used
with the TS solvers.
.keywords: Mat, Jacobian, finite differences, set, function
@*/
int MatFDColoringSetFunction(MatFDColoring matfd,int (*f)(void),void *fctx)
{
PetscFunctionBegin;
PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
matfd->f = f;
matfd->fctx = fctx;
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringSetFromOptions"
/*@
MatFDColoringSetFromOptions - Sets coloring finite difference parameters from
the options database.
Collective on MatFDColoring
The Jacobian, F'(u), is estimated with the differencing approximation
.vb
F'(u)_{:,i} = [F(u+h*dx_{i}) - F(u)]/h where
h = error_rel*u[i] if abs(u[i]) > umin
= +/- error_rel*umin otherwise, with +/- determined by the sign of u[i]
dx_{i} = (0, ... 1, .... 0)
.ve
Input Parameter:
. coloring - the coloring context
Options Database Keys:
+ -mat_fd_coloring_error - Sets (square root
of relative error in the function)
. -mat_fd_coloring_umin - Sets umin, the minimum allowable u-value magnitude
. -mat_fd_coloring_freq - Sets frequency of computing a new Jacobian
. -mat_fd_coloring_view - Activates basic viewing
. -mat_fd_coloring_view_info - Activates viewing info
- -mat_fd_coloring_view_draw - Activates drawing
Level: intermediate
.keywords: Mat, finite differences, parameters
@*/
int MatFDColoringSetFromOptions(MatFDColoring matfd)
{
int ierr,freq = 1;
PetscReal error = PETSC_DEFAULT,umin = PETSC_DEFAULT;
PetscTruth flag;
PetscFunctionBegin;
PetscValidHeaderSpecific(matfd,MAT_FDCOLORING_COOKIE);
ierr = OptionsGetDouble(matfd->prefix,"-mat_fd_coloring_err",&error,PETSC_NULL);CHKERRQ(ierr);
ierr = OptionsGetDouble(matfd->prefix,"-mat_fd_coloring_umin",&umin,PETSC_NULL);CHKERRQ(ierr);
ierr = MatFDColoringSetParameters(matfd,error,umin);CHKERRQ(ierr);
ierr = OptionsGetInt(matfd->prefix,"-mat_fd_coloring_freq",&freq,PETSC_NULL);CHKERRQ(ierr);
ierr = MatFDColoringSetFrequency(matfd,freq);CHKERRQ(ierr);
ierr = OptionsHasName(PETSC_NULL,"-help",&flag);CHKERRQ(ierr);
if (flag) {
ierr = MatFDColoringPrintHelp(matfd);CHKERRQ(ierr);
}
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringPrintHelp"
/*@
MatFDColoringPrintHelp - Prints help message for matrix finite difference calculations
using coloring.
Collective on MatFDColoring
Input Parameter:
. fdcoloring - the MatFDColoring context
Level: intermediate
.seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringSetFromOptions()
@*/
int MatFDColoringPrintHelp(MatFDColoring fd)
{
int ierr;
PetscFunctionBegin;
PetscValidHeaderSpecific(fd,MAT_FDCOLORING_COOKIE);
ierr = (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_err : set sqrt rel tol in function, defaults to %g\n",fd->error_rel);CHKERRQ(ierr);
ierr = (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_umin : see users manual, defaults to %d\n",fd->umin);CHKERRQ(ierr);
ierr = (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_freq : frequency that Jacobian is recomputed, defaults to %d\n",fd->freq);CHKERRQ(ierr);
ierr = (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_view\n");CHKERRQ(ierr);
ierr = (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_view_draw\n");CHKERRQ(ierr);
ierr = (*PetscHelpPrintf)(fd->comm,"-mat_fd_coloring_view_info\n");CHKERRQ(ierr);
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringView_Private"
int MatFDColoringView_Private(MatFDColoring fd)
{
int ierr;
PetscTruth flg;
PetscFunctionBegin;
ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view",&flg);CHKERRQ(ierr);
if (flg) {
ierr = MatFDColoringView(fd,VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
}
ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_info",&flg);CHKERRQ(ierr);
if (flg) {
ierr = ViewerPushFormat(VIEWER_STDOUT_(fd->comm),VIEWER_FORMAT_ASCII_INFO,PETSC_NULL);CHKERRQ(ierr);
ierr = MatFDColoringView(fd,VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
ierr = ViewerPopFormat(VIEWER_STDOUT_(fd->comm));CHKERRQ(ierr);
}
ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_view_draw",&flg);CHKERRQ(ierr);
if (flg) {
ierr = MatFDColoringView(fd,VIEWER_DRAW_(fd->comm));CHKERRQ(ierr);
ierr = ViewerFlush(VIEWER_DRAW_(fd->comm));CHKERRQ(ierr);
}
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringCreate"
/*@C
MatFDColoringCreate - Creates a matrix coloring context for finite difference
computation of Jacobians.
Collective on Mat
Input Parameters:
+ mat - the matrix containing the nonzero structure of the Jacobian
- iscoloring - the coloring of the matrix
Output Parameter:
. color - the new coloring context
Options Database Keys:
+ -mat_fd_coloring_view - Activates basic viewing or coloring
. -mat_fd_coloring_view_draw - Activates drawing of coloring
- -mat_fd_coloring_view_info - Activates viewing of coloring info
Level: intermediate
.seealso: MatFDColoringDestroy(),SNESDefaultComputeJacobianColor(), ISColoringCreate(),
MatFDColoringSetFunction(), MatFDColoringSetFromOptions()
@*/
int MatFDColoringCreate(Mat mat,ISColoring iscoloring,MatFDColoring *color)
{
MatFDColoring c;
MPI_Comm comm;
int ierr,M,N;
PetscFunctionBegin;
ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
if (M != N) SETERRQ(PETSC_ERR_SUP,0,"Only for square matrices");
ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
PetscHeaderCreate(c,_p_MatFDColoring,int,MAT_FDCOLORING_COOKIE,0,"MatFDColoring",comm,
MatFDColoringDestroy,MatFDColoringView);
PLogObjectCreate(c);
if (mat->ops->fdcoloringcreate) {
ierr = (*mat->ops->fdcoloringcreate)(mat,iscoloring,c);CHKERRQ(ierr);
} else {
SETERRQ(PETSC_ERR_SUP,0,"Code not yet written for this matrix type");
}
c->error_rel = 1.e-8;
c->umin = 1.e-6;
c->freq = 1;
ierr = MatFDColoringView_Private(c);CHKERRQ(ierr);
*color = c;
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringDestroy"
/*@C
MatFDColoringDestroy - Destroys a matrix coloring context that was created
via MatFDColoringCreate().
Collective on MatFDColoring
Input Parameter:
. c - coloring context
Level: intermediate
.seealso: MatFDColoringCreate()
@*/
int MatFDColoringDestroy(MatFDColoring c)
{
int i,ierr;
PetscFunctionBegin;
if (--c->refct > 0) PetscFunctionReturn(0);
for (i=0; incolors; i++) {
if (c->columns[i]) {ierr = PetscFree(c->columns[i]);CHKERRQ(ierr);}
if (c->rows[i]) {ierr = PetscFree(c->rows[i]);CHKERRQ(ierr);}
if (c->columnsforrow[i]) {ierr = PetscFree(c->columnsforrow[i]);CHKERRQ(ierr);}
}
ierr = PetscFree(c->ncolumns);CHKERRQ(ierr);
ierr = PetscFree(c->columns);CHKERRQ(ierr);
ierr = PetscFree(c->nrows);CHKERRQ(ierr);
ierr = PetscFree(c->rows);CHKERRQ(ierr);
ierr = PetscFree(c->columnsforrow);CHKERRQ(ierr);
ierr = PetscFree(c->scale);CHKERRQ(ierr);
if (c->w1) {
ierr = VecDestroy(c->w1);CHKERRQ(ierr);
ierr = VecDestroy(c->w2);CHKERRQ(ierr);
ierr = VecDestroy(c->w3);CHKERRQ(ierr);
}
PLogObjectDestroy(c);
PetscHeaderDestroy(c);
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringApply"
/*@
MatFDColoringApply - Given a matrix for which a MatFDColoring context
has been created, computes the Jacobian for a function via finite differences.
Collective on MatFDColoring
Input Parameters:
+ mat - location to store Jacobian
. coloring - coloring context created with MatFDColoringCreate()
. x1 - location at which Jacobian is to be computed
- sctx - optional context required by function (actually a SNES context)
Options Database Keys:
. -mat_fd_coloring_freq - Sets coloring frequency
Level: intermediate
.seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
.keywords: coloring, Jacobian, finite differences
@*/
int MatFDColoringApply(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
{
int k,ierr,N,start,end,l,row,col,srow;
Scalar dx,mone = -1.0,*y,*scale = coloring->scale,*xx,*wscale = coloring->wscale;
PetscReal epsilon = coloring->error_rel,umin = coloring->umin;
MPI_Comm comm = coloring->comm;
Vec w1,w2,w3;
int (*f)(void *,Vec,Vec,void*)= (int (*)(void *,Vec,Vec,void *))coloring->f;
void *fctx = coloring->fctx;
PetscTruth flg;
PetscFunctionBegin;
PetscValidHeaderSpecific(J,MAT_COOKIE);
PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE);
PetscValidHeaderSpecific(x1,VEC_COOKIE);
if (!coloring->w1) {
ierr = VecDuplicate(x1,&coloring->w1);CHKERRQ(ierr);
PLogObjectParent(coloring,coloring->w1);
ierr = VecDuplicate(x1,&coloring->w2);CHKERRQ(ierr);
PLogObjectParent(coloring,coloring->w2);
ierr = VecDuplicate(x1,&coloring->w3);CHKERRQ(ierr);
PLogObjectParent(coloring,coloring->w3);
}
w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
ierr = MatSetUnfactored(J);CHKERRQ(ierr);
ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg);CHKERRQ(ierr);
if (flg) {
PLogInfo(coloring,"MatFDColoringApply: Not calling MatZeroEntries()\n");
} else {
ierr = MatZeroEntries(J);CHKERRQ(ierr);
}
ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
ierr = (*f)(sctx,x1,w1,fctx);CHKERRQ(ierr);
ierr = PetscMemzero(wscale,N*sizeof(Scalar));CHKERRQ(ierr);
/*
Loop over each color
*/
ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);
for (k=0; kncolors; k++) {
ierr = VecCopy(x1,w3);CHKERRQ(ierr);
/*
Loop over each column associated with color adding the
perturbation to the vector w3.
*/
for (l=0; lncolumns[k]; l++) {
col = coloring->columns[k][l]; /* column of the matrix we are probing for */
dx = xx[col-start];
if (dx == 0.0) dx = 1.0;
#if !defined(PETSC_USE_COMPLEX)
if (dx < umin && dx >= 0.0) dx = umin;
else if (dx < 0.0 && dx > -umin) dx = -umin;
#else
if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0) dx = umin;
else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
#endif
dx *= epsilon;
wscale[col] = 1.0/dx;
ierr = VecSetValues(w3,1,&col,&dx,ADD_VALUES);CHKERRQ(ierr);
}
/*
Evaluate function at x1 + dx (here dx is a vector of perturbations)
*/
ierr = (*f)(sctx,w3,w2,fctx);CHKERRQ(ierr);
ierr = VecAXPY(&mone,w1,w2);CHKERRQ(ierr);
/* Communicate scale to all processors */
ierr = MPI_Allreduce(wscale,scale,N,MPIU_SCALAR,PetscSum_Op,comm);CHKERRQ(ierr);
/*
Loop over rows of vector, putting results into Jacobian matrix
*/
ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
for (l=0; lnrows[k]; l++) {
row = coloring->rows[k][l];
col = coloring->columnsforrow[k][l];
y[row] *= scale[col];
srow = row + start;
ierr = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
}
ierr = VecRestoreArray(w2,&y);CHKERRQ(ierr);
}
ierr = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
PetscFunctionReturn(0);
}
#undef __FUNC__
#define __FUNC__ /**/"MatFDColoringApplyTS"
/*@
MatFDColoringApplyTS - Given a matrix for which a MatFDColoring context
has been created, computes the Jacobian for a function via finite differences.
Collective on Mat, MatFDColoring, and Vec
Input Parameters:
+ mat - location to store Jacobian
. coloring - coloring context created with MatFDColoringCreate()
. x1 - location at which Jacobian is to be computed
- sctx - optional context required by function (actually a SNES context)
Options Database Keys:
. -mat_fd_coloring_freq - Sets coloring frequency
Level: intermediate
.seealso: MatFDColoringCreate(), MatFDColoringDestroy(), MatFDColoringView()
.keywords: coloring, Jacobian, finite differences
@*/
int MatFDColoringApplyTS(Mat J,MatFDColoring coloring,PetscReal t,Vec x1,MatStructure *flag,void *sctx)
{
int k,ierr,N,start,end,l,row,col,srow;
int (*f)(void *,PetscReal,Vec,Vec,void*)= (int (*)(void *,PetscReal,Vec,Vec,void *))coloring->f;
Scalar dx,mone = -1.0,*y,*scale = coloring->scale,*xx,*wscale = coloring->wscale;
PetscReal epsilon = coloring->error_rel,umin = coloring->umin;
MPI_Comm comm = coloring->comm;
Vec w1,w2,w3;
void *fctx = coloring->fctx;
PetscTruth flg;
PetscFunctionBegin;
PetscValidHeaderSpecific(J,MAT_COOKIE);
PetscValidHeaderSpecific(coloring,MAT_FDCOLORING_COOKIE);
PetscValidHeaderSpecific(x1,VEC_COOKIE);
if (!coloring->w1) {
ierr = VecDuplicate(x1,&coloring->w1);CHKERRQ(ierr);
PLogObjectParent(coloring,coloring->w1);
ierr = VecDuplicate(x1,&coloring->w2);CHKERRQ(ierr);
PLogObjectParent(coloring,coloring->w2);
ierr = VecDuplicate(x1,&coloring->w3);CHKERRQ(ierr);
PLogObjectParent(coloring,coloring->w3);
}
w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
ierr = OptionsHasName(PETSC_NULL,"-mat_fd_coloring_dont_rezero",&flg);CHKERRQ(ierr);
if (flg) {
PLogInfo(coloring,"MatFDColoringApplyTS: Not calling MatZeroEntries()\n");
} else {
ierr = MatZeroEntries(J);CHKERRQ(ierr);
}
ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
ierr = (*f)(sctx,t,x1,w1,fctx);CHKERRQ(ierr);
ierr = PetscMemzero(wscale,N*sizeof(Scalar));CHKERRQ(ierr);
/*
Loop over each color
*/
ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);
for (k=0; kncolors; k++) {
ierr = VecCopy(x1,w3);CHKERRQ(ierr);
/*
Loop over each column associated with color adding the
perturbation to the vector w3.
*/
for (l=0; lncolumns[k]; l++) {
col = coloring->columns[k][l]; /* column of the matrix we are probing for */
dx = xx[col-start];
if (dx == 0.0) dx = 1.0;
#if !defined(PETSC_USE_COMPLEX)
if (dx < umin && dx >= 0.0) dx = umin;
else if (dx < 0.0 && dx > -umin) dx = -umin;
#else
if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0) dx = umin;
else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
#endif
dx *= epsilon;
wscale[col] = 1.0/dx;
ierr = VecSetValues(w3,1,&col,&dx,ADD_VALUES);CHKERRQ(ierr);
}
/*
Evaluate function at x1 + dx (here dx is a vector of perturbations)
*/
ierr = (*f)(sctx,t,w3,w2,fctx);CHKERRQ(ierr);
ierr = VecAXPY(&mone,w1,w2);CHKERRQ(ierr);
/* Communicate scale to all processors */
ierr = MPI_Allreduce(wscale,scale,N,MPIU_SCALAR,PetscSum_Op,comm);CHKERRQ(ierr);
/*
Loop over rows of vector, putting results into Jacobian matrix
*/
ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
for (l=0; lnrows[k]; l++) {
row = coloring->rows[k][l];
col = coloring->columnsforrow[k][l];
y[row] *= scale[col];
srow = row + start;
ierr = MatSetValues(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
}
ierr = VecRestoreArray(w2,&y);CHKERRQ(ierr);
}
ierr = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
PetscFunctionReturn(0);
}