Beispiel #1
0
def _write_to_pvd_file(fun, directory, filename, suffix, components=None):
    if components is not None:
        filename = filename + "_component_" + "".join(components)
    fun_rank = fun.value_rank()
    fun_dim = product(fun.value_shape())
    assert fun_rank <= 2
    if ((fun_rank is 1 and fun_dim not in (2, 3))
            or (fun_rank is 2 and fun_dim not in (4, 9))):
        funs = fun.split(deepcopy=True)
        for (i, fun_i) in enumerate(funs):
            if components is not None:
                filename_i = filename + "_subcomponent_" + str(i)
            else:
                filename_i = filename + "_component_" + str(i)
            _write_to_pvd_file(fun_i, directory, filename_i, suffix)
    else:
        full_filename = os.path.join(str(directory), filename + ".pvd")
        if suffix is not None:
            if full_filename in _all_pvd_files:
                assert _all_pvd_latest_suffix[full_filename] == suffix - 1
                _all_pvd_latest_suffix[full_filename] = suffix
            else:
                assert suffix == 0
                _all_pvd_files[full_filename] = File(full_filename,
                                                     "compressed")
                _all_pvd_latest_suffix[full_filename] = 0
                _all_pvd_functions[full_filename] = fun.copy(deepcopy=True)
            # Make sure to always use the same function, otherwise dolfin
            # changes the numbering and visualization is difficult in ParaView
            assign(_all_pvd_functions[full_filename], fun)
            _all_pvd_files[full_filename] << _all_pvd_functions[full_filename]
        else:
            file_ = File(full_filename, "compressed")
            file_ << fun
Beispiel #2
0
def save_results_wrapper(PROJECT_ROOT, subFolder, u, p, w, subdomains, boundaries):
    velocityVisuPath = os.path.join(PROJECT_ROOT, 'src', 'Results', subFolder, 'Visualization', 'velocity.pvd')
    File(velocityVisuPath) << u

    pressureVisuPath = os.path.join(PROJECT_ROOT, 'src', 'Results', subFolder, 'Visualization', 'pressure.pvd')
    File(pressureVisuPath) << p

    resultsH5Path = os.path.join(PROJECT_ROOT, 'Results', subFolder, 'solution.h5')
    save_results_hdf5(resultsH5Path, subdomains, boundaries, w)
Beispiel #3
0
def save_meshfiles_wrapper(PROJECT_ROOT, subFolder, mesh, subdomains, boundaries):
    filePath = os.path.join(PROJECT_ROOT, 'src', 'MeshFiles', 'mesh.h5')
    mesh_to_h5(filePath, mesh, subdomains, boundaries)

    meshVisuPath = os.path.join(PROJECT_ROOT, 'src', 'MeshFiles', subFolder, 'Visualization', 'mesh.pvd')
    File(meshVisuPath) << mesh

    sudomainsVisuPath = os.path.join(PROJECT_ROOT, 'src', 'MeshFiles', subFolder, 'Visualization', 'subdomains.pvd')
    File(sudomainsVisuPath) << subdomains

    boundariesVisuPath = os.path.join(PROJECT_ROOT, 'src', 'MeshFiles', subFolder, 'Visualization', 'boundaries.pvd')
    File(boundariesVisuPath) << boundaries
Beispiel #4
0
def store_parameters(parameters):
    "Store parameters to file and return filename"

    # Save to file application_parameters.xml
    file = File("application_parameters.xml")
    file << parameters

    # Save to file <output_directory>/application_parameters.xml
    filename = "%s/application_parameters.xml" % parameters["output_directory"]
    file = File(filename)
    file << parameters

    return filename
