Exemplo n.º 1
0
def plot_heuristics(f, tht, basis, region, condition):
    """
    Parameters
    ----------
    f : lambda, 
        Function of θ to be integrated.
        
    n : int, 
        Sample size for Monte Carlo sample
    
    """
    tht.update_support()
    #
    # Plot samples of the random field
    #
    n = 10000
    tht_sample = tht.sample(n)
    tht_fn = Nodal(data=tht_sample, basis=basis)

    #
    # Compute the quantity of interest
    #

    # Define the kernel
    kf = Kernel(tht_fn, F=f)

    # Assemble over the mesh
    problems = [[Form(kernel=kf, flag=region)], [Form(flag=region)]]
    assembler = Assembler(problems, basis.mesh())
    assembler.assemble()

    # Extract sample
    dx = assembler.get_scalar(i_problem=1)
    q_sample = assembler.get_scalar(i_sample=None) / dx

    #
    # Compute correlation coefficients of q with spatial data
    #

    plot = Plot(quickview=False)
    fig, ax = plt.subplots()
    plt_args = {'linewidth': 0.5, 'color': 'k'}
    ax = plot.line(tht_fn,
                   axis=ax,
                   i_sample=list(range(100)),
                   plot_kwargs=plt_args)
    fig.savefig('ex01_sample_paths.eps')

    fig, ax = plt.subplots()
    ftht = Nodal(data=f(tht_sample), basis=basis)
    ax = plot.line(ftht,
                   axis=ax,
                   i_sample=list(range(100)),
                   plot_kwargs=plt_args)
    fig.savefig('ex01_integrand.eps')

    fig, ax = plt.subplots(1, 1)
    plt.hist(q_sample, bins=50, density=True)
    ax.set_title(r'Histogram $Q(\theta)$')
    fig.savefig('ex01_histogram.eps')
    plt.close('all')

    dh = basis.dofhandler()
    n_dofs = dh.n_dofs()

    # Extract the region on which we condition
    cnd_dofs = dh.get_region_dofs(entity_flag=condition)
    I = np.eye(n_dofs)
    I = I[cnd_dofs, :]

    # Measured tht
    tht_msr = tht_sample[cnd_dofs, 0][:, None]

    n_cnd = 30
    cnd_tht = tht.condition(I, tht_msr, n_samples=n_cnd)

    #cnd_tht_data = np.array([tht_sample[:,0] for dummy in range(n_cnd)])
    #cnd_tht_data[cnd_dofs,:] = cnd_tht

    cnd_tht_fn = Nodal(data=f(cnd_tht), basis=basis)
    fig, ax = plt.subplots()
    ax = plot.line(cnd_tht_fn,
                   axis=ax,
                   i_sample=np.arange(n_cnd),
                   plot_kwargs=plt_args)
    fig.tight_layout()
    plt.show()
Exemplo n.º 2
0
def reference_qoi(f, tht, basis, region, n=1000000, verbose=True):
    """
    Parameters
    ----------
    f : lambda function,
        Function of θ to be integrated.
        
    tht : GaussianField, 
        Random field θ defined on mesh in terms of its mean and covariance
        
    basis : Basis, 
        Basis function defining the nodal interpolant. It incorporates the
        mesh, the dofhandler, and the derivative.
        
    region : meshflag, 
        Flag indicating the region of integration
    
    n : int, default=1000000 
        Sample size
    
    Returns
    -------
    Q_ref : double, 
        Reference quantity of interest
        
    err : double, 
        Expected RMSE given by var(Q)/n. 
    """

    #
    # Assemble integral
    #
    batch_size = 100000
    n_batches = n // batch_size + (0 if (n % batch_size) == 0 else 1)

    if verbose:
        print('Computing Reference Quantity of Interest')
        print('========================================')
        print('Sample size: ', n)
        print('Batch size: ', batch_size)
        print('Number of batches: ', n_batches)

    Q_smpl = np.empty(n)
    for k in range(n_batches):

        # Determine sample sizes for each batch
        if k < n_batches - 1:
            n_sample = batch_size
        else:
            # Last sample may be smaller than batch_size
            n_sample = n - k * batch_size

        if verbose:
            print(' - Batch Number ', k)
            print(' - Sample Size: ', n_sample)
            print(' - Sampling random field')

        # Sample from field
        tht_smpl = tht.sample(n_sample)

        # Define kernel
        tht_n = Nodal(data=tht_smpl, basis=basis)
        kf = Kernel(tht_n, F=f)

        # Define forms
        if k == 0:
            problems = [[Form(kernel=kf, flag=region)], [Form(flag=region)]]
        else:
            problems = [Form(kernel=kf, flag=region)]

        if verbose:
            print(' - Assembling.')

        # Compute the integral
        assembler = Assembler(problems, basis.mesh())
        assembler.assemble()

        #
        # Compute statistic
        #

        # Get samples
        if k == 0:
            dx = assembler.get_scalar(i_problem=1)

        if verbose:
            print(' - Updating samples \n')

        batch_sample = assembler.get_scalar(i_problem=0, i_sample=None)
        Q_smpl[k * batch_size:k * batch_size + n_sample] = batch_sample / dx

    # Compute mean and MSE
    Q_ref = np.mean(Q_smpl)
    err = np.var(Q_smpl) / n

    # Return reference
    return Q_ref, err
