Dear all,

I was trying to reproduce /ts/examples/tutorials/ex4.c in python to learn how 
to use TS solvers; the example uses the function TSComputeRHSFunctionLinear.
However I get an error when running my code (attached in case you want to look 
at it), when I call ts.solve. 

Here is the trace:
[fcaimmi@Wotan 2645] > ./ts_ex4.py                                              
                                                      
Solving a linear TS problem, number of processors =  1
Timestep  0 : time = 0.0  2-norm error = 1.14956855594e-08  max norm error = 0
Traceback (most recent call last):
  File "./ts_ex4.py", line 473, in <module>
    main(m = m, debug = debug)
  File "./ts_ex4.py", line 340, in main
    ts.solve(u)
  File "PETSc/TS.pyx", line 568, in petsc4py.PETSc.TS.solve 
(src/petsc4py.PETSc.c:188927)
  File "PETSc/petscts.pxi", line 221, in petsc4py.PETSc.TS_RHSFunction 
(src/petsc4py.PETSc.c:35490)
  File "PETSc/TS.pyx", line 189, in petsc4py.PETSc.TS.computeRHSFunctionLinear 
(src/petsc4py.PETSc.c:181611)
TypeError: computeRHSFunctionLinear() takes exactly 3 positional arguments (5 
given)

I cannot understand if there is a problem with my code or if the problem is in 
computeRHSFunctionLinear interface.

 I checked https://bitbucket.org/petsc/petsc4py/ and the interface to 
computeRHSFunctionLinear  has three arguments, however I am not that much into 
petsc4py to tell how it gets called.

I am on Petsc Release Version 3.7.3

Thank you for your time.

Best,
-- 
Francesco Caimmi
 
Laboratorio di Ingegneria dei Polimeri
http://www.chem.polimi.it/polyenglab/

Politecnico di Milano - Dipartimento di Chimica,
Materiali e Ingegneria Chimica “Giulio Natta”

P.zza Leonardo da Vinci, 32
I-20133 Milano
Tel. +39.02.2399.4711
Fax +39.02.7063.8173

[email protected]
Skype: fmglcaimmi (please arrange meetings by e-mail)
#!/usr/bin/python
"""
NOT WORKING ATM

Python translation of /ts/examples/tutorials/ex4.c.
Comments mostly taken from there

This program solves the one-dimensional heat equation (also called the
diffusion equation),
       u_t = u_xx,
on the domain 0 <= x <= 1, with the boundary conditions
   u(t,0) = 0, u(t,1) = 0,
and the initial condition
   u(0,x) = sin(6*pi*x) + 3*sin(2*pi*x).
This is a linear, second-order, parabolic equation.

We discretize the right-hand side using finite differences with
uniform grid spacing h:
   u_xx = (u_{i+1} - 2u_{i} + u_{i-1})/(h^2)

We then demonstrate time evolution using the various TS methods by
running the program via
mpiexec -n <procs> ex3 -ts_type <timestepping solver>

   We compare the approximate solution with the exact solution, given by
   u_exact(x,t) = exp(-36*pi*pi*t) * sin(6*pi*x) +
      3*exp(-4*pi*pi*t) * sin(2*pi*x)

   Notes:
   This code demonstrates the TS solver interface to two variants of
   linear problems, u_t = f(u,t), namely
 - time-dependent f:   f(u,t) is a function of t
 - time-independent f: f(u,t) is simply f(u)

The uniprocessor version of this code is ts/examples/tutorials/ex3.c


"""

from __future__ import print_function
import numpy as np
import sys
import petsc4py
petsc4py.init(sys.argv)
from petsc4py import PETSc