Beispiel #5
0
    def __init__(self, meshes, facetfunctions, cover_points, bc_dict,
                 move_dict, length_width):
        """
        Solve the stokes problem with multiple meshes.
        Arguments:
           meshes: List of dolfin meshes, in the order they should be added 
                   to the multimesh
           facetfunctions: List of FacetFunctions corresponding to the
                   meshes above
           cover_points: 
                   dict where the key is the mesh that should get covered cells,
                   value is at which point auto_cover should start
           bc_dict: Dictionary describing boundary conditions for the Stokes
                    problem
           move_dict: Dictionary describing which node that will be fixed and 
                   which are design variables in the optimization problem
           length_width: List containing the length and width of channel
                   without an obstacle. Needed to compute barycenter of 
                   obstacle
        """
        self.__init_multimesh(meshes, cover_points)
        self.mfs = facetfunctions
        self.move_dict = move_dict
        self.V2 = VectorElement("CG", meshes[0].ufl_cell(), 2)
        self.S1 = FiniteElement("CG", meshes[0].ufl_cell(), 1)
        self.VQ = MultiMeshFunctionSpace(self.multimesh, self.V2 * self.S1)
        V = MultiMeshFunctionSpace(self.multimesh, self.V2)
        Q = MultiMeshFunctionSpace(self.multimesh, self.S1)
        self.__init_bcs(bc_dict)
        self.w = MultiMeshFunction(self.VQ, name="State")
        self.u = MultiMeshFunction(V, name="u")
        self.p = MultiMeshFunction(Q, name="p")

        self.f = Constant([0.] * self.multimesh.part(0).geometric_dimension())
        self.N = len(meshes)
        self.backup = [
            self.multimesh.part(i).coordinates().copy()
            for i in range(1, self.N)
        ]

        self.outu = [File("output/u_%d.pvd" % i) for i in range(self.N)]
        self.outp = [File("output/p_%d.pvd" % i) for i in range(self.N)]
        self.J = 0
        self.dJ = 0
        self.opt_it = 0
        self.vfac = 5e4
        self.bfac = 5e4
        self.length_width = length_width
        self.__init_geometric_quantities()
    def solve(self, opt):
        """ This procedure implements a first-order
        semi-Lagrangian time-stepping scheme to solve a parabolic
        second-order HJB equation in non-variational form
        - du/dt - sup_gamma{a^gamma : D^2 u + b^gamma * D u + c^gamma * u - f^gamma}= 0
        """

        if hasattr(self, 'dt'):
            opt["timeSteps"] *= opt["timeStepFactor"]

        nt = opt["timeSteps"]
        nc = len(self.gamma)

        Tspace = np.linspace(self.T[1], self.T[0], nt + 1)
        self.dt = (self.T[1] - self.T[0]) / nt
        self.u_np1 = Function(self.V)

        print('Setting final time conditions')
        assign(self.u, project(self.u_T, self.V))

        if opt["saveSolution"]:
            file_u = File('./pvd/u.pvd')
            file_gamma = []
            for i in range(nc):
                file_gamma.append(File('./pvd/gamma_{}.pvd'.format(i)))

        for i, s in enumerate(Tspace[1:]):
            self.current_time = s
            print('Iteration {}/{}:\t t = {}'.format(i + 1, nt, s))
            self.iter = i

            # Update time in coefficient functions
            self.updateTime(s)

            assign(self.u_np1, self.u)
            # Solve problem for current time step
            super().solve(opt)
            # self.plotControl()
            # self.plotSolution()

            if opt["saveSolution"]:
                file_u << self.u
                for i in range(nc):
                    try:
                        file_gamma[i] << self.gamma[i]
                    except AttributeError:
                        file_gamma[i] << project(self.gamma[i],
                                                 self.controlSpace[i])
Beispiel #7
0
   def __init__(self, mesh, mf, bc_dict, move_dict):
       """
       Inititalize Stokes solver with a mesh, its corresponding facet function,
       a dictionary describing boundary conditions and 
       a dictionary describing which boundaries are fixed in the shape optimization setting
       """
       self.mesh = mesh
       self.backup = mesh.coordinates().copy()
       self.mf = mf
       V2 = VectorElement("CG", mesh.ufl_cell(), 2)
       S1 = FiniteElement("CG", mesh.ufl_cell(), 1)
       TH = V2 * S1
       self.VQ = FunctionSpace(self.mesh, TH)
       self.w = Function(self.VQ)
       self.f = Constant([0.]*mesh.geometric_dimension())
       self.S = VectorFunctionSpace(self.mesh, "CG", 1)
       self.move_dict = move_dict
       self.J = 0
       self._init_bcs(bc_dict)
       self.solve()
       self.vfac = 1e4
       self.bfac = 1e2
       self._init_geometric_functions()
       self.eval_current_J()
       self.eval_current_dJ()
       self.outfile = File("output/u_singlemesh.pvd")
       self.outfile << self.u
       self.gradient_scale = 1
 
       self.iteration_counter = 1
       self.create_mapping_for_moving_boundary()
