예제 #1
0
def run_reference(Tend):
    """
    Routine to run particular SDC variant

    Args:
        Tend (float): end time for dumping
    """

    # load (incomplete) default parameters
    description, controller_params = setup_parameters_FFT()

    # setup parameters "in time"
    t0 = 0

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=1,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # filter statistics by variant (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(
        np.std(niters)), float(np.var(niters)))
    print(out)

    timing = sort_stats(filter_stats(stats, type='timing_run'), sortby='time')

    print('Time to solution: %6.4f sec.' % timing[0][1])
    print()

    computed_radii_tmp = sort_stats(filter_stats(stats,
                                                 type='computed_radius'),
                                    sortby='time')
    computed_radii = np.array([item0[1] for item0 in computed_radii_tmp])
    print(len(computed_radii_tmp), len(computed_radii))

    fname = 'data/AC_reference_FFT_Tend{:.1e}'.format(Tend)
    np.savez_compressed(file=fname, uend=uend.values, radius=computed_radii)
예제 #2
0
def run_diffusion(QI):
    """
    A simple test program to test PFASST convergence for the heat equation with random initial data

    Args:
        QI: preconditioner
    """

    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-08
    level_params['nsweeps'] = [3, 1]

    # initialize sweeper parameters
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = [3]
    sweeper_params['QI'] = [QI, 'LU']
    sweeper_params['spread'] = False

    # initialize problem parameters
    problem_params = dict()
    problem_params['nu'] = 0.1  # diffusion coefficient
    problem_params['freq'] = -1  # frequency for the test value
    problem_params['nvars'] = [127, 63
                               ]  # number of degrees of freedom for each level

    # initialize step parameters
    step_params = dict()
    step_params['maxiter'] = 200

    # initialize space transfer parameters
    space_transfer_params = dict()
    space_transfer_params['rorder'] = 2
    space_transfer_params['iorder'] = 2
    space_transfer_params['periodic'] = False

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 30
    controller_params['predict'] = False

    # fill description dictionary for easy step instantiation
    description = dict()
    description['problem_class'] = heat1d  # pass problem class
    description['problem_params'] = problem_params  # pass problem parameters
    description['dtype_u'] = mesh  # pass data type for u
    description['dtype_f'] = mesh  # pass data type for f
    description[
        'sweeper_class'] = generic_implicit  # pass sweeper (see part B)
    description['sweeper_params'] = sweeper_params  # pass sweeper parameters
    description['step_params'] = step_params  # pass step parameters
    description[
        'space_transfer_class'] = mesh_to_mesh  # pass spatial transfer class
    description[
        'space_transfer_params'] = space_transfer_params  # pass paramters for spatial transfer

    # set time parameters
    t0 = 0.0
    Tend = 1.0

    # set up number of parallel time-steps to run PFASST with

    fname = 'data/results_conv_diffusion_Linf_QI' + str(QI) + '.txt'
    file = open(fname, 'w')
    writer = csv.writer(file)
    writer.writerow(('num_proc', 'niter'))
    file.close()

    for i in range(0, 13):

        num_proc = 2**i
        level_params['dt'] = (Tend - t0) / num_proc
        description['level_params'] = level_params  # pass level parameters

        out = 'Working on num_proc = %5i' % num_proc
        print(out)
        cfl = problem_params['nu'] * level_params['dt'] / (
            1.0 / (problem_params['nvars'][0] + 1))**2
        out = '  CFL number: %4.2e' % cfl
        print(out)

        # instantiate controller
        controller = allinclusive_multigrid_nonMPI(
            num_procs=num_proc,
            controller_params=controller_params,
            description=description)

        # get initial values on finest level
        P = controller.MS[0].levels[0].prob
        uinit = P.u_exact(t0)

        # call main function to get things done...
        uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

        # filter statistics by type (number of iterations)
        filtered_stats = filter_stats(stats, type='niter')

        # convert filtered statistics to list of iterations count, sorted by process
        iter_counts = sort_stats(filtered_stats, sortby='time')

        niters = np.array([item[1] for item in iter_counts])

        out = '  Mean number of iterations: %4.2f' % np.mean(niters)
        print(out)

        file = open(fname, 'a')
        writer = csv.writer(file)
        writer.writerow((num_proc, np.mean(niters)))
        file.close()

    assert os.path.isfile(fname), 'ERROR: pickle did not create file'
