예제 #1
0
파일: utils.py 프로젝트: daveb-dev/xalbrain
    def __init__(self, V, parameters=None):
        # Set parameters
        self.parameters = self.default_parameters()
        if parameters is not None:
            self.parameters.update(parameters)

        # Set-up mass matrix for L^2 projection
        self.V = V
        self.u = df.TrialFunction(self.V)
        self.v = df.TestFunction(self.V)
        self.m = df.inner(self.u, self.v) * df.dx()
        self.M = df.assemble(self.m)
        self.b = df.Vector(V.mesh().mpi_comm(), V.dim())

        solver_type = self.parameters["linear_solver_type"]
        assert(solver_type == "lu" or solver_type == "cg"),  \
            "Expecting 'linear_solver_type' to be 'lu' or 'cg'"
        if solver_type == "lu":
            df.debug("Setting up direct solver for projecter")
            # Customize LU solver (reuse everything)
            solver = df.LUSolver(self.M)
            solver.parameters["same_nonzero_pattern"] = True
            solver.parameters["reuse_factorization"] = True
        else:
            df.debug("Setting up iterative solver for projecter")
            # Customize Krylov solver (reuse everything)
            solver = df.KrylovSolver("cg", "ilu")
            solver.set_operator(self.M)
            solver.parameters["preconditioner"]["structure"] = "same"
            # solver.parameters["nonzero_initial_guess"] = True
        self.solver = solver
예제 #2
0
    def assign_initial_conditions(self, function):
        function_space = function.function_space()
        markers = self.markers()

        u = TrialFunction(function_space)
        v = TestFunction(function_space)

        dy = Measure("dx", domain=self.mesh(), subdomain_data=markers)

        # Define projection into multiverse
        a = inner(u, v) * dy()

        Ls = list()
        for k, model in enumerate(self.models()):
            ic = model.initial_conditions()  # Extract initial conditions
            n_k = model.num_states()  # Extract number of local states
            i_k = self.keys()[k]  # Extract domain index of cell model k
            L_k = sum(ic[j] * v[j] * dy(i_k)
                      for j in range(n_k + 1))  # include v and s
            Ls.append(L_k)
        L = sum(Ls)
        # solve(a == L, function)       # really inaccurate

        params = df.KrylovSolver.default_parameters()
        params["absolute_tolerance"] = 1e-14
        params["relative_tolerance"] = 1e-14
        params["nonzero_initial_guess"] = True
        solver = df.KrylovSolver()
        solver.update_parameters(params)
        A, b = df.assemble_system(a, L)
        solver.set_operator(A)
        solver.solve(function.vector(), b)
예제 #3
0
def set_solver():
    # "hypre_amg") #"hypre_euclid") # "hypre_amg") # "petsc_amg" "petsc_amg"
    solver = d.KrylovSolver("cg", "hypre_amg")
    solver.parameters["maximum_iterations"] = 1000
    solver.parameters["absolute_tolerance"] = 1E-8
    solver.parameters["error_on_nonconvergence"] = True
    solver.parameters["monitor_convergence"] = True
    # solver.parameters["divergence_limit"] = 1E+6
    # solver.parameters["nonzero_initial_guess"] = True
    d.info(solver.parameters, verbose=True)
    d.set_log_level(d.PROGRESS)
    return solver
예제 #4
0
def solve(AA,
          uu,
          bb,
          *,
          krylov_args=('cg', 'hypre_amg'),
          direct_args=('mumps', )):
    try:
        solver = dolfin.KrylovSolver(*krylov_args)
        it = solver.solve(AA, uu.vector(), bb)
        print(f'krylov iterations: {it}')
    except:
        dolfin.solve(AA, uu.vector(), bb, *direct_args)
        print(f'direct solve after krylov failure')
        it = -1
    return it
예제 #5
0
    def __init__(self,mesh,m, parameters=sb.default_parameters , degree=1, element="CG",
                 project_method='magpar', unit_length=1,Ms = 1.0,bench = False,
                 mac=0.3,p=3,num_limit=100):
        
        sb.FemBemDeMagSolver.__init__(self,mesh,m, parameters, degree, element=element,
                                      project_method = project_method,
                                      unit_length = unit_length,Ms = Ms,bench = bench)
        self.__name__ = "Treecode Demag Solver"
        
        
        #Linear Solver parameters
        method = parameters["poisson_solver"]["method"]
        pc = parameters["poisson_solver"]["preconditioner"]
        
        self.poisson_solver = df.KrylovSolver(self.poisson_matrix, method, pc)

        self.phi1 = df.Function(self.V)
        self.phi2 = df.Function(self.V)

        # Eq (1) and code-block 2 - two first lines.
        b = self.Ms*df.inner(self.w, df.grad(self.v))*df.dx
        self.D = df.assemble(b)

        self.p=p
        self.mac=mac
        self.num_limit=num_limit
        
        self.mesh=mesh
        
        self.bmesh = df.BoundaryMesh(mesh,False)
        self.b2g_map = self.bmesh.vertex_map().array()
        
        self.compute_triangle_normal()

        self.__compute_bsa()
        
        fast_sum=FastSum(p=self.p,mac=self.mac,num_limit=self.num_limit)

        coords=self.bmesh.coordinates()
        face_nodes=np.array(self.bmesh.cells(),dtype=np.int32)
        
        fast_sum.init_mesh(coords,self.t_normals,face_nodes,self.vert_bsa)
        self.fast_sum=fast_sum
        
        self.phi2_b = np.zeros(self.bmesh.num_vertices())
예제 #6
0
def assign_ic_subdomain(
        *,
        brain: CoupledBrainModel,
        vs_prev: df.Function,
        value: float,
        subdomain_id: int,
        subfunction_index: int
) -> None:
    """
    Compute a function with `value` in the subdomain corresponding to `subdomain_id`.
    Assign this function to subfunction `subfunction_index` of vs_prev.
    """
    mesh = brain._mesh
    cell_function = brain._cell_function

    dX = df.Measure("dx", domain=mesh, subdomain_data=cell_function)

    V = df.FunctionSpace(mesh, "DG", 0)
    u = df.TrialFunction(V)
    v = df.TestFunction(V)
    sol = df.Function(V)
    sol.vector().zero()     # Make sure it is initialised to zero

    F = -u*v*dX(subdomain_id) + df.Constant(value)*v*dX(subdomain_id)
    a = df.lhs(F)
    L = df.rhs(F)

    A = df.assemble(a, keep_diagonal=True)
    A.ident_zeros()
    b = df.assemble(L)
    solver = df.KrylovSolver("cg", "petsc_amg")
    solver.set_operator(A)
    solver.solve(sol.vector(), b)

    VCG = df.FunctionSpace(mesh, "CG", 1)
    v_new = df.Function(VCG)
    v_new.interpolate(sol)

    Vp = vs_prev.function_space().sub(subfunction_index)
    merger = df.FunctionAssigner(Vp, VCG)
    merger.assign(vs_prev.sub(subfunction_index), v_new)
예제 #7
0
def solve_IC(mesh: df.Mesh, cell_function: df.MeshFunction,
             tag_ic_dict: tp.Dict[int, tp.List[float]],
             dimension: int) -> df.Function:
    """Solve a Poisson equation in order to assign values from a cell function to a (CG1) function

    NB! This is not precise --- Nah, it is fairly ok with the interpolation
    """
    dX = df.Measure("dx", domain=mesh, subdomain_data=cell_function)
    DG_fs = df.VectorFunctionSpace(mesh, "DG", 0, dim=dimension)

    u = df.TrialFunction(DG_fs)
    v = df.TestFunction(DG_fs)

    sol = df.Function(DG_fs)
    sol.vector().zero()  # Make sure it is initialised to zero

    # NB! For some reason map(int, cell_tags) does not work with the cell function.
    F = 0
    for ct, ic in tag_ic_dict.items():
        F += -df.dot(u, v) * dX(ct) + df.dot(df.Constant(tuple(ic)),
                                             v) * dX(ct)

    a = df.lhs(F)
    L = df.rhs(F)

    # TODO: Why keep diagonal and ident_zeros?
    A = df.assemble(a, keep_diagonal=True)
    A.ident_zeros()
    b = df.assemble(L)
    solver = df.KrylovSolver("cg", "petsc_amg")
    solver.set_operator(A)
    solver.solve(sol.vector(), b)

    # clamp to int
    # sol.vector()[:] = sol.vector().get_local()

    target_fs = df.VectorFunctionSpace(mesh, "CG", 1, dim=dimension)
    solsol = df.Function(target_fs)
    solsol.interpolate(sol)
    return solsol
예제 #8
0
    def set_solver(self, solver_method="mumps", **kwargs):
        """
        Choose the type of the solver and its method.

        An up-to-date list of the available solvers and preconditioners
        can be obtained with dolfin.list_linear_solver_methods() and
        dolfin.list_krylov_solver_preconditioners().

        kwargs:
        type e.g. 'LU',
        preconditioner e.g. 'default'
        """
        s_type = kwargs.pop("type", None)
        s_precond = kwargs.pop("preconditioner", "default")

        if s_type is None:
            if solver_method in DOLFIN_KRYLOV_METHODS.keys():
                s_type = "Krylov"
            elif solver_method in DOLFIN_LU_METHODS.keys():
                s_type = "LU"
            else:
                raise RuntimeError("The indicated solver method is unknown.")
        else:
            if not (solver_method in DOLFIN_KRYLOV_METHODS.keys()
                    or solver_method in DOLFIN_LU_METHODS.keys()):
                raise RuntimeError("The indicated solver method is unknown.")
        self._solver = dict(type=s_type,
                            method=solver_method,
                            preconditioner=s_precond)
        if s_precond:
            self._solver["preconditioner"] = s_precond

        if s_type == "Krylov":
            self.solver = fe.KrylovSolver(self.K, solver_method)
        elif s_type == "LU":
            self.solver = fe.LUSolver(self.K, solver_method)
        if s_precond != "default":
            self.solver.parameters.preconditioner = s_precond
        return self.solver