class AppCtx:
    """
    Application context class to store user data at make them availbel to the
    functions registered with the TS solver

    Parameters
    ------------
    comm: mpi4py object
        a mpi4py communicatro object

    da: PETSc DA object
        a distributed array data structure

    localwork:PETSc Vec
        local ghosted workvector

    u_local: PETSc Vec
        local ghosted approximated solution vector

    solution: PETSc Vec
        global exact solution vector

    m: int
        total number of grid point

    h: float
        mesh width (1/m-1)

    debug: boolean
        flag for debug output

    viewer1: PETSc Viewer
        viewer for the solution

    viewer2: PETSc Viewer
        viewer for the error

    norm_2: float
        the 2-norm error

    norm_max: float
        the maxe-norm error
    """

    def __init__(self, comm, da, localwork, u_local,solution,m,h,debug,viewer1,
                 viewer2,norm_2=0, norm_max=0):

        self.comm = comm
        self.da = da
        self.localwork = localwork
        self.u_local = u_local
        self.solution = solution
        self.m = m
        self.h = h
        self.debug = debug
        self.viewer1 = viewer1
        self.viewer2 = viewer2
        self.norm_2 = norm_2
        self.norm_max = norm_max

def exactSolution(t, solution, mctx):
    """
    Compute the exact solution
    Parameters
    -----------
    t: float
        the current time
    u: PETSc Vec
        the current solution iteration

    mctx: AppCtx
        the monitor contest

    Returns
    --------
    0
    """
    h = mctx.h
    start, end = solution.getOwnershipRange()
    with solution as s:
        ex1 = np.exp(-36.0 * np.pi * t)
        ex2 = np.exp(-4.0 * np.pi * t)
        sc1 = np.pi*6.0*h
        sc2 = np.pi*2.0*h
        for i in range(start,end):
            j= i-start
            s[j] = ex1 * np.sin(sc1*j) + 3.0 * ex2 * np.sin(sc2*j)
    return 0

def initialConditions(U, ctx):
    """
    Sets the initial conditions in the solution vector u
    Parameters
    -----------
    U: PETSc Vec
        the solution vector
    ctx: AppCtx object
        the application context object

    Returns
    --------
    0
    """
    h = ctx.h
    start, end = U.getOwnershipRange()

    with U as u:
        for i in range(start, end):
            u[i-start] = np.sin(np.pi*i*6*h) + 3.0 * np.sin(np.pi*i*2*h)

    #Print debugging information if desired
    if ctx.debug:
        PETSc.Sys.Print("Computed solution vector:")
        U.view(PETSc.Viewer().STDOUT())

    return 0


def monitor(ts, step, time, u, mctx):
    """
    User defined monitor function

    Parameters
    -----------

    ts: PETSc TS
        the TS solver object
    step: intExact solution vector:
        the iteration number
    time: float
        the current time
    u: PETSc Vec
        the current solution iteration

    mctx: AppCtx
        the monitor contest

    """

    #View a graph of the current iterate
    mctx.viewer2.view(obj=u)
    #Compute the exact solution
    exactSolution(time,mctx.solution,mctx)
    #Print debugging information if desired
    if mctx.debug:
        PETSc.Sys.Print("Computed solution vector:")
        u.view(PETSc.Viewer().STDOUT())
        PETSc.Sys.Print("Exact solution vector:")
        mctx.solution.view(PETSc.Viewer().STDOUT())
    #Compute the 2-norm and max-norm of the error
    mctx.solution.axpy(-1.0,u)
    norm_2 = mctx.solution.norm(norm_type = PETSc.NormType.NORM_2)
    norm_2 = np.sqrt(mctx.h*norm_2)
    if norm_2   < 1e-14: norm_2 = 0
    norm_max = mctx.solution.norm(norm_type = PETSc.NormType.MAX)
    if norm_max   < 1e-14: norm_max = 0

    PETSc.Sys.Print("Timestep ",step,": time =", time, " 2-norm error =",
                    norm_2," max norm error =", norm_max)
    mctx.norm_2 += norm_2
    mctx.norm_max += norm_max
    #View a graph of the error:
    mctx.solution.view(mctx.viewer1)
    #Print debugging information if desired
    if mctx.debug:
        PETSc.Sys.Print("Error vector ")
        mctx.solution.view(PETSc.Viewer().STDOUT())

