xref: /petsc/src/mat/interface/matnull.c (revision 73141a14a82ec84c377298716681fa5d6f33c903)
1be1d678aSKris Buschelman #define PETSCMAT_DLL
2be1d678aSKris Buschelman 
3f7765cecSBarry Smith /*
4b4fd4287SBarry Smith     Routines to project vectors out of null spaces.
5f7765cecSBarry Smith */
6f7765cecSBarry Smith 
77c4f633dSBarry Smith #include "private/matimpl.h"      /*I "petscmat.h" I*/
8e090d566SSatish Balay #include "petscsys.h"
9f7765cecSBarry Smith 
10166c7f25SBarry Smith PetscCookie PETSCMAT_DLLEXPORT MAT_NULLSPACE_COOKIE;
118ba1e511SMatthew Knepley 
124a2ae208SSatish Balay #undef __FUNCT__
1372875594SBarry Smith #define __FUNCT__ "MatNullSpaceSetFunction"
1472875594SBarry Smith /*@C
1572875594SBarry Smith    MatNullSpaceSetFunction - set a function that removes a null space from a vector
1672875594SBarry Smith    out of null spaces.
1772875594SBarry Smith 
1872875594SBarry Smith    Collective on MatNullSpace
1972875594SBarry Smith 
2072875594SBarry Smith    Input Parameters:
2172875594SBarry Smith +  sp - the null space object
229dbe9a8aSBarry Smith .  rem - the function that removes the null space
239dbe9a8aSBarry Smith -  ctx - context for the remove function
2472875594SBarry Smith 
25658c74aaSSatish Balay    Level: advanced
2672875594SBarry Smith 
27658c74aaSSatish Balay .keywords: PC, null space, create
28b47fd4b1SSatish Balay 
2972875594SBarry Smith .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate()
3072875594SBarry Smith @*/
319dbe9a8aSBarry Smith PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(Vec,void*),void *ctx)
3272875594SBarry Smith {
3372875594SBarry Smith   PetscFunctionBegin;
343cfa8680SLisandro Dalcin   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
359dbe9a8aSBarry Smith   sp->remove = rem;
369dbe9a8aSBarry Smith   sp->rmctx  = ctx;
3772875594SBarry Smith   PetscFunctionReturn(0);
3872875594SBarry Smith }
3972875594SBarry Smith 
4072875594SBarry Smith #undef __FUNCT__
414a2ae208SSatish Balay #define __FUNCT__ "MatNullSpaceCreate"
42f39d8e23SSatish Balay /*@
435cfeda75SBarry Smith    MatNullSpaceCreate - Creates a data structure used to project vectors
44b4fd4287SBarry Smith    out of null spaces.
45f7765cecSBarry Smith 
464e472627SLois Curfman McInnes    Collective on MPI_Comm
474e472627SLois Curfman McInnes 
48f7765cecSBarry Smith    Input Parameters:
4983c3bef8SLois Curfman McInnes +  comm - the MPI communicator associated with the object
5083c3bef8SLois Curfman McInnes .  has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE
51b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
5283c3bef8SLois Curfman McInnes -  vecs - the vectors that span the null space (excluding the constant vector);
53f7a9e4ceSBarry Smith           these vectors must be orthonormal. These vectors are NOT copied, so do not change them
54*73141a14SBarry Smith           after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count
55*73141a14SBarry Smith           for them by one).
56f7765cecSBarry Smith 
57f7765cecSBarry Smith    Output Parameter:
58b4fd4287SBarry Smith .  SP - the null space context
59f7765cecSBarry Smith 
6083c3bef8SLois Curfman McInnes    Level: advanced
6183c3bef8SLois Curfman McInnes 
6280bf1014SBarry Smith    Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs.
6380bf1014SBarry Smith 
6480bf1014SBarry Smith       If has_cnst is PETSC_TRUE you do not need to pass a constant vector in as a fourth argument to this routine, nor do you
6580bf1014SBarry Smith        need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction().
6680bf1014SBarry Smith 
676e1639daSBarry Smith   Users manual sections:
686e1639daSBarry Smith .   sec_singular
696e1639daSBarry Smith 
7083c3bef8SLois Curfman McInnes .keywords: PC, null space, create
7141a59933SSatish Balay 
7272875594SBarry Smith .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
73f7765cecSBarry Smith @*/
74be1d678aSKris Buschelman PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
75f7765cecSBarry Smith {
765cfeda75SBarry Smith   MatNullSpace   sp;
77dfbe8321SBarry Smith   PetscErrorCode ierr;
78c1ac3661SBarry Smith   PetscInt       i;
79f7765cecSBarry Smith 
803a40ed3dSBarry Smith   PetscFunctionBegin;
817850f3fbSLisandro Dalcin   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);
82574b3360SMatthew Knepley   if (n) PetscValidPointer(vecs,4);
83574b3360SMatthew Knepley   for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_COOKIE,4);
84574b3360SMatthew Knepley   PetscValidPointer(SP,5);
85574b3360SMatthew Knepley 
86574b3360SMatthew Knepley   *SP = PETSC_NULL;
87574b3360SMatthew Knepley #ifndef PETSC_USE_DYNAMIC_LIBRARIES
88574b3360SMatthew Knepley   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
89574b3360SMatthew Knepley #endif
90574b3360SMatthew Knepley 
9152e6d16bSBarry Smith   ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);CHKERRQ(ierr);
92f7765cecSBarry Smith 
93b4fd4287SBarry Smith   sp->has_cnst = has_cnst;
94b4fd4287SBarry Smith   sp->n        = n;
957850f3fbSLisandro Dalcin   sp->vecs     = 0;
967850f3fbSLisandro Dalcin   sp->alpha    = 0;
977850f3fbSLisandro Dalcin   sp->vec      = 0;
987850f3fbSLisandro Dalcin   sp->remove   = 0;
997850f3fbSLisandro Dalcin   sp->rmctx    = 0;
1007850f3fbSLisandro Dalcin 
101f7a9e4ceSBarry Smith   if (n) {
102f7a9e4ceSBarry Smith     ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr);
1037850f3fbSLisandro Dalcin     ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr);
1047850f3fbSLisandro Dalcin     ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr);
1057850f3fbSLisandro Dalcin     for (i=0; i<n; i++) {
1067850f3fbSLisandro Dalcin       ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr);
1077850f3fbSLisandro Dalcin       sp->vecs[i] = vecs[i];
1087850f3fbSLisandro Dalcin     }
109f7a9e4ceSBarry Smith   }
110b4fd4287SBarry Smith 
111b4fd4287SBarry Smith   *SP          = sp;
1123a40ed3dSBarry Smith   PetscFunctionReturn(0);
113f7765cecSBarry Smith }
114f7765cecSBarry Smith 
1154a2ae208SSatish Balay #undef __FUNCT__
1164a2ae208SSatish Balay #define __FUNCT__ "MatNullSpaceDestroy"
117f7765cecSBarry Smith /*@
1185cfeda75SBarry Smith    MatNullSpaceDestroy - Destroys a data structure used to project vectors
119b4fd4287SBarry Smith    out of null spaces.
120b4fd4287SBarry Smith 
1215cfeda75SBarry Smith    Collective on MatNullSpace
1224e472627SLois Curfman McInnes 
123b4fd4287SBarry Smith    Input Parameter:
124b9756687SLois Curfman McInnes .  sp - the null space context to be destroyed
125b9756687SLois Curfman McInnes 
126b9756687SLois Curfman McInnes    Level: advanced
127b4fd4287SBarry Smith 
12883c3bef8SLois Curfman McInnes .keywords: PC, null space, destroy
12941a59933SSatish Balay 
13072875594SBarry Smith .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
131b4fd4287SBarry Smith @*/
132be1d678aSKris Buschelman PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceDestroy(MatNullSpace sp)
133b4fd4287SBarry Smith {
134dfbe8321SBarry Smith   PetscErrorCode ierr;
13585614651SBarry Smith 
1365cfeda75SBarry Smith   PetscFunctionBegin;
1373cfa8680SLisandro Dalcin   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
1387adad957SLisandro Dalcin   if (--((PetscObject)sp)->refct > 0) PetscFunctionReturn(0);
13985614651SBarry Smith 
1405cfeda75SBarry Smith   if (sp->vec)  { ierr = VecDestroy(sp->vec);CHKERRQ(ierr); }
1417850f3fbSLisandro Dalcin   if (sp->vecs) { ierr = VecDestroyVecs(sp->vecs,sp->n);CHKERRQ(ierr); }
1427850f3fbSLisandro Dalcin   ierr = PetscFree(sp->alpha);CHKERRQ(ierr);
143d38fa0fbSBarry Smith   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
1443a40ed3dSBarry Smith   PetscFunctionReturn(0);
145b4fd4287SBarry Smith }
146b4fd4287SBarry Smith 
1474a2ae208SSatish Balay #undef __FUNCT__
1484a2ae208SSatish Balay #define __FUNCT__ "MatNullSpaceRemove"
149812c3f48SMatthew Knepley /*@C
1505cfeda75SBarry Smith    MatNullSpaceRemove - Removes all the components of a null space from a vector.
151f7765cecSBarry Smith 
1525cfeda75SBarry Smith    Collective on MatNullSpace
153f7765cecSBarry Smith 
1544e472627SLois Curfman McInnes    Input Parameters:
1554e472627SLois Curfman McInnes +  sp - the null space context
1564e7234bfSBarry Smith .  vec - the vector from which the null space is to be removed
1575fcf39f4SBarry Smith -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
1584e7234bfSBarry Smith          the removal is done in-place (in vec)
1594e7234bfSBarry Smith 
160db090513SMatthew Knepley    Note: The user is not responsible for the vector returned and should not destroy it.
1614e472627SLois Curfman McInnes 
162b9756687SLois Curfman McInnes    Level: advanced
163b9756687SLois Curfman McInnes 
16483c3bef8SLois Curfman McInnes .keywords: PC, null space, remove
16541a59933SSatish Balay 
16672875594SBarry Smith .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
167f7765cecSBarry Smith @*/
168be1d678aSKris Buschelman PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
169f7765cecSBarry Smith {
17087828ca2SBarry Smith   PetscScalar    sum;
1717850f3fbSLisandro Dalcin   PetscInt       i,N;
1726849ba73SBarry Smith   PetscErrorCode ierr;
173f7765cecSBarry Smith 
1743a40ed3dSBarry Smith   PetscFunctionBegin;
1753cd8ff7eSMatthew Knepley   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
1763cd8ff7eSMatthew Knepley   PetscValidHeaderSpecific(vec,VEC_COOKIE,2);
1773cd8ff7eSMatthew Knepley 
1785cfeda75SBarry Smith   if (out) {
1793cd8ff7eSMatthew Knepley     PetscValidPointer(out,3);
1805cfeda75SBarry Smith     if (!sp->vec) {
1815cfeda75SBarry Smith       ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr);
1827850f3fbSLisandro Dalcin       ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr);
1835cfeda75SBarry Smith     }
1847850f3fbSLisandro Dalcin     ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr);
1857850f3fbSLisandro Dalcin     vec = *out = sp->vec;
1865cfeda75SBarry Smith   }
1875cfeda75SBarry Smith 
188b4fd4287SBarry Smith   if (sp->has_cnst) {
1897850f3fbSLisandro Dalcin     ierr = VecGetSize(vec,&N);CHKERRQ(ierr);
1907850f3fbSLisandro Dalcin     if (N > 0) {
1917850f3fbSLisandro Dalcin       ierr = VecSum(vec,&sum);CHKERRQ(ierr);
19218a7d68fSSatish Balay       sum  = sum/(-1.0*N);
1937850f3fbSLisandro Dalcin       ierr = VecShift(vec,sum);CHKERRQ(ierr);
1947850f3fbSLisandro Dalcin     }
195f7765cecSBarry Smith   }
196b4fd4287SBarry Smith 
1977850f3fbSLisandro Dalcin   if (sp->n) {
1987850f3fbSLisandro Dalcin     ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr);
1997850f3fbSLisandro Dalcin     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
2007850f3fbSLisandro Dalcin     ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr);
201f7765cecSBarry Smith   }
202b4fd4287SBarry Smith 
20372875594SBarry Smith   if (sp->remove){
2047850f3fbSLisandro Dalcin     ierr = (*sp->remove)(vec,sp->rmctx);
20572875594SBarry Smith   }
2063a40ed3dSBarry Smith   PetscFunctionReturn(0);
207f7765cecSBarry Smith }
208a2e34c3dSBarry Smith 
2094a2ae208SSatish Balay #undef __FUNCT__
2104a2ae208SSatish Balay #define __FUNCT__ "MatNullSpaceTest"
211a2e34c3dSBarry Smith /*@
212a2e34c3dSBarry Smith    MatNullSpaceTest  - Tests if the claimed null space is really a
213a2e34c3dSBarry Smith      null space of a matrix
214a2e34c3dSBarry Smith 
215a2e34c3dSBarry Smith    Collective on MatNullSpace
216a2e34c3dSBarry Smith 
217a2e34c3dSBarry Smith    Input Parameters:
218a2e34c3dSBarry Smith +  sp - the null space context
219a2e34c3dSBarry Smith -  mat - the matrix
220a2e34c3dSBarry Smith 
22195902228SMatthew Knepley    Output Parameters:
22295902228SMatthew Knepley .  isNull - PETSC_TRUE if the nullspace is valid for this matrix
22395902228SMatthew Knepley 
224a2e34c3dSBarry Smith    Level: advanced
225a2e34c3dSBarry Smith 
226a2e34c3dSBarry Smith .keywords: PC, null space, remove
227a2e34c3dSBarry Smith 
22872875594SBarry Smith .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
229a2e34c3dSBarry Smith @*/
23095902228SMatthew Knepley PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscTruth *isNull)
231a2e34c3dSBarry Smith {
23287828ca2SBarry Smith   PetscScalar    sum;
2338bb6bcc5SSatish Balay   PetscReal      nrm;
2340b12b109SJed Brown   PetscInt       j,n,N;
2356849ba73SBarry Smith   PetscErrorCode ierr;
236a2e34c3dSBarry Smith   Vec            l,r;
23790d69ab7SBarry Smith   PetscTruth     flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
2383050cee2SBarry Smith   PetscViewer    viewer;
239a2e34c3dSBarry Smith 
240a2e34c3dSBarry Smith   PetscFunctionBegin;
2413cfa8680SLisandro Dalcin   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
2423cfa8680SLisandro Dalcin   PetscValidHeaderSpecific(mat,MAT_COOKIE,2);
2433cfa8680SLisandro Dalcin   n = sp->n;
24490d69ab7SBarry Smith   ierr = PetscOptionsGetTruth(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr);
24590d69ab7SBarry Smith   ierr = PetscOptionsGetTruth(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr);
246a2e34c3dSBarry Smith 
247a2e34c3dSBarry Smith   if (!sp->vec) {
248a2e34c3dSBarry Smith     if (n) {
249a2e34c3dSBarry Smith       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
250a2e34c3dSBarry Smith     } else {
2510b12b109SJed Brown       ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr);
252a2e34c3dSBarry Smith     }
253a2e34c3dSBarry Smith   }
254a2e34c3dSBarry Smith   l    = sp->vec;
255a2e34c3dSBarry Smith 
2567adad957SLisandro Dalcin   ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr);
257a2e34c3dSBarry Smith   if (sp->has_cnst) {
258a2e34c3dSBarry Smith     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
259a2e34c3dSBarry Smith     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
260a2e34c3dSBarry Smith     sum  = 1.0/N;
2612dcb1b2aSMatthew Knepley     ierr = VecSet(l,sum);CHKERRQ(ierr);
262a2e34c3dSBarry Smith     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
2638bb6bcc5SSatish Balay     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
26495902228SMatthew Knepley     if (nrm < 1.e-7) {
26595902228SMatthew Knepley       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr);
26695902228SMatthew Knepley     } else {
26795902228SMatthew Knepley       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr);
26895902228SMatthew Knepley       consistent = PETSC_FALSE;
26995902228SMatthew Knepley     }
2707adad957SLisandro Dalcin     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1 || = %G\n",nrm);CHKERRQ(ierr);
2713050cee2SBarry Smith     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
2723050cee2SBarry Smith     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
273a2e34c3dSBarry Smith     ierr = VecDestroy(r);CHKERRQ(ierr);
274a2e34c3dSBarry Smith   }
275a2e34c3dSBarry Smith 
276a2e34c3dSBarry Smith   for (j=0; j<n; j++) {
277a2e34c3dSBarry Smith     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
2788bb6bcc5SSatish Balay     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
27995902228SMatthew Knepley     if (nrm < 1.e-7) {
28095902228SMatthew Knepley       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);
28195902228SMatthew Knepley     } else {
28295902228SMatthew Knepley       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);
28395902228SMatthew Knepley       consistent = PETSC_FALSE;
28495902228SMatthew Knepley     }
2857adad957SLisandro Dalcin     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
2863050cee2SBarry Smith     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
2873050cee2SBarry Smith     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
288a2e34c3dSBarry Smith   }
289a2e34c3dSBarry Smith 
29072875594SBarry Smith   if (sp->remove){
29172875594SBarry Smith     SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
29272875594SBarry Smith   }
29395902228SMatthew Knepley   *isNull = consistent;
294a2e34c3dSBarry Smith   PetscFunctionReturn(0);
295a2e34c3dSBarry Smith }
296a2e34c3dSBarry Smith 
297