예제 #1
0
파일: solver.py 프로젝트: lirhlirh/gimli
def parseMapToCellArray(attributeMap, mesh, default=0.0):
    """
    Parse a value map to cell attributes.

    A map should consist of pairs of marker and value.
    A marker is an integer and corresponds to the cell.marker().

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh`
        For each cell of mesh a value will be returned.

    attributeMap : list | dict
        List of pairs [marker, value] ] || [[marker, value]],
        or dictionary with marker keys

    default : float [0.0]
        Fill all unmapped atts to this default.

    Returns
    -------
    atts : array
        Array of length mesh.cellCount()
    """

    atts = pg.RVector(mesh.cellCount(), default)

    if isinstance(attributeMap, dict):
        raise Exception("Please implement me!")
    elif hasattr(attributeMap, '__len__'):
        if not hasattr(attributeMap[0], '__len__'):
            # assuming [marker, value]
            attributeMap = [attributeMap]

        for pair in attributeMap:
            if hasattr(pair, '__len__'):
                idx = pg.find(mesh.cellMarkers() == pair[0])
                if len(idx) == 0:
                    print("Warning! parseMapToCellArray: cannot find marker " +
                          str(pair[0]) + " within mesh.")
                else:
                    #print('---------------------')
                    #print(atts, idx, pair[1], type(pair[1]), float(pair[1]))
                    if isinstance(pair[1], np.complex):
                        #print('+++++++++++++++++')
                        if not isinstance(atts, pg.CVector):
                            atts = pg.toComplex(atts)
                        atts[idx] = pair[1]
                    else:
                        atts[idx] = float(pair[1])
            else:
                raise Exception("Please provide a list of [int, value] pairs" +
                                str(pair))
    else:
        print("attributeMap: ", attributeMap)
        raise Exception("Cannot interpret attributeMap!")

    return atts
예제 #2
0
    def createJacobian(self, model):
        print('=' * 100)

        if self.complex():
            modelRe = model[0:int(len(model) / 2)]
            modelIm = model[int(len(model) / 2):len(model)]
            modelC = pg.toComplex(modelRe, modelIm)
            print("Real", min(modelRe), max(modelRe))
            print("Imag", min(modelIm), max(modelIm))

            u = self.prepareJacobian_(modelC)

            if self._J.rows() == 0:
                #re(data)/re(mod) = im(data)/im(mod)
                # we need a local copy until we have a gimli internal reference counter FIXTHIS
                M1 = pg.RMatrix()
                M2 = pg.RMatrix()
                self.matrixHeap.append(M1)
                self.matrixHeap.append(M2)

                JRe = self._J.addMatrix(M1)
                JIm = self._J.addMatrix(M2)

                self._J.addMatrixEntry(JRe, 0, 0)
                self._J.addMatrixEntry(JIm, 0, len(modelRe), -1.0)
                self._J.addMatrixEntry(JIm, self.data().size(), 0, 1.0)
                self._J.addMatrixEntry(JRe, self.data().size(), len(modelRe))

            else:
                self._J.clean()

            k = pg.RVector(self.data()('k'))
            self.data().set('k', k * 0.0 + 1.0)

            dMapResponse = pb.DataMap()
            dMapResponse.collect(self.electrodes(), self.solution())
            respRe = dMapResponse.data(self.data(), False, False)
            respIm = dMapResponse.data(self.data(), False, True)

            #CVector resp(toComplex(respRe, respIm));
            #RVector am(abs(resp) * dataContainer_->get("k"));
            #RVector ph(-phase(resp));

            print("respRe", pg.median(respRe), min(respRe), max(respRe))
            print("respIm", pg.median(respIm), min(respIm), max(respIm))

            JC = pg.CMatrix()
            self.createJacobian_(modelC, u, JC)
            for i in range(JC.rows()):
                #JC[i] *= 1.0/(modelC*modelC) * k[i]
                JC[i] /= (modelC * modelC) / k[i]

            self._J.mat(0).copy(pg.real(JC))
            self._J.mat(1).copy(pg.imag(JC))

            #self.createJacobian_(modelRe*0.0+1.0, pg.real(u), self._J.mat(1))
            #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(2))
            #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(3))

            sumsens0 = pg.RVector(self._J.mat(0).rows())
            sumsens1 = pg.RVector(self._J.mat(0).rows())
            sumsens2 = pg.RVector(self._J.mat(0).rows())

            for i in range(self._J.mat(0).rows()):
                #self._J.mat(0)[i] *= 1./modelRe / respRe[i]
                #self._J.mat(1)[i] *= 1./modelIm / respRe[i]

                #self._J.mat(2)[i] *= 1./modelRe / respIm[i]
                #self._J.mat(3)[i] *= 1./modelIm / respIm[i]

                #self._J.mat(0)[i] *= 1./(modelRe * modelRe) * k[i]
                #self._J.mat(1)[i] *= 1./(modelRe * modelIm) * k[i]

                #self._J.mat(2)[i] *= 1./(modelIm * modelRe) * k[i]
                #self._J.mat(3)[i] *= 1./(modelIm * modelIm) * k[i]

                sumsens0[i] = sum(self._J.mat(0)[i])
                sumsens1[i] = sum(self._J.mat(1)[i])
                sumsens2[i] = abs(sum(JC[i]))

            print(pg.median(sumsens0), min(sumsens0), max(sumsens0))
            print(pg.median(sumsens1), min(sumsens1), max(sumsens1))
            print(pg.median(sumsens2), min(sumsens2), max(sumsens2))

            self.data().set('k', k)

            self._J.recalcMatrixSize()
        else:
            # self.setVerbose(True)
            u = self.prepareJacobian_(model)

            #J = pg.RMatrix()
            if self._J.rows() == 0:
                print('#' * 100)
                M1 = pg.RMatrix()
                Jid = self._J.addMatrix(M1)
                self._J.addMatrixEntry(Jid, 0, 0)
            else:
                self._J.clean()

            self.createJacobian_(model, u, self._J.mat(0))
            self._J.recalcMatrixSize()
