(I don't have much experience in parallel programming, so apologies if the following does not make a lot of sense or is trivial.)
I wrote a object-oriented Python program, where each PDE that I encounter is a class on its own. In a very simplified way it looks like this:
program.py
import subprocess
from dolfin import *
class Main(object):
def __init__(self):
self.geometry = Geometry()
self.poissonpde = Poisson(self.geometry)
def do_stuff(self):
fct_list = [Expression("x[0]*x[0] + x[1]"), Expression("x[0] + 7 * x[1]")]
for fct in fct_list:
solution = self.poissonpde.solve(fct)
# plot(solution, interactive=True)
print solution.vector().array()[:10]
class Geometry(object):
def __init__(self):
subprocess.call(["gmsh", "-2", "square.geo"])
subprocess.call(["dolfin-convert", "square.msh", "square.xml"])
self.mesh = Mesh("square.xml")
self.regions = MeshFunction('size_t', self.mesh, "square_physical_region.xml")
self.boundaries = MeshFunction('size_t', self.mesh, "square_facet_region.xml")
self.dx = Measure('dx')[self.regions]
self.ds = Measure('ds')[self.boundaries]
class Poisson(object):
def __init__(self, geometry):
self.geometry = geometry
self.V = FunctionSpace(self.geometry.mesh, 'CG', 1)
self.u = TrialFunction(self.V)
self.v = TestFunction(self.V)
self.sol = Function(self.V)
self.bcs = [DirichletBC(self.V, Constant(0.0), self.geometry.boundaries, 2),
DirichletBC(self.V, Constant(0.0), self.geometry.boundaries, 3)]
self.solver = LUSolver()
def solve(self, sourcefct):
a = inner(grad(self.u), grad(self.v)) * self.geometry.dx
L = sourcefct * self.v * self.geometry.dx
A, L = assemble_system(a, L, self.bcs)
self.solver.set_operator(A)
self.solver.solve(self.sol.vector(), L)
return self.sol
main = Main()
main.do_stuff()
square.geo
cl = 1.0;
Point(1) = {0, 0, 0, cl};
Point(2) = {0, 20, 0, cl};
Point(3) = {20, 20, 0, cl};
Point(4) = {20, 0, 0, cl};
Line(1) = {1, 2};
Line(2) = {2, 3};
Line(3) = {3, 4};
Line(4) = {4, 1};
Line(5) = {1, 3};
Line Loop(6) = {1, 2, -5};
Plane Surface(7) = {6};
Line Loop(8) = {5, 3, 4};
Plane Surface(9) = {8};
Physical Line(1) = {1, 3};
Physical Line(2) = {2};
Physical Line(3) = {4};
Physical Surface(0) = {7};
Physical Surface(1) = {9};
... where in practice, this code consists of multiple modules. Now I would like to speed things up using MPI, but the examples all assume one python script.
Hence my question what is the recommended way to solve the PDE's using MPI, with as few modifications as possible?
EDIT Based on the discussion below, splitting program.py into the following two files works (running serial.py first, then parallel.py):
serial.py
import subprocess
from dolfin import *
subprocess.call(["gmsh", "-2", "square.geo"])
subprocess.call(["dolfin-convert", "square.msh", "square.xml"])
mesh = Mesh("square.xml")
regions = MeshFunction('size_t', mesh, "square_physical_region.xml")
boundaries = MeshFunction('size_t', mesh, "square_facet_region.xml")
hdf = HDF5File(mesh.mpi_comm(), "file.h5", "w")
hdf.write(mesh, "/mesh")
hdf.write(regions, "/regions")
hdf.write(boundaries, "/boundaries")
parallel.py
from dolfin import *
class Main(object):
def __init__(self):
self.geometry = Geometry()
self.poissonpde = Poisson(self.geometry)
def do_stuff(self):
fct_list = [Expression("x[0]*x[0] + x[1]"), Expression("x[0] + 7 * x[1]")]
for fct in fct_list:
solution = self.poissonpde.solve(fct)
# plot(solution, interactive=True)
print solution.vector().array()[:10]
class Geometry(object):
def __init__(self):
self.mesh = Mesh()
hdf = HDF5File(self.mesh.mpi_comm(), "file.h5", "r")
hdf.read(self.mesh, "/mesh", False)
self.regions = CellFunction("size_t", self.mesh)
hdf.read(self.regions, "/regions")
self.boundaries = FacetFunction("size_t", self.mesh)
hdf.read(self.boundaries, "/boundaries")
self.dx = Measure('dx')[self.regions]
self.ds = Measure('ds')[self.boundaries]
class Poisson(object):
def __init__(self, geometry):
self.geometry = geometry
self.V = FunctionSpace(self.geometry.mesh, 'CG', 1)
self.u = TrialFunction(self.V)
self.v = TestFunction(self.V)
self.sol = Function(self.V)
self.bcs = [DirichletBC(self.V, Constant(0.0), self.geometry.boundaries, 2),
DirichletBC(self.V, Constant(0.0), self.geometry.boundaries, 3)]
self.solver = LUSolver()
def solve(self, sourcefct):
a = inner(grad(self.u), grad(self.v)) * self.geometry.dx
L = sourcefct * self.v * self.geometry.dx
A, L = assemble_system(a, L, self.bcs)
self.solver.set_operator(A)
self.solver.solve(self.sol.vector(), L)
return self.sol
main = Main()
main.do_stuff()