def main(m = 60, debug = False, nlflag = False, tdflag = False):
    """
    Main program routine

    Parameters
    -----------

    m: float, optional
        the number of grid points. Defaults to 60.

    debug: bool, optional
        whether or not to print debug output. Defaults to False

    nlflag: bool, optional
        whether or not set the problem as non linear. Defaults to False.

    tdflag: bool, optional
        flag telling if the RHS of the problem is time dependent. This changes
        the way the problem is defined
        Defaults to False.
    """
    #globals
    time_steps_max = 100
    time_total_max = 1.0
    comm = PETSc.COMM_WORLD.tompi4py()
    size = comm.size
    PETSc.Sys.Print("Solving a linear TS problem, number of processors = ",
                    size)

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Create vector data structures
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #
    #Create distributed array (DMDA) to manage parallel grid and vectors
    #and to set up the ghost point communication pattern.  There are M
    #total grid values spread equally among all the processors.
    da = PETSc.DMDA().create(dim=1,sizes=(m,),dof=1, stencil_width=1,
                    boundary_type=PETSc.DMDA.BoundaryType.NONE)

    #Extract global and local vectors from DMDA; we use these to store the
    #approximate solution.  Then duplicate these for remaining vectors that
    #have the same types.

    u = da.createGlobalVec()
    u_local = da.createLocalVec()
    #Create local work vector for use in evaluating right-hand-side function;
    #create global work vector for storing exact solution
    localwork = u_local.duplicate()
    solution = u.duplicate()
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Set up displays to show graphs of the solution and error
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    viewer1 = PETSc.Viewer().createDraw(comm = comm, title ="",
                                        position = (80,380), size=(400,160))
    viewer2 = PETSc.Viewer().createDraw(comm = comm, title ="",
                                        position = (80,0), size=(400,160))
    #create the application context
    appctx = AppCtx(comm, da, localwork, u_local, solution, m, 1.0/(m-1.0),
                    debug, viewer1, viewer2)
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Create timestepping solver context
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ts = PETSc.TS().create()
    if nlflag:
        ts.setProblemType(PETSc.TS.ProblemType.NONLINEAR)
    else:
        ts.setProblemType(PETSc.TS.ProblemType.LINEAR)
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Set optional user-defined monitoring routine
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ts.setMonitor(monitor,args = (appctx,))

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Create matrix data structure; set matrix evaluation routine.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    A = PETSc.Mat().createAIJ([m,m],comm = comm)
    A.setFromOptions()
    A.setUp()
    if tdflag:
        #time dependent
        #For linear problems with a time-dependent f(u,t) in the equation
        #u_t = f(u,t), the user provides the discretized right-hand-side
        #as a time-dependent matrix.
        ts.setRHSFunction(ts.computeRHSFunctionLinear, args=(appctx,))
        ts.setRHSJacobian(RHSMatrixHeat, J = A, P = A, args=(appctx,))
    else:
        #time independent
        #For linear problems with a time-independent f(u) in the equation
        #u_t = f(u), the user provides the discretized right-hand-side
        #as a matrix only once, and then sets a null matrix evaluation
        #routine.
        RHSMatrixHeat(ts,0.0,u,A,A,appctx)
        ts.setRHSFunction(ts.computeRHSFunctionLinear, args=(appctx,))
        ts.setRHSJacobian(ts.computeRHSJacobianConstant, J = A, P = A,
                          args = (appctx,))

    if nlflag:
        ts.setRHSFunction(RHSFunctionHeat, args = (appctx,))
        snes = ts.getSNES()
        #serve 'sta roba ddel jacobiano di defualt? snes
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Set solution vector and initial timestep
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    dt   = appctx.h*appctx.h/2.0
    ts.setInitialTimeStep(0.0,dt)
    ts.setSolution(u)
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Customize timestepping solver:
    #   - Set the solution method to be the Backward Euler method.
    #   - Set timestepping duration info
    #Then set runtime options, which can override these defaults.
    #For example,
    #      -ts_max_steps <maxsteps> -ts_final_time <maxtime>
    #to override the defaults set by TSSetDuration().
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ts.setDuration(time_total_max,time_steps_max)
    ts.setExactFinalTime(ts.ExactFinalTimeOption.STEPOVER)
    ts.setFromOptions()
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Solve the problem
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Evaluate initial conditions
    initialConditions(u,appctx)
    #Run the timestepping solver
    ts.solve(u)
    #get solution infos
    ftime = ts.getSolveTime()
    steps = ts.getStepNumber()
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #View the time stepping information
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    PETSc.Sys.Print("Total timesteps ",steps, "Final time ", ftime)
    PETSc.Sys.Print("Avg. error (2 norm) = ",appctx.norm_2,
                    "Avg. error (max norm) = ", appctx.norm_max)

