I am solving a simple diffusion problem with Neumann boundary conditions in FEniCS. I am trying to extend the code in time, i.e., I ran it for time t =0 to t=0.5 and saved the solution in a file. Now I want to read the solution at t = 0.5 and pass it as an initial condition for the run from t=0.5 to t=1.
Here, the solver does a funny thing. When I print the value of the field upto machine precision for the extended run, it reads the initial condition correctly from the file but the field at the next timestep is off beyond the 12th decimal place. I am comparing the solution in the extended run with the one obtained by a direct run from t = 0 to t = 1.
I do not understand the mistake I’m making. Worryingly, I have to do this extension business for a non-linear problem where I’m interested in the long-time limit of the solution. I do not know how the errors would propagate for the non-linear problem, and how trustworthy the solution would be in the long-time limit.
Posting here the code where I have separated the run part from the solving of the differential equation part. The parameters are taken from the jsonfile.
SOLVE CODE:
import dolfin as df
import progressbar
import os
df.set_log_level(df.LogLevel.ERROR)
df.parameters['form_compiler']['optimize'] = True
np.set_printoptions(precision=16)
class diffusion(object):
def __init__(self, parameters):
# read in parameters
for key in parameters:
setattr(self, key, parameters[key])
self.mesh = df.IntervalMesh(self.resolution,
-self.L/2,
self.L/2)
self.function_space = df.FunctionSpace(self.mesh,'P', 1)
self.c = df.Function(self.function_space)
self.tc = df.TestFunction(self.function_space)
self.c0 = df.Function(self.function_space)
def setup_initial_conditions(self, initc):
if initc is None:
self.c0.interpolate(df.Expression('1 + 0.2 * cos(2 * pi*x[0]/L)', pi=np.pi, L=self.L, degree=1))
else:
self.c0.interpolate(initc)
print('c0=', self.c0.compute_vertex_values(self.mesh))
def setup_weak_forms(self):
self.form = (df.inner((self.c - self.c0)/self.timestep, self.tc)
+ self.D * df.inner(df.nabla_grad(self.c), df.nabla_grad(self.tc))
) * df.dx
def solve(self, initc=None, initTime=0.0, extend=False):
# create file if it doesn't exist, open if it does
self.cFile = df.XDMFFile('%s_concentration.xdmf' % self.timestamp)
# time-variables
self.time = initTime
print('time=', self.time)
maxsteps = int(self.maxtime/self.timestep)
self.setup_initial_conditions(initc)
self.setup_weak_forms()
# if fresh run, write initial condition
if not extend:
self.cFile.write_checkpoint(self.c0, 'concentration', self.time)
for steps in progressbar.progressbar(range(1, maxsteps+1)):
self.time += self.timestep
print('time=', self.time)
df.solve(self.form == 0, self.c)
self.cFile.write_checkpoint(self.c, 'concentration',
self.time, append=True)
print('c=', self.c.compute_vertex_values(self.mesh))
self.c0.assign(self.c)
self.cFile.close()
RUN CODE:
import os
from extend_for_diffusion import diffusion
import argparse
import dolfin as df
import h5py
parser = argparse.ArgumentParser()
parser.add_argument('-j','--jsonfile', help='data file',
default='parameters.json')
parser.add_argument('-t','--time', help='time to run', type=float)
args = parser.parse_args()
assert os.path.isfile(args.jsonfile), '%s file not found' % args.jsonfile
# load the parameters
with open(args.jsonfile) as jsonFile:
parameters = json.load(jsonFile)
if args.jsonfile=='parameters.json':
extend = False
print('Fresh run...')
timestamp = datetime.datetime.now().strftime("%d%m%y-%H%M%S")
parameters['timestamp'] = timestamp
parametersFile = timestamp + '_parameters.json'
initc = None
initTime = 0.0
else:
extend = True
print('Extending run...')
parametersFile = args.jsonfile
steps = int(parameters['maxtime']/parameters['timestep'])
mesh = df.IntervalMesh(parameters['resolution'],
- parameters['L']/2,
parameters['L']/2)
# Read data
var = 'concentration'
h5 = h5py.File( '%s_%s.h5' % (parameters['timestamp'], var))
SFS = df.FunctionSpace(mesh, 'P', 1)
initc = df.Function(SFS)
cFile = df.XDMFFile('%s_concentration.xdmf' % parameters['timestamp'])
cFile.read_checkpoint(initc, 'concentration', steps)
cFile.close()
initTime = parameters['maxtime']
parameters['maxtime'] = args.time
diff = diffusion(parameters)
diff.solve(initc, initTime, extend)
if extend:
parameters['maxtime'] = initTime + parameters['maxtime']
with open(parametersFile, "w") as jsonFile:
json.dump(parameters, jsonFile, indent=4, sort_keys=True)
PARAMETERS JSONFILE:
"resolution": 10,
"L": 1.0,
"D": 0.1,
"timestep": 0.1,
"maxtime": 0.5
}