예제 #3
0
def run_SDC_variant(variant=None, inexact=False, cwd=''):
    """
    Routine to run particular SDC variant

    Args:
        variant (str): string describing the variant
        inexact (bool): flag to use inexact nonlinear solve (or nor)
        cwd (str): current working directory

    Returns:
        timing (float)
        niter (float)
    """

    # load (incomplete) default parameters
    description, controller_params = setup_parameters()

    # add stuff based on variant
    if variant == 'fully-implicit':
        description['problem_class'] = petsc_grayscott_fullyimplicit
        description['dtype_f'] = petsc_data
        description['sweeper_class'] = generic_implicit
    elif variant == 'semi-implicit':
        description['problem_class'] = petsc_grayscott_semiimplicit
        description['dtype_f'] = rhs_imex_petsc_data
        description['sweeper_class'] = imex_1st_order
    elif variant == 'multi-implicit':
        description['problem_class'] = petsc_grayscott_multiimplicit
        description['dtype_f'] = rhs_2comp_petsc_data
        description['sweeper_class'] = multi_implicit
    else:
        raise NotImplemented('Wrong variant specified, got %s' % variant)

    if inexact:
        description['problem_params']['lsol_maxiter'] = 2
        description['problem_params']['nlsol_maxiter'] = 1
        out = 'Working on inexact %s variant...' % variant
    else:
        out = 'Working on exact %s variant...' % variant
    print(out)

    # set time parameters
    t0 = 0.0
    Tend = 1.0

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=1,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # load reference solution to compare with
    fname = cwd + 'data/GS_reference.dat'
    viewer = PETSc.Viewer().createBinary(fname, 'r')
    uex = P.u_exact(t0)
    uex.values = PETSc.Vec().load(viewer)
    err = abs(uex - uend)

    # filter statistics by variant (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(
        np.std(niters)), float(np.var(niters)))
    print(out)

    print('Iteration count (nonlinear/linear): %i / %i' %
          (P.snes_itercount, P.ksp_itercount))
    print('Mean Iteration count per call: %4.2f / %4.2f' %
          (P.snes_itercount / max(P.snes_ncalls, 1),
           P.ksp_itercount / max(P.ksp_ncalls, 1)))

    timing = sort_stats(filter_stats(stats, type='timing_run'), sortby='time')

    print('Time to solution: %6.4f sec.' % timing[0][1])
    print('Error vs. reference solution: %6.4e' % err)
    print()

    assert err < 3E-06, 'ERROR: variant %s did not match error tolerance, got %s' % (
        variant, err)
    assert np.mean(
        niters
    ) <= 10, 'ERROR: number of iterations is too high, got %s' % np.mean(
        niters)

    return timing[0][1], np.mean(niters)
예제 #4
0
def run_reference():
    """
    Helper routine to create a reference solution using very high order SDC and small time-steps
    """

    description, controller_params = setup_parameters()

    description['problem_class'] = petsc_grayscott_semiimplicit
    description['dtype_f'] = rhs_imex_petsc_data
    description['sweeper_class'] = imex_1st_order
    description['sweeper_params']['num_nodes'] = 9
    description['level_params']['dt'] = 0.01

    # set time parameters
    t0 = 0.0
    Tend = 1.0

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=1,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # filter statistics by variant (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(
        np.std(niters)), float(np.var(niters)))
    print(out)

    print('Iteration count (nonlinear/linear): %i / %i' %
          (P.snes_itercount, P.ksp_itercount))
    print('Mean Iteration count per call: %4.2f / %4.2f' %
          (P.snes_itercount / max(P.snes_ncalls, 1),
           P.ksp_itercount / max(P.ksp_ncalls, 1)))

    timing = sort_stats(filter_stats(stats, type='timing_run'), sortby='time')

    print('Time to solution: %6.4f sec.' % timing[0][1])

    fname = 'data/GS_reference.dat'
    viewer = PETSc.Viewer().createBinary(fname, 'w')
    viewer.view(uend.values)

    assert os.path.isfile(fname), 'ERROR: PETSc did not create file'

    return None
예제 #5
0
def run_advection(nsweeps):
    """
    A simple test program to test PFASST convergence for the periodic advection equation

    Args:
        nsweeps: number of fine sweeps to perform
    """

    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-08
    level_params['dt'] = 0.25
    level_params['nsweeps'] = [nsweeps, 1]

    # initialize sweeper parameters
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = [3]
    sweeper_params['QI'] = [
        'LU'
    ]  # For the IMEX sweeper, the LU-trick can be activated for the implicit part
    sweeper_params['spread'] = False

    # initialize problem parameters
    problem_params = dict()
    problem_params['freq'] = 64  # frequency for the test value
    problem_params['nvars'] = [128, 64
                               ]  # number of degrees of freedom for each level
    problem_params['order'] = 2
    problem_params['type'] = 'center'

    # initialize step parameters
    step_params = dict()
    step_params['maxiter'] = 50

    # initialize space transfer parameters
    space_transfer_params = dict()
    space_transfer_params['rorder'] = 2
    space_transfer_params['iorder'] = 2
    space_transfer_params['periodic'] = True

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 30
    controller_params['predict'] = False

    # fill description dictionary for easy step instantiation
    description = dict()
    description['problem_class'] = advection1d  # pass problem class
    description['dtype_u'] = mesh  # pass data type for u
    description['dtype_f'] = mesh  # pass data type for f
    description[
        'sweeper_class'] = generic_implicit  # pass sweeper (see part B)
    description['sweeper_params'] = sweeper_params  # pass sweeper parameters
    description['level_params'] = level_params  # pass level parameters
    description['step_params'] = step_params  # pass step parameters
    description[
        'space_transfer_class'] = mesh_to_mesh  # pass spatial transfer class
    description[
        'space_transfer_params'] = space_transfer_params  # pass paramters for spatial transfer

    # set time parameters
    t0 = 0.0
    Tend = 4 * level_params['dt']

    # set up number of parallel time-steps to run PFASST with
    num_proc = 4

    results = dict()

    for i in range(-3, 12):
        ratio = level_params['dt'] / (1.0 / (problem_params['nvars'][0] + 1))

        problem_params['c'] = 10.0**i / ratio  # diffusion coefficient
        description[
            'problem_params'] = problem_params  # pass problem parameters

        out = 'Working on nu = %6.4e' % problem_params['c']
        print(out)
        cfl = ratio * problem_params['c']
        out = '  CFL number: %4.2e' % cfl
        print(out)

        # instantiate controller
        controller = allinclusive_multigrid_nonMPI(
            num_procs=num_proc,
            controller_params=controller_params,
            description=description)

        # get initial values on finest level
        P = controller.MS[0].levels[0].prob
        uinit = P.u_exact(t0)

        # call main function to get things done...
        uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

        # filter statistics by type (number of iterations)
        filtered_stats = filter_stats(stats, type='niter')

        # convert filtered statistics to list of iterations count, sorted by process
        iter_counts = sort_stats(filtered_stats, sortby='time')

        niters = np.array([item[1] for item in iter_counts])

        out = '  Mean number of iterations: %4.2f' % np.mean(niters)
        print(out)

        results[cfl] = np.mean(niters)

    fname = 'data/results_conv_advection_NS' + str(nsweeps) + '.pkl'
    file = open(fname, 'wb')
    pickle.dump(results, file)
    file.close()

    assert os.path.isfile(fname), 'ERROR: pickle did not create file'