Beispiel #8
0
 def plot_vtk(self, variable, index=0):
     """Plot variable in vtk file given by filename"""
     self._check_outdir()
     self._check_varname()
     fname = self.varname + '_{0}'.format(index)
     File(self.outdir + fname + '.pvd') << variable
     (self.indices).append(index)
Beispiel #9
0
	def setOutputPath(self, outputPath):
		"""Set outut directory for saving the function state. Usually is done automatically by the simulator.

		Args:
			outputPath(:obj:`str`): A path to the output directory.
		"""
		self.file = File( os.path.join(outputPath, "{0}.pvd".format(self.userName) ))
Beispiel #10
0
def test_ect_current():
    """Test that the Neumann BC on the extracellular potential is applied correctly."""
    time = Constant(0)
    T = 1e-1
    dt = 1e-5
    mesh = UnitSquareMesh(75, 75)
    ect_current = Expression(
        "std::abs(sin(2*pi*70*t)) > 0.8 ? 800*(x[0] < 0.5 && x[1] < 0.5)*(t < t0) : 0",
        t=time,
        t0=10,
        degree=1)
    model = Wei()
    brain = CardiacModel(mesh, time, 0.1, 0.3, model, ect_current=ect_current)
    params = SplittingSolver.default_parameters()

    ps = SplittingSolver.default_parameters()
    ps["pde_solver"] = "bidomain"  # TODO: parametrise mono/bi
    ps["BidomainSolver"]["linear_solver_type"] = "direct"
    ps["theta"] = 0.5  # TODO: parametrise theta
    solver = SplittingSolver(brain, params=ps)

    vs_, vs, _ = solver.solution_fields()
    assert False, "Use the other weimodel initial conditions."
    vs_.assign(model.initial_conditions())

    solutions = solver.solve((0, T), dt)
    outfile = File("ect_testdir/v.pvd")
    counter = 0
    for interval, (vs_, vs, _) in solutions:
        print(counter)
        v, *_ = vs.split()
        outfile << v
        counter += 1
Beispiel #11
0
def as_pvd(h5_file):
    '''Store facet and cell function for pvd'''
    root, ext = os.path.splitext(h5_file)

    mesh = Mesh()
    hdf = HDF5File(mesh.mpi_comm(), h5_file, 'r')
    hdf.read(mesh, '/mesh', False)

    facet_markers = FacetFunction('size_t', mesh)
    hdf.read(facet_markers, '/facet_markers')

    cell_markers = CellFunction('size_t', mesh)
    hdf.read(cell_markers, '/cell_markers')

    File(root + 'facets' + '.pvd') << facet_markers
    File(root + 'volumes' + '.pvd') << cell_markers

    return True
Beispiel #12
0
    def build(self, accuracy=5, cache=False):
        if cache and os.path.exists(self._cache_path):
            self._mesh2d = DolfinMesh(self._cache_path)
            return

        self._mesh2d = mshr.generate_mesh(self._map, accuracy)

        if cache:
            f = File(self._cache_path)
            f << self._mesh2d
Beispiel #13
0
    def Save(self, func, filename, subfolder="",val=0,file=None,filetype="default"):
        """
        This function is used to save the various dolfin.Functions created
        by windse. It should only be accessed internally.

        Args:
            func (dolfin.Function): The Function to be saved
            filename (str): the name of the function

        :Keyword Arguments:
            * **subfolder** (*str*): where to save the files within the output folder
            * **n** (*float*): used for saving a series of output. Use n=0 for the first save.

        """
        self.fprint("Saving: {0}".format(filename))

        ### Name the function in the meta data, This should probably be done at creation
        func.rename(filename,filename)

        if filetype == "default":
            filetype = self.save_file_type

        if file is None:
            ### Make sure the folder exists
            if not os.path.exists(self.folder+subfolder): os.makedirs(self.folder+subfolder)

            if filetype == "pvd":
                file_string = self.folder+subfolder+filename+".pvd"
                out = File(file_string)
                out << (func,val)
            elif filetype == "xdmf":
                file_string = self.folder+subfolder+filename+".xdmf"
                out = XDMFFile(file_string)
                out.write(func,val)

            return out

        else:
            if filetype == "pvd" or isinstance(func,type(Mesh)):
                file << (func,val)
            elif filetype == "xdmf":
                file.write(func,val)
