コード例 #1
0
    def test(self, test_solution):
        """Test that the boundary value problem definition is self consistent, and
        tests whether test_solution is consistent with the bvp definition.
        This requires some legal values for the parameters and thus requires a test solution.
        
        Parameters
        ----------
        test_solution : :class:`Solution`
            solution to be tested with
        """

        if self._num_parameters > 0:
            tools.argShapeTest(test_solution.parameters, (self._num_parameters,),
                               "parameter array",
                               "Should be (num_parameters,)")

        tools.argShapeTest(test_solution.solution, (self._num_ODE,len(test_solution.mesh)),
                               "solution array",
                               "Should be (num_ODE,length(mesh))")

        if not (self._boundary_points.shape == (2,)):
            raise ValueError("This boundary value problem definition must be given exactly two boundary points, but got: "
                              + self._boundary_points +" as the boundary values")

        #at this point we want to check the call backs to make sure they take the right arguments and return the right things
        if self._num_parameters ==0:
            f = self._function(test_solution.mesh[0],
                         test_solution.solution[:,0])

            tools.argShapeTest(f, (self._num_ODE,),
                               "function callback return",
                               "Should be (num_ODE,)")

            bca,bcb = self._boundary_conditions(test_solution.solution[:,0],
                                     test_solution.solution[:,-1])

            tools.argShapeTest(bca, (self._num_left_boundary_conditions,),
                               "Boundary conditions callback first return",
                               "Should be (num_left_boundary_conditions,)")

            tools.argShapeTest(bcb, (self._num_ODE + self._num_parameters - self._num_left_boundary_conditions,),
                               "Boundary conditions callback second return",
                               "Should be (num_ODE + num_parameters - num_left_boundary_conditions,)")

            if self.has_function_derivative:
                df = self._function_derivative(test_solution.mesh[0],
                                         test_solution.solution[:,0])

                tools.argShapeTest(df, (self._num_ODE, self._num_ODE),
                                   "function derivative callback first return",
                                   "Should be (num_ODE, num_ODE)")

            if self.has_boundary_conditions_derivative:
                dbca, dbcb = self._boundary_conditions_derivative(test_solution.solution[:,0],
                                                            test_solution.solution[:,0])

                tools.argShapeTest(dbca, (self._num_left_boundary_conditions, self._num_ODE),
                                   "Boundary conditions derivative callback first return",
                                   "Should be (num_left_boundary_conditions, num_ODE)")

                tools.argShapeTest(dbcb, (self._num_ODE + self._num_parameters - self._num_left_boundary_conditions, self._num_ODE),
                                   "Boundary conditions derivative callback second return",
                                   "Should be (num_ODE + num_parameters - num_left_boundary_conditions, num_ODE)")

        else: ## if unknown parameters are used, things should be a little different
            f = self._functionp(test_solution.mesh[0],
                         test_solution.solution[:,0],
                         test_solution.parameters)

            tools.argShapeTest(f, (self._num_ODE,),
                               "function callback return",
                               "Should be (num_ODE,)")

            bca, bcb = self._boundary_conditionsp(test_solution.solution[:,0],
                                     test_solution.solution[:,0],
                                     test_solution.parameters)

            tools.argShapeTest(bca, (self._num_left_boundary_conditions,),
                               "Boundary conditions callback first return",
                               "Should be (num_left_boundary_conditions,)")

            tools.argShapeTest(bcb, (self._num_ODE + self._num_parameters - self._num_left_boundary_conditions,),
                               "Boundary conditions callback second return",
                               "Should be (num_ODE + num_parameters - num_left_boundary_conditions,)")

            if self.has_function_derivative:
                df, dfp = self._function_derivativep(test_solution.mesh[0],
                                         test_solution.solution[:,0],
                                         test_solution.parameters)

                tools.argShapeTest(df, (self._num_ODE, self._num_ODE),
                                   "function derivative callback first return",
                                   "Should be (num_ODE, num_ODE)")

                tools.argShapeTest(dfp, (self._num_ODE, self._num_parameters),
                                   "function derivative callback second return",
                                   "Should be (num_ODE ,num_parameters)")

            if self.has_boundary_conditions_derivative:
                dbca, dbcb, dbcap, dbcbp = self._boundary_conditions_derivativep(test_solution.solution[:,0],
                                                            test_solution.solution[:,0],
                                                            test_solution.parameters)

                tools.argShapeTest(dbca, (self._num_left_boundary_conditions, self._num_ODE),
                             "boundary conditions derivative callback first return",
                             "Should be (num_left_boundary_conditions, num_ODE)")

                tools.argShapeTest(dbcb, (self._num_ODE + self._num_parameters - self._num_left_boundary_conditions, self._num_ODE),
                             "boundary conditions derivative callback second return",
                             "Should be (num_ODE + num_parameters - num_left_boundary_conditions, num_ODE)")

                tools.argShapeTest(dbcap, (self._num_left_boundary_conditions, self._num_parameters),
                             "boundary conditions derivative callback third return",
                             "Should be (num_left_boundary_conditions, num_parameters)")

                tools.argShapeTest(dbcbp, (self._num_ODE + self._num_parameters - self._num_left_boundary_conditions, self._num_parameters),
                             "boundary conditions derivative callback fourth return",
                             "Should be (num_ODE + num_parameters - num_left_boundary_conditions, num_ODE, num_parameters)")

        # test derivatives
        step = 1e-8
        places = 4

        # chose the point near the middle of the test_solution to check the derivatives
        middlePoint = numpy.round(test_solution.mesh.size * .61, 0)


        if self.has_function_derivative:
            if self._num_parameters > 0:

                func_derivative_calc, func_param_derivative_calc = self._function_derivativep(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint], test_solution.parameters)
                func_derivative_num = numpy.zeros((self._num_ODE,self._num_ODE))
                func_param_derivative_num = numpy.zeros( (self._num_ODE, self._num_parameters))



                for i in range(self._num_ODE):
                    delta = numpy.zeros(self._num_ODE)
                    delta[i] += step

                    point1 = self._functionp(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint], test_solution.parameters)
                    point2 = self._functionp(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint] + delta, test_solution.parameters)

                    func_derivative_num[:, i] = (point2 - point1)/step

                for i in range(self._num_parameters):
                    delta = numpy.zeros(self._num_parameters)
                    delta[i] += step

                    point1 = self._functionp(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint], test_solution.parameters)
                    point2 = self._functionp(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint], test_solution.parameters + delta)

                    func_param_derivative_num[:, i] = (point2 - point1)/step

                # now compare the actual derivatives with the calculated ones

                difference = func_derivative_calc - func_derivative_num
                if not (numpy.round(difference, places) == 0).all():
                    raise ValueError("analytical derivative matrix does not match numerical derivative matrix.\n Analytical is:\n" + str(func_derivative_calc)
                                     + "\n Numerical is:\n" + str(func_derivative_num))

                parameterDifference = func_param_derivative_calc - func_param_derivative_num
                if not (numpy.round(parameterDifference, places) == 0).all():
                    raise ValueError("analytical derivative (with respect to parameters) matrix does not match numerical derivative matrix.\n Analytical is:\n" + str(func_param_derivative_calc)
                                     + "\n Numerical is:\n" + str(func_param_derivative_num))
            else:

                func_derivative_calc = self._function_derivative(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint])
                func_derivative_num = numpy.zeros((self._num_ODE,self._num_ODE))

                for i in range(self._num_ODE):
                    delta = numpy.zeros(self._num_ODE)
                    delta[i] += step

                    point1 = self._function(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint])
                    point2 = self._function(test_solution.mesh[middlePoint], test_solution.solution[:, middlePoint] + delta)

                    func_derivative_num[:, i] = (point2 - point1)/step

                # now compare the actual derivatives with the calculated ones
                difference = func_derivative_calc - func_derivative_num
                if not (numpy.round(difference, places) == 0).all():
                    raise ValueError("analytical derivative matrix does not match numerical derivative matrix.\n Analytical is:\n" + str(func_derivative_calc)
                                     + "\n Numerical is:\n" + str(func_derivative_num))

            if self.has_boundary_conditions_derivative:

                endPoint = test_solution.mesh.size - 1

                if self._num_parameters > 0:

                    bcA_derivative_calc,bcB_derivative_calc, bcA_param_derivative_calc, bcB_param_derivative_calc = self._boundary_conditions_derivativep(test_solution.solution[:, 0],
                                                                                                                                                        test_solution.solution[:,endPoint],
                                                                                                                                                        test_solution.parameters)

                    bcA_derivative_num = numpy.zeros((self._num_left_boundary_conditions, self._num_ODE))
                    bcB_derivative_num = numpy.zeros((self._num_ODE + self._num_parameters - self._num_left_boundary_conditions, self._num_ODE))
                    bcA_param_derivative_num = numpy.zeros((self._num_left_boundary_conditions, self._num_parameters))
                    bcB_param_derivative_num = numpy.zeros( (self._num_ODE + self._num_parameters - self._num_left_boundary_conditions, self._num_parameters))

                    # calculate analytic derivatives for
                    for i in range(self._num_ODE):
                        delta = numpy.zeros(self._num_ODE)
                        delta[i] += step

                        point1A, point1B = self._boundary_conditionsp(test_solution.solution[:, 0],test_solution.solution[:, endPoint], test_solution.parameters)
                        point2A, point2B = self._boundary_conditionsp(test_solution.solution[:, 0] + delta ,test_solution.solution[:, endPoint] + delta, test_solution.parameters)

                        bcA_derivative_num[:, i] = (point2A - point1A)/step
                        bcB_derivative_num[:, i] = (point2B - point1B)/step

                    for i in range(self._num_parameters):
                        delta = numpy.zeros(self._num_parameters)
                        delta[i] += step

                        point1A, point1B = self._boundary_conditionsp(test_solution.solution[:, 0],test_solution.solution[:, endPoint], test_solution.parameters)
                        point2A, point2B = self._boundary_conditionsp(test_solution.solution[:, 0] ,test_solution.solution[:, endPoint], test_solution.parameters + delta)

                        bcA_param_derivative_num[:, i] = (point2A - point1A)/step
                        bcB_param_derivative_num[:, i] = (point2B - point1B)/step

                    # now compare the actual derivatives with the calculated ones

                    if not  (numpy.round(bcA_derivative_calc - bcA_derivative_num, places) == 0).all():
                        raise ValueError("analytical derivative matrix for the left boundary condition does not match numerical derivative matrix.\n Analytical is:\n" + str(bcA_derivative_calc)
                                     + "\n Numerical is:\n" + str(bcA_derivative_num))

                    if not  (numpy.round(bcB_derivative_calc - bcB_derivative_num, places) == 0).all():
                        raise ValueError("analytical derivative matrix for the right boundary condition does not match numerical derivative matrix.\n Analytical is:\n" + str(bcB_derivative_calc)
                                     + "\n Numerical is:\n" + str(bcB_derivative_num))

                    if not  (numpy.round(bcA_param_derivative_calc - bcA_param_derivative_num, places) == 0).all():
                        raise ValueError("analytical derivative matrix (with respect to parameters) for the left boundary condition does not match numerical derivative matrix.\n Analytical is:\n" + str(bcA_param_derivative_calc)
                                     + "\n Numerical is:\n" + str(bcA_param_derivative_num))

                    if not  (numpy.round(bcB_param_derivative_calc - bcB_param_derivative_num, places) == 0).all():
                        raise ValueError("analytical derivative matrix (with respect to parameters) for the left boundary condition does not match numerical derivative matrix.\n Analytical is:\n" + str(bcB_param_derivative_calc)
                                     + "\n Numerical is:\n" + str(bcB_param_derivative_num))

                else:
                    bcA_derivative_calc,bcB_derivative_calc = self._boundary_conditions_derivative(test_solution.solution[:, 0],
                                                                                                   test_solution.solution[:,endPoint])

                    bcA_derivative_num = numpy.zeros((self._num_left_boundary_conditions, self._num_ODE))
                    bcB_derivative_num = numpy.zeros((self._num_ODE - self._num_left_boundary_conditions, self._num_ODE))

                    # calculate analytic derivatives for
                    for i in range(self._num_ODE):
                        delta = numpy.zeros(self._num_ODE)
                        delta[i] += step

                        point1A, point1B = self._boundary_conditions(test_solution.solution[:, 0],test_solution.solution[:, endPoint])
                        point2A, point2B = self._boundary_conditions(test_solution.solution[:, 0] + delta ,test_solution.solution[:, endPoint] + delta)

                        bcA_derivative_num[:, i] = (point2A - point1A)/step
                        bcB_derivative_num[:, i] = (point2B - point1B)/step

                    # now compare the actual derivatives with the calculated ones


                    if not  (numpy.round(bcA_derivative_calc - bcA_derivative_num, places) == 0).all():
                        raise ValueError("analytical derivative matrix for the left boundary condition does not match numerical derivative matrix.\n Analytical is:\n" + str(bcA_derivative_calc)
                                     + "\nNumerical is:\n" + str(bcA_derivative_num))

                    if not  (numpy.round(bcB_derivative_calc - bcB_derivative_num, places) == 0).all():
                        raise ValueError("analytical derivative matrix for the right boundary condition does not match numerical derivative matrix.\n Analytical is:\n" + str(bcB_derivative_calc)
                                     + "\nNumerical is:\n" + str(bcB_derivative_num))
