Exemple #1
0
    def test01_solve_2d(self):
        """
        Solve a simple 2D problem with no hanging nodes
        """
        mesh = QuadMesh(resolution=(5, 5))

        # Mark dirichlet boundaries
        mesh.mark_region('left',
                         lambda x, dummy: np.abs(x) < 1e-9,
                         entity_type='half_edge')

        mesh.mark_region('right',
                         lambda x, dummy: np.abs(x - 1) < 1e-9,
                         entity_type='half_edge')

        Q1 = QuadFE(mesh.dim(), 'Q1')
        dQ1 = DofHandler(mesh, Q1)
        dQ1.distribute_dofs()

        phi = Basis(dQ1, 'u')
        phi_x = Basis(dQ1, 'ux')
        phi_y = Basis(dQ1, 'uy')

        problem = [
            Form(1, test=phi_x, trial=phi_x),
            Form(1, test=phi_y, trial=phi_y),
            Form(0, test=phi)
        ]

        assembler = Assembler(problem, mesh)
        assembler.add_dirichlet('left', dir_fn=0)
        assembler.add_dirichlet('right', dir_fn=1)
        assembler.assemble()

        # Get matrix dirichlet correction and right hand side
        A = assembler.get_matrix().toarray()
        x0 = assembler.assembled_bnd()
        b = assembler.get_vector()

        ua = np.zeros((phi.n_dofs(), 1))
        int_dofs = assembler.get_dofs('interior')
        ua[int_dofs, 0] = np.linalg.solve(A, b - x0)

        dir_bc = assembler.get_dirichlet()
        dir_vals = np.array([dir_bc[dof] for dof in dir_bc])
        dir_dofs = [dof for dof in dir_bc]
        ua[dir_dofs] = dir_vals

        ue_fn = Nodal(f=lambda x: x[:, 0], basis=phi)
        ue = ue_fn.data()
        self.assertTrue(np.allclose(ue, ua))
        self.assertTrue(np.allclose(x0 + A.dot(ua[int_dofs, 0]), b))
Exemple #2
0
def sensitivity_sample_qoi(exp_q, dofhandler):
    """
    Sample QoI by means of Taylor expansion
    
        J(q+dq) ~= J(q) + dJdq(q)dq
    """
    # Basis
    phi = Basis(dofhandler, 'v')
    phi_x = Basis(dofhandler, 'vx')

    # Define problem
    exp_q_fn = Nodal(data=exp_q, basis=phi)

    primal = [Form(exp_q_fn, test=phi_x, trial=phi_x), Form(1, test=phi)]
    adjoint = [Form(exp_q_fn, test=phi_x, trial=phi_x), Form(0, test=phi)]
    qoi = [Form(exp_q_fn, test=phi_x)]
    problems = [primal, adjoint, qoi]

    # Define assembler
    assembler = Assembler(problems)

    #
    # Dirichlet conditions for primal problem
    #
    assembler.add_dirichlet('left', 0, i_problem=0)
    assembler.add_dirichlet('right', 1, i_problem=0)

    # Dirichlet conditions for adjoint problem
    assembler.add_dirichlet('left', 0, i_problem=1)
    assembler.add_dirichlet('right', -1, i_problem=1)

    # Assemble system
    assembler.assemble()

    # Compute solution and qoi at q (primal)
    u = assembler.solve(i_problem=0)

    # Compute solution of the adjoint problem
    v = assembler.solve(i_problem=1)

    # Evaluate J
    J = u.dot(assembler.get_vector(2))

    #
    # Assemble gradient
    #
    ux_fn = Nodal(data=u, basis=phi_x)
    vx_fn = Nodal(data=v, basis=phi_x)

    k_int = Kernel(f=[exp_q_fn, ux_fn, vx_fn],
                   F=lambda exp_q, ux, vx: exp_q * ux * vx)

    problem = [Form(k_int, test=phi)]

    assembler = Assembler(problem)
    assembler.assemble()
    dJ = -assembler.get_vector()
    return dJ
Exemple #3
0
    def test01_solve_1d(self):
        """
        Test solving 1D systems
        """
        mesh = Mesh1D(resolution=(20, ))
        mesh.mark_region('left', lambda x: np.abs(x) < 1e-9)
        mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-9)

        Q1 = QuadFE(1, 'Q1')
        dQ1 = DofHandler(mesh, Q1)
        dQ1.distribute_dofs()

        phi = Basis(dQ1, 'u')
        phi_x = Basis(dQ1, 'ux')

        problem = [Form(1, test=phi_x, trial=phi_x), Form(0, test=phi)]
        assembler = Assembler(problem, mesh)
        assembler.add_dirichlet('left', dir_fn=0)
        assembler.add_dirichlet('right', dir_fn=1)
        assembler.assemble()

        # Get matrix dirichlet correction and right hand side
        A = assembler.get_matrix().toarray()
        x0 = assembler.assembled_bnd()
        b = assembler.get_vector()

        ua = np.zeros((phi.n_dofs(), 1))
        int_dofs = assembler.get_dofs('interior')
        ua[int_dofs, 0] = np.linalg.solve(A, b - x0)

        dir_bc = assembler.get_dirichlet()
        dir_vals = np.array([dir_bc[dof] for dof in dir_bc])
        dir_dofs = [dof for dof in dir_bc]
        ua[dir_dofs] = dir_vals

        ue_fn = Nodal(f=lambda x: x[:, 0], basis=phi)
        ue = ue_fn.data()
        self.assertTrue(np.allclose(ue, ua))
        self.assertTrue(np.allclose(x0 + A.dot(ua[int_dofs, 0]), b))
