예제 #1
0
def test_Biharmonic(quad):
    M = 128
    SB = ShenBiharmonicBasis(M, quad=quad)
    x = Symbol("x")
    u = sin(6*pi*x)**2
    a = 1.0
    b = 1.0
    f = -u.diff(x, 4) + a*u.diff(x, 2) + b*u

    ul = lambdify(x, u, 'numpy')
    fl = lambdify(x, f, 'numpy')
    points, _ = SB.points_and_weights(M)
    uj = ul(points)
    fj = fl(points)

    A = inner_product((SB, 0), (SB, 4))
    B = inner_product((SB, 0), (SB, 0))
    C = inner_product((SB, 0), (SB, 2))

    AA = -A.diags() + C.diags() + B.diags()
    f_hat = np.zeros(M)
    f_hat = SB.scalar_product(fj, f_hat)
    u_hat = np.zeros(M)
    u_hat[:-4] = la.spsolve(AA, f_hat[:-4])
    u1 = np.zeros(M)
    u1 = SB.backward(u_hat, u1)
    #from IPython import embed; embed()

    assert np.allclose(u1, uj)
예제 #2
0
    def assemble(self):
        N = self.N
        SB = ShenBiharmonicBasis(N, quad=self.quad)
        SB.plan((N, N), 0, np.float, {})

        x, w = self.x, self.w = SB.points_and_weights(N)
        V = SB.vandermonde(x)

        # Trial function
        P4 = SB.get_vandermonde_basis(V)

        # Second derivatives
        T2x = SB.get_vandermonde_basis_derivative(V, 2)

        # (u'', v)
        K = np.zeros((N, N))
        K[:-4, :-4] = inner_product((SB, 0), (SB, 2)).diags().toarray()

        # ((1-x**2)u, v)
        xx = np.broadcast_to((1 - x**2)[:, np.newaxis], (N, N))
        #K1 = np.dot(w*P4.T, xx*P4)  # Alternative: K1 = np.dot(w*P4.T, ((1-x**2)*P4.T).T)
        K1 = np.zeros((N, N))
        K1 = SB.scalar_product(xx * P4, K1)
        K1 = extract_diagonal_matrix(
            K1).diags().toarray()  # For improved roundoff

        # ((1-x**2)u'', v)
        K2 = np.zeros((N, N))
        K2 = SB.scalar_product(xx * T2x, K2)
        K2 = extract_diagonal_matrix(
            K2).diags().toarray()  # For improved roundoff

        # (u'''', v)
        Q = np.zeros((self.N, self.N))
        Q[:-4, :-4] = inner_product((SB, 0), (SB, 4)).diags().toarray()

        # (u, v)
        M = np.zeros((self.N, self.N))
        M[:-4, :-4] = inner_product((SB, 0), (SB, 0)).diags().toarray()

        Re = self.Re
        a = self.alfa
        B = -Re * a * 1j * (K - a**2 * M)
        A = Q - 2 * a**2 * K + a**4 * M - 2 * a * Re * 1j * M - 1j * a * Re * (
            K2 - a**2 * K1)
        return A, B
예제 #3
0
    def interp(self, y, eigval=1, same_mesh=False, verbose=False):
        """Interpolate solution eigenvector and it's derivative onto y
        """
        N = self.N
        nx, eigval = self.get_eigval(eigval, verbose)
        phi_hat = np.zeros(N, np.complex)
        phi_hat[:-4] = np.squeeze(self.eigvectors[:, nx])
        if same_mesh:
            phi = np.zeros_like(phi_hat)
            dphidy = np.zeros_like(phi_hat)
            if self.SB is None:
                self.SB = ShenBiharmonicBasis(N, quad=self.quad, plan=True)
                self.SD = ShenDirichletBasis(N, quad=self.quad, plan=True)
                self.CDB = inner_product((self.SD, 0), (self.SB, 1))

            phi = self.SB.ifst(phi_hat, phi)
            dphidy_hat = self.CDB.matvec(phi_hat)
            dphidy_hat = self.SD.apply_inverse_mass(dphidy_hat)
            dphidy = self.SD.backward(dphidy_hat, dphidy)

        else:
            # Recompute interpolation matrices if necessary
            if not len(self.P4) == len(y):
                SB = ShenBiharmonicBasis(N, quad=self.quad)
                V = self.V = SB.vandermonde(y)
                P4 = self.P4 = SB.get_vandermonde_basis(V)
                T4x = self.T4x = SB.get_vandermonde_basis_derivative(V, 1)
            phi = np.dot(self.P4, phi_hat)
            dphidy = np.dot(self.T4x, phi_hat)

        return phi, dphidy