コード例 #2
0
ファイル: solver.py プロジェクト: rschroll/scikits.bvp_solver
def solve(bvp_problem,
          solution_guess,
          initial_mesh = None,
          parameter_guess = None,
          max_subintervals = 300,
          singular_term = None,
          tolerance = 1.0e-6,
          method = 4,
          trace = 0,
          error_on_fail = True):
    """Attempts to solve the supplied boundary value problem starting from the user supplied guess for the solution using BVP_SOLVER.

    Parameters
    ----------
    bvp_problem : :class:`ProblemDefinition`
        Defines the boundary value problem to be solved.
    solution_guess : :class:`Solution`, constant, array of values or function
        A guess for the solution.
    initial_mesh : castable to floating point ndarray
        Points on the x-axis to use for the supplied solution guess, default is 10 evenly spaced points. Must not be supplied if solution_guess is a :class:`Solution` object.
    parameter_guess : castable to floating point ndarray, shape (num_parameters)
        Guesses for the unknown parameters. Must not be supplied if solution_guess is a :class:`Solution` object.
    max_subintervals : int
        Maximum number of points on the mesh before an error is returned.
    singular_term : castable to floating point ndarray, shape(num_ODE, num_ODE)
        Matrix that defines the singular term for the problem if one exist.
    tolerance : positive float
        Tolerance for size of defect of approximate solution.
    method : {2, 4, 6}
        Order of Runge-Kutta to use.
    trace : {0, 1, 2}
        Indicates verbosity of output. 0 for no output, 1 for some output, 2 for full output.
    error_on_fail : logical
        Indicates whether an exception should be raised if solving fails.

    Returns
    -------
    sol : :class:`Solution`
        Approximate problem solution.

    Raises
    ------
    ValueError
        If bvp_problem failed validation in some way.
    ValueError
        If solving fails.
    """

    init_solution = 0

    if isinstance(solution_guess, Solution):
        if not (initial_mesh == None and
                parameter_guess == None):
            raise ValueError("values for initial mesh and parameter_guess must not be given if solution_guess is a Solution object")
        init_solution = solution_guess
    else:

        if initial_mesh == None:
            initial_mesh = numpy.linspace(bvp_problem.boundary_points[0],bvp_problem.boundary_points[1] , 10)

        # here we call one of the BVP_GUESS_i routines that make up BVP_INIT to set up the solution
        if ( not callable(solution_guess)):   # in this case the initial solution passed was not a function

            #try to cast the solution to an array
            solution_guess = numpy.array(solution_guess)

            # if the solution_guess is just an array the size of ODE
            if solution_guess.shape == (bvp_problem.num_ODE,) or (solution_guess.shape == () and bvp_problem.num_ODE == 1):

                bvp_solverf.bvp.guess_1_wrap(nparam_in = bvp_problem.num_parameters,
                                           leftbc_in = bvp_problem.num_left_boundary_conditions,
                                           x_in = tools.farg(initial_mesh),
                                           y_in = tools.farg(solution_guess),
                                           parameters_in = tools.farg(parameter_guess),
                                           mxnsub_in = max_subintervals,
                                           node_in = bvp_problem.num_ODE)

                init_solution = Solution.from_arg_list(bvp_solverf.bvp)

            else:

                tools.argShapeTest(solution_guess, (bvp_problem.num_ODE,initial_mesh.shape[0]), "solution guess")

                bvp_solverf.bvp.guess_2_wrap(nparam_in = bvp_problem.num_parameters,
                                             leftbc_in = bvp_problem.num_left_boundary_conditions,
                                             x_in = tools.farg(initial_mesh),
                                             y_in = tools.farg(solution_guess),
                                             parameters_in = tools.farg(parameter_guess),
                                             mxnsub_in = max_subintervals,
                                             node_in = bvp_problem.num_ODE)
                init_solution = Solution.from_arg_list(bvp_solverf.bvp)

        else:

            bvp_solverf.bvp.guess_3_wrap(node_in = bvp_problem.num_ODE,
                                           nparam_in = bvp_problem.num_parameters,
                                           leftbc_in = bvp_problem.num_left_boundary_conditions,
                                           x_in= tools.farg(initial_mesh),
                                           fcn = solution_guess,
                                           parameters_in = tools.farg(parameter_guess),
                                           mxnsub_in = max_subintervals)

            init_solution = Solution.from_arg_list(bvp_solverf.bvp)


    if not (method == 2 or method == 4 or method == 6 ):
        raise ValueError ("method must be either 2, 4 or 6 but got " + str(method) )

    if (tolerance < 0):
        raise ValueError("tolerance must be nonnegative")

    singular = not (singular_term is None)

    # check to see if the singular term is of the right size
    singular_term = tools.preparg(singular_term)
    if singular and not (singular_term.shape == (bvp_problem.num_ODE, bvp_problem.num_ODE)):
        raise ValueError("singular_term has the wrong shape/size. Expected: " +
                         (bvp_problem.num_ODE, bvp_problem.num_ODE)+
                         " but got :" +
                          singular_term.shape)

    # test the problem specifications with the initial solution
    bvp_problem.test(init_solution)
                                    
                                
                    
    bvp_solverf.bvp.bvp_solver_wrap(node_in = bvp_problem.num_ODE,
                                    npar_in = bvp_problem.num_parameters,
                                    leftbc_in = bvp_problem.num_left_boundary_conditions,
                                    npts_in = len(init_solution.mesh),
                                    info_in = init_solution.successIndicator,
                                    mxnsub_in = max_subintervals,
                                    x_in = tools.farg(init_solution.mesh),
                                    y_in = tools.farg(init_solution.solution),
                                    parameters_in = tools.farg(init_solution.parameters),
                                    work_in = tools.farg(init_solution.work),
                                    iwork_in = tools.farg(init_solution.iwork),
                                    fsub = bvp_problem._function,
                                    fsubp = bvp_problem._functionp,
                                    bcsub = bvp_problem._boundary_conditions,
                                    bcsubp = bvp_problem._boundary_conditionsp,

                                    singular = singular,

                                    hasdfdy = bvp_problem.has_function_derivative,
                                    dfdy = bvp_problem._function_derivative,
                                    dfdyp = bvp_problem._function_derivativep,

                                    hasdbcdy = bvp_problem.has_boundary_conditions_derivative,
                                    dbcdy = bvp_problem._boundary_conditions_derivative,
                                    dbcdyp = bvp_problem._boundary_conditions_derivativep,
                                    #optional arguments
                                    method = method,
                                    tol = tolerance,

                                    trace = trace,
                                    # we never want the actual program to shut down from the fortran side, we should throw an error
                                    stop_on_fail = False,

                                    singularterm = tools.farg(singular_term))

    calculatedSolution = Solution.from_arg_list(bvp_solverf.bvp)

    # check to see if there was a problem with the solution
    if error_on_fail and calculatedSolution._successIndicator == -1:
        raise ValueError("Boundary value problem solving failed. Run with trace = 1 or 2 for more information.")

    return calculatedSolution
