{"action":"created","comment":{"url":"https://api.github.com/repos/lsst/afw/pulls/comments/49122249","id":49122249,"diff_hunk":"@@ -0,0 +1,164 @@\n+# \n+# LSST Data Management System\n+# Copyright 2008-2015 AURA/LSST.\n+# \n+# This product includes software developed by the\n+# LSST Project (http://www.lsst.org/).\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 3 of the License, or\n+# (at your option) 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 LSST License Statement and \n+# the GNU General Public License along with this program.  If not, \n+# see <https://www.lsstcorp.org/LegalNotices/>.\n+#\n+from __future__ import absolute_import\n+\n+import os.path\n+\n+from .tableLib import BaseCatalog, SimpleCatalog, SourceCatalog, SimpleTable, SourceTable, \\\n+                      Schema, ReferenceMatch\n+from lsst.utils import getPackageDir\n+\n+__all__ = [\"copySchema\", \"copyCatalog\", \"matchesToCatalog\", \"matchesFromCatalog\"]\n+\n+def copySchema(schema, target, targetPrefix=None, sourcePrefix=None):\n+    \"\"\"Return a deep copy the provided schema\n+\n+    If sourcePrefix is set, only copy those keys that have that prefix.\n+    If targetPrefix is set, add that to the key name.\n+    \"\"\"\n+    existing = set(target.getNames())\n+    for keyName in schema.getNames():\n+        if sourcePrefix is not None:\n+            if not keyName.startswith(sourcePrefix):\n+                continue\n+            keyNameFix = keyName[len(sourcePrefix):]\n+        else:\n+            keyNameFix = keyName\n+        if keyNameFix in existing:\n+            continue\n+        field = schema.find(keyName).field\n+        typeStr = field.getTypeString()\n+        fieldDoc = field.getDoc()\n+        fieldUnits = field.getUnits()\n+        if typeStr in (\"ArrayF\", \"ArrayD\", \"ArrayI\", \"CovF\", \"CovD\"):\n+            fieldSize = field.getSize()\n+        else:\n+            fieldSize = None\n+\n+        target.addField((targetPrefix if targetPrefix is not None else \"\") + keyNameFix,\n+                        type=typeStr, doc=fieldDoc, units=fieldUnits, size=fieldSize)\n+    return target\n+\n+def copyCatalog(catalog, target, sourceSchema=None, targetPrefix=None, sourcePrefix=None):\n+    \"\"\"Copy entries from one Catalog to another.\n+\n+    If sourcePrefix is set, only copy those keys that have that prefix.\n+    If targetPrefix is set, add that to the key name.\n+    \"\"\"\n+    if sourceSchema is None:\n+        sourceSchema = catalog.schema\n+\n+    targetSchema = target.schema\n+    target.reserve(len(catalog))\n+    for i in range(len(target), len(catalog)):\n+        target.addNew()\n+\n+    if len(catalog) != len(target):\n+        raise RuntimeError(\"Length mismatch: %d vs %d\" % (len(catalog), len(target)))\n+\n+    sourceKeys = []\n+    targetKeys = []\n+    for k in sourceSchema.getNames():\n+        if sourcePrefix is not None:\n+            if not k.startswith(sourcePrefix):\n+                continue\n+            kFix = k[len(sourcePrefix):]\n+        else:\n+            kFix = k\n+        sourceKeys.append(sourceSchema.find(k).key)\n+        targetKeys.append(targetSchema.find((targetPrefix if targetPrefix is not None else \"\") + kFix).key)\n+\n+    for rFrom, rTo in zip(catalog, target):\n+        for kFrom, kTo in zip(sourceKeys, targetKeys):\n+            try:\n+                rTo.set(kTo, rFrom.get(kFrom))\n+            except:\n+                print \"Error setting: %s %s %s %s\" % (type(rFrom), type(rTo), type(kFrom), type(kTo))\n+\n+    return target\n+\n+def matchesToCatalog(matches, matchMeta):\n+    \"\"\"Denormalise matches into a Catalog of \"unpacked matches\"\n+\n+    \\param[in] matches    unpacked matches\n+    \\param[in] matchMeta  metadata for matches (must have .add attribute)\n+\n+    \\return  lsst.afw.table.BaseCatalog of matches (with ref_ and src_ prefix identifiers\n+             for referece and source entries, respectively)\n+    \"\"\"\n+\n+    if len(matches) == 0:\n+        raise RuntimeError(\"No matches provided.\")\n+\n+    refSchema = matches[0].first.getSchema()\n+    srcSchema = matches[0].second.getSchema()\n+\n+    mergedSchema = copySchema(refSchema, Schema(), targetPrefix=\"ref_\")\n+    mergedSchema = copySchema(srcSchema, mergedSchema, targetPrefix=\"src_\")\n+    distKey = mergedSchema.addField(\"distance\", type=float, doc=\"Distance between ref and src\")\n+\n+    mergedCatalog = BaseCatalog(mergedSchema)\n+    copyCatalog([m.first for m in matches], mergedCatalog, sourceSchema=refSchema, targetPrefix=\"ref_\")\n+    copyCatalog([m.second for m in matches], mergedCatalog, sourceSchema=srcSchema, targetPrefix=\"src_\")\n+    for m, r in zip(matches, mergedCatalog):\n+        r.set(distKey, m.distance)\n+\n+    # obtaining reference catalog name if one is setup\n+    try:\n+        catalogName = os.path.basename(getPackageDir(\"astrometry_net_data\"))\n+    except:\n+        catalogName = 'NOT_SET'\n+    matchMeta.add('REFCAT', catalogName)\n+    mergedCatalog.getTable().setMetadata(matchMeta)\n+\n+    return mergedCatalog\n+\n+def matchesFromCatalog(catalog, sourceSlotConfig=None, prefix=\"\"):\n+    \"\"\"Generate a list of ReferenceMatches from a Catalog of \"unpacked matches\"\n+\n+    \\param[in] catalog           catalog of matches.  Must have schema where reference entries are\n+                                 prefixed with \"ref_\" and source entries are prefixed with \"src_\"\n+    \\param[in] sourceSlotConfig  configuration for source slots (optional)\n+    \\param[in] prefix            prefix for slot config setup (optional)\n+\n+    \\returns   lsst.afw.table.ReferenceMatch of matches\n+    \"\"\"\n+    if catalog is None:\n+        # There are none\n+        return []","path":"python/lsst/afw/table/catalogMatches.py","position":147,"original_position":147,"commit_id":"c1dd7d5d77190d14eb0085adcfed89ccdf872e4e","original_commit_id":"c1dd7d5d77190d14eb0085adcfed89ccdf872e4e","user":{"login":"laurenam","id":10424871,"avatar_url":"https://avatars.githubusercontent.com/u/10424871?v=3","gravatar_id":"","url":"https://api.github.com/users/laurenam","html_url":"https://github.com/laurenam","followers_url":"https://api.github.com/users/laurenam/followers","following_url":"https://api.github.com/users/laurenam/following{/other_user}","gists_url":"https://api.github.com/users/laurenam/gists{/gist_id}","starred_url":"https://api.github.com/users/laurenam/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/laurenam/subscriptions","organizations_url":"https://api.github.com/users/laurenam/orgs","repos_url":"https://api.github.com/users/laurenam/repos","events_url":"https://api.github.com/users/laurenam/events{/privacy}","received_events_url":"https://api.github.com/users/laurenam/received_events","type":"User","site_admin":false},"body":"Removed","created_at":"2016-01-07T20:34:24Z","updated_at":"2016-01-07T20:34:24Z","html_url":"https://github.com/lsst/afw/pull/47#discussion_r49122249","pull_request_url":"https://api.github.com/repos/lsst/afw/pulls/47","_links":{"self":{"href":"https://api.github.com/repos/lsst/afw/pulls/comments/49122249"},"html":{"href":"https://github.com/lsst/afw/pull/47#discussion_r49122249"},"pull_request":{"href":"https://api.github.com/repos/lsst/afw/pulls/47"}}},"pull_request":{"url":"https://api.github.com/repos/lsst/afw/pulls/47","id":54510179,"html_url":"https://github.com/lsst/afw/pull/47","diff_url":"https://github.com/lsst/afw/pull/47.diff","patch_url":"https://github.com/lsst/afw/pull/47.patch","issue_url":"https://api.github.com/repos/lsst/afw/issues/47","number":47,"state":"open","locked":false,"title":"Review for DM-4729: Add functions to generate 'unpacked matches' in a Catalog","user":{"login":"jdswinbank","id":460854,"avatar_url":"https://avatars.githubusercontent.com/u/460854?v=3","gravatar_id":"","url":"https://api.github.com/users/jdswinbank","html_url":"https://github.com/jdswinbank","followers_url":"https://api.github.com/users/jdswinbank/followers","following_url":"https://api.github.com/users/jdswinbank/following{/other_user}","gists_url":"https://api.github.com/users/jdswinbank/gists{/gist_id}","starred_url":"https://api.github.com/users/jdswinbank/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdswinbank/subscriptions","organizations_url":"https://api.github.com/users/jdswinbank/orgs","repos_url":"https://api.github.com/users/jdswinbank/repos","events_url":"https://api.github.com/users/jdswinbank/events{/privacy}","received_events_url":"https://api.github.com/users/jdswinbank/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-12-23T21:56:55Z","updated_at":"2016-01-07T20:34:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d02c091b656ca1ead465617711fad67d36a6971e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/lsst/afw/pulls/47/commits","review_comments_url":"https://api.github.com/repos/lsst/afw/pulls/47/comments","review_comment_url":"https://api.github.com/repos/lsst/afw/pulls/comments{/number}","comments_url":"https://api.github.com/repos/lsst/afw/issues/47/comments","statuses_url":"https://api.github.com/repos/lsst/afw/statuses/c1dd7d5d77190d14eb0085adcfed89ccdf872e4e","head":{"label":"lsst:u/lauren/DM-4729","ref":"u/lauren/DM-4729","sha":"c1dd7d5d77190d14eb0085adcfed89ccdf872e4e","user":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"repo":{"id":23013175,"name":"afw","full_name":"lsst/afw","owner":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/lsst/afw","description":"LSST data management: astronomical framework, including images and tables","fork":false,"url":"https://api.github.com/repos/lsst/afw","forks_url":"https://api.github.com/repos/lsst/afw/forks","keys_url":"https://api.github.com/repos/lsst/afw/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lsst/afw/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lsst/afw/teams","hooks_url":"https://api.github.com/repos/lsst/afw/hooks","issue_events_url":"https://api.github.com/repos/lsst/afw/issues/events{/number}","events_url":"https://api.github.com/repos/lsst/afw/events","assignees_url":"https://api.github.com/repos/lsst/afw/assignees{/user}","branches_url":"https://api.github.com/repos/lsst/afw/branches{/branch}","tags_url":"https://api.github.com/repos/lsst/afw/tags","blobs_url":"https://api.github.com/repos/lsst/afw/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lsst/afw/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lsst/afw/git/refs{/sha}","trees_url":"https://api.github.com/repos/lsst/afw/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lsst/afw/statuses/{sha}","languages_url":"https://api.github.com/repos/lsst/afw/languages","stargazers_url":"https://api.github.com/repos/lsst/afw/stargazers","contributors_url":"https://api.github.com/repos/lsst/afw/contributors","subscribers_url":"https://api.github.com/repos/lsst/afw/subscribers","subscription_url":"https://api.github.com/repos/lsst/afw/subscription","commits_url":"https://api.github.com/repos/lsst/afw/commits{/sha}","git_commits_url":"https://api.github.com/repos/lsst/afw/git/commits{/sha}","comments_url":"https://api.github.com/repos/lsst/afw/comments{/number}","issue_comment_url":"https://api.github.com/repos/lsst/afw/issues/comments{/number}","contents_url":"https://api.github.com/repos/lsst/afw/contents/{+path}","compare_url":"https://api.github.com/repos/lsst/afw/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lsst/afw/merges","archive_url":"https://api.github.com/repos/lsst/afw/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lsst/afw/downloads","issues_url":"https://api.github.com/repos/lsst/afw/issues{/number}","pulls_url":"https://api.github.com/repos/lsst/afw/pulls{/number}","milestones_url":"https://api.github.com/repos/lsst/afw/milestones{/number}","notifications_url":"https://api.github.com/repos/lsst/afw/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lsst/afw/labels{/name}","releases_url":"https://api.github.com/repos/lsst/afw/releases{/id}","created_at":"2014-08-16T07:37:40Z","updated_at":"2015-10-14T16:00:23Z","pushed_at":"2016-01-07T20:13:07Z","git_url":"git://github.com/lsst/afw.git","ssh_url":"git@github.com:lsst/afw.git","clone_url":"https://github.com/lsst/afw.git","svn_url":"https://github.com/lsst/afw","homepage":"http://dm.lsst.org/","size":38811,"stargazers_count":3,"watchers_count":3,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":5,"forks":8,"open_issues":5,"watchers":3,"default_branch":"master"}},"base":{"label":"lsst:master","ref":"master","sha":"41776ed089aaea6f2fc53e3c991d8c175c730b75","user":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"repo":{"id":23013175,"name":"afw","full_name":"lsst/afw","owner":{"login":"lsst","id":1134504,"avatar_url":"https://avatars.githubusercontent.com/u/1134504?v=3","gravatar_id":"","url":"https://api.github.com/users/lsst","html_url":"https://github.com/lsst","followers_url":"https://api.github.com/users/lsst/followers","following_url":"https://api.github.com/users/lsst/following{/other_user}","gists_url":"https://api.github.com/users/lsst/gists{/gist_id}","starred_url":"https://api.github.com/users/lsst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lsst/subscriptions","organizations_url":"https://api.github.com/users/lsst/orgs","repos_url":"https://api.github.com/users/lsst/repos","events_url":"https://api.github.com/users/lsst/events{/privacy}","received_events_url":"https://api.github.com/users/lsst/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/lsst/afw","description":"LSST data management: astronomical framework, including images and tables","fork":false,"url":"https://api.github.com/repos/lsst/afw","forks_url":"https://api.github.com/repos/lsst/afw/forks","keys_url":"https://api.github.com/repos/lsst/afw/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lsst/afw/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lsst/afw/teams","hooks_url":"https://api.github.com/repos/lsst/afw/hooks","issue_events_url":"https://api.github.com/repos/lsst/afw/issues/events{/number}","events_url":"https://api.github.com/repos/lsst/afw/events","assignees_url":"https://api.github.com/repos/lsst/afw/assignees{/user}","branches_url":"https://api.github.com/repos/lsst/afw/branches{/branch}","tags_url":"https://api.github.com/repos/lsst/afw/tags","blobs_url":"https://api.github.com/repos/lsst/afw/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lsst/afw/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lsst/afw/git/refs{/sha}","trees_url":"https://api.github.com/repos/lsst/afw/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lsst/afw/statuses/{sha}","languages_url":"https://api.github.com/repos/lsst/afw/languages","stargazers_url":"https://api.github.com/repos/lsst/afw/stargazers","contributors_url":"https://api.github.com/repos/lsst/afw/contributors","subscribers_url":"https://api.github.com/repos/lsst/afw/subscribers","subscription_url":"https://api.github.com/repos/lsst/afw/subscription","commits_url":"https://api.github.com/repos/lsst/afw/commits{/sha}","git_commits_url":"https://api.github.com/repos/lsst/afw/git/commits{/sha}","comments_url":"https://api.github.com/repos/lsst/afw/comments{/number}","issue_comment_url":"https://api.github.com/repos/lsst/afw/issues/comments{/number}","contents_url":"https://api.github.com/repos/lsst/afw/contents/{+path}","compare_url":"https://api.github.com/repos/lsst/afw/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lsst/afw/merges","archive_url":"https://api.github.com/repos/lsst/afw/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lsst/afw/downloads","issues_url":"https://api.github.com/repos/lsst/afw/issues{/number}","pulls_url":"https://api.github.com/repos/lsst/afw/pulls{/number}","milestones_url":"https://api.github.com/repos/lsst/afw/milestones{/number}","notifications_url":"https://api.github.com/repos/lsst/afw/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lsst/afw/labels{/name}","releases_url":"https://api.github.com/repos/lsst/afw/releases{/id}","created_at":"2014-08-16T07:37:40Z","updated_at":"2015-10-14T16:00:23Z","pushed_at":"2016-01-07T20:13:07Z","git_url":"git://github.com/lsst/afw.git","ssh_url":"git@github.com:lsst/afw.git","clone_url":"https://github.com/lsst/afw.git","svn_url":"https://github.com/lsst/afw","homepage":"http://dm.lsst.org/","size":38811,"stargazers_count":3,"watchers_count":3,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":5,"forks":8,"open_issues":5,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/lsst/afw/pulls/47"},"html":{"href":"https://github.com/lsst/afw/pull/47"},"issue":{"href":"https://api.github.com/repos/lsst/afw/issues/47"},"comments":{"href":"https://api.github.com/repos/lsst/afw/issues/47/comments"},"review_comments":{"href":"https://api.github.com/repos/lsst/afw/pulls/47/comments"},"review_comment":{"href":"https://api.github.com/repos/lsst/afw/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/lsst/afw/pulls/47/commits"},"statuses":{"href":"https://api.github.com/repos/lsst/afw/statuses/c1dd7d5d77190d14eb0085adcfed89ccdf872e4e"}}}}