예제 #6
0
def main():
    """
    A simple test program to do PFASST runs for the heat equation
    """

    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-10
    level_params['dt'] = 0.25

    # initialize sweeper parameters
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = 3
    sweeper_params[
        'QI'] = 'LU'  # For the IMEX sweeper, the LU-trick can be activated for the implicit part

    # initialize problem parameters
    problem_params = dict()
    problem_params['nu'] = 0.1  # diffusion coefficient
    problem_params['freq'] = 8  # frequency for the test value
    problem_params[
        'nvars'] = 511  # number of degrees of freedom for each level

    # initialize step parameters
    step_params = dict()
    step_params['maxiter'] = 50

    # initialize space transfer parameters
    space_transfer_params = dict()
    space_transfer_params['rorder'] = 2
    space_transfer_params['iorder'] = 2

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 20

    # fill description dictionary for easy step instantiation
    description = dict()
    description['problem_class'] = heat1d_forced  # pass problem class
    description['problem_params'] = problem_params  # pass problem parameters
    description['dtype_u'] = mesh  # pass data type for u
    description['dtype_f'] = rhs_imex_mesh  # pass data type for f
    description['sweeper_class'] = imex_1st_order  # pass sweeper
    description['sweeper_params'] = sweeper_params  # pass sweeper parameters
    description['level_params'] = level_params  # pass level parameters
    description['step_params'] = step_params  # pass step parameters
    description[
        'space_transfer_class'] = mesh_to_mesh  # pass spatial transfer class
    description[
        'space_transfer_params'] = space_transfer_params  # pass paramters for spatial transfer

    # set time parameters
    t0 = 0.0
    Tend = 4.0

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=1,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # The following is used only for statistics and output, the main show is over now..

    # compute exact solution and compare
    uex = P.u_exact(Tend)
    err = abs(uex - uend)

    print('\nError (vs. exact solution) at time %4.2f: %6.4e\n' % (Tend, err))

    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    for item in iter_counts:
        print('Number of iterations for time %4.2f: %2i' % item)

    niters = np.array([item[1] for item in iter_counts])

    print('   Mean number of iterations: %4.2f' % np.mean(niters))
    print('   Range of values for number of iterations: %2i ' % np.ptp(niters))
    print('   Position of max/min number of iterations: %2i -- %2i' %
          (int(np.argmax(niters)), int(np.argmin(niters))))