def solve_tr_dir__const_rheo(mesh_name, hol_cyl, deg_choice, T_in_expr,
                             T_inf_expr, HTC, T_old_v, k_mesh, cp_mesh,
                             rho_mesh, k_mesh_old, cp_mesh_old, rho_mesh_old,
                             dt, time_v, theta, bool_plot, bool_solv,
                             savings_do, logger_f):
    '''
    mesh_name: a proper XML file.
    bool_plot: plots if bool_plot = 1.
    
    Solves a direct, steady-state heat conduction problem, and
    returns A_np, b_np, D_np, T_np, bool_ex, bool_in.
    
    A_np: stiffness matrix, ordered by vertices.
    
    b_np: integrated volumetric heat sources and surface heat fluxes, ordered by vertices.
    The surface heat fluxes come from the solution to the direct problem;
    hence, these terms will not be there in a real IHCP. 
    
    D_np: integrated Laplacian of T, ordered by vertices.
    Option 2.
    The Laplacian of q is properly assembled from D_np.
    If do.dx(domain = hol_cyl) -> do.Measure('ds')[boundary_faces] and
    do.Measure('ds')[boundary_faces] -> something representative of Gamma,
    I would get option 1.
    
    T_np: solution to the direct heat conduction problem, ordered by vertices.
    
    bool_ex: boolean array declaring which vertices lie on the outer boundary.
    
    bool_in: boolean array indicating which vertices lie on the inner boundary.
    
    T_sol: solution to the direct heat conduction problem.
    
    deg_choice: degree in FunctionSpace.
    
    hol_cyl: mesh.
    '''

    #comm1 = MPI.COMM_WORLD

    #current proc
    #rank1 = comm1.Get_rank()

    V = do.FunctionSpace(hol_cyl, 'CG', deg_choice)

    if 'hollow' in mesh_name and 'cyl' in mesh_name:
        from hollow_cyl_inv_mesh import geo_fun as geo_fun_hollow_cyl
        geo_params_d = geo_fun_hollow_cyl()[1]
        #x_c is a scalar here
        #y_c is a scalar here

    elif 'four' in mesh_name and 'cyl' in mesh_name:
        from four_hole_cyl_inv_mesh import geo_fun as geo_fun_four_hole_cyl
        geo_params_d = geo_fun_four_hole_cyl()[1]
        #x_c is an array here
        #y_c is an array here
        x_c_l = [geo_params_d['x_0_{}'.format(itera)] for itera in xrange(4)]
        y_c_l = [geo_params_d['y_0_{}'.format(itera)] for itera in xrange(4)]

    elif 'one_hole_cir' in mesh_name:
        from one_hole_cir_adj_mesh import geo_fun as geo_fun_one_hole_cir
        geo_params_d = geo_fun_one_hole_cir()[1]
        #x_c is an array here
        #y_c is an array here
        x_c_l = [geo_params_d['x_0']]
        y_c_l = [geo_params_d['y_0']]

    elif 'reinh_cir' in mesh_name:
        from reinh_cir_adj_mesh import geo_fun as geo_fun_one_hole_cir
        geo_params_d = geo_fun_one_hole_cir()[1]
        #x_c is an array here
        #y_c is an array here
        x_c_l = [geo_params_d['x_0']]
        y_c_l = [geo_params_d['y_0']]

    elif 'small_circle' in mesh_name:
        from four_hole_small_cir_adj_mesh import geo_fun as geo_fun_four_hole_cir
        geo_params_d = geo_fun_four_hole_cir()[1]
        #x_c is an array here
        #y_c is an array here
        x_c_l = [geo_params_d['x_0_{}'.format(itera)] for itera in xrange(4)]
        y_c_l = [geo_params_d['y_0_{}'.format(itera)] for itera in xrange(4)]

    #center of the cylinder base
    x_c = geo_params_d['x_0']
    y_c = geo_params_d['y_0']

    R_in = geo_params_d['R_in']
    R_ex = geo_params_d['R_ex']

    #define variational problem
    T = do.TrialFunction(V)
    g = do.Function(V)
    v = do.TestFunction(V)

    T_old = do.Function(V)
    T_inf = do.Function(V)

    #scalar
    T_old.vector()[:] = T_old_v
    T_inf.vector()[:] = T_inf_expr

    #solution
    T_sol = do.Function(V)

    #scalar
    T_sol.vector()[:] = T_old_v

    # Create boundary markers
    mark_all = 3
    mark_in = 4
    mark_ex = 5

    #x_c is an array here
    #y_c is an array here
    g_in = g_in_mesh(mesh_name, x_c_l, y_c_l, R_in)

    g_ex = g_ex_mesh(mesh_name, x_c, y_c, R_ex)

    in_boundary = do.AutoSubDomain(g_in)
    ex_boundary = do.AutoSubDomain(g_ex)

    #normal
    unitNormal = do.FacetNormal(hol_cyl)
    boundary_faces = do.MeshFunction('size_t', hol_cyl,
                                     hol_cyl.topology().dim() - 1)

    boundary_faces.set_all(mark_all)
    in_boundary.mark(boundary_faces, mark_in)
    ex_boundary.mark(boundary_faces, mark_ex)

    bc_in = do.DirichletBC(V, T_in_expr, boundary_faces, mark_in)
    #bc_ex = do.DirichletBC(V, T_ex_expr, boundary_faces, mark_ex)
    bcs = [bc_in]

    #k = do.Function(V)  #W/m/K
    #k.vector()[:] = k_mesh

    #A0 = k * do.dot(do.grad(T), do.grad(v)) * do.dx(domain = hol_cyl)
    A = dt / 2. * k_mesh * do.dot(do.grad(T), do.grad(v)) * do.dx(domain = hol_cyl) + \
        rho_mesh * cp_mesh * T * v * do.dx(domain = hol_cyl)

    A_full = A + dt / 2. * HTC * T * v * do.ds(
        mark_ex, domain=hol_cyl, subdomain_data=boundary_faces)

    L = -dt / 2. * k_mesh_old * do.dot(do.grad(T_old), do.grad(v)) * \
        do.dx(domain = hol_cyl) + \
        rho_mesh_old * cp_mesh_old * T_old * v * do.dx(domain = hol_cyl) - \
        dt / 2. * HTC * (T_old) * v * do.ds(mark_ex,
                                                    domain = hol_cyl,
                                                    subdomain_data = boundary_faces)  + \
        dt * HTC * T_inf * v * do.ds(mark_ex,
                                                    domain = hol_cyl,
                                                    subdomain_data = boundary_faces)

    #numpy version of A, T, and (L + int_fluxT)
    #A_np__not_v2d = do.assemble(A).array() #before applying BCs - needs v2d
    #L_np__not_v2d = do.assemble(L).array() #before applying BCs - needs v2d

    #Laplacian of T, without any -1/k int_S q*n*v dS
    '''
    Approximated integral of the Laplacian of T.
    Option 2.
    The Laplacian of q is properly assembled from D_np.
    If do.dx(domain = hol_cyl) -> do.Measure('ds')[boundary_faces] and
    do.Measure('ds')[boundary_faces] -> something representative of Gamma,
    I would get option 1.
    '''
    #D_np__not_v2d = do.assemble(-do.dot(do.grad(T), do.grad(v)) * do.dx(domain = hol_cyl) +
    #                             do.dot(unitNormal, do.grad(T)) * v *
    #                             do.Measure('ds')[boundary_faces]).array()
    #print np.max(D_np__not_v2d)#, np.max(A_np__not_v2d)
    #logger_f.warning('shape of D_np = {}, {}'.format(D_np__not_v2d.shape[0],
    #D_np__not_v2d.shape[1]))

    #nonzero_entries = []
    #for row in D_np__not_v2d:
    #    nonzero_entries += [len(np.where(abs(row) > 1e-16)[0])]

    #logger_f.warning('max, min, and mean of nonzero_entries = {}, {}, {}'.format(
    #      max(nonzero_entries), min(nonzero_entries), np.mean(nonzero_entries)))

    #solver parameters
    #linear solvers from
    #list_linear_solver_methods()
    #preconditioners from
    #do.list_krylov_solver_preconditioners()
    solver = do.KrylovSolver('gmres', 'ilu')
    do.info(solver.parameters, True)  #prints default values
    solver.parameters['relative_tolerance'] = 1e-16
    solver.parameters['maximum_iterations'] = 20000000
    solver.parameters['monitor_convergence'] = True  #on the screen
    #http://fenicsproject.org/qa/1124/is-there-a-way-to-set-the-inital-guess-in-the-krylov-solver
    '''solver.parameters['nonzero_initial_guess'] = True'''
    solver.parameters['absolute_tolerance'] = 1e-15
    #uses whatever in q_v as my initial condition

    #the next lines are used for CHECK 3 only
    #A_sys, b_sys = do.assemble_system(A, L, bcs)

    do.File(
        os.path.join(savings_do, '{}__markers.pvd'.format(
            mesh_name.split('.')[0]))) << boundary_faces

    if bool_plot:
        do.plot(boundary_faces, '3D mesh', title='boundary markers')

    #storage
    T_sol_d = {}
    g_d = {}

    if bool_solv == 1:

        xdmf_DHCP_T = do.File(os.path.join(savings_do, 'DHCP', 'T.pvd'))
        xdmf_DHCP_q = do.File(os.path.join(savings_do, 'DHCP', 'q.pvd'))

        for count_t_i, t_i in enumerate(time_v[1:]):

            #T_in_expr.ts = t_i
            #T_ex_expr.ts = t_i

            #storage
            T_sol_d[count_t_i] = do.Function(V)
            T_sol_d[count_t_i].vector()[:] = T_sol.vector().array()

            do.solve(A_full == L, T_sol, bcs)
            '''
            TO BE UPDATED:
            rheology is not updated
            '''

            #updates L
            T_old.assign(T_sol)

            T_sol.rename('DHCP_T', 'temperature from DHCP')

            #write solution to file
            #paraview format
            xdmf_DHCP_T << (T_sol, t_i)

            #plot solution
            if bool_plot:
                do.plot(T_sol, title='T')  #, interactive = True)

            logger_f.warning('len(T) = {}'.format(len(T_sol.vector().array())))

            print 'T: count_t = {}, min(T_DHCP) = {}'.format(
                count_t_i, min(T_sol_d[count_t_i].vector().array()))
            print 'T: count_t = {}, max(T_DHCP) = {}'.format(
                count_t_i, max(T_sol_d[count_t_i].vector().array())), '\n'

            #save flux - required for solving IHCP
            #same result if do.ds(mark_ex, subdomain_data = boundary_faces)
            #instead of do.Measure('ds')[boundary_faces]
            #Langtangen, p. 37:
            #either do.dot(do.nabla_grad(T), unitNormal)
            #or do.dot(unitNormal, do.grad(T))

            #int_fluxT = do.assemble(-k * do.dot(unitNormal, do.grad(T_sol)) * v *
            #                          do.Measure('ds')[boundary_faces])

            fluxT = do.project(
                -k_mesh * do.grad(T_sol),
                do.VectorFunctionSpace(hol_cyl, 'CG', deg_choice, dim=2))

            if bool_plot:
                do.plot(fluxT,
                        title='flux at iteration = {}'.format(count_t_i))

            fluxT.rename('DHCP_flux', 'flux from DHCP')

            xdmf_DHCP_q << (fluxT, t_i)

            print 'DHCP: iteration = {}'.format(count_t_i)

            ####################################################
            #full solution
            #T_sol_full = do.Vector()
            #T_sol.vector().gather(T_sol_full, np.array(range(V.dim()), 'intc'))
            ####################################################

        count_t_i += 1

        #copy previous lines
        #storage
        T_sol_d[count_t_i] = do.Function(V)
        T_sol_d[count_t_i].vector()[:] = T_sol.vector().array()

    for count_t_i, t_i in enumerate(time_v):
        #storage
        g_d[count_t_i] = do.Function(V)
        g_d[count_t_i].vector()[:] = g.vector().array()

    gdim = hol_cyl.geometry().dim()
    dofmap = V.dofmap()
    dofs = dofmap.dofs()

    #Get coordinates as len(dofs) x gdim array
    dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim))

    #booleans corresponding to the outer boundary -> ints since they are sent to root = 0
    bool_ex = 1. * np.array([g_ex(dof_x) for dof_x in dofs_x])
    #booleans corresponding to the inner boundary -> ints since they are sent to root = 0
    bool_in = 1. * np.array([g_in(dof_x) for dof_x in dofs_x])

    T_np_ex = []
    T_np_in = []

    for i_coor, coor in enumerate(dofs_x):
        if g_ex(coor):
            T_np_ex += [T_sol.vector().array()[i_coor]]
        if g_in(coor):
            T_np_in += [T_sol.vector().array()[i_coor]]

    print 'CHECK: mean(T) on the outer boundary = ', np.mean(np.array(T_np_ex))
    print 'CHECK: mean(T) on the inner boundary = ', np.mean(np.array(T_np_in))
    print 'CHECK: mean(HTC) = ', np.mean(do.project(HTC, V).vector().array())

    #v2d = do.vertex_to_dof_map(V) #orders by hol_cyl.coordinates()
    if deg_choice == 1:
        print 'len(dof_to_vertex_map) = ', len(do.dof_to_vertex_map(V))

    print 'min(dofs) = ', min(dofs), ', max(dofs) = ', max(dofs)
    print 'len(bool ex) = ', len(bool_ex)
    print 'len(bool in) = ', len(bool_in)
    print 'bool ex[:10] = ', repr(bool_ex[:10])
    print 'type(T) = ', type(T_sol.vector().array())

    #first global results, then local results
    return A, L, g_d, \
           V, v, k_mesh, \
           mark_in, mark_ex, \
           boundary_faces, bool_ex, \
           R_in, R_ex, T_sol_d, deg_choice, hol_cyl, \
           unitNormal, dofs_x
