{"action":"created","comment":{"url":"https://api.github.com/repos/stevengj/meep/pulls/comments/141654906","pull_request_review_id":65904036,"id":141654906,"diff_hunk":"@@ -0,0 +1,452 @@\n+/* Copyright (C) 2005-2015 Massachusetts Institute of Technology\n+%\n+%  This program is free software; you can redistribute it and/or modify\n+%  it under the terms of the GNU General Public License as published by\n+%  the Free Software Foundation; either version 2, or (at your option)\n+%  any later version.\n+%\n+%  This program is distributed in the hope that it will be useful,\n+%  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+%  GNU General Public License for more details.\n+%\n+%  You should have received a copy of the GNU General Public License\n+%  along with this program; if not, write to the Free Software Foundation,\n+%  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n+*/\n+\n+/* HDF5 output of fields and arbitrary functions thereof.  Works\n+   very similarly to integrate.cpp (using fields::loop_in_chunks). */\n+\n+#include <stdio.h>\n+#include <string.h>\n+#include <math.h>\n+\n+#include \"meep_internals.hpp\"\n+\n+using namespace std;\n+\n+typedef complex<double> cdouble;\n+\n+namespace meep {\n+\n+/***************************************************************************/\n+\n+typedef struct {\n+\n+  // information related to the volume covered by the\n+  // array slice (its size, etcetera) \n+  // these fields are filled in by get_array_slice_dimensions\n+  // if the data parameter is non-null\n+  ivec min_corner, max_corner;\n+  int num_chunks;\n+  int rank;\n+  direction ds[3];\n+  int slice_size;\n+\n+  // the function to output and related info (offsets for averaging, etc.)\n+  field_function fun;\n+  void *fun_data;\n+  std::vector<component> components;\n+\n+  void *vslice;\n+  bool has_imag;\n+\n+  // temporary internal storage buffers\n+  component *cS;\n+  cdouble *ph;\n+  cdouble *fields;\n+  int *offsets;\n+\n+  int ninveps;\n+  component inveps_cs[3];\n+  direction inveps_ds[3];\n+\n+  int ninvmu;\n+  component invmu_cs[3];\n+  direction invmu_ds[3];\n+\n+} array_slice_data;\n+\n+#define UNUSED(x) (void) x // silence compiler warnings\n+\n+/* passthrough field function equivalent to component_fun in h5fields.cpp */\n+static cdouble default_field_function(const cdouble *fields,\n+\t\t\t\t      const vec &loc, void *data_)\n+{\n+  (void) loc; // unused\n+  (void) data_; // unused\n+  return fields[0];\n+}\n+\n+/***************************************************************/\n+/* callback function passed to loop_in_chunks to compute       */\n+/* dimensions of array slice                                   */\n+/***************************************************************/\n+static void get_array_slice_dimensions_chunkloop(fields_chunk *fc, int ichnk, component cgrid,\n+\t\t\t\t  ivec is, ivec ie,\n+\t\t\t\t  vec s0, vec s1, vec e0, vec e1,\n+\t\t\t\t  double dV0, double dV1,\n+\t\t\t\t  ivec shift, complex<double> shift_phase,\n+\t\t\t\t  const symmetry &S, int sn,\n+\t\t\t\t  void *data_)\n+{\n+  UNUSED(ichnk);UNUSED(cgrid);UNUSED(s0);UNUSED(s1);UNUSED(e0);UNUSED(e1);\n+  UNUSED(dV0);UNUSED(dV1);UNUSED(shift_phase); UNUSED(fc);\n+  array_slice_data *data = (array_slice_data *) data_;\n+  ivec isS = S.transform(is, sn) + shift;\n+  ivec ieS = S.transform(ie, sn) + shift;\n+  data->min_corner = min(data->min_corner, min(isS, ieS));\n+  data->max_corner = max(data->max_corner, max(isS, ieS));\n+  data->num_chunks++;\n+\n+}\n+\n+/***************************************************************/\n+/* callback function passed to loop_in_chunks to fill array slice */\n+/***************************************************************/\n+static void get_array_slice_chunkloop(fields_chunk *fc, int ichnk, component cgrid,\n+\t      \t\t\t  ivec is, ivec ie, vec s0, vec s1, vec e0, vec e1,\n+\t\t\t\t  double dV0, double dV1,\n+\t  \t\t\t  ivec shift, complex<double> shift_phase,\n+\t\t\t\t  const symmetry &S, int sn, void *data_)\n+{\n+  UNUSED(ichnk);UNUSED(cgrid);UNUSED(s0);UNUSED(s1);UNUSED(e0);UNUSED(e1);\n+  UNUSED(dV0);UNUSED(dV1);\n+  array_slice_data *data = (array_slice_data *) data_;\n+\n+  //-----------------------------------------------------------------------//\n+  // Find output chunk dimensions and strides, etc.\n+\n+  int count[3]={1,1,1}, offset[3]={0,0,0}, stride[3]={1,1,1};\n+\n+  ivec isS = S.transform(is, sn) + shift;\n+  ivec ieS = S.transform(ie, sn) + shift;\n+  \n+  // figure out what yucky_directions (in LOOP_OVER_IVECS)\n+  // correspond to what directions in the transformed vectors (in output).\n+  ivec permute(zero_ivec(fc->gv.dim));\n+  for (int i = 0; i < 3; ++i) \n+    permute.set_direction(fc->gv.yucky_direction(i), i);\n+  permute = S.transform_unshifted(permute, sn);\n+  LOOP_OVER_DIRECTIONS(permute.dim, d)\n+    permute.set_direction(d, abs(permute.in_direction(d)));\n+  \n+  // compute the size of the chunk to output, and its strides etc.\n+  for (int i = 0; i < data->rank; ++i) {\n+    direction d = data->ds[i];\n+    int isd = isS.in_direction(d), ied = ieS.in_direction(d);\n+    count[i] = abs(ied - isd) / 2 + 1;\n+    if (ied < isd) offset[permute.in_direction(d)] = count[i] - 1;\n+  }\n+  for (int i = 0; i < data->rank; ++i) {\n+    direction d = data->ds[i];\n+    int j = permute.in_direction(d);\n+    for (int k = i + 1; k < data->rank; ++k) stride[j] *= count[k];\n+    offset[j] *= stride[j];\n+    if (offset[j]) stride[j] *= -1;\n+  }\n+  \n+  //-----------------------------------------------------------------------//\n+  // Compute the function to output, exactly as in fields::integrate.\n+  int *off = data->offsets;\n+  component *cS = data->cS;\n+  complex<double> *fields = data->fields, *ph = data->ph;\n+  const component *iecs = data->inveps_cs;\n+  const direction *ieds = data->inveps_ds;\n+  int ieos[6];\n+  const component *imcs = data->invmu_cs;\n+  const direction *imds = data->invmu_ds;\n+  int imos[6];\n+  int num_components=data->components.size();\n+  \n+  double *slice=0;\n+  cdouble *zslice=0;\n+  bool has_imag = data->has_imag;\n+  if (has_imag)\n+   zslice = (cdouble *)data->vslice;\n+  else\n+   slice = (double *)data->vslice;\n+\n+  for (int i = 0; i < num_components; ++i) {\n+    cS[i] = S.transform(data->components[i], -sn);\n+    if (cS[i] == Dielectric || cS[i] == Permeability)\n+      ph[i] = 1.0;\n+    else {\n+      fc->gv.yee2cent_offsets(cS[i], off[2*i], off[2*i+1]);\n+      ph[i] = shift_phase * S.phase_shift(cS[i], sn);\n+    }\n+  }\n+  for (int k = 0; k < data->ninveps; ++k)\n+    fc->gv.yee2cent_offsets(iecs[k], ieos[2*k], ieos[2*k+1]);\n+  for (int k = 0; k < data->ninvmu; ++k)\n+    fc->gv.yee2cent_offsets(imcs[k], imos[2*k], imos[2*k+1]);\n+\n+  vec rshift(shift * (0.5*fc->gv.inva));\n+  LOOP_OVER_IVECS(fc->gv, is, ie, idx) {\n+    IVEC_LOOP_LOC(fc->gv, loc);\n+    loc = S.transform(loc, sn) + rshift;\n+\n+    for (int i = 0; i < num_components; ++i) {\n+      if (cS[i] == Dielectric) {\n+\tdouble tr = 0.0;\n+\tfor (int k = 0; k < data->ninveps; ++k) {\n+\t  const realnum *ie = fc->s->chi1inv[iecs[k]][ieds[k]];\n+\t  if (ie) tr += (ie[idx] + ie[idx+ieos[2*k]] + ie[idx+ieos[1+2*k]]\n+\t\t\t + ie[idx+ieos[2*k]+ieos[1+2*k]]);\n+\t  else tr += 4; // default inveps == 1\n+\t}\n+\tfields[i] = (4 * data->ninveps) / tr;\n+      }\n+      else if (cS[i] == Permeability) {\n+\tdouble tr = 0.0;\n+\tfor (int k = 0; k < data->ninvmu; ++k) {\n+\t  const realnum *im = fc->s->chi1inv[imcs[k]][imds[k]];\n+\t  if (im) tr += (im[idx] + im[idx+imos[2*k]] + im[idx+imos[1+2*k]]\n+\t\t\t + im[idx+imos[2*k]+imos[1+2*k]]);\n+\t  else tr += 4; // default invmu == 1\n+\t}\n+\tfields[i] = (4 * data->ninvmu) / tr;\n+      }\n+      else {\n+\tdouble f[2];\n+\tfor (int k = 0; k < 2; ++k)\n+\t  if (fc->f[cS[i]][k])\n+\t    f[k] = 0.25 * (fc->f[cS[i]][k][idx]\n+\t\t\t   + fc->f[cS[i]][k][idx+off[2*i]]\n+\t\t\t   + fc->f[cS[i]][k][idx+off[2*i+1]]\n+\t\t\t   + fc->f[cS[i]][k][idx+off[2*i]+off[2*i+1]]);\n+\t  else\n+\t    f[k] = 0;\n+\tfields[i] = complex<double>(f[0], f[1]) * ph[i];\n+      }\n+    }\n+    int idx2 = ((((offset[0] + offset[1] + offset[2])\n+                   + loop_i1 * stride[0])\n+                   + loop_i2 * stride[1])\n+                   + loop_i3 * stride[2]);\n+    if (has_imag)\n+     zslice[idx2] = data->fun(fields, loc, data->fun_data);\n+    else\n+     slice[idx2]  = real(data->fun(fields, loc, data->fun_data));\n+\n+  };\n+\n+}\n+\n+/***************************************************************/\n+/* given a volume, fill in the dims[] and directions[] arrays  */\n+/* describing the array slice needed to store field data for   */\n+/* all grid points in the volume.                              */\n+/*                                                             */\n+/* return value is rank of array slice.                        */\n+/*                                                             */\n+/* if caller_data is non-NULL, it should point to a            */\n+/* caller-allocated array_slice_data structure which will be   */\n+/* initialized appopriately for subsequent use in              */\n+/* get_array_slice.                                            */\n+/***************************************************************/\n+int fields::get_array_slice_dimensions(const volume &where, int dims[3], void *caller_data)\n+{\n+  am_now_working_on(ArraySlice);\n+\n+  // use a local data structure if the caller didn't provide one\n+  array_slice_data local_data;\n+  array_slice_data *data=(array_slice_data *)caller_data;\n+  if (data==0)\n+   data=&local_data;\n+\n+  data->min_corner = gv.round_vec(where.get_max_corner()) + one_ivec(gv.dim);\n+  data->max_corner = gv.round_vec(where.get_min_corner()) - one_ivec(gv.dim);\n+  data->num_chunks = 0;\n+\n+  loop_in_chunks(get_array_slice_dimensions_chunkloop,\n+                 (void *) data, where, Centered, true, true);\n+\n+  data->max_corner = max_to_all(data->max_corner);\n+  data->min_corner = -max_to_all(-data->min_corner); // i.e., min_to_all\n+  data->num_chunks = sum_to_all(data->num_chunks);\n+  if (data->num_chunks == 0 || !(data->min_corner <= data->max_corner))\n+    return 0; // no data to write;\n+\n+  int rank=0, slice_size=1;\n+  LOOP_OVER_DIRECTIONS(gv.dim, d) {\n+    if (rank >= 3) abort(\"too many dimensions in array_slice\");\n+    int n = (data->max_corner.in_direction(d)\n+\t     - data->min_corner.in_direction(d)) / 2 + 1;\n+    if (n > 1) {\n+      data->ds[rank] = d;\n+      dims[rank++] = n;\n+      slice_size *= n;\n+    }\n+  }\n+  data->rank=rank;\n+  data->slice_size=slice_size;\n+  finished_working();\n+\n+  return rank;\n+}\n+\n+/***************************************************************/\n+/***************************************************************/\n+/***************************************************************/\n+void *fields::do_get_array_slice(const volume &where,\n+                                 std::vector<component> components,\n+                                 field_function fun, void *fun_data,\n+                                 bool has_imag,\n+                                 void *vslice) {\n+\n+  am_now_working_on(ArraySlice);\n+\n+  /***************************************************************/\n+  /* call get_array_slice_dimensions to get slice dimensions and */\n+  /* partially initialze an array_slice_data struct              */\n+  /***************************************************************/\n+  int dims[3];\n+  array_slice_data data;\n+  int rank=get_array_slice_dimensions(where, dims, &data);\n+  int slice_size=data.slice_size;\n+  if (rank==0 || slice_size==0) return 0; // no data to write\n+\n+  cdouble *zslice;\n+  double *slice;\n+  if (vslice==0)\n+   { if (has_imag)\n+      { zslice = new cdouble[slice_size];\n+        vslice = (void *)zslice;\n+      } \n+     else\n+      { slice  = new double[slice_size];\n+        vslice = (void *)slice;\n+      };\n+   };\n+   \n+  data.vslice     = vslice;\n+  data.has_imag   = has_imag;\n+  data.fun        = fun ? fun : default_field_function;\n+  data.fun_data   = fun_data;\n+  data.components = components;\n+\n+  int num_components = components.size();\n+\n+  data.cS      = new component[num_components];\n+  data.ph      = new cdouble[num_components];\n+  data.fields  = new cdouble[num_components];\n+  \n+  data.offsets = new int[2 * num_components];\n+  for (int i = 0; i < 2 * num_components; ++i)\n+    data.offsets[i] = 0;\n+\n+  /* compute inverse-epsilon directions for computing Dielectric fields */\n+  data.ninveps = 0;\n+  bool needs_dielectric = false;\n+  for (int i = 0; i < num_components; ++i)\n+    if (components[i] == Dielectric) { needs_dielectric = true; break; }\n+  if (needs_dielectric) \n+    FOR_ELECTRIC_COMPONENTS(c) if (gv.has_field(c)) {\n+      if (data.ninveps == 3) abort(\"more than 3 field components??\");\n+      data.inveps_cs[data.ninveps] = c;\n+      data.inveps_ds[data.ninveps] = component_direction(c);\n+      ++data.ninveps;\n+    }\n+  \n+  /* compute inverse-mu directions for computing Permeability fields */\n+  data.ninvmu = 0;\n+  bool needs_permeability = false;\n+  for (int i = 0; i < num_components; ++i)\n+    if (components[i] == Permeability) { needs_permeability = true; break; }\n+  if (needs_permeability) \n+    FOR_MAGNETIC_COMPONENTS(c) if (gv.has_field(c)) {\n+      if (data.ninvmu == 3) abort(\"more than 3 field components??\");\n+      data.invmu_cs[data.ninvmu] = c;\n+      data.invmu_ds[data.ninvmu] = component_direction(c);\n+      ++data.ninvmu;\n+    }\n+ \n+  loop_in_chunks(get_array_slice_chunkloop, (void *) &data,\n+\t\t where, Centered, true, true);\n+\n+  /***************************************************************/\n+  /* repeatedly call sum_to_all to consolidate full array slice  */\n+  /* on all cores                                                */\n+  /***************************************************************/\n+#define BUFSIZE 1<<16 // use 64k buffer\n+  if (has_imag)\n+   { cdouble buffer[BUFSIZE];","path":"src/array_slice.cpp","position":375,"original_position":375,"commit_id":"c73f9d9bece0a3474fb22561082d3a953afa0584","original_commit_id":"c73f9d9bece0a3474fb22561082d3a953afa0584","user":{"login":"stevengj","id":2913679,"avatar_url":"https://avatars3.githubusercontent.com/u/2913679?v=4","gravatar_id":"","url":"https://api.github.com/users/stevengj","html_url":"https://github.com/stevengj","followers_url":"https://api.github.com/users/stevengj/followers","following_url":"https://api.github.com/users/stevengj/following{/other_user}","gists_url":"https://api.github.com/users/stevengj/gists{/gist_id}","starred_url":"https://api.github.com/users/stevengj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevengj/subscriptions","organizations_url":"https://api.github.com/users/stevengj/orgs","repos_url":"https://api.github.com/users/stevengj/repos","events_url":"https://api.github.com/users/stevengj/events{/privacy}","received_events_url":"https://api.github.com/users/stevengj/received_events","type":"User","site_admin":false},"body":"In general I would prefer not to stack-allocate here.  This is allocating 2¹⁶ * (16 bytes per `cdouble`) = 1MB for the buffer, which could easily overflow the stack size limit on some systems.  (e.g. the [default stack limit on Windows](https://software.intel.com/en-us/articles/memory-limits-applications-windows) is 1MB)\r\n\r\nUse `new`/`delete` instead.","created_at":"2017-09-28T15:38:27Z","updated_at":"2017-09-28T15:38:27Z","html_url":"https://github.com/stevengj/meep/pull/96#discussion_r141654906","pull_request_url":"https://api.github.com/repos/stevengj/meep/pulls/96","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/stevengj/meep/pulls/comments/141654906"},"html":{"href":"https://github.com/stevengj/meep/pull/96#discussion_r141654906"},"pull_request":{"href":"https://api.github.com/repos/stevengj/meep/pulls/96"}}},"pull_request":{"url":"https://api.github.com/repos/stevengj/meep/pulls/96","id":141423464,"html_url":"https://github.com/stevengj/meep/pull/96","diff_url":"https://github.com/stevengj/meep/pull/96.diff","patch_url":"https://github.com/stevengj/meep/pull/96.patch","issue_url":"https://api.github.com/repos/stevengj/meep/issues/96","number":96,"state":"open","locked":false,"title":"Arrayslice","user":{"login":"HomerReid","id":920123,"avatar_url":"https://avatars0.githubusercontent.com/u/920123?v=4","gravatar_id":"","url":"https://api.github.com/users/HomerReid","html_url":"https://github.com/HomerReid","followers_url":"https://api.github.com/users/HomerReid/followers","following_url":"https://api.github.com/users/HomerReid/following{/other_user}","gists_url":"https://api.github.com/users/HomerReid/gists{/gist_id}","starred_url":"https://api.github.com/users/HomerReid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HomerReid/subscriptions","organizations_url":"https://api.github.com/users/HomerReid/orgs","repos_url":"https://api.github.com/users/HomerReid/repos","events_url":"https://api.github.com/users/HomerReid/events{/privacy}","received_events_url":"https://api.github.com/users/HomerReid/received_events","type":"User","site_admin":false},"body":"The primary new routine here is\r\n\r\n````\r\n std::complex<double> *get_array_slice(const volume &where,\r\n                                        std::vector<component> components,\r\n                                        field_function fun=0, void *fun_data_=0,\r\n                                        std::complex<double> *slice=0);\r\n````\r\n\r\nThe implementation is similar to `output_hdf5`, but I rearranged the calling convention based on the following rationale:\r\n    -- the subvolume of interest, and the desired component(s), must always be specified and have no defaults, so those should come first\r\n    -- for components, I use a `std::vector` instead of pointer-plus-integer-valued-size-parameter as in `output_hdf5`\r\n    -- callers should be able to omit the `field_function` argument to request the identity function\r\n    -- callers should have the option of (a) passing a caller-allocated array to be filled in with the array-slice data, (b) having the function allocate and return a new array.\r\n\r\nFor option (a) above I added two new routines:\r\n     `get_array_slice_dimensions()`\r\n   and\r\n    `allocate_array_slice_buffer()`\r\n   with self-explanatory calling conventions.\r\n\r\nIf the caller passes a non-null buffer, it's not obvious how we would check to make sure its the correct size. Some options include\r\n    (a) don't check, creating the risk of core dump if the caller passes a buffer that's too small\r\n    (b) use a container like `std::vector<cdouble>` instead of a bare pointer\r\n    (c) use some sort of high-level multidimensional array construct that would play nicely with existing python libraries\r\n\r\nFor the time being I've gone with (a).\r\n\r\nTesting: Added `tests/array_slice_test.cpp` for testing. This is a modified version of `h5test.cpp`. The implementation is not complete, but the idea is to use the same volumes and subvolumes as h5test.cpp and compare the resulting array slices with arrays read in from hdf5 files produced by running `h5test`.\r\n\r\nUsage example:\r\n````\r\n int dims[3], dirs[3];\r\n int rank=f.get_array_slice_dimensions(subvolume, dims, dirs);\r\n\r\n std::vector<component> components(Ez);\r\n components.push_back(Hz);\r\n cdouble *slice=f.get_array_slice(subvolume, components);\r\n\r\n int NC=components.size();\r\n int NX=dims[0];\r\n int NY=dims[1];\r\n for(int nx=0; nx<NX; nx++)\r\n   for(int ny=0; ny<NY; ny++)\r\n    printf(\"At (%i,%i): (Ez,Hz)=(%e,%e)\\n\",nx,ny,\r\n               real(slice[0*NX*NY + nx*NY + ny]),\r\n               real(slice[1*NX*NY + nx*NY + ny]));\r\n```\r\n","created_at":"2017-09-16T00:19:18Z","updated_at":"2017-09-28T15:38:27Z","closed_at":null,"merged_at":null,"merge_commit_sha":"479306e313bad80d0fafb38ee63cf1d0721a8528","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/stevengj/meep/pulls/96/commits","review_comments_url":"https://api.github.com/repos/stevengj/meep/pulls/96/comments","review_comment_url":"https://api.github.com/repos/stevengj/meep/pulls/comments{/number}","comments_url":"https://api.github.com/repos/stevengj/meep/issues/96/comments","statuses_url":"https://api.github.com/repos/stevengj/meep/statuses/c73f9d9bece0a3474fb22561082d3a953afa0584","head":{"label":"HomerReid:arrayslice","ref":"arrayslice","sha":"c73f9d9bece0a3474fb22561082d3a953afa0584","user":{"login":"HomerReid","id":920123,"avatar_url":"https://avatars0.githubusercontent.com/u/920123?v=4","gravatar_id":"","url":"https://api.github.com/users/HomerReid","html_url":"https://github.com/HomerReid","followers_url":"https://api.github.com/users/HomerReid/followers","following_url":"https://api.github.com/users/HomerReid/following{/other_user}","gists_url":"https://api.github.com/users/HomerReid/gists{/gist_id}","starred_url":"https://api.github.com/users/HomerReid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HomerReid/subscriptions","organizations_url":"https://api.github.com/users/HomerReid/orgs","repos_url":"https://api.github.com/users/HomerReid/repos","events_url":"https://api.github.com/users/HomerReid/events{/privacy}","received_events_url":"https://api.github.com/users/HomerReid/received_events","type":"User","site_admin":false},"repo":{"id":81499515,"name":"meep","full_name":"HomerReid/meep","owner":{"login":"HomerReid","id":920123,"avatar_url":"https://avatars0.githubusercontent.com/u/920123?v=4","gravatar_id":"","url":"https://api.github.com/users/HomerReid","html_url":"https://github.com/HomerReid","followers_url":"https://api.github.com/users/HomerReid/followers","following_url":"https://api.github.com/users/HomerReid/following{/other_user}","gists_url":"https://api.github.com/users/HomerReid/gists{/gist_id}","starred_url":"https://api.github.com/users/HomerReid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HomerReid/subscriptions","organizations_url":"https://api.github.com/users/HomerReid/orgs","repos_url":"https://api.github.com/users/HomerReid/repos","events_url":"https://api.github.com/users/HomerReid/events{/privacy}","received_events_url":"https://api.github.com/users/HomerReid/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/HomerReid/meep","description":"free finite-difference time-domain (FDTD) software for electromagnetic simulations","fork":true,"url":"https://api.github.com/repos/HomerReid/meep","forks_url":"https://api.github.com/repos/HomerReid/meep/forks","keys_url":"https://api.github.com/repos/HomerReid/meep/keys{/key_id}","collaborators_url":"https://api.github.com/repos/HomerReid/meep/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/HomerReid/meep/teams","hooks_url":"https://api.github.com/repos/HomerReid/meep/hooks","issue_events_url":"https://api.github.com/repos/HomerReid/meep/issues/events{/number}","events_url":"https://api.github.com/repos/HomerReid/meep/events","assignees_url":"https://api.github.com/repos/HomerReid/meep/assignees{/user}","branches_url":"https://api.github.com/repos/HomerReid/meep/branches{/branch}","tags_url":"https://api.github.com/repos/HomerReid/meep/tags","blobs_url":"https://api.github.com/repos/HomerReid/meep/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/HomerReid/meep/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/HomerReid/meep/git/refs{/sha}","trees_url":"https://api.github.com/repos/HomerReid/meep/git/trees{/sha}","statuses_url":"https://api.github.com/repos/HomerReid/meep/statuses/{sha}","languages_url":"https://api.github.com/repos/HomerReid/meep/languages","stargazers_url":"https://api.github.com/repos/HomerReid/meep/stargazers","contributors_url":"https://api.github.com/repos/HomerReid/meep/contributors","subscribers_url":"https://api.github.com/repos/HomerReid/meep/subscribers","subscription_url":"https://api.github.com/repos/HomerReid/meep/subscription","commits_url":"https://api.github.com/repos/HomerReid/meep/commits{/sha}","git_commits_url":"https://api.github.com/repos/HomerReid/meep/git/commits{/sha}","comments_url":"https://api.github.com/repos/HomerReid/meep/comments{/number}","issue_comment_url":"https://api.github.com/repos/HomerReid/meep/issues/comments{/number}","contents_url":"https://api.github.com/repos/HomerReid/meep/contents/{+path}","compare_url":"https://api.github.com/repos/HomerReid/meep/compare/{base}...{head}","merges_url":"https://api.github.com/repos/HomerReid/meep/merges","archive_url":"https://api.github.com/repos/HomerReid/meep/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/HomerReid/meep/downloads","issues_url":"https://api.github.com/repos/HomerReid/meep/issues{/number}","pulls_url":"https://api.github.com/repos/HomerReid/meep/pulls{/number}","milestones_url":"https://api.github.com/repos/HomerReid/meep/milestones{/number}","notifications_url":"https://api.github.com/repos/HomerReid/meep/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/HomerReid/meep/labels{/name}","releases_url":"https://api.github.com/repos/HomerReid/meep/releases{/id}","deployments_url":"https://api.github.com/repos/HomerReid/meep/deployments","created_at":"2017-02-09T22:05:00Z","updated_at":"2017-02-09T22:05:02Z","pushed_at":"2017-09-28T02:58:58Z","git_url":"git://github.com/HomerReid/meep.git","ssh_url":"git@github.com:HomerReid/meep.git","clone_url":"https://github.com/HomerReid/meep.git","svn_url":"https://github.com/HomerReid/meep","homepage":null,"size":6984,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"stevengj:master","ref":"master","sha":"9543c592216a84c1694b69e4fb56316e2c15e0f5","user":{"login":"stevengj","id":2913679,"avatar_url":"https://avatars3.githubusercontent.com/u/2913679?v=4","gravatar_id":"","url":"https://api.github.com/users/stevengj","html_url":"https://github.com/stevengj","followers_url":"https://api.github.com/users/stevengj/followers","following_url":"https://api.github.com/users/stevengj/following{/other_user}","gists_url":"https://api.github.com/users/stevengj/gists{/gist_id}","starred_url":"https://api.github.com/users/stevengj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevengj/subscriptions","organizations_url":"https://api.github.com/users/stevengj/orgs","repos_url":"https://api.github.com/users/stevengj/repos","events_url":"https://api.github.com/users/stevengj/events{/privacy}","received_events_url":"https://api.github.com/users/stevengj/received_events","type":"User","site_admin":false},"repo":{"id":18223131,"name":"meep","full_name":"stevengj/meep","owner":{"login":"stevengj","id":2913679,"avatar_url":"https://avatars3.githubusercontent.com/u/2913679?v=4","gravatar_id":"","url":"https://api.github.com/users/stevengj","html_url":"https://github.com/stevengj","followers_url":"https://api.github.com/users/stevengj/followers","following_url":"https://api.github.com/users/stevengj/following{/other_user}","gists_url":"https://api.github.com/users/stevengj/gists{/gist_id}","starred_url":"https://api.github.com/users/stevengj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevengj/subscriptions","organizations_url":"https://api.github.com/users/stevengj/orgs","repos_url":"https://api.github.com/users/stevengj/repos","events_url":"https://api.github.com/users/stevengj/events{/privacy}","received_events_url":"https://api.github.com/users/stevengj/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stevengj/meep","description":"free finite-difference time-domain (FDTD) software for electromagnetic simulations","fork":false,"url":"https://api.github.com/repos/stevengj/meep","forks_url":"https://api.github.com/repos/stevengj/meep/forks","keys_url":"https://api.github.com/repos/stevengj/meep/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stevengj/meep/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stevengj/meep/teams","hooks_url":"https://api.github.com/repos/stevengj/meep/hooks","issue_events_url":"https://api.github.com/repos/stevengj/meep/issues/events{/number}","events_url":"https://api.github.com/repos/stevengj/meep/events","assignees_url":"https://api.github.com/repos/stevengj/meep/assignees{/user}","branches_url":"https://api.github.com/repos/stevengj/meep/branches{/branch}","tags_url":"https://api.github.com/repos/stevengj/meep/tags","blobs_url":"https://api.github.com/repos/stevengj/meep/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stevengj/meep/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stevengj/meep/git/refs{/sha}","trees_url":"https://api.github.com/repos/stevengj/meep/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stevengj/meep/statuses/{sha}","languages_url":"https://api.github.com/repos/stevengj/meep/languages","stargazers_url":"https://api.github.com/repos/stevengj/meep/stargazers","contributors_url":"https://api.github.com/repos/stevengj/meep/contributors","subscribers_url":"https://api.github.com/repos/stevengj/meep/subscribers","subscription_url":"https://api.github.com/repos/stevengj/meep/subscription","commits_url":"https://api.github.com/repos/stevengj/meep/commits{/sha}","git_commits_url":"https://api.github.com/repos/stevengj/meep/git/commits{/sha}","comments_url":"https://api.github.com/repos/stevengj/meep/comments{/number}","issue_comment_url":"https://api.github.com/repos/stevengj/meep/issues/comments{/number}","contents_url":"https://api.github.com/repos/stevengj/meep/contents/{+path}","compare_url":"https://api.github.com/repos/stevengj/meep/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stevengj/meep/merges","archive_url":"https://api.github.com/repos/stevengj/meep/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stevengj/meep/downloads","issues_url":"https://api.github.com/repos/stevengj/meep/issues{/number}","pulls_url":"https://api.github.com/repos/stevengj/meep/pulls{/number}","milestones_url":"https://api.github.com/repos/stevengj/meep/milestones{/number}","notifications_url":"https://api.github.com/repos/stevengj/meep/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stevengj/meep/labels{/name}","releases_url":"https://api.github.com/repos/stevengj/meep/releases{/id}","deployments_url":"https://api.github.com/repos/stevengj/meep/deployments","created_at":"2014-03-28T18:59:52Z","updated_at":"2017-09-27T15:31:47Z","pushed_at":"2017-09-28T02:58:59Z","git_url":"git://github.com/stevengj/meep.git","ssh_url":"git@github.com:stevengj/meep.git","clone_url":"https://github.com/stevengj/meep.git","svn_url":"https://github.com/stevengj/meep","homepage":null,"size":6581,"stargazers_count":111,"watchers_count":111,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":56,"mirror_url":null,"open_issues_count":25,"forks":56,"open_issues":25,"watchers":111,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/stevengj/meep/pulls/96"},"html":{"href":"https://github.com/stevengj/meep/pull/96"},"issue":{"href":"https://api.github.com/repos/stevengj/meep/issues/96"},"comments":{"href":"https://api.github.com/repos/stevengj/meep/issues/96/comments"},"review_comments":{"href":"https://api.github.com/repos/stevengj/meep/pulls/96/comments"},"review_comment":{"href":"https://api.github.com/repos/stevengj/meep/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/stevengj/meep/pulls/96/commits"},"statuses":{"href":"https://api.github.com/repos/stevengj/meep/statuses/c73f9d9bece0a3474fb22561082d3a953afa0584"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"stevengj"}}