예제 #3
0
    def createJacobian(self, model):
        print('=' * 100)

        if self.complex():
            modelRe = model[0:int(len(model)/2)]
            modelIm = model[int(len(model)/2):len(model)]
            modelC = pg.toComplex(modelRe, modelIm)
            print("Real", min(modelRe), max(modelRe))
            print("Imag", min(modelIm), max(modelIm))

            u = self.prepareJacobian_(modelC)

            if self._J.rows() == 0:
                #re(data)/re(mod) = im(data)/im(mod)
                # we need a local copy until we have a gimli internal reference counter FIXTHIS
                M1 = pg.RMatrix()
                M2 = pg.RMatrix()
                self.matrixHeap.append(M1)
                self.matrixHeap.append(M2)

                JRe = self._J.addMatrix(M1)
                JIm = self._J.addMatrix(M2)

                self._J.addMatrixEntry(JRe, 0, 0)
                self._J.addMatrixEntry(JIm, 0, len(modelRe), -1.0)
                self._J.addMatrixEntry(JIm, self.data().size(), 0, 1.0)
                self._J.addMatrixEntry(JRe, self.data().size(), len(modelRe))

            else:
                self._J.clean()


            k = pg.RVector(self.data()('k'))
            self.data().set('k', k*0.0 + 1.0)

            dMapResponse = pb.DataMap()
            dMapResponse.collect(self.electrodes(), self.solution())
            respRe = dMapResponse.data(self.data(), False, False)
            respIm = dMapResponse.data(self.data(), False, True)

            #CVector resp(toComplex(respRe, respIm));
            #RVector am(abs(resp) * dataContainer_->get("k"));
            #RVector ph(-phase(resp));

            print("respRe", pg.median(respRe), min(respRe), max(respRe))
            print("respIm", pg.median(respIm), min(respIm), max(respIm))

            JC = pg.CMatrix()
            self.createJacobian_(modelC, u, JC)
            for i in range(JC.rows()):
                #JC[i] *= 1.0/(modelC*modelC) * k[i]
                JC[i] /= (modelC * modelC) / k[i]

            self._J.mat(0).copy(pg.real(JC))
            self._J.mat(1).copy(pg.imag(JC))

            #self.createJacobian_(modelRe*0.0+1.0, pg.real(u), self._J.mat(1))
            #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(2))
            #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(3))


            sumsens0 = pg.RVector(self._J.mat(0).rows())
            sumsens1 = pg.RVector(self._J.mat(0).rows())
            sumsens2 = pg.RVector(self._J.mat(0).rows())

            for i in range(self._J.mat(0).rows()):
                #self._J.mat(0)[i] *= 1./modelRe / respRe[i]
                #self._J.mat(1)[i] *= 1./modelIm / respRe[i]

                #self._J.mat(2)[i] *= 1./modelRe / respIm[i]
                #self._J.mat(3)[i] *= 1./modelIm / respIm[i]

                #self._J.mat(0)[i] *= 1./(modelRe * modelRe) * k[i]
                #self._J.mat(1)[i] *= 1./(modelRe * modelIm) * k[i]

                #self._J.mat(2)[i] *= 1./(modelIm * modelRe) * k[i]
                #self._J.mat(3)[i] *= 1./(modelIm * modelIm) * k[i]

                sumsens0[i] = sum(self._J.mat(0)[i])
                sumsens1[i] = sum(self._J.mat(1)[i])
                sumsens2[i] = abs(sum(JC[i]))

            print(pg.median(sumsens0), min(sumsens0), max(sumsens0))
            print(pg.median(sumsens1), min(sumsens1), max(sumsens1))
            print(pg.median(sumsens2), min(sumsens2), max(sumsens2))

            self.data().set('k', k)

            self._J.recalcMatrixSize()
        else:
            # self.setVerbose(True)
            u = self.prepareJacobian_(model)

            #J = pg.RMatrix()
            if self._J.rows() == 0:
                print('#' * 100)
                M1 = pg.RMatrix()
                Jid = self._J.addMatrix(M1)
                self._J.addMatrixEntry(Jid, 0, 0)
            else:
                self._J.clean()

            self.createJacobian_(model, u, self._J.mat(0))
            self._J.recalcMatrixSize()