Exemple #4
0
            #
            # Define weak form
            #
            a_diff_x = Form(eps, trial=ux, test=ux)
            a_diff_y = Form(eps, trial=uy, test=uy)
            a_adv_x = Form(vx, trial=ux, test=u)
            a_adv_y = Form(vy, trial=uy, test=u)
            b = Form(f, test=u)

            problem = [a_diff_x, a_diff_y, a_adv_x, a_adv_y, b]

            #
            # Assembler system
            #
            assembler = Assembler([problem], mesh)
            assembler.add_dirichlet(None, ue)
            assembler.assemble()

            #
            # Get solution
            #
            ua = assembler.solve()

            #
            # Compute the error
            #
            e_vec = ua[:, None] - ue.interpolant(dofhandler).data()
            efn = Nodal(data=e_vec, basis=u, dim=2)

            #
            # Record error
Exemple #5
0
plot.contour(eq, n_sample=25)

#
# Compute state
#

# Define weak form
state = [[
    Form(eq, test=phix_1, trial=phix_1),
    Form(eq, test=phiy_1, trial=phiy_1),
    Form(1, test=phi_1)
], [Form(1, test=phi_1, flag='dmn')]]

# Assemble system
assembler = Assembler(state)
assembler.add_dirichlet('bnd')
assembler.assemble()

J = assembler.get_vector(1)

# Solve system
u_vec = assembler.solve()
u = Nodal(basis=phi_1, data=u_vec)

plot.contour(u)
plt.title('Sample Path')

# Solve the adjoint system
adjoint = [
    Form(eq, test=phix_2, trial=phix_2),
    Form(eq, test=phiy_2, trial=phiy_2),
Exemple #6
0
# Sample from field
tht_fn = Nodal(data=tht.sample(n_samples=3), basis=phi)
plot = Plot()
plot.contour(tht_fn)

#
# Advection
#
v = [0.1, -0.1]

plot.mesh(mesh, regions=[('in', 'edge'), ('out', 'edge'), ('reg', 'cell')])

k = Kernel(tht_fn, F=lambda tht: np.exp(tht))
adv_diff = [
    Form(k, trial=phi_x, test=phi_x),
    Form(k, trial=phi_y, test=phi_y),
    Form(0, test=phi),
    Form(v[0], trial=phi_x, test=phi),
    Form(v[1], trial=phi_y, test=phi)
]

average = [Form(1, test=phi, flag='reg'), Form(1, flag='reg')]
assembler = Assembler([adv_diff, average], mesh)
assembler.add_dirichlet('out', dir_fn=0)
assembler.add_dirichlet('in', dir_fn=10)

assembler.assemble()

u_vec = assembler.solve(i_problem=0, i_matrix=0, i_vector=0)
plot.contour(Nodal(data=u_vec, basis=phi))
Exemple #7
0
def test_ft():
    plot = Plot()
    vb = Verbose()

    # =============================================================================
    # Parameters
    # =============================================================================
    #
    # Flow
    #

    # permeability field
    phi = Constant(1)  # porosity
    D = Constant(0.0252)  # dispersivity
    K = Constant(1)  # permeability

    # =============================================================================
    # Mesh and Elements
    # =============================================================================
    # Mesh
    mesh = QuadMesh(resolution=(30, 30))

    # Mark left and right regions
    mesh.mark_region('left',
                     lambda x, y: np.abs(x) < 1e-9,
                     entity_type='half_edge')
    mesh.mark_region('right',
                     lambda x, y: np.abs(x - 1) < 1e-9,
                     entity_type='half_edge')

    # Elements
    p_element = QuadFE(2, 'Q1')  # element for pressure
    c_element = QuadFE(2, 'Q1')  # element for concentration

    # Dofhandlers
    p_dofhandler = DofHandler(mesh, p_element)
    c_dofhandler = DofHandler(mesh, c_element)

    p_dofhandler.distribute_dofs()
    c_dofhandler.distribute_dofs()

    # Basis functions
    p_ux = Basis(p_dofhandler, 'ux')
    p_uy = Basis(p_dofhandler, 'uy')
    p_u = Basis(p_dofhandler, 'u')

    p_inflow = lambda x, y: np.ones(shape=x.shape)
    p_outflow = lambda x, y: np.zeros(shape=x.shape)
    c_inflow = lambda x, y: np.zeros(shape=x.shape)

    # =============================================================================
    # Solve the steady state flow equations
    # =============================================================================
    vb.comment('Solving flow equations')

    # Define problem
    flow_problem = [
        Form(1, test=p_ux, trial=p_ux),
        Form(1, test=p_uy, trial=p_uy),
        Form(0, test=p_u)
    ]

    # Assemble
    vb.tic('assembly')
    assembler = Assembler(flow_problem)
    assembler.add_dirichlet('left', 1)
    assembler.add_dirichlet('right', 0)
    assembler.assemble()
    vb.toc()

    # Solve linear system
    vb.tic('solve')
    A = assembler.get_matrix().tocsr()
    b = assembler.get_vector()
    x0 = assembler.assembled_bnd()

    # Interior nodes
    pa = np.zeros((p_u.n_dofs(), 1))
    int_dofs = assembler.get_dofs('interior')
    pa[int_dofs, 0] = spla.spsolve(A, b - x0)

    # Resolve Dirichlet conditions
    dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False)
    pa[dir_dofs] = dir_vals
    vb.toc()

    # Pressure function
    pfn = Nodal(data=pa, basis=p_u)

    px = pfn.differentiate((1, 0))
    py = pfn.differentiate((1, 1))

    #plot.contour(px)
    #plt.show()

    # =============================================================================
    # Transport Equations
    # =============================================================================
    # Specify initial condition
    c0 = Constant(1)
    dt = 1e-1
    T = 6
    N = int(np.ceil(T / dt))

    c = Basis(c_dofhandler, 'c')
    cx = Basis(c_dofhandler, 'cx')
    cy = Basis(c_dofhandler, 'cy')

    print('assembling transport equations')
    k_phi = Kernel(f=phi)
    k_advx = Kernel(f=[K, px], F=lambda K, px: -K * px)
    k_advy = Kernel(f=[K, py], F=lambda K, py: -K * py)
    tht = 1
    m = [Form(kernel=k_phi, test=c, trial=c)]
    s = [
        Form(kernel=k_advx, test=c, trial=cx),
        Form(kernel=k_advy, test=c, trial=cy),
        Form(kernel=Kernel(D), test=cx, trial=cx),
        Form(kernel=Kernel(D), test=cy, trial=cy)
    ]

    problems = [m, s]
    assembler = Assembler(problems)
    assembler.add_dirichlet('left', 0, i_problem=0)
    assembler.add_dirichlet('left', 0, i_problem=1)
    assembler.assemble()

    x0 = assembler.assembled_bnd()

    # Interior nodes
    int_dofs = assembler.get_dofs('interior')

    # Dirichlet conditions
    dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False)

    # System matrices
    M = assembler.get_matrix(i_problem=0)
    S = assembler.get_matrix(i_problem=1)

    # Initialize c0 and cp
    c0 = np.ones((c.n_dofs(), 1))
    cp = np.zeros((c.n_dofs(), 1))
    c_fn = Nodal(data=c0, basis=c)

    #
    # Compute solution
    #
    print('time stepping')
    for i in range(N):

        # Build system
        A = M + tht * dt * S
        b = M.dot(c0[int_dofs]) - (1 - tht) * dt * S.dot(c0[int_dofs])

        # Solve linear system
        cp[int_dofs, 0] = spla.spsolve(A, b)

        # Add Dirichlet conditions
        cp[dir_dofs] = dir_vals

        # Record current iterate
        c_fn.add_samples(data=cp)

        # Update c0
        c0 = cp.copy()

        #plot.contour(c_fn, n_sample=i)

    #
    # Quantity of interest
    #
    def F(c, px, py, entity=None):
        """
        Compute c(x,y,t)*(grad p * n)
        """
        n = entity.unit_normal()
        return c * (px * n[0] + py * n[1])

    px.set_subsample(i=np.arange(41))
    py.set_subsample(i=np.arange(41))

    #kernel = Kernel(f=[c_fn,px,py], F=F)
    kernel = Kernel(c_fn)

    #print(kernel.n_subsample())
    form = Form(kernel, flag='right', dmu='ds')
    assembler = Assembler(form, mesh=mesh)
    assembler.assemble()
    QQ = assembler.assembled_forms()[0].aggregate_data()['array']

    Q = np.array([assembler.get_scalar(i_sample=i) for i in np.arange(N + 1)])
    t = np.linspace(0, T, N + 1)
    plt.plot(t, Q)
    plt.show()
    print(Q)
