diff --git a/aiida/backends/tests/restapi.py b/aiida/backends/tests/restapi.py
index eccd6aa543..2e46135674 100644
--- a/aiida/backends/tests/restapi.py
+++ b/aiida/backends/tests/restapi.py
@@ -789,6 +789,28 @@ def test_structure_visualization(self):
url,
response, uuid=node_uuid)
+ def test_xsf_visualization(self):
+ """
+ Get the list of given calculation inputs
+ """
+ from aiida.backends.tests.dataclasses import simplify
+ node_uuid = self.get_dummy_data()["structuredata"][0]["uuid"]
+ url = self.get_url_prefix() + '/structures/' + str(
+ node_uuid) + '/content/visualization?visformat=xsf'
+ with self.app.test_client() as client:
+ rv = client.get(url)
+ response = json.loads(rv.data)
+ expected_visdata = "CRYSTAL\nPRIMVEC 1\n 2.0000000000 0.0000000000 0.0000000000\n 0.0000000000 2.0000000000 0.0000000000\n 0.0000000000 0.0000000000 2.0000000000\nPRIMCOORD 1\n1 1\n56 0.0000000000 0.0000000000 0.0000000000\n"
+ self.assertEquals(simplify(response["data"]["visualization"]["str_viz_info"]["data"]),simplify(expected_visdata))
+ self.assertEquals(response["data"]["visualization"]["str_viz_info"]["format"],"xsf")
+ self.assertEquals(response["data"]["visualization"]["dimensionality"],
+ {u'dim': 3, u'value': 8.0, u'label': u'volume'})
+ self.assertEquals(response["data"]["visualization"]["pbc"], [True,True,True])
+ self.assertEquals(response["data"]["visualization"]["formula"], "Ba")
+ RESTApiTestCase.compare_extra_response_data(self, "structures",
+ url,
+ response, uuid=node_uuid)
+
def test_cif(self):
"""
Test download of cif file
diff --git a/aiida/orm/data/structure.py b/aiida/orm/data/structure.py
index d3c2e2dde6..d9a810ae9a 100644
--- a/aiida/orm/data/structure.py
+++ b/aiida/orm/data/structure.py
@@ -705,6 +705,47 @@ def _get_cif_ase_inline(struct=None, parameters=None):
return {'cif': cif}
+def atom_kinds_to_html(atom_kind):
+ """
+
+ Construct in html format
+
+ an alloy with 0.5 Ge, 0.4 Si and 0.1 vacancy is represented as
+ Ge0.5 + Si0.4 + vacancy0.1
+
+ Args:
+ atom_kind: a string with the name of the atomic kind, as printed by
+ kind.get_symbols_string(), e.g. Ba0.80Ca0.10X0.10
+
+ Returns:
+ html code for rendered formula
+ """
+
+ # Parse the formula (TODO can be made more robust though never fails if
+ # it takes strings generated with kind.get_symbols_string())
+ import re
+ elements = re.findall(r'([A-Z][a-z]*)([0-1][.[0-9]*]?)?', atom_kind)
+
+ # Compose the html string
+ html_formula_pieces = []
+
+ for element in elements:
+
+ # replace element X by 'vacancy'
+ species = element[0] if element[0] != 'X' else 'vacancy'
+ weight = element[1] if element[1] != '' else None
+
+ if weight is not None:
+ html_formula_pieces.append(species + '' + weight +
+ '')
+ else:
+ html_formula_pieces.append(species)
+
+ html_formula = ' + '.join(html_formula_pieces)
+
+ return html_formula
+
+
class StructureData(Data):
"""
This class contains the information about a given structure, i.e. a
@@ -976,6 +1017,79 @@ def _prepare_tcod(self, main_file_name="", **kwargs):
from aiida.tools.dbexporters.tcod import export_cif
return export_cif(self, **kwargs).encode('utf-8'), {}
+ def _prepare_chemdoodle(self, main_file_name=""):
+ """
+ Write the given structure to a string of format required by ChemDoodle.
+ """
+ import numpy as np
+ from itertools import product
+ import json
+
+ supercell_factors=[1, 1, 1]
+
+ # Get cell vectors and atomic position
+ lattice_vectors = np.array(self.get_attr('cell'))
+ base_sites = self.get_attr('sites')
+
+ start1 = -int(supercell_factors[0] / 2)
+ start2 = -int(supercell_factors[1] / 2)
+ start3 = -int(supercell_factors[2] / 2)
+
+ stop1 = start1 + supercell_factors[0]
+ stop2 = start2 + supercell_factors[1]
+ stop3 = start3 + supercell_factors[2]
+
+ grid1 = range(start1, stop1)
+ grid2 = range(start2, stop2)
+ grid3 = range(start3, stop3)
+
+ atoms_json = []
+
+ # Manual recenter of the structure
+ center = (lattice_vectors[0] + lattice_vectors[1] +
+ lattice_vectors[2]) / 2.
+
+ for ix, iy, iz in product(grid1, grid2, grid3):
+ for base_site in base_sites:
+ shift = (ix * lattice_vectors[0] + iy * lattice_vectors[1] + \
+ iz * lattice_vectors[2] - center).tolist()
+
+ kind_name = base_site['kind_name']
+ kind_string = self.get_kind(kind_name).get_symbols_string()
+
+ atoms_json.append(
+ {'l': kind_string,
+ 'x': base_site['position'][0] + shift[0],
+ 'y': base_site['position'][1] + shift[1],
+ 'z': base_site['position'][2] + shift[2],
+ # 'atomic_elements_html': kind_string
+ 'atomic_elements_html': atom_kinds_to_html(kind_string)
+ })
+
+ cell_json = {
+ "t": "UnitCell",
+ "i": "s0",
+ "o": (-center).tolist(),
+ "x": (lattice_vectors[0] - center).tolist(),
+ "y": (lattice_vectors[1] - center).tolist(),
+ "z": (lattice_vectors[2] - center).tolist(),
+ "xy": (lattice_vectors[0] + lattice_vectors[1]
+ - center).tolist(),
+ "xz": (lattice_vectors[0] + lattice_vectors[2]
+ - center).tolist(),
+ "yz": (lattice_vectors[1] + lattice_vectors[2]
+ - center).tolist(),
+ "xyz": (lattice_vectors[0] + lattice_vectors[1]
+ + lattice_vectors[2] - center).tolist(),
+ }
+
+ return_dict = {"s": [cell_json],
+ "m": [{"a": atoms_json}],
+ "units": 'Å'
+ }
+
+ return json.dumps(return_dict), {}
+
def _prepare_xyz(self, main_file_name=""):
"""
Write the given structure to a string of format XYZ.
diff --git a/aiida/restapi/translator/data/structure.py b/aiida/restapi/translator/data/structure.py
index 210fd1982e..9a5a394414 100644
--- a/aiida/restapi/translator/data/structure.py
+++ b/aiida/restapi/translator/data/structure.py
@@ -8,51 +8,10 @@
# For further information please visit http://www.aiida.net #
###########################################################################
from aiida.restapi.translator.data import DataTranslator
-from aiida.restapi.common.exceptions import RestValidationError
+from aiida.restapi.common.exceptions import RestInputValidationError
from aiida.common.exceptions import LicensingException
import numpy as np
-def atom_kinds_to_html(atom_kind):
- """
-
- Construct in html format
-
- an alloy with 0.5 Ge, 0.4 Si and 0.1 vacancy is represented as
- Ge0.5 + Si0.4 + vacancy0.1
-
- Args:
- atom_kind: a string with the name of the atomic kind, as printed by
- kind.get_symbols_string(), e.g. Ba0.80Ca0.10X0.10
-
- Returns:
- html code for rendered formula
- """
-
- # Parse the formula (TODO can be made more robust though never fails if
- # it takes strings generated with kind.get_symbols_string())
- import re
- elements = re.findall(r'([A-Z][a-z]*)([0-1][.[0-9]*]?)?', atom_kind)
-
- # Compose the html string
- html_formula_pieces = []
-
- for element in elements:
-
- # replace element X by 'vacancy'
- species = element[0] if element[0] != 'X' else 'vacancy'
- weight = element[1] if element[1] != '' else None
-
- if weight is not None:
- html_formula_pieces.append(species + '' + weight +
- '')
- else:
- html_formula_pieces.append(species)
-
- html_formula = ' + '.join(html_formula_pieces)
-
- return html_formula
-
-
class StructureDataTranslator(DataTranslator):
"""
Translator relative to resource 'structures' and aiida class StructureData
@@ -80,98 +39,25 @@ def __init__(self, **kwargs):
@staticmethod
- def get_visualization_data(node, format=None, supercell_factors=[1, 1, 1]):
+ def get_visualization_data(node, format=None):
"""
Returns: data in specified format. If format is not specified returns data
- in a format required by chemdoodle to visualize a structure.
+ in xsf format in order to visualize the structure with JSmol.
"""
response = {}
response["str_viz_info"] = {}
+ if format is None:
+ format = 'xsf'
+
if format in node.get_export_formats():
try:
response["str_viz_info"]["data"] = node._exportstring(format)[0]
response["str_viz_info"]["format"] = format
except LicensingException as e:
response = e.message
-
else:
- import numpy as np
- from itertools import product
-
-
- # Validate supercell factors
- if type(supercell_factors) is not list:
- raise RestValidationError('supercell factors have to be a list of three integers')
-
- for fac in supercell_factors:
- if type(fac) is not int:
- raise RestValidationError('supercell factors have to be '
- 'integers')
-
- # Get cell vectors and atomic position
- lattice_vectors = np.array(node.get_attr('cell'))
- base_sites = node.get_attr('sites')
-
- start1 = -int(supercell_factors[0] / 2)
- start2 = -int(supercell_factors[1] / 2)
- start3 = -int(supercell_factors[2] / 2)
-
- stop1 = start1 + supercell_factors[0]
- stop2 = start2 + supercell_factors[1]
- stop3 = start3 + supercell_factors[2]
-
- grid1 = range(start1, stop1)
- grid2 = range(start2, stop2)
- grid3 = range(start3, stop3)
-
- atoms_json = []
-
- # Manual recenter of the structure
- center = (lattice_vectors[0] + lattice_vectors[1] +
- lattice_vectors[2])/2.
-
- for ix, iy, iz in product(grid1, grid2, grid3):
- for base_site in base_sites:
-
- shift = (ix*lattice_vectors[0] + iy*lattice_vectors[1] + \
- iz*lattice_vectors[2] - center).tolist()
-
- kind_name = base_site['kind_name']
- kind_string = node.get_kind(kind_name).get_symbols_string()
-
- atoms_json.append(
- {'l': kind_string,
- 'x': base_site['position'][0] + shift[0],
- 'y': base_site['position'][1] + shift[1],
- 'z': base_site['position'][2] + shift[2],
- # 'atomic_elements_html': kind_string
- 'atomic_elements_html': atom_kinds_to_html(kind_string)
- })
-
- cell_json = {
- "t": "UnitCell",
- "i": "s0",
- "o": (-center).tolist(),
- "x": (lattice_vectors[0]-center).tolist(),
- "y": (lattice_vectors[1]-center).tolist(),
- "z": (lattice_vectors[2]-center).tolist(),
- "xy": (lattice_vectors[0] + lattice_vectors[1]
- - center).tolist(),
- "xz": (lattice_vectors[0] + lattice_vectors[2]
- - center).tolist(),
- "yz": (lattice_vectors[1] + lattice_vectors[2]
- - center).tolist(),
- "xyz": (lattice_vectors[0] + lattice_vectors[1]
- + lattice_vectors[2] - center).tolist(),
- }
-
- # These will be passed to ChemDoodle
- response["str_viz_info"]["data"] = {"s": [cell_json],
- "m": [{"a": atoms_json}],
- "units": 'Å'
- }
- response["str_viz_info"]["format"] = "default (ChemDoodle)"
+ raise RestInputValidationError("The format {} is not supported.".format(format))
# Add extra information
response["dimensionality"] = node.get_dimensionality()