def nablau_fun(
        V,
        v,
        hol_cyl,
        A,
        boundary_faces,
        mark_in,
        dg_d,  #S_in
        k_mesh_old,
        cp_mesh_old,
        rho_mesh_old,
        dt,
        time_v,
        theta,
        itera):
    '''
    Sensitivity problem.
    Solves A u = L.
    A = dt * theta * k_mesh * do.dot(do.grad(T), do.grad(v)) * do.dx(domain = hol_cyl) + \
        rho_mesh * cp_mesh * T * v * do.dx(domain = hol_cyl)
    
    Solved after setting dg_in = p^k.                         
    '''
    #solver parameters
    #linear solvers from
    #list_linear_solver_methods()
    #preconditioners from
    #do.list_krylov_solver_preconditioners()
    solver = do.KrylovSolver('gmres', 'ilu')
    do.info(solver.parameters, False)  #prints default values
    solver.parameters['relative_tolerance'] = 1e-13
    solver.parameters['maximum_iterations'] = 200000
    solver.parameters['monitor_convergence'] = True  #on the screen
    #http://fenicsproject.org/qa/1124/
    #is-there-a-way-to-set-the-inital-guess-in-the-krylov-solver
    '''solver.parameters['nonzero_initial_guess'] = True'''
    #solver.parameters['absolute_tolerance'] = 1e-15
    #uses whatever in q_v as my initial condition

    #starts from 0
    #u_stept = do.TrialFunction(V)
    u_step3 = do.Function(V)

    #starts from 0
    u_old = do.Function(V)

    u_step3_d = {}

    theta = do.Constant(theta)

    dt = do.Constant(dt)

    #A = dt / 2. * k_mesh_old * do.dot(do.grad(u_stept), do.grad(v)) * do.dx(domain = hol_cyl) + \
    #   rho_mesh_old * cp_mesh_old * u_stept * v * do.dx(domain = hol_cyl)

    for count_t_i, t_i in enumerate(time_v[1:]):
        #storage
        u_step3_d[count_t_i] = do.Function(V)
        u_step3_d[count_t_i].vector()[:] = u_step3.vector().array()

        #int_fluxT_ex = 0
        int_fluxT_in = dg_d[count_t_i + 1] * v * do.ds(
            mark_in, domain=hol_cyl, subdomain_data=boundary_faces)
        int_fluxT_in_old = dg_d[count_t_i] * v * do.ds(
            mark_in, domain=hol_cyl, subdomain_data=boundary_faces)

        #L -= (int_fluxT_in + int_fluxT_ex)
        L_old = -dt * (1. - theta) * k_mesh_old * do.dot(do.grad(u_old), do.grad(v)) * \
                do.dx(domain = hol_cyl) + \
                rho_mesh_old * cp_mesh_old * u_old * v * do.dx(domain = hol_cyl)

        L = L_old + (dt * theta * int_fluxT_in + dt *
                     (1. - theta) * int_fluxT_in_old)

        do.solve(A == L, u_step3)

        print 'u: count_t = {}, min(dg) = {}'.format(
            count_t_i, min(dg_d[count_t_i].vector().array()))

        print 'u: count_t = {}, max(dg) = {}'.format(
            count_t_i, max(dg_d[count_t_i].vector().array()))

        print 'u: count_t = {}, min(int_fluxT_in) = {}'.format(
            count_t_i, min(do.assemble(int_fluxT_in).array()))
        print 'u: count_t = {}, max(int_fluxT_in) = {}'.format(
            count_t_i, max(do.assemble(int_fluxT_in).array()))

        print 'u: count_t = {}, min(L) = {}'.format(
            count_t_i, min(do.assemble(L).array()))
        print 'u: count_t = {}, max(L) = {}'.format(
            count_t_i, max(do.assemble(L).array()))

        print 'u: count_t = {}, min(u) = {}'.format(
            count_t_i, min(u_step3.vector().array()))
        print 'u: count_t = {}, max(u) = {}'.format(
            count_t_i, max(u_step3.vector().array())), '\n'

        u_old.assign(u_step3)

    count_t_i += 1

    #storage
    u_step3_d[count_t_i] = do.Function(V)
    u_step3_d[count_t_i].vector()[:] = u_step3.vector().array()

    return u_step3_d