Exemplo n.º 3
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)
Exemplo n.º 4
0
eta_trunc_sg = V[:, :k].dot(np.diag(np.sqrt(D[:k])).dot(z.T))

# Generate a Monte Carlo sample on top of sparse grid
n_mc = 20
zz = np.random.randn(n_dofs - k, n_mc)
eta_tail_mc = V[:, k:].dot(np.diag(np.sqrt(D[k:]))).dot(zz)

# -----------------------------------------------------------------------------
# Sample and Integrate
# -----------------------------------------------------------------------------
# Samples of random field
theta_trunc = Nodal(data=eta_trunc_sg[:, [50]] + eta_tail_mc, basis=phi_1)

# Assembler
k = Kernel(theta_trunc, F=lambda tht: tht**2)
problem = Form(flag='integration', kernel=k)
assembler = Assembler(problem, mesh)
assembler.assemble()
v = assembler.get_scalar(i_sample=3)

#plot = Plot(quickview=False)
#fig, ax = plt.subplots()

#plot.mesh(mesh,regions=[('region','cell')])
"""
ax = plot.line(theta_trunc, axis=ax, i_sample=np.arange(n_mc), 
               plot_kwargs={'linewidth':0.2, 
                            'color':'k'})
"""
#plt.show()
Exemplo n.º 5
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)
Exemplo n.º 6
0
# Solve the steady state flow equations
# =============================================================================

# Define problem

flow_problem = [
    Form(fNodal),
    Form(1, test=p_uy, trial=p_uy),
    Form(1, test=p_u)
]

# Assembler

tic = time.time()
assembler = Assembler(flow_problem, mesh)
toc = time.time() - tic

print('initializing assembler', toc)

tic = time.time()
assembler.assemble()
toc = time.time() - tic
print('assembly time', toc)

tic = time.time()
A = assembler.get_matrix()
print('forming bilinear array', time.time() - tic)