Exemple #8
0
def sample_qoi(q, dofhandler, return_state=False):
    """
    Compute the Quantity of Interest 
    
        J(u) = -exp(q(1))*u'(1),
        
    where u solves 
    
        -d/dx ( exp(q)* du/dx) = 1
        u(0) = 0,  u(1) = 1
        
    for a sample of q's. 
    
    Inputs:
    
        q: Nodal, (n_dofs, n_samples) function representing the log porosity
        
        dofhandler: DofHandler
        
    """
    # Basis
    phi = Basis(dofhandler, 'v')
    phi_x = Basis(dofhandler, 'vx')
    n_dofs = phi.n_dofs()

    # Define problem
    expq_fn = Nodal(data=np.exp(q), basis=phi)

    problem = [[Form(expq_fn, test=phi_x, trial=phi_x),
                Form(1, test=phi)],
               [Form(expq_fn, test=phi_x, dmu='dv', flag='right')]]

    # Define assembler
    assembler = Assembler(problem, dofhandler.mesh)

    # Incorporate Dirichlet conditions
    assembler.add_dirichlet('left', 0)
    assembler.add_dirichlet('right', 1)

    n_samples = expq_fn.n_subsample()

    # Assemble system
    assembler.assemble()

    if return_state:
        U = np.empty((n_dofs, n_samples))

    J = np.zeros(n_samples)
    for i in range(n_samples):
        # Solve system
        u = assembler.solve(i_problem=0, i_matrix=i, i_vector=0)

        # Compute quantity of interest
        J[i] = -u.dot(assembler.get_vector(1, i))

        if return_state:
            U[:, i] = u

    if return_state:
        return J, U
    else:
        return J