def nablap_fun(
        V,
        v,
        hol_cyl,
        A,
        boundary_faces,
        mark_ex,
        T_step_d,
        T_exp_d,  #S_ex 
        k_mesh_oldp,
        cp_mesh_oldp,
        rho_mesh_oldp,
        dt,
        time_v,
        theta,
        itera,
        mesh_name,
        savings_do):
    '''
    Adjoint problem.
    Solves A p = L.
    A = dt * theta * k_mesh * do.dot(do.grad(p), do.grad(v)) * do.dx(domain = hol_cyl) + \
        rho_mesh * cp_mesh * p * v * do.dx(domain = hol_cyl)
        
    T_stepp: from T_step flipped.
    T_exp  : from T_ex flipped.
    '''
    #solver parameters
    #linear solvers from
    #list_linear_solver_methods()
    #preconditioners from
    #do.list_krylov_solver_preconditioners()
    solver = do.KrylovSolver('gmres', 'ilu')
    do.info(solver.parameters, False)  #prints default values
    solver.parameters['relative_tolerance'] = 1e-13
    solver.parameters['maximum_iterations'] = 2000000
    solver.parameters['monitor_convergence'] = True  #on the screen
    #http://fenicsproject.org/qa/1124/
    #is-there-a-way-to-set-the-inital-guess-in-the-krylov-solver
    '''solver.parameters['nonzero_initial_guess'] = True'''
    #solver.parameters['absolute_tolerance'] = 1e-15
    #uses whatever in q_v as my initial condition

    #p_stept = do.TrialFunction(V)
    p_step2 = do.Function(V)

    #starts from 0
    p_old = do.Function(V)

    p_step2_d = {}

    #e.g., e.g., count_t_i = 100
    #storage
    p_step2_d[len(time_v) - 1] = do.Function(V)
    p_step2_d[len(time_v) - 1].vector()[:] = p_old.vector().array()

    theta = do.Constant(theta)

    dt = do.Constant(dt)

    p_step2_f = do.File(os.path.join(savings_do, str(itera), 'adj_IHCP.pvd'))

    #A = dt / 2. * k_mesh_oldp * do.dot(do.grad(p_stept), do.grad(v)) * do.dx(domain = hol_cyl) + \
    #    rho_mesh_oldp * cp_mesh_oldp * p_stept * v * do.dx(domain = hol_cyl)

    #runs backwards in time
    for count_t_i, t_i in reversed(list(enumerate(time_v[:-1]))):

        #int_fluxT_in = 0
        #e.g., count_t_i = 99
        int_fluxT_ex = (T_step_d[count_t_i] - T_exp_d[count_t_i]) * v * \
                       do.ds(mark_ex,
                             domain = hol_cyl,
                             subdomain_data = boundary_faces)

        #'old' = old tau = new time; e.g., count_t_i + 1 = 100
        int_fluxT_ex_old = (T_step_d[count_t_i + 1] - T_exp_d[count_t_i + 1]) * v * \
                           do.ds(mark_ex,
                                 domain = hol_cyl,
                                 subdomain_data = boundary_faces)

        L_oldp = -dt * (1. - theta) * k_mesh_oldp * do.dot(do.grad(p_old), do.grad(v)) * \
                 do.dx(domain = hol_cyl) + \
                 rho_mesh_oldp * cp_mesh_oldp * p_old * v * do.dx(domain = hol_cyl)

        #before:
        #L = L_oldp - (dt * theta * int_fluxT_ex + dt * (1. - theta) * int_fluxT_ex_old)
        L = L_oldp + (dt * theta * int_fluxT_ex + dt *
                      (1. - theta) * int_fluxT_ex_old)

        do.solve(A == L, p_step2)

        print 'p: count_t = {}, min(T_step_d) = {}'.format(
            count_t_i, min(T_step_d[count_t_i].vector().array()))

        print 'p: count_t = {}, max(T_step_d) = {}'.format(
            count_t_i, max(T_step_d[count_t_i].vector().array()))

        print 'p: count_t = {}, min(int_fluxT_ex) = {}'.format(
            count_t_i, min(do.assemble(int_fluxT_ex).array()))
        print 'p: count_t = {}, max(int_fluxT_ex) = {}'.format(
            count_t_i, max(do.assemble(int_fluxT_ex).array()))

        print 'p: count_t = {}, min(L) = {}'.format(
            count_t_i, min(do.assemble(L).array()))
        print 'p: count_t = {}, max(L) = {}'.format(
            count_t_i, max(do.assemble(L).array()))

        print 'p: count_t = {}, min(p) = {}'.format(count_t_i,
                                                    min(p_step2.vector()))
        print 'p: count_t = {}, max(p) = {}'.format(
            count_t_i, max(p_step2.vector())), '\n'

        p_old.assign(p_step2)

        p_step2.rename('dual_T', 'dual temperature')

        #storage
        p_step2_d[count_t_i] = do.Function(V)
        p_step2_d[count_t_i].vector()[:] = p_step2.vector().array()

        p_step2_f << (p_step2, t_i)

    return p_step2_d
def nablaT_fun(
        V,
        v,
        hol_cyl,
        A,
        boundary_faces,
        mark_in,
        mark_ex,
        T_old_v,
        g_d,  #S_in
        T_sol_d,
        T_ex,  #S_ex   
        unitNormal,
        k_mesh_old,
        cp_mesh_old,
        rho_mesh_old,
        dt,
        time_v,
        theta,
        itera,
        mesh_name,
        savings_do):
    '''
    Direct problem.
    Solves A T = L.
    A = dt * theta * k_mesh * do.dot(do.grad(T), do.grad(v)) * do.dx(domain = hol_cyl) + \
        rho_mesh * cp_mesh * T * v * do.dx(domain = hol_cyl)
        
    int_fluxT_ex = -k_mesh * do.dot(unitNormal, do.grad(T_sol)) * v * \
                         do.ds(mark_ex, 
                               domain = hol_cyl,
                               subdomain_data = boundary_faces)
                         
    no T_ex on outer boundary.                         
    '''
    #solver parameters
    #linear solvers from
    #list_linear_solver_methods()
    #preconditioners from
    #do.list_krylov_solver_preconditioners()
    solver = do.KrylovSolver('gmres', 'ilu')
    do.info(solver.parameters, False)  #prints default values
    solver.parameters['relative_tolerance'] = 1e-13
    solver.parameters['maximum_iterations'] = 2000000
    solver.parameters['monitor_convergence'] = True  #on the screen
    #http://fenicsproject.org/qa/1124/
    #is-there-a-way-to-set-the-inital-guess-in-the-krylov-solver
    solver.parameters['nonzero_initial_guess'] = True
    #solver.parameters['absolute_tolerance'] = 1e-15

    #T_stept = do.TrialFunction(V)
    T_step1 = do.Function(V)
    T_old = do.Function(V)

    #T_old_v is a scalar
    T_step1.vector()[:] = T_old_v
    T_old.vector()[:] = T_old_v

    T_step1_d = {}

    print 'T: min(g_d[0]) = ', min(g_d[0].vector().array())
    print 'T: max(g_d[0]) = ', max(g_d[0].vector().array())

    theta = do.Constant(theta)

    dt = do.Constant(dt)

    T_step1_f = do.File(os.path.join(savings_do, str(itera), 'dir_IHCP.pvd'))

    #A = dt / 2. * k_mesh_old * do.dot(do.grad(T_stept), do.grad(v)) * do.dx(domain = hol_cyl) + \
    #    rho_mesh_old * cp_mesh_old * T_stept * v * do.dx(domain = hol_cyl)

    for count_t_i, t_i in enumerate(time_v[1:]):
        #storage
        T_step1_d[count_t_i] = do.Function(V)
        T_step1_d[count_t_i].vector()[:] = T_step1.vector().array()

        #g is a k * dot(grad(T), n)
        int_fluxT_in = g_d[count_t_i + 1] * v * do.ds(
            mark_in, domain=hol_cyl, subdomain_data=boundary_faces)

        int_fluxT_in_old = g_d[count_t_i] * v * do.ds(
            mark_in, domain=hol_cyl, subdomain_data=boundary_faces)

        int_fluxT_ex = + k_mesh_old * do.dot(unitNormal, do.grad(T_sol_d[count_t_i + 1])) * \
                                  v * do.ds(mark_ex,
                                            domain = hol_cyl,
                                            subdomain_data = boundary_faces)

        int_fluxT_ex_old = + k_mesh_old * do.dot(unitNormal, do.grad(T_sol_d[count_t_i])) * \
                                      v * do.ds(mark_ex,
                                                domain = hol_cyl,
                                                subdomain_data = boundary_faces)

        #print 'T: type(int_fluxT_in) = ', type(int_fluxT_in)
        #print 'T: type(int_fluxT_in_old) = ', type(int_fluxT_in_old)
        #print 'T: min(int_fluxT_in) = ', min(do.assemble(int_fluxT_in))

        #L -= (int_fluxT_in + int_fluxT_ex)
        L_old = -dt * (1. - theta) * k_mesh_old * do.dot(do.grad(T_old), do.grad(v)) * \
                do.dx(domain = hol_cyl) + \
                rho_mesh_old * cp_mesh_old * T_old * v * do.dx(domain = hol_cyl)

        L = L_old + (dt * theta * int_fluxT_in + dt *
                     (1. - theta) * int_fluxT_in_old +
                     dt * theta * int_fluxT_ex + dt *
                     (1. - theta) * int_fluxT_ex_old)

        do.solve(A == L, T_step1)  #, bc_ex)

        print 'T: count_t = {}, avg(g) = {}'.format(
            count_t_i, np.mean(g_d[count_t_i + 1].vector().array()))
        print 'T: count_t = {}, min(L) = {}'.format(
            count_t_i, min(do.assemble(L).array()))
        print 'T: count_t = {}, max(L) = {}'.format(
            count_t_i, max(do.assemble(L).array()))
        print 'T: count_t = {}, min(T) = {}'.format(
            count_t_i, min(T_step1.vector().array()))
        print 'T: count_t = {}, max(T) = {}'.format(
            count_t_i, max(T_step1.vector().array()))
        print 'T: count_t = {}, min(T_DHCP) = {}'.format(
            count_t_i, min(T_sol_d[count_t_i].vector().array()))
        print 'T: count_t = {}, max(T_DHCP) = {}'.format(
            count_t_i, max(T_sol_d[count_t_i].vector().array())), '\n'

        T_old.assign(T_step1)

        #rename
        T_step1.rename('IHCP_T', 'temperature from IHCP')

        T_step1_f << (T_step1, t_i)

    count_t_i += 1

    #storage
    T_step1_d[count_t_i] = do.Function(V)
    T_step1_d[count_t_i].vector()[:] = T_step1.vector().array()

    return T_step1_d
