def __init__(self, mesh, time, model, I_s=None, params=None):

        import ufl.classes

        # Store input
        self._mesh = mesh
        self._time = time
        self._model = model

        # Extract some information from cell model
        self._F = self._model.F
        self._I_ion = self._model.I
        self._num_states = self._model.num_states()

        self._I_s = handle_markerwise(I_s, GenericFunction)

        # Create time if not given, otherwise use given time
        if time is None:
            self._time = Constant(0.0)
        else:
            self._time = time

        # Initialize and update parameters if given
        self.parameters = self.default_parameters()
        if params is not None:
            self.parameters.update(params)

        # Create (vector) function space for potential + states
        self.VS = VectorFunctionSpace(self._mesh,
                                      "CG",
                                      1,
                                      dim=self._num_states + 1)

        # Initialize solution field
        self.vs_ = Function(self.VS, name="vs_")
        self.vs = Function(self.VS, name="vs")

        # Initialize scheme
        (v, s) = splat(self.vs, self._num_states + 1)
        (w, q) = splat(TestFunction(self.VS), self._num_states + 1)

        # Workaround to get algorithm in RL schemes working as it only
        # works for scalar expressions
        F_exprs = self._F(v, s, self._time)

        # MER: This looks much more complicated than it needs to be!
        # If we have a as_vector expression
        F_exprs_q = zero()
        if isinstance(F_exprs, ufl.classes.ListTensor):
            #for i, expr_i in enumerate(F_exprs.operands()):
            for i, expr_i in enumerate(F_exprs.ufl_operands):
                F_exprs_q += expr_i * q[i]
        else:
            F_exprs_q = F_exprs * q

        rhs = F_exprs_q - self._I_ion(v, s, self._time) * w

        # Handle stimulus: only handle single function case for now
        msg = "Markerwise stimulus not supported by PointIntegralSolver."
        assert (not isinstance(self._I_s, Markerwise)), msg
        if self._I_s:
            rhs += self._I_s * w

        # FIXME: The application of dP was moved so adding an integral
        # is done just once. Otherwise ufl could not figure out that
        # we had only one integral...
        self._rhs = rhs * dP()

        #sys.exit()
        name = self.parameters["scheme"]
        Scheme = self._name_to_scheme(name)
        self._scheme = Scheme(self._rhs, self.vs, self._time)

        # Figure out whether we should annotate or not
        self._annotate_kwargs = annotate_kwargs(self.parameters)

        # Initialize solver and update its parameters
        self._pi_solver = PointIntegralSolver(self._scheme)
        self._pi_solver.parameters.update(
            self.parameters["point_integral_solver"])
    def step(self, interval):
        """
        Solve on the given time step (t0, t1).

        End users are recommended to use solve instead.

        *Arguments*
          interval (:py:class:`tuple`)
            The time interval (t0, t1) for the step
        """

        timer = Timer("ODE step")

        # Check for cell meshs
        dim = self._mesh.topology().dim()

        # Extract time mesh
        (t0, t1) = interval
        k_n = Constant(t1 - t0)

        # Extract previous solution(s)
        (v_, s_) = splat(self.vs_, self._num_states + 1)

        # Set-up current variables
        self.vs.assign(self.vs_)  # Start with good guess
        (v, s) = splat(self.vs, self._num_states + 1)
        (w, r) = splat(TestFunction(self.VS), self._num_states + 1)

        # Define equation based on cell model
        Dt_v = (v - v_) / k_n
        Dt_s = (s - s_) / k_n

        theta = self.parameters["theta"]

        # Set time (propagates to time-dependent variables defined via
        # self.time)
        t = t0 + theta * (t1 - t0)
        self.time.assign(t)

        v_mid = theta * v + (1.0 - theta) * v_
        s_mid = theta * s + (1.0 - theta) * s_

        if isinstance(self._model, MultiCellModel):
            #assert(model.mesh() == self._mesh)

            model = self._model
            mesh = model.mesh()
            dy = Measure("dx", domain=mesh, subdomain_data=model.markers())

            # Only allowing trivial forcing functions here
            if isinstance(self._I_s, Markerwise):
                error("Not implemented")
            rhs = self._I_s * w * dy()

            n = model.num_states()  # Extract number of global states

            # Collect contributions to lhs by iterating over the different cell models
            domains = self._model.keys()
            lhs = list()
            for (k, model_k) in enumerate(model.models()):
                n_k = model_k.num_states(
                )  # Extract number of local (non-trivial) states

                # Extract right components of coefficients and test functions
                # () is not the same as (1,)
                if n_k == 1:
                    s_mid_k = s_mid[0]
                    r_k = r[0]
                    Dt_s_k = Dt_s[0]
                else:
                    s_mid_k = as_vector(tuple(s_mid[j] for j in range(n_k)))
                    r_k = as_vector(tuple(r[j] for j in range(n_k)))
                    Dt_s_k = as_vector(tuple(Dt_s[j] for j in range(n_k)))

                i_k = domains[k]  # Extract domain index of cell model k

                # Extract right currents and ion channel expressions
                F_theta_k = self._F(v_mid, s_mid_k, time=self.time, index=i_k)
                I_theta_k = -self._I_ion(
                    v_mid, s_mid_k, time=self.time, index=i_k)

                # Variational contribution over the relevant domain
                a_k = ((Dt_v - I_theta_k) * w + inner(Dt_s_k, r_k) +
                       inner(-F_theta_k, r_k)) * dy(i_k)

                # Add s_trivial = 0 on Omega_{i_k} in variational form:
                a_k += sum(s[j] * r[j] for j in range(n_k, n)) * dy(i_k)
                lhs.append(a_k)
            lhs = sum(lhs)

        else:
            (dz, rhs) = rhs_with_markerwise_field(self._I_s, self._mesh, w)

            # Evaluate currents at averaged v and s. Note sign for I_theta
            F_theta = self._F(v_mid, s_mid, time=self.time)
            I_theta = -self._I_ion(v_mid, s_mid, time=self.time)
            lhs = (Dt_v - I_theta) * w * dz + inner(Dt_s - F_theta, r) * dz

        # Set-up system of equations
        G = lhs - rhs

        # Solve system
        pde = NonlinearVariationalProblem(G, self.vs, J=derivative(G, self.vs))
        solver = NonlinearVariationalSolver(pde)
        solver_params = self.parameters["nonlinear_variational_solver"]
        solver.parameters.update(solver_params)
        solver.solve()
        timer.stop()