xref: /petsc/src/tao/bound/tutorials/plate2f.F90 (revision a336c15037c72f93cd561f5a5e11e93175f2efd9)
1!  Program usage: mpiexec -n <proc> plate2f [all TAO options]
2!
3!  This example demonstrates use of the TAO package to solve a bound constrained
4!  minimization problem.  This example is based on a problem from the
5!  MINPACK-2 test suite.  Given a rectangular 2-D domain and boundary values
6!  along the edges of the domain, the objective is to find the surface
7!  with the minimal area that satisfies the boundary conditions.
8!  The command line options are:
9!    -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction
10!    -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction
11!    -bmx <bxg>, where <bxg> = number of grid points under plate in 1st direction
12!    -bmy <byg>, where <byg> = number of grid points under plate in 2nd direction
13!    -bheight <ht>, where <ht> = height of the plate
14!
15#include "petsc/finclude/petscdmda.h"
16#include "petsc/finclude/petsctao.h"
17module plate2fmodule
18  use petscdmda
19  use petsctao
20
21  implicit none
22  Vec localX, localV
23  Vec Top, Left
24  Vec Right, Bottom
25  DM dm
26  PetscReal bheight
27  PetscInt bmx, bmy
28! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29!                   Variable declarations
30! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31!
32!  Variables:
33!    (common from plate2f.h):
34!    Nx, Ny           number of processors in x- and y- directions
35!    mx, my           number of grid points in x,y directions
36!    N    global dimension of vector
37  PetscInt mx, my, Nx, Ny, N
38contains
39
40! ---------------------------------------------------------------------
41!
42!  FormFunctionGradient - Evaluates function f(X).
43!
44!  Input Parameters:
45!  tao   - the Tao context
46!  X     - the input vector
47!  dummy - optional user-defined context, as set by TaoSetFunction()
48!          (not used here)
49!
50!  Output Parameters:
51!  fcn     - the newly evaluated function
52!  G       - the gradient vector
53!  info  - error code
54!
55
56  subroutine FormFunctionGradient(ta, X, fcn, G, dummy, ierr)
57! Input/output variables
58
59    Tao ta
60    PetscReal fcn
61    Vec X, G
62    PetscErrorCode ierr
63    PetscInt dummy
64
65    PetscInt i, j, row
66    PetscInt xs, xm
67    PetscInt gxs, gxm
68    PetscInt ys, ym
69    PetscInt gys, gym
70    PetscReal ft, zero, hx, hy, hydhx, hxdhy
71    PetscReal area, rhx, rhy
72    PetscReal f1, f2, f3, f4, f5, f6, d1, d2, d3
73    PetscReal d4, d5, d6, d7, d8
74    PetscReal df1dxc, df2dxc, df3dxc, df4dxc
75    PetscReal df5dxc, df6dxc
76    PetscReal xc, xl, xr, xt, xb, xlt, xrb
77
78    PetscReal, pointer :: g_v(:), x_v(:)
79    PetscReal, pointer :: top_v(:), left_v(:)
80    PetscReal, pointer :: right_v(:), bottom_v(:)
81
82    ft = 0.0
83    zero = 0.0
84    hx = 1.0/real(mx + 1)
85    hy = 1.0/real(my + 1)
86    hydhx = hy/hx
87    hxdhy = hx/hy
88    area = 0.5*hx*hy
89    rhx = real(mx) + 1.0
90    rhy = real(my) + 1.0
91
92! Get local mesh boundaries
93    PetscCall(DMDAGetCorners(dm, xs, ys, PETSC_NULL_INTEGER, xm, ym, PETSC_NULL_INTEGER, ierr))
94    PetscCall(DMDAGetGhostCorners(dm, gxs, gys, PETSC_NULL_INTEGER, gxm, gym, PETSC_NULL_INTEGER, ierr))
95
96! Scatter ghost points to local vector
97    PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX, ierr))
98    PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX, ierr))
99
100! Initialize the vector to zero
101    PetscCall(VecSet(localV, zero, ierr))
102
103! Get arrays to vector data (See note above about using VecGetArray in Fortran)
104    PetscCall(VecGetArray(localX, x_v, ierr))
105    PetscCall(VecGetArray(localV, g_v, ierr))
106    PetscCall(VecGetArray(Top, top_v, ierr))
107    PetscCall(VecGetArray(Bottom, bottom_v, ierr))
108    PetscCall(VecGetArray(Left, left_v, ierr))
109    PetscCall(VecGetArray(Right, right_v, ierr))
110
111! Compute function over the locally owned part of the mesh
112    do j = ys, ys + ym - 1
113      do i = xs, xs + xm - 1
114        row = (j - gys)*gxm + (i - gxs)
115        xc = x_v(1 + row)
116        xt = xc
117        xb = xc
118        xr = xc
119        xl = xc
120        xrb = xc
121        xlt = xc
122
123        if (i == 0) then !left side
124          xl = left_v(1 + j - ys + 1)
125          xlt = left_v(1 + j - ys + 2)
126        else
127          xl = x_v(1 + row - 1)
128        end if
129
130        if (j == 0) then !bottom side
131          xb = bottom_v(1 + i - xs + 1)
132          xrb = bottom_v(1 + i - xs + 2)
133        else
134          xb = x_v(1 + row - gxm)
135        end if
136
137        if (i + 1 == gxs + gxm) then !right side
138          xr = right_v(1 + j - ys + 1)
139          xrb = right_v(1 + j - ys)
140        else
141          xr = x_v(1 + row + 1)
142        end if
143
144        if (j + 1 == gys + gym) then !top side
145          xt = top_v(1 + i - xs + 1)
146          xlt = top_v(1 + i - xs)
147        else
148          xt = x_v(1 + row + gxm)
149        end if
150
151        if ((i > gxs) .and. (j + 1 < gys + gym)) then
152          xlt = x_v(1 + row - 1 + gxm)
153        end if
154
155        if ((j > gys) .and. (i + 1 < gxs + gxm)) then
156          xrb = x_v(1 + row + 1 - gxm)
157        end if
158
159        d1 = xc - xl
160        d2 = xc - xr
161        d3 = xc - xt
162        d4 = xc - xb
163        d5 = xr - xrb
164        d6 = xrb - xb
165        d7 = xlt - xl
166        d8 = xt - xlt
167
168        df1dxc = d1*hydhx
169        df2dxc = d1*hydhx + d4*hxdhy
170        df3dxc = d3*hxdhy
171        df4dxc = d2*hydhx + d3*hxdhy
172        df5dxc = d2*hydhx
173        df6dxc = d4*hxdhy
174
175        d1 = d1*rhx
176        d2 = d2*rhx
177        d3 = d3*rhy
178        d4 = d4*rhy
179        d5 = d5*rhy
180        d6 = d6*rhx
181        d7 = d7*rhy
182        d8 = d8*rhx
183
184        f1 = sqrt(1.0 + d1*d1 + d7*d7)
185        f2 = sqrt(1.0 + d1*d1 + d4*d4)
186        f3 = sqrt(1.0 + d3*d3 + d8*d8)
187        f4 = sqrt(1.0 + d3*d3 + d2*d2)
188        f5 = sqrt(1.0 + d2*d2 + d5*d5)
189        f6 = sqrt(1.0 + d4*d4 + d6*d6)
190
191        ft = ft + f2 + f4
192
193        df1dxc = df1dxc/f1
194        df2dxc = df2dxc/f2
195        df3dxc = df3dxc/f3
196        df4dxc = df4dxc/f4
197        df5dxc = df5dxc/f5
198        df6dxc = df6dxc/f6
199
200        g_v(1 + row) = 0.5*(df1dxc + df2dxc + df3dxc + df4dxc + df5dxc + df6dxc)
201      end do
202    end do
203
204! Compute triangular areas along the border of the domain.
205    if (xs == 0) then  ! left side
206      do j = ys, ys + ym - 1
207        d3 = (left_v(1 + j - ys + 1) - left_v(1 + j - ys + 2))*rhy
208        d2 = (left_v(1 + j - ys + 1) - x_v(1 + (j - gys)*gxm))*rhx
209        ft = ft + sqrt(1.0 + d3*d3 + d2*d2)
210      end do
211    end if
212
213    if (ys == 0) then !bottom side
214      do i = xs, xs + xm - 1
215        d2 = (bottom_v(1 + i + 1 - xs) - bottom_v(1 + i - xs + 2))*rhx
216        d3 = (bottom_v(1 + i - xs + 1) - x_v(1 + i - gxs))*rhy
217        ft = ft + sqrt(1.0 + d3*d3 + d2*d2)
218      end do
219    end if
220
221    if (xs + xm == mx) then ! right side
222      do j = ys, ys + ym - 1
223        d1 = (x_v(1 + (j + 1 - gys)*gxm - 1) - right_v(1 + j - ys + 1))*rhx
224        d4 = (right_v(1 + j - ys) - right_v(1 + j - ys + 1))*rhy
225        ft = ft + sqrt(1.0 + d1*d1 + d4*d4)
226      end do
227    end if
228
229    if (ys + ym == my) then
230      do i = xs, xs + xm - 1
231        d1 = (x_v(1 + (gym - 1)*gxm + i - gxs) - top_v(1 + i - xs + 1))*rhy
232        d4 = (top_v(1 + i - xs + 1) - top_v(1 + i - xs))*rhx
233        ft = ft + sqrt(1.0 + d1*d1 + d4*d4)
234      end do
235    end if
236
237    if ((ys == 0) .and. (xs == 0)) then
238      d1 = (left_v(1 + 0) - left_v(1 + 1))*rhy
239      d2 = (bottom_v(1 + 0) - bottom_v(1 + 1))*rhx
240      ft = ft + sqrt(1.0 + d1*d1 + d2*d2)
241    end if
242
243    if ((ys + ym == my) .and. (xs + xm == mx)) then
244      d1 = (right_v(1 + ym + 1) - right_v(1 + ym))*rhy
245      d2 = (top_v(1 + xm + 1) - top_v(1 + xm))*rhx
246      ft = ft + sqrt(1.0 + d1*d1 + d2*d2)
247    end if
248
249    ft = ft*area
250    PetscCallMPI(MPI_Allreduce(ft, fcn, 1, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD, ierr))
251
252! Restore vectors
253    PetscCall(VecRestoreArray(localX, x_v, ierr))
254    PetscCall(VecRestoreArray(localV, g_v, ierr))
255    PetscCall(VecRestoreArray(Left, left_v, ierr))
256    PetscCall(VecRestoreArray(Top, top_v, ierr))
257    PetscCall(VecRestoreArray(Bottom, bottom_v, ierr))
258    PetscCall(VecRestoreArray(Right, right_v, ierr))
259
260! Scatter values to global vector
261    PetscCall(DMLocalToGlobalBegin(dm, localV, INSERT_VALUES, G, ierr))
262    PetscCall(DMLocalToGlobalEnd(dm, localV, INSERT_VALUES, G, ierr))
263
264    PetscCall(PetscLogFlops(70.0d0*xm*ym, ierr))
265
266  end  !FormFunctionGradient
267
268! ----------------------------------------------------------------------------
269!
270!
271!   FormHessian - Evaluates Hessian matrix.
272!
273!   Input Parameters:
274!.  tao  - the Tao context
275!.  X    - input vector
276!.  dummy  - not used
277!
278!   Output Parameters:
279!.  Hessian    - Hessian matrix
280!.  Hpc    - optionally different matrix used to construct the preconditioner
281!
282!   Notes:
283!   Due to mesh point reordering with DMs, we must always work
284!   with the local mesh points, and then transform them to the new
285!   global numbering with the local-to-global mapping.  We cannot work
286!   directly with the global numbers for the original uniprocessor mesh!
287!
288!      MatSetValuesLocal(), using the local ordering (including
289!         ghost points!)
290!         - Then set matrix entries using the local ordering
291!           by calling MatSetValuesLocal()
292
293  subroutine FormHessian(ta, X, Hessian, Hpc, dummy, ierr)
294
295    Tao ta
296    Vec X
297    Mat Hessian, Hpc
298    PetscInt dummy
299    PetscErrorCode ierr
300
301    PetscInt i, j, k, row
302    PetscInt xs, xm, gxs, gxm
303    PetscInt ys, ym, gys, gym
304    PetscInt col(0:6)
305    PetscReal hx, hy, hydhx, hxdhy, rhx, rhy
306    PetscReal f1, f2, f3, f4, f5, f6, d1, d2, d3
307    PetscReal d4, d5, d6, d7, d8
308    PetscReal xc, xl, xr, xt, xb, xlt, xrb
309    PetscReal hl, hr, ht, hb, hc, htl, hbr
310
311    PetscReal, pointer ::  right_v(:), left_v(:)
312    PetscReal, pointer ::  bottom_v(:), top_v(:)
313    PetscReal, pointer ::  x_v(:)
314    PetscReal v(0:6)
315    PetscBool assembled
316    PetscInt i1
317
318    i1 = 1
319
320! Set various matrix options
321    PetscCall(MatSetOption(Hessian, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE, ierr))
322
323! Get local mesh boundaries
324    PetscCall(DMDAGetCorners(dm, xs, ys, PETSC_NULL_INTEGER, xm, ym, PETSC_NULL_INTEGER, ierr))
325    PetscCall(DMDAGetGhostCorners(dm, gxs, gys, PETSC_NULL_INTEGER, gxm, gym, PETSC_NULL_INTEGER, ierr))
326
327! Scatter ghost points to local vectors
328    PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX, ierr))
329    PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX, ierr))
330
331! Get pointers to vector data (see note on Fortran arrays above)
332    PetscCall(VecGetArray(localX, x_v, ierr))
333    PetscCall(VecGetArray(Top, top_v, ierr))
334    PetscCall(VecGetArray(Bottom, bottom_v, ierr))
335    PetscCall(VecGetArray(Left, left_v, ierr))
336    PetscCall(VecGetArray(Right, right_v, ierr))
337
338! Initialize matrix entries to zero
339    PetscCall(MatAssembled(Hessian, assembled, ierr))
340    if (assembled .eqv. PETSC_TRUE) PetscCall(MatZeroEntries(Hessian, ierr))
341
342    rhx = real(mx) + 1.0
343    rhy = real(my) + 1.0
344    hx = 1.0/rhx
345    hy = 1.0/rhy
346    hydhx = hy/hx
347    hxdhy = hx/hy
348! compute Hessian over the locally owned part of the mesh
349
350    do i = xs, xs + xm - 1
351      do j = ys, ys + ym - 1
352        row = (j - gys)*gxm + (i - gxs)
353
354        xc = x_v(1 + row)
355        xt = xc
356        xb = xc
357        xr = xc
358        xl = xc
359        xrb = xc
360        xlt = xc
361
362        if (i == gxs) then   ! Left side
363          xl = left_v(1 + j - ys + 1)
364          xlt = left_v(1 + j - ys + 2)
365        else
366          xl = x_v(1 + row - 1)
367        end if
368
369        if (j == gys) then ! bottom side
370          xb = bottom_v(1 + i - xs + 1)
371          xrb = bottom_v(1 + i - xs + 2)
372        else
373          xb = x_v(1 + row - gxm)
374        end if
375
376        if (i + 1 == gxs + gxm) then !right side
377          xr = right_v(1 + j - ys + 1)
378          xrb = right_v(1 + j - ys)
379        else
380          xr = x_v(1 + row + 1)
381        end if
382
383        if (j + 1 == gym + gys) then !top side
384          xt = top_v(1 + i - xs + 1)
385          xlt = top_v(1 + i - xs)
386        else
387          xt = x_v(1 + row + gxm)
388        end if
389
390        if ((i > gxs) .and. (j + 1 < gys + gym)) then
391          xlt = x_v(1 + row - 1 + gxm)
392        end if
393
394        if ((i + 1 < gxs + gxm) .and. (j > gys)) then
395          xrb = x_v(1 + row + 1 - gxm)
396        end if
397
398        d1 = (xc - xl)*rhx
399        d2 = (xc - xr)*rhx
400        d3 = (xc - xt)*rhy
401        d4 = (xc - xb)*rhy
402        d5 = (xrb - xr)*rhy
403        d6 = (xrb - xb)*rhx
404        d7 = (xlt - xl)*rhy
405        d8 = (xlt - xt)*rhx
406
407        f1 = sqrt(1.0 + d1*d1 + d7*d7)
408        f2 = sqrt(1.0 + d1*d1 + d4*d4)
409        f3 = sqrt(1.0 + d3*d3 + d8*d8)
410        f4 = sqrt(1.0 + d3*d3 + d2*d2)
411        f5 = sqrt(1.0 + d2*d2 + d5*d5)
412        f6 = sqrt(1.0 + d4*d4 + d6*d6)
413
414        hl = (-hydhx*(1.0 + d7*d7) + d1*d7)/(f1*f1*f1) + (-hydhx*(1.0 + d4*d4) + d1*d4)/(f2*f2*f2)
415
416        hr = (-hydhx*(1.0 + d5*d5) + d2*d5)/(f5*f5*f5) + (-hydhx*(1.0 + d3*d3) + d2*d3)/(f4*f4*f4)
417
418        ht = (-hxdhy*(1.0 + d8*d8) + d3*d8)/(f3*f3*f3) + (-hxdhy*(1.0 + d2*d2) + d2*d3)/(f4*f4*f4)
419
420        hb = (-hxdhy*(1.0 + d6*d6) + d4*d6)/(f6*f6*f6) + (-hxdhy*(1.0 + d1*d1) + d1*d4)/(f2*f2*f2)
421
422        hbr = -d2*d5/(f5*f5*f5) - d4*d6/(f6*f6*f6)
423        htl = -d1*d7/(f1*f1*f1) - d3*d8/(f3*f3*f3)
424
425        hc = hydhx*(1.0 + d7*d7)/(f1*f1*f1) + hxdhy*(1.0 + d8*d8)/(f3*f3*f3) + hydhx*(1.0 + d5*d5)/(f5*f5*f5) +                      &
426  &           hxdhy*(1.0 + d6*d6)/(f6*f6*f6) + (hxdhy*(1.0 + d1*d1) + hydhx*(1.0 + d4*d4) - 2*d1*d4)/(f2*f2*f2) + (hxdhy*(1.0 + d2*d2) +   &
427  &           hydhx*(1.0 + d3*d3) - 2*d2*d3)/(f4*f4*f4)
428
429        hl = hl*0.5
430        hr = hr*0.5
431        ht = ht*0.5
432        hb = hb*0.5
433        hbr = hbr*0.5
434        htl = htl*0.5
435        hc = hc*0.5
436
437        k = 0
438
439        if (j > 0) then
440          v(k) = hb
441          col(k) = row - gxm
442          k = k + 1
443        end if
444
445        if ((j > 0) .and. (i < mx - 1)) then
446          v(k) = hbr
447          col(k) = row - gxm + 1
448          k = k + 1
449        end if
450
451        if (i > 0) then
452          v(k) = hl
453          col(k) = row - 1
454          k = k + 1
455        end if
456
457        v(k) = hc
458        col(k) = row
459        k = k + 1
460
461        if (i < mx - 1) then
462          v(k) = hr
463          col(k) = row + 1
464          k = k + 1
465        end if
466
467        if ((i > 0) .and. (j < my - 1)) then
468          v(k) = htl
469          col(k) = row + gxm - 1
470          k = k + 1
471        end if
472
473        if (j < my - 1) then
474          v(k) = ht
475          col(k) = row + gxm
476          k = k + 1
477        end if
478
479! Set matrix values using local numbering, defined earlier in main routine
480        PetscCall(MatSetValuesLocal(Hessian, i1, [row], k, col, v, INSERT_VALUES, ierr))
481
482      end do
483    end do
484
485! restore vectors
486    PetscCall(VecRestoreArray(localX, x_v, ierr))
487    PetscCall(VecRestoreArray(Left, left_v, ierr))
488    PetscCall(VecRestoreArray(Right, right_v, ierr))
489    PetscCall(VecRestoreArray(Top, top_v, ierr))
490    PetscCall(VecRestoreArray(Bottom, bottom_v, ierr))
491
492! Assemble the matrix
493    PetscCall(MatAssemblyBegin(Hessian, MAT_FINAL_ASSEMBLY, ierr))
494    PetscCall(MatAssemblyEnd(Hessian, MAT_FINAL_ASSEMBLY, ierr))
495
496    PetscCall(PetscLogFlops(199.0d0*xm*ym, ierr))
497
498  end
499
500! Top,Left,Right,Bottom,bheight,mx,my,bmx,bmy,H, defined in plate2f.h
501
502! ----------------------------------------------------------------------------
503!
504!/*
505!     MSA_BoundaryConditions - calculates the boundary conditions for the region
506!
507!
508!*/
509
510  subroutine MSA_BoundaryConditions(ierr)
511
512    PetscErrorCode ierr
513    PetscInt i, j, k, limit, maxits
514    PetscInt xs, xm, gxs, gxm
515    PetscInt ys, ym, gys, gym
516    PetscInt bsize, lsize
517    PetscInt tsize, rsize
518    PetscReal one, two, three, tol
519    PetscReal scl, fnorm, det, xt
520    PetscReal yt, hx, hy, u1, u2, nf1, nf2
521    PetscReal njac11, njac12, njac21, njac22
522    PetscReal b, t, l, r
523    PetscReal, pointer :: boundary_v(:)
524
525    logical exitloop
526    PetscBool flg
527
528    limit = 0
529    maxits = 5
530    tol = 1e-10
531    b = -0.5
532    t = 0.5
533    l = -0.5
534    r = 0.5
535    xt = 0
536    yt = 0
537    one = 1.0
538    two = 2.0
539    three = 3.0
540
541    PetscCall(DMDAGetCorners(dm, xs, ys, PETSC_NULL_INTEGER, xm, ym, PETSC_NULL_INTEGER, ierr))
542    PetscCall(DMDAGetGhostCorners(dm, gxs, gys, PETSC_NULL_INTEGER, gxm, gym, PETSC_NULL_INTEGER, ierr))
543
544    bsize = xm + 2
545    lsize = ym + 2
546    rsize = ym + 2
547    tsize = xm + 2
548
549    PetscCall(VecCreateMPI(PETSC_COMM_WORLD, bsize, PETSC_DECIDE, Bottom, ierr))
550    PetscCall(VecCreateMPI(PETSC_COMM_WORLD, tsize, PETSC_DECIDE, Top, ierr))
551    PetscCall(VecCreateMPI(PETSC_COMM_WORLD, lsize, PETSC_DECIDE, Left, ierr))
552    PetscCall(VecCreateMPI(PETSC_COMM_WORLD, rsize, PETSC_DECIDE, Right, ierr))
553
554    hx = (r - l)/(mx + 1)
555    hy = (t - b)/(my + 1)
556
557    do j = 0, 3
558
559      if (j == 0) then
560        yt = b
561        xt = l + hx*xs
562        limit = bsize
563        PetscCall(VecGetArray(Bottom, boundary_v, ierr))
564
565      elseif (j == 1) then
566        yt = t
567        xt = l + hx*xs
568        limit = tsize
569        PetscCall(VecGetArray(Top, boundary_v, ierr))
570
571      elseif (j == 2) then
572        yt = b + hy*ys
573        xt = l
574        limit = lsize
575        PetscCall(VecGetArray(Left, boundary_v, ierr))
576
577      elseif (j == 3) then
578        yt = b + hy*ys
579        xt = r
580        limit = rsize
581        PetscCall(VecGetArray(Right, boundary_v, ierr))
582      end if
583
584      do i = 0, limit - 1
585
586        u1 = xt
587        u2 = -yt
588        k = 0
589        exitloop = .false.
590        do while (k < maxits .and. (.not. exitloop))
591
592          nf1 = u1 + u1*u2*u2 - u1*u1*u1/three - xt
593          nf2 = -u2 - u1*u1*u2 + u2*u2*u2/three - yt
594          fnorm = sqrt(nf1*nf1 + nf2*nf2)
595          if (fnorm > tol) then
596            njac11 = one + u2*u2 - u1*u1
597            njac12 = two*u1*u2
598            njac21 = -two*u1*u2
599            njac22 = -one - u1*u1 + u2*u2
600            det = njac11*njac22 - njac21*njac12
601            u1 = u1 - (njac22*nf1 - njac12*nf2)/det
602            u2 = u2 - (njac11*nf2 - njac21*nf1)/det
603          else
604            exitloop = .true.
605          end if
606          k = k + 1
607        end do
608
609        boundary_v(1 + i) = u1*u1 - u2*u2
610        if ((j == 0) .or. (j == 1)) then
611          xt = xt + hx
612        else
613          yt = yt + hy
614        end if
615
616      end do
617
618      if (j == 0) then
619        PetscCall(VecRestoreArray(Bottom, boundary_v, ierr))
620      elseif (j == 1) then
621        PetscCall(VecRestoreArray(Top, boundary_v, ierr))
622      elseif (j == 2) then
623        PetscCall(VecRestoreArray(Left, boundary_v, ierr))
624      elseif (j == 3) then
625        PetscCall(VecRestoreArray(Right, boundary_v, ierr))
626      end if
627
628    end do
629
630! Scale the boundary if desired
631    PetscCall(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-bottom', scl, flg, ierr))
632    if (flg .eqv. PETSC_TRUE) then
633      PetscCall(VecScale(Bottom, scl, ierr))
634    end if
635
636    PetscCall(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-top', scl, flg, ierr))
637    if (flg .eqv. PETSC_TRUE) then
638      PetscCall(VecScale(Top, scl, ierr))
639    end if
640
641    PetscCall(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-right', scl, flg, ierr))
642    if (flg .eqv. PETSC_TRUE) then
643      PetscCall(VecScale(Right, scl, ierr))
644    end if
645
646    PetscCall(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-left', scl, flg, ierr))
647    if (flg .eqv. PETSC_TRUE) then
648      PetscCall(VecScale(Left, scl, ierr))
649    end if
650
651  end
652
653! ----------------------------------------------------------------------------
654!
655!/*
656!     MSA_Plate - Calculates an obstacle for surface to stretch over
657!
658!     Output Parameter:
659!.    xl - lower bound vector
660!.    xu - upper bound vector
661!
662!*/
663
664  subroutine MSA_Plate(ta, xl, xu, dummy, ierr)
665
666    Tao ta
667    Vec xl, xu
668    PetscErrorCode ierr
669    PetscInt i, j, row
670    PetscInt xs, xm, ys, ym
671    PetscReal lb, ub
672    PetscInt dummy
673    PetscReal, pointer :: xl_v(:)
674
675    lb = PETSC_NINFINITY
676    ub = PETSC_INFINITY
677
678    if (bmy < 0) bmy = 0
679    if (bmy > my) bmy = my
680    if (bmx < 0) bmx = 0
681    if (bmx > mx) bmx = mx
682
683    PetscCall(DMDAGetCorners(dm, xs, ys, PETSC_NULL_INTEGER, xm, ym, PETSC_NULL_INTEGER, ierr))
684
685    PetscCall(VecSet(xl, lb, ierr))
686    PetscCall(VecSet(xu, ub, ierr))
687
688    PetscCall(VecGetArray(xl, xl_v, ierr))
689
690    do i = xs, xs + xm - 1
691
692      do j = ys, ys + ym - 1
693
694        row = (j - ys)*xm + (i - xs)
695
696        if (i >= ((mx - bmx)/2) .and. i < (mx - (mx - bmx)/2) .and.           &
697  &          j >= ((my - bmy)/2) .and. j < (my - (my - bmy)/2)) then
698          xl_v(1 + row) = bheight
699
700        end if
701
702      end do
703    end do
704
705    PetscCall(VecRestoreArray(xl, xl_v, ierr))
706
707  end
708
709! ----------------------------------------------------------------------------
710!
711!/*
712!     MSA_InitialPoint - Calculates an obstacle for surface to stretch over
713!
714!     Output Parameter:
715!.    X - vector for initial guess
716!
717!*/
718
719  subroutine MSA_InitialPoint(X, ierr)
720
721    Vec X
722    PetscErrorCode ierr
723    PetscInt start, i, j
724    PetscInt row
725    PetscInt xs, xm, gxs, gxm
726    PetscInt ys, ym, gys, gym
727    PetscReal zero, np5
728
729    PetscReal, pointer :: left_v(:), right_v(:)
730    PetscReal, pointer :: bottom_v(:), top_v(:)
731    PetscReal, pointer :: x_v(:)
732    PetscBool flg
733    PetscRandom rctx
734
735    zero = 0.0
736    np5 = -0.5
737
738    PetscCall(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-start', start, flg, ierr))
739
740    if ((flg .eqv. PETSC_TRUE) .and. (start == 0)) then  ! the zero vector is reasonable
741      PetscCall(VecSet(X, zero, ierr))
742
743    elseif ((flg .eqv. PETSC_TRUE) .and. (start > 0)) then  ! random start -0.5 < xi < 0.5
744      PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, rctx, ierr))
745      do i = 0, start - 1
746        PetscCall(VecSetRandom(X, rctx, ierr))
747      end do
748
749      PetscCall(PetscRandomDestroy(rctx, ierr))
750      PetscCall(VecShift(X, np5, ierr))
751
752    else   ! average of boundary conditions
753
754!        Get Local mesh boundaries
755      PetscCall(DMDAGetCorners(dm, xs, ys, PETSC_NULL_INTEGER, xm, ym, PETSC_NULL_INTEGER, ierr))
756      PetscCall(DMDAGetGhostCorners(dm, gxs, gys, PETSC_NULL_INTEGER, gxm, gym, PETSC_NULL_INTEGER, ierr))
757
758!        Get pointers to vector data
759      PetscCall(VecGetArray(Top, top_v, ierr))
760      PetscCall(VecGetArray(Bottom, bottom_v, ierr))
761      PetscCall(VecGetArray(Left, left_v, ierr))
762      PetscCall(VecGetArray(Right, right_v, ierr))
763
764      PetscCall(VecGetArray(localX, x_v, ierr))
765
766!        Perform local computations
767      do j = ys, ys + ym - 1
768        do i = xs, xs + xm - 1
769          row = (j - gys)*gxm + (i - gxs)
770          x_v(1 + row) = ((j + 1)*bottom_v(1 + i - xs + 1)/my + (my - j + 1)*top_v(1 + i - xs + 1)/(my + 2) +                  &
771  &                          (i + 1)*left_v(1 + j - ys + 1)/mx + (mx - i + 1)*right_v(1 + j - ys + 1)/(mx + 2))*0.5
772        end do
773      end do
774
775!        Restore vectors
776      PetscCall(VecRestoreArray(localX, x_v, ierr))
777
778      PetscCall(VecRestoreArray(Left, left_v, ierr))
779      PetscCall(VecRestoreArray(Top, top_v, ierr))
780      PetscCall(VecRestoreArray(Bottom, bottom_v, ierr))
781      PetscCall(VecRestoreArray(Right, right_v, ierr))
782
783      PetscCall(DMLocalToGlobalBegin(dm, localX, INSERT_VALUES, X, ierr))
784      PetscCall(DMLocalToGlobalEnd(dm, localX, INSERT_VALUES, X, ierr))
785
786    end if
787
788  end
789
790end module
791
792program plate2f
793  use plate2fmodule
794  implicit none
795
796  PetscErrorCode ierr          ! used to check for functions returning nonzeros
797  Vec x             ! solution vector
798  PetscInt m             ! number of local elements in vector
799  Tao ta           ! Tao solver context
800  Mat H             ! Hessian matrix
801  ISLocalToGlobalMapping isltog  ! local to global mapping object
802  PetscBool flg
803  PetscInt i1, i3, i7
804
805! Initialize Tao
806
807  i1 = 1
808  i3 = 3
809  i7 = 7
810
811  PetscCallA(PetscInitialize(ierr))
812
813! Specify default dimensions of the problem
814  mx = 10
815  my = 10
816  bheight = 0.1
817
818! Check for any command line arguments that override defaults
819
820  PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-mx', mx, flg, ierr))
821  PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-my', my, flg, ierr))
822
823  bmx = mx/2
824  bmy = my/2
825
826  PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-bmx', bmx, flg, ierr))
827  PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-bmy', bmy, flg, ierr))
828  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-bheight', bheight, flg, ierr))
829
830! Calculate any derived values from parameters
831  N = mx*my
832
833! Let PETSc determine the dimensions of the local vectors
834  Nx = PETSC_DECIDE
835  NY = PETSC_DECIDE
836
837! A two dimensional distributed array will help define this problem, which
838! derives from an elliptic PDE on a two-dimensional domain.  From the
839! distributed array, create the vectors
840
841  PetscCallA(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, mx, my, Nx, Ny, i1, i1, PETSC_NULL_INTEGER_ARRAY, PETSC_NULL_INTEGER_ARRAY, dm, ierr))
842  PetscCallA(DMSetFromOptions(dm, ierr))
843  PetscCallA(DMSetUp(dm, ierr))
844
845! Extract global and local vectors from DM; The local vectors are
846! used solely as work space for the evaluation of the function,
847! gradient, and Hessian.  Duplicate for remaining vectors that are
848! the same types.
849
850  PetscCallA(DMCreateGlobalVector(dm, x, ierr))
851  PetscCallA(DMCreateLocalVector(dm, localX, ierr))
852  PetscCallA(VecDuplicate(localX, localV, ierr))
853
854! Create a matrix data structure to store the Hessian.
855! Here we (optionally) also associate the local numbering scheme
856! with the matrix so that later we can use local indices for matrix
857! assembly
858
859  PetscCallA(VecGetLocalSize(x, m, ierr))
860  PetscCallA(MatCreateAIJ(PETSC_COMM_WORLD, m, m, N, N, i7, PETSC_NULL_INTEGER_ARRAY, i3, PETSC_NULL_INTEGER_ARRAY, H, ierr))
861
862  PetscCallA(MatSetOption(H, MAT_SYMMETRIC, PETSC_TRUE, ierr))
863  PetscCallA(DMGetLocalToGlobalMapping(dm, isltog, ierr))
864  PetscCallA(MatSetLocalToGlobalMapping(H, isltog, isltog, ierr))
865
866! The Tao code begins here
867! Create TAO solver and set desired solution method.
868! This problems uses bounded variables, so the
869! method must either be 'tao_tron' or 'tao_blmvm'
870
871  PetscCallA(TaoCreate(PETSC_COMM_WORLD, ta, ierr))
872  PetscCallA(TaoSetType(ta, TAOBLMVM, ierr))
873
874!     Set minimization function and gradient, hessian evaluation functions
875
876  PetscCallA(TaoSetObjectiveAndGradient(ta, PETSC_NULL_VEC, FormFunctionGradient, 0, ierr))
877
878  PetscCallA(TaoSetHessian(ta, H, H, FormHessian, 0, ierr))
879
880! Set Variable bounds
881  PetscCallA(MSA_BoundaryConditions(ierr))
882  PetscCallA(TaoSetVariableBoundsRoutine(ta, MSA_Plate, 0, ierr))
883
884! Set the initial solution guess
885  PetscCallA(MSA_InitialPoint(x, ierr))
886  PetscCallA(TaoSetSolution(ta, x, ierr))
887
888! Check for any tao command line options
889  PetscCallA(TaoSetFromOptions(ta, ierr))
890
891! Solve the application
892  PetscCallA(TaoSolve(ta, ierr))
893
894! Free TAO data structures
895  PetscCallA(TaoDestroy(ta, ierr))
896
897! Free PETSc data structures
898  PetscCallA(VecDestroy(x, ierr))
899  PetscCallA(VecDestroy(Top, ierr))
900  PetscCallA(VecDestroy(Bottom, ierr))
901  PetscCallA(VecDestroy(Left, ierr))
902  PetscCallA(VecDestroy(Right, ierr))
903  PetscCallA(MatDestroy(H, ierr))
904  PetscCallA(VecDestroy(localX, ierr))
905  PetscCallA(VecDestroy(localV, ierr))
906  PetscCallA(DMDestroy(dm, ierr))
907
908! Finalize TAO
909
910  PetscCallA(PetscFinalize(ierr))
911
912end program plate2f
913!
914!/*TEST
915!
916!   build:
917!      requires: !complex
918!
919!   test:
920!      args: -tao_monitor_short -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bqnls -tao_gatol 1.e-4
921!      filter: sort -b
922!      filter_output: sort -b
923!      requires: !single
924!
925!   test:
926!      suffix: 2
927!      nsize: 2
928!      args: -tao_monitor_short -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bqnls -tao_gatol 1.e-4
929!      filter: sort -b
930!      filter_output: sort -b
931!      requires: !single
932!
933!TEST*/
934