예제 #13
0
파일: homog2d.py 프로젝트: bd1747/HO_homog
    def __init__(self, fenics_2d_rve, **kwargs):
        """[summary]

        Parameters
        ----------
        object : [type]
            [description]
        fenics_2d_rve : [type]
            [description]
        element : tuple or dict
            Type and degree of element for displacement FunctionSpace
            Ex: ('CG', 2) or {'family':'Lagrange', degree:2}
        solver : dict
            Choose the type of the solver, its method and the preconditioner.
            An up-to-date list of the available solvers and preconditioners
            can be obtained with dolfin.list_linear_solver_methods() and
            dolfin.list_krylov_solver_preconditioners().

        """
        self.rve = fenics_2d_rve
        self.topo_dim = topo_dim = fenics_2d_rve.dim
        try:
            bottom_left_corner = fenics_2d_rve.bottom_left_corner
        except AttributeError:
            logger.warning(
                "For the definition of the periodicity boundary conditions,"
                "the bottom left corner of the RVE is assumed to be on (0.,0.)"
            )
            bottom_left_corner = np.zeros(shape=(topo_dim, ))
        self.pbc = periodicity.PeriodicDomain.pbc_dual_base(
            fenics_2d_rve.gen_vect, "XY", bottom_left_corner, topo_dim)

        solver = kwargs.pop("solver", {})
        # {'type': solver_type, 'method': solver_method, 'preconditioner': preconditioner}
        s_type = solver.pop("type", None)
        s_method = solver.pop("method", SOLVER_METHOD)
        s_precond = solver.pop("preconditioner", None)
        if s_type is None:
            if s_method in DOLFIN_KRYLOV_METHODS.keys():
                s_type = "Krylov"
            elif s_method in DOLFIN_LU_METHODS.keys():
                s_type = "LU"
            else:
                raise RuntimeError("The indicated solver method is unknown.")
        self._solver = dict(type=s_type, method=s_method)
        if s_precond:
            self._solver["preconditioner"] = s_precond

        element = kwargs.pop("element", ("Lagrange", 2))
        if isinstance(element, dict):
            element = (element["family"], element["degree"])
        self._element = element

        # * Function spaces
        cell = self.rve.mesh.ufl_cell()
        self.scalar_FE = fe.FiniteElement(element[0], cell, element[1])
        self.displ_FE = fe.VectorElement(element[0], cell, element[1])
        strain_deg = element[1] - 1 if element[1] >= 1 else 0
        strain_dim = int(topo_dim * (topo_dim + 1) / 2)
        self.strain_FE = fe.VectorElement("DG",
                                          cell,
                                          strain_deg,
                                          dim=strain_dim)
        # Espace fonctionel scalaire
        self.X = fe.FunctionSpace(self.rve.mesh,
                                  self.scalar_FE,
                                  constrained_domain=self.pbc)
        # Espace fonctionnel 3D : deformations, notations de Voigt
        self.W = fe.FunctionSpace(self.rve.mesh, self.strain_FE)
        # Espace fonctionel 2D pour les champs de deplacement
        # TODO : reprendre le Ve défini pour l'espace fonctionnel mixte. Par ex: V = FunctionSpace(mesh, Ve)
        self.V = fe.VectorFunctionSpace(self.rve.mesh,
                                        element[0],
                                        element[1],
                                        constrained_domain=self.pbc)

        # * Espace fonctionel mixte pour la résolution :
        # * 2D pour les champs + scalaire pour multiplicateur de Lagrange

        # "R" : Real element with one global degree of freedom
        self.real_FE = fe.VectorElement("R", cell, 0)
        self.M = fe.FunctionSpace(
            self.rve.mesh,
            fe.MixedElement([self.displ_FE, self.real_FE]),
            constrained_domain=self.pbc,
        )

        # Define variational problem
        self.v, self.lamb_ = fe.TestFunctions(self.M)
        self.u, self.lamb = fe.TrialFunctions(self.M)
        self.w = fe.Function(self.M)

        # bilinear form
        self.a = (
            fe.inner(sigma(self.rve.C_per, epsilon(self.u)), epsilon(self.v)) *
            fe.dx + fe.dot(self.lamb_, self.u) * fe.dx +
            fe.dot(self.lamb, self.v) * fe.dx)
        self.K = fe.assemble(self.a)
        if self._solver["type"] == "Krylov":
            self.solver = fe.KrylovSolver(self.K, self._solver["method"])
        elif self._solver["type"] == "LU":
            self.solver = fe.LUSolver(self.K, self._solver["method"])
            self.solver.parameters["symmetric"] = True
        try:
            self.solver.parameters.preconditioner = self._solver[
                "preconditioner"]
        except KeyError:
            pass
        # fe.info(self.solver.parameters, True)

        self.localization = dict()
        # dictionary of localization field objects,
        # will be filled up when calling auxiliary problems (lazy evaluation)
        self.ConstitutiveTensors = dict()
예제 #14
0
    def __init__(self,
                 m,
                 parameters=None,
                 degree=1,
                 element="CG",
                 project_method='magpar',
                 unit_length=1,
                 Ms=None,
                 bench=False,
                 normalize=True,
                 solver_type=None):
        assert isinstance(m, Field)
        assert isinstance(
            Ms, Field
        )  # currently this means that Ms must be passed in (we don't have a default value)

        self.m = m

        # Problem objects and parameters
        self.name = "Demag"
        self.in_jacobian = False
        self.unit_length = unit_length
        self.degree = degree
        self.bench = bench
        self.parameters = parameters

        # This is used in energy density calculations
        self.mu0 = np.pi * 4e-7  # Vs/(Am)

        # Mesh Facet Normal
        self.n = df.FacetNormal(self.m.mesh())

        # Spaces and functions for the Demag Potential
        self.V = df.FunctionSpace(self.m.mesh(), element, degree)
        self.v = df.TestFunction(self.V)
        self.u = df.TrialFunction(self.V)
        self.phi = df.Function(self.V)

        # Space and functions for the Demag Field
        self.W = df.VectorFunctionSpace(self.m.mesh(), element, degree, dim=3)
        self.w = df.TrialFunction(self.W)
        self.vv = df.TestFunction(self.W)
        self.H_demag = df.Function(self.W)

        # Interpolate the Unit Magentisation field if necessary
        # A try block was not used since it might lead to an unneccessary (and potentially bad)
        # interpolation
        # if isinstance(m, df.Expression) or isinstance(m, df.Constant):
        #     self.m = df.interpolate(m,self.W)

        # elif isinstance(m,tuple):
        #     self.m = df.interpolate(df.Expression(m, degree=1),self.W)

        # elif isinstance(m,list):
        #     self.m = df.interpolate(df.Expression(tuple(m, degree=1)),self.W)

        # else:
        #     self.m = m
        # Normalize m (should be normalized anyway).
        # if normalize:
        #     self.m.vector()[:] = helpers.fnormalise(self.m.vector().array())

        assert isinstance(Ms, Field)
        self.Ms = Ms

        # Initilize the boundary element matrix variable
        self.bem = None

        # Objects that are needed frequently for linear solves.
        self.poisson_matrix = self.build_poisson_matrix()
        self.laplace_zeros = df.Function(self.V).vector()

        # 2nd FEM.
        if parameters:
            method = parameters["laplace_solver"]["method"]
            pc = parameters["laplace_solver"]["preconditioner"]
        else:
            method, pc = "default", "default"

        if solver_type is None:
            solver_type = 'Krylov'
        solver_type = solver_type.lower()
        if solver_type == 'lu':
            self.laplace_solver = df.LUSolver()
            self.laplace_solver.parameters["reuse_factorization"] = True
        elif solver_type == 'krylov':
            self.laplace_solver = df.KrylovSolver(method, pc)
            # We're setting 'same_nonzero_pattern=True' to enforce the
            # same matrix sparsity pattern across different demag solves,
            # which should speed up things.
            #self.laplace_solver.parameters["preconditioner"][
            #    "structure"] = "same_nonzero_pattern"
        else:
            raise ValueError(
                "Wrong solver type specified: '{}' (allowed values: 'Krylov', 'LU')"
                .format(solver_type))

        # Objects needed for energy density computation
        self.nodal_vol = df.assemble(self.v * df.dx).array()
        self.ED = df.Function(self.V)

        # Method to calculate the Demag field from the potential
        self.project_method = project_method
        if self.project_method == 'magpar':
            self.__setup_field_magpar()
            self.__compute_field = self.__compute_field_magpar
        elif self.project_method == 'project':
            self.__compute_field = self.__compute_field_project
        else:
            raise NotImplementedError("""Only methods currently implemented are
                                    * 'magpar',
                                    * 'project'""")