Exemple #9
0
def experiment01_problem():
    """
    Illustrate the problem:  Plot sample paths of the input q, of the output, 
        and histogram of the QoI.
    """

    #
    # Computational Mesh
    #
    mesh = Mesh1D(resolution=(100, ))
    mesh.mark_region('left', lambda x: np.abs(x) < 1e-10)
    mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10)

    #
    # Element
    #
    Q1 = QuadFE(mesh.dim(), 'Q1')
    dQ1 = DofHandler(mesh, Q1)
    dQ1.distribute_dofs()

    #
    # Basis
    #
    phi = Basis(dQ1, 'v')
    phi_x = Basis(dQ1, 'vx')

    #
    # Covariance
    #
    cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05})
    cov.compute_eig_decomp()
    lmd, V = cov.get_eig_decomp()
    d = len(lmd)

    #
    # Sample and plot full dimensional parameter and solution
    #
    n_samples = 20000
    z = np.random.randn(d, n_samples)
    q = sample_q0(V, lmd, d, z)

    # Define finite element function
    qfn = Nodal(data=q, basis=phi)
    problem = [[Form(qfn, test=phi_x, trial=phi_x),
                Form(1, test=phi)],
               [Form(qfn, test=phi_x, dmu='dv', flag='right')]]

    # Define assembler
    assembler = Assembler(problem)

    # Incorporate Dirichlet conditions
    assembler.add_dirichlet('left', 0)
    assembler.add_dirichlet('right', 1)

    comment.tic('assembly')
    # Assemble system
    assembler.assemble()
    comment.toc()

    comment.tic('solver')
    ufn = Nodal(basis=phi, data=None)
    J = np.zeros(n_samples)
    for i in range(n_samples):
        # Solve system
        u = assembler.solve(i_problem=0, i_matrix=i, i_vector=0)

        # Compute quantity of interest
        J[i] = u.dot(assembler.get_vector(1, i))

        # Update sample paths
        ufn.add_samples(u)
    comment.toc()

    #
    # Plots
    #
    """
    # Formatting
    plt.rc('text', usetex=True)
    
    # Figure sizes
    fs2 = (3,2)
    fs1 = (4,3)
    
    plot = Plot(quickview=False)
    plot_kwargs = {'color':'k', 'linewidth':0.05}
    
    #
    # Plot qfn
    # 
    
    # Figure 
    fig = plt.figure(figsize=fs2)
    ax = fig.add_subplot(111)
    ax = plot.line(qfn, axis=ax, 
                   i_sample=np.arange(100), 
                   plot_kwargs=plot_kwargs)
    ax.set_xlabel(r'$x$')
    ax.set_ylabel(r'$q$')
    plt.tight_layout()
    fig.savefig('fig/ex02_gauss_qfn.eps')
    plt.close()
    
    #
    # Plot ufn
    # 
    fig = plt.figure(figsize=fs2)
    ax = fig.add_subplot(111)
    ax = plot.line(ufn, axis=ax, 
                   i_sample=np.arange(100), 
                   plot_kwargs=plot_kwargs)
    ax.set_xlabel(r'$x$')
    ax.set_ylabel(r'$u$')
    plt.tight_layout()
    fig.savefig('fig/ex02_gauss_ufn.eps')
    plt.close()
    """

    # Formatting
    plt.rc('text', usetex=True)

    # Figure sizes
    fs2 = (3, 2)
    fs1 = (4, 3)

    fig = plt.figure(figsize=fs2)
    ax = fig.add_subplot(111)
    plt.hist(J, bins=100, density=True)
    ax.set_xlabel(r'$J(u)$')
    plt.tight_layout()
    fig.savefig('fig/ex02_gauss_jhist.eps')
Exemple #10
0
def test02_sensitivity():
    """
    Check that the sensitivity calculation works. Compare 
    
        J(q+eps*dq) - J(q) ~= eps*dJ^T dq
    """
    #
    # Mesh
    #
    mesh = Mesh1D(resolution=(20, ))
    mesh.mark_region('left', lambda x: np.abs(x) < 1e-10)
    mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10)

    #
    # Element
    #
    Q = QuadFE(mesh.dim(), 'Q3')
    dQ = DofHandler(mesh, Q)
    dQ.distribute_dofs()
    nx = dQ.n_dofs()
    x = dQ.get_dof_vertices()

    #
    # Basis
    #
    phi = Basis(dQ, 'v')
    phi_x = Basis(dQ, 'vx')

    #
    # Parameters
    #

    # Reference q
    q_ref = np.zeros(nx)

    # Perturbation
    dq = np.ones(nx)

    # Perturbed q
    n_eps = 10  # Number of refinements
    epsilons = [10**(-l) for l in range(n_eps)]
    q_per = np.empty((nx, n_eps))
    for i in range(n_eps):
        q_per[:, i] = q_ref + epsilons[i] * dq

    # Define finite element function
    exp_qref = Nodal(data=np.exp(q_ref), basis=phi)
    exp_qper = Nodal(data=np.exp(q_per), basis=phi)

    #
    # PDEs
    #

    # 1. State Equation
    state_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(1, test=phi)]
    state_dbc = {'left': 0, 'right': 1}

    # 2. Perturbed Equation
    perturbed_eqn = [
        Form(exp_qper, test=phi_x, trial=phi_x),
        Form(1, test=phi)
    ]
    perturbed_dbc = {'left': 0, 'right': 1}

    # 3. Adjoint Equation
    adjoint_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(0, test=phi)]
    adjoint_dbc = {'left': 0, 'right': -1}

    # Combine
    eqns = [state_eqn, perturbed_eqn, adjoint_eqn]
    bcs = [state_dbc, perturbed_dbc, adjoint_dbc]

    #
    # Assembly
    #
    assembler = Assembler(eqns)

    # Boundary conditions
    for i, bc in zip(range(3), bcs):
        for loc, val in bc.items():
            assembler.add_dirichlet(loc, val, i_problem=i)

    # Assemble
    assembler.assemble()

    #
    # Solve
    #

    # Solve state
    ur = assembler.solve(i_problem=0)
    u_ref = Nodal(data=ur, basis=phi)
    ux_ref = Nodal(data=ur, basis=phi_x)

    # Solve perturbed state
    u_per = Nodal(basis=phi)
    ue_per = Nodal(basis=phi)
    for i in range(n_eps):
        # FEM solution
        up = assembler.solve(i_problem=1, i_matrix=i)
        u_per.add_samples(up)

        # Exact perturbed solution
        eps = epsilons[i]
        ue_per.add_samples(0.5 * np.exp(-eps) * (x - x**2) + x)

    ux_per = Nodal(data=u_per.data(), basis=phi_x)

    # Solve adjoint equation
    v = assembler.solve(i_problem=2)
    v_adj = Nodal(data=v, basis=phi)
    vx_adj = Nodal(data=v, basis=phi_x)

    #
    # Check against exact solution
    #
    ue = -0.5 * x**2 + 1.5 * x
    ve = -x

    assert np.allclose(ue, u_ref.data())
    assert np.allclose(ve, v_adj.data())
    assert np.allclose(ue_per.data(), u_per.data())

    #
    # Quantities of Interest
    #

    # Reference
    k_ref = Kernel(f=[exp_qref, ux_ref], F=lambda eq, ux: eq * ux)
    ref_qoi = [Form(k_ref, dmu='dv', flag='right')]

    # Perturbed
    k_per = Kernel(f=[exp_qper, ux_per], F=lambda eq, ux: eq * ux)
    per_qoi = [Form(k_per, dmu='dv', flag='right')]

    # Adjoint
    k_adj = Kernel(f=[exp_qref, ux_ref, vx_adj],
                   F=lambda eq, ux, vx: -eq * ux * vx)
    adj_qoi = [Form(k_adj, test=phi)]

    qois = [ref_qoi, per_qoi, adj_qoi]

    # Assemble
    assembler = Assembler(qois)
    assembler.assemble()

    # Evaluate
    J_ref = assembler.get_scalar(0)
    J_per = []
    for i in range(n_eps):
        J_per.append(assembler.get_scalar(1, i))

    # Finite difference approximation
    dJ = []
    for eps, J_p in zip(epsilons, J_per):
        dJ.append((J_p - J_ref) / eps)

    # Adjoint differential
    dJ_adj = assembler.get_vector(2).dot(dq)

    #
    # Check against exact qois
    #

    # Check reference sol
    Je_ref = 0.5
    assert np.allclose(Je_ref, J_ref)

    # Check perturbed cost
    Je_per = -0.5 + np.exp(np.array(epsilons))
    assert np.allclose(Je_per, J_per)

    # Check derivative by the adjoint equation
    dJdq = 1
    assert np.allclose(dJ_adj, dJdq)
