{"action":"created","comment":{"url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments/75163423","id":75163423,"diff_hunk":"@@ -0,0 +1,331 @@\n+from __future__ import absolute_import\n+import abc\n+\n+from firedrake.petsc import PETSc\n+\n+__all__ = (\"AssembledPC\", \"MassInvPC\", \"PCDPC\", \"PCBase\")\n+\n+\n+class PCBase(object):\n+\n+    __metaclass__ = abc.ABCMeta\n+\n+    def __init__(self):\n+        \"\"\"Create a PC context suitable for PETSc.\n+\n+        Matrix free preconditioners should inherit from this class and\n+        implement:\n+\n+        - :meth:`initialize`\n+        - :meth:`update`\n+        - :meth:`apply`\n+        - :meth:`applyTranspose`\n+\n+        \"\"\"\n+        self.initialized = False\n+        super(PCBase, self).__init__()\n+\n+    @abc.abstractmethod\n+    def update(self, pc):\n+        \"\"\"Update any state in this preconditioner.\"\"\"\n+        pass\n+\n+    @abc.abstractmethod\n+    def initialize(self, pc):\n+        \"\"\"Initialize any state in this preconditioner.\"\"\"\n+        pass\n+\n+    def setUp(self, pc):\n+        \"\"\"Setup method called by PETSc.\n+\n+        Subclasses should probably not override this and instead\n+        implement :meth:`update` and :meth:`initialize`.\"\"\"\n+        if self.initialized:\n+            self.update(pc)\n+        else:\n+            self.initialize(pc)\n+            self.initialized = True\n+\n+    def view(self, pc, viewer=None):\n+        if viewer is None:\n+            return\n+        typ = viewer.getType()\n+        if typ != PETSc.Viewer.Type.ASCII:\n+            return\n+        viewer.printfASCII(\"Firedrake matrix-free preconditioner %s\\n\" %\n+                           type(self).__name__)\n+\n+    @abc.abstractmethod\n+    def apply(self, pc, X, Y):\n+        \"\"\"Apply the preconditioner to X, putting the result in Y.\n+\n+        Both X and Y are PETSc Vecs, Y is not guaranteed to be zero on entry.\n+        \"\"\"\n+        pass\n+\n+    @abc.abstractmethod\n+    def applyTranspose(self, pc, X, Y):\n+        \"\"\"Apply the transpose of the preconditioner to X, putting the result in Y.\n+\n+        Both X and Y are PETSc Vecs, Y is not guaranteed to be zero on entry.\n+\n+        \"\"\"\n+        pass\n+\n+\n+class AssembledPC(PCBase):\n+    \"\"\"A matrix-free PC that assembles the operator.\n+\n+    Internally this makes a PETSc PC object that can be controlled by\n+    options using the extra options prefix ``assembled_``.\n+    \"\"\"\n+    def initialize(self, pc):\n+        from firedrake.assemble import assemble\n+\n+        _, P = pc.getOperators()\n+\n+        context = P.getPythonContext()\n+\n+        # It only makes sense to preconditioner/invert a diagonal\n+        # block in general.  That's all we're going to allow.\n+        if not context.on_diag:\n+            raise ValueError(\"Only makes sense to invert diagonal block\")\n+\n+        self.P = assemble(context.a, bcs=context.row_bcs,\n+                          form_compiler_parameters=context.fc_params,\n+                          mat_type='aij')\n+        self.P.force_evaluation()\n+\n+        # Transfer nullspace over\n+        Pmat = self.P.petscmat\n+        Pmat.setNullSpace(P.getNullSpace())\n+        Pmat.setTransposeNullSpace(P.getTransposeNullSpace())\n+\n+        prefix = pc.getOptionsPrefix()\n+\n+        # Internally, we just set up a PC object that the user can configure\n+        # however from the PETSc command line.  Since PC allows the user to specify\n+        # a KSP, we can do iterative by -assembled_pc_type ksp.\n+        pc = PETSc.PC().create()\n+        pc.setOptionsPrefix(prefix+\"assembled_\")\n+        pc.setOperators(Pmat, Pmat)\n+        pc.setUp()\n+        pc.setFromOptions()\n+        self.pc = pc\n+\n+    def update(self, pc):\n+        from firedrake import assemble\n+        P = self.P\n+        P = assemble(P.a, tensor=P, bcs=P.bcs)\n+        P.force_evaluation()\n+\n+    def apply(self, pc, x, y):\n+        self.pc.apply(x, y)\n+\n+    def applyTranspose(self, pc, x, y):\n+        self.pc.applyTranspose(x, y)\n+\n+    def view(self, pc, viewer=None):\n+        super(AssembledPC, self).view(pc, viewer)\n+        viewer.printfASCII(\"PC to apply inverse\\n\")\n+        viewer.pushASCIITab()\n+        self.pc.view(viewer)\n+        viewer.popASCIITab()\n+\n+\n+class MassInvPC(PCBase):\n+\n+    \"\"\"A matrix free operator that inverts the mass matrix in the provided space.\n+\n+    Internally this creates a PETSc KSP object that can be controlled\n+    by options using the extra options prefix ``Mp_``.\n+    \"\"\"\n+    def initialize(self, pc):\n+        from firedrake import TrialFunction, TestFunction, dx, assemble, inner\n+        prefix = pc.getOptionsPrefix()\n+\n+        # we assume P has things stuffed inside of it\n+        _, P = pc.getOperators()\n+        context = P.getPythonContext()\n+\n+        test, trial = context.a.arguments()\n+\n+        if test.function_space() != trial.function_space():\n+            raise ValueError(\"MassInvPC only makes sense if test and trial space are the same\")\n+\n+        V = test.function_space()\n+\n+        u = TrialFunction(V)\n+        v = TestFunction(V)\n+        # Handle vector and tensor-valued spaces.\n+        a = inner(u, v)*dx\n+\n+        opts = PETSc.Options()\n+        mat_type = opts.getString(prefix+\"Mp_mat_type\", \"\")\n+        \n+        A = assemble(a, form_compiler_parameters=context.fc_params,\n+                     mat_type=mat_type)\n+        A.force_evaluation()\n+\n+        Pmat = A.petscmat\n+        Pmat.setNullSpace(P.getNullSpace())\n+        Pmat.setTransposeNullSpace(P.getTransposeNullSpace())\n+\n+        ksp = PETSc.KSP().create()\n+        ksp.setOperators(Pmat)\n+        ksp.setOptionsPrefix(prefix + \"Mp_\")\n+        ksp.setUp()\n+        ksp.setFromOptions()\n+        self.ksp = ksp\n+\n+    def update(self, pc):\n+        pass\n+\n+    def apply(self, pc, X, Y):\n+        self.ksp.solve(X, Y)\n+\n+    # Mass matrix is symmetric\n+    applyTranspose = apply\n+\n+    def view(self, pc, viewer=None):\n+        super(MassInvPC, self).view(pc, viewer)\n+        viewer.printfASCII(\"KSP solver for M^-1\\n\")\n+        viewer.pushASCIITab()\n+        self.ksp.view(viewer)\n+        viewer.popASCIITab()\n+\n+\n+class PCDPC(PCBase):\n+    \"\"\"A Pressure-Convection-Diffusion preconditioner for Navier-Stokes.\n+\n+    This preconditioner approximates the inverse of the pressure schur\n+    complement for the Navier-Stokes equations by.\n+\n+    .. math::\n+\n+       S^{-1} \\approx K^{-1} F_p M^{-1}\n+\n+    Where :math:`K = \\nabla^2`, :math:`M = \\mathbb{I}` and\n+    :math:`F_p = 1/\\mathrm{Re} \\nabla^2 + u\\cdot\\grad`.\n+\n+    The inverse of :math:`K` is approximated by a KSP which can be\n+    controlled using the options prefix ``pcd_Kp_``.\n+\n+    The inverse of :math:`M` is similarly approximated by a KSP which\n+    can be controlled using the options prefix ``pcd_Mp_``.\n+\n+    :math:`F_p` requires both the Reynolds number and the current\n+    velocity.  You must provide these with options using the glbaol\n+    option ``Re`` for the Reynolds number and the prefixed option\n+    ``pcd_velocity_space`` which should be the index into the full\n+    space that gives velocity field.\n+\n+    \"\"\"\n+    def initialize(self, pc):\n+        from firedrake import TrialFunction, TestFunction, dx, \\\n+            assemble, inner, grad, split, Constant\n+        prefix = pc.getOptionsPrefix() + \"pcd_\"\n+\n+        # we assume P has things stuffed inside of it\n+        _, P = pc.getOperators()\n+        context = P.getPythonContext()\n+\n+        test, trial = context.a.arguments()\n+        if test.function_space() != trial.function_space():\n+            raise ValueError(\"Pressure space test and trial space differ\")\n+\n+        Q = test.function_space()\n+\n+        p = TrialFunction(Q)\n+        q = TestFunction(Q)\n+\n+        mass = p*q*dx\n+\n+        # Regularisation to avoid having to think about nullspaces.\n+        stiffness = inner(grad(p), grad(q))*dx + Constant(1e-6)*p*q*dx\n+\n+        opts = PETSc.Options()\n+        # we're inverting Mp and Kp, so default them to assembled.\n+        # Fp only needs its action, so default it to mat-free.\n+        # These can of course be overridden.\n+        # only Fp is referred to in update, so that's the only\n+        # one we stash.\n+        Mp_mat_type = opts.getString(prefix+\"Mp_mat_type\", \"\")\n+        Kp_mat_type = opts.getString(prefix+\"Kp_mat_type\", \"\")\n+        self.Fp_mat_type = opts.getString(prefix+\"Fp_mat_type\", \"matfree\")\n+\n+        \n+        # FIXME: allow these guys to be matrix-free\n+        Mp = assemble(mass, form_compiler_parameters=context.fc_params,\n+                      mat_type=Mp_mat_type)\n+        Kp = assemble(stiffness, form_compiler_parameters=context.fc_params,\n+                      mat_type=Kp_mat_type)\n+\n+        Mp.force_evaluation()\n+        Kp.force_evaluation()\n+\n+        # FIXME: Should we transfer nullspaces over.  I think not.\n+\n+        Mksp = PETSc.KSP().create()\n+        Mksp.setOptionsPrefix(prefix + \"Mp_\")\n+        Mksp.setOperators(Mp.petscmat)\n+        Mksp.setUp()\n+        Mksp.setFromOptions()\n+        self.Mksp = Mksp\n+\n+        Kksp = PETSc.KSP().create()\n+        Kksp.setOptionsPrefix(prefix + \"Kp_\")\n+        Kksp.setOperators(Kp.petscmat)\n+        Kksp.setUp()\n+        Kksp.setFromOptions()\n+        self.Kksp = Kksp\n+\n+        state = context.context[\"state\"]\n+\n+        Re = context.context.get(\"Re\", 1.0)\n+\n+        velid = context.context[\"velocity_space\"]\n+\n+        u0 = split(state)[velid]\n+        fp = 1.0/Re * inner(grad(p), grad(q))*dx + inner(u0, grad(p))*q*dx\n+\n+        self.Re = Re\n+        # FIXME, allow assembled matrix here\n+        self.Fp = assemble(fp, form_compiler_parameters=context.fc_params,\n+                           mat_type=self.Fp_mat_type)\n+        self.Fp.force_evaluation()\n+        Fpmat = self.Fp.petscmat\n+        self.workspace = [Fpmat.createVecLeft() for i in (0, 1)]","path":"firedrake/matrix_free/preconditioners.py","position":298,"original_position":298,"commit_id":"4ae09350675779089c0b84e43dd28c13a7d4940f","original_commit_id":"4ae09350675779089c0b84e43dd28c13a7d4940f","user":{"login":"wence-","id":1126981,"avatar_url":"https://avatars.githubusercontent.com/u/1126981?v=3","gravatar_id":"","url":"https://api.github.com/users/wence-","html_url":"https://github.com/wence-","followers_url":"https://api.github.com/users/wence-/followers","following_url":"https://api.github.com/users/wence-/following{/other_user}","gists_url":"https://api.github.com/users/wence-/gists{/gist_id}","starred_url":"https://api.github.com/users/wence-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wence-/subscriptions","organizations_url":"https://api.github.com/users/wence-/orgs","repos_url":"https://api.github.com/users/wence-/repos","events_url":"https://api.github.com/users/wence-/events{/privacy}","received_events_url":"https://api.github.com/users/wence-/received_events","type":"User","site_admin":false},"body":"So you need to specify a bunch of information (presumably through the appctx).  Particularly, which subdomains the inflow is applied to and also the value that u.n should take.  Of course, we don't specify u.n, but rather `u`.  As you say, handling all the cases is somewhat tricky.  Can we modify the existing N-S example to do backward-facing step instead.  Then we can demonstrate how to do this in the demo? ","created_at":"2016-08-17T17:03:21Z","updated_at":"2016-08-17T17:03:21Z","html_url":"https://github.com/firedrakeproject/firedrake/pull/853#discussion_r75163423","pull_request_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853","_links":{"self":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments/75163423"},"html":{"href":"https://github.com/firedrakeproject/firedrake/pull/853#discussion_r75163423"},"pull_request":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853"}}},"pull_request":{"url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853","id":80995232,"html_url":"https://github.com/firedrakeproject/firedrake/pull/853","diff_url":"https://github.com/firedrakeproject/firedrake/pull/853.diff","patch_url":"https://github.com/firedrakeproject/firedrake/pull/853.patch","issue_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/853","number":853,"state":"open","locked":false,"title":"New matrix free","user":{"login":"wence-","id":1126981,"avatar_url":"https://avatars.githubusercontent.com/u/1126981?v=3","gravatar_id":"","url":"https://api.github.com/users/wence-","html_url":"https://github.com/wence-","followers_url":"https://api.github.com/users/wence-/followers","following_url":"https://api.github.com/users/wence-/following{/other_user}","gists_url":"https://api.github.com/users/wence-/gists{/gist_id}","starred_url":"https://api.github.com/users/wence-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wence-/subscriptions","organizations_url":"https://api.github.com/users/wence-/orgs","repos_url":"https://api.github.com/users/wence-/repos","events_url":"https://api.github.com/users/wence-/events{/privacy}","received_events_url":"https://api.github.com/users/wence-/received_events","type":"User","site_admin":false},"body":"For comment and improvements.  This is mostly @rckirby's work.\r\n\r\nIt is now possible to solve problems using completely matrix-free operators.  The idea is that for assembled operators, once passes `matfree=True` to assemble.  Then the `LinearSolver` object DTRT.  Alternately, for variational solvers, one should set the solver parameter `\"mat_type\" : \"matfree\"`.  This is then picked up inside the assembler.\r\n\r\nNaturally preconditioning doesn't work.  So some preconditioners are provided.  Particular and \"assembled operator PC\" which has the effect of applying the operator action matrix free but assembling the operator for the preconditioner.\r\n\r\nFor navier-stokes, a pressure-convection-diffusion PC is implemented.  This nests, so it can be used inside (say) Rayleigh-Benard convection.  Which is one of the demos.\r\n\r\nNot perfect yet:\r\n\r\n- Should be able to specify that the operator is assembled but pmat is not, and vice versa\r\n- Should be able to specify `mat_type` with an options prefix so that down in the guts we assemble matrices.  This is one-way because a PETSc matrix doesn't have the information we need to go back into a matrix-free operator.\r\n\r\nI'm sure Rob can add some more comments.","created_at":"2016-08-11T17:14:51Z","updated_at":"2016-08-17T17:03:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":"91edfca887deabf8bbd8bfba766797cf05cb51b7","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853/commits","review_comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853/comments","review_comment_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments{/number}","comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/853/comments","statuses_url":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/4ae09350675779089c0b84e43dd28c13a7d4940f","head":{"label":"firedrakeproject:new-matrix-free","ref":"new-matrix-free","sha":"4ae09350675779089c0b84e43dd28c13a7d4940f","user":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"repo":{"id":13384052,"name":"firedrake","full_name":"firedrakeproject/firedrake","owner":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/firedrakeproject/firedrake","description":"Firedrake is an automated system for the portable solution of partial differential equations using the finite element method (FEM)","fork":false,"url":"https://api.github.com/repos/firedrakeproject/firedrake","forks_url":"https://api.github.com/repos/firedrakeproject/firedrake/forks","keys_url":"https://api.github.com/repos/firedrakeproject/firedrake/keys{/key_id}","collaborators_url":"https://api.github.com/repos/firedrakeproject/firedrake/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/firedrakeproject/firedrake/teams","hooks_url":"https://api.github.com/repos/firedrakeproject/firedrake/hooks","issue_events_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/events{/number}","events_url":"https://api.github.com/repos/firedrakeproject/firedrake/events","assignees_url":"https://api.github.com/repos/firedrakeproject/firedrake/assignees{/user}","branches_url":"https://api.github.com/repos/firedrakeproject/firedrake/branches{/branch}","tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/tags","blobs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/refs{/sha}","trees_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/trees{/sha}","statuses_url":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/{sha}","languages_url":"https://api.github.com/repos/firedrakeproject/firedrake/languages","stargazers_url":"https://api.github.com/repos/firedrakeproject/firedrake/stargazers","contributors_url":"https://api.github.com/repos/firedrakeproject/firedrake/contributors","subscribers_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscribers","subscription_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscription","commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/commits{/sha}","git_commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/commits{/sha}","comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/comments{/number}","issue_comment_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/comments{/number}","contents_url":"https://api.github.com/repos/firedrakeproject/firedrake/contents/{+path}","compare_url":"https://api.github.com/repos/firedrakeproject/firedrake/compare/{base}...{head}","merges_url":"https://api.github.com/repos/firedrakeproject/firedrake/merges","archive_url":"https://api.github.com/repos/firedrakeproject/firedrake/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/firedrakeproject/firedrake/downloads","issues_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues{/number}","pulls_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls{/number}","milestones_url":"https://api.github.com/repos/firedrakeproject/firedrake/milestones{/number}","notifications_url":"https://api.github.com/repos/firedrakeproject/firedrake/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/firedrakeproject/firedrake/labels{/name}","releases_url":"https://api.github.com/repos/firedrakeproject/firedrake/releases{/id}","deployments_url":"https://api.github.com/repos/firedrakeproject/firedrake/deployments","created_at":"2013-10-07T13:07:44Z","updated_at":"2016-08-11T08:22:03Z","pushed_at":"2016-08-17T16:59:36Z","git_url":"git://github.com/firedrakeproject/firedrake.git","ssh_url":"git@github.com:firedrakeproject/firedrake.git","clone_url":"https://github.com/firedrakeproject/firedrake.git","svn_url":"https://github.com/firedrakeproject/firedrake","homepage":"http://firedrakeproject.org","size":15725,"stargazers_count":39,"watchers_count":39,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":24,"mirror_url":null,"open_issues_count":60,"forks":24,"open_issues":60,"watchers":39,"default_branch":"master"}},"base":{"label":"firedrakeproject:master","ref":"master","sha":"42478cb57273f3e566ee366bf7f50fb646819c30","user":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"repo":{"id":13384052,"name":"firedrake","full_name":"firedrakeproject/firedrake","owner":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/firedrakeproject/firedrake","description":"Firedrake is an automated system for the portable solution of partial differential equations using the finite element method (FEM)","fork":false,"url":"https://api.github.com/repos/firedrakeproject/firedrake","forks_url":"https://api.github.com/repos/firedrakeproject/firedrake/forks","keys_url":"https://api.github.com/repos/firedrakeproject/firedrake/keys{/key_id}","collaborators_url":"https://api.github.com/repos/firedrakeproject/firedrake/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/firedrakeproject/firedrake/teams","hooks_url":"https://api.github.com/repos/firedrakeproject/firedrake/hooks","issue_events_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/events{/number}","events_url":"https://api.github.com/repos/firedrakeproject/firedrake/events","assignees_url":"https://api.github.com/repos/firedrakeproject/firedrake/assignees{/user}","branches_url":"https://api.github.com/repos/firedrakeproject/firedrake/branches{/branch}","tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/tags","blobs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/refs{/sha}","trees_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/trees{/sha}","statuses_url":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/{sha}","languages_url":"https://api.github.com/repos/firedrakeproject/firedrake/languages","stargazers_url":"https://api.github.com/repos/firedrakeproject/firedrake/stargazers","contributors_url":"https://api.github.com/repos/firedrakeproject/firedrake/contributors","subscribers_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscribers","subscription_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscription","commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/commits{/sha}","git_commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/commits{/sha}","comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/comments{/number}","issue_comment_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/comments{/number}","contents_url":"https://api.github.com/repos/firedrakeproject/firedrake/contents/{+path}","compare_url":"https://api.github.com/repos/firedrakeproject/firedrake/compare/{base}...{head}","merges_url":"https://api.github.com/repos/firedrakeproject/firedrake/merges","archive_url":"https://api.github.com/repos/firedrakeproject/firedrake/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/firedrakeproject/firedrake/downloads","issues_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues{/number}","pulls_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls{/number}","milestones_url":"https://api.github.com/repos/firedrakeproject/firedrake/milestones{/number}","notifications_url":"https://api.github.com/repos/firedrakeproject/firedrake/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/firedrakeproject/firedrake/labels{/name}","releases_url":"https://api.github.com/repos/firedrakeproject/firedrake/releases{/id}","deployments_url":"https://api.github.com/repos/firedrakeproject/firedrake/deployments","created_at":"2013-10-07T13:07:44Z","updated_at":"2016-08-11T08:22:03Z","pushed_at":"2016-08-17T16:59:36Z","git_url":"git://github.com/firedrakeproject/firedrake.git","ssh_url":"git@github.com:firedrakeproject/firedrake.git","clone_url":"https://github.com/firedrakeproject/firedrake.git","svn_url":"https://github.com/firedrakeproject/firedrake","homepage":"http://firedrakeproject.org","size":15725,"stargazers_count":39,"watchers_count":39,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":24,"mirror_url":null,"open_issues_count":60,"forks":24,"open_issues":60,"watchers":39,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853"},"html":{"href":"https://github.com/firedrakeproject/firedrake/pull/853"},"issue":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/issues/853"},"comments":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/issues/853/comments"},"review_comments":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853/comments"},"review_comment":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/853/commits"},"statuses":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/4ae09350675779089c0b84e43dd28c13a7d4940f"}}}}
{"actor":{"display_login":"wence-"}}