{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# XML Import/Export" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# NB: python -m pip install pyhf[xmlio]\n", "import pyhf" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "total 1752\n", "drwxr-xr-x 7 kratsg staff 238B Oct 16 22:20 \u001b[34m.\u001b[m\u001b[m\n", "drwxr-xr-x 21 kratsg staff 714B Apr 4 14:26 \u001b[34m..\u001b[m\u001b[m\n", "drwxr-xr-x 6 kratsg staff 204B Feb 27 17:13 \u001b[34mconfig\u001b[m\u001b[m\n", "drwxr-xr-x 7 kratsg staff 238B Feb 27 23:41 \u001b[34mdata\u001b[m\u001b[m\n", "-rw-r--r-- 1 kratsg staff 850K Oct 16 22:20 log\n", "drwxr-xr-x 17 kratsg staff 578B Nov 15 12:24 \u001b[34mresults\u001b[m\u001b[m\n", "-rw-r--r-- 1 kratsg staff 21K Oct 16 22:20 scan.pdf\n" ] } ], "source": [ "!ls -lavh ../../../validation/xmlimport_input" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Importing\n", "\n", "In order to convert HistFactory XML+ROOT to the pyhf JSON spec for likelihoods, you need to point the command-line interface `pyhf xml2json` at the top-level XML file. Additionally, as the HistFactory XML specification often uses relative paths, you might need to specify the base directory `--basedir` from which all other files are located, as specified in the top-level XML. The command will be of the format\n", "\n", "```\n", "pyhf xml2json {top-level XML} --basedir {base directory}\n", "```\n", "\n", "This will print the JSON representation of the XML+ROOT specified. If you wish to store this as a JSON file, you simply need to redirect it\n", "\n", "```\n", "pyhf xml2json {top-level XML} --basedir {base directory} > spec.json\n", "```" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"channels\": [\n", " {\n", " \"name\": \"channel1\",\n", " \"samples\": [\n", " {\n", " \"data\": [\n", " 20.0,\n", " 10.0\n", " ],\n", " \"modifiers\": [\n", " {\n", " \"data\": {\n", " \"hi\": 1.05,\n", " \"lo\": 0.95\n", " },\n", " \"name\": \"syst1\",\n", " \"type\": \"normsys\"\n", " },\n", " {\n", " \"data\": null,\n", " \"name\": \"SigXsecOverSM\",\n", " \"type\": \"normfactor\"\n", " }\n", " ],\n", " \"name\": \"signal\"\n", " },\n", " {\n", " \"data\": [\n", " 100.0,\n", " 0.0\n", " ],\n", " \"modifiers\": [\n", " {\n", " \"data\": null,\n", " \"name\": \"lumi\",\n", " \"type\": \"lumi\"\n", " },\n", " {\n", " \"data\": [\n", " 5.000000074505806,\n", " 0.0\n", " ],\n", " \"name\": \"staterror_channel1\",\n", " \"type\": \"staterror\"\n", " },\n", " {\n", " \"data\": {\n", " \"hi\": 1.05,\n", " \"lo\": 0.95\n", " },\n", " \"name\": \"syst2\",\n", " \"type\": \"normsys\"\n", " }\n", " ],\n", " \"name\": \"background1\"\n", " },\n", " {\n", " \"data\": [\n", " 0.0,\n", " 100.0\n", " ],\n", " \"modifiers\": [\n", " {\n", " \"data\": null,\n", " \"name\": \"lumi\",\n", " \"type\": \"lumi\"\n", " },\n", " {\n", " \"data\": [\n", " 0.0,\n", " 10.0\n", " ],\n", " \"name\": \"staterror_channel1\",\n", " \"type\": \"staterror\"\n", " },\n", " {\n", " \"data\": {\n", " \"hi\": 1.05,\n", " \"lo\": 0.95\n", " },\n", " \"name\": \"syst3\",\n", " \"type\": \"normsys\"\n", " }\n", " ],\n", " \"name\": \"background2\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"data\": {\n", " \"channel1\": [\n", " 122.0,\n", " 112.0\n", " ]\n", " },\n", " \"toplvl\": {\n", " \"measurements\": [\n", " {\n", " \"config\": {\n", " \"parameters\": [\n", " {\n", " \"auxdata\": [\n", " 1.0\n", " ],\n", " \"bounds\": [\n", " [\n", " 0.5,\n", " 1.5\n", " ]\n", " ],\n", " \"fixed\": true,\n", " \"inits\": [\n", " 1.0\n", " ],\n", " \"name\": \"lumi\",\n", " \"sigmas\": [\n", " 0.1\n", " ]\n", " },\n", " {\n", " \"fixed\": true,\n", " \"name\": \"alpha_syst1\"\n", " }\n", " ],\n", " \"poi\": \"SigXsecOverSM\"\n", " },\n", " \"name\": \"GaussExample\"\n", " },\n", " {\n", " \"config\": {\n", " \"parameters\": [\n", " {\n", " \"auxdata\": [\n", " 1.0\n", " ],\n", " \"bounds\": [\n", " [\n", " 0.5,\n", " 1.5\n", " ]\n", " ],\n", " \"fixed\": true,\n", " \"inits\": [\n", " 1.0\n", " ],\n", " \"name\": \"lumi\",\n", " \"sigmas\": [\n", " 0.1\n", " ]\n", " },\n", " {\n", " \"fixed\": true,\n", " \"name\": \"alpha_syst1\"\n", " }\n", " ],\n", " \"poi\": \"SigXsecOverSM\"\n", " },\n", " \"name\": \"GammaExample\"\n", " },\n", " {\n", " \"config\": {\n", " \"parameters\": [\n", " {\n", " \"auxdata\": [\n", " 1.0\n", " ],\n", " \"bounds\": [\n", " [\n", " 0.5,\n", " 1.5\n", " ]\n", " ],\n", " \"fixed\": true,\n", " \"inits\": [\n", " 1.0\n", " ],\n", " \"name\": \"lumi\",\n", " \"sigmas\": [\n", " 0.1\n", " ]\n", " },\n", " {\n", " \"fixed\": true,\n", " \"name\": \"alpha_syst1\"\n", " }\n", " ],\n", " \"poi\": \"SigXsecOverSM\"\n", " },\n", " \"name\": \"LogNormExample\"\n", " },\n", " {\n", " \"config\": {\n", " \"parameters\": [\n", " {\n", " \"auxdata\": [\n", " 1.0\n", " ],\n", " \"bounds\": [\n", " [\n", " 0.5,\n", " 1.5\n", " ]\n", " ],\n", " \"fixed\": true,\n", " \"inits\": [\n", " 1.0\n", " ],\n", " \"name\": \"lumi\",\n", " \"sigmas\": [\n", " 0.1\n", " ]\n", " },\n", " {\n", " \"fixed\": true,\n", " \"name\": \"alpha_syst1\"\n", " }\n", " ],\n", " \"poi\": \"SigXsecOverSM\"\n", " },\n", " \"name\": \"ConstExample\"\n", " }\n", " ],\n", " \"resultprefix\": \"./results/example\"\n", " }\n", "}\n" ] } ], "source": [ "!pyhf xml2json --hide-progress ../../../validation/xmlimport_input/config/example.xml --basedir ../../../validation/xmlimport_input | tee xml_importexport.json" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exporting\n", "\n", "In order to convert the pyhf JSON to the HistFactory XML+ROOT spec for likelihoods, you need to point the command-line interface `pyhf json2xml` at the JSON file you want to convert. As everything is specified in a single file, there is no need to deal with base directories or looking up additional files. This will produce output XML+ROOT in the `--output-dir=./` directory (your current working directory), storing XML configs under `--specroot=config` and the data file under `--dataroot=data`. The XML configs are prefixed with `--resultprefix=FitConfig` by default, so that the top-level XML file will be located at `{output dir}/{prefix}.xml`. The command will be of the format\n", "\n", "```\n", "pyhf json2xml {JSON spec}\n", "```\n", "\n", "Note that the output directory must already exist." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/Users/jovyan/pyhf/src/pyhf/writexml.py:120: RuntimeWarning: invalid value encountered in true_divide\n", " attrs['HistoName'], np.divide(modifierspec['data'], sampledata).tolist()\n", "-rw-r--r-- 1 kratsg staff 822B Apr 9 09:36 output/FitConfig.xml\n", "\n", "output/config:\n", "total 8\n", "drwxr-xr-x 3 kratsg staff 102B Apr 9 09:36 \u001b[34m.\u001b[m\u001b[m\n", "drwxr-xr-x 5 kratsg staff 170B Apr 9 09:36 \u001b[34m..\u001b[m\u001b[m\n", "-rw-r--r-- 1 kratsg staff 1.0K Apr 9 09:36 FitConfig_channel1.xml\n", "\n", "output/data:\n", "total 96\n", "drwxr-xr-x 3 kratsg staff 102B Apr 9 09:36 \u001b[34m.\u001b[m\u001b[m\n", "drwxr-xr-x 5 kratsg staff 170B Apr 9 09:36 \u001b[34m..\u001b[m\u001b[m\n", "-rw-r--r-- 1 kratsg staff 46K Apr 9 09:36 data.root\n" ] } ], "source": [ "!mkdir -p output\n", "!pyhf json2xml xml_importexport.json --output-dir output\n", "!ls -lavh output/*" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "!rm xml_importexport.json\n", "!rm -rf output/" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.5" } }, "nbformat": 4, "nbformat_minor": 4 }