예제 #15
0
    def solve_linear(self, d_outputs, d_residuals, mode):
        linear_solver_ = self.options['linear_solver_']
        pde_problem = self.options['pde_problem']
        state_name = self.options['state_name']

        state_function = pde_problem.states_dict[state_name]['function']
        for argument_name, argument_function in iteritems(
                self.argument_functions_dict):
            density_func = argument_function
        mesh = state_function.function_space().mesh()
        sub_domains = df.MeshFunction('size_t', mesh,
                                      mesh.topology().dim() - 1)
        upper_edge = TractionBoundary()
        upper_edge.mark(sub_domains, 6)
        dss = df.Measure('ds')(subdomain_data=sub_domains)
        tractionBC = dss(6)

        residual_form = get_residual_form(
            state_function,
            df.TestFunction(state_function.function_space()),
            density_func,
            density_func.function_space(),
            tractionBC,
            # df.Constant((0.0, -9.e-1))
            df.Constant((0.0, -9.e-1)),
            int(self.itr))

        A, _ = df.assemble_system(self.derivative_form, -residual_form,
                                  pde_problem.bcs_list)

        if linear_solver_ == 'fenics_direct':

            rhs_ = df.Function(state_function.function_space())
            dR = df.Function(state_function.function_space())

            rhs_.vector().set_local(d_outputs[state_name])

            for bc in pde_problem.bcs_list:
                bc.apply(A)
            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            AT = df.PETScMatrix(ATm)

            df.solve(AT, dR.vector(), rhs_.vector())
            d_residuals[state_name] = dR.vector().get_local()

        elif linear_solver_ == 'scipy_splu':
            for bc in pde_problem.bcs_list:
                bc.apply(A)
            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            ATm_csr = csr_matrix(ATm.getValuesCSR()[::-1], shape=Am.size)
            lu = splu(ATm_csr.tocsc())
            d_residuals[state_name] = lu.solve(d_outputs[state_name],
                                               trans='T')

        elif linear_solver_ == 'fenics_Krylov':

            rhs_ = df.Function(state_function.function_space())
            dR = df.Function(state_function.function_space())

            rhs_.vector().set_local(d_outputs[state_name])

            for bc in pde_problem.bcs_list:
                bc.apply(A)
            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            AT = df.PETScMatrix(ATm)

            solver = df.KrylovSolver('gmres', 'ilu')
            prm = solver.parameters
            prm["maximum_iterations"] = 1000000
            prm["divergence_limit"] = 1e2
            solver.solve(AT, dR.vector(), rhs_.vector())

            d_residuals[state_name] = dR.vector().get_local()

        elif linear_solver_ == 'petsc_gmres_ilu':
            ksp = PETSc.KSP().create()
            ksp.setType(PETSc.KSP.Type.GMRES)
            ksp.setTolerances(rtol=5e-11)

            for bc in pde_problem.bcs_list:
                bc.apply(A)
            Am = df.as_backend_type(A).mat()

            ksp.setOperators(Am)

            ksp.setFromOptions()
            pc = ksp.getPC()
            pc.setType("ilu")

            size = state_function.function_space().dim()

            dR = PETSc.Vec().create()
            dR.setSizes(size)
            dR.setType('seq')
            dR.setValues(range(size), d_residuals[state_name])
            dR.setUp()

            du = PETSc.Vec().create()
            du.setSizes(size)
            du.setType('seq')
            du.setValues(range(size), d_outputs[state_name])
            du.setUp()

            if mode == 'fwd':
                ksp.solve(dR, du)
                d_outputs[state_name] = du.getValues(range(size))
            else:
                ksp.solveTranspose(du, dR)
                d_residuals[state_name] = dR.getValues(range(size))
예제 #16
0
    def solve_linear(self, d_outputs, d_residuals, mode):

        option = self.options['option']

        dR_du_sparse = self.dR_du_sparse

        
        if option==1:

            ksp = PETSc.KSP().create() 

            ksp.setType(PETSc.KSP.Type.GMRES)
            ksp.setTolerances(rtol=5e-14)
            ksp.setOperators(dR_du_sparse)
            ksp.setFromOptions()

            pc = ksp.getPC()
            pc.setType("ilu")

            size = len(self.fea.VC.dofmap().dofs())

            dR = PETSc.Vec().create()
            dR.setSizes(size)
            dR.setType('seq')
            dR.setValues(range(size), d_residuals['density'])
            dR.setUp()

            du = PETSc.Vec().create()
            du.setSizes(size)
            du.setType('seq')
            du.setValues(range(size), d_outputs['density'])
            du.setUp()

            if mode == 'fwd':
                ksp.solve(dR,du)
                d_outputs['density'] = du.getValues(range(size))
            else:
                ksp.solveTranspose(du,dR)
                d_residuals['density'] = dR.getValues(range(size))
                print('d_residual[density]', d_residuals['density'])
        elif option==2:
            # print('option 2')

            rhs_ = df.Function(self.function_space)
            dR = df.Function(self.function_space)

            rhs_.vector().set_local(d_outputs['density'])

            A = self.A
            Am = df.as_backend_type(A).mat()

            ATm = Am.transpose()
            AT =  df.PETScMatrix(ATm)

            df.solve(AT,dR.vector(),rhs_.vector()) # cannot directly use fea.u here, the update for the solution is not compatible
            d_residuals['density'] =  dR.vector().get_local()


        elif option==3:
            A = self.A

            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            ATm_csr = csr_matrix(ATm.getValuesCSR()[::-1], shape=Am.size)
            lu = splu(ATm_csr.tocsc())
            d_residuals['density'] = lu.solve(d_outputs['density'],trans='T')


        elif option==4:

            rhs_ = df.Function(self.function_space)
            dR = df.Function(self.function_space)

            rhs_.vector().set_local(d_outputs['density'])

            A = self.A
            Am = df.as_backend_type(A).mat()

            ATm = Am.transpose()
            AT =  df.PETScMatrix(ATm)
            df.set_log_active(True)

            solver = df.KrylovSolver('gmres', 'ilu')
            prm = solver.parameters          
            prm["maximum_iterations"]=1000000
            prm["divergence_limit"] = 1e2
            # info(parameters,True)
            solver.solve(AT,dR.vector(),rhs_.vector())


            d_residuals['displacements'] =  dR.vector().get_local()
예제 #17
0
    def setup(self, m, Ms, unit_length=1):

        self.m = m
        self.Ms = Ms
        self.unit_length = unit_length

        mesh = m.mesh()
        self.S1 = df.FunctionSpace(mesh, "Lagrange", 1)
        self.dim = mesh.topology().dim()

        self._test1 = df.TestFunction(self.S1)
        self._trial1 = df.TrialFunction(self.S1)
        self._test3 = df.TestFunction(self.m.functionspace)
        self._trial3 = df.TrialFunction(self.m.functionspace)

        # for computation of energy
        self._nodal_volumes = nodal_volume(self.S1, unit_length)
        # we will copy field into this when we need the energy
        self._H_func = df.Function(self.m.functionspace)
        self._E_integrand = -0.5 * mu0 * \
            df.dot(self._H_func, self.m.f * self.Ms.f)
        self._E = self._E_integrand * df.dx
        self._nodal_E = df.dot(self._E_integrand, self._test1) * df.dx
        self._nodal_E_func = df.Function(self.S1)

        # for computation of field and scalar magnetic potential
        self._poisson_matrix = self._poisson_matrix()
        self._poisson_solver = df.KrylovSolver(
            self._poisson_matrix.copy(), self.parameters['phi_1_solver'],
            self.parameters['phi_1_preconditioner'])
        self._poisson_solver.parameters.update(self.parameters['phi_1'])
        self._laplace_zeros = df.Function(self.S1).vector()
        self._laplace_solver = df.KrylovSolver(
            self.parameters['phi_2_solver'],
            self.parameters['phi_2_preconditioner'])
        self._laplace_solver.parameters.update(self.parameters['phi_2'])
        # We're setting 'same_nonzero_pattern=True' to enforce the
        # same matrix sparsity pattern across different demag solves,
        # which should speed up things.
        self._laplace_solver.parameters["preconditioner"][
            "structure"] = "same_nonzero_pattern"

        # solution of inhomogeneous Neumann problem
        self._phi_1 = df.Function(self.S1)
        # solution of Laplace equation inside domain
        self._phi_2 = df.Function(self.S1)
        self._phi = df.Function(self.S1)  # magnetic potential phi_1 + phi_2

        # To be applied to the vector field m as first step of computation of _phi_1.
        # This gives us div(M), which is equal to Laplace(_phi_1), equation
        # which is then solved using _poisson_solver.
        self._Ms_times_divergence = df.assemble(
            self.Ms.f * df.inner(self._trial3, df.grad(self._test1)) * df.dx)

        # we move the bounday condition here to avoid create a instance each time when compute the
        # magnetic potential
        self.boundary_condition = df.DirichletBC(self.S1, self._phi_2,
                                                 df.DomainBoundary())
        self.boundary_condition.apply(self._poisson_matrix)

        self._setup_gradient_computation()

        self.mesh = self.m.mesh()

        self.bmesh = df.BoundaryMesh(self.mesh, 'exterior', False)
        #self.b2g_map = self.bmesh.vertex_map().array()
        self._b2g_map = self.bmesh.entity_map(0).array()

        self.compute_triangle_normal()

        self.__compute_bsa()

        fast_sum = FastSum(p=self.p,
                           mac=self.mac,
                           num_limit=self.num_limit,
                           correct_factor=self.correct_factor,
                           type_I=self.type_I)

        coords = self.bmesh.coordinates()
        face_nodes = np.array(self.bmesh.cells(), dtype=np.int32)

        fast_sum.init_mesh(coords, self.t_normals, face_nodes, self.vert_bsa)
        self.fast_sum = fast_sum

        self.phi2_b = np.zeros(self.bmesh.num_vertices())