コード例 #3
0
def solve(bvp_problem,
          solution_guess,
          initial_mesh = None,
          parameter_guess = None,
          max_subintervals = 300,
          singular_term = None,
          tolerance = 1.0e-6,
          method = 4,
          trace = 0,
          error_on_fail = True):
    """Attempts to solve the supplied boundary value problem starting from the user supplied guess for the solution using BVP_SOLVER.

    Parameters
    ----------
    bvp_problem : :class:`ProblemDefinition`
        Defines the boundary value problem to be solved.
    solution_guess : :class:`Solution`, constant, array of values or function
        A guess for the solution.
    initial_mesh : castable to floating point ndarray
        Points on the x-axis to use for the supplied solution guess, default is 10 evenly spaced points. Must not be supplied if solution_guess is a :class:`Solution` object.
    parameter_guess : castable to floating point ndarray, shape (num_parameters)
        Guesses for the unknown parameters. Must not be supplied if solution_guess is a :class:`Solution` object.
    max_subintervals : int
        Maximum number of points on the mesh before an error is returned.
    singular_term : castable to floating point ndarray, shape(num_ODE, num_ODE)
        Matrix that defines the singular term for the problem if one exist.
    tolerance : positive float
        Tolerance for size of defect of approximate solution.
    method : {2, 4, 6}
        Order of Runge-Kutta to use.
    trace : {0, 1, 2}
        Indicates verbosity of output. 0 for no output, 1 for some output, 2 for full output.
    error_on_fail : logical
        Indicates whether an exception should be raised if solving fails.

    Returns
    -------
    sol : :class:`Solution`
        Approximate problem solution.

    Raises
    ------
    ValueError
        If bvp_problem failed validation in some way.
    ValueError
        If solving fails.
    """

    init_solution = 0

    if isinstance(solution_guess, Solution):
        if not (initial_mesh == None and
                parameter_guess == None):
            raise ValueError("values for initial mesh and parameter_guess must not be given if solution_guess is a Solution object")
        init_solution = solution_guess
    else:

        if initial_mesh == None:
            initial_mesh = numpy.linspace(bvp_problem.boundary_points[0],bvp_problem.boundary_points[1] , 10)

        # here we call one of the BVP_GUESS_i routines that make up BVP_INIT to set up the solution
        if ( not callable(solution_guess)):   # in this case the initial solution passed was not a function

            #try to cast the solution to an array
            solution_guess = numpy.array(solution_guess)

            # if the solution_guess is just an array the size of ODE
            if solution_guess.shape == (bvp_problem.num_ODE,) or (solution_guess.shape == () and bvp_problem.num_ODE == 1):

                bvp_solverf.bvp.guess_1_wrap(nparam_in = bvp_problem.num_parameters,
                                           leftbc_in = bvp_problem.num_left_boundary_conditions,
                                           x_in = tools.farg(initial_mesh),
                                           y_in = tools.farg(solution_guess),
                                           parameters_in = tools.farg(parameter_guess),
                                           mxnsub_in = max_subintervals,
                                           node_in = bvp_problem.num_ODE)

                init_solution = Solution.from_arg_list(bvp_solverf.bvp)

            else:

                tools.argShapeTest(solution_guess, (bvp_problem.num_ODE,initial_mesh.shape[0]), "solution guess")

                bvp_solverf.bvp.guess_2_wrap(nparam_in = bvp_problem.num_parameters,
                                             leftbc_in = bvp_problem.num_left_boundary_conditions,
                                             x_in = tools.farg(initial_mesh),
                                             y_in = tools.farg(solution_guess),
                                             parameters_in = tools.farg(parameter_guess),
                                             mxnsub_in = max_subintervals,
                                             node_in = bvp_problem.num_ODE)
                init_solution = Solution.from_arg_list(bvp_solverf.bvp)

        else:
            y_in = numpy.zeros((bvp_problem.num_ODE,1))

            bvp_solverf.bvp.guess_1_wrap(nparam_in = bvp_problem.num_parameters,
                                           leftbc_in = bvp_problem.num_left_boundary_conditions,
                                           x_in = tools.farg(initial_mesh),
                                           y_in = y_in,
                                           parameters_in = tools.farg(parameter_guess),
                                           mxnsub_in = max_subintervals,
                                           node_in = bvp_problem.num_ODE)

            init_solution = Solution.from_arg_list(bvp_solverf.bvp)
            for i,v in enumerate(init_solution._mesh):
                init_solution._solution[:, i] = solution_guess(v)


    if not (method == 2 or method == 4 or method == 6 ):
        raise ValueError ("method must be either 2, 4 or 6 but got " + str(method) )

    if (tolerance < 0):
        raise ValueError("tolerance must be nonnegative")

    singular = not (singular_term is None)

    # check to see if the singular term is of the right size
    singular_term = tools.preparg(singular_term)
    if singular and not (singular_term.shape == (bvp_problem.num_ODE, bvp_problem.num_ODE)):
        raise ValueError("singular_term has the wrong shape/size. Expected: " +
                         (bvp_problem.num_ODE, bvp_problem.num_ODE)+
                         " but got :" +
                          singular_term.shape)

    # test the problem specifications with the initial solution
    bvp_problem.test(init_solution)
                                    
                                
                    
    bvp_solverf.bvp.bvp_solver_wrap(node_in = bvp_problem.num_ODE,
                                    npar_in = bvp_problem.num_parameters,
                                    leftbc_in = bvp_problem.num_left_boundary_conditions,
                                    npts_in = len(init_solution.mesh),
                                    info_in = init_solution.successIndicator,
                                    mxnsub_in = max_subintervals,
                                    x_in = tools.farg(init_solution.mesh),
                                    y_in = tools.farg(init_solution.solution),
                                    parameters_in = tools.farg(init_solution.parameters),
                                    work_in = tools.farg(init_solution.work),
                                    iwork_in = tools.farg(init_solution.iwork),
                                    fsub = bvp_problem._function,
                                    fsubp = bvp_problem._functionp,
                                    bcsub = bvp_problem._boundary_conditions,
                                    bcsubp = bvp_problem._boundary_conditionsp,

                                    singular = singular,

                                    hasdfdy = bvp_problem.has_function_derivative,
                                    dfdy = bvp_problem._function_derivative,
                                    dfdyp = bvp_problem._function_derivativep,

                                    hasdbcdy = bvp_problem.has_boundary_conditions_derivative,
                                    dbcdy = bvp_problem._boundary_conditions_derivative,
                                    dbcdyp = bvp_problem._boundary_conditions_derivativep,
                                    #optional arguments
                                    method = method,
                                    tol = tolerance,

                                    trace = trace,
                                    # we never want the actual program to shut down from the fortran side, we should throw an error
                                    stop_on_fail = False,

                                    singularterm = tools.farg(singular_term))

    calculatedSolution = Solution.from_arg_list(bvp_solverf.bvp)

    # check to see if there was a problem with the solution
    if error_on_fail and calculatedSolution._successIndicator == -1:
        raise ValueError("Boundary value problem solving failed. Run with trace = 1 or 2 for more information.")

    return calculatedSolution