예제 #4
0
    def interp(self,
               y,
               eigvals,
               eigvectors,
               eigval=1,
               same_mesh=False,
               verbose=False):
        """Interpolate solution eigenvector and it's derivative onto y

        args:
            y            Interpolation points
            eigvals      All computed eigenvalues
            eigvectors   All computed eigenvectors
        kwargs:
            eigval       The chosen eigenvalue, ranked with descending imaginary
                         part. The largest imaginary part is 1, the second
                         largest is 2, etc.
            same_mesh    Boolean. Whether or not to interpolate to the same
                         quadrature points as used for computing the eigenvectors
            verbose      Boolean. Print information or not
        """
        N = self.N
        nx, eigval = self.get_eigval(eigval, eigvals, verbose)
        phi_hat = np.zeros(N, np.complex)
        phi_hat[:-4] = np.squeeze(eigvectors[:, nx])
        if same_mesh:
            phi = np.zeros_like(phi_hat)
            dphidy = np.zeros_like(phi_hat)
            if self.SB is None:
                self.SB = ShenBiharmonicBasis(N, quad=self.quad, plan=True)
                self.SD = ShenDirichletBasis(N, quad=self.quad, plan=True)
                self.CDB = inner_product((self.SD, 0), (self.SB, 1))

            phi = self.SB.ifst(phi_hat, phi)
            dphidy_hat = self.CDB.matvec(phi_hat)
            dphidy_hat = self.SD.apply_inverse_mass(dphidy_hat)
            dphidy = self.SD.backward(dphidy_hat, dphidy)

        else:
            # Recompute interpolation matrices if necessary
            if not len(self.P4) == len(y):
                SB = ShenBiharmonicBasis(N, quad=self.quad)
                V = SB.vandermonde(y)
                self.P4 = SB.get_vandermonde_basis(V)
                self.T4x = SB.get_vandermonde_basis_derivative(V, 1)
            phi = np.dot(self.P4, phi_hat)
            dphidy = np.dot(self.T4x, phi_hat)

        return eigval, phi, dphidy