def RHSFunctionHeat( ts,t,globalin, globalout,ctx):
    """
    The non linear case RHSFunction

    Parameters
    -----------
    ts: PETSc TS
        the TS solver object

    t: float
        current time

    globalin: PETSc Vec
        the input vector

    globalout: PETSc Vec
        the ouput vector

    ctx: AppCtx object
        the application context

    """
    A = ts.getRHSJacobian()
    RHSMatrixHeat(ts, t, globalin,A,None,appctx)
    A.matMult(globalin, result = globalout)
    return 0

#def RHSMatrixHeat(ts, t, X, AA, BB, strf, appctx):
def RHSMatrixHeat(ts, t, X, AA, BB, appctx):
    """
    User-provided routine to compute the right-hand-side matrix for the heat
    equation.

    Parameters
    -----------
    ts: PETSc TS
        the TS solver object

    t: float
        current time

    X: PETSc Vec
        the global input vector

    AA: PETSc Mat
        Jacobian matrix

    BB: PETSc Mat
        optionally different preconditioning matrix

    str:
        flag indicating matrix structure

    Returns
    --------
    0

    Notes
    --------
    RHSMatrixHeat computes entries for the locally owned part of the system.
    - Currently, all PETSc parallel matrix formats are partitioned by
     contiguous chunks of rows across the processors.
    - Each processor needs to insert only elements that it owns
     locally (but any non-local elements will be sent to the
     appropriate processor during matrix assembly).
    - Always specify global row and columns of matrix entries when
     using MatSetValues(); we could alternatively use MatSetValuesLocal().
    - Here, we set all entries for a particular row at once.
    - Note that MatSetValues() uses 0-based row and column numbers
     in Fortran as well as in C.
    """
    #variables
    stwo = -2.0/(appctx.h**2)
    sone = -0.5*stwo

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Compute entries for the locally owned part of the matrix
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    start, end = AA.getOwnershipRange()

    #Set matrix rows corresponding to boundary data
    if start ==0:#first processor only
        AA.setValue(start,start,1.0)
        start += 1
    if end == appctx.m:#last processor only
        end -= 1
        AA.setValue(end,end,1.0)

    #Set matrix rows corresponding to interior data.  We construct the
    #matrix one row at a time.
    v = np.array([sone, stwo, sone])
    idx = np.zeros_like(v, dtype='int32')
    for i in range(start,end):
        idx[0] = i-1
        idx[1] = 1
        idx[2] = i+1
        AA.setValues(i,idx,v)
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Complete the matrix assembly process and set some options
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    #Assemble matrix, using the 2-step process:
    #MatAssemblyBegin(), MatAssemblyEnd()
    #Computations can be done while messages are in transition
    #by placing code between these two statements.
    AA.assemblyBegin()
    AA.assemblyEnd()
    #Set and option to indicate that we will never add a new nonzero location
    #to the matrix. If we do, it will generate an error.
    AA.setOption(AA.Option.NEW_NONZERO_LOCATION_ERR,True)
    return 0

if __name__=="__main__":
    #PETSC options
    OptDB = PETSc.Options()#get PETSc option DB
    #set options, one can set them from the command line
    m = OptDB.getInt('M', 60)#grid dimensions
    nlflag = OptDB.getBool('-nonlinear', False)
    tdflag = OptDB.getBool("-time_dependent_rhs", False)
    if OptDB.hasName('debug')==0:
        debug = False
    else:
        debug = True
    main(m = m, debug = debug)

Reply via email to