예제 #4
0
def solveFiniteElements(mesh, a=1.0, b=0.0, f=0.0, times=None, userData=None,
                        verbose=False, stats=None, **kwargs):
    """
    WRITEME short

    WRITEME long

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh`
        Mesh represents spatial discretization of the calculation domain

    a   : value | array | callable(cell, userData)
        Cell values

    b   : value | array | callable(cell, userData)
        Cell values

    u0 : value | array | callable(pos, userData)
        Node values

    ub : value | array | callable(pos, userData)
        Dirichlet values for u at the boundary

    dub : value | array | callable(pos, userData)
        Neumann values for du/dn at the boundary

    f : value | array(cells) | array(nodes) | callable(args, kwargs)
        force values

    times : array [None]
        solve as time dependent problem for the given times

    theta : float [1]
        - `theta` = 0, explicit Euler, maybe stable for
        - `theta` = 0.5, Crank-Nicolsen, maybe instable
        - `theta` = 1, implicit Euler

        .. math:: \\Delta t \\quad\\text{near}\\quad h

        Time dependent equation is stable for:
        .. math:: 0.5 <= \\theta <= 1.0

        If unsure choose 0.5 + epsilon, which is probably be stable.

    progress : bool
        Give some calculation progress.

    Returns
    -------

    u : array
        Returns the solution u either 1,n array for stationary problems or
        for m,n array for m time steps

    Examples
    --------
    >>> import pygimli as pg
    >>> from pygimli.meshtools import polytools as plc
    >>> from pygimli.mplviewer import drawField, drawMesh
    >>> import matplotlib.pyplot as plt
    >>> world = plc.createWorld(start=[-10, 0], end=[10, -10], marker=1, worldMarker=False)
    >>> c1 = plc.createCircle(pos=[0.0, -5.0], radius=3.0, area=.1, marker=2)
    >>> mesh = pg.meshtools.createMesh([world, c1], quality=34.3)
    >>> u = pg.solver.solveFiniteElements(mesh, a=[[1, 100], [2, 1]], uB=[[4, 1.0], [3, 0.0]])
    >>> fig, ax = plt.subplots()
    >>> pc = drawField(ax, mesh, u)
    >>> drawMesh(ax, mesh)
    >>> plt.show()

    See Also
    --------

    other solver TODO
    """

    if 'uDirichlet' in kwargs or 'uBoundary' in kwargs:
        raise("use uB instead")

    if 'uBoundary' in kwargs:
        raise("use duB instead")

    debug = kwargs.pop('debug', False)

    if verbose:
        print("Mesh: ", str(mesh))

    dof = mesh.nodeCount()

    swatch = pg.Stopwatch(True)
    swatch2 = pg.Stopwatch(True)

    # check for material parameter
    a = parseArgToArray(a, ndof=mesh.cellCount(), mesh=mesh, userData=userData)
    b = parseArgToArray(b, ndof=mesh.cellCount(), mesh=mesh, userData=userData)

    if debug:
        print("2: ", swatch2.duration(True))
    # assemble the stiffness matrix
    A = createStiffnessMatrix(mesh, a)

    if debug:
        print("3: ", swatch2.duration(True))
    M = createMassMatrix(mesh, b)

    if debug:
        print("4: ", swatch2.duration(True))
    S = A + M

    if debug:
        print("5: ", swatch2.duration(True))
    if times is None:

        rhs = assembleForceVector(mesh, f, userData=userData)

        if debug:
            print("6a: ", swatch2.duration(True))

        if 'duB' in kwargs:
            print(userData)
            assembleNeumannBC(S,
                              parseArgToBoundaries(kwargs['duB'], mesh),
                              time=0.0,
                              userData=userData,
                              verbose=False)

        if debug:
            print("6b: ", swatch2.duration(True))
        if 'uB' in kwargs:
            assembleDirichletBC(S,
                                parseArgToBoundaries(kwargs['uB'], mesh),
                                rhs, time=0.0,
                                userData=userData,
                                verbose=False)

        if debug:
            print("6c: ", swatch2.duration(True))

        u = None

        if isinstance(a[0], complex):
            u = pg.CVector(rhs.size(), 0.0)
            rhs = pg.toComplex(rhs)
        else:
            u = pg.RVector(rhs.size(), 0.0)

        if debug:
            print("7: ", swatch2.duration(True))

        assembleTime = swatch.duration(True)
        if stats:
            stats.assembleTime = assembleTime

        if verbose:
            print(("Asssemblation time: ", assembleTime))

        # showSparseMatrix(S)

        solver = pg.LinSolver(False)
        solver.setMatrix(S, 0)

        u = solver.solve(rhs)

        solverTime = swatch.duration(True)
        if verbose:
            if stats:
                stats.solverTime = solverTime
            print(("Solving time: ", solverTime))

        return u

    else:
        if debug:
            print("start TL", swatch.duration())

        M = createMassMatrix(mesh)
        F = assembleForceVector(mesh, f)

        if 'u0' in kwargs:
            u0 = parseArgToArray(kwargs['u0'], dof, mesh, userData)

        theta = kwargs.pop('theta', 1)

        if not 'duB' in kwargs:
            A = createStiffnessMatrix(mesh, a)

            if 'uB' in kwargs:
                assembleDirichletBC(A,
                                    parseArgToBoundaries(kwargs['uB'], mesh),
                                    rhs=F)

            return crankNicolson(times, theta, A, M, F, u0=u0, verbose=verbose)

        rhs = np.zeros((len(times), dof))
        # rhs kann zeitabhängig sein ..wird hier nicht berücksichtigt
        rhs[:] = F  # this is slow: optimize

        if debug:
            print("rhs", swatch.duration())
        U = np.zeros((len(times), dof))
        U[0, :] = u0

        # init state
        u = pg.RVector(dof, 0.0)

        if debug:
            print("u0", swatch.duration())

        measure = 0.
        for n in range(1, len(times)):
            swatch.reset()

            dt = times[n] - times[n - 1]

            # previous timestep
            # print "i: ", i, dt, U[i - 1]

            if 'duB' in kwargs:
                # aufschreiben und checken ob neumann auf A oder auf S mit
                # skaliertem val*dt angewendet wird
                A = createStiffnessMatrix(mesh, a)
                assembleNeumannBC(A,
                                  parseArgToBoundaries(kwargs['duB'],
                                                       mesh),
                                  time=times[n],
                                  userData=userData,
                                  verbose=False)

            swatch.reset()
            # (A + a*B)u is fastest, followed by A*u + (B*u)*a and finally A*u + a*B*u and
            b = (M + (dt * (theta - 1.)) * A ) * U[n - 1] + \
                dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])

            #print ('a',swatch.duration(True))
            # b = M * U[n - 1] - (A * U[n - 1]) * (dt*(1.0 - theta)) + \
            #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])

            #print ('b',swatch.duration(True))

            # b = M * U[n - 1] - (dt*(1.0 - theta)) * A * U[n - 1] + \
            #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
            #print ('c',swatch.duration(True))

            measure += swatch.duration()

            S = M + A * dt * theta

            if 'uB' in kwargs:
                assembleDirichletBC(S,
                                    parseArgToBoundaries(kwargs['uB'], mesh),
                                    rhs=b,
                                    time=times[n],
                                    userData=userData,
                                    verbose=verbose)

            #u = S/b
            t_prep = swatch.duration(True)
            solver = pg.LinSolver(S, verbose)
            solver.solve(b, u)

            if 'plotTimeStep' in kwargs:
                kwargs['plotTimeStep'](u, times[n])

            U[n, :] = np.asarray(u)

            if 'progress' in kwargs:
                if kwargs['progress']:
                    print(("\t" + str(n) + "/" + str(len(times) - 1) +
                           ": " + str(t_prep) + "/" + str(swatch.duration())))

        if debug:
            print("Measure(" + str(len(times)) + "): ",
                  measure, measure / len(times))
        return U