예제 #18
0
    def solve_linear(self, d_outputs, d_residuals, mode):
        linear_solver_ = self.options['linear_solver_']
        pde_problem = self.options['pde_problem']
        state_name = self.options['state_name']

        state_function = pde_problem.states_dict[state_name]['function']

        residual_form = pde_problem.states_dict[state_name]['residual_form']
        if state_name == 'density':
            print('this is a variational density filter')
            A, _ = df.assemble_system(self.derivative_form, -residual_form)
        else:
            A, _ = df.assemble_system(self.derivative_form, -residual_form,
                                      pde_problem.bcs_list)

        def report(xk):
            frame = inspect.currentframe().f_back

        if linear_solver_ == 'fenics_direct':

            rhs_ = df.Function(state_function.function_space())
            dR = df.Function(state_function.function_space())

            rhs_.vector().set_local(d_outputs[state_name])
            if state_name != 'density':
                for bc in pde_problem.bcs_list:
                    bc.apply(A)
            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            AT = df.PETScMatrix(ATm)

            df.solve(AT, dR.vector(), rhs_.vector())
            d_residuals[state_name] = dR.vector().get_local()

        elif linear_solver_ == 'scipy_splu':
            if state_name != 'density':
                for bc in pde_problem.bcs_list:
                    bc.apply(A)
            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            ATm_csr = csr_matrix(ATm.getValuesCSR()[::-1], shape=Am.size)
            lu = splu(ATm_csr.tocsc())
            d_residuals[state_name] = lu.solve(d_outputs[state_name],
                                               trans='T')

        elif linear_solver_ == 'scipy_cg':
            if state_name != 'density':
                for bc in pde_problem.bcs_list:
                    bc.apply(A)
            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            ATm_csr = csr_matrix(ATm.getValuesCSR()[::-1], shape=Am.size)
            # lu = splu(ATm_csr.tocsc())
            b = d_outputs[state_name]
            x, info = splinalg.cg(ATm_csr, b, tol=1e-8, callback=report)
            print('the residual is:')
            print(info)

            d_residuals[state_name] = x

        elif linear_solver_ == 'fenics_krylov':

            rhs_ = df.Function(state_function.function_space())
            dR = df.Function(state_function.function_space())

            rhs_.vector().set_local(d_outputs[state_name])
            if state_name != 'density':
                for bc in pde_problem.bcs_list:
                    bc.apply(A)

            Am = df.as_backend_type(A).mat()
            ATm = Am.transpose()
            AT = df.PETScMatrix(ATm)

            solver = df.KrylovSolver('gmres', 'ilu')
            prm = solver.parameters
            prm["maximum_iterations"] = 1000000
            prm["divergence_limit"] = 1e2
            solver.solve(AT, dR.vector(), rhs_.vector())
            # print('solve'+iter)

            d_residuals[state_name] = dR.vector().get_local()

        elif linear_solver_ == 'petsc_gmres_ilu':
            ksp = PETSc.KSP().create()
            ksp.setType(PETSc.KSP.Type.GMRES)
            ksp.setTolerances(rtol=5e-17)

            if state_name != 'density':
                for bc in pde_problem.bcs_list:
                    bc.apply(A)
            Am = df.as_backend_type(A).mat()

            ksp.setOperators(Am)

            ksp.setFromOptions()
            pc = ksp.getPC()
            pc.setType("lu")

            size = state_function.function_space().dim()

            dR = PETSc.Vec().create()
            dR.setSizes(size)
            dR.setType('seq')
            dR.setValues(range(size), d_residuals[state_name])
            dR.setUp()

            du = PETSc.Vec().create()
            du.setSizes(size)
            du.setType('seq')
            du.setValues(range(size), d_outputs[state_name])
            du.setUp()

            if mode == 'fwd':
                ksp.solve(dR, du)
                d_outputs[state_name] = du.getValues(range(size))
            else:
                ksp.solveTranspose(du, dR)
                d_residuals[state_name] = dR.getValues(range(size))

        elif linear_solver_ == 'petsc_cg_ilu':
            ksp = PETSc.KSP().create()
            ksp.setType(PETSc.KSP.Type.CG)
            ksp.setTolerances(rtol=5e-15)

            if state_name != 'density':
                for bc in pde_problem.bcs_list:
                    bc.apply(A)
            Am = df.as_backend_type(A).mat()

            ksp.setOperators(Am)

            ksp.setFromOptions()
            pc = ksp.getPC()
            pc.setType("lu")

            size = state_function.function_space().dim()

            dR = PETSc.Vec().create()
            dR.setSizes(size)
            dR.setType('seq')
            dR.setValues(range(size), d_residuals[state_name])
            dR.setUp()

            du = PETSc.Vec().create()
            du.setSizes(size)
            du.setType('seq')
            du.setValues(range(size), d_outputs[state_name])
            du.setUp()

            if mode == 'fwd':
                ksp.solve(dR, du)
                d_outputs[state_name] = du.getValues(range(size))
            else:
                ksp.solveTranspose(du, dR)
                d_residuals[state_name] = dR.getValues(range(size))
예제 #19
0
import dolfin as d
import vtk

print(vtk.VTK_VERSION)
dump_file = d.HDF5File(d.mpi_comm_world(), 'test.h5', 'w')
dump_file_2 = d.File('test.xml.gz')
solver = d.KrylovSolver("cg", "hypre_amg")
mesh = d.UnitCubeMesh(10, 10, 10)
V = d.FunctionSpace(mesh, "CG", 2)
phi = d.Function(V)

dump_file.write(phi, 'phi_func')
dump_file.close()
        
dump_file_2 << phi

예제 #20
0
    def run(self, species="Oxygen", increment=0):

        # Specify the test/trial function space

        df.set_log_active(False)
        V = df.FunctionSpace(self.mesh, "Lagrange", 1)

        # Specify the boundary conditions, Dirichlet on all domain faces
        def u0_boundary(x, on_boundary):
            return on_boundary

        # Define the problem
        u = df.TrialFunction(V)
        v = df.TestFunction(V)
        if species == "Oxygen":
            bc = df.DirichletBC(V, df.Constant(1), u0_boundary)
            f = df.Constant(0.0)
            a = self.Dc * df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx
            L = f * v * df.dx
        elif species == "Factor":
            bc = df.DirichletBC(V, df.Constant(0), u0_boundary)
            f = df.Constant(0)
            a = (self.decayRate * u * v + self.Dv *
                 df.inner(df.nabla_grad(u), df.nabla_grad(v))) * df.dx
            L = f * v * df.dx

        # Assemble the system
        A, b = df.assemble_system(a, L, bc)

        if species == "Oxygen":

            # Add vessel source terms
            vesselSources = self.sources[1]
            for eachSource in vesselSources:
                location = [
                    point - self.spacing / 2.0 for point in eachSource[0]
                ]
                if self.extents[2] > 1:
                    delta = df.PointSource(
                        V, df.Point(location[0], location[1], location[2]),
                        self.permeability * eachSource[1])
                else:
                    delta = df.PointSource(V, df.Point(location[0],
                                                       location[1]),
                                           self.permeability * eachSource[1])
                try:
                    delta.apply(b)
                except:
                    pass

            # Add cell sink terms
            cellSources = self.sources[0]
            for eachSource in cellSources:
                location = [
                    point - self.spacing / 2.0 for point in eachSource[0]
                ]
                if self.extents[2] > 1:
                    delta = df.PointSource(
                        V, df.Point(location[0], location[1], location[2]),
                        -self.consumptionRate * eachSource[1])
                else:
                    delta = df.PointSource(
                        V, df.Point(location[0], location[1]),
                        -self.consumptionRate * eachSource[1])
                try:
                    delta.apply(b)
                except:
                    pass

        elif species == "Factor":
            # Add cell source terms
            cellSources = self.sources[0]
            for eachSource in cellSources:
                location = [
                    point - self.spacing / 2.0 for point in eachSource[0]
                ]
                if self.extents[2] > 1:
                    delta = df.PointSource(
                        V, df.Point(location[0], location[1], location[2]),
                        self.factorSensitvity * eachSource[1])
                else:
                    delta = df.PointSource(
                        V, df.Point(location[0], location[1]),
                        self.factorSensitvity * eachSource[1])
                try:
                    delta.apply(b)
                except:
                    pass

        # Set up solution vector
        u = df.Function(V)
        U = u.vector()

        # Set up and run solver
        solver = df.KrylovSolver("cg", "ilu")
        solver.solve(A, U, b)

        self.result = []
        for eachEntry in self.sources[0]:
            location = [point - self.spacing / 2.0 for point in eachEntry[0]]
            if self.extents[2] <= 1:
                location = location[:2]
            try:
                result = u(location)
            except:
                if species == "Oxygen":
                    result = 1.0
                else:
                    result = 0.0
            self.result.append(result)

        self.write_output(species, increment)
        return self.result