예제 #5
0
class OrrSommerfeld(object):
    def __init__(self, **kwargs):
        self.par = {'alfa': 1., 'Re': 8000., 'N': 80, 'quad': 'GC'}
        self.par.update(**kwargs)
        for name, val in six.iteritems(self.par):
            setattr(self, name, val)
        self.P4 = np.zeros(0)
        self.T4x = np.zeros(0)
        self.SB, self.SD, self.CDB = (None, ) * 3
        self.x, self.w = None, None

    def interp(self,
               y,
               eigvals,
               eigvectors,
               eigval=1,
               same_mesh=False,
               verbose=False):
        """Interpolate solution eigenvector and it's derivative onto y

        args:
            y            Interpolation points
            eigvals      All computed eigenvalues
            eigvectors   All computed eigenvectors
        kwargs:
            eigval       The chosen eigenvalue, ranked with descending imaginary
                         part. The largest imaginary part is 1, the second
                         largest is 2, etc.
            same_mesh    Boolean. Whether or not to interpolate to the same
                         quadrature points as used for computing the eigenvectors
            verbose      Boolean. Print information or not
        """
        N = self.N
        nx, eigval = self.get_eigval(eigval, eigvals, verbose)
        phi_hat = np.zeros(N, np.complex)
        phi_hat[:-4] = np.squeeze(eigvectors[:, nx])
        if same_mesh:
            phi = np.zeros_like(phi_hat)
            dphidy = np.zeros_like(phi_hat)
            if self.SB is None:
                self.SB = ShenBiharmonicBasis(N, quad=self.quad, plan=True)
                self.SD = ShenDirichletBasis(N, quad=self.quad, plan=True)
                self.CDB = inner_product((self.SD, 0), (self.SB, 1))

            phi = self.SB.ifst(phi_hat, phi)
            dphidy_hat = self.CDB.matvec(phi_hat)
            dphidy_hat = self.SD.apply_inverse_mass(dphidy_hat)
            dphidy = self.SD.backward(dphidy_hat, dphidy)

        else:
            # Recompute interpolation matrices if necessary
            if not len(self.P4) == len(y):
                SB = ShenBiharmonicBasis(N, quad=self.quad)
                V = SB.vandermonde(y)
                self.P4 = SB.get_vandermonde_basis(V)
                self.T4x = SB.get_vandermonde_basis_derivative(V, 1)
            phi = np.dot(self.P4, phi_hat)
            dphidy = np.dot(self.T4x, phi_hat)

        return eigval, phi, dphidy

    def assemble(self):
        N = self.N
        SB = ShenBiharmonicBasis(N, quad=self.quad)
        SB.plan((N, N), 0, np.float, {})

        x, w = self.x, self.w = SB.points_and_weights(N)
        V = SB.vandermonde(x)

        # Trial function
        P4 = SB.get_vandermonde_basis(V)

        # Second derivatives
        T2x = SB.get_vandermonde_basis_derivative(V, 2)

        # (u'', v)
        K = np.zeros((N, N))
        K[:-4, :-4] = inner_product((SB, 0), (SB, 2)).diags().toarray()

        # ((1-x**2)u, v)
        xx = np.broadcast_to((1 - x**2)[:, np.newaxis], (N, N))
        #K1 = np.dot(w*P4.T, xx*P4)  # Alternative: K1 = np.dot(w*P4.T, ((1-x**2)*P4.T).T)
        K1 = np.zeros((N, N))
        K1 = SB.scalar_product(xx * P4, K1)
        K1 = extract_diagonal_matrix(
            K1).diags().toarray()  # For improved roundoff

        # ((1-x**2)u'', v)
        K2 = np.zeros((N, N))
        K2 = SB.scalar_product(xx * T2x, K2)
        K2 = extract_diagonal_matrix(
            K2).diags().toarray()  # For improved roundoff

        # (u'''', v)
        Q = np.zeros((self.N, self.N))
        Q[:-4, :-4] = inner_product((SB, 0), (SB, 4)).diags().toarray()

        # (u, v)
        M = np.zeros((self.N, self.N))
        M[:-4, :-4] = inner_product((SB, 0), (SB, 0)).diags().toarray()

        Re = self.Re
        a = self.alfa
        B = -Re * a * 1j * (K - a**2 * M)
        A = Q - 2 * a**2 * K + a**4 * M - 2 * a * Re * 1j * M - 1j * a * Re * (
            K2 - a**2 * K1)
        return A, B

    def solve(self, verbose=False):
        """Solve the Orr-Sommerfeld eigenvalue problem
        """
        if verbose:
            print('Solving the Orr-Sommerfeld eigenvalue problem...')
            print('Re = ' + str(self.par['Re']) + ' and alfa = ' +
                  str(self.par['alfa']))
        A, B = self.assemble()
        return eig(A[:-4, :-4], B[:-4, :-4])
        # return eig(np.dot(inv(B[:-4, :-4]), A[:-4, :-4]))

    @staticmethod
    def get_eigval(nx, eigvals, verbose=False):
        """Get the chosen eigenvalue

        Args:
            nx       The chosen eigenvalue. nx=1 corresponds to the one with the
                     largest imaginary part, nx=2 the second largest etc.
            eigvals  Computed eigenvalues

            verbose  Print the value of the chosen eigenvalue

        """
        indices = np.argsort(np.imag(eigvals))
        indi = indices[-1 * np.array(nx)]
        eigval = eigvals[indi]
        if verbose:
            ev = list(eigval) if np.ndim(eigval) else [eigval]
            indi = list(indi) if np.ndim(indi) else [indi]
            for i, (e, v) in enumerate(zip(ev, indi)):
                print('Eigenvalue {} ({}) = {:2.16e}'.format(i + 1, v, e))
        return indi, eigval