예제 #7
0
def compare_controllers(type=None, par=0.0, f=None):
    """
    A simple test program to compare PFASST runs with matrix-based and matrix-free controllers

    Args:
        type (str): setup type
        par (float) parameter for controlling stiffness
        f: file handler
    """

    # set time parameters
    t0 = 0.0
    Tend = 1.0

    if type == 'diffusion':
        description, controller_params = diffusion_setup(par)
    elif type == 'advection':
        description, controller_params = advection_setup(par)
    elif type == 'testequation':
        description, controller_params = testequation_setup()
    else:
        raise ValueError('No valis setup type provided, aborting..')

    out = '\nWorking with %s setup and parameter %3.1e..' % (type, par)
    f.write(out + '\n')
    print(out)

    # instantiate controller
    controller_mat = allinclusive_matrix_nonMPI(
        num_procs=4,
        controller_params=controller_params,
        description=description)

    controller_nomat = allinclusive_multigrid_nonMPI(
        num_procs=4,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller_nomat.MS[0].levels[0].prob
    uinit = P.u_exact(t0)
    uex = P.u_exact(Tend)

    # this is where the iteration is happening
    uend_mat, stats_mat = controller_mat.run(u0=uinit, t0=t0, Tend=Tend)
    uend_nomat, stats_nomat = controller_nomat.run(u0=uinit, t0=t0, Tend=Tend)

    diff = abs(uend_mat - uend_nomat)

    err_mat = abs(uend_mat - uex)
    err_nomat = abs(uend_nomat - uex)

    out = '  Error (mat/nomat) vs. exact solution: %6.4e -- %6.4e' % (
        err_mat, err_nomat)
    f.write(out + '\n')
    print(out)
    out = '  Difference between both results: %6.4e' % diff
    f.write(out + '\n')
    print(out)

    assert diff < 2.3E-15, 'ERROR: difference between matrix-based and matrix-free result is too large, got %s' % diff

    # filter statistics by type (number of iterations)
    filtered_stats_mat = filter_stats(stats_mat, type='niter')
    filtered_stats_nomat = filter_stats(stats_nomat, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts_mat = sort_stats(filtered_stats_mat, sortby='time')
    iter_counts_nomat = sort_stats(filtered_stats_nomat, sortby='time')

    out = '  Iteration counts for matrix-based version: %s' % iter_counts_mat
    f.write(out + '\n')
    print(out)
    out = '  Iteration counts for matrix-free version: %s' % iter_counts_nomat
    f.write(out + '\n')
    print(out)

    assert iter_counts_nomat == iter_counts_mat, \
        'ERROR: number of iterations differ between matrix-based and matrix-free controller'
예제 #8
0
def main():
    """
    A simple test program to do PFASST runs for the heat equation
    """

    # set up number of parallel time-steps to run PFASST with
    num_proc = 16

    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-08
    level_params['dt'] = 1.0 / num_proc
    level_params['nsweeps'] = [3, 1]

    # initialize sweeper parameters
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = [3]
    sweeper_params['QI'] = ['LU2', 'LU']  # For the IMEX sweeper, the LU-trick can be activated for the implicit part

    # initialize problem parameters
    problem_params = dict()
    problem_params['nu'] = 0.1  # diffusion coefficient
    problem_params['freq'] = -1  # frequency for the test value
    problem_params['nvars'] = [128, 64]  # number of degrees of freedom for each level

    # initialize step parameters
    step_params = dict()
    step_params['maxiter'] = 50

    # initialize space transfer parameters
    space_transfer_params = dict()
    space_transfer_params['rorder'] = 2
    space_transfer_params['iorder'] = 2
    space_transfer_params['periodic'] = True

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 30
    # controller_params['hook_class'] = error_output

    # fill description dictionary for easy step instantiation
    description = dict()
    description['problem_class'] = heat1d_periodic  # pass problem class
    description['problem_params'] = problem_params  # pass problem parameters
    description['dtype_u'] = mesh  # pass data type for u
    description['dtype_f'] = mesh  # pass data type for f
    description['sweeper_class'] = generic_implicit  # pass sweeper (see part B)
    description['sweeper_params'] = sweeper_params  # pass sweeper parameters
    description['level_params'] = level_params  # pass level parameters
    description['step_params'] = step_params  # pass step parameters
    description['space_transfer_class'] = mesh_to_mesh  # pass spatial transfer class
    description['space_transfer_params'] = space_transfer_params  # pass paramters for spatial transfer

    # set time parameters
    t0 = 0.0
    Tend = 1.0

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(num_procs=num_proc, controller_params=controller_params,
                                               description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # compute exact solution and compare
    uex = P.u_exact(Tend)
    err = abs(uex - uend)

    # filter statistics by type (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    for item in iter_counts:
        out = 'Number of iterations for time %4.2f: %2i' % item
        print(out)

    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(np.std(niters)), float(np.var(niters)))
    print(out)

    print('CFL number: %4.2f' % (level_params['dt'] * problem_params['nu'] / (1.0 / problem_params['nvars'][0])**2))
    print('Error: %8.4e' % err)
예제 #9
0
def main():
    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-10
    level_params['dt'] = None

    # This comes as read-in for the step class (this is optional!)
    step_params = dict()
    step_params['maxiter'] = None

    # This comes as read-in for the problem class
    problem_params = dict()
    problem_params['nu'] = 0.01
    problem_params['freq'] = 2
    problem_params['nvars'] = [2**7, 2**6]

    # This comes as read-in for the sweeper class
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = [5]
    sweeper_params['QI'] = ['IE', 'PIC']
    sweeper_params['spread'] = False
    sweeper_params['do_coll_update'] = False

    # initialize space transfer parameters
    space_transfer_params = dict()
    space_transfer_params['rorder'] = 2
    space_transfer_params['iorder'] = 6
    space_transfer_params['periodic'] = True

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 20
    controller_params['predict'] = False

    # Fill description dictionary for easy hierarchy creation
    description = dict()
    description['problem_class'] = heat1d_periodic
    description['dtype_u'] = mesh
    description['dtype_f'] = mesh  #rhs_imex_mesh
    description['sweeper_class'] = generic_implicit  #imex_1st_order
    description['sweeper_params'] = sweeper_params
    description['step_params'] = step_params
    description['level_params'] = level_params
    description['problem_params'] = problem_params
    description[
        'space_transfer_class'] = mesh_to_mesh  # pass spatial transfer class
    description[
        'space_transfer_params'] = space_transfer_params  # pass paramters for spatial transfer

    # setup parameters "in time"
    t0 = 0.0
    Tend = 1.0

    dt_list = [Tend / 2**i for i in range(0, 6)]
    niter_list = [100]  #[1, 2, 3, 4]

    for niter in niter_list:

        err = 0
        for dt in dt_list:

            print('Working with dt = %s and k = %s iterations...' %
                  (dt, niter))

            description['step_params']['maxiter'] = niter
            description['level_params']['dt'] = dt

            # Tend = t0 + dt

            # instantiate the controller
            controller = allinclusive_multigrid_nonMPI(
                num_procs=1,
                controller_params=controller_params,
                description=description)

            # get initial values on finest level
            P = controller.MS[0].levels[0].prob
            uinit = P.u_exact(t0)

            # call main function to get things done...
            uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

            # compute exact solution and compare
            # uex = compute_collocation_solution(controller)
            # print(abs(uex - P.u_exact(Tend)))
            uex = P.u_exact(Tend)
            err_new = abs(uex - uend)

            print('   error at time %s: %s' % (Tend, err_new))
            if err > 0:
                print('   order of accuracy: %6.4f' %
                      (np.log(err / err_new) / np.log(2)))

            err = err_new

            # # filter statistics by type (number of iterations)
            filtered_stats = filter_stats(stats, type='niter')

            # convert filtered statistics to list of iterations count, sorted by process
            iter_counts = sort_stats(filtered_stats, sortby='time')

            # compute and print statistics
            niters = np.array([item[1] for item in iter_counts])
            out = '   Mean number of iterations: %4.2f' % np.mean(niters)
            print(out)
            # out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
            # # f.write(out + '\n')
            # print(out)
            # out = '   Position of max/min number of iterations: %2i -- %2i' % \
            #       (int(np.argmax(niters)), int(np.argmin(niters)))
            # # f.write(out + '\n')
            # print(out)
            # out = '   Std and var for number of iterations: %4.2f -- %4.2f' % \
            #       (float(np.std(niters)), float(np.var(niters)))
            # # f.write(out + '\n')
            # # f.write(out + '\n')
            # print(out)
        print()
예제 #10
0
def main():
    """
    A simple test program to do PFASST runs for the heat equation
    """

    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-14
    level_params['dt'] = 0.9 / 32
    level_params['nsweeps'] = 1

    # initialize sweeper parameters
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussLobatto
    sweeper_params['num_nodes'] = [5, 3, 2]
    sweeper_params['QI'] = [
        'LU'
    ]  # For the IMEX sweeper, the LU-trick can be activated for the implicit part
    sweeper_params['spread'] = True
    sweeper_params['do_coll_update'] = False

    # initialize problem parameters
    problem_params = dict()
    problem_params['nu'] = 0.02  # diffusion coefficient
    problem_params['c'] = 1.0  # advection speed
    problem_params['freq'] = -1  # frequency for the test value
    problem_params['nvars'] = [256, 128, 64
                               ]  # number of degrees of freedom for each level
    problem_params['L'] = 1.0  # length of the interval [-L/2, L/2]

    # initialize step parameters
    step_params = dict()
    step_params['maxiter'] = 10

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 30
    controller_params['hook_class'] = libpfasst_output
    controller_params['predict'] = False

    # fill description dictionary for easy step instantiation
    description = dict()
    # description['problem_class'] = advectiondiffusion1d_imex # pass problem class
    description[
        'problem_class'] = advectiondiffusion1d_implicit  # pass problem class
    description['problem_params'] = problem_params  # pass problem parameters
    description['dtype_u'] = mesh  # pass data type for u
    # description['dtype_f'] = rhs_imex_mesh # pass data type for f
    description['dtype_f'] = mesh  # pass data type for f
    # description['sweeper_class'] = imex_1st_order  # pass sweeper
    description['sweeper_class'] = generic_implicit  # pass sweeper
    description['sweeper_params'] = sweeper_params  # pass sweeper parameters
    description['level_params'] = level_params  # pass level parameters
    description['step_params'] = step_params  # pass step parameters
    description[
        'space_transfer_class'] = mesh_to_mesh_fft  # pass spatial transfer class
    description['space_transfer_params'] = dict(
    )  # pass paramters for spatial transfer

    # set time parameters
    t0 = 0.0
    Tend = level_params['dt']
    num_proc = 1

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=num_proc,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # print(controller.MS[0].levels[0].sweep.coll.Qmat)
    # print(controller.MS[0].levels[0].sweep.QI)
    # exit()

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # compute exact solution and compare
    uex = P.u_exact(Tend)
    err = abs(uex - uend)

    # filter statistics by type (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    for item in iter_counts:
        out = 'Number of iterations for time %4.2f: %2i' % item
        print(out)

    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(
        np.std(niters)), float(np.var(niters)))
    print(out)

    print('Error: %8.4e' % err)
예제 #11
0
def main():
    """
    A simple test program to do compare PFASST with multi-step SDC
    """

    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 5E-10
    level_params['dt'] = 0.125

    # initialize sweeper parameters
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = [3]

    # initialize problem parameters
    problem_params = dict()
    problem_params['nu'] = 0.1  # diffusion coefficient
    problem_params['freq'] = 2  # frequency for the test value

    # initialize step parameters
    step_params = dict()
    step_params['maxiter'] = 50

    # initialize space transfer parameters
    space_transfer_params = dict()
    space_transfer_params['rorder'] = 2
    space_transfer_params['iorder'] = 6

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 40
    controller_params['predict'] = False

    # fill description dictionary for easy step instantiation
    description = dict()
    description['problem_class'] = heat1d  # pass problem class
    description['dtype_u'] = mesh  # pass data type for u
    description['dtype_f'] = mesh  # pass data type for f
    description['sweeper_class'] = generic_LU  # pass sweeper
    description['sweeper_params'] = sweeper_params  # pass sweeper parameters
    description['level_params'] = level_params  # pass level parameters
    description['step_params'] = step_params  # pass step parameters
    description[
        'space_transfer_class'] = mesh_to_mesh  # pass spatial transfer class
    description[
        'space_transfer_params'] = space_transfer_params  # pass paramters for spatial transfer

    # set up parameters for PFASST run
    problem_params['nvars'] = [63, 31]
    description['problem_params'] = problem_params.copy()
    description_pfasst = description.copy()

    # set up parameters for MSSDC run
    problem_params['nvars'] = [63]
    description['problem_params'] = problem_params.copy()
    description_mssdc = description.copy()

    # set time parameters
    t0 = 0.0
    Tend = 1.0

    # set up list of parallel time-steps to run PFASST/MSSDC with
    num_proc = 8

    # instantiate controllers
    controller_mssdc = allinclusive_multigrid_nonMPI(
        num_procs=num_proc,
        controller_params=controller_params,
        description=description_mssdc)
    controller_pfasst = allinclusive_multigrid_nonMPI(
        num_procs=num_proc,
        controller_params=controller_params,
        description=description_pfasst)

    # get initial values on finest level
    P = controller_mssdc.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main functions to get things done...
    uend_pfasst, stats_pfasst = controller_pfasst.run(u0=uinit,
                                                      t0=t0,
                                                      Tend=Tend)
    uend_mssdc, stats_mssdc = controller_mssdc.run(u0=uinit, t0=t0, Tend=Tend)

    # compute exact solution and compare for both runs
    uex = P.u_exact(Tend)
    err_mssdc = abs(uex - uend_mssdc)
    err_pfasst = abs(uex - uend_pfasst)
    diff = abs(uend_mssdc - uend_pfasst)

    f = open('step_7_B_out.txt', 'w')

    out = 'Error PFASST: %12.8e' % err_pfasst
    f.write(out + '\n')
    print(out)
    out = 'Error MSSDC: %12.8e' % err_mssdc
    f.write(out + '\n')
    print(out)
    out = 'Diff: %12.8e' % diff
    f.write(out + '\n')
    print(out)

    # filter statistics by type (number of iterations)
    filtered_stats_pfasst = filter_stats(stats_pfasst, type='niter')
    filtered_stats_mssdc = filter_stats(stats_mssdc, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts_pfasst = sort_stats(filtered_stats_pfasst, sortby='time')
    iter_counts_mssdc = sort_stats(filtered_stats_mssdc, sortby='time')

    # compute and print statistics
    for item_pfasst, item_mssdc in zip(iter_counts_pfasst, iter_counts_mssdc):
        out = 'Number of iterations for time %4.2f (PFASST/MSSDC): %1i / %1i' % \
              (item_pfasst[0], item_pfasst[1], item_mssdc[1])
        f.write(out + '\n')
        print(out)

    f.close()

    # call helper routine to produce residual plot
    show_residual_across_simulation(stats_mssdc, 'step_7_residuals_mssdc.png')

    assert os.path.isfile('step_7_residuals_mssdc.png')
    assert diff < 1E-10, "ERROR: difference between PFASST and MSSDC controller is too large, got %s" % diff
예제 #12
0
파일: Fisher.py 프로젝트: schreiberx/pySDC
def main():
    # initialize level parameters
    level_params = dict()
    level_params['restol'] = 1E-10

    # This comes as read-in for the step class (this is optional!)
    step_params = dict()
    step_params['maxiter'] = 50

    # This comes as read-in for the problem class
    problem_params = dict()
    problem_params['nu'] = 1
    problem_params['nvars'] = 2047
    problem_params['lambda0'] = 1.0
    problem_params['newton_maxiter'] = 50
    problem_params['newton_tol'] = 1E-10
    problem_params['interval'] = (-1, 1)

    # This comes as read-in for the sweeper class
    sweeper_params = dict()
    sweeper_params['collocation_class'] = CollGaussRadau_Right
    sweeper_params['num_nodes'] = 4
    sweeper_params['QI'] = 'LU'
    sweeper_params['spread'] = False
    sweeper_params['do_coll_update'] = False

    # initialize controller parameters
    controller_params = dict()
    controller_params['logger_level'] = 30

    # Fill description dictionary for easy hierarchy creation
    description = dict()
    description['problem_class'] = generalized_fisher
    description['problem_params'] = problem_params
    description['dtype_u'] = mesh
    description['dtype_f'] = mesh
    description['sweeper_class'] = generic_implicit
    description['sweeper_params'] = sweeper_params
    description['step_params'] = step_params

    # setup parameters "in time"
    t0 = 0
    Tend = 1.0
    dt_list = [Tend / 2 ** i for i in range(0, 4)]

    err = 0
    for dt in dt_list:
        print('Working with dt = %s...' % dt)

        level_params['dt'] = dt
        description['level_params'] = level_params

        # instantiate the controller
        controller = allinclusive_multigrid_nonMPI(num_procs=1, controller_params=controller_params,
                                                   description=description)

        # get initial values on finest level
        P = controller.MS[0].levels[0].prob
        uinit = P.u_exact(t0)

        # call main function to get things done...
        uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

        # compute exact solution and compare
        uex = P.u_exact(Tend)
        err_new = abs(uex - uend)

        print('error at time %s: %s' % (Tend, err_new))
        if err > 0:
            print('order of accuracy: %6.4f' % (np.log(err / err_new) / np.log(2)))

        err = err_new

        # filter statistics by type (number of iterations)
        filtered_stats = filter_stats(stats, type='niter')

        # convert filtered statistics to list of iterations count, sorted by process
        iter_counts = sort_stats(filtered_stats, sortby='time')

        # compute and print statistics
        niters = np.array([item[1] for item in iter_counts])
        out = '   Mean number of iterations: %4.2f' % np.mean(niters)
        # f.write(out + '\n')
        print(out)
        out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
        # f.write(out + '\n')
        print(out)
        out = '   Position of max/min number of iterations: %2i -- %2i' % \
              (int(np.argmax(niters)), int(np.argmin(niters)))
        # f.write(out + '\n')
        print(out)
        out = '   Std and var for number of iterations: %4.2f -- %4.2f' % \
              (float(np.std(niters)), float(np.var(niters)))
        # f.write(out + '\n')
        # f.write(out + '\n')
        print(out)
예제 #13
0
def main(num_proc_list=None, fname=None, multi_level=True):
    """
    A simple test program to compare classical and multigrid PFASST runs

    Args:
        num_proc_list: list of number of processes to test with
        fname: filename/path for output
        multi_level (bool): do multi-level run or single-level
    """

    if multi_level:
        description, controller_params, t0, Tend = set_parameters_ml()
    else:
        assert all(num_proc == 1 for num_proc in num_proc_list), \
            'ERROR: single-elevel run can only use 1 processor, got %s' % num_proc_list
        description, controller_params, t0, Tend = set_parameters_sl()

    f = open(fname, 'w')
    # loop over different numbers of processes
    for num_proc in num_proc_list:

        out = 'Working with %2i processes...' % num_proc
        f.write(out + '\n')
        print(out)

        # instantiate controllers
        controller_classic = allinclusive_classic_nonMPI(
            num_procs=num_proc,
            controller_params=controller_params,
            description=description)
        controller_multigrid = allinclusive_multigrid_nonMPI(
            num_procs=num_proc,
            controller_params=controller_params,
            description=description)

        # get initial values on finest level
        P = controller_classic.MS[0].levels[0].prob
        uinit = P.u_exact(t0)

        # call main functions to get things done...
        uend_classic, stats_classic = controller_classic.run(u0=uinit,
                                                             t0=t0,
                                                             Tend=Tend)
        uend_multigrid, stats_multigrid = controller_multigrid.run(u0=uinit,
                                                                   t0=t0,
                                                                   Tend=Tend)

        # compute exact solution and compare with both results
        uex = P.u_exact(Tend)
        err_classic = abs(uex - uend_classic)
        err_multigrid = abs(uex - uend_multigrid)
        diff = abs(uend_classic - uend_multigrid)

        out = 'Error classic: %12.8e' % err_classic
        f.write(out + '\n')
        print(out)
        out = 'Error multigrid: %12.8e' % err_multigrid
        f.write(out + '\n')
        print(out)
        out = 'Diff: %6.4e' % diff
        f.write(out + '\n')
        print(out)

        # filter statistics by type (number of iterations)
        filtered_stats_classic = filter_stats(stats_classic, type='niter')
        filtered_stats_multigrid = filter_stats(stats_multigrid, type='niter')

        # convert filtered statistics to list of iterations count, sorted by process
        iter_counts_classic = sort_stats(filtered_stats_classic, sortby='time')
        iter_counts_multigrid = sort_stats(filtered_stats_multigrid,
                                           sortby='time')

        # compute and print statistics
        for item_classic, item_multigrid in zip(iter_counts_classic,
                                                iter_counts_multigrid):
            out = 'Number of iterations for time %4.2f (classic/multigrid): %1i / %1i' % \
                  (item_classic[0], item_classic[1], item_multigrid[1])
            f.write(out + '\n')
            print(out)

            if num_proc == 1:
                assert item_classic[1] == item_multigrid[1], \
                    'ERROR: number of iterations differ between classic and multigrid controller by %2i' \
                    % (item_classic[1] - item_multigrid[1])

        f.write('\n')
        print()

        assert all([item[1] <= 8 for item in iter_counts_multigrid]), \
            "ERROR: weird iteration counts for multigrid, got %s" % iter_counts_multigrid
        assert diff < 3.5E-09, "ERROR: difference between classic and multigrid controller is too large, got %s" % diff

    f.close()
예제 #14
0
def run_SDC_variant(variant=None, inexact=False):
    """
    Routine to run particular SDC variant

    Args:
        variant (str): string describing the variant
        inexact (bool): flag to use inexact nonlinear solve (or nor)

    Returns:
        timing (float)
        niter (float)
    """

    # load (incomplete) default parameters
    description, controller_params = setup_parameters()

    # add stuff based on variant
    if variant == 'semi-implicit':
        description['problem_class'] = allencahn2d_imex
        description['dtype_f'] = rhs_imex_mesh
        description['sweeper_class'] = imex_1st_order
    else:
        raise NotImplemented('Wrong variant specified, got %s' % variant)

    # setup parameters "in time"
    t0 = 0
    Tend = 0.032

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=8,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # plt_helper.plt.imshow(uinit.values)
    # plt_helper.plt.show()

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # plt_helper.plt.imshow(uend.values)
    # plt_helper.plt.show()

    # filter statistics by variant (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(
        np.std(niters)), float(np.var(niters)))
    print(out)

    timing = sort_stats(filter_stats(stats, type='timing_run'), sortby='time')

    print('Time to solution: %6.4f sec.' % timing[0][1])
    print()

    return stats
