def test_dump(self): """Test the dump functionality.""" # Create the property instance with the property name str_obj = self.kim_property.kim_property_create( 1, 'cohesive-energy-relation-cubic-crystal') str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "short-name", "source-value", "1", "fcc", "key", "species", "source-value", "1:4", "Al", "Al", "Al", "Al", "key", "a", "source-value", "1:5", "3.9149", "4.0000", "4.032", "4.0817", "4.1602", "source-unit", "angstrom", "digits", "5", "key", "basis-atom-coordinates", "source-value", "2", "1:2", "0.5", "0.5", "key", "basis-atom-coordinates", "source-value", "3", "1:3", "0.5", "0.0", "0.5", "key", "basis-atom-coordinates", "source-value", "4", "2:3", "0.5", "0.5", "key", "cohesive-potential-energy", "source-value", "1:5", "3.324", "3.3576", "3.3600", "3.3550", "3.3260", "source-std-uncert-value", "1:5", "0.002", "0.0001", "0.00001", "0.0012", "0.00015", "source-unit", "eV", "digits", "5") kim_obj = kim_edn.load(str_obj)[0] out_str = kim_edn.dumps(kim_obj, indent=0) + '\n' sio = StringIO() # Fail when there is no property instance to dump it. for str_obj1 in [None, 'None', '', '[]']: self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_dump, str_obj1, sio) self.kim_property.kim_property_dump(str_obj, sio, indent=0) self.assertTrue(sio.getvalue() == out_str) # Fail to create a file to dump the property self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, "output/results.edn") str_obj = self.kim_property.kim_property_create( 2, 'atomic-mass', str_obj) str_obj = self.kim_property.kim_property_modify( str_obj, 2, "key", "species", "source-value", "Al", "key", "mass", "source-value", 26.98, "source-unit", "grams/mole") self.kim_property.kim_property_dump(str_obj, sio, indent=0)
def test_property_from_string(self): """Check the property definition from a KIM-EDN string.""" # Property definition edn file edn_file = join("tests", "fixtures", "atomic-mass.edn") self.assertTrue(isfile(edn_file)) pd = kim_edn.load(edn_file) fp = kim_edn.dumps(pd) # Complete check on the property definition self.kim_property.check_property_definition(fp)
def kim_property_destroy(property_instances, instance_id): """Destroy a kim property instance. Delete a previously created property instance. For example:: >>> obj = '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1}]' >>> kim_property_destroy(obj, 1) '[]' >>> obj = '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1} {"property-id" "tag:[email protected],2016-05-11:property/atomic-mass" "instance-id" 2}]' >>> kim_property_destroy(obj, 2) '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1}]' Arguments: property_instances {string} -- A string containing the serialized KIM-EDN formatted property instances. instance_id {int} -- A positive integer identifying the property instance. Returns: string -- serialized KIM-EDN formatted property instances. """ if not isinstance(instance_id, int): msg = 'the "instance_id" is not an `int`.' raise KIMPropertyError(msg) if property_instances is None or \ property_instances in ('None', '', '[]'): return '[]' # Deserialize the KIM property instances. kim_property_instances = kim_edn.loads(property_instances) for a_property_instance in kim_property_instances: if instance_id == a_property_instance["instance-id"]: property_id = a_property_instance["property-id"] unset_property_id(property_id) kim_property_instances.remove(a_property_instance) # Return the serialize KIM property instances return kim_edn.dumps(kim_property_instances)
def test_modify(self): """Test the modify functionality.""" # Fails when the input is none or not created for str_obj in [None, '', 'None', '[]']: self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1) # Fails when there is a different instance id str_obj = '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1}]' self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 2) # Fails when not having the instance id str_obj = '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal"}]' self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1) # Fails when not having the property id str_obj = '[{"instance-id" 1}]' self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1) # Create the property instance with the property name str_obj = self.kim_property.kim_property_create( 1, 'cohesive-energy-relation-cubic-crystal') # Fails when the instance id is not an integer self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1.0) str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "short-name", "source-value", "1", "fcc", "key", "species", "source-value", "1:4", "Al", "Al", "Al", "Al", "key", "a", "source-value", "1:5", "3.9149", "4.0000", "4.032", "4.0817", "4.1602", "source-unit", "angstrom", "digits", "5", "key", "basis-atom-coordinates", "source-value", "2", "1:2", "0.5", "0.5", "key", "basis-atom-coordinates", "source-value", "3", "1:3", "0.5", "0.0", "0.5", "key", "basis-atom-coordinates", "source-value", "4", "2:3", "0.5", "0.5", "key", "cohesive-potential-energy", "source-value", "1:5", "3.324", "3.3576", "3.3600", "3.3550", "3.3260", "source-std-uncert-value", "1:5", "0.002", "0.0001", "0.00001", "0.0012", "0.00015", "source-unit", "eV", "digits", "5") kim_obj = kim_edn.load(str_obj)[0] Property_Instance = '{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1 "short-name" {"source-value" ["fcc"]} "species" {"source-value" ["Al" "Al" "Al" "Al"]} "a" {"source-value" [3.9149 4.0 4.032 4.0817 4.1602] "source-unit" "angstrom" "digits" 5} "basis-atom-coordinates" {"source-value" [[0.0 0.0 0.0] [0.5 0.5 0.0] [0.5 0.0 0.5] [0.0 0.5 0.5]]} "cohesive-potential-energy" {"source-value" [3.324 3.3576 3.36 3.355 3.326] "source-std-uncert-value" [0.002 0.0001 1e-05 0.0012 0.00015] "source-unit" "eV" "digits" 5}}' self.assertTrue(Property_Instance == kim_edn.dumps(kim_obj)) # Create the property instance with the property name str_obj = self.kim_property.kim_property_create( 1, 'cohesive-energy-relation-cubic-crystal') str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "short-name", "source-value", "1", "fcc", "key", "species", "source-value", "1:4", "Al", "Al", "Al", "Al") str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "a", "source-value", "1:5", "3.9149", "4.0000", "4.032", "4.0817", "4.1602") str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "a", "source-unit", "angstrom", "digits", "5") str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "basis-atom-coordinates", "source-value", "4", "2:3", "0.5", "0.5", "key", "basis-atom-coordinates", "source-value", "3", "3", "0.5", "key", "basis-atom-coordinates", "source-value", "2", "1:2", "0.5", "0.5") str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "basis-atom-coordinates", "source-value", "3", "1", "0.5") str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "cohesive-potential-energy", "source-value", "1:5", "3.324", "3.3576", "3.3600", "3.3550", "3.3260", "source-std-uncert-value", "1:5", "0.002", "0.0001", "0.00001", "0.0012", "0.00015", "source-unit", "eV", "digits", "5") kim_obj = kim_edn.load(str_obj)[0] self.assertTrue(Property_Instance == kim_edn.dumps(kim_obj)) # Test for scalar values str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "space-group", "source-value", "Immm") kim_obj = kim_edn.load(str_obj)[0] self.assertTrue(kim_obj["space-group"]["source-value"] == "Immm") str_obj = self.kim_property.kim_property_modify( str_obj, 1, "key", "space-group", "source-value", "Fm-3m") kim_obj = kim_edn.load(str_obj)[0] self.assertTrue(kim_obj["space-group"]["source-value"] == "Fm-3m") # Fails when new keyword is not in the property definition self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1, "key", "a", "source-value", 2.5) # Fails when not in the standard key-value pairs self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-unknown", 2.5) # Fails when not enough input self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-value", 3) msg = 'there is not enough input arguments ' msg += 'to use.\nProcessing the {"basis-atom-coordinates"}:' msg += '{"source-value"} input arguments failed.\nThe second ' msg += 'index is missing from the input arguments.' self.assertRaisesRegex(self.KIMPropertyError, msg, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-value", 3) self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-value", 3, 3) msg = 'there is not enough input arguments ' msg += 'to use.\nProcessing the {"basis-atom-coordinates"}:' msg += '{"source-value"} input arguments failed.\n' msg += 'At least we need one further input.' self.assertRaisesRegex(self.KIMPropertyError, msg, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-value", 3, 3) self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-value", 3, 4) msg = 'this dimension has a fixed length = 3, while, ' msg += 'wrong index = 4 is requested.\nProcessing the ' msg += '{"basis-atom-coordinates"}:{"source-value"} input arguments,' msg += ' wrong index at the second dimension is requested.' self.assertRaisesRegex(self.KIMPropertyError, msg, self.kim_property.kim_property_modify, str_obj, 1, "key", "basis-atom-coordinates", "source-value", 3, 4)
def kim_property_remove(property_instances, instance_id, *argv): """Remove or delete a key from the property instance. Arguments: property_instances {string} -- A string containing the serialized KIM-EDN formatted property instances. instance_id {int} -- A positive integer identifying the property instance. Returns: string -- serialized KIM-EDN formatted property instances. """ if property_instances is None or property_instances in ('None', '', '[]'): msg = 'there is no property instance to remove the content.' raise KIMPropertyError(msg) if not isinstance(instance_id, int): msg = 'the "instance_id" is not an `int`.' raise KIMPropertyError(msg) # Deserialize the KIM property instances. kim_property_instances = kim_edn.loads(property_instances) a_property_instance = None for p in kim_property_instances: if p["instance-id"] == instance_id: a_property_instance = p break if a_property_instance is None: msg = 'the requested instance id :\n{}\n'.format(instance_id) msg += 'doesn\'t match any of the property instances ids.' raise KIMPropertyError(msg) # Number of arguments n_arguments = len(argv) # key keyword k_keyword = False # new keyword new_keyword = None new_keyword_map = {} i = 0 while i < n_arguments: try: arg = argv[i] except IndexError: msg = 'unexpected index exception happened.' raise KIMPropertyError(msg) if arg == 'key': k_keyword = True i += 1 continue if k_keyword: k_keyword = False # new keyword new_keyword = arg if new_keyword not in a_property_instance: msg = 'the key {} '.format(new_keyword) msg += 'doesn\'t exist in the property instance.' raise KIMPropertyError(msg) # Remove the whole key if it is requested if i + 1 < n_arguments: try: arg = argv[i + 1] except IndexError: msg = 'unexpected index exception happened.' raise KIMPropertyError(msg) if arg == 'key': del a_property_instance[new_keyword] i += 1 continue # There is no more argument delete a key and stop else: del a_property_instance[new_keyword] break new_keyword_map = a_property_instance[new_keyword] i += 1 continue if arg in new_keyword_map: del new_keyword_map[arg] i += 1 continue return kim_edn.dumps(kim_property_instances)
def kim_property_create(instance_id, property_name, property_instances=None): """Create a new kim property instance. It takes as input the property instance ID and property definition name and creates initial property instance data structure. If the "property_instances" obj is already exist it adds the newly created property instance to the obj and fails if it already exist there. For example:: >>> kim_property_create(1, 'cohesive-energy-relation-cubic-crystal') '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1}]' >>> str = kim_property_create(1, 'cohesive-energy-relation-cubic-crystal') Creating and addition of a second property instance:: >>> kim_property_create(2, 'atomic-mass', str) '[{"property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1} {"property-id" "tag:[email protected],2016-05-11:property/atomic-mass" "instance-id" 2}]' >>> str = kim_property_create(2, 'atomic-mass', str) >>> obj = kim_edn.loads(str) >>> print(kim_edn.dumps(obj, indent=4)) [ { "property-id" "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal" "instance-id" 1 } { "property-id" "tag:[email protected],2016-05-11:property/atomic-mass" "instance-id" 2 } ] Arguments: instance_id {int} -- A positive integer identifying the property instance. property_name {string} -- - A string containing the property name or - unique ID of the property, or - a path-like object giving the pathname (absolute or relative to the current working directory) of the file to be opened property_instances {string} -- A string containing the serialized KIM-EDN formatted property instances. (default: {None}) Returns: string -- serialized KIM-EDN formatted property instances. """ global KIM_PROPERTIES global PROPERTY_NAME_TO_PROPERTY_ID global PROPERTY_ID_TO_PROPERTY_NAME global NEW_PROPERTY_IDS if not isinstance(instance_id, int): msg = 'the "instance_id" is not an `int`.' raise KIMPropertyError(msg) # Check instance id format to prevent mistakes as early as possible check_instance_id_format(instance_id) if not isinstance(property_name, str): msg = 'the "property_name" is not an `str`.' raise KIMPropertyError(msg) if property_instances is None: kim_property_instances = [] else: # Deserialize the KIM property instances. kim_property_instances = kim_edn.loads(property_instances) for a_property_instance in kim_property_instances: if instance_id == a_property_instance["instance-id"]: msg = 'the "instance-id"’s cannot repeat. ' msg += 'In the case where there are multiple property ' msg += 'instances, the instance-id’s cannot repeat.' raise KIMPropertyError(msg) # KIM property names. kim_property_names = list(PROPERTY_NAME_TO_PROPERTY_ID.keys()) # KIM property full IDs. kim_property_ids = list(PROPERTY_ID_TO_PROPERTY_NAME.keys()) new_property_instance = {} # If the property_name is a path-like object to a file to be opened if isfile(property_name): # Load the property definition from a file pd = kim_edn.load(property_name) # Check the correctness of th eproperty definition check_property_definition(pd) # Get the property ID _property_id = pd["property-id"] # Check to make sure that this property does not exist in OpenKIM if _property_id in KIM_PROPERTIES: msg = 'the input property_name file contains a property ID:\n' msg += '"{}"\nwhich already '.format(_property_id) msg += 'exists in the KIM Property Definition list.\n' msg += 'Use the KIM Property Definition or update the ID in the' msg += 'property_name file.\n' msg += 'See the KIM Property Definitions at ' msg += 'https://openkim.org/properties for more detailed ' msg += 'information.' raise KIMPropertyError(msg) # Add the new property definition to KIM_PROPERTIES KIM_PROPERTIES[_property_id] = pd # Get the property name _, _, _, _property_name = get_property_id_path(_property_id) PROPERTY_NAME_TO_PROPERTY_ID[_property_name] = _property_id PROPERTY_ID_TO_PROPERTY_NAME[_property_id] = _property_name kim_property_names.append(_property_name) kim_property_ids.append(_property_id) # Keep the record of a newly added properties if NEW_PROPERTY_IDS is None: NEW_PROPERTY_IDS = [] NEW_PROPERTY_IDS.append(_property_id) # Set the new instance property ID new_property_instance["property-id"] = _property_id else: if property_name in kim_property_names: new_property_instance["property-id"] = \ PROPERTY_NAME_TO_PROPERTY_ID[property_name] elif property_name in kim_property_ids: new_property_instance["property-id"] = property_name else: msg = 'the requested "property_name" :\n' msg += '"{}"\n'.format(property_name) msg += 'is not a valid KIM property name nor ' msg += 'a path-like object to a file.\n' msg += 'See the KIM Property Definitions at ' msg += 'https://openkim.org/properties for more detailed ' msg += 'information.' raise KIMPropertyError(msg) new_property_instance["instance-id"] = instance_id # Add the newly created property instance to the collection kim_property_instances.append(new_property_instance) # If there are multiple keys sort them based on instance-id if len(kim_property_instances) > 1: kim_property_instances = sorted(kim_property_instances, key=lambda i: i["instance-id"]) # Return the serialize KIM property instances return kim_edn.dumps(kim_property_instances)