6import scipy.sparse.linalg
7from scipy.sparse
import lil_matrix
10import dune.grid
as grid
11import dune.functions
as functions
16def getLocalMatrix(localView):
19 element = localView.element()
23 elementMatrix = numpy.zeros((n,n))
26 fluxLocalFiniteElement = localView.tree().child(0).finiteElement()
27 pressureLocalFiniteElement = localView.tree().child(1).finiteElement()
30 localFluxBasis = fluxLocalFiniteElement.localBasis
31 localPressureBasis = pressureLocalFiniteElement.localBasis
33 nFlux = len(fluxLocalFiniteElement)
34 nPressure = len(pressureLocalFiniteElement)
37 fluxOrder = element.mydimension * fluxLocalFiniteElement.localBasis.order
38 pressureOrder = element.mydimension * pressureLocalFiniteElement.localBasis.order
39 quadOrder = numpy.max((2*fluxOrder, (fluxOrder-1)+pressureOrder))
41 quadRule = dune.geometry.quadratureRule(element.type, quadOrder)
44 for quadPoint
in quadRule:
47 quadPos = quadPoint.position
50 geometryJacobianInverse = element.geometry.jacobianInverse(quadPos)
53 integrationElement = element.geometry.integrationElement(quadPos)
60 fluxValues = localFluxBasis.evaluateFunction(quadPos)
63 fluxReferenceJacobians = localFluxBasis.evaluateJacobian(quadPos)
65 fluxDivergence = numpy.zeros(nFlux)
69 for i
in range(nFlux):
70 fluxDivergence[i] = numpy.trace(numpy.array(fluxReferenceJacobians[i]) * geometryJacobianInverse)
77 pressureValues = localPressureBasis.evaluateFunction(quadPos)
83 for i
in range(nFlux):
85 row = localView.tree().child(0).localIndex(i)
87 for j
in range(nFlux):
89 col = localView.tree().child(0).localIndex(j)
92 elementMatrix[row,col] += numpy.dot(fluxValues[i], fluxValues[j]) * quadPoint.weight * integrationElement
98 for i
in range(nFlux):
100 fluxIndex = localView.tree().child(0).localIndex(i)
102 for j
in range(nPressure):
104 pressureIndex = localView.tree().child(1).localIndex(j)
107 tmp = (fluxDivergence[i] * pressureValues[j][0]) * quadPoint.weight * integrationElement
110 elementMatrix[fluxIndex, pressureIndex] += tmp
111 elementMatrix[pressureIndex, fluxIndex] += tmp
119def getVolumeTerm(localView, localVolumeTerm):
122 element = localView.element()
125 localRhs = numpy.zeros(len(localView))
129 pressureLocalFiniteElement = localView.tree().child(1).finiteElement()
132 quadOrder = 2*element.mydimension*pressureLocalFiniteElement.localBasis.order
133 quadRule = dune.geometry.quadratureRule(element.type, quadOrder)
135 nPressure = len(pressureLocalFiniteElement)
138 for quadPoint
in quadRule:
141 quadPos = quadPoint.position
144 integrationElement = element.geometry.integrationElement(quadPos)
147 functionValue = localVolumeTerm(quadPos)
150 pressureValues = pressureLocalFiniteElement.localBasis.evaluateFunction(quadPos)
153 for j
in range(nPressure):
154 pressureIndex = localView.tree().child(1).localIndex(j)
155 localRhs[pressureIndex] += - pressureValues[j][0] * functionValue * quadPoint.weight * integrationElement
163def assembleMixedPoissonMatrix(basis):
169 stiffnessMatrix = lil_matrix( (n,n) )
172 localView = basis.localView()
175 for element
in basis.gridView.elements:
178 localView.bind(element)
181 elementMatrix = getLocalMatrix(localView)
184 for i
in range(len(localView)):
187 row = localView.index(i)[0]
189 for j
in range(len(localView)):
192 col = localView.index(j)[0]
193 stiffnessMatrix[row,col] += elementMatrix[i, j];
196 return stiffnessMatrix.tocsr()
202def assembleMixedPoissonRhs(basis, volumeTerm):
205 pressureBasis = functions.subspaceBasis(basis, 1)
208 volumeTermCoeff = numpy.zeros(len(basis))
209 pressureBasis.interpolate(volumeTermCoeff, volumeTerm)
210 volumeTermGF = pressureBasis.asFunction(volumeTermCoeff)
213 localVolumeTerm = volumeTermGF.localFunction()
216 b = numpy.zeros(len(basis))
219 localView = basis.localView()
222 for element
in basis.gridView.elements:
225 localView.bind(element)
228 localVolumeTerm.bind(element)
229 localRhs = getVolumeTerm(localView, localVolumeTerm)
232 for i
in range(len(localRhs)):
234 row = localView.index(i)[0]
235 b[row] += localRhs[i]
247def markBoundaryDOFsByIndicator(basis, vector, indicator):
248 from io
import StringIO
252 #include<dune/common/fvector.hh>
253 #include<dune/functions/functionspacebases/boundarydofs.hh>
254 template<class Basis, class Vector, class Indicator>
255 void run(const Basis& basis, Vector& vector, const Indicator& indicator)
257 auto vectorBackend = vector.mutable_unchecked();
258 Dune::Functions::forEachBoundaryDOF(basis, [&] (auto&& localIndex, const auto& localView, const auto& intersection) {
259 if (indicator(intersection.geometry().center()).template cast<bool>())
260 vectorBackend[localView.index(localIndex)] = true;
264 dune.generator.algorithm.run(
"run",StringIO(code), basis, vector, indicator)
273def incorporateEssentialConstraints(A, b, isConstrained, x):
274 b -= A*(x*isConstrained)
275 rows, cols = A.nonzero()
276 for i,j
in zip(rows, cols):
277 if isConstrained[i]
or isConstrained[j]:
279 for i
in range(len(b)):
294gridView = grid.structuredGrid([0,0],upperRight,elements)
301basis = functions.defaultGlobalBasis(gridView,
302 functions.Composite(functions.RaviartThomas(order=0),
303 functions.Lagrange(order=0)))
305fluxBasis = functions.subspaceBasis(basis, 0);
306pressureBasis = functions.subspaceBasis(basis, 1);
311stiffnessMatrix = assembleMixedPoissonMatrix(basis)
314volumeTerm =
lambda x : 2
316b = assembleMixedPoissonRhs(basis, volumeTerm)
321fluxDirichletIndicator =
lambda x : 1.*((x[1] > upperRight[1] - 1e-8)
or (x[1] < 1e-8))
323isDirichlet = numpy.zeros(len(basis))
327markBoundaryDOFsByIndicator(fluxBasis, isDirichlet, fluxDirichletIndicator);
338normal =
lambda x : numpy.array([0.,1.])
if numpy.abs(x[1]-1) < 1e-8
else numpy.array([0., -1.])
339fluxDirichletValues =
lambda x : numpy.sin(2.*numpy.pi*x[0]) * normal(x)
342fluxDirichletCoefficients = numpy.zeros(len(basis))
343fluxBasis.interpolate(fluxDirichletCoefficients, fluxDirichletValues);
350incorporateEssentialConstraints(stiffnessMatrix, b, isDirichlet, fluxDirichletCoefficients)
357x = scipy.sparse.linalg.spsolve(stiffnessMatrix, b)
367vtkWriter = gridView.vtkWriter(subsampling=2)
369fluxFunction = fluxBasis.asFunction(x)
370fluxFunction.addToVTKWriter(
"flux", vtkWriter, grid.DataType.PointVector)
372pressureFunction = pressureBasis.asFunction(x)
373pressureFunction.addToVTKWriter(
"pressure", vtkWriter, grid.DataType.PointData)
375vtkWriter.write(
"poisson-mfem-result")