예제 #6
0
def get_context():
    """Set up context for solver"""

    # Get points and weights for Chebyshev weighted integrals
    ST = ShenDirichletBasis(params.N[0], quad=params.Dquad)
    SB = ShenBiharmonicBasis(params.N[0], quad=params.Bquad)
    CT = Basis(params.N[0], quad=params.Dquad)
    ST0 = ShenDirichletBasis(params.N[0], quad=params.Dquad,
                             plan=True)  # For 1D problem
    K0 = C2CBasis(params.N[1], domain=(0, params.L[1]))
    K1 = R2CBasis(params.N[2], domain=(0, params.L[2]))

    #CT = ST.CT  # Chebyshev transform
    FST = TensorProductSpace(comm, (ST, K0, K1), **{
        'threads': params.threads,
        'planner_effort': params.planner_effort["dct"]
    })  # Dirichlet
    FSB = TensorProductSpace(comm, (SB, K0, K1), **{
        'threads': params.threads,
        'planner_effort': params.planner_effort["dct"]
    })  # Biharmonic
    FCT = TensorProductSpace(comm, (CT, K0, K1), **{
        'threads': params.threads,
        'planner_effort': params.planner_effort["dct"]
    })  # Regular Chebyshev
    VFS = VectorTensorProductSpace([FSB, FST, FST])

    # Padded
    STp = ShenDirichletBasis(params.N[0], quad=params.Dquad)
    SBp = ShenBiharmonicBasis(params.N[0], quad=params.Bquad)
    CTp = Basis(params.N[0], quad=params.Dquad)
    K0p = C2CBasis(params.N[1], padding_factor=1.5, domain=(0, params.L[1]))
    K1p = R2CBasis(params.N[2], padding_factor=1.5, domain=(0, params.L[2]))
    FSTp = TensorProductSpace(
        comm, (STp, K0p, K1p), **{
            'threads': params.threads,
            'planner_effort': params.planner_effort["dct"]
        })
    FSBp = TensorProductSpace(
        comm, (SBp, K0p, K1p), **{
            'threads': params.threads,
            'planner_effort': params.planner_effort["dct"]
        })
    FCTp = TensorProductSpace(
        comm, (CTp, K0p, K1p), **{
            'threads': params.threads,
            'planner_effort': params.planner_effort["dct"]
        })
    VFSp = VectorTensorProductSpace([FSBp, FSTp, FSTp])

    VFSp = VFS
    FCTp = FCT
    FSTp = FST
    FSBp = FSB

    Nu = params.N[0] - 2  # Number of velocity modes in Shen basis
    Nb = params.N[0] - 4  # Number of velocity modes in Shen biharmonic basis
    u_slice = slice(0, Nu)
    v_slice = slice(0, Nb)

    float, complex, mpitype = datatypes("double")

    # Mesh variables
    X = FST.local_mesh(True)
    x0, x1, x2 = FST.mesh()
    K = FST.local_wavenumbers(scaled=True)

    # Solution variables
    U = Array(VFS, False)
    U0 = Array(VFS, False)
    U_hat = Array(VFS)
    U_hat0 = Array(VFS)
    g = Array(FST)

    # primary variable
    u = (U_hat, g)

    H_hat = Array(VFS)
    H_hat0 = Array(VFS)
    H_hat1 = Array(VFS)

    dU = Array(VFS)
    hv = Array(FST)
    hg = Array(FST)
    Source = Array(VFS, False)
    Sk = Array(VFS)

    K2 = K[1] * K[1] + K[2] * K[2]
    K_over_K2 = np.zeros((2, ) + g.shape)
    for i in range(2):
        K_over_K2[i] = K[i + 1] / np.where(K2 == 0, 1, K2)

    work = work_arrays()

    nu, dt, N = params.nu, params.dt, params.N
    K4 = K2**2
    kx = K[0][:, 0, 0]

    alfa = K2[0] - 2.0 / nu / dt
    # Collect all matrices
    mat = config.AttributeDict(
        dict(
            CDD=inner_product((ST, 0), (ST, 1)),
            AB=HelmholtzCoeff(kx, -1.0, -alfa, ST.quad),
            AC=BiharmonicCoeff(kx,
                               nu * dt / 2., (1. - nu * dt * K2[0]),
                               -(K2[0] - nu * dt / 2. * K4[0]),
                               quad=SB.quad),
            # Matrices for biharmonic equation
            CBD=inner_product((SB, 0), (ST, 1)),
            ABB=inner_product((SB, 0), (SB, 2)),
            BBB=inner_product((SB, 0), (SB, 0)),
            SBB=inner_product((SB, 0), (SB, 4)),
            # Matrices for Helmholtz equation
            ADD=inner_product((ST, 0), (ST, 2)),
            BDD=inner_product((ST, 0), (ST, 0)),
            BBD=inner_product((SB, 0), (ST, 0)),
            CDB=inner_product((ST, 0), (SB, 1)),
            ADD0=inner_product((ST0, 0), (ST0, 2)),
            BDD0=inner_product((ST0, 0), (ST0, 0)),
        ))

    # Collect all linear algebra solvers
    #la = config.AttributeDict(dict(
    #HelmholtzSolverG = Helmholtz(N[0], np.sqrt(K2[0]+2.0/nu/dt), ST),
    #BiharmonicSolverU = Biharmonic(N[0], -nu*dt/2., 1.+nu*dt*K2[0],
    #-(K2[0] + nu*dt/2.*K4[0]), quad=SB.quad,
    #solver="cython"),
    #HelmholtzSolverU0 = Helmholtz(N[0], np.sqrt(2./nu/dt), ST),
    #TDMASolverD = TDMA(inner_product((ST, 0), (ST, 0)))
    #)
    #)
    mat.ADD.axis = 0
    mat.BDD.axis = 0
    mat.SBB.axis = 0

    la = config.AttributeDict(
        dict(HelmholtzSolverG=Helmholtz(mat.ADD, mat.BDD, -np.ones(
            (1, 1, 1)), (K2[0] + 2.0 / nu / dt)[np.newaxis, :, :]),
             BiharmonicSolverU=Biharmonic(
                 mat.SBB, mat.ABB, mat.BBB, -nu * dt / 2. * np.ones(
                     (1, 1, 1)), (1. + nu * dt * K2[0])[np.newaxis, :, :],
                 (-(K2[0] + nu * dt / 2. * K4[0]))[np.newaxis, :, :]),
             HelmholtzSolverU0=old_Helmholtz(N[0], np.sqrt(2. / nu / dt), ST),
             TDMASolverD=TDMA(inner_product((ST, 0), (ST, 0)))))

    hdf5file = KMMWriter({
        "U": U[0],
        "V": U[1],
        "W": U[2]
    },
                         chkpoint={
                             'current': {
                                 'U': U
                             },
                             'previous': {
                                 'U': U0
                             }
                         },
                         filename=params.solver + ".h5",
                         mesh={
                             "x": x0,
                             "y": x1,
                             "z": x2
                         })

    return config.AttributeDict(locals())
