Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
felix-andreas committed Nov 8, 2019
0 parents commit ebec41d
Show file tree
Hide file tree
Showing 15 changed files with 1,073 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on: [push]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Build
run: |
pip install .
- name: Test with pytest
run: |
pip install pytest
pytest
- name: Build distributions
run: |
pip install setuptools wheel
python setup.py sdist bdist_wheel
26 changes: 26 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Upload Python Package

on:
release:
types: [created]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.7'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# OS and IDE
.DS_Store
.idea
.vscode

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
.Python
build/
dist/
sdist/
wheels/
*.egg
*.egg-info/
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# LatticeJSON

LatticeJSON is a JSON based lattice file format. JSON is able to describe complex data structures,
has a human readable syntax and is available in all common programming language. It is therefore an
appropriate choice to characterize the magnetic lattice of a particle accelerator.

## Specification
This repository contains the
[Specification of LatticeJSON](https://github.com/andreasfelix/latticejson/blob/master/latticejson/schema.json)
in form of a [JSON Schema](https://json-schema.org).

## Example

A LatticeJSON file for a FODO lattice:
```json
{
"name": "FODO lattice",
"description": "This is the simplest possible strong focusing lattice.",
"elements": {
"D1": {"type": "Drift", "length": 0.55},
"Q1": {"type": "Quad", "length": 0.2, "k1": 1.2},
"Q2": {"type": "Quad", "length": 0.4, "k1": -1.2},
"B1": {"type": "Bend", "length": 1.5, "angle": 0.392701, "e1": 0.1963505, "e2": 0.1963505}
},
"cells": {
"fodo": ["Q1", "D1", "B1", "D1", "Q2", "D1", "B1", "D1", "Q1"]
},

"main_cell": ["fodo", "fodo", "fodo", "fodo", "fodo", "fodo", "fodo", "fodo"]
}
```


# LatticeJSON CLI
[![Python Version](https://img.shields.io/pypi/pyversions/latticejson)](https://pypi.org/project/latticejson/)
[![PyPI](https://img.shields.io/pypi/v/latticejson.svg)](https://pypi.org/project/latticejson/)
[![CI](https://github.com/andreasfelix/latticejson/workflows/CI/badge.svg)](https://github.com/andreasfelix/latticejson/actions?query=workflow%3ACI)

This repository also contains a Python based commandline tool which is able validate and convert LatticeJSON
files into other common lattice file formats.

You can install and update it using pip or pipenv:

```sh
pip install -U latticejson
```

Validate a LatticeJSON file:
```sh
latticejson validate /path/to/lattice
```

Convert a LatticeJSON file into the elegant lattice format:
```sh
latticejson convert json elegant /path/to/lattice
```

## License
[GNU General Public License v3.0](https://github.com/andreasfelix/latticejson/blob/master/LICENSE)


6 changes: 6 additions & 0 deletions latticejson/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
__title__ = 'latticeJSON'
__description__ = 'A JSON based lattice file format'
__url__ = 'https://github.com/andreasfelix/latticejson'
__version__ = '0.0.0'
__author__ = 'Felix Andreas'
__license__ = 'GNU General Public License v3.0'
2 changes: 2 additions & 0 deletions latticejson/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .convert import convert_file
from .validate import validate
24 changes: 24 additions & 0 deletions latticejson/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import click
from .validate import validate_file
from .convert import convert_file


@click.group()
@click.version_option()
def main():
pass


@main.command()
@click.argument('input_format')
@click.argument('output_format')
@click.argument('file', type=click.Path(exists=True))
def convert(**kwargs):
x = convert_file(kwargs['file'], kwargs['input_format'], kwargs['output_format'])
print(x)


@main.command()
@click.argument('file', type=click.Path(exists=True))
def validate(**kwargs):
validate_file(kwargs['file'])
70 changes: 70 additions & 0 deletions latticejson/convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from typing import List, Dict
import json

from .validate import validate


def convert_file(file_path, input_format, output_format):
if input_format == 'json' and output_format == 'elegant':
with open(file_path) as lattice_file:
lattice_dict = json.load(lattice_file)

validate(lattice_dict)
return convert_json_to_elegant(lattice_dict)
else:
raise NotImplementedError(f'Unknown formats: {input_format}, {output_format}')


JSON_TO_ELEGANT = {
'Drift': 'DRIF',
'Bend': 'CSBEND',
'Quad': 'KQUAD',
'Sext': 'KSEXT',
'Cell': 'LINE',
'main_cell': 'RING',
'length': 'L',
'angle': 'ANGLE',
'e1': 'e1',
'e2': 'e2',
'k1': 'K1',
'k2': 'K2',
}

ELEGANT_TO_JSON = dict(reversed(tup) for tup in JSON_TO_ELEGANT.items())

ELEGANT_ELEMENT_TEMPLATE = '{name}: {type}, {attributes}'.format
ELEGANT_CELL_TEMPLATE = '{name}: LINE=({objects})'.format


def convert_json_to_elegant(lattice_dict):
elements_dict = lattice_dict['elements']
cells_dict = lattice_dict['cells']

elements_string = []
for name, element in elements_dict.items():
attributes = ', '.join(f'{JSON_TO_ELEGANT[key]}={value}' for key, value in element.items() if key != 'type')
type_ = JSON_TO_ELEGANT[element['type']]
elements_string.append(ELEGANT_ELEMENT_TEMPLATE(name=name, type=type_, attributes=attributes))

ordered_cells = order_cells(cells_dict)
cells_string = [ELEGANT_CELL_TEMPLATE(name=name, objects=', '.join(cells_dict[name])) for name in ordered_cells]
cells_string.append(ELEGANT_CELL_TEMPLATE(name=lattice_dict['name'], objects=', '.join(lattice_dict['main_cell'])))
return '\n'.join(elements_string + cells_string)


def order_cells(cells_dict: Dict[str, List[str]]):
cells_dict_copy = cells_dict.copy()
ordered_cells = []

def _order_cells(name, cell: List[str]):
for cell_name in cell:
if cell_name in cells_dict_copy:
_order_cells(cell_name, cells_dict_copy[cell_name])

ordered_cells.append(name)
cells_dict_copy.pop(name)

for name, cell in cells_dict.items():
_order_cells(name, cell)

return ordered_cells
77 changes: 77 additions & 0 deletions latticejson/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"$id": "",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "JSON lattice file format",
"description": "Defines the magnetic lattice format",
"additionalProperties": false,
"required": [
"name",
"main_cell",
"elements"
],
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the lattice"
},
"description": {
"type": "string",
"description": "A brief description of the lattice"
},
"main_cell": {
"type": "array",
"items": {
"type": "string"
}
},
"cells": {
"type": "object",
"patternProperties": {
"^.*$": {
"$ref": "#/definitions/cell"
}
},
"additionalProperties": false
},
"elements": {
"type": "object",
"items": {
"anyOf": [
{
"$ref": "#/definitions/cell"
},
{
"$ref": "#/definitions/element"
}
]
}
}
},
"definitions": {
"cell": {
"type": "array",
"items": {
"type": "string"
}
},
"element": {
"type": "object",
"required": [
"type",
"length"
],
"properties": {
"type": {
"type": "string",
"description": "Type of the element."
},
"length": {
"type": "number",
"minimum": 0,
"description": "The length of the element."
}
}
}
}
}
18 changes: 18 additions & 0 deletions latticejson/validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import os
import json
import fastjsonschema

dir_name = os.path.dirname(__file__)
schema_path = os.path.join(dir_name, 'schema.json')

with open(schema_path) as schema_file:
schema = json.load(schema_file)

validate = fastjsonschema.compile(schema)


def validate_file(file_path: str):
with open(file_path) as lattice_file:
data = json.load(lattice_file)

validate(data)
37 changes: 37 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from setuptools import setup, find_packages

with open('latticejson/__about__.py') as file:
about = {}
exec(file.read(), about)

with open('README.md') as file:
readme = file.read()

setup(
name=about['__title__'],
version=about['__version__'],
description=about['__description__'],
long_description=readme,
long_description_content_type='text/markdown',
url=about['__url__'],
author=about['__author__'],
license=about['__license__'],
packages=find_packages(),
install_requires=['fastjsonschema', 'click'],
test_requires=['pytest'],
python_requires='>=3.6',
include_package_data=True,
package_data={'latticejson': ['schema.json'], },
entry_points={'console_scripts': ["latticejson = latticejson.cli:main"]},
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Scientific/Engineering'
],
)
15 changes: 15 additions & 0 deletions tests/data/fodo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "FODO lattice",
"description": "This is the simplest possible strong focusing lattice.",
"elements": {
"D1": {"type": "Drift", "length": 0.55},
"Q1": {"type": "Quad", "length": 0.2, "k1": 1.2},
"Q2": {"type": "Quad", "length": 0.4, "k1": -1.2},
"B1": {"type": "Bend", "length": 1.5, "angle": 0.392701, "e1": 0.1963505, "e2": 0.1963505}
},
"cells": {
"fodo": ["Q1", "D1", "B1", "D1", "Q2", "D1", "B1", "D1", "Q1"]
},

"main_cell": ["fodo", "fodo", "fodo", "fodo", "fodo", "fodo", "fodo", "fodo"]
}
Loading

0 comments on commit ebec41d

Please sign in to comment.