Beispiel #14
0
def store_parameters(p, problem, case):
    "Store parameters to file and return filename"

    # Set output directory
    if p["output_directory"] == "unspecified":
        if case is None:
            p["output_directory"] = "results-%s-%s" % (problem, date())
        else:
            p["output_directory"] = "results-%s-%s" % (problem, str(case))

    # Save to file application_parameters.xml
    file = File("application_parameters.xml")
    file << p

    # Save to file <output_directory>/application_parameters.xml
    filename = "%s/application_parameters.xml" % p["output_directory"]
    file = File(filename)
    file << p

    return filename
Beispiel #15
0
def savingPreparation(paraFullPath, ParaViewFilenames):
    from dolfin import File

    # Create New Result Files (Paraview Files: .pvd)
    fileNames = []
    paraFiles = []
    for i in range(0, len(
            ParaViewFilenames)):  # ParaViewFilenames defined in Problem Imputs
        fileNames.append(ParaViewFilenames[i] + ".pvd")
        paraFiles.append(File(paraFullPath + fileNames[i]))

    return paraFiles
Beispiel #16
0
    def write(self, comm, filename="muflon-parameters.xml"):
        """
        Write parameters to XML file.

        :param comm: MPI communicator
        :type comm: :py:class:`dolfin.MPI_Comm`
        :param filename: name of the output XML file (can be relative or
                         absolute path)
        :type filename: str
        """
        filename += ".xml" if filename[-4:] != ".xml" else ""
        log(DEBUG, "Writing current parameter values into '%s'." % filename)
        from dolfin import DOLFIN_VERSION_MAJOR, DOLFIN_VERSION_MINOR
        if DOLFIN_VERSION_MAJOR >= 2017 and DOLFIN_VERSION_MINOR >= 2:
            with File(filename) as xmlfile:
                xmlfile << self
        elif MPI.rank(comm) == 0: # FIXME: remove this backporting
            with File(filename) as xmlfile:
                xmlfile << self
        else:
            return
Beispiel #17
0
def _read_from_xml_file(fun, directory, filename, suffix):
    if suffix is not None:
        filename = filename + "." + str(suffix)
    full_filename = os.path.join(str(directory), filename + ".xml")
    file_exists = False
    if is_io_process() and os.path.exists(full_filename):
        file_exists = True
    file_exists = is_io_process.mpi_comm.bcast(file_exists,
                                               root=is_io_process.root)
    if file_exists:
        file_ = File(full_filename)
        file_ >> fun
    return file_exists
Beispiel #18
0
 def _update_pvd_file(self, field_name, saveformat, data, timestep, t):
     "Update pvd file with new data."
     assert isinstance(data, Function)
     assert saveformat == "pvd"
     fullname, metadata = self._get_datafile_name(field_name, saveformat,
                                                  timestep)
     key = (field_name, saveformat)
     datafile = self._datafile_cache.get(key)
     if datafile is None:
         datafile = File(fullname)
         self._datafile_cache[key] = datafile
     datafile << data
     return metadata
Beispiel #19
0
    def _update_xml_gz_file(self, field_name, saveformat, data, timestep, t):
        "Create new xml.gz file for current timestep with new data."
        assert saveformat == "xml.gz"
        fullname, metadata = self._get_datafile_name(field_name, saveformat,
                                                     timestep)
        meshfile = os.path.join(self.get_savedir(field_name), "mesh.hdf5")
        if not os.path.isfile(meshfile):
            hdf5file = HDF5File(mpi_comm_world(), meshfile, 'w')
            hdf5file.write(data.function_space().mesh(), "Mesh")
            del hdf5file
        datafile = File(fullname)
        datafile << data

        return metadata
Beispiel #20
0
    def read(self, filename="muflon-parameters.xml"):
        """
        Read parameters from XML file.

        :param filename: name of the input XML file (can be relative or
                         absolute path)
        :type filename: str
        """
        filename += ".xml" if filename[-4:] != ".xml" else ""
        if os.path.isfile(filename) and os.access(filename, os.R_OK):
            log(DEBUG, "Reading default values from '%s'" % filename)
            with File(filename) as xmlfile:
                xmlfile >> self
        else:
            log(DEBUG, "File '%s' is missing or not readable." % filename)