예제 #7
0
def get_context():
    """Set up context for solver"""

    # Get points and weights for Chebyshev weighted integrals
    ST = ShenDirichletBasis(params.N[0], quad=params.Dquad)
    SB = ShenBiharmonicBasis(params.N[0], quad=params.Bquad)
    CT = ST.CT  # Chebyshev transform

    Nu = params.N[0] - 2  # Number of velocity modes in Shen basis
    Nb = params.N[0] - 4  # Number of velocity modes in Shen biharmonic basis
    u_slice = slice(0, Nu)
    v_slice = slice(0, Nb)

    FST = SlabShen_R2C(params.N,
                       params.L,
                       comm,
                       threads=params.threads,
                       communication=params.communication,
                       planner_effort=params.planner_effort,
                       dealias_cheb=params.dealias_cheb)

    float, complex, mpitype = datatypes("double")

    ST.plan(FST.complex_shape(), 0, complex, {
        'threads': params.threads,
        'planner_effort': params.planner_effort["dct"]
    })
    SB.plan(FST.complex_shape(), 0, complex, {
        'threads': params.threads,
        'planner_effort': params.planner_effort["dct"]
    })

    # Mesh variables
    X = FST.get_local_mesh(ST)
    x0, x1, x2 = FST.get_mesh_dims(ST)
    K = FST.get_local_wavenumbermesh(scaled=True)

    K2 = K[1] * K[1] + K[2] * K[2]
    K_over_K2 = zeros((2, ) + FST.complex_shape())
    for i in range(2):
        K_over_K2[i] = K[i + 1] / np.where(K2 == 0, 1, K2)

    # Solution variables
    U = zeros((3, ) + FST.real_shape(), dtype=float)
    U0 = zeros((3, ) + FST.real_shape(), dtype=float)
    U_hat = zeros((3, ) + FST.complex_shape(), dtype=complex)
    U_hat0 = zeros((3, ) + FST.complex_shape(), dtype=complex)
    g = zeros(FST.complex_shape(), dtype=complex)

    # primary variable
    u = (U_hat, g)

    H_hat = zeros((3, ) + FST.complex_shape(), dtype=complex)
    H_hat0 = zeros((3, ) + FST.complex_shape(), dtype=complex)
    H_hat1 = zeros((3, ) + FST.complex_shape(), dtype=complex)

    dU = zeros((3, ) + FST.complex_shape(), dtype=complex)
    hv = zeros(FST.complex_shape(), dtype=complex)
    hg = zeros(FST.complex_shape(), dtype=complex)
    Source = zeros((3, ) + FST.real_shape(), dtype=float)
    Sk = zeros((3, ) + FST.complex_shape(), dtype=complex)

    work = work_arrays()

    nu, dt, N = params.nu, params.dt, params.N
    K4 = K2**2
    kx = K[0][:, 0, 0]

    # Collect all linear algebra solvers
    la = config.AttributeDict(
        dict(HelmholtzSolverG=Helmholtz(N[0], np.sqrt(K2[0] + 2.0 / nu / dt),
                                        ST),
             BiharmonicSolverU=Biharmonic(N[0],
                                          -nu * dt / 2.,
                                          1. + nu * dt * K2[0],
                                          -(K2[0] + nu * dt / 2. * K4[0]),
                                          quad=SB.quad,
                                          solver="cython"),
             HelmholtzSolverU0=Helmholtz(N[0], np.sqrt(2. / nu / dt), ST),
             TDMASolverD=TDMA(inner_product((ST, 0), (ST, 0)))))

    alfa = K2[0] - 2.0 / nu / dt
    # Collect all matrices
    mat = config.AttributeDict(
        dict(
            CDD=inner_product((ST, 0), (ST, 1)),
            AB=HelmholtzCoeff(N[0], 1.0, -alfa, ST.quad),
            AC=BiharmonicCoeff(N[0],
                               nu * dt / 2., (1. - nu * dt * K2[0]),
                               -(K2[0] - nu * dt / 2. * K4[0]),
                               quad=SB.quad),
            # Matrices for biharmonic equation
            CBD=inner_product((SB, 0), (ST, 1)),
            ABB=inner_product((SB, 0), (SB, 2)),
            BBB=inner_product((SB, 0), (SB, 0)),
            SBB=inner_product((SB, 0), (SB, 4)),
            # Matrices for Helmholtz equation
            ADD=inner_product((ST, 0), (ST, 2)),
            BDD=inner_product((ST, 0), (ST, 0)),
            BBD=inner_product((SB, 0), (ST, 0)),
            CDB=inner_product((ST, 0), (SB, 1))))

    hdf5file = KMMWriter({
        "U": U[0],
        "V": U[1],
        "W": U[2]
    },
                         chkpoint={
                             'current': {
                                 'U': U
                             },
                             'previous': {
                                 'U': U0
                             }
                         },
                         filename=params.solver + ".h5",
                         mesh={
                             "x": x0,
                             "y": x1,
                             "z": x2
                         })

    return config.AttributeDict(locals())
예제 #8
0
from shenfun.chebyshev.bases import ShenBiharmonicBasis, Basis
from shenfun.fourier.bases import R2CBasis, C2CBasis
from shenfun.chebyshev.la import Biharmonic as Solver
from shenfun import inner, div, grad, TestFunction, TrialFunction, project, Dx
from shenfun import Function, TensorProductSpace
from mpi4py import MPI
import numpy as np

comm = MPI.COMM_WORLD

N = (32, 33, 34)
K0 = ShenBiharmonicBasis(N[0])
K1 = C2CBasis(N[1])
K2 = R2CBasis(N[2])
W = TensorProductSpace(comm, (K0, K1, K2))
u = TrialFunction(W)
v = TestFunction(W)
matrices = inner(v, div(grad(div(grad(u)))))
fj = Function(W, False)
fj[:] = np.random.random(fj.shape)

f_hat = inner(v, fj)  # Some right hand side
B = Solver(**matrices)

# Solve and transform to real space
u_hat = Function(W)  # Solution spectral space
u_hat = B(u_hat, f_hat)  # Solve
u = Function(W, False)
u = W.backward(u_hat, u)

# compute dudx of the solution