예제 #5
0
파일: solver.py 프로젝트: lirhlirh/gimli
def solveFiniteElements(mesh,
                        a=1.0,
                        b=0.0,
                        f=0.0,
                        times=None,
                        userData=None,
                        verbose=False,
                        stats=None,
                        **kwargs):
    r"""Solve partial differential equation with Finite Elements.

    This function is a syntactic sugar proxy for using the Finite Element
    functionality of the library core to solve elliptic and parabolic partial
    differential of the following type:

    .. math::

        \frac{\partial u}{\partial t} & = \nabla\cdot(a \nabla u) + b u + f(\mathbf{r},t) \\
        u(\mathbf{r}, t) & = u_B  \quad\mathbf{r}\in\Gamma_{\text{Dirichlet}}\\
        \frac{\partial u(\mathbf{r}, t)}{\partial \mathbf{n}} & = u_{\partial \text{B}} \quad\mathbf{r}\in\Gamma_{\text{Neumann}}\\
        u(\mathbf{r}, t=0) & = u_0 \quad\text{with} \quad\mathbf{r}\in\Omega\quad\text{for}\quad t\neq 0

    The Domain :math:`\Omega` and the Boundary :math:`\Gamma` are defined
    through the given mesh with appropriate boundary marker.

    The solution :math:`u(\mathbf{r}, t)` is given for each node in mesh.


    TODO:

        * unsteady ub and dub

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh`
        Mesh represents spatial discretization of the calculation domain

    a   : value | array | callable(cell, userData)
        Cell values

    b   : value | array | callable(cell, userData)
        Cell values

    u0 : value | array | callable(pos, userData)
        Node values

    uB : value | array | callable(pos, userData)
        Dirichlet values for u at the boundary

    uN : list([node, value])
        Dirichlet values for u at given nodes

    duB : value | array | callable(pos, userData)
        Neumann values for du/dn at the boundary

    f : value | array(cells) | array(nodes) | callable(args, kwargs)
        force values

    times : array [None]
        Solve as time dependent problem for the given times.

    theta : float [1]
        - :math:`theta = 0` means explicit Euler, maybe stable for
         :math:`\Delta t \quad\text{near}\quad h`
        - :math:`theta = 0.5`, Crank-Nicolsen, maybe instable
        - :math:`theta = 1`, implicit Euler

        If unsure choose :math:`\theta = 0.5 + \epsilon`, which is probably stable.

    progress : bool
        Give some calculation progress.

    ret :
        Workspace for results so no new memory will be allocated.

    Returns
    -------

    u : array
        Returns the solution u either 1,n array for stationary problems or
        for m,n array for m time steps

    Examples
    --------
    >>> import pygimli as pg
    >>> from pygimli.meshtools import polytools as plc
    >>> from pygimli.mplviewer import drawField, drawMesh
    >>> import matplotlib.pyplot as plt
    >>> world = plc.createWorld(start=[-10, 0], end=[10, -10],
    ...                         marker=1, worldMarker=False)
    >>> c1 = plc.createCircle(pos=[0.0, -5.0], radius=3.0, area=.1, marker=2)
    >>> mesh = pg.meshtools.createMesh([world, c1], quality=34.3)
    >>> u = pg.solver.solveFiniteElements(mesh, a=[[1, 100], [2, 1]],
    ...                                   uB=[[4, 1.0], [2, 0.0]])
    >>> fig, ax = plt.subplots()
    >>> pc = drawField(ax, mesh, u)
    >>> drawMesh(ax, mesh)
    >>> plt.show()

    See Also
    --------

    other solver TODO
    """

    if 'uDirichlet' in kwargs or 'uBoundary' in kwargs:
        raise BaseException("use uB instead")

    if 'uBoundary' in kwargs:
        raise BaseException("use duB instead")

    debug = kwargs.pop('debug', False)

    mesh.createNeighbourInfos()
    if verbose:
        print("Mesh: ", str(mesh))

    dof = mesh.nodeCount()

    swatch = pg.Stopwatch(True)
    swatch2 = pg.Stopwatch(True)

    # check for material parameter
    a = parseArgToArray(a, ndof=mesh.cellCount(), mesh=mesh, userData=userData)
    b = parseArgToArray(b, ndof=mesh.cellCount(), mesh=mesh, userData=userData)

    if debug:
        print("2: ", swatch2.duration(True))
    # assemble the stiffness matrix
    A = createStiffnessMatrix(mesh, a)

    if debug:
        print("3: ", swatch2.duration(True))
    M = createMassMatrix(mesh, b)

    if debug:
        print("4: ", swatch2.duration(True))
    S = A + M

    if debug:
        print("5: ", swatch2.duration(True))
    if times is None:

        rhs = assembleForceVector(mesh, f, userData=userData)

        if debug:
            print("6a: ", swatch2.duration(True))

        if 'duB' in kwargs:
            assembleNeumannBC(S,
                              parseArgToBoundaries(kwargs['duB'], mesh),
                              time=0.0,
                              userData=userData)

        if debug:
            print("6b: ", swatch2.duration(True))
        if 'uB' in kwargs:
            assembleDirichletBC(S,
                                parseArgToBoundaries(kwargs['uB'], mesh),
                                rhs,
                                time=0.0,
                                userData=userData)

        if 'uN' in kwargs:
            assembleDirichletBC(S, [],
                                nodePairs=kwargs['uN'],
                                rhs=rhs,
                                time=0.0,
                                userData=userData)

        if debug:
            print("6c: ", swatch2.duration(True))

        # create result array

        u = kwargs.pop('ret', None)

        singleForce = True
        if hasattr(rhs, 'ndim'):
            if rhs.ndim == 2:
                singleForce = False
                if u is None:
                    u = np.zeros(rhs.shape)
        else:
            if isinstance(a[0], complex):
                if u is None:
                    u = pg.CVector(rhs.size(), 0.0)
                rhs = pg.toComplex(rhs)
            else:
                if u is None:
                    u = pg.RVector(rhs.size(), 0.0)

        assembleTime = swatch.duration(True)
        if stats:
            stats.assembleTime = assembleTime

        if verbose:
            print(("Asssemblation time: ", assembleTime))

        # showSparseMatrix(S)

        solver = pg.LinSolver(False)
        solver.setMatrix(S, 0)

        if singleForce:
            u = solver.solve(rhs)
        else:
            for i, r in enumerate(rhs):
                solver.solve(r, u[i])

        solverTime = swatch.duration(True)
        if verbose:
            if stats:
                stats.solverTime = solverTime
            print(("Solving time: ", solverTime))

        return u

    else:
        if debug:
            print("start TL", swatch.duration())

        M = createMassMatrix(mesh)
        F = assembleForceVector(mesh, f)

        if 'u0' in kwargs:
            u0 = parseArgToArray(kwargs['u0'], dof, mesh, userData)

        theta = kwargs.pop('theta', 1)

        if 'duB' not in kwargs:
            A = createStiffnessMatrix(mesh, a)

            if 'uB' in kwargs:
                assembleDirichletBC(A,
                                    parseArgToBoundaries(kwargs['uB'], mesh),
                                    rhs=F)

            if 'uN' in kwargs:
                assembleDirichletBC(A, [], nodePairs=kwargs['uN'], rhs=F)

            return crankNicolson(times, theta, A, M, F, u0=u0, verbose=verbose)

        rhs = np.zeros((len(times), dof))
        # rhs kann zeitabhängig sein ..wird hier nicht berücksichtigt
        rhs[:] = F  # this is slow: optimize

        if debug:
            print("rhs", swatch.duration())
        U = np.zeros((len(times), dof))
        U[0, :] = u0

        # init state
        u = pg.RVector(dof, 0.0)

        if debug:
            print("u0", swatch.duration())

        measure = 0.
        for n in range(1, len(times)):
            swatch.reset()

            dt = times[n] - times[n - 1]

            # previous timestep
            # print "i: ", i, dt, U[i - 1]

            if 'duB' in kwargs:
                # aufschreiben und checken ob neumann auf A oder auf S mit
                # skaliertem val*dt angewendet wird
                A = createStiffnessMatrix(mesh, a)
                assembleNeumannBC(A,
                                  parseArgToBoundaries(kwargs['duB'], mesh),
                                  time=times[n],
                                  userData=userData)

            swatch.reset()
            # (A + a*B)u is fastest,
            # followed by A*u + (B*u)*a and finally A*u + a*B*u and
            b = (M + (dt * (theta - 1.)) * A) * U[n - 1] + \
                dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])

            # print ('a',swatch.duration(True))
            # b = M * U[n - 1] - (A * U[n - 1]) * (dt*(1.0 - theta)) + \
            # dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])

            # print ('b',swatch.duration(True))

            # b = M * U[n - 1] - (dt*(1.0 - theta)) * A * U[n - 1] + \
            # dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
            # print ('c',swatch.duration(True))

            measure += swatch.duration()

            S = M + A * dt * theta

            if 'uB' in kwargs:
                assembleDirichletBC(S,
                                    parseArgToBoundaries(kwargs['uB'], mesh),
                                    rhs=b,
                                    time=times[n],
                                    userData=userData)

            if 'uN' in kwargs:
                assembleDirichletBC(S, [],
                                    nodePairs=kwargs['uN'],
                                    rhs=b,
                                    time=times[n],
                                    userData=userData)

            # u = S/b
            t_prep = swatch.duration(True)
            solver = pg.LinSolver(S, verbose)
            solver.solve(b, u)

            if 'plotTimeStep' in kwargs:
                kwargs['plotTimeStep'](u, times[n])

            U[n, :] = np.asarray(u)

            if 'progress' in kwargs:
                if kwargs['progress']:
                    print(("\t" + str(n) + "/" + str(len(times) - 1) + ": " +
                           str(t_prep) + "/" + str(swatch.duration())))

        if debug:
            print("Measure(" + str(len(times)) + "): ", measure,
                  measure / len(times))
        return U