Beispiel #21
0
def read_parameters():
    """Read parametrs from file specified on command-line or return
    default parameters if no file is specified"""

    # Read parameters from the command-line
    import sys
    p = default_parameters()
    try:
        file = File(sys.argv[1])
        file >> p
        info("Parameters read from %s." % sys.argv[1])
    except:
        info("No parameters specified, using default parameters.")

    # Set output directory
    if p["output_directory"] == "unspecified":
        p["output_directory"] = "results-%s" % date()

    # Save to file <output_directory>/application_parameters.xml
    filename = "%s/application_parameters.xml" % p["output_directory"]
    file = File(filename)
    file << p

    return p
Beispiel #22
0
 def _export_vtk(self, solution, filename, output_options={}):
     if not "With mesh motion" in output_options:
         output_options["With mesh motion"] = False
     if not "With preprocessing" in output_options:
         output_options["With preprocessing"] = False
     #
     file = File(filename + ".pvd", "compressed")
     if output_options["With mesh motion"]:
         self.move_mesh()  # deform the mesh
     if output_options["With preprocessing"]:
         preprocessed_solution = self.preprocess_solution_for_plot(solution)
         file << preprocessed_solution
     else:
         file << solution
     if output_options["With mesh motion"]:
         self.reset_reference()  # undo mesh motion
Beispiel #23
0
 def save_eigenvectors(self,n,file_name="output/modes.pvd",save_imaginary=False):
     eigenvalues = [] 
     eigenvectors = [] 
     file = File(self.comm,file_name)
     for i in range(n):
         eig, u_r, u_im = self.get_eigenpair(i)
         u_r.rename("mode real","mode real")
         file.write(u_r,i)
         if save_imaginary:
             u_im.rename("mode imaginary","mode imaginary")
             file.write(u_im,i)            
     return file_name
Beispiel #24
0
	def __init__(self, name, functionSpace0 = None, function = None, functionSpace = None):
		
		self.userName = name
		self.file = File(os.path.join( sys.path[0], "{0}.pvd".format(self.userName) ))

		if function:
			super().__init__(function.function_space(), function.vector())
		elif functionSpace:
			super().__init__(functionSpace)
		else:
			raise Exception("Either function or functionSpace must be supplied.")
		
		self.functionSpace0 = None
		if functionSpace0:
			self.functionSpace0 = functionSpace0
			self.initial = Function(functionSpace0, self.vector())

		self.functionSpace = self.function_space()
Beispiel #25
0
 def _write(self, filename, encoding=None):
     assert filename.endswith(".rtc.xml") or filename.endswith(".rtc.xdmf")
     # Create output folder
     try:
         os.makedirs(filename)
     except OSError:
         if not os.path.isdir(filename):
             raise
     # Write out MeshFunctions
     for (d, mesh_function_d) in enumerate(self):
         if filename.endswith(".rtc.xml"):
             File(filename + "/mesh_function_" + str(d) + ".xml") << mesh_function_d
         else:
             xdmf_file = XDMFFile(filename + "/mesh_function_" + str(d) + ".xdmf")
             if encoding is not None:
                 xdmf_file.write(mesh_function_d, encoding)
             else:
                 xdmf_file.write(mesh_function_d)
