1 
2 #include <petsc/private/dmimpl.h>
3 #include <petscdm.h>     /*I "petscdm.h" I*/
4 #include <petscdmplex.h> /*I "petscdmplex.h" I*/
5 #include <petscksp.h>    /*I "petscksp.h" I*/
6 #include <petscblaslapack.h>
7 
8 typedef struct _projectConstraintsCtx
9 {
10   DM  dm;
11   Vec mask;
12 }
13 projectConstraintsCtx;
14 
MatMult_GlobalToLocalNormal(Mat CtC,Vec x,Vec y)15 PetscErrorCode MatMult_GlobalToLocalNormal(Mat CtC, Vec x, Vec y)
16 {
17   DM                    dm;
18   Vec                   local, mask;
19   projectConstraintsCtx *ctx;
20   PetscErrorCode        ierr;
21 
22   PetscFunctionBegin;
23   ierr = MatShellGetContext(CtC,&ctx);CHKERRQ(ierr);
24   dm   = ctx->dm;
25   mask = ctx->mask;
26   ierr = DMGetLocalVector(dm,&local);CHKERRQ(ierr);
27   ierr = DMGlobalToLocalBegin(dm,x,INSERT_VALUES,local);CHKERRQ(ierr);
28   ierr = DMGlobalToLocalEnd(dm,x,INSERT_VALUES,local);CHKERRQ(ierr);
29   if (mask) {ierr = VecPointwiseMult(local,mask,local);CHKERRQ(ierr);}
30   ierr = VecSet(y,0.);CHKERRQ(ierr);
31   ierr = DMLocalToGlobalBegin(dm,local,ADD_VALUES,y);CHKERRQ(ierr);
32   ierr = DMLocalToGlobalEnd(dm,local,ADD_VALUES,y);CHKERRQ(ierr);
33   ierr = DMRestoreLocalVector(dm,&local);CHKERRQ(ierr);
34   PetscFunctionReturn(0);
35 }
36 
DMGlobalToLocalSolve_project1(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar u[],void * ctx)37 static PetscErrorCode DMGlobalToLocalSolve_project1 (PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx)
38 {
39   PetscInt f;
40 
41   PetscFunctionBegin;
42   for (f = 0; f < Nf; f++) {
43     u[f] = 1.;
44   }
45   PetscFunctionReturn(0);
46 }
47 
48 /*@
49   DMGlobalToLocalSolve - Solve for the global vector that is mapped to a given local vector by DMGlobalToLocalBegin()/DMGlobalToLocalEnd() with mode
50   = INSERT_VALUES.  It is assumed that the sum of all the local vector sizes is greater than or equal to the global vector size, so the solution is
51   a least-squares solution.  It is also assumed that DMLocalToGlobalBegin()/DMLocalToGlobalEnd() with mode = ADD_VALUES is the adjoint of the
52   global-to-local map, so that the least-squares solution may be found by the normal equations.
53 
54   collective
55 
56   Input Parameters:
57 + dm - The DM object
58 . x - The local vector
59 - y - The global vector: the input value of globalVec is used as an initial guess
60 
61   Output Parameters:
62 . y - The least-squares solution
63 
64   Level: advanced
65 
66   Note: If the DM is of type DMPLEX, then y is the solution of L' * D * L * y = L' * D * x, where D is a diagonal mask that is 1 for every point in
67   the union of the closures of the local cells and 0 otherwise.  This difference is only relevant if there are anchor points that are not in the
68   closure of any local cell (see DMPlexGetAnchors()/DMPlexSetAnchors()).
69 
70 .seealso: DMGlobalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMPlexGetAnchors(), DMPlexSetAnchors()
71 @*/
DMGlobalToLocalSolve(DM dm,Vec x,Vec y)72 PetscErrorCode DMGlobalToLocalSolve(DM dm, Vec x, Vec y)
73 {
74   Mat                   CtC;
75   PetscInt              n, N, cStart, cEnd, c;
76   PetscBool             isPlex;
77   KSP                   ksp;
78   PC                    pc;
79   Vec                   global, mask=NULL;
80   projectConstraintsCtx ctx;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex);CHKERRQ(ierr);
85   if (isPlex) {
86     /* mark points in the closure */
87     ierr = DMCreateLocalVector(dm,&mask);CHKERRQ(ierr);
88     ierr = VecSet(mask,0.0);CHKERRQ(ierr);
89     ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
90     if (cEnd > cStart) {
91       PetscScalar *ones;
92       PetscInt numValues, i;
93 
94       ierr = DMPlexVecGetClosure(dm,NULL,mask,cStart,&numValues,NULL);CHKERRQ(ierr);
95       ierr = PetscMalloc1(numValues,&ones);CHKERRQ(ierr);
96       for (i = 0; i < numValues; i++) {
97         ones[i] = 1.;
98       }
99       for (c = cStart; c < cEnd; c++) {
100         ierr = DMPlexVecSetClosure(dm,NULL,mask,c,ones,INSERT_VALUES);CHKERRQ(ierr);
101       }
102       ierr = PetscFree(ones);CHKERRQ(ierr);
103     }
104   }
105   else {
106     PetscBool hasMask;
107 
108     ierr = DMHasNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &hasMask);CHKERRQ(ierr);
109     if (!hasMask) {
110       PetscErrorCode (**func) (PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
111       void            **ctx;
112       PetscInt          Nf, f;
113 
114       ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
115       ierr = PetscMalloc2(Nf, &func, Nf, &ctx);CHKERRQ(ierr);
116       for (f = 0; f < Nf; ++f) {
117         func[f] = DMGlobalToLocalSolve_project1;
118         ctx[f]  = NULL;
119       }
120       ierr = DMGetNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr);
121       ierr = DMProjectFunctionLocal(dm,0.0,func,ctx,INSERT_ALL_VALUES,mask);CHKERRQ(ierr);
122       ierr = DMRestoreNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr);
123       ierr = PetscFree2(func, ctx);CHKERRQ(ierr);
124     }
125     ierr = DMGetNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr);
126   }
127   ctx.dm   = dm;
128   ctx.mask = mask;
129   ierr = VecGetSize(y,&N);CHKERRQ(ierr);
130   ierr = VecGetLocalSize(y,&n);CHKERRQ(ierr);
131   ierr = MatCreate(PetscObjectComm((PetscObject)dm),&CtC);CHKERRQ(ierr);
132   ierr = MatSetSizes(CtC,n,n,N,N);CHKERRQ(ierr);
133   ierr = MatSetType(CtC,MATSHELL);CHKERRQ(ierr);
134   ierr = MatSetUp(CtC);CHKERRQ(ierr);
135   ierr = MatShellSetContext(CtC,&ctx);CHKERRQ(ierr);
136   ierr = MatShellSetOperation(CtC,MATOP_MULT,(void(*)(void))MatMult_GlobalToLocalNormal);CHKERRQ(ierr);
137   ierr = KSPCreate(PetscObjectComm((PetscObject)dm),&ksp);CHKERRQ(ierr);
138   ierr = KSPSetOperators(ksp,CtC,CtC);CHKERRQ(ierr);
139   ierr = KSPSetType(ksp,KSPCG);CHKERRQ(ierr);
140   ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
141   ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr);
142   ierr = KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);CHKERRQ(ierr);
143   ierr = KSPSetUp(ksp);CHKERRQ(ierr);
144   ierr = DMGetGlobalVector(dm,&global);CHKERRQ(ierr);
145   ierr = VecSet(global,0.);CHKERRQ(ierr);
146   if (mask) {ierr = VecPointwiseMult(x,mask,x);CHKERRQ(ierr);}
147   ierr = DMLocalToGlobalBegin(dm,x,ADD_VALUES,global);CHKERRQ(ierr);
148   ierr = DMLocalToGlobalEnd(dm,x,ADD_VALUES,global);CHKERRQ(ierr);
149   ierr = KSPSolve(ksp,global,y);CHKERRQ(ierr);
150   ierr = DMRestoreGlobalVector(dm,&global);CHKERRQ(ierr);
151   /* clean up */
152   ierr = KSPDestroy(&ksp);CHKERRQ(ierr);
153   ierr = MatDestroy(&CtC);CHKERRQ(ierr);
154   if (isPlex) {
155     ierr = VecDestroy(&mask);CHKERRQ(ierr);
156   }
157   else {
158     ierr = DMRestoreNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr);
159   }
160 
161   PetscFunctionReturn(0);
162 }
163 
164 /*@C
165   DMProjectField - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector.
166 
167   Collective on DM
168 
169   Input Parameters:
170 + dm      - The DM
171 . time    - The time
172 . U       - The input field vector
173 . funcs   - The functions to evaluate, one per field
174 - mode    - The insertion mode for values
175 
176   Output Parameter:
177 . X       - The output vector
178 
179    Calling sequence of func:
180 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
181 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
182 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
183 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
184 
185 +  dim          - The spatial dimension
186 .  Nf           - The number of input fields
187 .  NfAux        - The number of input auxiliary fields
188 .  uOff         - The offset of each field in u[]
189 .  uOff_x       - The offset of each field in u_x[]
190 .  u            - The field values at this point in space
191 .  u_t          - The field time derivative at this point in space (or NULL)
192 .  u_x          - The field derivatives at this point in space
193 .  aOff         - The offset of each auxiliary field in u[]
194 .  aOff_x       - The offset of each auxiliary field in u_x[]
195 .  a            - The auxiliary field values at this point in space
196 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
197 .  a_x          - The auxiliary field derivatives at this point in space
198 .  t            - The current time
199 .  x            - The coordinates of this point
200 .  numConstants - The number of constants
201 .  constants    - The value of each constant
202 -  f            - The value of the function at this point in space
203 
204   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
205   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
206   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
207   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
208 
209   Level: intermediate
210 
211 .seealso: DMProjectFieldLocal(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
212 @*/
DMProjectField(DM dm,PetscReal time,Vec U,void (** funcs)(PetscInt,PetscInt,PetscInt,const PetscInt[],const PetscInt[],const PetscScalar[],const PetscScalar[],const PetscScalar[],const PetscInt[],const PetscInt[],const PetscScalar[],const PetscScalar[],const PetscScalar[],PetscReal,const PetscReal[],PetscInt,const PetscScalar[],PetscScalar[]),InsertMode mode,Vec X)213 PetscErrorCode DMProjectField(DM dm, PetscReal time, Vec U,
214                               void (**funcs)(PetscInt, PetscInt, PetscInt,
215                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
216                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
217                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
218                               InsertMode mode, Vec X)
219 {
220   Vec            localX, localU;
221   PetscErrorCode ierr;
222 
223   PetscFunctionBegin;
224   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
225   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
226   /* We currently check whether locU == locX to see if we need to apply BC */
227   if (U != X) {ierr = DMGetLocalVector(dm, &localU);CHKERRQ(ierr);}
228   else        {localU = localX;}
229   ierr = DMGlobalToLocalBegin(dm, U, INSERT_VALUES, localU);CHKERRQ(ierr);
230   ierr = DMGlobalToLocalEnd(dm, U, INSERT_VALUES, localU);CHKERRQ(ierr);
231   ierr = DMProjectFieldLocal(dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
232   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
233   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
234   if (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES) {
235     Mat cMat;
236 
237     ierr = DMGetDefaultConstraints(dm, NULL, &cMat);CHKERRQ(ierr);
238     if (cMat) {
239       ierr = DMGlobalToLocalSolve(dm, localX, X);CHKERRQ(ierr);
240     }
241   }
242   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
243   if (U != X) {ierr = DMRestoreLocalVector(dm, &localU);CHKERRQ(ierr);}
244   PetscFunctionReturn(0);
245 }
246 
247 /********************* Adaptive Interpolation **************************/
248 
249 /* See the discussion of Adaptive Interpolation in manual/high_level_mg.rst */
DMAdaptInterpolator(DM dmc,DM dmf,Mat In,KSP smoother,PetscInt Nc,Vec vf[],Vec vc[],Mat * InAdapt,void * user)250 PetscErrorCode DMAdaptInterpolator(DM dmc, DM dmf, Mat In, KSP smoother, PetscInt Nc, Vec vf[], Vec vc[], Mat *InAdapt, void *user)
251 {
252   Mat            globalA;
253   Vec            tmp, tmp2;
254   PetscScalar   *A, *b, *x, *workscalar;
255   PetscReal     *w, *sing, *workreal, rcond = PETSC_SMALL;
256   PetscBLASInt   M, N, one = 1, irank, lwrk, info;
257   PetscInt       debug = 0, rStart, rEnd, r, maxcols = 0, k;
258   PetscBool      allocVc = PETSC_FALSE;
259   PetscErrorCode ierr;
260 
261   PetscFunctionBegin;
262   ierr = PetscLogEventBegin(DM_AdaptInterpolator,dmc,dmf,0,0);CHKERRQ(ierr);
263   ierr = PetscOptionsGetInt(NULL, NULL, "-dm_interpolator_adapt_debug", &debug, NULL);CHKERRQ(ierr);
264   ierr = MatDuplicate(In, MAT_SHARE_NONZERO_PATTERN, InAdapt);CHKERRQ(ierr);
265   ierr = MatGetOwnershipRange(In, &rStart, &rEnd);CHKERRQ(ierr);
266   #if 0
267   ierr = MatGetMaxRowLen(In, &maxcols);CHKERRQ(ierr);
268   #else
269   for (r = rStart; r < rEnd; ++r) {
270     PetscInt           ncols;
271     const PetscInt    *cols;
272     const PetscScalar *vals;
273 
274     ierr = MatGetRow(In, r, &ncols, &cols, &vals);CHKERRQ(ierr);
275     maxcols = PetscMax(maxcols, ncols);
276     ierr = MatRestoreRow(In, r, &ncols, &cols, &vals);CHKERRQ(ierr);
277   }
278   #endif
279   if (Nc < maxcols) PetscPrintf(PETSC_COMM_SELF, "The number of input vectors %D < %D the maximum number of column entries\n", Nc, maxcols);
280   for (k = 0; k < Nc; ++k) {
281     char        name[PETSC_MAX_PATH_LEN];
282     const char *prefix;
283 
284     ierr = PetscObjectGetOptionsPrefix((PetscObject) smoother, &prefix);CHKERRQ(ierr);
285     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%sCoarse Vector %D", prefix ? prefix : NULL, k);CHKERRQ(ierr);
286     ierr = PetscObjectSetName((PetscObject) vc[k], name);CHKERRQ(ierr);
287     ierr = VecViewFromOptions(vc[k], NULL, "-dm_adapt_interp_view_coarse");CHKERRQ(ierr);
288     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%sFine Vector %D", prefix ? prefix : NULL, k);CHKERRQ(ierr);
289     ierr = PetscObjectSetName((PetscObject) vf[k], name);CHKERRQ(ierr);
290     ierr = VecViewFromOptions(vf[k], NULL, "-dm_adapt_interp_view_fine");CHKERRQ(ierr);
291   }
292   ierr = PetscBLASIntCast(3*PetscMin(Nc, maxcols) + PetscMax(2*PetscMin(Nc, maxcols), PetscMax(Nc, maxcols)), &lwrk);CHKERRQ(ierr);
293   ierr = PetscMalloc7(Nc*maxcols, &A, PetscMax(Nc, maxcols), &b, Nc, &w, maxcols, &x, maxcols, &sing, lwrk, &workscalar, 5*PetscMin(Nc, maxcols), &workreal);CHKERRQ(ierr);
294   /* w_k = \frac{\HC{v_k} B_l v_k}{\HC{v_k} A_l v_k} or the inverse Rayleigh quotient, which we calculate using \frac{\HC{v_k} v_k}{\HC{v_k} B^{-1}_l A_l v_k} */
295   ierr = KSPGetOperators(smoother, &globalA, NULL);CHKERRQ(ierr);
296   ierr = DMGetGlobalVector(dmf, &tmp);CHKERRQ(ierr);
297   ierr = DMGetGlobalVector(dmf, &tmp2);CHKERRQ(ierr);
298   for (k = 0; k < Nc; ++k) {
299     PetscScalar vnorm, vAnorm;
300     PetscBool   canMult = PETSC_FALSE;
301     const char *type;
302 
303     w[k] = 1.0;
304     ierr = PetscObjectGetType((PetscObject) globalA, &type);CHKERRQ(ierr);
305     if (type) {ierr = MatAssembled(globalA, &canMult);CHKERRQ(ierr);}
306     if (type && canMult) {
307       ierr = VecDot(vf[k], vf[k], &vnorm);CHKERRQ(ierr);
308       ierr = MatMult(globalA, vf[k], tmp);CHKERRQ(ierr);
309 #if 0
310       ierr = KSPSolve(smoother, tmp, tmp2);CHKERRQ(ierr);
311       ierr = VecDot(vf[k], tmp2, &vAnorm);CHKERRQ(ierr);
312 #else
313       ierr = VecDot(vf[k], tmp, &vAnorm);CHKERRQ(ierr);
314 #endif
315       w[k] = PetscRealPart(vnorm) / PetscRealPart(vAnorm);
316     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "System matrix is not assembled.");
317   }
318   ierr = DMRestoreGlobalVector(dmf, &tmp);CHKERRQ(ierr);
319   ierr = DMRestoreGlobalVector(dmf, &tmp2);CHKERRQ(ierr);
320   if (!vc) {
321     allocVc = PETSC_TRUE;
322     ierr = PetscMalloc1(Nc, &vc);CHKERRQ(ierr);
323     for (k = 0; k < Nc; ++k) {
324       ierr = DMGetGlobalVector(dmc, &vc[k]);CHKERRQ(ierr);
325       ierr = MatMultTranspose(In, vf[k], vc[k]);CHKERRQ(ierr);
326     }
327   }
328   /* Solve a LS system for each fine row */
329   for (r = rStart; r < rEnd; ++r) {
330     PetscInt           ncols, c;
331     const PetscInt    *cols;
332     const PetscScalar *vals, *a;
333 
334     ierr = MatGetRow(In, r, &ncols, &cols, &vals);CHKERRQ(ierr);
335     for (k = 0; k < Nc; ++k) {
336       /* Need to fit lowest mode exactly */
337       const PetscReal wk = ((ncols == 1) && (k > 0)) ? 0.0 : PetscSqrtReal(w[k]);
338 
339       /* b_k = \sqrt{w_k} f^{F,k}_r */
340       ierr = VecGetArrayRead(vf[k], &a);CHKERRQ(ierr);
341       b[k] = wk * a[r-rStart];
342       ierr = VecRestoreArrayRead(vf[k], &a);CHKERRQ(ierr);
343       /* A_{kc} = \sqrt{w_k} f^{C,k}_c */
344       /* TODO Must pull out VecScatter from In, scatter in vc[k] values up front, and access them indirectly just as in MatMult() */
345       ierr = VecGetArrayRead(vc[k], &a);CHKERRQ(ierr);
346       for (c = 0; c < ncols; ++c) {
347         /* This is element (k, c) of A */
348         A[c*Nc+k] = wk * a[cols[c]-rStart];
349       }
350       ierr = VecRestoreArrayRead(vc[k], &a);CHKERRQ(ierr);
351     }
352     ierr = PetscBLASIntCast(Nc,    &M);CHKERRQ(ierr);
353     ierr = PetscBLASIntCast(ncols, &N);CHKERRQ(ierr);
354     if (debug) {
355 #if defined(PETSC_USE_COMPLEX)
356       PetscScalar *tmp;
357       PetscInt     j;
358 
359       ierr = DMGetWorkArray(dmc, Nc, MPIU_SCALAR, (void *) &tmp);CHKERRQ(ierr);
360       for (j = 0; j < Nc; ++j) tmp[j] = w[j];
361       ierr = DMPrintCellMatrix(r, "Interpolator Row LS weights", Nc, 1, tmp);CHKERRQ(ierr);
362       ierr = DMPrintCellMatrix(r, "Interpolator Row LS matrix", Nc, ncols, A);CHKERRQ(ierr);
363       for (j = 0; j < Nc; ++j) tmp[j] = b[j];
364       ierr = DMPrintCellMatrix(r, "Interpolator Row LS rhs", Nc, 1, tmp);CHKERRQ(ierr);
365       ierr = DMRestoreWorkArray(dmc, Nc, MPIU_SCALAR, (void *) &tmp);CHKERRQ(ierr);
366 #else
367       ierr = DMPrintCellMatrix(r, "Interpolator Row LS weights", Nc, 1, w);CHKERRQ(ierr);
368       ierr = DMPrintCellMatrix(r, "Interpolator Row LS matrix", Nc, ncols, A);CHKERRQ(ierr);
369       ierr = DMPrintCellMatrix(r, "Interpolator Row LS rhs", Nc, 1, b);CHKERRQ(ierr);
370 #endif
371     }
372 #if defined(PETSC_USE_COMPLEX)
373     /* ZGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, RWORK, INFO) */
374     PetscStackCallBLAS("LAPACKgelss",LAPACKgelss_(&M, &N, &one, A, &M, b, M > N ? &M : &N, sing, &rcond, &irank, workscalar, &lwrk, workreal, &info));
375 #else
376     /* DGELSS( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, INFO) */
377     PetscStackCallBLAS("LAPACKgelss",LAPACKgelss_(&M, &N, &one, A, &M, b, M > N ? &M : &N, sing, &rcond, &irank, workscalar, &lwrk, &info));
378 #endif
379     if (info < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Bad argument to GELSS");
380     if (info > 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SVD failed to converge");
381     if (debug) {
382       ierr = PetscPrintf(PETSC_COMM_SELF, "rank %d rcond %g\n", irank, (double) rcond);CHKERRQ(ierr);
383 #if defined(PETSC_USE_COMPLEX)
384       {
385         PetscScalar *tmp;
386         PetscInt     j;
387 
388         ierr = DMGetWorkArray(dmc, Nc, MPIU_SCALAR, (void *) &tmp);CHKERRQ(ierr);
389         for (j = 0; j < PetscMin(Nc, ncols); ++j) tmp[j] = sing[j];
390         ierr = DMPrintCellMatrix(r, "Interpolator Row LS singular values", PetscMin(Nc, ncols), 1, tmp);CHKERRQ(ierr);
391         ierr = DMRestoreWorkArray(dmc, Nc, MPIU_SCALAR, (void *) &tmp);CHKERRQ(ierr);
392       }
393 #else
394       ierr = DMPrintCellMatrix(r, "Interpolator Row LS singular values", PetscMin(Nc, ncols), 1, sing);CHKERRQ(ierr);
395 #endif
396       ierr = DMPrintCellMatrix(r, "Interpolator Row LS old P", ncols, 1, vals);CHKERRQ(ierr);
397       ierr = DMPrintCellMatrix(r, "Interpolator Row LS sol", ncols, 1, b);CHKERRQ(ierr);
398     }
399     ierr = MatSetValues(*InAdapt, 1, &r, ncols, cols, b, INSERT_VALUES);CHKERRQ(ierr);
400     ierr = MatRestoreRow(In, r, &ncols, &cols, &vals);CHKERRQ(ierr);
401   }
402   ierr = PetscFree7(A, b, w, x, sing, workscalar, workreal);CHKERRQ(ierr);
403   if (allocVc) {
404     for (k = 0; k < Nc; ++k) {ierr = DMRestoreGlobalVector(dmc, &vc[k]);CHKERRQ(ierr);}
405     ierr = PetscFree(vc);CHKERRQ(ierr);
406   }
407   ierr = MatAssemblyBegin(*InAdapt, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
408   ierr = MatAssemblyEnd(*InAdapt, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
409   ierr = PetscLogEventEnd(DM_AdaptInterpolator,dmc,dmf,0,0);CHKERRQ(ierr);
410   PetscFunctionReturn(0);
411 }
412 
DMCheckInterpolator(DM dmf,Mat In,PetscInt Nc,Vec vc[],Vec vf[],PetscReal tol)413 PetscErrorCode DMCheckInterpolator(DM dmf, Mat In, PetscInt Nc, Vec vc[], Vec vf[], PetscReal tol)
414 {
415   Vec            tmp;
416   PetscReal      norminf, norm2, maxnorminf = 0.0, maxnorm2 = 0.0;
417   PetscInt       k;
418   PetscErrorCode ierr;
419 
420   PetscFunctionBegin;
421   ierr = DMGetGlobalVector(dmf, &tmp);CHKERRQ(ierr);
422   ierr = MatViewFromOptions(In, NULL, "-dm_interpolator_adapt_error");CHKERRQ(ierr);
423   for (k = 0; k < Nc; ++k) {
424     ierr = MatMult(In, vc[k], tmp);CHKERRQ(ierr);
425     ierr = VecAXPY(tmp, -1.0, vf[k]);CHKERRQ(ierr);
426     ierr = VecViewFromOptions(vc[k], NULL, "-dm_interpolator_adapt_error");CHKERRQ(ierr);
427     ierr = VecViewFromOptions(vf[k], NULL, "-dm_interpolator_adapt_error");CHKERRQ(ierr);
428     ierr = VecViewFromOptions(tmp, NULL, "-dm_interpolator_adapt_error");CHKERRQ(ierr);
429     ierr = VecNorm(tmp, NORM_INFINITY, &norminf);CHKERRQ(ierr);
430     ierr = VecNorm(tmp, NORM_2, &norm2);CHKERRQ(ierr);
431     maxnorminf = PetscMax(maxnorminf, norminf);
432     maxnorm2   = PetscMax(maxnorm2,   norm2);
433     ierr = PetscPrintf(PetscObjectComm((PetscObject) dmf), "Coarse vec %D ||vf - P vc||_\\infty %g, ||vf - P vc||_2 %g\n", k, norminf, norm2);CHKERRQ(ierr);
434   }
435   ierr = DMRestoreGlobalVector(dmf, &tmp);CHKERRQ(ierr);
436   if (maxnorm2 > tol) SETERRQ2(PetscObjectComm((PetscObject) dmf), PETSC_ERR_ARG_WRONG, "max_k ||vf_k - P vc_k||_2 %g > tol %g", maxnorm2, tol);
437   PetscFunctionReturn(0);
438 }
439