예제 #6
0
파일: solver.py 프로젝트: wk1984/gimli
def solvePoisson(mesh, a=1.0, b=0.0, f=0.0, times=None, userData=None,
                 verbose=False, stats=None, *args, **kwargs):
    """
    TODO
    
    The value of :math:`\omega` is larger than 5.

    Variable names are displayed in typewriter font, obtained by using \\mathtt{var}:

    We square the input parameter `a` to obtain
    :math:`\mathtt{alpha}^2`.
    

    Parameters
    ----------
    
    a   : value | array | callable(cell, userData)
        Cell values
    b   : value | array | callable(cell, userData)
        Cell values
    u0      : value | array | callable(pos, userData)
        Node values
    f       : value | array(cells) | array(nodes) | callable(args, kwargs)
        force values 
    theta   : float
        - `theta` = 0, explicit Euler, maybe stable for
        - `theta` = 0.5, Crank-Nicolsen, maybe instable 
        - `theta` = 1, implicit Euler

        .. math:: \\Delta t \\quad\\text{near}\\quad h

        Time dependent equation is stable for:
        .. math:: 0.5 <= \\theta <= 1.0
        
        If unsure choose 0.5 + epsilon, which is probably be stable.
    
    progress : bool
        Give some calculation progress.

    Returns
    -------
    
    u : array
        Returns the solution u either 1,n array for stationary problems or 
        for m,n array for m time steps
        
    See Also
    --------
        
    other solver TODO
    
    """
    if verbose:
        print(("Mesh: ", str(mesh)))

    dof = mesh.nodeCount()
        
    swatch = pg.Stopwatch(True)
    swatch2 = pg.Stopwatch(True)
    
    # check for material parameter
    a = parseArgToArray(a, mesh.cellCount(), mesh, userData)
    b = parseArgToArray(b, mesh.cellCount(), mesh, userData)
        
    print("2: ", swatch2.duration(True))
    # assemble the stiffness matrix
    A = createStiffnessMatrix(mesh, a)
    
    print("3: ", swatch2.duration(True))
    M = createMassMatrix(mesh, b)
        
    print("4: ", swatch2.duration(True))
    S = A + M
    
    print("5: ", swatch2.duration(True))
    if times == None:
        
        rhs = assembleForceVector(mesh, f, userData=userData)
        
        print("6a: ", swatch2.duration(True))
        if 'duBoundary' in kwargs:
            assembleBoundaryConditions(mesh, S, rhs, kwargs['duBoundary'], 
                                       assembleNeumannBC,
                                       userData=userData, 
                                       verbose=verbose)

        print("6b: ", swatch2.duration(True))
        if 'uBoundary' in kwargs:
            assembleBoundaryConditions(mesh, S, rhs, kwargs['uBoundary'],
                                       assembleDirichletBC, 
                                       userData=userData,
                                       verbose=verbose)

        print("6c: ", swatch2.duration(True))
        if 'uDirichlet' in kwargs:
            assembleUDirichlet_(S, rhs,
                                kwargs['uDirichlet'][0],
                                kwargs['uDirichlet'][1])
            
        u = None    
        if type(a[0]) is float:
            u = pg.RVector(rhs.size(), 0.0)
        else:
            u = pg.CVector(rhs.size(), 0.0)
            rhs = pg.toComplex(rhs)
            
        print("7: ", swatch2.duration(True))
        
        assembleTime = swatch.duration(True)
        if stats:
            stats.assembleTime = assembleTime
                
        if verbose:
            print(("Asssemblation time: ", assembleTime))

        #showSparseMatrix(S)
        
        solver = pg.LinSolver(1)
        solver.setMatrix(S, 0)
        u = solver.solve(rhs)
        
        solverTime = swatch.duration(True)
        if verbose:
            if stats:
                stats.solverTime = solverTime
            print(("Solving time: ", solverTime))
            
        return u
        
    else:
        print("start TL", swatch.duration())
        M = createMassMatrix(mesh, pg.RVector(mesh.cellCount(), 1.0))

        rhs = np.zeros((len(times), dof))
        # rhs kann zeitabhängig sein ..wird hier nicht berücksichtigt
        rhs[:] = assembleForceVector(mesh, f) # this is slow: optimize
        
        print("rhs", swatch.duration())
        U = np.zeros((len(times), dof))
        #init state
        u = pg.RVector(dof, 0.0)
        
        if 'u0' in kwargs:
            U[0, :] = parseArgToArray(kwargs['u0'], dof, mesh, userData)
            
        theta = 1.0
        if 'theta' in kwargs:
             theta = float(kwargs['theta'])
             
        print("u0", swatch.duration())
             
        measure = 0.
        for n in range(1, len(times)):
            swatch.reset()
            
            dt = times[n] - times[n - 1]
            
            #u[n] = u[n-1] + dt * theta * L(u[n]) + dt * (1-theta) * L(u[n-1])
            
            
            
            # previous timestep
            #print "i: ", i, dt, U[i - 1]
            
            if 'duBoundary' in kwargs:
                # aufschreiben und checken ob neumann auf A oder auf S mit skaliertem val*dt angewendet wird
                A = createStiffnessMatrix(mesh, a)
                assembleBoundaryConditions(mesh, A, None, kwargs['duBoundary'],
                                           assembleNeumannBC,
                                           time=times[n],
                                           verbose=verbose)

            swatch.reset()
            # (A + a*B)u is fastest, followed by A*u + (B*u)*a and finally A*u + a*B*u and 
            b = (M - (dt*(1.0 - theta)) * A) * U[n - 1] + \
                dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
                       
            #print ('a',swatch.duration(True))
            #b = M * U[n - 1] - (A * U[n - 1]) * (dt*(1.0 - theta)) + \
                #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
            
            #print ('b',swatch.duration(True))
            
            #b = M * U[n - 1] - (dt*(1.0 - theta)) * A * U[n - 1] + \
                #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
            #print ('c',swatch.duration(True))
                        
            measure += swatch.duration()
            
            S = M + A * dt * theta
                
            if 'uBoundary' in kwargs:
                assembleBoundaryConditions(mesh, S, b, kwargs['uBoundary'], 
                                           assembleDirichletBC,
                                           time=times[n],
                                           verbose=verbose)
                
            #u = S/b
            t_prep = swatch.duration(True)
            solver = pg.LinSolver(S, verbose)
            solver.solve(b, u)
            
            if 'plotTimeStep' in kwargs:
                kwargs['plotTimeStep'](u, times[n])
                    
            U[n,:] = np.asarray(u)

            if 'progress' in kwargs:
                if kwargs['progress']:
                    print(("\t" + str(n) +"/" + str(len(times)-1) + 
                          ": " + str(t_prep) +"/" + str(swatch.duration())))
        print( "Measure("+str(len(times))+"): ", measure, measure/len(times))
        return U
# def solvePoisson(..):