Example #1
0
    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)
Example #2
0
    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)
Example #3
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)
Example #4
0
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)
Example #5
0
    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)
Example #6
0
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)
Example #7
0
    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())
Example #8
0
    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)
Example #9
0
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)
Example #10
0
    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")
Example #11
0
    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)
Example #12
0
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)
Example #13
0
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)