Exemple #11
0
def test01_finite_elements():
    """
    Test accuracy of the finite element approximation
    """
    #
    # Construct reference solution
    #
    plot = Plot(quickview=False)

    # Mesh
    mesh = Mesh1D(resolution=(2**11, ))
    mesh.mark_region('left', lambda x: np.abs(x) < 1e-10)
    mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10)

    # Element
    Q1 = QuadFE(mesh.dim(), 'Q1')
    dQ1 = DofHandler(mesh, Q1)
    dQ1.distribute_dofs()

    # Basis
    phi = Basis(dQ1, 'v')
    phi_x = Basis(dQ1, 'vx')

    #
    # Covariance
    #
    cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05})
    cov.compute_eig_decomp()
    lmd, V = cov.get_eig_decomp()
    d = len(lmd)

    #
    # Sample and plot full dimensional parameter and solution
    #
    n_samples = 1
    z = np.random.randn(d, n_samples)
    q_ref = sample_q0(V, lmd, d, z)

    print(q_ref.shape)

    # Define finite element function
    q_ref_fn = Nodal(data=q_ref, basis=phi)
    problem = [[Form(q_ref_fn, test=phi_x, trial=phi_x),
                Form(1, test=phi)],
               [Form(q_ref_fn, test=phi_x, dmu='dv', flag='right')]]

    # Define assembler
    assembler = Assembler(problem)

    # Incorporate Dirichlet conditions
    assembler.add_dirichlet('left', 0)
    assembler.add_dirichlet('right', 1)

    # Assemble system
    assembler.assemble()

    # Solve system
    u_ref = assembler.solve()

    # Compute quantity of interest
    J_ref = u_ref.dot(assembler.get_vector(1))

    # Plot
    fig = plt.figure(figsize=(6, 4))
    ax = fig.add_subplot(111)
    u_ref_fn = Nodal(basis=phi, data=u_ref)

    ax = plot.line(u_ref_fn, axis=ax)

    n_levels = 10
    J = np.zeros(n_levels)
    for l in range(10):
        comment.comment('level: %d' % (l))

        #
        # Mesh
        #
        mesh = Mesh1D(resolution=(2**l, ))
        mesh.mark_region('left', lambda x: np.abs(x) < 1e-10)
        mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10)

        #
        # Element
        #
        Q1 = QuadFE(mesh.dim(), 'Q1')
        dQ1 = DofHandler(mesh, Q1)
        dQ1.distribute_dofs()

        #
        # Basis
        #
        phi = Basis(dQ1, 'v')
        phi_x = Basis(dQ1, 'vx')

        # Define problem
        problem = [[
            Form(q_ref_fn, test=phi_x, trial=phi_x),
            Form(1, test=phi)
        ], [Form(q_ref_fn, test=phi_x, dmu='dv', flag='right')]]

        assembler = Assembler(problem)

        # Incorporate Dirichlet conditions
        assembler.add_dirichlet('left', 0)
        assembler.add_dirichlet('right', 1)

        assembler.assemble()
        A = assembler.get_matrix()
        print('A shape', A.shape)

        u = assembler.solve()
        J[l] = u.dot(assembler.get_vector(1))

        print(u.shape)
        print(phi.n_dofs())
        ufn = Nodal(basis=phi, data=u)
        ax = plot.line(ufn, axis=ax)

    plt.show()
    #
    # Plots
    #
    # Formatting
    plt.rc('text', usetex=True)

    # Figure sizes
    fs2 = (3, 2)
    fs1 = (4, 3)

    print(J_ref)
    print(J)

    #
    # Plot truncation error for mean and variance of J
    #

    fig = plt.figure(figsize=fs2)
    ax = fig.add_subplot(111)

    err = np.array([np.abs(J[i] - J_ref) for i in range(n_levels)])
    h = np.array([2**(-l) for l in range(n_levels)])
    plt.loglog(h, err, '.-')

    ax.set_xlabel(r'$h$')
    ax.set_ylabel(r'$|J-J^h|$')
    plt.tight_layout()
    fig.savefig('fig/ex02_gauss_fem_error.eps')
