{"action":"created","comment":{"url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/comments/227129127","pull_request_review_id":167098253,"id":227129127,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNzEyOTEyNw==","diff_hunk":"@@ -23,373 +23,118 @@\n #include <math.h>\n #include \"allvars.h\"\n #include \"sfr_eff.h\"\n-#include \"drift.h\"\n-#include \"treewalk.h\"\n #include \"cooling.h\"\n #include \"slotsmanager.h\"\n #include \"timestep.h\"\n-\n-#include \"utils.h\"\n+#include \"treewalk.h\"\n+#include \"winds.h\"\n \n /*Cooling only: no star formation*/\n static void cooling_direct(int i);\n \n-/*\n- * This routine does cooling and star formation for\n- * the effective multi-phase model.\n- */\n-static int\n-sfr_cooling_haswork(int target, TreeWalk * tw)\n-{\n-    return P[target].Type == 0 && P[target].Mass > 0;\n-}\n-\n-#ifdef SFR\n-/* these guys really shall be local to cooling_and_starformation, but\n- * I am too lazy to pass them around to subroutines.\n- */\n-static int * stars_converted;\n-static int * stars_spawned;\n-static double * sum_mass_stars;\n-static double * sum_sm;\n-static double * localsfr;\n-\n static void cooling_relaxed(int i, double egyeff, double dtime, double trelax);\n \n-static int get_sfr_condition(int i);\n-static int make_particle_star(int i);\n-static void starformation(int i);\n-static void quicklyastarformation(int i);\n+static int sfreff_on_eeqos(int i);\n+static int make_particle_star(int i, double mass_of_star);\n+static int starformation(int i, double *localsfr, double * sum_sm, double *sum_mass_stars);\n+static int quicklyastarformation(int i);\n static double get_sfr_factor_due_to_selfgravity(int i);\n static double get_sfr_factor_due_to_h2(int i);\n static double get_starformation_rate_full(int i, double dtime, MyFloat * ne_new, double * trelax, double * egyeff);\n static double find_star_mass(int i);\n \n-/*Prototypes and structures for the wind model*/\n-typedef struct {\n-    TreeWalkQueryBase base;\n-    int NodeList[NODELISTLENGTH];\n-    double Sfr;\n-    double Dt;\n-    double Mass;\n-    double Hsml;\n-    double TotalWeight;\n-    double DMRadius;\n-    double Vdisp;\n-    double Vmean[3];\n-} TreeWalkQueryWind;\n-\n-typedef struct {\n-    TreeWalkResultBase base;\n-    double TotalWeight;\n-    double V1sum[3];\n-    double V2sum;\n-    int Ngb;\n-} TreeWalkResultWind;\n-\n-typedef struct {\n-    TreeWalkNgbIterBase base;\n-} TreeWalkNgbIterWind;\n-\n-static struct winddata {\n-    double DMRadius;\n-    double Left;\n-    double Right;\n-    double TotalWeight;\n-    union {\n-        double Vdisp;\n-        double V2sum;\n-    };\n-    union {\n-        double Vmean[3];\n-        double V1sum[3];\n-    };\n-    int Ngb;\n-} * Wind;\n-\n-static int\n-make_particle_wind(MyIDType ID, int i, double v, double vmean[3]);\n-\n-static int\n-sfr_wind_weight_haswork(int target, TreeWalk * tw);\n-\n-static int\n-sfr_wind_feedback_haswork(int target, TreeWalk * tw);\n-\n-static void\n-sfr_wind_reduce_weight(int place, TreeWalkResultWind * remote, enum TreeWalkReduceMode mode, TreeWalk * tw);\n-\n-static void\n-sfr_wind_copy(int place, TreeWalkQueryWind * input, TreeWalk * tw);\n-\n-static void\n-sfr_wind_weight_ngbiter(TreeWalkQueryWind * I,\n-        TreeWalkResultWind * O,\n-        TreeWalkNgbIterWind * iter,\n-        LocalTreeWalk * lv);\n-\n-static void\n-sfr_wind_feedback_ngbiter(TreeWalkQueryWind * I,\n-        TreeWalkResultWind * O,\n-        TreeWalkNgbIterWind * iter,\n-        LocalTreeWalk * lv);\n-\n-static int NPLeft;\n-\n-static void\n-sfr_wind_feedback_preprocess(const int n, TreeWalk * tw)\n-{\n-    Wind[n].DMRadius = 2 * P[n].Hsml;\n-    Wind[n].Left = 0;\n-    Wind[n].Right = -1;\n-    P[n].DensityIterationDone = 0;\n-}\n-\n-static void\n-sfr_wind_weight_postprocess(const int i, TreeWalk * tw)\n-{\n-    int diff = Wind[i].Ngb - 40;\n-    if(diff < -2) {\n-        /* too few */\n-        Wind[i].Left = Wind[i].DMRadius;\n-    } else if(diff > 2) {\n-        /* too many */\n-        Wind[i].Right = Wind[i].DMRadius;\n-    } else {\n-        P[i].DensityIterationDone = 1;\n-    }\n-    if(Wind[i].Right >= 0) {\n-        /* if Ngb hasn't converged to 40, see if DMRadius converged*/\n-        if(Wind[i].Right - Wind[i].Left < 1e-2) {\n-            P[i].DensityIterationDone = 1;\n-        } else {\n-            Wind[i].DMRadius = 0.5 * (Wind[i].Left + Wind[i].Right);\n-        }\n-    } else {\n-        Wind[i].DMRadius *= 1.3;\n-    }\n-\n-    if(P[i].DensityIterationDone) {\n-        double vdisp = Wind[i].V2sum / Wind[i].Ngb;\n-        int d;\n-        for(d = 0; d < 3; d ++) {\n-            Wind[i].Vmean[d] = Wind[i].V1sum[d] / Wind[i].Ngb;\n-            vdisp -= Wind[i].Vmean[d] * Wind[i].Vmean[d];\n-        }\n-        Wind[i].Vdisp = sqrt(vdisp / 3);\n-    } else {\n-#pragma omp atomic\n-        NPLeft ++;\n-    }\n-}\n-\n-static void\n-sfr_wind_feedback_postprocess(const int i, TreeWalk * tw)\n+/* cooling and star formation routine.*/\n+void cooling_and_starformation(void)\n {\n-    P[i].IsNewParticle = 0;\n-}\n+    if(!All.CoolingOn)\n+        return;\n \n-/*End of wind model functions*/\n+    int i;\n \n-static void\n-sfr_cool_postprocess(int i, TreeWalk * tw)\n-{\n-        int flag;\n-        /*Remove a wind particle from the delay mode if the (physical) density has dropped sufficiently.*/\n-        if(SPHP(i).DelayTime > 0 && SPHP(i).Density * All.cf.a3inv < All.WindFreeTravelDensFac * All.PhysDensThresh) {\n-                SPHP(i).DelayTime = 0;\n-        }\n-        /*Reduce the time until the particle can form stars again by the current timestep*/\n-        if(SPHP(i).DelayTime > 0) {\n-            const double dloga = get_dloga_for_bin(P[i].TimeBin);\n-            /*  the proper time duration of the step */\n-            const double dtime = dloga / All.cf.hubble;\n-            SPHP(i).DelayTime = DMAX(SPHP(i).DelayTime - dtime, 0);\n-        }\n+    double sum_sm = 0, sum_mass_stars = 0, localsfr = 0;\n+    int stars_converted=0, stars_spawned=0;\n \n-        /* check whether conditions for star formation are fulfilled.\n-         *\n-         * f=1  normal cooling\n-         * f=0  star formation\n-         */\n-        flag = get_sfr_condition(i);\n-\n-        /* normal implicit isochoric cooling */\n-        if(flag == 1 || (All.QuickLymanAlphaProbability > 0 && All.QuickLymanAlphaProbability < 1)) {\n-            cooling_direct(i);\n-        }\n-        if(flag == 0) {\n-            /* active star formation */\n+    /* First decide which stars are cooling and which starforming. If star forming we add them to a list.\n+     * Note the dynamic scheduling: individual particles may have very different loop iteration lengths.\n+     * Cooling is much slower than sfr. I tried splitting it into a separate loop instead, but this was faster.*/\n+    #pragma omp parallel for schedule(dynamic, 100) reduction(+: stars_spawned) reduction(+:stars_converted) reduction(+:localsfr) reduction(+: sum_sm) reduction(+:sum_mass_stars)\n+    for(i=0; i < NumActiveParticle; i++)\n+    {\n+        /*Use raw particle number if active_set is null, otherwise use active_set*/\n+        const int p_i = ActiveParticle ? ActiveParticle[i] : i;\n+        /* Skip non-gas or garbage particles */\n+        if(P[p_i].Type != 0 || P[p_i].IsGarbage || P[p_i].Mass <= 0)\n+            continue;\n+\n+        int shall_we_star_form = 0;\n+        if(All.StarformationOn) {\n+#ifdef SFR\n+            wind_evolve(p_i);\n+#endif\n+            /* check whether we are star forming gas.*/\n             if(All.QuickLymanAlphaProbability > 0)\n-                quicklyastarformation(i);\n+                shall_we_star_form = quicklyastarformation(p_i);\n             else\n-                starformation(i);\n+                shall_we_star_form = sfreff_on_eeqos(p_i);\n         }\n-}\n \n-void cooling_and_starformation(void)\n-    /* cooling routine when star formation is enabled */\n-{\n-    walltime_measure(\"/Misc\");\n-\n-    /*When we switch to OpenMP 4.5, which supports array reduction,\n-     * we can perhaps remove this*/\n-    stars_spawned = ta_malloc(\"stars_spawned\", int, All.NumThreads);\n-    stars_converted = ta_malloc(\"stars_converted\", int, All.NumThreads);\n-    sum_sm = ta_malloc(\"sum_sm\", double, All.NumThreads);\n-    sum_mass_stars = ta_malloc(\"sum_mass_stars\", double, All.NumThreads);\n-    localsfr = ta_malloc(\"localsfr\", double, All.NumThreads);\n-    memset(stars_spawned, 0, All.NumThreads * sizeof(int));\n-    memset(stars_converted, 0, All.NumThreads * sizeof(int));\n-    memset(sum_sm, 0, All.NumThreads * sizeof(double));\n-    memset(sum_mass_stars, 0, All.NumThreads * sizeof(double));\n-    memset(localsfr, 0, All.NumThreads * sizeof(double));\n-\n-    TreeWalk tw[1] = {{0}};\n-\n-    tw->visit = NULL; /* no tree walk */\n-    tw->ev_label = \"SFR_COOL\";\n-    tw->haswork = sfr_cooling_haswork;\n-    tw->postprocess = (TreeWalkProcessFunction) sfr_cool_postprocess;\n-\n-    treewalk_run(tw, ActiveParticle, NumActiveParticle);\n-\n-    int i;\n-    for(i = 1; i < All.NumThreads; i++)\n-    {\n-        sum_mass_stars[0] += sum_mass_stars[i];\n-        localsfr[0] += localsfr[i];\n-        sum_sm[0] += sum_sm[i];\n-        stars_spawned[0] += stars_spawned[i];\n-        stars_converted[0] += stars_converted[i];\n+        if(shall_we_star_form) {\n+            if(All.QuickLymanAlphaProbability > 0) {\n+                double mass_of_star = find_star_mass(p_i);\n+                make_particle_star(p_i, mass_of_star);\n+                stars_converted++;\n+                sum_mass_stars += mass_of_star;\n+            } else {\n+                int spawn = starformation(p_i, &localsfr, &sum_sm, &sum_mass_stars);\n+                if(spawn == 1)\n+                    stars_converted ++;\n+                if(spawn == 2)\n+                    stars_spawned ++;\n+            }\n+        }\n+        else\n+            cooling_direct(p_i);\n     }\n \n-    int tot_spawned, tot_converted;\n-    MPI_Allreduce(&stars_spawned[0], &tot_spawned, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);\n-    MPI_Allreduce(&stars_converted[0], &tot_converted, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);\n+    walltime_measure(\"/Cooling/Cooling\");\n \n-    if(tot_spawned > 0 || tot_converted > 0)\n-    {\n-        message(0, \"SFR: spawned %d stars, converted %d gas particles into stars\\n\",\n-                    tot_spawned, tot_converted);\n+    if(!All.StarformationOn)\n+        return;\n \n-        /* Note: N_sph is only reduced once domain_garbage_collection is called */\n+    int64_t tot_spawned=0, tot_converted=0;\n+    sumup_large_ints(1, &stars_spawned, &tot_spawned);\n+    sumup_large_ints(1, &stars_converted, &tot_converted);\n \n-        /* Note: New tree construction can be avoided because of  `force_add_star_to_tree()' */\n-    }\n+    if(tot_spawned || tot_converted)\n+        message(0, \"SFR: spawned %ld stars, converted %ld gas particles into stars\\n\", tot_spawned, tot_converted);\n \n     double total_sum_mass_stars, total_sm, totsfrrate;\n \n-    MPI_Reduce(&localsfr[0], &totsfrrate, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);\n-    MPI_Reduce(&sum_sm[0], &total_sm, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);\n-    MPI_Reduce(&sum_mass_stars[0], &total_sum_mass_stars, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);\n+    MPI_Reduce(&localsfr, &totsfrrate, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);\n+    MPI_Reduce(&sum_sm, &total_sm, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);\n+    MPI_Reduce(&sum_mass_stars, &total_sum_mass_stars, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);\n     if(ThisTask == 0)\n     {\n-        double rate;\n-        double rate_in_msunperyear;\n+        double rate = 0;\n         if(All.TimeStep > 0)\n             rate = total_sm / (All.TimeStep / (All.Time * All.cf.hubble));\n-        else\n-            rate = 0;\n \n         /* convert to solar masses per yr */\n \n-        rate_in_msunperyear = rate * (All.UnitMass_in_g / SOLAR_MASS) / (All.UnitTime_in_s / SEC_PER_YEAR);\n+        double rate_in_msunperyear = rate * (All.UnitMass_in_g / SOLAR_MASS) / (All.UnitTime_in_s / SEC_PER_YEAR);\n \n         fprintf(FdSfr, \"%g %g %g %g %g\\n\", All.Time, total_sm, totsfrrate, rate_in_msunperyear,\n                 total_sum_mass_stars);\n         fflush(FdSfr);\n     }\n \n-    ta_free(localsfr);\n-    ta_free(sum_mass_stars);\n-    ta_free(sum_sm);\n-    ta_free(stars_converted);\n-    ta_free(stars_spawned);\n-\n     walltime_measure(\"/Cooling/StarFormation\");\n \n-    /* now lets make winds. this has to be after NumPart is updated */\n-    if(All.WindOn && !HAS(All.WindModel, WIND_SUBGRID)){\n-        Wind = (struct winddata * ) mymalloc(\"WindExtraData\", PartManager->NumPart * sizeof(struct winddata));\n-        TreeWalk tw[1] = {{0}};\n-\n-        tw->ev_label = \"SFR_WIND\";\n-        tw->fill = (TreeWalkFillQueryFunction) sfr_wind_copy;\n-        tw->reduce = (TreeWalkReduceResultFunction) sfr_wind_reduce_weight;\n-        tw->UseNodeList = 1;\n-        tw->query_type_elsize = sizeof(TreeWalkQueryWind);\n-        tw->result_type_elsize = sizeof(TreeWalkResultWind);\n-\n-        /* sum the total weight of surrounding gas */\n-        tw->ngbiter_type_elsize = sizeof(TreeWalkNgbIterWind);\n-        tw->ngbiter = (TreeWalkNgbIterFunction) sfr_wind_weight_ngbiter;\n-\n-        /* First set DensityIterationDone for weighting */\n-        /* Watchout: the process function name is preprocess, but not called in the feedback tree walk\n-         * because we need to compute the normalization before the feedback . */\n-        tw->visit = NULL;\n-        tw->haswork = (TreeWalkHasWorkFunction) sfr_wind_feedback_haswork;\n-        tw->postprocess = (TreeWalkProcessFunction) sfr_wind_feedback_preprocess;\n-        treewalk_run(tw, ActiveParticle, NumActiveParticle);\n-\n-        tw->haswork = sfr_wind_weight_haswork;\n-        tw->visit = (TreeWalkVisitFunction) treewalk_visit_ngbiter;\n-        tw->postprocess = (TreeWalkProcessFunction) sfr_wind_weight_postprocess;\n-\n-        int done = 0;\n-        while(!done) {\n-            NPLeft = 0;\n-            treewalk_run(tw, ActiveParticle, NumActiveParticle);\n-\n-            int64_t totalleft = 0;\n-            sumup_large_ints(1, &NPLeft, &totalleft);\n-            message(0, \"Star DM iteration Total left = %ld\\n\", totalleft);\n-            done = totalleft == 0;\n-        }\n-\n-        /* Then run feedback */\n-        tw->haswork = (TreeWalkHasWorkFunction) sfr_wind_feedback_haswork;\n-        tw->ngbiter = (TreeWalkNgbIterFunction) sfr_wind_feedback_ngbiter;\n-        tw->postprocess = (TreeWalkProcessFunction) sfr_wind_feedback_postprocess;\n-        tw->reduce = NULL;\n-\n-        treewalk_run(tw, ActiveParticle, NumActiveParticle);\n-        myfree(Wind);\n-    }\n-    walltime_measure(\"/Cooling/Wind\");\n-}\n-\n-#else //No SFR\n-\n-static void\n-cool_postprocess(int i, TreeWalk * tw)\n-{\n-    cooling_direct(i);\n-}\n-\n-/* cooling routine when star formation is disabled */\n-void cooling_only(void)\n-{\n-    if(!All.CoolingOn) return;\n-    walltime_measure(\"/Misc\");\n-\n-    TreeWalk tw[1] = {0};\n-\n-    /* Only used to list all active particles for the parallel loop */\n-    /* no tree walking and no need to export / copy particles. */\n-\n-    tw->visit = NULL; /* no tree walk */\n-    tw->ev_label = \"SFR_COOL\";\n-    tw->haswork = sfr_cooling_haswork;\n-    tw->postprocess = (TreeWalkProcessFunction) cool_postprocess;\n-\n-    treewalk_run(tw, ActiveParticle, NumActiveParticle);\n-\n-    walltime_measure(\"/Cooling/StarFormation\");\n-}\n-\n+#ifdef SFR\n+    /* Now apply the wind model: has to use the new NumActiveParticle.*/\n+    winds_and_feedback(ActiveParticle, NumActiveParticle);","path":"libgadget/sfr_eff.c","position":434,"original_position":434,"commit_id":"22f78ab3783787d4047adeccba1f14743310a1aa","original_commit_id":"22f78ab3783787d4047adeccba1f14743310a1aa","user":{"login":"rainwoodman","id":138060,"node_id":"MDQ6VXNlcjEzODA2MA==","avatar_url":"https://avatars0.githubusercontent.com/u/138060?v=4","gravatar_id":"","url":"https://api.github.com/users/rainwoodman","html_url":"https://github.com/rainwoodman","followers_url":"https://api.github.com/users/rainwoodman/followers","following_url":"https://api.github.com/users/rainwoodman/following{/other_user}","gists_url":"https://api.github.com/users/rainwoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/rainwoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rainwoodman/subscriptions","organizations_url":"https://api.github.com/users/rainwoodman/orgs","repos_url":"https://api.github.com/users/rainwoodman/repos","events_url":"https://api.github.com/users/rainwoodman/events{/privacy}","received_events_url":"https://api.github.com/users/rainwoodman/received_events","type":"User","site_admin":false},"body":"But NumActiveParticle is also a global variable? ","created_at":"2018-10-22T20:37:07Z","updated_at":"2018-10-22T20:37:07Z","html_url":"https://github.com/MP-Gadget/MP-Gadget/pull/238#discussion_r227129127","pull_request_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/comments/227129127"},"html":{"href":"https://github.com/MP-Gadget/MP-Gadget/pull/238#discussion_r227129127"},"pull_request":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238"}}},"pull_request":{"url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238","id":224749796,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI0NzQ5Nzk2","html_url":"https://github.com/MP-Gadget/MP-Gadget/pull/238","diff_url":"https://github.com/MP-Gadget/MP-Gadget/pull/238.diff","patch_url":"https://github.com/MP-Gadget/MP-Gadget/pull/238.patch","issue_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues/238","number":238,"state":"open","locked":false,"title":"Sfrcleanup","user":{"login":"sbird","id":1325948,"node_id":"MDQ6VXNlcjEzMjU5NDg=","avatar_url":"https://avatars2.githubusercontent.com/u/1325948?v=4","gravatar_id":"","url":"https://api.github.com/users/sbird","html_url":"https://github.com/sbird","followers_url":"https://api.github.com/users/sbird/followers","following_url":"https://api.github.com/users/sbird/following{/other_user}","gists_url":"https://api.github.com/users/sbird/gists{/gist_id}","starred_url":"https://api.github.com/users/sbird/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sbird/subscriptions","organizations_url":"https://api.github.com/users/sbird/orgs","repos_url":"https://api.github.com/users/sbird/repos","events_url":"https://api.github.com/users/sbird/events{/privacy}","received_events_url":"https://api.github.com/users/sbird/received_events","type":"User","site_admin":false},"body":"This is the first part of a series on removing thread contention in the star formation code. I split this one out to make the whole thing easier to review - this part is just cleanups. The main nice thing about it is that it removes the global thread-local variables in sfr_eff.c, instead just using locals with omp reduction clauses. Hooray! I also split winds into a separate file.\r\n\r\nOne thing I did was to make -DSFR just guard the wind model, so I could unify the routines for cooling and star formation and just cooling. This should prevent us from breaking compilation of the !SFR case. I also considered removing -DSFR entirely - the main runtime penalty is an extra double in SPHP which isn't really a big deal. What do you think?","created_at":"2018-10-22T17:17:26Z","updated_at":"2018-10-22T20:37:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e8b289ecc556ddd97beb91ad207fce2746d88a9b","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238/commits","review_comments_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238/comments","review_comment_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/comments{/number}","comments_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues/238/comments","statuses_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/statuses/22f78ab3783787d4047adeccba1f14743310a1aa","head":{"label":"sbird:sfrcleanup","ref":"sfrcleanup","sha":"22f78ab3783787d4047adeccba1f14743310a1aa","user":{"login":"sbird","id":1325948,"node_id":"MDQ6VXNlcjEzMjU5NDg=","avatar_url":"https://avatars2.githubusercontent.com/u/1325948?v=4","gravatar_id":"","url":"https://api.github.com/users/sbird","html_url":"https://github.com/sbird","followers_url":"https://api.github.com/users/sbird/followers","following_url":"https://api.github.com/users/sbird/following{/other_user}","gists_url":"https://api.github.com/users/sbird/gists{/gist_id}","starred_url":"https://api.github.com/users/sbird/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sbird/subscriptions","organizations_url":"https://api.github.com/users/sbird/orgs","repos_url":"https://api.github.com/users/sbird/repos","events_url":"https://api.github.com/users/sbird/events{/privacy}","received_events_url":"https://api.github.com/users/sbird/received_events","type":"User","site_admin":false},"repo":{"id":52700117,"node_id":"MDEwOlJlcG9zaXRvcnk1MjcwMDExNw==","name":"MP-Gadget3","full_name":"sbird/MP-Gadget3","private":false,"owner":{"login":"sbird","id":1325948,"node_id":"MDQ6VXNlcjEzMjU5NDg=","avatar_url":"https://avatars2.githubusercontent.com/u/1325948?v=4","gravatar_id":"","url":"https://api.github.com/users/sbird","html_url":"https://github.com/sbird","followers_url":"https://api.github.com/users/sbird/followers","following_url":"https://api.github.com/users/sbird/following{/other_user}","gists_url":"https://api.github.com/users/sbird/gists{/gist_id}","starred_url":"https://api.github.com/users/sbird/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sbird/subscriptions","organizations_url":"https://api.github.com/users/sbird/orgs","repos_url":"https://api.github.com/users/sbird/repos","events_url":"https://api.github.com/users/sbird/events{/privacy}","received_events_url":"https://api.github.com/users/sbird/received_events","type":"User","site_admin":false},"html_url":"https://github.com/sbird/MP-Gadget3","description":"massively-parallel cosmology simulator ","fork":true,"url":"https://api.github.com/repos/sbird/MP-Gadget3","forks_url":"https://api.github.com/repos/sbird/MP-Gadget3/forks","keys_url":"https://api.github.com/repos/sbird/MP-Gadget3/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sbird/MP-Gadget3/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sbird/MP-Gadget3/teams","hooks_url":"https://api.github.com/repos/sbird/MP-Gadget3/hooks","issue_events_url":"https://api.github.com/repos/sbird/MP-Gadget3/issues/events{/number}","events_url":"https://api.github.com/repos/sbird/MP-Gadget3/events","assignees_url":"https://api.github.com/repos/sbird/MP-Gadget3/assignees{/user}","branches_url":"https://api.github.com/repos/sbird/MP-Gadget3/branches{/branch}","tags_url":"https://api.github.com/repos/sbird/MP-Gadget3/tags","blobs_url":"https://api.github.com/repos/sbird/MP-Gadget3/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sbird/MP-Gadget3/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sbird/MP-Gadget3/git/refs{/sha}","trees_url":"https://api.github.com/repos/sbird/MP-Gadget3/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sbird/MP-Gadget3/statuses/{sha}","languages_url":"https://api.github.com/repos/sbird/MP-Gadget3/languages","stargazers_url":"https://api.github.com/repos/sbird/MP-Gadget3/stargazers","contributors_url":"https://api.github.com/repos/sbird/MP-Gadget3/contributors","subscribers_url":"https://api.github.com/repos/sbird/MP-Gadget3/subscribers","subscription_url":"https://api.github.com/repos/sbird/MP-Gadget3/subscription","commits_url":"https://api.github.com/repos/sbird/MP-Gadget3/commits{/sha}","git_commits_url":"https://api.github.com/repos/sbird/MP-Gadget3/git/commits{/sha}","comments_url":"https://api.github.com/repos/sbird/MP-Gadget3/comments{/number}","issue_comment_url":"https://api.github.com/repos/sbird/MP-Gadget3/issues/comments{/number}","contents_url":"https://api.github.com/repos/sbird/MP-Gadget3/contents/{+path}","compare_url":"https://api.github.com/repos/sbird/MP-Gadget3/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sbird/MP-Gadget3/merges","archive_url":"https://api.github.com/repos/sbird/MP-Gadget3/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sbird/MP-Gadget3/downloads","issues_url":"https://api.github.com/repos/sbird/MP-Gadget3/issues{/number}","pulls_url":"https://api.github.com/repos/sbird/MP-Gadget3/pulls{/number}","milestones_url":"https://api.github.com/repos/sbird/MP-Gadget3/milestones{/number}","notifications_url":"https://api.github.com/repos/sbird/MP-Gadget3/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sbird/MP-Gadget3/labels{/name}","releases_url":"https://api.github.com/repos/sbird/MP-Gadget3/releases{/id}","deployments_url":"https://api.github.com/repos/sbird/MP-Gadget3/deployments","created_at":"2016-02-28T02:10:17Z","updated_at":"2018-10-20T02:00:59Z","pushed_at":"2018-10-22T06:56:27Z","git_url":"git://github.com/sbird/MP-Gadget3.git","ssh_url":"git@github.com:sbird/MP-Gadget3.git","clone_url":"https://github.com/sbird/MP-Gadget3.git","svn_url":"https://github.com/sbird/MP-Gadget3","homepage":null,"size":9416,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"MP-Gadget:master","ref":"master","sha":"1bbe896770b3778951355ecaef0eb442ebf3ae58","user":{"login":"MP-Gadget","id":38799051,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM4Nzk5MDUx","avatar_url":"https://avatars3.githubusercontent.com/u/38799051?v=4","gravatar_id":"","url":"https://api.github.com/users/MP-Gadget","html_url":"https://github.com/MP-Gadget","followers_url":"https://api.github.com/users/MP-Gadget/followers","following_url":"https://api.github.com/users/MP-Gadget/following{/other_user}","gists_url":"https://api.github.com/users/MP-Gadget/gists{/gist_id}","starred_url":"https://api.github.com/users/MP-Gadget/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MP-Gadget/subscriptions","organizations_url":"https://api.github.com/users/MP-Gadget/orgs","repos_url":"https://api.github.com/users/MP-Gadget/repos","events_url":"https://api.github.com/users/MP-Gadget/events{/privacy}","received_events_url":"https://api.github.com/users/MP-Gadget/received_events","type":"Organization","site_admin":false},"repo":{"id":24486904,"node_id":"MDEwOlJlcG9zaXRvcnkyNDQ4NjkwNA==","name":"MP-Gadget","full_name":"MP-Gadget/MP-Gadget","private":false,"owner":{"login":"MP-Gadget","id":38799051,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM4Nzk5MDUx","avatar_url":"https://avatars3.githubusercontent.com/u/38799051?v=4","gravatar_id":"","url":"https://api.github.com/users/MP-Gadget","html_url":"https://github.com/MP-Gadget","followers_url":"https://api.github.com/users/MP-Gadget/followers","following_url":"https://api.github.com/users/MP-Gadget/following{/other_user}","gists_url":"https://api.github.com/users/MP-Gadget/gists{/gist_id}","starred_url":"https://api.github.com/users/MP-Gadget/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MP-Gadget/subscriptions","organizations_url":"https://api.github.com/users/MP-Gadget/orgs","repos_url":"https://api.github.com/users/MP-Gadget/repos","events_url":"https://api.github.com/users/MP-Gadget/events{/privacy}","received_events_url":"https://api.github.com/users/MP-Gadget/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/MP-Gadget/MP-Gadget","description":"massively-parallel cosmology simulator ","fork":false,"url":"https://api.github.com/repos/MP-Gadget/MP-Gadget","forks_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/forks","keys_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/teams","hooks_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/hooks","issue_events_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues/events{/number}","events_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/events","assignees_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/assignees{/user}","branches_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/branches{/branch}","tags_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/tags","blobs_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/git/refs{/sha}","trees_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/statuses/{sha}","languages_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/languages","stargazers_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/stargazers","contributors_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/contributors","subscribers_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/subscribers","subscription_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/subscription","commits_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/commits{/sha}","git_commits_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/git/commits{/sha}","comments_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/comments{/number}","issue_comment_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues/comments{/number}","contents_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/contents/{+path}","compare_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/merges","archive_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/downloads","issues_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues{/number}","pulls_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls{/number}","milestones_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/milestones{/number}","notifications_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/labels{/name}","releases_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/releases{/id}","deployments_url":"https://api.github.com/repos/MP-Gadget/MP-Gadget/deployments","created_at":"2014-09-26T05:02:22Z","updated_at":"2018-10-19T22:37:11Z","pushed_at":"2018-10-22T17:17:27Z","git_url":"git://github.com/MP-Gadget/MP-Gadget.git","ssh_url":"git@github.com:MP-Gadget/MP-Gadget.git","clone_url":"https://github.com/MP-Gadget/MP-Gadget.git","svn_url":"https://github.com/MP-Gadget/MP-Gadget","homepage":null,"size":29924,"stargazers_count":4,"watchers_count":4,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":8,"mirror_url":null,"archived":false,"open_issues_count":17,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":8,"open_issues":17,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238"},"html":{"href":"https://github.com/MP-Gadget/MP-Gadget/pull/238"},"issue":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues/238"},"comments":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/issues/238/comments"},"review_comments":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238/comments"},"review_comment":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/pulls/238/commits"},"statuses":{"href":"https://api.github.com/repos/MP-Gadget/MP-Gadget/statuses/22f78ab3783787d4047adeccba1f14743310a1aa"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"rainwoodman"}}