Beispiel #1
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)
Beispiel #2
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')
Beispiel #3
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
Beispiel #4
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)
Beispiel #5
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)
    """