예제 #21
0
파일: fk_demag.py 프로젝트: whshangl/finmag
    def setup(self, DG3, m, Ms, unit_length=1):
        """
        Setup the FKDemag instance. Usually called automatically by the Simulation object.

        *Arguments*

        S3: dolfin.VectorFunctionSpace

            The finite element space the magnetisation is defined on.

        m: dolfin.Function on S3

            The unit magnetisation.

        Ms: float

            The saturation magnetisation in A/m.

        unit_length: float

            The length (in m) represented by one unit on the mesh. Default 1.

        """
        self.m = m
        self.Ms = Ms
        self.unit_length = unit_length

        mesh = DG3.mesh()
        self.S1 = df.FunctionSpace(mesh, "Lagrange", 1)
        self.S3 = df.VectorFunctionSpace(mesh, "Lagrange", 1)
        self.dim = mesh.topology().dim()

        self.n = df.FacetNormal(mesh)

        self.DG3 = DG3

        self._test1 = df.TestFunction(self.S1)
        self._trial1 = df.TrialFunction(self.S1)
        self._test3 = df.TestFunction(self.S3)
        self._trial3 = df.TrialFunction(self.S3)
        self._test_dg3 = df.TestFunction(self.DG3)
        self._trial_dg3 = df.TrialFunction(self.DG3)

        # for computation of energy
        self._nodal_volumes = nodal_volume(self.S1, unit_length)
        self._H_func = df.Function(
            DG3)  # we will copy field into this when we need the energy
        self._E_integrand = -0.5 * mu0 * df.dot(self._H_func, self.m * self.Ms)
        self._E = self._E_integrand * df.dx
        self._nodal_E = df.dot(self._E_integrand, self._test1) * df.dx
        self._nodal_E_func = df.Function(self.S1)

        # for computation of field and scalar magnetic potential
        self._poisson_matrix = self._poisson_matrix()
        self._poisson_solver = df.KrylovSolver(
            self._poisson_matrix, self.parameters['phi_1_solver'],
            self.parameters['phi_1_preconditioner'])
        self._poisson_solver.parameters.update(self.parameters['phi_1'])
        self._laplace_zeros = df.Function(self.S1).vector()
        self._laplace_solver = df.KrylovSolver(
            self.parameters['phi_2_solver'],
            self.parameters['phi_2_preconditioner'])
        self._laplace_solver.parameters.update(self.parameters['phi_2'])
        self._laplace_solver.parameters["preconditioner"][
            "same_nonzero_pattern"] = True
        with fk_timed('compute BEM'):
            if not hasattr(self, "_bem"):
                self._bem, self._b2g_map = compute_bem_fk(
                    df.BoundaryMesh(mesh, 'exterior', False))
        self._phi_1 = df.Function(
            self.S1)  # solution of inhomogeneous Neumann problem
        self._phi_2 = df.Function(
            self.S1)  # solution of Laplace equation inside domain
        self._phi = df.Function(self.S1)  # magnetic potential phi_1 + phi_2

        # To be applied to the vector field m as first step of computation of _phi_1.
        # This gives us div(M), which is equal to Laplace(_phi_1), equation
        # which is then solved using _poisson_solver.
        self._Ms_times_divergence = df.assemble(
            self.Ms * df.inner(self._trial_dg3, df.grad(self._test1)) * df.dx)

        self._setup_gradient_computation()
예제 #22
0
    def setup(self, m, Ms, unit_length=1):
        """
        Setup the FKDemag instance. Usually called automatically by the
        Simulation object.

        *Arguments*

        m: finmag.Field

            The unit magnetisation on a finite element space.

        Ms: float

            The saturation magnetisation in A/m.

        unit_length: float

            The length (in m) represented by one unit on the mesh. Default 1.

        """
        assert isinstance(m, Field)
        assert isinstance(Ms, Field)

        self.m = m
        self.Ms = Ms
        self.unit_length = unit_length
        self.S1 = df.FunctionSpace(self.m.mesh(), "Lagrange", 1)

        self._test1 = df.TestFunction(self.S1)
        self._trial1 = df.TrialFunction(self.S1)
        self._test3 = df.TestFunction(self.m.functionspace)
        self._trial3 = df.TrialFunction(self.m.functionspace)

        # for computation of energy
        self._nodal_volumes = nodal_volume(self.S1, unit_length)
        self._H_func = df.Function(m.functionspace)  # we will copy field into
        # this when we need the
        # energy
        self._E_integrand = -0.5 * mu0 * \
            df.dot(self._H_func, self.m.f * self.Ms.f)
        self._E = self._E_integrand * df.dx
        self._nodal_E = df.dot(self._E_integrand, self._test1) * df.dx
        self._nodal_E_func = df.Function(self.S1)

        # for computation of field and scalar magnetic potential
        self._poisson_matrix = self._poisson_matrix()
        self._laplace_zeros = df.Function(self.S1).vector()

        # determine the solver type to be used (Krylov or LU); if the kwarg
        # 'solver_type' is not provided, try to read the setting from the
        # .finmagrc file; use 'Krylov' if this fails.
        solver_type = self.solver_type
        if solver_type is None:
            solver_type = configuration.get_config_option(
                'demag', 'solver_type', 'Krylov')
        if solver_type == 'None':  # if the user set 'solver_type = None' in
            # the .finmagrc file, solver_type will be a
            # string so we need to catch this here.
            solver_type = 'Krylov'
        logger.debug("Using {} solver for demag.".format(solver_type))

        if solver_type == 'Krylov':
            self._poisson_solver = df.KrylovSolver(
                self._poisson_matrix.copy(), self.parameters['phi_1_solver'],
                self.parameters['phi_1_preconditioner'])
            self._poisson_solver.parameters.update(self.parameters['phi_1'])
            self._laplace_solver = df.KrylovSolver(
                self.parameters['phi_2_solver'],
                self.parameters['phi_2_preconditioner'])
            self._laplace_solver.parameters.update(self.parameters['phi_2'])
            # We're setting 'same_nonzero_pattern=True' to enforce the
            # same matrix sparsity pattern across different demag solves,
            # which should speed up things.
            #self._laplace_solver.parameters["preconditioner"][
            #    "structure"] = "same_nonzero_pattern"
        elif solver_type == 'LU':
            self._poisson_solver = df.LUSolver(self._poisson_matrix.copy())
            self._laplace_solver = df.LUSolver()
            self._poisson_solver.parameters["reuse_factorization"] = True
            self._laplace_solver.parameters["reuse_factorization"] = True
        else:
            raise ValueError(
                "Argument 'solver_type' must be either 'Krylov' or 'LU'. "
                "Got: '{}'".format(solver_type))

        with fk_timer('compute BEM'):
            if not hasattr(self, "_bem"):
                if self.macrogeometry is not None:
                    Ts = self.macrogeometry.compute_Ts(self.m.mesh())
                    pbc = BMatrixPBC(self.m.mesh(), Ts)
                    self._b2g_map = np.array(pbc.b2g_map, dtype=np.int)
                    self._bem = pbc.bm
                else:
                    self._bem, self._b2g_map = compute_bem_fk(
                        df.BoundaryMesh(self.m.mesh(), 'exterior', False))
        logger.debug(
            "Boundary element matrix uses {:.2f} MB of memory.".format(
                self._bem.nbytes / 1024.**2))
        # solution of inhomogeneous Neumann problem
        self._phi_1 = df.Function(self.S1)
        # solution of Laplace equation inside domain
        self._phi_2 = df.Function(self.S1)
        self._phi = df.Function(self.S1)  # magnetic potential phi_1 + phi_2

        # To be applied to the vector field m as first step of computation of
        # _phi_1.  This gives us div(M), which is equal to Laplace(_phi_1),
        # equation which is then solved using _poisson_solver.
        self._Ms_times_divergence = df.assemble(
            self.Ms.f * df.inner(self._trial3, df.grad(self._test1)) * df.dx)

        # we move the boundary condition here to avoid create a instance each
        # time when compute the magnetic potential
        self.boundary_condition = df.DirichletBC(self.S1, self._phi_2,
                                                 df.DomainBoundary())
        self.boundary_condition.apply(self._poisson_matrix)

        self._setup_gradient_computation()
    (v, q) = df.TestFunctions(W)
    f = df.Constant((0.0, 0.0))  # right hand side
    a = mu * df.inner(df.grad(u), df.grad(v)) * df.dx + df.div(v) * p * df.dx + q * df.div(u) * df.dx
    L = df.inner(f, v) * df.dx

    # Form for use in constructing preconditioner matrix
    b = df.inner(df.grad(u), df.grad(v)) * df.dx + p * q * df.dx

    # Assemble system
    A, bb = df.assemble_system(a, L, bcs)

    # Assemble preconditioner system
    P, btmp = df.assemble_system(b, L, bcs)

    # Create Krylov solver and AMG preconditioner
    solver = df.KrylovSolver(krylov_method, 'amg')

    # Associate operator (A) and preconditioner matrix (P)
    solver.set_operators(A, P)

    # Solve
    print('Solving PDE...')
    t = time.time()
    U = df.Function(W)

    #this should go fast up to here, so let's flush before solving the PDE
    sys.stdout.flush()

    try:
        solver.solve(U.vector(), bb)
        elapsed_time = time.time() - t