예제 #15
0
def run_SDC_variant(variant=None, inexact=False):
    """
    Routine to run particular SDC variant

    Args:
        variant (str): string describing the variant
        inexact (bool): flag to use inexact nonlinear solve (or nor)

    Returns:
        results and statistics of the run
    """

    # load (incomplete) default parameters
    description, controller_params = setup_parameters()

    # add stuff based on variant
    if variant == 'fully-implicit':
        description['problem_class'] = allencahn_fullyimplicit
        description['dtype_f'] = mesh
        description['sweeper_class'] = generic_implicit
        if inexact:
            description['problem_params']['newton_maxiter'] = 1
    elif variant == 'semi-implicit':
        description['problem_class'] = allencahn_semiimplicit
        description['dtype_f'] = rhs_imex_mesh
        description['sweeper_class'] = imex_1st_order
        if inexact:
            description['problem_params']['lin_maxiter'] = 10
    elif variant == 'semi-implicit_v2':
        description['problem_class'] = allencahn_semiimplicit_v2
        description['dtype_f'] = rhs_imex_mesh
        description['sweeper_class'] = imex_1st_order
        if inexact:
            description['problem_params']['newton_maxiter'] = 1
    elif variant == 'multi-implicit':
        description['problem_class'] = allencahn_multiimplicit
        description['dtype_f'] = rhs_comp2_mesh
        description['sweeper_class'] = multi_implicit
        if inexact:
            description['problem_params']['newton_maxiter'] = 1
            description['problem_params']['lin_maxiter'] = 10
    elif variant == 'multi-implicit_v2':
        description['problem_class'] = allencahn_multiimplicit_v2
        description['dtype_f'] = rhs_comp2_mesh
        description['sweeper_class'] = multi_implicit
        if inexact:
            description['problem_params']['newton_maxiter'] = 1
    else:
        raise NotImplemented('Wrong variant specified, got %s' % variant)

    if inexact:
        out = 'Working on inexact %s variant...' % variant
    else:
        out = 'Working on exact %s variant...' % variant
    print(out)

    # setup parameters "in time"
    t0 = 0
    Tend = 0.032

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(num_procs=1, controller_params=controller_params,
                                               description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # filter statistics by variant (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(np.std(niters)), float(np.var(niters)))
    print(out)

    print('   Iteration count (nonlinear/linear): %i / %i' % (P.newton_itercount, P.lin_itercount))
    print('   Mean Iteration count per call: %4.2f / %4.2f' % (P.newton_itercount / max(P.newton_ncalls, 1),
                                                               P.lin_itercount / max(P.lin_ncalls, 1)))

    timing = sort_stats(filter_stats(stats, type='timing_run'), sortby='time')

    print('Time to solution: %6.4f sec.' % timing[0][1])

    fname = 'data/AC_reference_Tend{:.1e}'.format(Tend) + '.npz'
    loaded = np.load(fname)
    uref = loaded['uend']

    err = np.linalg.norm(uref - uend.values, np.inf)
    print('Error vs. reference solution: %6.4e' % err)
    print()

    return stats
def run_variant(nlevels=None):
    """
    Routine to run particular SDC variant

    Args:

    Returns:

    """

    # load (incomplete) default parameters
    description, controller_params = setup_parameters()

    # add stuff based on variant
    if nlevels == 1:
        description['level_params']['nsweeps'] = 1
        description['problem_params']['nvars'] = [(128, 128)]
        # description['problem_params']['nvars'] = [(32, 32)]
    elif nlevels == 2:
        description['level_params']['nsweeps'] = [1, 1]
        description['problem_params']['nvars'] = [(128, 128), (32, 32)]
        # description['problem_params']['nvars'] = [(32, 32), (16, 16)]
    else:
        raise NotImplemented('Wrong variant specified, got %s' % nlevels)

    out = 'Working on %s levels...' % nlevels
    print(out)

    # setup parameters "in time"
    t0 = 0.0
    Tend = 0.032

    # instantiate controller
    controller = allinclusive_multigrid_nonMPI(
        num_procs=1,
        controller_params=controller_params,
        description=description)

    # get initial values on finest level
    P = controller.MS[0].levels[0].prob
    uinit = P.u_exact(t0)

    # call main function to get things done...
    uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)

    # filter statistics by variant (number of iterations)
    filtered_stats = filter_stats(stats, type='niter')

    # convert filtered statistics to list of iterations count, sorted by process
    iter_counts = sort_stats(filtered_stats, sortby='time')

    # compute and print statistics
    niters = np.array([item[1] for item in iter_counts])
    out = '   Mean number of iterations: %4.2f' % np.mean(niters)
    print(out)
    out = '   Range of values for number of iterations: %2i ' % np.ptp(niters)
    print(out)
    out = '   Position of max/min number of iterations: %2i -- %2i' % \
          (int(np.argmax(niters)), int(np.argmin(niters)))
    print(out)
    out = '   Std and var for number of iterations: %4.2f -- %4.2f' % (float(
        np.std(niters)), float(np.var(niters)))
    print(out)

    timing = sort_stats(filter_stats(stats, type='timing_run'), sortby='time')

    print('Time to solution: %6.4f sec.' % timing[0][1])

    fname = 'data/AC_reference_FFT_Tend{:.1e}'.format(Tend) + '.npz'
    loaded = np.load(fname)
    uref = loaded['uend']

    err = np.linalg.norm(uref - uend.values, np.inf)
    print('Error vs. reference solution: %6.4e' % err)
    print()

    return stats