{"action":"created","comment":{"url":"https://api.github.com/repos/mit-crpg/openmc/pulls/comments/71927334","id":71927334,"diff_hunk":"@@ -0,0 +1,396 @@\n+from collections import Iterable\n+from difflib import get_close_matches\n+from numbers import Real\n+from warnings import warn\n+\n+import numpy as np\n+import h5py\n+\n+import openmc.checkvalue as cv\n+from .ace import Table, get_table\n+from .angle_energy import AngleEnergy\n+from .function import Tabulated1D\n+from .correlated import CorrelatedAngleEnergy\n+from openmc.stats import Discrete, Tabular\n+\n+\n+_THERMAL_NAMES = {'al': 'c_Al27', 'al27': 'c_Al27',\n+                  'be': 'c_Be',\n+                  'bebeo': 'c_Be_in_BeO', 'be-o': 'c_Be_in_BeO',\n+                  'benz': 'c_Benzine',\n+                  'cah': 'c_Ca_in_CaH2',\n+                  'dd2o': 'c_D_in_D2O', 'hwtr': 'c_D_in_D2O',\n+                  'fe': 'c_Fe56', 'fe56': 'c_Fe56',\n+                  'graph': 'c_Graphite', 'grph': 'c_Graphite',\n+                  'hca': 'c_H_in_CaH2',\n+                  'hch2': 'c_H_in_CH2', 'poly': 'c_H_in_CH2',\n+                  'hh2o': 'c_H_in_H2O', 'lwtr': 'c_H_in_H2O',\n+                  'hzrh': 'c_H_in_ZrH', 'h-zr': 'c_H_in_ZrH',\n+                  'lch4': 'c_liquid_CH4', 'lmeth': 'c_liquid_CH4',\n+                  'mg': 'c_Mg24',\n+                  'obeo': 'c_O_in_BeO', 'o-be': 'c_O_in_BeO',\n+                  'orthod': 'c_ortho_D', 'dortho': 'c_ortho_D',\n+                  'orthoh': 'c_ortho_H', 'hortho': 'c_ortho_H',\n+                  'ouo2': 'c_O_in_UO2', 'o2-u': 'c_O_in_UO2',\n+                  'parad': 'c_para_D', 'dpara': 'c_para_D',\n+                  'parah': 'c_para_H', 'hpara': 'c_para_H',\n+                  'sch4': 'c_solid_CH4', 'smeth': 'c_solid_CH4',\n+                  'uuo2': 'c_U_in_UO2', 'u-o2': 'c_U_in_UO2',\n+                  'zrzrh': 'c_Zr_in_ZrH', 'zr-h': 'c_Zr_in_ZrH'}\n+\n+\n+class CoherentElastic(object):\n+    r\"\"\"Coherent elastic scattering data from a crystalline material\n+\n+    Parameters\n+    ----------\n+    bragg_edges : Iterable of float\n+        Bragg edge energies in MeV\n+    factors : Iterable of float\n+        Partial sum of structure factors, :math:`\\sum\\limits_{i=1}^{E_i<E} S_i`\n+\n+    Attributes\n+    ----------\n+    bragg_edges : Iterable of float\n+        Bragg edge energies in MeV\n+    factors : Iterable of float\n+        Partial sum of structure factors, :math:`\\sum\\limits_{i=1}^{E_i<E} S_i`\n+\n+    \"\"\"\n+\n+    def __init__(self, bragg_edges, factors):\n+        self.bragg_edges = bragg_edges\n+        self.factors = factors\n+\n+    def __call__(self, E):\n+        if isinstance(E, Iterable):\n+            E = np.asarray(E)\n+        idx = np.searchsorted(self.bragg_edges, E)\n+        return self.factors[idx]/E\n+\n+    def __len__(self):\n+        return len(self.bragg_edges)\n+\n+    @property\n+    def bragg_edges(self):\n+        return self._bragg_edges\n+\n+    @property\n+    def factors(self):\n+        return self._factors\n+\n+    @bragg_edges.setter\n+    def bragg_edges(self, bragg_edges):\n+        cv.check_type('Bragg edges', bragg_edges, Iterable, Real)\n+        self._bragg_edges = np.asarray(bragg_edges)\n+\n+    @factors.setter\n+    def factors(self, factors):\n+        cv.check_type('structure factor cumulative sums', factors,\n+                      Iterable, Real)\n+        self._factors = np.asarray(factors)\n+\n+    def to_hdf5(self, group, name):\n+        \"\"\"Write coherent elastic scattering to an HDF5 group\n+\n+        Parameters\n+        ----------\n+        group : h5py.Group\n+            HDF5 group to write to\n+        name : str\n+            Name of the dataset to create\n+\n+        \"\"\"\n+        dataset = group.create_dataset(name, data=np.vstack(\n+            [self.bragg_edges, self.factors]))\n+        dataset.attrs['type'] = np.string_('bragg')\n+\n+    @classmethod\n+    def from_hdf5(cls, dataset):\n+        \"\"\"Read coherent elastic scattering from an HDF5 dataset\n+\n+        Parameters\n+        ----------\n+        group : h5py.Dataset\n+            HDF5 group to write to\n+\n+        Returns\n+        -------\n+        openmc.data.CoherentElastic\n+            Coherent elastic scattering cross section\n+\n+        \"\"\"\n+        bragg_edges = dataset.value[0, :]\n+        factors = dataset.value[1, :]\n+        return cls(bragg_edges, factors)\n+\n+\n+class ThermalScattering(object):\n+    \"\"\"A ThermalScattering object contains thermal scattering data as represented by\n+    an S(alpha, beta) table.\n+\n+    Parameters\n+    ----------\n+    name : str\n+        ZAID identifier of the table, e.g. lwtr.10t.\n+    atomic_weight_ratio : float\n+        Atomic mass ratio of the target nuclide.\n+    temperature : float\n+        Temperature of the target nuclide in eV.\n+\n+    Attributes\n+    ----------\n+    atomic_weight_ratio : float\n+        Atomic mass ratio of the target nuclide.\n+    elastic_xs : openmc.data.Tabulated1D or openmc.data.CoherentElastic\n+        Elastic scattering cross section derived in the coherent or incoherent\n+        approximation\n+    inelastic_xs : openmc.data.Tabulated1D\n+        Inelastic scattering cross section derived in the incoherent\n+        approximation\n+    name : str\n+        Name of the table, e.g. lwtr.20t.\n+    temperature : float\n+        Temperature of the target nuclide in eV.\n+    zaids : Iterable of int\n+        ZAID identifiers that the thermal scattering data applies to\n+\n+    \"\"\"\n+\n+    def __init__(self, name, atomic_weight_ratio, temperature):\n+        self.name = name\n+        self.atomic_weight_ratio = atomic_weight_ratio\n+        self.temperature = temperature\n+        self.elastic_xs = None\n+        self.elastic_mu_out = None\n+        self.inelastic_xs = None\n+        self.inelastic_e_out = None\n+        self.inelastic_mu_out = None\n+        self.secondary_mode = None\n+        self.zaids = []\n+\n+    def __repr__(self):\n+        if hasattr(self, 'name'):\n+            return \"<Thermal Scattering Data: {0}>\".format(self.name)\n+        else:\n+            return \"<Thermal Scattering Data>\"\n+\n+    def export_to_hdf5(self, path, mode='a'):\n+        \"\"\"Export table to an HDF5 file.\n+\n+        Parameters\n+        ----------\n+        path : str\n+            Path to write HDF5 file to\n+        mode : {'r', r+', 'w', 'x', 'a'}\n+            Mode that is used to open the HDF5 file. This is the second argument\n+            to the :class:`h5py.File` constructor.\n+\n+        \"\"\"\n+\n+        f = h5py.File(path, mode, libver='latest')\n+\n+        # Write basic data\n+        g = f.create_group(self.name)\n+        g.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio\n+        g.attrs['temperature'] = self.temperature\n+        g.attrs['zaids'] = self.zaids\n+\n+        # Write thermal elastic scattering\n+        if self.elastic_xs is not None:\n+            elastic_group = g.create_group('elastic')\n+            self.elastic_xs.to_hdf5(elastic_group, 'xs')\n+            if self.elastic_mu_out is not None:\n+                elastic_group.create_dataset('mu_out', data=self.elastic_mu_out)\n+\n+        # Write thermal inelastic scattering\n+        if self.inelastic_xs is not None:\n+            inelastic_group = g.create_group('inelastic')\n+            self.inelastic_xs.to_hdf5(inelastic_group, 'xs')\n+            inelastic_group.attrs['secondary_mode'] = np.string_(self.secondary_mode)\n+            if self.secondary_mode in ('equal', 'skewed'):\n+                inelastic_group.create_dataset('energy_out', data=self.inelastic_e_out)\n+                inelastic_group.create_dataset('mu_out', data=self.inelastic_mu_out)\n+            elif self.secondary_mode == 'continuous':\n+                self.inelastic_dist.to_hdf5(inelastic_group)\n+\n+    @classmethod\n+    def from_hdf5(cls, group):\n+        \"\"\"Generate thermal scattering data from HDF5 group\n+\n+        Parameters\n+        ----------\n+        group : h5py.Group\n+            HDF5 group to read from\n+\n+        Returns\n+        -------\n+        openmc.data.ThermalScattering\n+            Neutron thermal scattering data\n+\n+        \"\"\"\n+        name = group.name[1:]\n+        atomic_weight_ratio = group.attrs['atomic_weight_ratio']\n+        temperature = group.attrs['temperature']\n+        table = cls(name, atomic_weight_ratio, temperature)\n+        table.zaids = group.attrs['zaids']\n+\n+        # Read thermal elastic scattering\n+        if 'elastic' in group:\n+            elastic_group = group['elastic']\n+\n+            # Cross section\n+            elastic_xs_type = elastic_group['xs'].attrs['type'].decode()\n+            if elastic_xs_type == 'tab1':\n+                table.elastic_xs = Tabulated1D.from_hdf5(elastic_group['xs'])\n+            elif elastic_xs_type == 'bragg':\n+                table.elastic_xs = CoherentElastic.from_hdf5(elastic_group['xs'])\n+\n+            # Angular distribution\n+            if 'mu_out' in elastic_group:\n+                table.elastic_mu_out = elastic_group['mu_out'].value\n+\n+        # Read thermal inelastic scattering\n+        if 'inelastic' in group:\n+            inelastic_group = group['inelastic']\n+            table.secondary_mode = inelastic_group.attrs['secondary_mode'].decode()\n+            table.inelastic_xs = Tabulated1D.from_hdf5(inelastic_group['xs'])\n+            if table.secondary_mode in ('equal', 'skewed'):\n+                table.inelastic_e_out = inelastic_group['energy_out']\n+                table.inelastic_mu_out = inelastic_group['mu_out']\n+            elif table.secondary_mode == 'continuous':\n+                table.inelastic_dist = AngleEnergy.from_hdf5(inelastic_group)\n+\n+        return table\n+\n+    @classmethod\n+    def from_ace(cls, ace_or_filename, name=None):\n+        \"\"\"Generate thermal scattering data from an ACE table\n+\n+        Parameters\n+        ----------\n+        ace : openmc.data.ace.Table or str\n+            ACE table to read from. If given as a string, it is assumed to be\n+            the filename for the ACE file.\n+        name : str\n+            GND-conforming name of the material, e.g. c_H_in_H2O. If none is\n+            passed, the appropriate name is guessed based on the name of the ACE\n+            table.\n+\n+        Returns\n+        -------\n+        openmc.data.ThermalScattering\n+            Thermal scattering data\n+\n+        \"\"\"\n+        if isinstance(ace_or_filename, Table):\n+            ace = ace_or_filename\n+        else:\n+            ace = get_table(ace_or_filename)\n+\n+        # Get new name that is GND-consistent\n+        ace_name, xs = ace.name.split('.')\n+        if name is None:\n+            if ace_name.lower() in _THERMAL_NAMES:\n+                name = _THERMAL_NAMES[ace_name.lower()] + '.' + xs\n+            else:\n+                # Make an educated guess?? This actually works well for JEFF-3.2\n+                # which stupidly uses names like lw00.32t, lw01.32t, etc. for\n+                # different temperatures","path":"openmc/data/thermal.py","position":299,"original_position":299,"commit_id":"3d68c07625e33cd64188df03ee03e9c31b3d4b74","original_commit_id":"3d68c07625e33cd64188df03ee03e9c31b3d4b74","user":{"login":"smharper","id":4622797,"avatar_url":"https://avatars.githubusercontent.com/u/4622797?v=3","gravatar_id":"","url":"https://api.github.com/users/smharper","html_url":"https://github.com/smharper","followers_url":"https://api.github.com/users/smharper/followers","following_url":"https://api.github.com/users/smharper/following{/other_user}","gists_url":"https://api.github.com/users/smharper/gists{/gist_id}","starred_url":"https://api.github.com/users/smharper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smharper/subscriptions","organizations_url":"https://api.github.com/users/smharper/orgs","repos_url":"https://api.github.com/users/smharper/repos","events_url":"https://api.github.com/users/smharper/events{/privacy}","received_events_url":"https://api.github.com/users/smharper/received_events","type":"User","site_admin":false},"body":"JEFF is so sloppy :(  Makes me question how much I can trust their data...","created_at":"2016-07-22T18:49:14Z","updated_at":"2016-07-22T18:49:14Z","html_url":"https://github.com/mit-crpg/openmc/pull/684#discussion_r71927334","pull_request_url":"https://api.github.com/repos/mit-crpg/openmc/pulls/684","_links":{"self":{"href":"https://api.github.com/repos/mit-crpg/openmc/pulls/comments/71927334"},"html":{"href":"https://github.com/mit-crpg/openmc/pull/684#discussion_r71927334"},"pull_request":{"href":"https://api.github.com/repos/mit-crpg/openmc/pulls/684"}}},"pull_request":{"url":"https://api.github.com/repos/mit-crpg/openmc/pulls/684","id":77668673,"html_url":"https://github.com/mit-crpg/openmc/pull/684","diff_url":"https://github.com/mit-crpg/openmc/pull/684.diff","patch_url":"https://github.com/mit-crpg/openmc/pull/684.patch","issue_url":"https://api.github.com/repos/mit-crpg/openmc/issues/684","number":684,"state":"open","locked":false,"title":"'openmc.data' Package and HDF5 Nuclear Data","user":{"login":"paulromano","id":743095,"avatar_url":"https://avatars.githubusercontent.com/u/743095?v=3","gravatar_id":"","url":"https://api.github.com/users/paulromano","html_url":"https://github.com/paulromano","followers_url":"https://api.github.com/users/paulromano/followers","following_url":"https://api.github.com/users/paulromano/following{/other_user}","gists_url":"https://api.github.com/users/paulromano/gists{/gist_id}","starred_url":"https://api.github.com/users/paulromano/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paulromano/subscriptions","organizations_url":"https://api.github.com/users/paulromano/orgs","repos_url":"https://api.github.com/users/paulromano/repos","events_url":"https://api.github.com/users/paulromano/events{/privacy}","received_events_url":"https://api.github.com/users/paulromano/received_events","type":"User","site_admin":false},"body":"In what is likely to be one of the largest changes in OpenMC in its 5 year history, this pull request changes OpenMC to use a new native HDF5 nuclear data format. Motivation for this change was discussed in more detail in #599, so I won't go to great lengths to describe why we're doing this.\r\n\r\n## Python API\r\n\r\nThe major addition in this PR is a new `openmc.data` package in our Python API which allows us to convert ACE (and HDF5) into a hierarchy of Python objects in memory. These objects can then be written out to HDF5. It's possible to go back and forth from Python objects to HDF5 and no information is lost. The basic usage is as follows:\r\n\r\n```Python\r\nu235 = openmc.data.IncidentNeutron.from_ace('path_to_ace_file')\r\nthermal_scatt = openmc.data.ThermalScattering.from_ace('path_to_thermal_ace')\r\n```\r\n\r\nThe `from_ace()` factory method assumes the library only has one ACE table in it. If you have an ACE library with multiple tables (e.g., the MCNP5 endf70[a-k] files), you can pick out a single table as follows:\r\n\r\n```Python\r\nlib = openmc.data.ace.Library('endf70a')\r\nh1 = openmc.data.IncidentNeutron.from_ace(lib.tables[0])\r\n```\r\n\r\nI won't go into too much gory detail on the class hierarchy. The refactor of neutron data within the Fortran source was designed to match what I have on the Python side, so if you're familiar with the Fortran derived type hierarchy that was introduced in #557 and #610, it should make sense. Basically, an `IncidentNeutron` has a dictionary containing `Reaction`s, each `Reaction` has `Product`s, and `Product`s have subclasses of `AngleEnergy` (`UncorrelatedAngleEnergy`, `KalbachMann`, etc.). At the lowest level, univariate probability distributions come from `openmc.stats` which is also used for specifying source distributions. If you're not at all familiar, the best place to start out is the nuclear data notebook that I've added in this PR.\r\n\r\nThere's also a new `openmc.data.DataLibrary` object that is used to create cross_sections.xml files. I'll talk more about changes to that file in the next section, but the basic usage is:\r\n\r\n```Python\r\nlibrary = openmc.data.DataLibrary()\r\nlibrary.register_file('Am241.h5')\r\nlibrary.register_file('U235.h5')\r\n...\r\nlibrary.export_to_xml()\r\n```\r\n\r\n## Fortran changes\r\n\r\nMost of the hard work here was already done in #557 and #610. All of the derived types under `Nuclide` now have `from_hdf5` type-bound procedures. The XsListing type is replaced by Library and the corresponding global array is gone. Instead, local variables are used when reading cross section data. The flow is a little bit different, with the main call to read cross section data now occurring in input_xml rather than initialize.\r\n\r\nSetting up data for a nuclide that doesn't exist in the HDF5 data, e.g. total cross sections, nu-fission, etc., is done in `Nuclide % create_derived`. In the future we could consider off-loading this responsibility to the Python API.\r\n\r\n## User-facing changes\r\n\r\nThe most immediately noticeable change is that the nuclide naming scheme has been changed to adopt the proposed GND convention (also discussed in #599). So, Am-242m is now Am242_m1. Water (HH2O, lwtr) is now c_H_in_H2O. To ease the burden on users, the openmc-update-inputs script can now update materials.xml files with the appropriate changes. Unfortunately, if you're using the Python API to create your inputs, you'll have to manually update how you're creating nuclides/materials. But, if you're advanced enough to be using the Python API, you can probably handle a few 'sed's or regex replacements :)\r\n\r\nThe other big change is that cross_sections.xml looks a lot different now. It now looks like:\r\n\r\n```XML\r\n<?xml version='1.0' encoding='utf-8'?>\r\n<cross_sections>\r\n    <library materials=\"Ac225.71c\" path=\"Ac225_71c.h5\" type=\"neutron\" />\r\n    <library materials=\"Ac226.71c\" path=\"Ac226_71c.h5\" type=\"neutron\" />\r\n    <library materials=\"Ac227.71c\" path=\"Ac227_71c.h5\" type=\"neutron\" />\r\n    <library materials=\"Ag107.71c\" path=\"Ag107_71c.h5\" type=\"neutron\" />\r\n    <library materials=\"Ag109.71c\" path=\"Ag109_71c.h5\" type=\"neutron\" />\r\n    <library materials=\"Ag110_m1.71c\" path=\"Ag110_m1_71c.h5\" type=\"neutron\" />\r\n...\r\n    <library materials=\"c_para_D.71t\" path=\"c_para_D_71t.h5\" type=\"thermal\" />\r\n    <library materials=\"c_para_H.71t\" path=\"c_para_H_71t.h5\" type=\"thermal\" />\r\n    <library materials=\"c_solid_CH4.71t\" path=\"c_solid_CH4_71t.h5\" type=\"thermal\" />\r\n    <library materials=\"c_U_in_UO2.71t\" path=\"c_U_in_UO2_71t.h5\" type=\"thermal\" />\r\n    <library materials=\"c_Zr_in_ZrH.71t\" path=\"c_Zr_in_ZrH_71t.h5\" type=\"thermal\" />\r\n</cross_sections>\r\n```\r\n\r\nThe idea is that a single HDF5 library can contain multiple materials (although at present they must be of the same type). You'll notice we don't have name/alias pairs, no AWR, no ZAIDs, no metastable information. All of that is in the file itself, so there's no risk of having conflicting data.\r\n\r\nI fully realize that it is going to be a pain in the ass for everyone to generate new HDF5 libraries when their environment is already set up nicely. If you're using NNDC libraries, it's not a big deal at all -- get_nndc_data.py has been updated and will create a new HDF5 library for you. Otherwise, the new openmc-ace-to-hdf5 script handles what I consider to be common cases:\r\n\r\n- Creating a library from a set of ACE files: `openmc-ace-to-hdf5 ace1 ace2 ace3`\r\n- Creating a library from an existing cross_sections.xml: `openmc-ace-to-hdf5 --xml cross_sections.xml`\r\n- Creating a library from an MCNP xsdir file: `openmc-ace-to-hdf5 --metastable mcnp --xsdir /opt/mcnp/data/xsdir`\r\n- Creating a library from a Serpent xsdata file: `openmc-ace-to-hdf5 --xsdata /opt/serpent/data/xsdata`\r\n\r\nAs you can see, it's pretty straightforward, and I've tried to test it out a bit to make sure things work OK. It works with the MCNP5 endf70[a-k] libraries, it works with MCNP6's endf71x library, and it sort-of works with some JEFF data.\r\n\r\n## Metastable States\r\n\r\nI will forever curse the original creators of the ACE format for not including any information about the metastable state of a nuclide. During the course of developing our new HDF5 libraries, I agonized for hours on how I wanted to handle the messiness of assigning metastable states based on ZAIDs. I ended up doing the following:\r\n\r\n- `openmc.data.IncidentNeutron.from_ace(...)` has a metastable argument that takes either 'nndc' or 'mcnp', indicating what ZAID convention is to be used. They are essentially the same except that MCNP libraries use 95242 as the first metastable state and 95642 as the ground.\r\n- As you may have noticed before, `openmc-ace-to-hdf5` has a --metastable optional argument which controls what is passed to `from_ace(...)`.\r\n\r\nIf this doesn't suit your needs and you have some oddball ZAID naming scheme for metastables, well you're just going to have to adjust the nuclide name and metastable attribute inside the HDF5 data once it's generated.\r\n\r\nTesting\r\n-------\r\n\r\nYou may notice some hacks I put in to get test results to match, e.g., I originally didn't want to store the cumulative distribution values for univariate densities in the HDF5 files, but if you try to regenerate them, they're not exactly the same (NJOY loses precision somewhere), so I ended up including those values in the HDF5 data. We can consider removing them later (along with a few other hacks that have been put in over time). A few results changed by virtue of the fact that they included nuclide names (U-235 -> U235).\r\n\r\nAs far as having Travis get the NNDC HDF5 data needed for testing, I've moved away from our existing method of using a github repository. Instead, I'm hosting the data in Box and Travis downloads it from there using a publicly shared link. My Box account has a bandwidth limit of 1 TB/month which shouldn't be an issue because I have Travis cache the data so actual downloads from Box should be infrequent. For point of reference, the .tar.xz is about 350 MB.\r\n\r\nFuture Work\r\n-----------\r\n\r\n- Handle temperature-dependent data more gracefully (i.e., get away from stupid nuclide suffixes)\r\n- Merge multipole data to have single library for a given nuclide?\r\n- Refactor `openmc.data.Tabulated1D` to be more GND-like\r\n- Extending the capabilities in the Python API so that we're able to pull in ENDF data using `from_endf` factory methods\r\n- Extending to store photoatomic/photonuclear reaction data\r\n- Use the photon production data (it's there in the HDF5!) to enable coupled neutron/photon transport calculations.","created_at":"2016-07-15T19:51:50Z","updated_at":"2016-07-22T18:49:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"952361fa4aa46529cbdd0d7c76e2dec640efc41a","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/mit-crpg/openmc/pulls/684/commits","review_comments_url":"https://api.github.com/repos/mit-crpg/openmc/pulls/684/comments","review_comment_url":"https://api.github.com/repos/mit-crpg/openmc/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mit-crpg/openmc/issues/684/comments","statuses_url":"https://api.github.com/repos/mit-crpg/openmc/statuses/3d68c07625e33cd64188df03ee03e9c31b3d4b74","head":{"label":"paulromano:pyapi-data","ref":"pyapi-data","sha":"3d68c07625e33cd64188df03ee03e9c31b3d4b74","user":{"login":"paulromano","id":743095,"avatar_url":"https://avatars.githubusercontent.com/u/743095?v=3","gravatar_id":"","url":"https://api.github.com/users/paulromano","html_url":"https://github.com/paulromano","followers_url":"https://api.github.com/users/paulromano/followers","following_url":"https://api.github.com/users/paulromano/following{/other_user}","gists_url":"https://api.github.com/users/paulromano/gists{/gist_id}","starred_url":"https://api.github.com/users/paulromano/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paulromano/subscriptions","organizations_url":"https://api.github.com/users/paulromano/orgs","repos_url":"https://api.github.com/users/paulromano/repos","events_url":"https://api.github.com/users/paulromano/events{/privacy}","received_events_url":"https://api.github.com/users/paulromano/received_events","type":"User","site_admin":false},"repo":{"id":6039026,"name":"openmc","full_name":"paulromano/openmc","owner":{"login":"paulromano","id":743095,"avatar_url":"https://avatars.githubusercontent.com/u/743095?v=3","gravatar_id":"","url":"https://api.github.com/users/paulromano","html_url":"https://github.com/paulromano","followers_url":"https://api.github.com/users/paulromano/followers","following_url":"https://api.github.com/users/paulromano/following{/other_user}","gists_url":"https://api.github.com/users/paulromano/gists{/gist_id}","starred_url":"https://api.github.com/users/paulromano/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paulromano/subscriptions","organizations_url":"https://api.github.com/users/paulromano/orgs","repos_url":"https://api.github.com/users/paulromano/repos","events_url":"https://api.github.com/users/paulromano/events{/privacy}","received_events_url":"https://api.github.com/users/paulromano/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/paulromano/openmc","description":"OpenMC Monte Carlo Code","fork":true,"url":"https://api.github.com/repos/paulromano/openmc","forks_url":"https://api.github.com/repos/paulromano/openmc/forks","keys_url":"https://api.github.com/repos/paulromano/openmc/keys{/key_id}","collaborators_url":"https://api.github.com/repos/paulromano/openmc/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/paulromano/openmc/teams","hooks_url":"https://api.github.com/repos/paulromano/openmc/hooks","issue_events_url":"https://api.github.com/repos/paulromano/openmc/issues/events{/number}","events_url":"https://api.github.com/repos/paulromano/openmc/events","assignees_url":"https://api.github.com/repos/paulromano/openmc/assignees{/user}","branches_url":"https://api.github.com/repos/paulromano/openmc/branches{/branch}","tags_url":"https://api.github.com/repos/paulromano/openmc/tags","blobs_url":"https://api.github.com/repos/paulromano/openmc/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/paulromano/openmc/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/paulromano/openmc/git/refs{/sha}","trees_url":"https://api.github.com/repos/paulromano/openmc/git/trees{/sha}","statuses_url":"https://api.github.com/repos/paulromano/openmc/statuses/{sha}","languages_url":"https://api.github.com/repos/paulromano/openmc/languages","stargazers_url":"https://api.github.com/repos/paulromano/openmc/stargazers","contributors_url":"https://api.github.com/repos/paulromano/openmc/contributors","subscribers_url":"https://api.github.com/repos/paulromano/openmc/subscribers","subscription_url":"https://api.github.com/repos/paulromano/openmc/subscription","commits_url":"https://api.github.com/repos/paulromano/openmc/commits{/sha}","git_commits_url":"https://api.github.com/repos/paulromano/openmc/git/commits{/sha}","comments_url":"https://api.github.com/repos/paulromano/openmc/comments{/number}","issue_comment_url":"https://api.github.com/repos/paulromano/openmc/issues/comments{/number}","contents_url":"https://api.github.com/repos/paulromano/openmc/contents/{+path}","compare_url":"https://api.github.com/repos/paulromano/openmc/compare/{base}...{head}","merges_url":"https://api.github.com/repos/paulromano/openmc/merges","archive_url":"https://api.github.com/repos/paulromano/openmc/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/paulromano/openmc/downloads","issues_url":"https://api.github.com/repos/paulromano/openmc/issues{/number}","pulls_url":"https://api.github.com/repos/paulromano/openmc/pulls{/number}","milestones_url":"https://api.github.com/repos/paulromano/openmc/milestones{/number}","notifications_url":"https://api.github.com/repos/paulromano/openmc/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/paulromano/openmc/labels{/name}","releases_url":"https://api.github.com/repos/paulromano/openmc/releases{/id}","deployments_url":"https://api.github.com/repos/paulromano/openmc/deployments","created_at":"2012-10-02T01:55:56Z","updated_at":"2016-01-18T18:36:18Z","pushed_at":"2016-07-21T02:39:29Z","git_url":"git://github.com/paulromano/openmc.git","ssh_url":"git@github.com:paulromano/openmc.git","clone_url":"https://github.com/paulromano/openmc.git","svn_url":"https://github.com/paulromano/openmc","homepage":"","size":26881,"stargazers_count":2,"watchers_count":2,"language":"FORTRAN","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":2,"default_branch":"develop"}},"base":{"label":"mit-crpg:develop","ref":"develop","sha":"bc2fab296b428b38ec6c0f9b6cf552c5ec73ac58","user":{"login":"mit-crpg","id":1247634,"avatar_url":"https://avatars.githubusercontent.com/u/1247634?v=3","gravatar_id":"","url":"https://api.github.com/users/mit-crpg","html_url":"https://github.com/mit-crpg","followers_url":"https://api.github.com/users/mit-crpg/followers","following_url":"https://api.github.com/users/mit-crpg/following{/other_user}","gists_url":"https://api.github.com/users/mit-crpg/gists{/gist_id}","starred_url":"https://api.github.com/users/mit-crpg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mit-crpg/subscriptions","organizations_url":"https://api.github.com/users/mit-crpg/orgs","repos_url":"https://api.github.com/users/mit-crpg/repos","events_url":"https://api.github.com/users/mit-crpg/events{/privacy}","received_events_url":"https://api.github.com/users/mit-crpg/received_events","type":"Organization","site_admin":false},"repo":{"id":2081118,"name":"openmc","full_name":"mit-crpg/openmc","owner":{"login":"mit-crpg","id":1247634,"avatar_url":"https://avatars.githubusercontent.com/u/1247634?v=3","gravatar_id":"","url":"https://api.github.com/users/mit-crpg","html_url":"https://github.com/mit-crpg","followers_url":"https://api.github.com/users/mit-crpg/followers","following_url":"https://api.github.com/users/mit-crpg/following{/other_user}","gists_url":"https://api.github.com/users/mit-crpg/gists{/gist_id}","starred_url":"https://api.github.com/users/mit-crpg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mit-crpg/subscriptions","organizations_url":"https://api.github.com/users/mit-crpg/orgs","repos_url":"https://api.github.com/users/mit-crpg/repos","events_url":"https://api.github.com/users/mit-crpg/events{/privacy}","received_events_url":"https://api.github.com/users/mit-crpg/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mit-crpg/openmc","description":"OpenMC Monte Carlo Code","fork":false,"url":"https://api.github.com/repos/mit-crpg/openmc","forks_url":"https://api.github.com/repos/mit-crpg/openmc/forks","keys_url":"https://api.github.com/repos/mit-crpg/openmc/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mit-crpg/openmc/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mit-crpg/openmc/teams","hooks_url":"https://api.github.com/repos/mit-crpg/openmc/hooks","issue_events_url":"https://api.github.com/repos/mit-crpg/openmc/issues/events{/number}","events_url":"https://api.github.com/repos/mit-crpg/openmc/events","assignees_url":"https://api.github.com/repos/mit-crpg/openmc/assignees{/user}","branches_url":"https://api.github.com/repos/mit-crpg/openmc/branches{/branch}","tags_url":"https://api.github.com/repos/mit-crpg/openmc/tags","blobs_url":"https://api.github.com/repos/mit-crpg/openmc/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mit-crpg/openmc/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mit-crpg/openmc/git/refs{/sha}","trees_url":"https://api.github.com/repos/mit-crpg/openmc/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mit-crpg/openmc/statuses/{sha}","languages_url":"https://api.github.com/repos/mit-crpg/openmc/languages","stargazers_url":"https://api.github.com/repos/mit-crpg/openmc/stargazers","contributors_url":"https://api.github.com/repos/mit-crpg/openmc/contributors","subscribers_url":"https://api.github.com/repos/mit-crpg/openmc/subscribers","subscription_url":"https://api.github.com/repos/mit-crpg/openmc/subscription","commits_url":"https://api.github.com/repos/mit-crpg/openmc/commits{/sha}","git_commits_url":"https://api.github.com/repos/mit-crpg/openmc/git/commits{/sha}","comments_url":"https://api.github.com/repos/mit-crpg/openmc/comments{/number}","issue_comment_url":"https://api.github.com/repos/mit-crpg/openmc/issues/comments{/number}","contents_url":"https://api.github.com/repos/mit-crpg/openmc/contents/{+path}","compare_url":"https://api.github.com/repos/mit-crpg/openmc/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mit-crpg/openmc/merges","archive_url":"https://api.github.com/repos/mit-crpg/openmc/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mit-crpg/openmc/downloads","issues_url":"https://api.github.com/repos/mit-crpg/openmc/issues{/number}","pulls_url":"https://api.github.com/repos/mit-crpg/openmc/pulls{/number}","milestones_url":"https://api.github.com/repos/mit-crpg/openmc/milestones{/number}","notifications_url":"https://api.github.com/repos/mit-crpg/openmc/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mit-crpg/openmc/labels{/name}","releases_url":"https://api.github.com/repos/mit-crpg/openmc/releases{/id}","deployments_url":"https://api.github.com/repos/mit-crpg/openmc/deployments","created_at":"2011-07-21T00:33:27Z","updated_at":"2016-07-19T22:21:06Z","pushed_at":"2016-07-21T14:56:16Z","git_url":"git://github.com/mit-crpg/openmc.git","ssh_url":"git@github.com:mit-crpg/openmc.git","clone_url":"https://github.com/mit-crpg/openmc.git","svn_url":"https://github.com/mit-crpg/openmc","homepage":"http://mit-crpg.github.io/openmc/","size":45633,"stargazers_count":82,"watchers_count":82,"language":"FORTRAN","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":97,"mirror_url":null,"open_issues_count":54,"forks":97,"open_issues":54,"watchers":82,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/mit-crpg/openmc/pulls/684"},"html":{"href":"https://github.com/mit-crpg/openmc/pull/684"},"issue":{"href":"https://api.github.com/repos/mit-crpg/openmc/issues/684"},"comments":{"href":"https://api.github.com/repos/mit-crpg/openmc/issues/684/comments"},"review_comments":{"href":"https://api.github.com/repos/mit-crpg/openmc/pulls/684/comments"},"review_comment":{"href":"https://api.github.com/repos/mit-crpg/openmc/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mit-crpg/openmc/pulls/684/commits"},"statuses":{"href":"https://api.github.com/repos/mit-crpg/openmc/statuses/3d68c07625e33cd64188df03ee03e9c31b3d4b74"}}}}
{"actor":{"display_login":"smharper"}}