Exemple #12
0
def dJdq_sen(q, u, dq):
    """
    Compute the directional derivative dJ(q,dq) by means of the sensitivity 
    equation.

        -(exp(q)*s')' = (exp(q)*dq*u')'
        s(0) = s(1) = 0
        
    and computing 
    
        dJ(q,dq) = -exp(q(1))*dq(1)*u'(1) - exp(q(1))*s'(1)
        
    """
    #
    # Finite Element Specification
    #

    # Reference state
    u_dh = u.basis().dofhandler()
    mesh = u_dh.mesh
    phi = Basis(u_dh, 'u')
    phi_x = Basis(u_dh, 'ux')
    ux_fn = Nodal(data=u.data(), basis=phi_x)

    # Reference diffusivitity
    q_dh = q.basis().dofhandler()
    psi = q.basis()
    exp_q = Nodal(data=np.exp(q.data()), basis=phi)

    # Define sensitivity equation
    ker_sen = Kernel(f=[exp_q, dq, ux_fn], F=lambda eq, dq, ux: -eq * dq * ux)
    sensitivity_eqn = [
        Form(exp_q, test=phi_x, trial=phi_x),
        Form(ker_sen, test=phi_x)
    ]

    # Assembler
    assembler = Assembler(sensitivity_eqn, u_dh.mesh, n_gauss=(6, 36))

    # Apply Dirichlet Boundary conditions
    assembler.add_dirichlet('left', 0)
    assembler.add_dirichlet('right', 0)

    # Assemble system
    assembler.assemble()

    # Solve for sensitivity
    s_fn = Nodal(basis=phi)
    for i in range(dq.n_samples()):
        # Solve for ith sensitivity
        s = assembler.solve(i_vector=i)
        s_fn.add_samples(s)

    # Derivative of sensitivity
    sx_fn = Nodal(data=s_fn.data(), basis=phi_x)

    # Sensitivity
    k_sens = Kernel(f=[exp_q, dq, ux_fn, sx_fn],
                    F=lambda eq, dq, ux, sx: -eq * dq * ux - eq * sx)
    sens_qoi = Form(k_sens, dmu='dv', flag='right')

    # Assemble
    assembler = Assembler(sens_qoi, mesh=mesh)
    assembler.assemble()

    # Differential
    dJ = np.array([assembler.get_scalar(i_sample=i) \
                   for i in range(dq.n_samples())])

    return dJ
Exemple #13
0
def dJdq_adj(q, u, dq=None):
    """
    Compute the directional derivative dJ(q,dq) by solving the adjoint equation 
    
        -(exp(q)v')' = 0, 
        v(0)=0, v(1)=1 
        
    and computing
    
        ( v, (exp(q)*dq(1)*u')' ) + exp(q(1))*dq(1)*u'(1) = -(exp(q)*dq u', v')
        
        
    Inputs: 
    
        q: Nodal, single reference log diffusitivity 
        
        u: Nodal, single reference system response
        
        dq: Nodal/None, sampled perturbation vector (or None) 
        
    
    Output:
    
        dJdq: Derivative of J wrt q
        
            If dq = Nodal, return directional derivative in direction dq
            
            If dq = None, return gradient
    """
    #
    # Finite Element Specification
    #

    # Reference solution
    u_dh = u.basis().dofhandler()
    phi = Basis(u_dh, 'u')
    phi_x = Basis(u_dh, 'ux')
    ux = Nodal(data=u.data(), basis=phi_x)

    # Reference diffusivity
    q_dh = q.basis().dofhandler()
    psi = Basis(q_dh, 'q')
    exp_q = Nodal(data=np.exp(q.data()), basis=psi)

    # Define adjoint equations
    adjoint_eqn = [Form(exp_q, test=phi_x, trial=phi_x), Form(0, test=phi)]

    # Assembler
    assembler = Assembler(adjoint_eqn)

    # Apply Dirichlet BC
    assembler.add_dirichlet('left', 0)
    assembler.add_dirichlet('right', 1)

    # Assemble
    assembler.assemble()

    # Solve for adjoint
    v = assembler.solve()

    # Get derivative
    vx = Nodal(data=v, basis=phi_x)

    # Assemble

    if dq is None:
        #
        # Compute the gradient
        #

        # Kernel
        k_adj = Kernel(f=[exp_q, ux, vx], F=lambda eq, ux, vx: -eq * ux * vx)

        # Linear form
        adj_qoi = [Form(k_adj, test=psi)]

        # Assemble
        assembler = Assembler(adj_qoi)
        assembler.assemble()

        # Get gradient vector
        dJdq = assembler.get_vector()
    else:
        #
        # Compute the directional derivative
        #

        # Kernel
        k_adj = Kernel(f=[exp_q, dq, ux, vx],
                       F=lambda eq, dq, ux, vx: -eq * dq * ux * vx)

        # Constant form
        adj_qoi = [Form(k_adj)]

        # Assemble
        assembler = Assembler(adj_qoi, mesh=u_dh.mesh)
        assembler.assemble()

        # Get directional derivatives for each direction
        dJdq = np.array(
            [assembler.get_scalar(i_sample=i) for i in range(dq.n_samples())])
    # Return
    return dJdq
