Dear all,
I am using TS to solve the PDE
u_t + c * u_c = eps * u_xx in 1D i.e. smthg. similar to
https://urldefense.us/v3/__https://petsc.org/release/src/ts/tutorials/ex4.c.html__;!!G_uCfscf7eWS!eeErx_FNg50N1eRlD9eyfoEp8I0llTQmVFpPWoz5_LQhL8K6uOId5zbgle0ghE71NJmon8T_vwwfN3LnEbf4cTUXtlkWJRflikU$
except that I am using DMPlex, instead of a structured grid.
Since the problem is linear, I tried smthg. like:
PetscCall(RHSMatrixHeat(ts,0.0,u,A,A,&appctx));
PetscCall(TSSetRHSFunction(ts,NULL,TSComputeRHSFunctionLinear,&appctx));
PetscCall(TSSetRHSJacobian(ts,A,A,TSComputeRHSJacobianConstant,&appctx));
My problem is that the A matrix (as well as the global vector) is
missing the rows/cols corresponding to the endpoints where Dirichlet
boundary conditions are prescribed;
A global vector is missing both the shared dofs which are not owned by
this process, as well as /constrained/ dofs. These constraints
represent essential (Dirichlet) boundary conditions. They are dofs
that have a given fixed value, so they are present in local vectors
for assembly purposes, but absent from global vectors since they are
never solved for during algebraic solves.
therefore, A*u = f(u) except in the two vertices adjacent to the
endpoints, i.e. first and last entries of the global vector.
The code is attached; when the flag -use_jacobian is set, f(u) is
computed as A*u, if it is not set, f(u) is computed in FormRHSFunction.
The latter approach works, the former does not.
Regards,
Aldo
--
Dr. Aldo Bonfiglioli
Associate professor of Fluid Machines
Scuola di Ingegneria
Universita' della Basilicata
V.le dell'Ateneo lucano, 10 85100 Potenza ITALY
tel:+39.0971.205203 fax:+39.0971.205215
web:https://urldefense.us/v3/__http://docenti.unibas.it/site/home/docente.html?m=002423__;!!G_uCfscf7eWS!eeErx_FNg50N1eRlD9eyfoEp8I0llTQmVFpPWoz5_LQhL8K6uOId5zbgle0ghE71NJmon8T_vwwfN3LnEbf4cTUXtlkWzhmq6Yg$
program main
! solve the PDE: u_t + c * u_x = eps * u_xx on a 1D plex
! using TS
!
! if L = 1 is the length of the box, Pe = c*L/eps
!
!
! good references are:
!
! https://petsc.org/release/src/ts/tutorials/ex4.c.html
! and
! https://petsc.org/main/src/ts/tutorials/ex17.c.html
!
! run with:
! ./ex15f90 -dm_plex_dim 1 -dm_plex_shape box -dm_plex_box_faces 30 -dm_plex_simplex true -dm_plex_interpolate -dm_plex_check_all -dm_petscsection_view
! -ts_max_steps 500 -options_left -Peclet xxxx
!
! if the option -Peclet is omitted, then solves u_tt = u_xx
! if the option -use_jacobian is used, compute f(u) as A*u
!
! Author: aldo.bonfigli...@unibas.it
!
#include <petsc/finclude/petsc.h>
use petsc
implicit none
DM :: dm
TS :: ts
Vec :: u,y,rhs
Mat :: jac,Pmat
PetscBool :: lflag
external FormRHSFunction,dtFunction,MyOwnTSMonitoringRoutine,TSSetRHSJacobian
PetscErrorCode :: ierr
PetscReal:: user(5)
PetscReal:: dt
PetscReal:: Peclet,rnorm_2,rnorm_max,s
PetscInt:: nitems
character(len=PETSC_MAX_PATH_LEN) :: IOBuffer
PetscViewer :: viewer
logical, parameter :: verbose = .FALSE.
PetscCallA(PetscInitialize(ierr))
!
! Make the mesh (the mesh length is returned in user(3))
!
call Createmesh(dm,user(3))
!
PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER , "-Peclet", Peclet, lflag, ierr))
!
IF(.NOT.lflag)then
Peclet = 0.d0
user(1) = 1.d0 ! diffusion coefficient
user(2) = 0.d0 ! convective speed
else
user(2) = 1.d0 ! convective speed
user(1) = user(2) * user(3) / Peclet ! diffusion coefficient
endif
write(IOBuffer,FMT=*)"\n Peclet number is: ",Peclet,"\n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
write(IOBuffer,FMT=*)"\n diffusion coefficient is: ",user(1),"\n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
!
! Is the following call really needed ?!?!?!
!
PetscCallA(DMPlexCreateClosureIndex(dm, PETSC_NULL_SECTION, ierr))
!
! Attach a section to the DM
!
! call SetupSection(dm)
call CreateSectionAlternate(dm)
!
! u is the vector where the solution is stored
!
PetscCallA(DMCreateGlobalVector(dm, u, ierr))
!
! A global vector is missing both the shared dofs which are not owned by this process, as well as constrained dofs.
!
PetscCallA(VecSet(u,0.d0,ierr))
PetscCallA(DMCreateMatrix(dm, jac, ierr))
PetscCallA(DMCreateMatrix(dm, Pmat, ierr))
! look @ https://petsc.org/release/src/ts/utils/dmplexlandau/tutorials/ex1f90.F90.html
PetscCallA(TSCreate(PETSC_COMM_WORLD, ts, ierr))
PetscCall(TSSetProblemType(ts, TS_LINEAR, ierr));
PetscCallA(TSSetDM(ts, dm, ierr))
! Initialize the solution
call FormInitialSolution(ts,u,user,ierr)
! Build the matrix
PetscCallA(TSRHSJacobianFn(ts, dt, u, jac, Pmat, user, ierr))
!
! This is a linear problem, i.e. u_t = F(u) = A*u
!
! https://petsc.org/release/src/ts/tutorials/ex3.c.html
!
PetscCallA(PetscOptionsHasName(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-use_jacobian',lflag, ierr))
if(lflag)then
PetscCallA(TSSetRHSFunction(ts,PETSC_NULL_VEC,TSComputeRHSFunctionLinear,user,ierr))
PetscCallA(TSSetRHSJacobian(ts,jac,jac,TSComputeRHSJacobianConstant,user,ierr))
else
! Set the user-defined function for computing the residual
PetscCallA(TSSetRHSFunction(ts,PETSC_NULL_VEC,FormRHSFunction,user,ierr))
! PetscCallA(TSSetRHSFunction(ts,r,FormRHSFunction,user,ierr))
!
! Sets the function to compute the Jacobian of G, where U_t = G(U,t), as well as the location to store the matrix.
PetscCallA(TSSetRHSJacobian(ts, jac, Pmat, TSRHSJacobianFn, user, ierr))
endif
!
! looks like TSPseudoSetTimeStep is NOT available in fortran
! PetscCallA(TSPseudoSetTimeStep(ts, dtFunction, PETSC_NULL_VEC,ierr))
!
! PetscCallA(TSMonitorSet(ts, MyOwnTSMonitoringRoutine, PETSC_NULL_REAL, PETSC_NULL_FUNCTION, ierr))
PetscCallA(TSMonitorSet(ts, MyOwnTSMonitoringRoutine, user, PETSC_NULL_FUNCTION, ierr))
!
! check also the following:
! DMPlexInsertBoundaryValues
! DMPlexMarkBoundaryFaces
!
! PetscCall(DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, &ctx));
! PetscCall(DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &ctx));
! PetscCall(DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &ctx));
! PetscCallA(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER,ierr))
!
PetscCallA(TSSetFromOptions(ts,ierr))
!
! User-defined function to compute the maximum allowable timestep;
! the sintax complies with TSPseudoSetTimeStep, but there seems to be no fortran interface for TSPseudoSetTimeStep
call dtFunction(ts,dt,user,ierr)
PetscCallA(TSSetTimeStep(ts, dt,ierr))
!
! Here we check if rhs = jac * u
!
! +++++++++++++++ start checking tha f(u) = A*u ++++++++++++++++
!
if(verbose)then
write(IOBuffer,FMT="(A)")"This is u \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
PetscCallA(VecView(u,PETSC_VIEWER_STDOUT_SELF,ierr))
endif
!
PetscCallA(VecDuplicate(u,rhs,ierr))
PetscCallA(VecSet(rhs,0.d0,ierr))
call FormRHSFunction(ts,dt,u,rhs,user,ierr)
if(verbose)then
write(IOBuffer,FMT="(A)")"This is f(u) \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
PetscCallA(VecView(rhs,PETSC_VIEWER_STDOUT_SELF,ierr))
endif
!
PetscCallA(VecDuplicate(u,y,ierr))
PetscCallA(MatMult(jac,u,y,ierr))
if(verbose)then
write(IOBuffer,FMT="(A)")"This is A*u \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
PetscCallA(VecView(y,PETSC_VIEWER_STDOUT_SELF,ierr))
endif
!
PetscCallA(MatView(jac,PETSC_VIEWER_STDOUT_SELF,ierr))
!
PetscCallA(VecAXPY(y, -1.d0, rhs, ierr))
write(IOBuffer,FMT=*)"This is A*u-f(u): should be 0.d0 \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
PetscCallA(VecView(y,PETSC_VIEWER_STDOUT_SELF,ierr))
!
PetscCallA(VecDestroy(y,ierr))
PetscCallA(VecDestroy(rhs,ierr))
!
! +++++++++++++++ finished checking ++++++++++++++++
!
! call exit(-1)
!
! DMTSCheckFromOptions does NOT seem to be available in fortran
! PetscCallA(DMTSCheckFromOptions(ts, u, ierr))
!
PetscCallA(TSSolve(ts, u, ierr))
! PetscCallA(VecViewFromOptions(u, PETSC_NULL_VIEWER, "-sol_vec_view", ierr))
! Need X support
! PetscCallA(PetscViewerDrawOpen(PETSC_COMM_WORLD,PETSC_NULL_CHARACTER,PETSC_NULL_CHARACTER,0,0,300,300,viewer,ierr))
!
PetscCallA(PetscViewerCreate(PETSC_COMM_WORLD,viewer,ierr))
PetscCallA(PetscViewerSetType(viewer,PETSCVIEWERASCII,ierr))
PetscCallA(PetscViewerFileSetMode(viewer,FILE_MODE_WRITE,ierr))
PetscCallA(PetscViewerFileSetName(viewer,"sol.dat",ierr))
! View the vector
PetscCallA(VecView(u,viewer,ierr))
! Deallocate memory.
PetscCallA(PetscViewerDestroy(viewer,ierr))
!
!
PetscCallA(PetscViewerCreate(PETSC_COMM_WORLD,viewer,ierr))
PetscCallA(PetscViewerSetType(viewer,PETSCVIEWERASCII,ierr))
PetscCallA(PetscViewerFileSetMode(viewer,FILE_MODE_WRITE,ierr))
PetscCallA(PetscViewerFileSetName(viewer,"exact.dat",ierr))
!
PetscCallA(VecDuplicate(u,y,ierr))
call FormInitialSolution(ts,y,user,ierr) ! returns the exact solution except when Peclet = 0
! View the vector
PetscCallA(VecView(y,viewer,ierr))
! Deallocate memory.
PetscCallA(PetscViewerDestroy(viewer,ierr))
!
! Steady Error calculation
!
PetscCallA(PetscViewerCreate(PETSC_COMM_WORLD,viewer,ierr))
PetscCallA(PetscViewerSetType(viewer,PETSCVIEWERASCII,ierr))
PetscCallA(PetscViewerFileSetMode(viewer,FILE_MODE_WRITE,ierr))
PetscCallA(PetscViewerFileSetName(viewer,"err.dat",ierr))
!
PetscCallA(VecGetSize(y, nitems, ierr))
s = 1.d0/dble(nitems)
s = user(4) ! average mesh spacing
PetscCallA(VecAXPY(y, -1.d0, u, ierr))
PetscCallA(VecView(y,viewer,ierr))
! Deallocate memory.
PetscCallA(PetscViewerDestroy(viewer,ierr))
!
PetscCallA(VecNorm(y, NORM_2, rnorm_2, ierr))
rnorm_2 = dsqrt(s) * rnorm_2
PetscCallA(VecNorm(y, NORM_MAX, rnorm_max, ierr))
write(IOBuffer,FMT=*)"h;L2;Lmax error norms are : ",user(4),rnorm_2,rnorm_max,"\n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
!
!
!
PetscCallA(VecDestroy(y,ierr))
!
! Free work space. All PETSc objects should be destroyed when they
! are no longer needed.
!
PetscCallA(MatDestroy(jac,ierr))
PetscCallA(MatDestroy(Pmat,ierr))
PetscCallA(VecDestroy(u,ierr))
PetscCallA(TSDestroy(ts,ierr))
PetscCallA(DMDestroy(dm,ierr))
PetscCallA(PetscFinalize(ierr))
!
! /home/abonfi/src/petsc-3.22.0/src/dm/impls/plex/tutorials ex1F90
!
write ( *, '(a)' ) ' '
write ( *, '(a)' ) ' Normal end of execution.'
write ( *, '(a)' ) ' '
stop
end
!
!
!
subroutine Createmesh(dm,length)
#include <petsc/finclude/petsc.h>
use petsc
implicit none
DM :: dm
PetscReal :: length
PetscErrorCode :: ierr
PetscInt :: depth,ndim,ibgn,iend
character(len=PETSC_MAX_PATH_LEN) :: IOBuffer
!
! The support/closure of a point is defined as the set of all point of the next highest topological dimension that is connected to the current point.
! For example, in a 3 dimensional fully interpolated mesh, the closure of a vertex would be the set of all of the edges which contain this vertex.
!
! The cone of a point is defined as the set of every points of the next lowest topological dimension. For example, in a 3 dimensional fully interpolated mesh,
! the cone of a cell would be the set of every face on belonging to that cell.
!
!
PetscCall(DMPlexCreate(PETSC_COMM_WORLD, dm, ierr))
PetscCall(PetscObjectSetName(dm, '1D plex', ierr))
PetscCall(DMSetFromOptions(dm,ierr))
PetscCall(DMGetDimension(dm,ndim,ierr))
if( ndim .NE. 1 )call PetscError(PETSC_COMM_WORLD,1,PETSC_ERROR_INITIAL,'Topological dimension must equal 1')
PetscCall(DMViewFromOptions(dm, PETSC_NULL_VEC, '-dm_view', ierr))
PetscCall(DMView(dm,PETSC_VIEWER_STDOUT_WORLD,ierr))
PetscCall(DMSetup(dm,ierr))
! Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, often “vertices”.
! If the mesh is “interpolated” (see DMPlexInterpolate()), then depth stratum 1 contains the next higher dimension, e.g., “edges”.
do depth = 0,1
PetscCall(DMPlexGetDepthStratum(dm, depth, ibgn , iend,ierr))
write(IOBuffer,FMT=*)"there are ",iend-ibgn," entries in depth: ",depth," \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
enddo
! can I get the length from Petsc?
length = 1.d0 ! should be set to the length
return
end
!
! -------------------- Evaluate Function F(x) ---------------------
!
subroutine FormRHSFunction(ts,t,u,f,user,ierr)
#include <petsc/finclude/petsc.h>
use petsc
implicit none
TS :: ts
PetscReal::t
Vec :: u,f
Vec :: localu,localF
PetscReal::user(*)
PetscErrorCode :: ierr
DM :: dm
PetscInt :: depth,cell,cbgn,cend
PetscReal, pointer :: pcentroid(:)
PetscReal, pointer :: pnormal(:)
PetscScalar, dimension(:),pointer :: p_values
PetscScalar, dimension(:),pointer :: p_res
PetscReal, target, dimension(2) :: centroid
PetscReal, target, dimension(2) :: normal
PetscReal, target, dimension(2) :: res
PetscReal :: eps,c,length,cplus,cmins
PetscReal :: du,ux,vol,h
pcentroid => centroid
pnormal => normal
p_res => res
eps = user(1) ! viscosity coefficient
c = user(2) ! convective speed
length = user(3)
cplus = 0.5d0*(c+dabs(c))
cmins = c - cplus
h = user(4)
PetscCall(TSGetDM(ts, dm, ierr));
PetscCall(DMGetLocalVector(dm, localu, ierr ))
PetscCall(DMGetLocalVector(dm, localf, ierr ))
PetscCall(DMGlobaltoLocal(dm, u, INSERT_VALUES, localu, ierr ))
PetscCall(VecSet(localf, 0.d0, ierr ))
!
! Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, often “vertices”.
! If the mesh is “interpolated” (see DMPlexInterpolate()), then depth stratum 1 contains the next higher dimension, e.g., “edges”.
!
depth = 1 ! pick up cells (edges), NOT vertices
PetscCall(DMPlexGetDepthStratum(dm, depth, cbgn, cend, ierr))
do cell = cbgn,cend-1 ! loop over 1D cells (edges)
PetscCall(DMPlexVecGetClosure(dm, PETSC_NULL_SECTION, localu, cell, p_values, ierr))
PetscCall(DMPlexComputeCellGeometryFVM(dm, cell, vol, pcentroid, pnormal, ierr))
du = (p_values(2)-p_values(1))
ux = du/vol ! cell-wise gradient
p_res(1) = (-cmins*du+eps*ux)!/h ! send it to the "left"
p_res(2) = (-cplus*du-eps*ux)!/h ! send it to the "right"
! write(6,*)cell,(p_values(j),j=1,2),du
PetscCall(DMPlexVecRestoreClosure(dm, PETSC_NULL_SECTION, localu, cell, p_values, ierr))
PetscCall(DMPlexVecSetClosure(dm, PETSC_NULL_SECTION, localf, cell, p_res, ADD_VALUES, ierr ))
enddo
! PetscCall(VecScale(localu,1.d0/h, ierr ))
PetscCall(DMRestoreLocalVector(dm, localu, ierr ))
! Insert (do NOT ADD!!) values into the "global" solution vector f
PetscCall(DMLocalToGlobal(dm, localf, INSERT_VALUES, f, ierr))
PetscCall(DMRestoreLocalVector(dm, localf, ierr ))
! do I need to VecAssembly or is it done inside DMLocalToGlobalEnd ?
! PetscCall(VecAssemblyBegin(f,ierr))
! PetscCall(VecAssemblyEnd(f,ierr))
return
end
!
!
!
subroutine FormInitialSolution(ts,u,user,ierr)
!
! build the initial solution: we only need to initialize processor owned vertices, I believe ......
!
#include <petsc/finclude/petsc.h>
use petsc
implicit none
TS :: ts
Vec :: u
Vec :: localu
PetscReal :: user(*)
PetscErrorCode :: ierr
DM :: dm
PetscBool :: simplex
PetscInt :: size,depth,vbgn,vend
PetscReal :: x
integer :: i,nitems,ifail
PetscScalar, pointer :: xx_g(:),xx_u(:)
PetscReal :: eps,c,length,Pe,rx,fi0,fin
Vec :: coordVec
character(len=PETSC_MAX_PATH_LEN) :: IOBuffer
logical, parameter :: verbose = .FALSE.
eps = user(1)
c = user(2)
length = user(3)
Pe = c*length/eps
rx = 1.d0/length
fi0 = 1.d0
fin = 0.d0
PetscCall(TSGetDM(ts, dm, ierr));
PetscCall(DMPlexIsSimplex(dm, simplex, ierr));
if( simplex .NEQV. PETSC_TRUE )then
PetscCall(PetscError(PETSC_COMM_WORLD,1,PETSC_ERROR_INITIAL,"I can only work with simplices"))
endif
! use DMGetCoordinatesLocal or it will NOT work in the parallel case
PetscCall(DMGetCoordinatesLocal(dm,coordVec,ierr))
PetscCall(VecGetSize(coordVec,size,ierr))
! call VecView(coordVec,PETSC_VIEWER_STDOUT_WORLD, ierr)
!
! do I need the CoordinateSection ?
!
! PetscCall(DMGetCoordinateSection(dm, coordSection,ierr))
!
! I need to retrieve the LocalVector or Dirichlet nodes will be missing
PetscCall(DMGetLocalVector(dm, localu, ierr ))
PetscCall(DMGlobalToLocal(dm, u, INSERT_VALUES, localu, ierr))
!
! Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, often “vertices”.
! If the mesh is “interpolated” (see DMPlexInterpolate()), then depth stratum 1 contains the next higher dimension, e.g., “edges”.
!
depth = 0 ! pick up the vertices
PetscCall(DMPlexGetDepthStratum(dm, depth, vbgn, vend, ierr))
nitems = vend-vbgn
if(nitems.NE.size)then
write(IOBuffer,FMT=*)"There is a mismatch ",nitems,size,"\n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
ifail = nitems-size
else
ifail = 0
endif
PetscCall(VecGetArrayF90(localu,xx_u,ierr))
PetscCall(VecGetArrayReadF90(coordVec,xx_g,ierr))
do i = 1,nitems ! loop over the vertices
x = xx_g(i)
if(verbose)then
write(IOBuffer,FMT=*)"x-Coord of gridpoint ",i," is ",x," \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
endif
if(pe .LE. 1.d-8)then ! diffusive limit
xx_u(i) = fi0 + (x*x*x) * (fin-fi0)
else
xx_u(i) = fi0 + (exp(pe*x*rx)-1.d0)/(exp(pe)-1.d0) * (fin-fi0)
endif
enddo
PetscCall(VecRestoreArrayReadF90(coordVec,xx_g,ierr))
PetscCall(VecRestoreArrayF90(localu,xx_u,ierr))
! call VecView(localu,PETSC_VIEWER_STDOUT_WORLD, ierr)
PetscCall(DMLocalToGlobal(dm, localu, INSERT_VALUES, u, ierr))
PetscCall(DMRestoreLocalVector(dm, localu, ierr ))
if(ifail.NE.0)call PetscError(PETSC_COMM_WORLD,1,PETSC_ERROR_INITIAL,'There is a mismatch')
return
end
subroutine SetupSection(dm)
#include <petsc/finclude/petsc.h>
use petsc
implicit none
DM :: dm
PetscInt :: ndofs
PetscErrorCode :: ierr
PetscSection :: s
PetscInt :: depth, vStart, vEnd, v, numDof, numFixed, nitems , numPoints, i
DMLabel :: label
PetscBool :: hasLabel
! PetscInt, dimension(:),pointer :: p_idx
PetscInt,dimension(:),pointer :: constraints
PetscInt, pointer :: xx_v(:)
IS, target, dimension(1) :: bcPointIS
ndofs = 1
numDof = 0
depth = 0 ! loop over vertices
PetscCall(DMPlexGetDepthStratum(dm, depth, vStart, vEnd, ierr))
PetscCall(PetscSectionCreate(PETSC_COMM_WORLD, s, ierr))
! PetscCall(PetscSectionSetNumFields(s, 1, ierr))
! PetscCall(PetscSectionSetFieldComponents(s, 0, 1, ierr))
PetscCall(PetscSectionSetChart(s, vStart, vEnd, ierr))
write(6,*)"Setting up a section on ",vEnd-vStart," meshpoints with ",ndofs," dofs"
do v = vStart, vEnd-1
PetscCall(PetscSectionSetDof(s, v, ndofs, ierr))
! PetscCall(PetscSectionSetFieldDof(s, v, 0, 1));
enddo
! un-comment the following goto to avoid setting BCs
! goto 10
!
! Identify boundary vertices
!
PetscCall(DMHasLabel(dm, "marker", hasLabel, ierr))
if(.NOT. hasLabel) call CreateBCLabel(dm, "marker")
PetscCall(DMGetLabel(dm, "marker", label, ierr))
PetscCall(DMGetStratumSize(dm,'marker',1,numPoints,ierr))
PetscCall(DMLabelGetStratumIS(label, 1, bcPointIS(1), ierr))
PetscCall(ISGetSize(bcPointIS(1), nitems, ierr))
write(6,*)"IS bcPoint has ",nitems," items "
PetscCall(ISGetIndicesF90(bcPointIS(1),xx_v,ierr))
do i = 1,numPoints
v = xx_v(i)
write(6,*)"Point ",v,"is a boundary point"
PetscCall(PetscSectionSetConstraintDof(s, v, ndofs, ierr))
! PetscCall(PetscSectionSetConstraintIndicesF90(s,pointID(1),constraints,ierr))
enddo
PetscCall(PetscSectionSetUp(s,ierr))
do v = vStart, vEnd-1
PetscCall(PetscSectionGetDof(s, v, numDof, ierr))
PetscCall(PetscSectionGetConstraintDof(s, v, numFixed, ierr))
write(6,*)"Point ",v," has ",numDof, " dofs; ",numFixed," of these are fixed"
enddo
allocate(constraints(1))
! allocate(pointID(1))
constraints(1) = 0
do i = 1,numPoints
v = xx_v(i)
write(6,*)"Point ",v,"is a boundary point",constraints
! PetscCall(PetscSectionSetConstraintIndicesF90(s,xx_v(i),constraints(1),ierr))
PetscCall(PetscSectionSetConstraintIndicesF90(s,v,constraints,ierr))
enddo
deallocate(constraints)
! deallocate(pointID)
! look @ ./src/dm/impls/plex/tests/ex98f90.F90
! for the use of PetscSectionSetConstraintIndicesF90 and PetscSectionSetFieldConstraintIndicesF90
! allocate(p_idx(1))
!
! am I doing smthg wrong when calling PetscSectionGetConstraintIndicesF90 ?
!
! do v = vStart, vEnd-1
! PetscCall(PetscSectionGetConstraintDof(s, v, numFixed, ierr))
! if(numFixed.NE.0)then
! PetscCall(PetscSectionGetConstraintIndicesF90(s, v, p_idx, ierr))
! write(6,*)v,(p_idx(j),j=1,numFixed)
! PetscCall(PetscSectionRestoreConstraintIndicesF90(s, v, p_idx, ierr))
! endif
! enddo
10 continue
! deallocate(p_idx)
! PetscCall(PetscSectionSetup(s, ierr))
! Get the nof points in depth=1 that are marked; should be 2
! do i = 1,numPoints
! PetscCall(ISGetIndicesF90(bcpointIS,pointID,ierr))
! PetscCall(PetscSectionSetConstraintIndicesF90(s,pointID(1),constraints,ierr))
! enddo
PetscCall(DMSetLocalSection(dm, s,ierr))
PetscCall(PetscSectionGetStorageSize(s, nitems, ierr))
write(6,*)"Constrained section has size = ",nitems
PetscCall(PetscSectionView(s, PETSC_VIEWER_STDOUT_WORLD, ierr))
PetscCall(PetscSectionDestroy(s,ierr))
return
end
!
subroutine dtFunction(ts,newdt,user,ierr)
!
! -------------------- Evaluate time-step ---------------------
!
#include <petsc/finclude/petsc.h>
use petsc
implicit none
TS :: ts
PetscReal::newdt
PetscReal::user(*)
PetscErrorCode :: ierr
DM :: dm
PetscInt :: depth,cell,cbgn,cend,nitems
PetscReal :: eps,c
PetscReal :: vol,h,dt(2)
PetscReal, pointer :: pcentroid(:)
PetscReal, pointer :: pnormal(:)
PetscReal, target, dimension(1) :: centroid
PetscReal, target, dimension(1) :: normal
PetscReal, parameter :: cfl = 0.8d0
character(len=PETSC_MAX_PATH_LEN) :: IOBuffer
pcentroid => centroid
pnormal => normal
eps = user(1) ! user(1)
c = user(2) ! user(2)
h = 0.d0 ! average mesh spacing
PetscCall(TSGetDM(ts, dm, ierr))
depth = 1 ! loop over cells (edges), NOT vertices !!
PetscCall(DMPlexGetDepthStratum(dm, depth, cbgn , cend,ierr))
do cell = cbgn,cend-1 ! loop over 1D cells (edges)
PetscCall(DMPlexComputeCellGeometryFVM(dm, cell, vol, pcentroid, pnormal,ierr))
h = h + vol
enddo
nitems = cend-cbgn
h = h/dble(nitems) ! average cell volume
dt(1) = h/c
dt(2) = h*h/(2.d0*eps)
newdt = min(dt(1),dt(2)) ! maximum explicit timestep
newdt = cfl*newdt
write(IOBuffer,FMT=*)"\n Average mesh spacing is ",h," \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
write(IOBuffer,FMT=*)"\n Time-step is set to ",dt,newdt," \n"
PetscCallA(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
user(4) = h
return
end
!
subroutine CreateBCLabel(dm, name)
#include <petsc/finclude/petsc.h>
use petsc
implicit none
DM :: dm
character*(*) name
DMLabel :: label
PetscErrorCode :: ierr
PetscCall(DMCreateLabel(dm, name, ierr))
PetscCall(DMGetLabel(dm, name, label, ierr))
! PetscCall(DMConvert(dm, DMPLEX, plex));
! PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label, ierr))
PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label, ierr))
! PetscCall(DMDestroy(&plex, ierr));
return
end
subroutine CreateSectionAlternate(dm)
#include "petsc/finclude/petscdmplex.h"
#include "petsc/finclude/petscdmlabel.h"
use petscdmplex
use petscsys
implicit none
DM :: dm
DMLabel :: label
PetscSection :: section
PetscInt :: ndim,numFields,numBC,size
PetscInt :: i
DMLabel, pointer :: nolabel(:) => NULL()
PetscInt, target, dimension(3) :: numComp
PetscInt, pointer :: pNumComp(:)
PetscInt, target, dimension(12) :: numDof
PetscInt, pointer :: pNumDof(:)
PetscInt, target, dimension(1) :: bcField
PetscInt, pointer :: pBcField(:)
PetscInt, parameter :: zero = 0, one = 1, two = 2
PetscInt :: nitems
! PetscMPIInt ::
IS, target, dimension(1) :: bcCompIS
IS, target, dimension(1) :: bcPointIS
IS, pointer :: pBcCompIS(:)
IS, pointer :: pBcPointIS(:)
PetscErrorCode :: ierr
character(len=PETSC_MAX_PATH_LEN) :: IOBuffer
PetscCall(DMGetDimension(dm, ndim, ierr))
! Create a scalar field u, a vector field v, and a surface vector field w
numFields = 1
numComp(1) = 1
! numComp(2) = ndim
! numComp(3) = ndim-1
pNumComp => numComp
do i = 1, numFields*(ndim+1)
numDof(i) = 0
end do
! Let u be defined on vertices
numDof(0*(ndim+1)+1) = 1
! Let v be defined on cells
! numDof(1*(ndim+1)+ndim+1) = ndim
! Let v be defined on faces
! numDof(2*(ndim+1)+ndim) = ndim-1
do i = 1, numFields*(ndim+1)
write(6,*)"numDof(",i,")= ",numDof(i)
end do
pNumDof => numDof
! Prescribe a Dirichlet condition on u on the boundary
numBC = 1
! Get the nof points in depth=1 that are marked; should be 2
PetscCall(DMGetStratumSize(dm, "marker", one, size, ierr))
write(IOBuffer,FMT=*)"DMGetStratumSize found ",size," points \n"
PetscCall(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
PetscCall(DMGetLabel(dm, "marker", label, ierr))
PetscCall(DMLabelGetStratumIS(label, one, bcPointIS(1), ierr))
PetscCall(ISGetSize(bcPointIS(1), nitems, ierr))
write(IOBuffer,FMT=*)"IS bcPointIS has ",nitems," items \n"
PetscCall(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
! bcField is An array of size numBC giving the field number for each boundary condition
bcField(1) = 0
pBcField => bcField
! PetscErrorCode ISCreateStride(MPI_Comm comm, PetscInt n, PetscInt first, PetscInt step, IS *is)
PetscCall(ISCreateStride(PETSC_COMM_WORLD, one, zero, one, bcCompIS(1), ierr))
PetscCall(ISGetSize(bcCompIS(1), nitems, ierr))
write(IOBuffer,FMT=*)"IS bcCompIS has ",nitems," items \n"
PetscCall(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
! bcCompIS is An array of size numBC giving an IS holding the field components to which each boundary condition applies
pBcCompIS => bcCompIS
pBcPointIS => bcPointIS
! Create a PetscSection with this data layout
PetscCall(DMSetNumFields(dm, numFields,ierr))
PetscCall(DMPlexCreateSection(dm,nolabel,pNumComp,pNumDof,numBC,pBcField,pBcCompIS,pBcPointIS,PETSC_NULL_IS,section,ierr))
PetscCall(ISDestroy(bcCompIS(1), ierr))
PetscCall(ISDestroy(bcPointIS(1), ierr))
! Name the Field variables
PetscCall(PetscSectionSetFieldName(section, zero, 'u', ierr))
PetscCall(PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD, ierr))
! Tell the DM to use this data layout
PetscCall(DMSetLocalSection(dm, section, ierr))
! Cleanup
PetscCall(PetscSectionDestroy(section, ierr))
return
end
!
!
!
subroutine MyOwnTSMonitoringRoutine(ts,iter,time,u,user,ierr)
!
!
!
#include <petsc/finclude/petsc.h>
use petsc
implicit none
TS :: ts
PetscInt :: iter
PetscReal :: time
Vec :: u
PetscReal :: user(*)
PetscErrorCode :: ierr
PetscReal :: s,t
Vec :: f
character(len=PETSC_MAX_PATH_LEN) :: IOBuffer
PetscCall(VecDuplicate(u,f,ierr))
PetscCall(VecNorm(u,NORM_2,t,ierr))
PetscCall(FormRHSFunction(ts,time,u,f,user,ierr))
PetscCall(VecNorm(f,NORM_2,s,ierr))
PetscCall(VecDestroy(f,ierr))
write(IOBuffer,FMT="(A,1X,I6,1X,A,F10.6,2(1X,A,E12.6),A)")"@ iter = ",iter," time = ",time," ||f|| = ",s," ||u|| = ",t,"\n"
PetscCall(PetscPrintf(PETSC_COMM_WORLD, IOBuffer, ierr))
return
end
subroutine TSRHSJacobianFn(ts, time, u, jac, Pmat, user, ierr)
#include <petsc/finclude/petsc.h>
use petsc
implicit none
TS :: ts
PetscReal :: time
Vec :: u
DM :: dm
Mat :: jac,Pmat
PetscReal :: user(*)
!
PetscInt :: ierr,height,cbgn,cend,cell,numDof,point
PetscInt, dimension(:),pointer :: p_points
PetscBool :: useCone = PETSC_TRUE
! PetscBool :: useCone = PETSC_FALSE
integer :: j,ic
PetscReal, target, dimension(2) :: centroid
PetscReal, target, dimension(2) :: normal
PetscReal, pointer :: pcentroid(:)
PetscReal, pointer :: pnormal(:)
PetscInt :: offset
PetscInt :: row(2)
PetscInt :: col(2)
PetscReal :: valA(2,2)
PetscSection :: section
PetscReal :: aplus,amins,eps,vol
pcentroid => centroid
pnormal => normal
aplus = 0.5d0*(user(2)+dabs(user(2)))
amins = user(2) - aplus
eps = user(1)
PetscCall(TSGetDM(ts, dm, ierr))
height = 1
PetscCall(DMGetLocalSection(dm, section, ierr))
PetscCall(DMPlexGetDepthStratum(dm, height, cbgn , cend,ierr))
do cell = cbgn,cend-1
!
PetscCall(DMPlexComputeCellGeometryFVM(dm, cell, vol, pcentroid, pnormal,ierr))
! write(6,*)"Cell # ",cell," ranges btw. : ",(values(j),j=1,2),vol,(pcentroid(j),j=1,1),(pnormal(j),j=1,1)
!
! cell-wise stiffness matrix
! Sorted, row-oriented input will generally assemble the fastest. The default is row-oriented.
!
valA(2,1)=-amins+eps/vol
valA(1,2)=+aplus+eps/vol
valA(1,1)=-valA(1,2)
valA(2,2)=-valA(2,1)
!
PetscCall(DMPlexGetTransitiveClosure(dm, cell, useCone, p_points, ierr))
! write(6,*)"Cell # ",cell," is bounded by vertices: ",(p_points(j),j=1,6,1)
ic = 0
! loop over the (two) vertices of the 1D cell
do j = 3,5,2 ! this is tricky, because vertices are stored in locations 3 and 5 of p_points
ic = ic+1
point = p_points(j)
!
! we know there is only one dof
!
PetscCall(PetscSectionGetDof(section, point, numDof, ierr))
PetscCall(PetscSectionGetOffset(section, point, offset,ierr))
row(ic) = offset
col(ic) = offset
! write(6,*)point,offset,numDof
enddo
PetscCall(MatSetValuesLocal(jac,2,row,2,col,valA(1,1),ADD_VALUES,ierr))
PetscCall(DMPlexRestoreTransitiveClosure(dm, cell,useCone, p_points, ierr))
enddo
PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY,ierr))
PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY,ierr))
return
end
-dm_plex_dim 1
-Peclet 50
-dm_plex_shape box
-dm_plex_box_faces 30
-dm_plex_simplex true
-dm_plex_interpolate
-dm_plex_check_all
-dm_petscsection_view
-ts_max_steps 5000
-options_left