Hello everyone; I would like to be able to split my simulation region into parts; solve those partially, combine those to get the solution.
The reason is that the problem is composed of repeating structures and I hope to increase the calculation speed.
Can anyone point to an example; I could not find any.
Thanks in advance
Have a look into this:
https://jschoeberl.github.io/iFEM/subspacecorrection/minimaldd.html
and also section 72 ff
Hope this gives some ideas.
Joachim
Thank you very much; I was not aware of that resource. That should at least keep me busy for some time.
I had a look at the given example. Since I am using a more complex geometry I tried to extend the example. As a first step I wanted to combine sets of 3 rectangles to form 3 regions.
regions = []
key = lambda x: x[-1]
for k, g in groupby(sorted(mesh.GetMaterials(), key=key), key):
reg = reduce(operator.add, (mesh.Materials(m) for m in g))
regions.append(reg)
fes = FESpace([Compress(H1(mesh, definedon=dom, dirichlet="bot")) for dom in regions])
a = BilinearForm(fes)
f = LinearForm(fes)
for (ui,vi) in zip(u,v):
a += grad(ui)*grad(vi)*dx + 1*ui*vi*dx
f += y*x*vi*dx
gfu = GridFunction(fes)
gfu.vec.data = a.mat.Inverse(inverse="sparsecholesky", freedofs=fes.FreeDofs())*f.vec
gftot = CF(list(gfu.components))
This clearly does not work; (simply check by actually composing the the geometry to 3 larger rectangles).
What am I missing here.
Best to everyone
if you post a complete example, your chance for help increases
Joachim
My apologies; posting a minimal working example should have been a no-brainer.
Here it is and thanks for your quick reply
from ngsolve import *
from netgen.geom2d import CSG2d, Rectangle
from itertools import groupby
from functools import reduce
import operator
geo = CSG2d()
mx, my = 3,3
for i in range(mx):
for j in range(my):
rect = Rectangle(pmin=(i/mx,j/my), \
pmax=((i+1)/mx,(j+1)/my), \
mat='mat'+str(i)+str(j), \
bc = 'default', \
bottom = 'bot' if j == 0 else None)
geo.Add(rect)
mesh = Mesh(geo.GenerateMesh(maxh=0.04))
key = lambda x: x[-1]
mats = ['|'.join(m for m in g) for k, g in groupby(sorted(mesh.GetMaterials(), key=key), key)]
regions = [reg:=mesh.Materials(mat) for mat in mats]
# equivalent result using this construction of the regions
# mats = [list(g) for k, g in groupby(sorted(mesh.GetMaterials(), key=key), key)]
# regions = []
# for k, g in groupby(sorted(mesh.GetMaterials(), key=key), key):
# reg = reduce(operator.add, (mesh.Materials(m) for m in g))
# regions.append(reg)
fes = FESpace([Compress(H1(mesh, definedon=dom, dirichlet="bot")) for dom in regions])
print ("ndof =", fes.ndof)
u, v = fes.TnT()
a = BilinearForm(fes)
f = LinearForm(fes)
for (ui,vi) in zip(u,v):
a += grad(ui)*grad(vi)*dx + 1*ui*vi*dx
f += y*x*vi*dx
a.Assemble()
f.Assemble()
gfu = GridFunction(fes)
gfu.vec.data = a.mat.Inverse(inverse="sparsecholesky", freedofs=fes.FreeDofs())*f.vec
gftot = CF(list(gfu.components))
Draw(gftot)
Using the method mentioned in your initial response, I can get it to work.
Still, I am confused what went wrong with the other approach
from ngsolve import *
from netgen.geom2d import CSG2d, Rectangle
from itertools import groupby
from functools import reduce
import operator
from ngsolve.krylovspace import CGSolver
geo = CSG2d()
mx, my = 3,3
for i in range(mx):
for j in range(my):
rect = Rectangle(pmin=(i/mx,j/my), \
pmax=((i+1)/mx,(j+1)/my), \
mat='mat'+str(i)+str(j), \
bc = 'default', \
bottom = 'bot' if j == 0 else None)
geo.Add(rect)
mesh = Mesh(geo.GenerateMesh(maxh=0.04))
key = lambda x: x[-1]
mats = [list(g) for k, g in groupby(sorted(mesh.GetMaterials(), key=key), key)]
regions = []
for k, g in groupby(sorted(mesh.GetMaterials(), key=key), key):
reg = reduce(operator.add, (mesh.Materials(m) for m in g))
regions.append(reg)
fes = H1(mesh, order=1, dirichlet='bot')
print ("ndof =", fes.ndof)
u, v = fes.TnT()
a = BilinearForm(fes)
f = LinearForm(fes)
f += x*v*dx
a += grad(u)*grad(v)*dx
f.Assemble()
a.Assemble()
invs = []
for dom in regions:
domaindofs = fes.GetDofs(dom) & fes.FreeDofs()
print ("num dofs:", domaindofs.NumSet())
invs.append(a.mat.Inverse(domaindofs))
invs = reduce(operator.add, invs)
inv = CGSolver(mat=a.mat, pre=invs)
print ("Iterations: ", len(inv.errors))
gfu = GridFunction(fes)
gfu.vec.data = inv * f.vec
gftot = CF(gfu)
Draw(gftot)
Some apologies at this point: I got it to work; since I use custom drawing functions, drawing the result was wrong. it is still a bit surprising but with the following replacement I got it to work:
gftot = reduce(operator.add, (CF(comp) for comp in gfu.components))
# instead of
gftot = CF(list(gfu.components))
CF (list) is domain wise, CF(tuple) vectorial. it has some legacy reasons and is a quite common pitfall (as seen in documentation)