def solve_bvp_casadi(self):
        """
        Uses casadi's interface to sundials to solve the boundary value
        problem using a single-shooting method with automatic differen-
        tiation.
        
        Related to PCSJ code. 
        """

        self.bvpint = cs.Integrator('cvodes', self.modlT)
        self.bvpint.setOption('abstol', self.intoptions['bvp_abstol'])
        self.bvpint.setOption('reltol', self.intoptions['bvp_reltol'])
        self.bvpint.setOption('tf', 1)
        self.bvpint.setOption('disable_internal_warnings', True)
        self.bvpint.setOption('fsens_err_con', True)
        self.bvpint.init()

        # Vector of unknowns [y0, T]
        V = cs.MX.sym("V", self.neq + 1)
        y0 = V[:-1]
        T = V[-1]
        param = cs.vertcat([self.param, T])
        yf = self.bvpint.call(cs.integratorIn(x0=y0, p=param))[0]
        fout = self.modlT.call(cs.daeIn(t=T, x=y0, p=param))[0]

        # objective: continuity
        obj = (yf -
               y0)**2  # yf and y0 are the same ..i.e. 2 ends of periodic fcn
        obj.append(
            fout[0])  # y0 is a peak for state 0, i.e. fout[0] is slope state 0

        #set up the matrix we want to solve
        F = cs.MXFunction([V], [obj])
        F.init()
        guess = np.append(self.y0, self.T)
        solver = cs.ImplicitFunction('kinsol', F)
        solver.setOption('abstol', self.intoptions['bvp_ftol'])
        solver.setOption('strategy', 'linesearch')
        solver.setOption('exact_jacobian', False)
        solver.setOption('pretype', 'both')
        solver.setOption('use_preconditioner', True)
        if self.intoptions['constraints'] == 'positive':
            solver.setOption('constraints', (2, ) * (self.neq + 1))
        solver.setOption('linear_solver_type', 'dense')
        solver.init()
        solver.setInput(guess)
        solver.evaluate()

        sol = solver.output().toArray().squeeze()

        self.y0 = sol[:-1]
        self.T = sol[-1]
    def corestationary(self,guess=None,contstraints='positive'):
        """
        find stationary solutions that satisfy ydot = 0 for stability
        analysis.
        """
        guess=None
        if guess is None: guess = np.array(self.y0)
        else: guess = np.array(guess)
        y = self.model.inputExpr(cs.DAE_X)
        t = self.model.inputExpr(cs.DAE_T)
        p = self.model.inputExpr(cs.DAE_P)
        ode = self.model.outputExpr()
        fn = cs.SXFunction([y,t,p],ode)
        kfn = cs.ImplicitFunction('kinsol',fn)
        abstol = 1E-10
        kfn.setOption("abstol",abstol)
        if self.intoptions['constraints']=='positive':
            # constain using kinsol to >0, for physical
            kfn.setOption("constraints",(2,)*self.neq)
        kfn.setOption("linear_solver_type","dense")
        kfn.setOption("exact_jacobian",True)
        kfn.setOption("u_scale",(100/guess).tolist())
        kfn.setOption("disable_internal_warnings",True)
        kfn.init()
        kfn.setInput(self.param,2)
        kfn.setInput(guess)
        kfn.evaluate()
        y0out = kfn.output().toArray()

        if any(np.isnan(y0out)):
            raise RuntimeError("findstationary: KINSOL failed to find \
                               acceptable solution")

        self.ss = y0out.flatten()

        if np.linalg.norm(self.dydt(self.ss)) >= abstol or any(y0out <= 0):
            raise RuntimeError("findstationary: KINSOL failed to reach"+
                                " acceptable bounds")

        self.eigs = np.linalg.eigvals(self.dfdy(self.ss))