def test_check_instance_optional_key_marked_required_are_present(self): """Test the inctances optional presence of the keys marked as required.""" import kim_edn # property instance is not a dict pi = ["property-id"] pd = kim_edn.load( join("tests", "fixtures", "cohesive-energy-relation-cubic-crystal.edn")) self.assertRaises( self.KIMPropertyError, self.kim_property. check_instance_optional_key_marked_required_are_present, pi, pd) # property definition is not a dict pi = { "property-id": "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal", "instance-id": 1 } pd = ["property-id"] self.assertRaises( self.KIMPropertyError, self.kim_property. check_instance_optional_key_marked_required_are_present, pi, pd) pi = { "property-id": "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal", "instance-id": 1 } pd = kim_edn.load( join("tests", "fixtures", "cohesive-energy-relation-cubic-crystal.edn")) self.assertRaises( self.KIMPropertyError, self.kim_property. check_instance_optional_key_marked_required_are_present, pi, pd)
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 main(): """Validate and pretty-print KIM-EDN tool main file.""" prog = 'python -m kim_edn.tool' description = ('A simple command line interface for KIM-EDN module ' 'to validate and pretty-print kim-EDN objects.') parser = argparse.ArgumentParser(prog=prog, description=description) parser.add_argument( 'infile', nargs='?', type=argparse.FileType(encoding="utf-8"), help='a KIM-EDN file to be validated or pretty-printed', default=sys.stdin) parser.add_argument('outfile', nargs='?', type=argparse.FileType('w', encoding="utf-8"), help='write the output of infile to outfile', default=sys.stdout) parser.add_argument( '--sort-keys', action='store_true', default=False, help='sort the output of dictionaries alphabetically by key') parser.add_argument('--edn-lines', action='store_true', default=False, help='parse input using the kim_edn lines format') options = parser.parse_args() with options.infile as infile, options.outfile as outfile: try: if options.edn_lines: objs = (kim_edn.loads(line) for line in infile) else: objs = (kim_edn.load(infile), ) for obj in objs: kim_edn.dump(obj, outfile, sort_keys=options.sort_keys, indent=4) outfile.write('\n') except ValueError as e: raise SystemExit(e)
def test_create_sorted(self): """Test create functionality and sorting based on instance-id.""" str1 = self.kim_property.kim_property_create(2, 'atomic-mass') str1 = self.kim_property.kim_property_modify(str1, 2, "key", "species", "source-value", "Ar", "key", "mass", "source-value", 39.948, "source-unit", "grams/mole") str1 = self.kim_property.kim_property_create( 5, "cohesive-energy-lattice-invariant-shear-unrelaxed-path-cubic-crystal", str1) str1 = self.kim_property.kim_property_create( 1, 'cohesive-energy-relation-cubic-crystal', str1) kim_obj = kim_edn.load(str1) self.assertTrue(kim_obj[0]["instance-id"] == 1) self.assertTrue(kim_obj[1]["instance-id"] == 2) self.assertTrue(kim_obj[2]["instance-id"] == 5)
def check_property_definition(fp, _m=KEY_FORMAT.match): r"""Check the KIM property definition format. Check the KIM property definition format from a deserialized ``fp``. Arguments: fp (a ``.read()``-supporting file-like object, or a name string to a file containing a KIM-EDN document or a string or a KIM-EDN object) to a property definition Python object. """ # property definition if isinstance(fp, dict): pd = fp # Other format should be loaded by kim_edn else: pd = kim_edn.load(fp) if isinstance(pd, dict): try: check_required_keys_present(pd, rk=required_keys) check_property_id_format(pd["property-id"]) check_property_title_format(pd["property-title"]) # Check optional fields. for k in pd: if k not in required_keys: check_property_optional_key_map(k, pd[k], _m=_m) except KIMPropertyError: msg = '{} \n'.format(fp) msg += str(KIMPropertyError) raise KIMPropertyError(msg) else: msg = 'input to the function :\n' msg += '{}\n'.format(fp) msg += 'is not a correct KIM-EDN type.' raise KIMPropertyError(msg)
def test_unpickle_kim_properties(self): """Test unpickling the KIM properties.""" # Fails when can't load pickle from unicode string self.assertRaises(self.KIMPropertyError, unpickle_kim_properties, 'kim_properties.pickle') # Property definition edn file edn_file1 = join("tests", "fixtures", "atomic-mass.edn") self.assertTrue(isfile(edn_file1)) edn_file2 = join("tests", "fixtures", "cohesive-energy-relation-cubic-crystal.edn") self.assertTrue(isfile(edn_file2)) properties = {"tag:[email protected],2016-05-11:property/atomic-mass": kim_edn.load(edn_file1), "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal": kim_edn.load(edn_file2)} bio = BytesIO() pickle_kim_properties(properties, bio) # Test the unpickle utility _properties, _name_to_id, _id_to_name = unpickle_kim_properties( bio.getvalue()) name_to_id = {"atomic-mass": "tag:[email protected],2016-05-11:property/atomic-mass", "cohesive-energy-relation-cubic-crystal": "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal"} id_to_name = {"tag:[email protected],2016-05-11:property/atomic-mass": "atomic-mass", "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal": "cohesive-energy-relation-cubic-crystal"} self.assertTrue(_properties == properties) self.assertTrue(_name_to_id == name_to_id) self.assertTrue(_id_to_name == id_to_name) bio1 = BytesIO() # Fails when neither can open nor load the input self.assertRaises(self.KIMPropertyError, unpickle_kim_properties, bio1.getvalue())
def test_pickle_kim_properties(self): """Test pickling the KIM properties.""" # Property definition edn file edn_file1 = join("tests", "fixtures", "atomic-mass.edn") self.assertTrue(isfile(edn_file1)) edn_file2 = join("tests", "fixtures", "cohesive-energy-relation-cubic-crystal.edn") self.assertTrue(isfile(edn_file2)) properties = {"tag:[email protected],2016-05-11:property/atomic-mass": kim_edn.load(edn_file1), "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal": kim_edn.load(edn_file2)} name_to_id = {"atomic-mass": "tag:[email protected],2016-05-11:property/atomic-mass", "cohesive-energy-relation-cubic-crystal": "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal"} id_to_name = {"tag:[email protected],2016-05-11:property/atomic-mass": "atomic-mass", "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal": "cohesive-energy-relation-cubic-crystal"} bio = BytesIO() pickle_kim_properties(properties, bio) _properties, _name_to_id, _id_to_name = pickle.loads(bio.getvalue()) self.assertTrue(_properties == properties) self.assertTrue(_name_to_id == name_to_id) self.assertTrue(_id_to_name == id_to_name) sio = StringIO() self.assertRaises(self.KIMPropertyError, pickle_kim_properties, properties, sio)
def check_property_instances(fi, fp=None, fp_path=None, _m=KEY_FORMAT.match): r"""Check the KIM property instances format. Check the KIM property instances format from a deserialized ``fi``. Property Instances are either Predictions or items of Reference Data and must conform to the specification in the associated Property Definition. A Property Instance is stored in a subset of the EDN format. Multiple Property Instances in a file may optionally be contained within an array represented by a start bracket \(\[\) at the beginning, and an end bracket \(\]\) at the end of the file: Arguments: fi (a ``.read()``-supporting file-like object, or a name string to a file containing a KIM-EDN document or a string or a KIM-EDN object) to a property instance Python object. fp (a ``.read()``-supporting file-like object, or a name string to a file containing a KIM-EDN document or a string) to a property definition Python object. (default: None) fp_path should be an absolute path (or a valid relative path) to the KIM property definition folder. (default: None) or a KIM properties object containing all the available properties """ # Check whether the property definition is provided? if fp is None: # Check whether the path is provided to the property files? if fp_path is None: msg = 'either the absolute path to the KIM properties ' msg += 'or a KIM property definition should be provided.' raise KIMPropertyError(msg) if isinstance(fp_path, str): # Check whether the provided path is an absolute path? if not isabs(fp_path): # Loosen the check for the relative path which exists if isdir(fp_path): fp_path = abspath(fp_path) else: msg = 'the path KIM properties should be an ' msg += 'absolute path name.' raise KIMPropertyError(msg) elif not isinstance(fp_path, dict): msg = 'wrong KIM properties object.' raise KIMPropertyError(msg) # Property definition file is provided elif fp_path is not None: msg = 'only the absolute path to the KIM properties ' msg += 'or a KIM property file should be provided (not both).' raise KIMPropertyError(msg) # Property instance if isinstance(fi, (list, dict)): pi = fi else: pi = kim_edn.load(fi) if isinstance(pi, dict): check_required_keys_present(pi, rk=required_keys) check_property_id_format(pi["property-id"]) if fp is None: if isinstance(fp_path, dict): if pi["property-id"] in fp_path: fp = fp_path[pi["property-id"]] else: msg = 'the requested property ID = \n"' msg += pi["property-id"] msg += '"\ndoes not exist in the input KIM properties.' raise KIMPropertyError(msg) else: _path, _, _, _property_name = get_property_id_path( pi["property-id"]) if isfile(join(fp_path, _path)): fp = join(fp_path, _path) elif isfile(join(fp_path, _property_name + ".edn")): fp = join(fp_path, _property_name + ".edn") else: msg = 'unable to find a KIM property definition at {\n"' msg += join(fp_path, _path) msg += '",\nnor at\n"' msg += join(fp_path, _property_name + ".edn") msg += '"}' raise KIMPropertyError(msg) del _path del _property_name if isinstance(fp, dict): # It is already in the KIM-EDN format pd = fp else: # property definition pd = kim_edn.load(fp) # We have to check if required keys are there check_required_keys_present(pd, rk=def_required_keys) if pd["property-id"] != pi["property-id"]: msg = 'wrong property definition is provided.\n' msg += 'Property id :\n' msg += '{}\n'.format(pd["property-id"]) msg += 'read from the property definition file is different ' msg += 'from the property id :\n' msg += '{}\n'.format(pi["property-id"]) msg += 'read from the property instance file.' raise KIMPropertyError(msg) check_instance_id_format(pi["instance-id"]) # Check optional fields. for k in pi: if k not in required_keys: if k in pd: check_instance_optional_key_map(k, pi[k], pd[k], _m=_m) else: check_instance_optional_key_map(k, pi[k], _m=_m) # Check optional variables marked required are present in the instance. check_instance_optional_key_marked_required_are_present(pi, pd) elif isinstance(pi, list): instance_id = [] for pi_ in pi: check_required_keys_present(pi_, rk=required_keys) check_property_id_format(pi_["property-id"]) if fp is None: if isinstance(fp_path, dict): if pi_["property-id"] in fp_path: pd = fp_path[pi_["property-id"]] else: msg = 'the requested property ID = \n"' msg += pi_["property-id"] msg += '"\ndoes not exist in the input KIM ' msg += 'properties.' raise KIMPropertyError(msg) else: _path, _, _, _property_name = get_property_id_path( pi_["property-id"]) if isfile(join(fp_path, _path)): fp = join(fp_path, _path) elif isfile(join(fp_path, _property_name + ".edn")): fp = join(fp_path, _property_name + ".edn") else: msg = 'unable to find a KIM property definition ' msg += 'at {\n"' msg += join(fp_path, _path) msg += '",\nnor at\n"' msg += join(fp_path, _property_name + ".edn") msg += '"}' raise KIMPropertyError(msg) # property definition pd = kim_edn.load(fp) # Set fp back to None for the next property in the loop fp = None else: if isinstance(fp, dict): # It is already in the KIM-EDN format pd = fp else: # property definition pd = kim_edn.load(fp) # We have to check if required keys are there check_required_keys_present(pd, rk=def_required_keys) if pd["property-id"] != pi_["property-id"]: msg = 'wrong property definition is provided.\n' msg += 'Property id :\n' msg += '{}\n'.format(pd["property-id"]) msg += 'read from the property definition file is different ' msg += 'from the property id :\n' msg += '{}\n'.format(pi_["property-id"]) msg += 'read from the property instance file.' raise KIMPropertyError(msg) check_instance_id_format(pi_["instance-id"]) if pi_["instance-id"] in instance_id: msg = 'the "instance-id’s" cannot repeat.' raise KIMPropertyError(msg) instance_id.append(pi_["instance-id"]) # Check optional fields. for k in pi_: if k not in required_keys: if k in pd: check_instance_optional_key_map(k, pi_[k], pd[k], _m=_m) else: check_instance_optional_key_map(k, pi_[k], _m=_m) # Check optional variables marked required # are present in the instance. check_instance_optional_key_marked_required_are_present(pi_, pd) else: msg = 'input to the function does not have a correct KIM-EDN format.' raise KIMPropertyError(msg)
def test_remove(self): """Test the remove 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] self.assertTrue("a" in kim_obj) self.assertTrue("source-value" in kim_obj["a"]) self.assertTrue("cohesive-potential-energy" in kim_obj) self.assertTrue("basis-atom-coordinates" in kim_obj) # Fail when there is no property instance to remove the content. for str_obj1 in [None, 'None', '', '[]']: self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj1, 1, "key", "a") # Fails when the "instance_id" is not an `int`. self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, 1.0, "key", "a") self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, "1", "key", "a") self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, [1], "key", "a") self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, {1}, "key", "a") # Fails when the requested instance id doesn\'t match any # of the property instances ids. self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, 10, "key", "a") self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, 2, "key", "a") # Fails when the key doesn\'t exist in the property instance. self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, 1, "key", "new_item") self.assertRaises(self.KIMPropertyError, self.kim_property.kim_property_remove, str_obj, 1, "key", "aa") # Removing the whole key str_obj1 = self.kim_property.kim_property_remove( str_obj, 1, "key", "a") kim_obj1 = kim_edn.load(str_obj1)[0] self.assertFalse("a" in kim_obj1) del str_obj1 del kim_obj1 # Removing the internal key from the key-map pairs for key str_obj2 = self.kim_property.kim_property_remove( str_obj, 1, "key", "a", "source-value") kim_obj2 = kim_edn.load(str_obj2)[0] self.assertTrue("a" in kim_obj2) self.assertFalse("source-value" in kim_obj2["a"]) del str_obj2 del kim_obj2 # Removing multiple keys str_obj3 = self.kim_property.kim_property_remove( str_obj, 1, "key", "cohesive-potential-energy", "key", "basis-atom-coordinates") kim_obj3 = kim_edn.load(str_obj3)[0] self.assertFalse("cohesive-potential-energy" in kim_obj3) self.assertFalse("basis-atom-coordinates" in kim_obj3) str_obj3 = self.kim_property.kim_property_remove( str_obj3, 1, "key", "a", "source-unit") kim_obj3 = kim_edn.load(str_obj3)[0] self.assertTrue("a" in kim_obj3) self.assertTrue("source-value" in kim_obj3["a"]) self.assertFalse("source-unit" in kim_obj3["a"]) # Test for scalar values str_obj4 = self.kim_property.kim_property_modify( str_obj3, 1, "key", "space-group", "source-value", "Immm") str_obj4 = self.kim_property.kim_property_modify( str_obj4, 1, "key", "space-group", "source-value", "Fm-3m") kim_obj4 = kim_edn.load(str_obj4)[0] self.assertTrue(kim_obj4["space-group"]["source-value"] == "Fm-3m") str_obj4 = self.kim_property.kim_property_remove( str_obj4, 1, "key", "space-group", "source-value") kim_obj4 = kim_edn.load(str_obj4)[0] self.assertFalse("source-value" in kim_obj4["space-group"]) str_obj4 = self.kim_property.kim_property_modify( str_obj4, 1, "key", "space-group", "source-value", "Fm-3m") kim_obj4 = kim_edn.load(str_obj4)[0] self.assertTrue(kim_obj4["space-group"]["source-value"] == "Fm-3m")
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 pickle_kim_properties(properties=None, fp=join(kim_properties_path, 'kim_properties.pickle'), protocol=0): """Serialize KIM properties. Keyword Arguments: properties {dict} -- KIM properties dictionary indexed by properties full IDs. (default: {None}) fp {string, or a ``.write()``-supporting bytes-like object} -- fp is a file name string to open it or a ``.write()``-supporting bytes-like object. protocol {int} -- protocol which can be used for pickling. (default: {0}) """ # List of KIM properties to be pickled kim_properties_list = [] if properties is None: # KIM property files. kim_property_files = [] # KIM property files path. An absolute path (or a valid relative path) # to the KIM property files folder. kim_property_files_path = join(dirname(abspath(__file__)), pardir, "external", "openkim-properties", "properties") if isdir(abspath(kim_property_files_path)): kim_property_files_path = abspath(kim_property_files_path) else: msg = 'property files can not be found!' raise KIMPropertyError(msg) # KIM property names. kim_property_names = [ "atomic-mass", "bulk-modulus-isothermal-cubic-crystal-npt", "bulk-modulus-isothermal-hexagonal-crystal-npt", "cohesive-energy-lattice-invariant-shear-path-cubic-crystal", "cohesive-energy-lattice-invariant-shear-unrelaxed-path-cubic-crystal", "cohesive-energy-relation-cubic-crystal", "cohesive-energy-shear-stress-path-cubic-crystal", "cohesive-free-energy-cubic-crystal", "cohesive-free-energy-hexagonal-crystal", "cohesive-potential-energy-2d-hexagonal-crystal", "cohesive-potential-energy-cubic-crystal", "cohesive-potential-energy-hexagonal-crystal", "configuration-cluster-fixed", "configuration-cluster-relaxed", "configuration-nonorthogonal-periodic-3d-cell-fixed-particles-fixed", "configuration-nonorthogonal-periodic-3d-cell-fixed-particles-relaxed", "configuration-nonorthogonal-periodic-3d-cell-relaxed-particles-fixed", "configuration-nonorthogonal-periodic-3d-cell-relaxed-particles-relaxed", "configuration-periodic-2d-cell-fixed-particles-fixed", "dislocation-core-energy-cubic-crystal-npt", "elastic-constants-first-strain-gradient-isothermal-cubic-crystal-npt", "elastic-constants-first-strain-gradient-isothermal-monoatomic-hexagonal-crystal-npt", "elastic-constants-isothermal-cubic-crystal-npt", "enthalpy-of-mixing-curve-substitutional-binary-cubic-crystal-npt", "enthalpy-of-mixing-curve-substitutional-binary-cubic-crystal-nvt", "extrinsic-stacking-fault-relaxed-energy-fcc-crystal-npt", "gamma-surface-relaxed-fcc-crystal-npt", "grain-boundary-symmetric-tilt-energy-ideal-cubic-crystal", "grain-boundary-symmetric-tilt-energy-relaxed-cubic-crystal", "grain-boundary-symmetric-tilt-energy-relaxed-relation-cubic-crystal", "intrinsic-stacking-fault-relaxed-energy-fcc-crystal-npt", "linear-thermal-expansion-coefficient-cubic-crystal-npt", "melting-temperature-constant-pressure-cubic-crystal", "monovacancy-formation-energy-monoatomic-cubic-diamond", "monovacancy-neutral-formation-free-energy-crystal-npt", "monovacancy-neutral-migration-energy-crystal-npt", "monovacancy-neutral-relaxation-volume-crystal-npt", "monovacancy-neutral-relaxed-formation-potential-energy-crystal-npt", "monovacancy-neutral-unrelaxed-formation-potential-energy-crystal-npt", "phonon-dispersion-dos-cubic-crystal-npt", "phonon-dispersion-relation-cubic-crystal-npt", "shear-stress-path-cubic-crystal", "stacking-fault-relaxed-energy-curve-fcc-crystal-npt", "structure-2d-hexagonal-crystal-npt", "structure-cubic-crystal-npt", "structure-hexagonal-crystal-npt", "structure-monoclinic-crystal-npt", "structure-orthorhombic-crystal-npt", "structure-rhombohedral-crystal-npt", "structure-tetragonal-crystal-npt", "structure-triclinic-crystal-npt", "surface-energy-broken-bond-fit-cubic-bravais-crystal-npt", "surface-energy-cubic-crystal-npt", "surface-energy-ideal-cubic-crystal", "unstable-stacking-fault-relaxed-energy-fcc-crystal-npt", "unstable-twinning-fault-relaxed-energy-fcc-crystal-npt", "verification-check", ] # KIM property full IDs. kim_property_ids = [ "tag:[email protected],2016-05-11:property/atomic-mass", "tag:[email protected],2014-04-15:property/bulk-modulus-isothermal-cubic-crystal-npt", "tag:[email protected],2014-04-15:property/bulk-modulus-isothermal-hexagonal-crystal-npt", "tag:[email protected],2015-05-26:property/cohesive-energy-lattice-invariant-shear-path-cubic-crystal", "tag:[email protected],2015-05-26:property/cohesive-energy-lattice-invariant-shear-unrelaxed-path-cubic-crystal", "tag:[email protected],2014-04-15:property/cohesive-energy-relation-cubic-crystal", "tag:[email protected],2015-05-26:property/cohesive-energy-shear-stress-path-cubic-crystal", "tag:[email protected],2014-04-15:property/cohesive-free-energy-cubic-crystal", "tag:[email protected],2014-04-15:property/cohesive-free-energy-hexagonal-crystal", "tag:[email protected],2015-05-26:property/cohesive-potential-energy-2d-hexagonal-crystal", "tag:[email protected],2014-04-15:property/cohesive-potential-energy-cubic-crystal", "tag:[email protected],2014-04-15:property/cohesive-potential-energy-hexagonal-crystal", "tag:[email protected],2014-04-15:property/configuration-cluster-fixed", "tag:[email protected],2014-04-15:property/configuration-cluster-relaxed", "tag:[email protected],2014-04-15:property/configuration-nonorthogonal-periodic-3d-cell-fixed-particles-fixed", "tag:[email protected],2014-04-15:property/configuration-nonorthogonal-periodic-3d-cell-fixed-particles-relaxed", "tag:[email protected],2014-04-15:property/configuration-nonorthogonal-periodic-3d-cell-relaxed-particles-fixed", "tag:[email protected],2014-04-15:property/configuration-nonorthogonal-periodic-3d-cell-relaxed-particles-relaxed", "tag:[email protected],2015-10-12:property/configuration-periodic-2d-cell-fixed-particles-fixed", "tag:[email protected],2021-02-24:property/dislocation-core-energy-cubic-crystal-npt", "tag:[email protected],2016-05-24:property/elastic-constants-first-strain-gradient-isothermal-cubic-crystal-npt", "tag:[email protected],2016-05-24:property/elastic-constants-first-strain-gradient-isothermal-monoatomic-hexagonal-crystal-npt", "tag:[email protected],2014-05-21:property/elastic-constants-isothermal-cubic-crystal-npt", "tag:[email protected],2017-07-31:property/enthalpy-of-mixing-curve-substitutional-binary-cubic-crystal-npt", "tag:[email protected],2017-07-31:property/enthalpy-of-mixing-curve-substitutional-binary-cubic-crystal-nvt", "tag:[email protected],2015-05-26:property/extrinsic-stacking-fault-relaxed-energy-fcc-crystal-npt", "tag:[email protected],2015-05-26:property/gamma-surface-relaxed-fcc-crystal-npt", "tag:[email protected],2016-01-23:property/grain-boundary-symmetric-tilt-energy-ideal-cubic-crystal", "tag:[email protected],2016-01-23:property/grain-boundary-symmetric-tilt-energy-relaxed-cubic-crystal", "tag:[email protected],2016-02-18:property/grain-boundary-symmetric-tilt-energy-relaxed-relation-cubic-crystal", "tag:[email protected],2015-05-26:property/intrinsic-stacking-fault-relaxed-energy-fcc-crystal-npt", "tag:[email protected],2015-07-30:property/linear-thermal-expansion-coefficient-cubic-crystal-npt", "tag:[email protected],2014-08-21:property/melting-temperature-constant-pressure-cubic-crystal", "tag:[email protected],2014-04-15:property/monovacancy-formation-energy-monoatomic-cubic-diamond", "tag:[email protected],2015-07-28:property/monovacancy-neutral-formation-free-energy-crystal-npt", "tag:[email protected],2015-09-16:property/monovacancy-neutral-migration-energy-crystal-npt", "tag:[email protected],2015-07-28:property/monovacancy-neutral-relaxation-volume-crystal-npt", "tag:[email protected],2015-07-28:property/monovacancy-neutral-relaxed-formation-potential-energy-crystal-npt", "tag:[email protected],2015-07-28:property/monovacancy-neutral-unrelaxed-formation-potential-energy-crystal-npt", "tag:[email protected],2014-05-21:property/phonon-dispersion-dos-cubic-crystal-npt", "tag:[email protected],2014-05-21:property/phonon-dispersion-relation-cubic-crystal-npt", "tag:[email protected],2015-05-26:property/shear-stress-path-cubic-crystal", "tag:[email protected],2015-05-26:property/stacking-fault-relaxed-energy-curve-fcc-crystal-npt", "tag:[email protected],2015-05-26:property/structure-2d-hexagonal-crystal-npt", "tag:[email protected],2014-04-15:property/structure-cubic-crystal-npt", "tag:[email protected],2014-04-15:property/structure-hexagonal-crystal-npt", "tag:[email protected],2014-04-15:property/structure-monoclinic-crystal-npt", "tag:[email protected],2014-04-15:property/structure-orthorhombic-crystal-npt", "tag:[email protected],2014-04-15:property/structure-rhombohedral-crystal-npt", "tag:[email protected],2014-04-15:property/structure-tetragonal-crystal-npt", "tag:[email protected],2014-04-15:property/structure-triclinic-crystal-npt", "tag:[email protected],2014-05-21:property/surface-energy-broken-bond-fit-cubic-bravais-crystal-npt", "tag:[email protected],2014-05-21:property/surface-energy-cubic-crystal-npt", "tag:[email protected],2014-05-21:property/surface-energy-ideal-cubic-crystal", "tag:[email protected],2015-05-26:property/unstable-stacking-fault-relaxed-energy-fcc-crystal-npt", "tag:[email protected],2015-05-26:property/unstable-twinning-fault-relaxed-energy-fcc-crystal-npt", "tag:[email protected],2017-02-01:property/verification-check", ] for _id in kim_property_ids: _path, _, _, _ = get_property_id_path(_id) kim_property_files.append(join(kim_property_files_path, _path)) if not isfile(kim_property_files[-1]): msg = 'the property file =\n"' msg += kim_property_files[-1] msg += '"\ncan not be found!' raise KIMPropertyError(msg) del kim_property_files_path # KIM properties dictionary indexed by properties full IDs. kim_properties = { k: kim_edn.load(v) for k, v in zip(kim_property_ids, kim_property_files) } # KIM properties name to full ID dictionary. property_name_to_property_id = \ dict(zip(kim_property_names, kim_property_ids)) # KIM properties full ID to name dictionary. property_id_to_property_name = \ dict(zip(kim_property_ids, kim_property_names)) del kim_property_names del kim_property_ids kim_properties_list = [ kim_properties, property_name_to_property_id, property_id_to_property_name, ] else: if not isinstance(properties, dict): msg = 'wrong input, "properties" is not a `dict`.' raise KIMPropertyError(msg) if len(properties) == 0: msg = 'wrong input, "properties" is empty.' raise KIMPropertyError(msg) property_ids = list(properties.keys()) property_names = [] for _id in property_ids: _, _, _, _name = get_property_id_path(_id) property_names.append(_name) # KIM properties name to full ID dictionary. name_to_property_id = dict(zip(property_names, property_ids)) # KIM properties full ID to name dictionary. id_to_property_name = dict(zip(property_ids, property_names)) del property_names del property_ids kim_properties_list = [ properties, name_to_property_id, id_to_property_name, ] if isinstance(fp, str): # See if this is a file name with open(fp, 'wb') as f: # Pickle the kim_properties pickle.dump(kim_properties_list, f, protocol=protocol) else: try: pickle.dump(kim_properties_list, fp, protocol=protocol) except: msg = 'wrong input. ("fp" should refer to a bytes-like object.)' raise KIMPropertyError(msg)
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)