b = assembler.get_vector()
c = assembler.get_scalar()
Exemplo n.º 7
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
Exemplo n.º 8
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
Exemplo n.º 9
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)
    """
Exemplo n.º 10
0
    def test_integrals_2d(self):
        """
        Test Assembly of some 2D systems
        """
        mesh = QuadMesh(box=[1, 2, 1, 2], resolution=(2, 2))
        mesh.cells.get_leaves()[0].mark(0)
        mesh.cells.refine(refinement_flag=0)

        # Kernel
        kernel = Kernel(Explicit(f=lambda x: x[:, 0] * x[:, 1], dim=2))

        problem = Form(kernel)
        assembler = Assembler(problem, mesh=mesh)
        assembler.assemble()
        self.assertAlmostEqual(assembler.get_scalar(), 9 / 4)

        #
        # Linear forms (x,x) and (x,x') over [1,2]^2 = 7/3, 3/2
        #

        # Elements
        Q1 = QuadFE(mesh.dim(), 'Q1')
        Q2 = QuadFE(mesh.dim(), 'Q2')
        Q3 = QuadFE(mesh.dim(), 'Q3')

        # Dofhandlers
        dQ1 = DofHandler(mesh, Q1)
        dQ2 = DofHandler(mesh, Q2)
        dQ3 = DofHandler(mesh, Q3)

        # Distribute dofs
        [d.distribute_dofs() for d in [dQ1, dQ2, dQ3]]

        for dQ in [dQ1, dQ2, dQ3]:
            # Basis
            phi = Basis(dQ, 'u')
            phi_x = Basis(dQ, 'ux')

            # Kernel function
            xfn = Nodal(f=lambda x: x[:, 0], basis=phi)
            yfn = Nodal(f=lambda x: x[:, 1], basis=phi)

            # Kernel
            kernel = Kernel(xfn)

            # Form
            problem = [[Form(kernel, test=phi)], [Form(kernel, test=phi_x)]]

            # Assembly
            assembler = Assembler(problem, mesh)
            assembler.assemble()

            # Check b^Tx = (x,y)
            b0 = assembler.get_vector(0)
            self.assertAlmostEqual(np.sum(b0 * yfn.data()[:, 0]), 9 / 4)

            b1 = assembler.get_vector(1)
            self.assertAlmostEqual(np.sum(b1 * xfn.data()[:, 0]), 3 / 2)
            self.assertAlmostEqual(np.sum(b1 * yfn.data()[:, 0]), 0)

        #
        # Bilinear forms
        #
        # Compute (1,x,y) = 9/4, or (xy, 1, 1) = 9/4

        for dQ in [dQ1, dQ2, dQ3]:
            # Basis
            phi = Basis(dQ, 'u')
            phi_x = Basis(dQ, 'ux')
            phi_y = Basis(dQ, 'uy')

            # Kernel function
            xyfn = Explicit(f=lambda x: x[:, 0] * x[:, 1], dim=2)
            xfn = Nodal(f=lambda x: x[:, 0], basis=phi)
            yfn = Nodal(f=lambda x: x[:, 1], basis=phi)

            # Form
            problems = [[Form(1, test=phi, trial=phi)],
                        [Form(Kernel(xfn), test=phi, trial=phi_x)],
                        [Form(Kernel(xyfn), test=phi_y, trial=phi_x)]]

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

            x = xfn.data()[:, 0]
            y = yfn.data()[:, 0]
            for i_problem in range(3):
                A = assembler.get_matrix(i_problem)
                self.assertAlmostEqual(y.T.dot(A.dot(x)), 9 / 4)
Exemplo n.º 11
0
    def test_integrals_1d(self):
        """
        Test system assembly
        """
        #
        # Constant form
        #

        # Mesh
        mesh = Mesh1D(box=[1, 2], resolution=(1, ))

        # Kernel
        kernel = Kernel(Explicit(f=lambda x: x[:, 0], dim=1))

        problem = Form(kernel)
        assembler = Assembler(problem, mesh=mesh)
        assembler.assemble()
        self.assertAlmostEqual(assembler.get_scalar(), 3 / 2)

        #
        # Linear forms (x,x) and (x,x') over [1,2] = 7/3, 3/2
        #

        # Elements
        Q1 = QuadFE(mesh.dim(), 'Q1')
        Q2 = QuadFE(mesh.dim(), 'Q2')
        Q3 = QuadFE(mesh.dim(), 'Q3')

        # Dofhandlers
        dQ1 = DofHandler(mesh, Q1)
        dQ2 = DofHandler(mesh, Q2)
        dQ3 = DofHandler(mesh, Q3)

        # Distribute dofs
        [d.distribute_dofs() for d in [dQ1, dQ2, dQ3]]

        for dQ in [dQ1, dQ2, dQ3]:
            # Basis
            phi = Basis(dQ, 'u')
            phi_x = Basis(dQ, 'ux')

            # Kernel function
            xfn = Nodal(f=lambda x: x[:, 0], basis=phi)

            # Kernel
            kernel = Kernel(xfn)

            # Form
            problem = [[Form(kernel, test=phi)], [Form(kernel, test=phi_x)]]

            # Assembly
            assembler = Assembler(problem, mesh)
            assembler.assemble()

            # Check b^Tx = (x,x)
            b0 = assembler.get_vector(0)
            self.assertAlmostEqual(np.sum(b0 * xfn.data()[:, 0]), 7 / 3)

            b1 = assembler.get_vector(1)
            self.assertAlmostEqual(np.sum(b1 * xfn.data()[:, 0]), 3 / 2)

        #
        # Bilinear forms
        #
        # Compute (1,x,x) = 7/3, or (x^2, 1, 1) = 7/3

        for dQ in [dQ1, dQ2, dQ3]:
            # Basis
            phi = Basis(dQ, 'u')
            phi_x = Basis(dQ, 'ux')

            # Kernel function
            x2fn = Explicit(f=lambda x: x[:, 0]**2, dim=1)
            xfn = Nodal(f=lambda x: x[:, 0], basis=phi)

            # Form
            problems = [[Form(1, test=phi, trial=phi)],
                        [Form(Kernel(xfn), test=phi, trial=phi_x)],
                        [Form(Kernel(x2fn), test=phi_x, trial=phi_x)]]

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

            x = xfn.data()[:, 0]
            for i_problem in range(3):
                A = assembler.get_matrix(i_problem)
                self.assertAlmostEqual(x.T.dot(A.dot(x)), 7 / 3)

        # ======================================================================
        # Test 1: Assemble simple bilinear form (u,v) on Mesh1D
        # ======================================================================
        # Mesh
        mesh = Mesh1D(resolution=(1, ))
        Q1 = QuadFE(mesh.dim(), 'Q1')
        Q2 = QuadFE(mesh.dim(), 'Q2')
        Q3 = QuadFE(mesh.dim(), 'Q3')

        # Test and trial functions
        dhQ1 = DofHandler(mesh, QuadFE(1, 'Q1'))
        dhQ1.distribute_dofs()

        u = Basis(dhQ1, 'u')
        v = Basis(dhQ1, 'v')

        # Form
        form = Form(trial=u, test=v)

        # Define system
        system = Assembler(form, mesh)

        # Get local information
        cell = mesh.cells.get_child(0)
        si = system.shape_info(cell)

        # Compute local Gauss nodes
        xg, wg, phi, dofs = system.shape_eval(cell)
        self.assertTrue(cell in xg)
        self.assertTrue(cell in wg)

        # Compute local shape functions
        self.assertTrue(cell in phi)
        self.assertTrue(u in phi[cell])
        self.assertTrue(v in phi[cell])
        self.assertTrue(u in dofs[cell])

        # Assemble system
        system.assemble()

        # Extract system bilinear form
        A = system.get_matrix()

        # Use bilinear form to integrate x^2 over [0,1]
        f = Nodal(lambda x: x, basis=u)
        fv = f.data()[:, 0]
        self.assertAlmostEqual(np.sum(fv * A.dot(fv)), 1 / 3)

        # ======================================================================
        # Test 3: Constant form (x^2,.,.) over 1D mesh
        # ======================================================================

        # Mesh
        mesh = Mesh1D(resolution=(10, ))

        # Nodal kernel function
        Q2 = QuadFE(1, 'Q2')
        dhQ2 = DofHandler(mesh, Q2)
        dhQ2.distribute_dofs()
        phiQ2 = Basis(dhQ2)

        f = Nodal(lambda x: x**2, basis=phiQ2)
        kernel = Kernel(f=f)

        # Form
        form = Form(kernel=kernel)

        # Generate and assemble the system
        system = Assembler(form, mesh)
        system.assemble()

        # Check
        self.assertAlmostEqual(system.get_scalar(), 1 / 3)

        # =====================================================================
        # Test 4: Periodic Mesh
        # =====================================================================
        #
        # TODO: NO checks yet
        #

        mesh = Mesh1D(resolution=(2, ), periodic=True)

        #
        Q1 = QuadFE(1, 'Q1')
        dhQ1 = DofHandler(mesh, Q1)
        dhQ1.distribute_dofs()
        u = Basis(dhQ1, 'u')

        form = Form(trial=u, test=u)

        system = Assembler(form, mesh)
        system.assemble()

        # =====================================================================
        # Test 5: Assemble simple sampled form
        # ======================================================================
        mesh = Mesh1D(resolution=(3, ))

        Q1 = QuadFE(1, 'Q1')
        dofhandler = DofHandler(mesh, Q1)
        dofhandler.distribute_dofs()
        phi = Basis(dofhandler)

        xv = dofhandler.get_dof_vertices()
        n_points = dofhandler.n_dofs()

        n_samples = 6
        a = np.arange(n_samples)

        f = lambda x, a: a * x

        fdata = np.zeros((n_points, n_samples))
        for i in range(n_samples):
            fdata[:, i] = f(xv, a[i]).ravel()

        # Define sampled function
        fn = Nodal(data=fdata, basis=phi)
        kernel = Kernel(fn)
        #
        # Integrate I[0,1] ax^2 dx by using the linear form (ax,x)
        #
        v = Basis(dofhandler, 'v')
        form = Form(kernel=kernel, test=v)
        system = Assembler(form, mesh)
        system.assemble()

        one = np.ones(n_points)
        for i in range(n_samples):
            b = system.get_vector(i_sample=i)
            self.assertAlmostEqual(one.dot(b), 0.5 * a[i])

        #
        # Integrate I[0,1] ax^4 dx using bilinear form (ax, x^2, x)
        #
        Q2 = QuadFE(1, 'Q2')
        dhQ2 = DofHandler(mesh, Q2)
        dhQ2.distribute_dofs()
        u = Basis(dhQ2, 'u')

        # Define form
        form = Form(kernel=kernel, test=v, trial=u)

        # Define and assemble system
        system = Assembler(form, mesh)
        system.assemble()

        # Express x^2 in terms of trial function basis
        dhQ2.distribute_dofs()
        xvQ2 = dhQ2.get_dof_vertices()
        xv_squared = xvQ2**2

        for i in range(n_samples):
            #
            # Iterate over samples
            #

            # Form sparse matrix
            A = system.get_matrix(i_sample=i)

            # Evaluate the integral
            I = np.sum(xv * A.dot(xv_squared))

            # Compare with expected result
            self.assertAlmostEqual(I, 0.2 * a[i])

        # =====================================================================
        # Test 6: Working with submeshes
        # =====================================================================
        mesh = Mesh1D(resolution=(2, ))