Beispiel #26
0
    def exportU(self, Vh, fname, varname="evect", normalize=1):
        """
        Export in paraview the generalized eigenvectors U.
        Inputs:
        - Vh:        the parameter finite element space
        - fname:     the name of the paraview output file
        - varname:   the name of the paraview variable
        - normalize: if True the eigenvector are rescaled such that || u ||_inf = 1 
        """
        evect = Function(Vh, name=varname)
        fid = File(fname)

        for i in range(0, self.U.shape[1]):
            Ui = self.U[:, i]
            if normalize:
                s = 1 / np.linalg.norm(Ui, np.inf)
                evect.vector().set_local(s * Ui)
            else:
                evect.vector().set_local(Ui)
            fid << evect
    def create_output(self, fname):
        args = self.args
        parameters = self.parameters
        self.signature = hashlib.md5(
            str(parameters).encode('utf-8')).hexdigest()
        print('Signature is: ', self.signature)
        regime = self.p
        if args.outdir == None:
            outdir = "output/{:s}-{}{}".format(fname, self.signature,
                                               args.postfix)
        else:
            outdir = args.outdir

        self.outdir = outdir
        Path(outdir).mkdir(parents=True, exist_ok=True)
        print('Outdir is: ', outdir)
        print('Output in: ',
              os.path.join(outdir, fname + 'p-' + regime + '.xdmf'))
        print('P-proc in: ',
              os.path.join(outdir, fname + 'p-' + regime + '_pproc.xdmf'))

        file_results = XDMFFile(
            os.path.join(outdir, fname + 'p-' + regime + '.xdmf'))
        file_results.parameters["flush_output"] = True
        file_results.parameters["functions_share_mesh"] = True

        file_pproc = XDMFFile(
            os.path.join(outdir, fname + 'p-' + regime + '_pproc.xdmf'))
        file_pproc.parameters["flush_output"] = True
        file_pproc.parameters["functions_share_mesh"] = True

        file_mesh = File(
            os.path.join(outdir, fname + 'p-' + regime + "_mesh.xml"))

        with open(os.path.join(outdir, 'parameters.pkl'), 'w') as f:
            json.dump(parameters, f)
        print('DEBUG: pproc file',
              os.path.join(outdir, fname + 'p-' + regime + '_pproc.xdmf'))
        return file_results, file_pproc, file_mesh
    def solve(self, opt):
        """ This procedure implements a first-order
        semi-Lagrangian time-stepping scheme to solve a parabolic
        second-order PDE in non-variational form
                - du/dt - (a : D^2 u + b * D u + c * u )  =  - f
        <==>    - du/dt - (a : D^2 u + b * D u + c * u - f ) = 0
        """

        if hasattr(self, 'dt'):
            opt["timeSteps"] *= opt["timeStepFactor"]
        nt = opt["timeSteps"]

        Tspace = np.linspace(self.T[1], self.T[0], nt + 1)
        self.dt = (self.T[1] - self.T[0]) / nt
        self.u_np1 = Function(self.V)

        if opt["saveSolution"]:
            file_u = File('./pvd/u.pvd')

        print('Setting final time conditions')
        assign(self.u, project(self.u_T, self.V))
        if opt["saveSolution"]:
            file_u << self.u

        for i, s in enumerate(Tspace[1:]):

            print('Iteration {}/{}:\t t = {}'.format(i + 1, nt, s))
            self.iter = i

            # Update time in coefficient functions
            self.updateTime(s)

            assign(self.u_np1, self.u)

            # Solve problem for current time step
            super().solve(opt)

            if opt["saveSolution"]:
                file_u << self.u
 def export(self, Vh, filename, varname="mv", normalize=False):
     """
     Export in paraview this multivector
     Inputs:
     - Vh:        the parameter finite element space
     - filename:  the name of the paraview output file
     - varname:   the name of the paraview variable
     - normalize: if True the vector are rescaled such that || u ||_inf = 1 
     """
     fid = File(filename)
     if not normalize:
         for i in range(self.nvec()):
             fun = vector2Function(self[i], Vh, name=varname)
             fid << fun
     else:
         tmp = self[0].copy()
         for i in range(self.nvec()):
             s = self[i].norm("linf")
             tmp.zero()
             tmp.axpy(1. / s, self[i])
             fun = vector2Function(tmp, Vh, name=varname)
             fid << fun
Beispiel #30
0
def collect_timings(outdir, tic):

    # list_timings(TimingClear.keep, [TimingType.wall, TimingType.system])

    # t = timings(TimingClear.keep, [TimingType.wall, TimingType.user, TimingType.system])
    t = timings(TimingClear.keep, [TimingType.wall])
    # Use different MPI reductions
    t_sum = MPI.sum(MPI.comm_world, t)
    # t_min = MPI.min(MPI.comm_world, t)
    # t_max = MPI.max(MPI.comm_world, t)
    t_avg = MPI.avg(MPI.comm_world, t)
    # Print aggregate timings to screen
    print('\n' + t_sum.str(True))
    # print('\n'+t_min.str(True))
    # print('\n'+t_max.str(True))
    print('\n' + t_avg.str(True))

    # Store to XML file on rank 0
    if MPI.rank(MPI.comm_world) == 0:
        f = File(MPI.comm_self, os.path.join(outdir, "timings_aggregate.xml"))
        f << t_sum
        # f << t_min
        # f << t_max
        f << t_avg

    dump_timings_to_xml(os.path.join(outdir, "timings_avg_min_max.xml"),
                        TimingClear.clear)
    elapsed = time.time() - tic

    comm = mpi4py.MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()

    if rank == 0:
        with open(os.path.join(outdir, 'timings.pkl'), 'w') as f:
            json.dump({'elapsed': elapsed, 'size': size}, f)

    pass