Exemple #14
0
def test06_linearization():
    """
    Compute samples on fine grid via the linearization
    """
    plot = Plot()
    #
    # Computational mesh
    #
    mesh = Mesh1D(resolution=(100, ))
    mesh.mark_region('left', lambda x: np.abs(x) < 1e-10)
    mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10)

    #
    # Element
    #
    Q1 = QuadFE(mesh.dim(), 'Q1')
    dQ1 = DofHandler(mesh, Q1)
    dQ1.distribute_dofs()
    nx = dQ1.n_dofs()
    x = dQ1.get_dof_vertices()

    Q3 = QuadFE(mesh.dim(), 'Q3')
    dQ3 = DofHandler(mesh, Q3)
    dQ3.distribute_dofs()

    #
    # Basis
    #
    phi = Basis(dQ1, 'u')
    phi_x = Basis(dQ1, 'ux')
    psi = Basis(dQ3, 'u')
    psi_x = Basis(dQ3, 'ux')

    #
    # Covariance
    #
    cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05})
    cov.compute_eig_decomp()
    lmd, V = cov.get_eig_decomp()
    d = len(lmd)

    # Fix coarse truncation level
    d0 = 10

    #
    # Build Sparse Grid
    #
    grid = TasmanianSG.TasmanianSparseGrid()
    dimensions = d0
    outputs = 1
    depth = 2
    type = 'level'
    rule = 'gauss-hermite'
    grid.makeGlobalGrid(dimensions, outputs, depth, type, rule)

    # Sample Points
    zzSG = grid.getPoints()
    zSG = np.sqrt(2) * zzSG  # transform to N(0,1)

    # Quadrature Weights
    wSG = grid.getQuadratureWeights()
    wSG /= np.sqrt(np.pi)**d0  # normalize weights

    # Number of grid points
    n0 = grid.getNumPoints()

    #
    # Sample low dimensional input parameter
    #
    q0 = sample_q0(V, lmd, d0, zSG.T)
    J0 = sample_qoi(q0, dQ1)

    #
    # Sample conditional expectation
    #

    # Pick a single coarse sample to check
    i0 = np.random.randint(0, high=n0)

    # Sample fine, conditional on coarse
    n_samples = 1
    z1 = np.random.randn(d - d0, n_samples)
    q = sample_q_given_q0(q0[:, i0], V, lmd, d0, z1)

    # Perturbation
    log_qref = np.log(q0[:, i0])
    dlog_q = np.log(q.ravel()) - log_qref
    dlog_qfn = Nodal(data=dlog_q, basis=phi)

    # Perturbed q
    n_eps = 12  # Number of refinements
    epsilons = [10**(-l) for l in range(n_eps)]
    log_qper = np.empty((nx, n_eps))
    for i in range(n_eps):
        log_qper[:, i] = log_qref + epsilons[i] * dlog_q
    """
    plt.plot(x, log_qref, label='ref')
    for i in range(n_eps):
        plt.plot(x, log_qper[:,i],label='%d'%(i))
    """

    assert np.allclose(log_qper[:, 0], np.log(q.ravel()))

    plt.legend()
    plt.show()

    # Define finite element function
    exp_qref = Nodal(data=q0[:, i0], basis=phi)
    exp_qper = Nodal(data=np.exp(log_qper), basis=phi)

    #
    # PDEs
    #

    # 1. State Equation
    state_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(1, test=phi)]
    state_dbc = {'left': 0, 'right': 1}

    # 2. Perturbed Equation
    perturbed_eqn = [
        Form(exp_qper, test=phi_x, trial=phi_x),
        Form(1, test=phi)
    ]
    perturbed_dbc = {'left': 0, 'right': 1}

    # 3. Adjoint Equation
    adjoint_eqn = [Form(exp_qref, test=psi_x, trial=psi_x), Form(0, test=psi)]
    adjoint_dbc = {'left': 0, 'right': -1}

    # Combine
    eqns = [state_eqn, perturbed_eqn, adjoint_eqn]
    bcs = [state_dbc, perturbed_dbc, adjoint_dbc]

    #
    # Assembly
    #
    assembler = Assembler(eqns, n_gauss=(6, 36))

    # Boundary conditions
    for i, bc in zip(range(3), bcs):
        for loc, val in bc.items():
            assembler.add_dirichlet(loc, val, i_problem=i)

    # Assemble
    assembler.assemble()

    #
    # Solve
    #

    # Solve state
    ur = assembler.solve(i_problem=0)
    u_ref = Nodal(data=ur, basis=phi)
    ux_ref = Nodal(data=ur, basis=phi_x)

    # Solve perturbed state
    u_per = Nodal(basis=phi)
    for i in range(n_eps):
        # FEM solution
        up = assembler.solve(i_problem=1, i_matrix=i)
        u_per.add_samples(up)

        plt.plot(x, up - ur)
    plt.show()
    ux_per = Nodal(data=u_per.data(), basis=phi_x)

    # Solve adjoint equation
    v = assembler.solve(i_problem=2)
    v_adj = Nodal(data=v, basis=psi)
    vx_adj = Nodal(data=v, basis=psi_x)

    #
    # Sensitivity
    #

    # Sensitivity Equation
    ker_sen = Kernel(f=[exp_qref, dlog_qfn, ux_ref],
                     F=lambda eq, dq, ux: -eq * dq * ux)
    sensitivity_eqn = [
        Form(exp_qref, test=phi_x, trial=phi_x),
        Form(ker_sen, test=phi_x)
    ]

    sensitivity_dbc = {'left': 0, 'right': 0}
    assembler = Assembler(sensitivity_eqn, n_gauss=(6, 36))
    for loc in sensitivity_dbc:
        assembler.add_dirichlet(loc, sensitivity_dbc[loc])
    assembler.assemble()
    s = assembler.solve()
    sx = Nodal(data=s, basis=phi_x)

    plt.plot(x, s)
    plt.show()

    #
    # Quantities of Interest
    #

    # Reference
    k_ref = Kernel(f=[exp_qref, ux_ref], F=lambda eq, ux: eq * ux)
    ref_qoi = [Form(k_ref, dmu='dv', flag='right')]

    # Perturbed
    k_per = Kernel(f=[exp_qper, ux_per], F=lambda eq, ux: eq * ux)
    per_qoi = [Form(k_per, dmu='dv', flag='right')]

    # Adjoint
    k_adj = Kernel(f=[exp_qref, dlog_qfn, ux_ref, vx_adj],
                   F=lambda eq, dq, ux, vx: -eq * dq * ux * vx)
    adj_qoi = [Form(k_adj)]

    # Sensitivity
    k_sens = Kernel(f=[exp_qref, dlog_qfn, ux_ref, sx],
                    F=lambda eq, dq, ux, sx: eq * dq * ux + eq * sx)
    sens_qoi = Form(k_sens, dmu='dv', flag='right')

    qois = [ref_qoi, per_qoi, adj_qoi, sens_qoi]

    # Assemble
    assembler = Assembler(qois, mesh=mesh)
    assembler.assemble()

    # Evaluate
    J_ref = assembler.get_scalar(0)
    J_per = []
    for i in range(n_eps):
        J_per.append(assembler.get_scalar(1, i))

    # Finite difference approximation
    dJ = []
    for eps, J_p in zip(epsilons, J_per):
        dJ.append((J_p - J_ref) / eps)

    # Adjoint differential
    dJ_adj = assembler.get_scalar(2)

    # Sensitivity differential
    dJ_sen = assembler.get_scalar(3)

    print(dJ_adj)
    print(dJ_sen)
    print(dJ)
    """
Exemple #15
0
    def test03_solve_2d(self):
        """
        Test problem with Neumann conditions
        """
        #
        # Define Mesh
        #
        mesh = QuadMesh(resolution=(2, 1))
        mesh.cells.get_child(1).mark(1)
        mesh.cells.refine(refinement_flag=1)

        # Mark left and right boundaries
        bm_left = lambda x, dummy: np.abs(x) < 1e-9
        bm_right = lambda x, dummy: np.abs(1 - x) < 1e-9
        mesh.mark_region('left', bm_left, entity_type='half_edge')
        mesh.mark_region('right', bm_right, entity_type='half_edge')

        for etype in ['Q1', 'Q2', 'Q3']:
            #
            # Define element and basis type
            #
            element = QuadFE(2, etype)
            dofhandler = DofHandler(mesh, element)
            dofhandler.distribute_dofs()

            u = Basis(dofhandler, 'u')
            ux = Basis(dofhandler, 'ux')
            uy = Basis(dofhandler, 'uy')

            #
            # Exact solution
            #
            ue = Nodal(f=lambda x: x[:, 0], basis=u)

            #
            # Set up forms
            #
            one = Constant(1)
            ax = Form(kernel=Kernel(one), trial=ux, test=ux)
            ay = Form(kernel=Kernel(one), trial=uy, test=uy)
            L = Form(kernel=Kernel(Constant(0)), test=u)
            Ln = Form(kernel=Kernel(one), test=u, dmu='ds', flag='right')

            problem = [ax, ay, L, Ln]

            assembler = Assembler(problem, mesh)
            assembler.add_dirichlet('left', dir_fn=0)
            assembler.add_hanging_nodes()
            assembler.assemble()

            #
            # Automatic solve
            #
            ya = assembler.solve()
            self.assertTrue(np.allclose(ue.data()[:, 0], ya))

            #
            # Explicit solve
            #

            # System Matrices
            A = assembler.get_matrix().toarray()
            b = assembler.get_vector()
            x0 = assembler.assembled_bnd()

            # Solve linear system
            xa = np.zeros(u.n_dofs())
            int_dofs = assembler.get_dofs('interior')
            xa[int_dofs] = np.linalg.solve(A, b - x0)

            # Resolve Dirichlet conditions
            dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False)
            xa[dir_dofs] = dir_vals[:, 0]

            # Resolve hanging nodes
            C = assembler.hanging_node_matrix()
            xa += C.dot(xa)

            self.assertTrue(np.allclose(ue.data()[:, 0], xa))
Exemple #16
0
    def test02_solve_2d(self):
        """
        Solve 2D problem with hanging nodes
        """
        # Mesh
        mesh = QuadMesh(resolution=(2, 2))
        mesh.cells.get_leaves()[0].mark(0)
        mesh.cells.refine(refinement_flag=0)

        mesh.mark_region('left',
                         lambda x, y: abs(x) < 1e-9,
                         entity_type='half_edge')
        mesh.mark_region('right',
                         lambda x, y: abs(x - 1) < 1e-9,
                         entity_type='half_edge')

        # Element
        Q1 = QuadFE(2, 'Q1')
        dofhandler = DofHandler(mesh, Q1)
        dofhandler.distribute_dofs()
        dofhandler.set_hanging_nodes()

        # Basis functions
        phi = Basis(dofhandler, 'u')
        phi_x = Basis(dofhandler, 'ux')
        phi_y = Basis(dofhandler, 'uy')

        #
        # Define problem
        #
        problem = [
            Form(1, trial=phi_x, test=phi_x),
            Form(1, trial=phi_y, test=phi_y),
            Form(0, test=phi)
        ]

        ue = Nodal(f=lambda x: x[:, 0], basis=phi)
        xe = ue.data().ravel()

        #
        # Assemble without Dirichlet and without Hanging Nodes
        #
        assembler = Assembler(problem, mesh)
        assembler.add_dirichlet('left', dir_fn=0)
        assembler.add_dirichlet('right', dir_fn=1)
        assembler.add_hanging_nodes()
        assembler.assemble()

        # Get dofs for different regions
        int_dofs = assembler.get_dofs('interior')

        # Get matrix and vector
        A = assembler.get_matrix().toarray()
        b = assembler.get_vector()
        x0 = assembler.assembled_bnd()

        # Solve linear system
        xa = np.zeros(phi.n_dofs())
        xa[int_dofs] = np.linalg.solve(A, b - x0)

        # Resolve Dirichlet conditions
        dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False)
        xa[dir_dofs] = dir_vals[:, 0]

        # Resolve hanging nodes
        C = assembler.hanging_node_matrix()
        xa += C.dot(xa)

        self.assertTrue(np.allclose(xa, xe))