From 71744641ffe6a1e490837383e1f7d4dbef43f427 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sat, 4 Mar 2023 16:20:25 -0300 Subject: [PATCH] Read Potentials and Initial Testing --- Pipfile | 1 + Pipfile.lock | 180 ++-- control.yml.example => control.example.yml | 2 +- diceplayer/DPpack/External/Dice.py | 753 ---------------- diceplayer/DPpack/External/Gaussian.py | 595 ------------- diceplayer/DPpack/Player.py | 801 ------------------ diceplayer/DPpack/Utils/Misc.py | 67 -- diceplayer/DPpack/Utils/Optimization.py | 263 ------ diceplayer/DPpack/Utils/StepDTO.py | 21 - .../{DPpack/Environment => }/__init__.py | 0 diceplayer/__main__.py | 191 +---- diceplayer/player.py | 274 ++++++ .../{DPpack/External => shared}/__init__.py | 0 .../Utils => shared/config}/__init__.py | 0 diceplayer/shared/config/dice_dto.py | 54 ++ diceplayer/shared/config/gaussian_dto.py | 28 + diceplayer/shared/config/player_dto.py | 24 + .../environment}/__init__.py | 0 .../Atom.py => shared/environment/atom.py} | 22 +- .../environment/molecule.py} | 100 +-- .../environment/system.py} | 32 +- diceplayer/shared/external/__external.py | 26 + diceplayer/shared/external/__init__.py | 0 diceplayer/shared/external/dice.py | 22 + diceplayer/shared/external/gaussian.py | 23 + diceplayer/shared/utils/__init__.py | 0 diceplayer/shared/utils/dataclass_protocol.py | 6 + diceplayer/shared/utils/misc.py | 64 ++ .../PTable.py => shared/utils/ptable.py} | 0 .../utils/validations.py} | 0 tests/__init__.py | 0 tests/shared/__init__.py | 0 tests/shared/environment/__init__.py | 0 tests/shared/environment/atom.py | 19 + tests/shared/environment/molecule.py | 61 ++ 35 files changed, 793 insertions(+), 2836 deletions(-) rename control.yml.example => control.example.yml (100%) delete mode 100644 diceplayer/DPpack/External/Dice.py delete mode 100644 diceplayer/DPpack/External/Gaussian.py delete mode 100644 diceplayer/DPpack/Player.py delete mode 100644 diceplayer/DPpack/Utils/Misc.py delete mode 100644 diceplayer/DPpack/Utils/Optimization.py delete mode 100644 diceplayer/DPpack/Utils/StepDTO.py rename diceplayer/{DPpack/Environment => }/__init__.py (100%) create mode 100644 diceplayer/player.py rename diceplayer/{DPpack/External => shared}/__init__.py (100%) rename diceplayer/{DPpack/Utils => shared/config}/__init__.py (100%) create mode 100644 diceplayer/shared/config/dice_dto.py create mode 100644 diceplayer/shared/config/gaussian_dto.py create mode 100644 diceplayer/shared/config/player_dto.py rename diceplayer/{DPpack => shared/environment}/__init__.py (100%) rename diceplayer/{DPpack/Environment/Atom.py => shared/environment/atom.py} (86%) rename diceplayer/{DPpack/Environment/Molecule.py => shared/environment/molecule.py} (87%) rename diceplayer/{DPpack/Environment/System.py => shared/environment/system.py} (91%) create mode 100644 diceplayer/shared/external/__external.py create mode 100644 diceplayer/shared/external/__init__.py create mode 100644 diceplayer/shared/external/dice.py create mode 100644 diceplayer/shared/external/gaussian.py create mode 100644 diceplayer/shared/utils/__init__.py create mode 100644 diceplayer/shared/utils/dataclass_protocol.py create mode 100644 diceplayer/shared/utils/misc.py rename diceplayer/{DPpack/Utils/PTable.py => shared/utils/ptable.py} (100%) rename diceplayer/{DPpack/Utils/Validations.py => shared/utils/validations.py} (100%) create mode 100644 tests/__init__.py create mode 100644 tests/shared/__init__.py create mode 100644 tests/shared/environment/__init__.py create mode 100644 tests/shared/environment/atom.py create mode 100644 tests/shared/environment/molecule.py diff --git a/Pipfile b/Pipfile index fe71db5..ed75480 100644 --- a/Pipfile +++ b/Pipfile @@ -13,6 +13,7 @@ pyyaml = "*" nptyping = "*" intel-openmp = "*" typing = "*" +dacite = "*" [dev-packages] pyinstaller = "*" diff --git a/Pipfile.lock b/Pipfile.lock index b528f76..d61ee4f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "37db6602bae8a383e7907bd2bfb346daf1051cfb240564b5d23de92a0cdd7536" + "sha256": "f68e7183744102bdc470014dfc368a947097de4d482f891b1c9b31d17160fd64" }, "pipfile-spec": 6, "requires": { @@ -31,58 +31,64 @@ "index": "pypi", "version": "==1.4.0" }, - "intel-openmp": { + "dacite": { "hashes": [ - "sha256:22e09934d9f8f8b864ae68cab95bf43667f00d24e4675eb6d2a4ee089754c439", - "sha256:342c9e2b6e1500a9fb8d39828293ab5f9bb310b81fad7eba5c9d865001b95a7e", - "sha256:6ae4a878135ec08aa16dd97b6d72ac16bb92fad4c6ba40f28b3558d70b1f447a", - "sha256:77414289c14cb48d7f99926da69c9ced9e70c27feb825b0608f304f9d49844ae", - "sha256:c8b95fc493e2945b259153f7b0dd34a3d849e8e1e43b6c14ac04f613b3b45433" + "sha256:6257a5e505b61a8cafee7ef3ad08cf32ee9b885718f42395d017e0a9b4c6af65", + "sha256:f7b1205cc5d9b62835aac8cbc1e6e37c1da862359a401f1edbe2ae08fbdc6193" ], "index": "pypi", - "version": "==2022.2.1" + "version": "==1.8.0" + }, + "intel-openmp": { + "hashes": [ + "sha256:1ebce47df0b5ddad77992a70689fd3185df25f47cf901dd8384fd6d05a974f81", + "sha256:77131c2cda75ace2060f6e9cdcc9f9c672ec838c4602fc544ce0858cfe8f416e", + "sha256:adfb32b0dde6b3a95ced62608b05a45a7cfad928054136ddbfe0563e16cbf33c" + ], + "index": "pypi", + "version": "==2023.0.0" }, "nptyping": { "hashes": [ - "sha256:23e8164b1e2c55e872f392ca7516b9b1b0cb400b03b70accaa63998b4106b0b3", - "sha256:57ba684ee5fc5eb681ee04270ee94adb879e4372ce6b640defa08ace8e1df295" + "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", + "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a" ], "index": "pypi", - "version": "==2.4.1" + "version": "==2.5.0" }, "numpy": { "hashes": [ - "sha256:0fe563fc8ed9dc4474cbf70742673fc4391d70f4363f917599a7fa99f042d5a8", - "sha256:12ac457b63ec8ded85d85c1e17d85efd3c2b0967ca39560b307a35a6703a4735", - "sha256:2341f4ab6dba0834b685cce16dad5f9b6606ea8a00e6da154f5dbded70fdc4dd", - "sha256:296d17aed51161dbad3c67ed6d164e51fcd18dbcd5dd4f9d0a9c6055dce30810", - "sha256:488a66cb667359534bc70028d653ba1cf307bae88eab5929cd707c761ff037db", - "sha256:4d52914c88b4930dafb6c48ba5115a96cbab40f45740239d9f4159c4ba779962", - "sha256:5e13030f8793e9ee42f9c7d5777465a560eb78fa7e11b1c053427f2ccab90c79", - "sha256:61be02e3bf810b60ab74e81d6d0d36246dbfb644a462458bb53b595791251911", - "sha256:7607b598217745cc40f751da38ffd03512d33ec06f3523fb0b5f82e09f6f676d", - "sha256:7a70a7d3ce4c0e9284e92285cba91a4a3f5214d87ee0e95928f3614a256a1488", - "sha256:7ab46e4e7ec63c8a5e6dbf5c1b9e1c92ba23a7ebecc86c336cb7bf3bd2fb10e5", - "sha256:8981d9b5619569899666170c7c9748920f4a5005bf79c72c07d08c8a035757b0", - "sha256:8c053d7557a8f022ec823196d242464b6955a7e7e5015b719e76003f63f82d0f", - "sha256:926db372bc4ac1edf81cfb6c59e2a881606b409ddc0d0920b988174b2e2a767f", - "sha256:95d79ada05005f6f4f337d3bb9de8a7774f259341c70bc88047a1f7b96a4bcb2", - "sha256:95de7dc7dc47a312f6feddd3da2500826defdccbc41608d0031276a24181a2c0", - "sha256:a0882323e0ca4245eb0a3d0a74f88ce581cc33aedcfa396e415e5bba7bf05f68", - "sha256:a8365b942f9c1a7d0f0dc974747d99dd0a0cdfc5949a33119caf05cb314682d3", - "sha256:a8aae2fb3180940011b4862b2dd3756616841c53db9734b27bb93813cd79fce6", - "sha256:c237129f0e732885c9a6076a537e974160482eab8f10db6292e92154d4c67d71", - "sha256:c67b833dbccefe97cdd3f52798d430b9d3430396af7cdb2a0c32954c3ef73894", - "sha256:ce03305dd694c4873b9429274fd41fc7eb4e0e4dea07e0af97a933b079a5814f", - "sha256:d331afac87c92373826af83d2b2b435f57b17a5c74e6268b79355b970626e329", - "sha256:dada341ebb79619fe00a291185bba370c9803b1e1d7051610e01ed809ef3a4ba", - "sha256:ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c", - "sha256:f260da502d7441a45695199b4e7fd8ca87db659ba1c78f2bbf31f934fe76ae0e", - "sha256:f2f390aa4da44454db40a1f0201401f9036e8d578a25f01a6e237cea238337ef", - "sha256:f76025acc8e2114bb664294a07ede0727aa75d63a06d2fae96bf29a81747e4a7" + "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22", + "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f", + "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9", + "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96", + "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0", + "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a", + "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281", + "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04", + "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468", + "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253", + "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756", + "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a", + "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb", + "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d", + "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0", + "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910", + "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978", + "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5", + "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f", + "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a", + "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5", + "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2", + "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d", + "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95", + "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5", + "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d", + "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780", + "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa" ], "index": "pypi", - "version": "==1.23.4" + "version": "==1.24.2" }, "pickle5": { "hashes": [ @@ -93,28 +99,29 @@ }, "pyinstaller": { "hashes": [ - "sha256:04ecf805bde2ef25b8e3642410871e6747c22fa7254107f155b8cd179c2a13b6", - "sha256:05df5d2b9ca645cc6ef61d8a85451d2aabe5501997f1f50cd94306fd6bc0485d", - "sha256:0d167d57036219914188f1400427dd297b975707e78c32a5511191e607be920a", - "sha256:181856ade585b090379ae26b7017dc2c30620e36e3a804b381417a6dc3b2a82b", - "sha256:1b1e3b37a22fb36555d917f0c3dfb998159ff4af6d8fa7cc0074d630c6fe81ad", - "sha256:32727232f446aa96e394f01b0c35b3de0dc3513c6ba3e26d1ef64c57edb1e9e5", - "sha256:77888f52b61089caa0bee70809bbce9e9b1c613c88b6cb0742ff2a45f1511cbb", - "sha256:865025b6809d777bb0f66d8f8ab50cc97dc3dbe0ff09a1ef1f2fd646432714fc", - "sha256:d888db9afedff290d362ee296d30eb339abeba707ca1565916ce1cd5947131c3", - "sha256:e026adc92c60158741d0bfca27eefaa2414801f61328cb84d0c88241fe8c2087", - "sha256:eb083c25f711769af0898852ea30dcb727ba43990bbdf9ffbaa9c77a7bd0d720" + "sha256:314fb883caf3cbf06adbea2b77671bb73c3481568e994af0467ea7e47eb64755", + "sha256:3b74f50a57b1413047042e47033480b7324b091f23dff790a4494af32b377d94", + "sha256:4f4d818588e2d8de4bf24ed018056c3de0c95898ad25719e12d68626161b4933", + "sha256:502a2166165a8e8c3d99c19272e923d2548bac2132424d78910ef9dd8bb11705", + "sha256:5c9632a20faecd6d79f0124afb31e6557414d19be271e572765b474f860f8d76", + "sha256:8d004699c5d71c704c14a5f81eec233faa4f87a3bf0ae68e222b87d63f5dd17e", + "sha256:a62ee598b137202ef2e99d8dbaee6bc7379a6565c3ddf0331decb41b98eff1a2", + "sha256:bacf236b5c2f8f674723a39daca399646dceb470881f842f52e393b9a67ff2f8", + "sha256:bf1f7b7e88b467d7aefcdb2bc9cbd2e856ca88c5ab232c0efe0848f146d3bd5f", + "sha256:ded780f0d3642d7bfc21d97b98d4ec4b41d2fe70c3f5c5d243868612f536e011", + "sha256:e68bcadf32edc1171ccb06117699a6a4f8e924b7c2c8812cfa00fd0186ade4ee", + "sha256:f9361eff44c7108c2312f39d85ed768c4ada7e0aa729046bbcef3ef3c1577d18" ], "index": "pypi", - "version": "==5.6.2" + "version": "==5.8.0" }, "pyinstaller-hooks-contrib": { "hashes": [ - "sha256:91ecb30db757a8db8b6661d91d5df99e0998245f05f5cfaade0550922c7030a3", - "sha256:e06d0881e599d94dc39c6ed1917f0ad9b1858a2478b9892faac18bd48bcdc2de" + "sha256:29d052eb73e0ab8f137f11df8e73d464c1c6d4c3044d9dc8df2af44639d8bfbf", + "sha256:bd578781cd6a33ef713584bf3726f7cd60a3e656ec08a6cc7971e39990808cc0" ], "markers": "python_version >= '3.7'", - "version": "==2022.13" + "version": "==2023.0" }, "pyyaml": { "hashes": [ @@ -172,13 +179,18 @@ "sha256:1ff863a20d1ff6ba2c24e22436a3daa3cd80be1dfb26891aae73f61b54b04aca", "sha256:265ecbe2c6eafe82e104f994ddd7c811520acdd0647b73f65c24f51374cf9494", "sha256:288943dec88e178bb2fd868adf491197cc0fc8b6810416b1c6775e686bab87fe", + "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa", "sha256:2e3ac25bfc4a0f29d2409650c7532d5ddfdbf29f16f8a256fc31c47d0dc05172", "sha256:2fbd8187948284293f43533c150cd69a0e4192c83c377da837dbcd29f6b83084", + "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80", "sha256:4058564195b975ddc3f0462375c533cce310ccdd41b80ac9aed641c296c3eff4", "sha256:4749a2b0c9ac52f864d13cee94546606f92b981b50e46226f7f830a56a9dc8e1", + "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77", "sha256:4d8938249a7cea45ab7e1e48b77685d0f2bab1ebfa9dde23e94ab97968996a7c", "sha256:5194b4969f82ea842a4f6af2f82cd16ebdc3f1771fb2771796e6add9835c1973", "sha256:55ce1e9925ce1765865442ede9dca0ba9bde10593fcd570b1f0fa25d3ec6b31c", + "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3", + "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077", "sha256:589be87172b238f839e19f146b9ea47c71e413e951ef0dc6db4218ddacf3c202", "sha256:5b932c3041aa924163f4aab970c2f0e6b4d9d773f4d50326e0ea1cd69240e5c5", "sha256:5fb4f769c02f63fac90989711a3fee83919f47ae9afd4758ced5d86596318c65", @@ -191,12 +203,15 @@ "sha256:7f0bed90a216ef28b9d227d8d73e28a8c9b88c0f48a082d13ab3fa83c581488f", "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1", "sha256:7fe9df7aeb8c64db6c34fc3b13271a363475d77bc157d3f00275a53910cb1989", + "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff", + "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf", "sha256:8ff3c8cb26afaed25e8bca7b9dd0c1e36de71f35a3a0706b5c0d5172587a3827", "sha256:9124bedd8006b0e04d4e8a71a0945da9b67e7a4ab88fdad7b1440dc5b6122c42", "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927", "sha256:a149a5f7f2c5a065d4e63cb0d7a4b6d3b66e6e80f12e3f8827c4f63974cbf122", "sha256:a47d97a75fd2d10c37410b180f67a5835cb1d8fdea2648fd7f359d4277f180b9", "sha256:a499fff50387c1520c085a07578a000123f519e5f3eee61dd68e1d301659651f", + "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4", "sha256:ab45146c71ca6592c9cc8b354a2cc9cc4843c33efcbe1d245d7d37ce9696552d", "sha256:b2c9cb2705fc84cb8798f1ba74194f4c080aaef19d9dae843591c09b97678e98", "sha256:b34baef93bfb20a8ecb930e395ccd2ae3268050d8cf4fe187de5e2bd806fd796", @@ -206,7 +221,10 @@ "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806", "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484", "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e", + "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc", + "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de", "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575", + "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7", "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76", "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246", "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb", @@ -216,6 +234,7 @@ "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865", "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b", "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d", + "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e", "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10", "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f", "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94", @@ -230,11 +249,11 @@ }, "setuptools": { "hashes": [ - "sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31", - "sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f" + "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330", + "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251" ], "markers": "python_version >= '3.7'", - "version": "==65.5.1" + "version": "==67.4.0" }, "typing": { "hashes": [ @@ -243,6 +262,14 @@ ], "index": "pypi", "version": "==3.7.4.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb", + "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4" + ], + "markers": "python_version < '3.10'", + "version": "==4.5.0" } }, "develop": { @@ -255,36 +282,37 @@ }, "pyinstaller": { "hashes": [ - "sha256:04ecf805bde2ef25b8e3642410871e6747c22fa7254107f155b8cd179c2a13b6", - "sha256:05df5d2b9ca645cc6ef61d8a85451d2aabe5501997f1f50cd94306fd6bc0485d", - "sha256:0d167d57036219914188f1400427dd297b975707e78c32a5511191e607be920a", - "sha256:181856ade585b090379ae26b7017dc2c30620e36e3a804b381417a6dc3b2a82b", - "sha256:1b1e3b37a22fb36555d917f0c3dfb998159ff4af6d8fa7cc0074d630c6fe81ad", - "sha256:32727232f446aa96e394f01b0c35b3de0dc3513c6ba3e26d1ef64c57edb1e9e5", - "sha256:77888f52b61089caa0bee70809bbce9e9b1c613c88b6cb0742ff2a45f1511cbb", - "sha256:865025b6809d777bb0f66d8f8ab50cc97dc3dbe0ff09a1ef1f2fd646432714fc", - "sha256:d888db9afedff290d362ee296d30eb339abeba707ca1565916ce1cd5947131c3", - "sha256:e026adc92c60158741d0bfca27eefaa2414801f61328cb84d0c88241fe8c2087", - "sha256:eb083c25f711769af0898852ea30dcb727ba43990bbdf9ffbaa9c77a7bd0d720" + "sha256:314fb883caf3cbf06adbea2b77671bb73c3481568e994af0467ea7e47eb64755", + "sha256:3b74f50a57b1413047042e47033480b7324b091f23dff790a4494af32b377d94", + "sha256:4f4d818588e2d8de4bf24ed018056c3de0c95898ad25719e12d68626161b4933", + "sha256:502a2166165a8e8c3d99c19272e923d2548bac2132424d78910ef9dd8bb11705", + "sha256:5c9632a20faecd6d79f0124afb31e6557414d19be271e572765b474f860f8d76", + "sha256:8d004699c5d71c704c14a5f81eec233faa4f87a3bf0ae68e222b87d63f5dd17e", + "sha256:a62ee598b137202ef2e99d8dbaee6bc7379a6565c3ddf0331decb41b98eff1a2", + "sha256:bacf236b5c2f8f674723a39daca399646dceb470881f842f52e393b9a67ff2f8", + "sha256:bf1f7b7e88b467d7aefcdb2bc9cbd2e856ca88c5ab232c0efe0848f146d3bd5f", + "sha256:ded780f0d3642d7bfc21d97b98d4ec4b41d2fe70c3f5c5d243868612f536e011", + "sha256:e68bcadf32edc1171ccb06117699a6a4f8e924b7c2c8812cfa00fd0186ade4ee", + "sha256:f9361eff44c7108c2312f39d85ed768c4ada7e0aa729046bbcef3ef3c1577d18" ], "index": "pypi", - "version": "==5.6.2" + "version": "==5.8.0" }, "pyinstaller-hooks-contrib": { "hashes": [ - "sha256:91ecb30db757a8db8b6661d91d5df99e0998245f05f5cfaade0550922c7030a3", - "sha256:e06d0881e599d94dc39c6ed1917f0ad9b1858a2478b9892faac18bd48bcdc2de" + "sha256:29d052eb73e0ab8f137f11df8e73d464c1c6d4c3044d9dc8df2af44639d8bfbf", + "sha256:bd578781cd6a33ef713584bf3726f7cd60a3e656ec08a6cc7971e39990808cc0" ], "markers": "python_version >= '3.7'", - "version": "==2022.13" + "version": "==2023.0" }, "setuptools": { "hashes": [ - "sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31", - "sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f" + "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330", + "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251" ], "markers": "python_version >= '3.7'", - "version": "==65.5.1" + "version": "==67.4.0" } } } diff --git a/control.yml.example b/control.example.yml similarity index 100% rename from control.yml.example rename to control.example.yml index d846419..cd02ce9 100644 --- a/control.yml.example +++ b/control.example.yml @@ -13,8 +13,8 @@ dice: dens: 0.75 nstep: [2000, 3000] isave: 1000 - ljname: 'phb.ljc' outname: 'phb' + ljname: 'phb.ljc' randominit: 'always' gaussian: diff --git a/diceplayer/DPpack/External/Dice.py b/diceplayer/DPpack/External/Dice.py deleted file mode 100644 index dbc6b7c..0000000 --- a/diceplayer/DPpack/External/Dice.py +++ /dev/null @@ -1,753 +0,0 @@ -import os -import shutil -import subprocess -import sys -from multiprocessing import Process, connection -from typing import Final, List, TextIO - -import setproctitle -from diceplayer.DPpack.Utils.Misc import * -from diceplayer.DPpack.Utils.PTable import * -from diceplayer.DPpack.Utils.StepDTO import StepDTO -from diceplayer.DPpack.Utils.Validations import NotNull -from numpy import random - -DICE_END_FLAG: Final[str] = "End of simulation" -DICE_FLAG_LINE: Final[int] = -2 -UMAANG3_TO_GCM3: Final[float] = 1.6605 - -MAX_SEED: Final[int] = 4294967295 - - -class Dice: - - title = "Diceplayer run" - progname = "dice" - - nprocs: int = None - randominit = "first" - combrule = "*" - - temp = 300.0 - press = 1.0 - isave = 1000 - dens = None - ljname = None - outname = None - nmol: List[int] = None - nstep: List[int] = None - upbuf = 360 - - def __init__(self, infile: TextIO, outfile: TextIO) -> None: - - self.infile = infile - self.outfile = outfile - - @NotNull(requiredArgs=["ncores", "nmol", "dens", "nstep", "ljname", "outname"]) - def updateKeywords(self, **data): - self.__dict__.update(**data) - - def __new_density(self, cycle: int, proc: int) -> float: - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle - 1) - proc_dir = "p{:02d}".format(proc) - path = sim_dir + os.sep + step_dir + os.sep + proc_dir - file = path + os.sep + "last.xyz" - - if not os.path.isfile(file): - sys.exit( - "Error: cannot find the xyz file {} in main directory".format(file) - ) - try: - with open(file) as fh: - xyzfile = fh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - box = xyzfile[1].split() - volume = float(box[-3]) * float(box[-2]) * float(box[-1]) - - total_mass = 0 - for i in range(len(self.step.molecule)): - - total_mass += self.step.molecule[i].total_mass * self.step.nmol[i] - - density = (total_mass / volume) * UMAANG3_TO_GCM3 - - return density - - def __print_last_config(self, cycle: int, proc: int) -> None: - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle) - proc_dir = "p{:02d}".format(proc) - path = sim_dir + os.sep + step_dir + os.sep + proc_dir - file = path + os.sep + "phb.xyz" - if not os.path.isfile(file): - sys.exit("Error: cannot find the xyz file {}".format(file)) - try: - with open(file) as fh: - xyzfile = fh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - nsites = len(self.step.molecule[0].atom) * self.step.nmol[0] - for i in range(1, len(self.step.nmol)): - nsites += self.step.nmol[i] * len(self.step.molecule[i].atom) - - nsites += 2 - - nsites *= -1 - xyzfile = xyzfile[nsites:] - - file = path + os.sep + "last.xyz" - fh = open(file, "w") - for line in xyzfile: - fh.write(line) - - def __make_dice_inputs(self, cycle: int, proc: int) -> None: - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle) - proc_dir = "p{:02d}".format(proc) - path = sim_dir + os.sep + step_dir + os.sep + proc_dir - - num = time.time() - num = (num - int(num)) * 1e6 - - num = int((num - int(num)) * 1e6) - random.seed((os.getpid() * num) % (MAX_SEED + 1)) - - if self.randominit == "first" and cycle > self.step.initcyc: - last_step_dir = "step{:02d}".format(cycle - 1) - last_path = sim_dir + os.sep + last_step_dir + os.sep + proc_dir - xyzfile = last_path + os.sep + "last.xyz" - self.__make_init_file(path, xyzfile) - - if len(self.nstep) == 2: - - self.__make_nvt_ter(cycle, path) - self.__make_nvt_eq(path) - - elif len(self.nstep) == 3: - - if self.randominit == "first" and cycle > self.step.initcyc: - self.dens = self.__new_density(cycle, proc) - else: - self.__make_nvt_ter(cycle, path) - - self.__make_npt_ter(cycle, path) - self.__make_npt_eq(path) - - else: - sys.exit("Error: bad number of entries for 'nstep'") - - self.__make_potential(path) - - def __make_nvt_ter(self, cycle: int, path: str) -> None: - - file = path + os.sep + "NVT.ter" - try: - fh = open(file, "w") - except: - sys.exit("Error: cannot open file {}".format(file)) - - fh.write("title = {} - NVT Thermalization\n".format(self.title)) - fh.write("ncores = {}\n".format(self.ncores)) - fh.write("ljname = {}\n".format(self.ljname)) - fh.write("outname = {}\n".format(self.outname)) - - string = " ".join(str(x) for x in self.nmol) - fh.write("nmol = {}\n".format(string)) - - fh.write("dens = {}\n".format(self.dens)) - fh.write("temp = {}\n".format(self.temp)) - - if self.randominit == "first" and cycle > self.step.initcyc: - fh.write("init = yesreadxyz\n") - fh.write("nstep = {}\n".format(self.step.altsteps)) - else: - fh.write("init = yes\n") - fh.write("nstep = {}\n".format(self.nstep[0])) - - fh.write("vstep = 0\n") - fh.write("mstop = 1\n") - fh.write("accum = no\n") - fh.write("iprint = 1\n") - fh.write("isave = 0\n") - fh.write("irdf = 0\n") - - seed = int(1e6 * random.random()) - fh.write("seed = {}\n".format(seed)) - fh.write("upbuf = {}".format(self.upbuf)) - - fh.close() - - def __make_nvt_eq(self, path: str) -> None: - - file = path + os.sep + "NVT.eq" - try: - fh = open(file, "w") - except: - sys.exit("Error: cannot open file {}".format(file)) - - fh.write("title = {} - NVT Production\n".format(self.title)) - fh.write("ncores = {}\n".format(self.ncores)) - fh.write("ljname = {}\n".format(self.ljname)) - fh.write("outname = {}\n".format(self.outname)) - - string = " ".join(str(x) for x in self.nmol) - fh.write("nmol = {}\n".format(string)) - - fh.write("dens = {}\n".format(self.dens)) - fh.write("temp = {}\n".format(self.temp)) - fh.write("init = no\n") - fh.write("nstep = {}\n".format(self.nstep[1])) - fh.write("vstep = 0\n") - fh.write("mstop = 1\n") - fh.write("accum = no\n") - fh.write("iprint = 1\n") - fh.write("isave = {}\n".format(self.isave)) - fh.write("irdf = {}\n".format(10 * self.step.nprocs)) - - seed = int(1e6 * random.random()) - fh.write("seed = {}\n".format(seed)) - - fh.close() - - def __make_npt_ter(self, cycle: int, path: str) -> None: - - file = path + os.sep + "NPT.ter" - try: - fh = open(file, "w") - except: - sys.exit("Error: cannot open file {}".format(file)) - - fh.write("title = {} - NPT Thermalization\n".format(self.title)) - fh.write("ncores = {}\n".format(self.ncores)) - fh.write("ljname = {}\n".format(self.ljname)) - fh.write("outname = {}\n".format(self.outname)) - - string = " ".join(str(x) for x in self.nmol) - fh.write("nmol = {}\n".format(string)) - - fh.write("press = {}\n".format(self.press)) - fh.write("temp = {}\n".format(self.temp)) - - if self.randominit == "first" and cycle > self.step.initcyc: - fh.write("init = yesreadxyz\n") - fh.write("dens = {:<8.4f}\n".format(self.dens)) - fh.write("vstep = {}\n".format(int(self.step.altsteps / 5))) - else: - fh.write("init = no\n") - fh.write("vstep = {}\n".format(int(self.nstep[1] / 5))) - - fh.write("nstep = 5\n") - fh.write("mstop = 1\n") - fh.write("accum = no\n") - fh.write("iprint = 1\n") - fh.write("isave = 0\n") - fh.write("irdf = 0\n") - - seed = int(1e6 * random.random()) - fh.write("seed = {}\n".format(seed)) - - fh.close() - - def __make_npt_eq(self, path: str) -> None: - - file = path + os.sep + "NPT.eq" - try: - fh = open(file, "w") - except: - sys.exit("Error: cannot open file {}".format(file)) - - fh.write("title = {} - NPT Production\n".format(self.title)) - fh.write("ncores = {}\n".format(self.ncores)) - fh.write("ljname = {}\n".format(self.ljname)) - fh.write("outname = {}\n".format(self.outname)) - - string = " ".join(str(x) for x in self.nmol) - fh.write("nmol = {}\n".format(string)) - - fh.write("press = {}\n".format(self.press)) - fh.write("temp = {}\n".format(self.temp)) - - fh.write("nstep = 5\n") - - fh.write("vstep = {}\n".format(int(self.nstep[2] / 5))) - fh.write("init = no\n") - fh.write("mstop = 1\n") - fh.write("accum = no\n") - fh.write("iprint = 1\n") - fh.write("isave = {}\n".format(self.isave)) - fh.write("irdf = {}\n".format(10 * self.step.nprocs)) - - seed = int(1e6 * random.random()) - fh.write("seed = {}\n".format(seed)) - - fh.close() - - def __make_init_file(self, path: str, file: TextIO) -> None: - - if not os.path.isfile(file): - sys.exit( - "Error: cannot find the xyz file {} in main directory".format(file) - ) - try: - with open(file) as fh: - xyzfile = fh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - nsites_mm = 0 - for i in range(1, len(self.step.nmol)): - nsites_mm += self.step.nmol[i] * len(self.step.molecule[i].atom) - - nsites_mm *= -1 - - xyzfile = xyzfile[nsites_mm:] - - file = path + os.sep + self.outname + ".xy" - - try: - fh = open(file, "w", 1) - except: - sys.exit("Error: cannot open file {}".format(file)) - - for atom in self.step.molecule[0].atom: - fh.write( - "{:>10.6f} {:>10.6f} {:>10.6f}\n".format(atom.rx, atom.ry, atom.rz) - ) - - for line in xyzfile: - atom = line.split() - rx = float(atom[1]) - ry = float(atom[2]) - rz = float(atom[3]) - fh.write("{:>10.6f} {:>10.6f} {:>10.6f}\n".format(rx, ry, rz)) - - fh.write("$end") - - fh.close() - - def __make_potential(self, path: str) -> None: - - fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n" - - file = path + os.sep + self.ljname - try: - fh = open(file, "w") - except: - sys.exit("Error: cannot open file {}".format(file)) - - fh.write("{}\n".format(self.combrule)) - fh.write("{}\n".format(len(self.step.nmol))) - - nsites_qm = ( - len(self.step.molecule[0].atom) - + len(self.step.molecule[0].ghost_atoms) - + len(self.step.molecule[0].lp_atoms) - ) - - fh.write("{} {}\n".format(nsites_qm, self.step.molecule[0].molname)) - for atom in self.step.molecule[0].atom: - fh.write( - fstr.format( - atom.lbl, - atom.na, - atom.rx, - atom.ry, - atom.rz, - atom.chg, - atom.eps, - atom.sig, - ) - ) - - ghost_label = self.step.molecule[0].atom[-1].lbl + 1 - for i in self.step.molecule[0].ghost_atoms: - fh.write( - fstr.format( - ghost_label, - ghost_number, - self.step.molecule[0].atom[i].rx, - self.step.molecule[0].atom[i].ry, - self.step.molecule[0].atom[i].rz, - self.step.molecule[0].atom[i].chg, - 0, - 0, - ) - ) - - ghost_label += 1 - for lp in self.step.molecule[0].lp_atoms: - fh.write( - fstr.format( - ghost_label, - ghost_number, - lp["rx"], - lp["ry"], - lp["rz"], - lp["chg"], - 0, - 0, - ) - ) - - for mol in self.step.molecule[1:]: - fh.write("{} {}\n".format(len(mol.atom), mol.molname)) - for atom in mol.atom: - fh.write( - fstr.format( - atom.lbl, - atom.na, - atom.rx, - atom.ry, - atom.rz, - atom.chg, - atom.eps, - atom.sig, - ) - ) - - def __make_proc_dir(self, cycle: int, proc: int) -> None: - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle) - proc_dir = "p{:02d}".format(proc) - path = sim_dir + os.sep + step_dir + os.sep + proc_dir - try: - os.makedirs(path) - except: - sys.exit("Error: cannot make directory {}".format(path)) - - def __run_dice(self, cycle: int, proc: int, fh: str) -> None: - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle) - proc_dir = "p{:02d}".format(proc) - - try: - fh.write( - "Simulation process {} initiated with pid {}\n".format( - sim_dir + os.sep + step_dir + os.sep + proc_dir, os.getpid() - ) - ) - - except Exception as err: - print("I/O error({0}): {1}".format(err)) - - path = sim_dir + os.sep + step_dir + os.sep + proc_dir - working_dir = os.getcwd() - os.chdir(path) - - if len(self.nstep) == 2: - - if self.randominit == "first" and cycle > self.step.initcyc: - string_tmp = "previous" - else: - string_tmp = "random" - - string = "(from " + string_tmp + " configuration)" - fh.write( - "p{:02d}> NVT thermalization finished {} on {}\n".format( - proc, string, date_time() - ) - ) - - infh = open("NVT.ter") - outfh = open("NVT.ter.out", "w") - - if shutil.which("bash") != None: - exit_status = subprocess.call( - [ - "bash", - "-c", - "exec -a dice-step{}-p{} {} < {} > {}".format( - cycle, proc, self.progname, infh.name, outfh.name - ), - ] - ) - else: - exit_status = subprocess.call( - self.progname, stin=infh.name, stout=outfh.name - ) - - infh.close() - outfh.close() - - if os.getppid() == 1: - sys.exit() - - if exit_status != 0: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - else: - outfh = open("NVT.ter.out") - flag = outfh.readlines()[DICE_FLAG_LINE].strip() - outfh.close() - if flag != DICE_END_FLAG: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - - fh.write( - "p{:02d}> NVT production initiated on {}\n".format(proc, date_time()) - ) - - infh = open("NVT.eq") - outfh = open("NVT.eq.out", "w") - - if shutil.which("bash") != None: - exit_status = subprocess.call( - [ - "bash", - "-c", - "exec -a dice-step{}-p{} {} < {} > {}".format( - cycle, proc, self.progname, infh.name, outfh.name - ), - ] - ) - else: - exit_status = subprocess.call( - self.progname, stin=infh.name, stout=outfh.name - ) - - infh.close() - outfh.close() - - if os.getppid() == 1: - sys.exit() - - if exit_status != 0: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - else: - outfh = open("NVT.eq.out") - flag = outfh.readlines()[DICE_FLAG_LINE].strip() - outfh.close() - if flag != DICE_END_FLAG: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - - fh.write( - "p{:02d}> ----- NVT production finished on {}\n".format( - proc, date_time() - ) - ) - - elif len(self.nstep) == 3: - if ( - self.randominit == "always" - or (self.randominit == "first" and cycle == 1) - or self.continued - ): - string = "(from random configuration)" - fh.write( - "p{:02d}> NVT thermalization initiated {} on {}\n".format( - proc, string, date_time() - ) - ) - infh = open("NVT.ter") - outfh = open("NVT.ter.out", "w") - - if shutil.which("bash") != None: - exit_status = subprocess.call( - [ - "bash", - "-c", - "exec -a dice-step{}-p{} {} < {} > {}".format( - cycle, proc, self.progname, infh.name, outfh.name - ), - ] - ) - else: - exit_status = subprocess.call( - self.progname, stin=infh.name, stout=outfh.name - ) - - infh.close() - outfh.close() - - if os.getppid() == 1: - sys.exit() - - if exit_status != 0: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - else: - outfh = open("NVT.ter.out") - flag = outfh.readlines()[DICE_FLAG_LINE].strip() - outfh.close() - if flag != DICE_END_FLAG: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - - if not self.randominit == "always" or ( - (self.randominit == "first" and cycle > self.step.initcyc) - ): - string = " (from previous configuration) " - else: - string = " " - fh.write( - "p{:02d}> NPT thermalization finished {} on {}\n".format( - proc, string, date_time() - ) - ) - - infh = open("NPT.ter") - outfh = open("NPT.ter.out", "w") - - if shutil.which("bash") != None: - exit_status = subprocess.call( - [ - "bash", - "-c", - "exec -a dice-step{}-p{} {} < {} > {}".format( - cycle, proc, self.progname, infh.name, outfh.name - ), - ] - ) - else: - exit_status = subprocess.call( - self.progname, stin=infh.name, stout=outfh.name - ) - - infh.close() - outfh.close() - - if os.getppid() == 1: - sys.exit() - - if exit_status != 0: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - else: - outfh = open("NPT.ter.out") - flag = outfh.readlines()[DICE_FLAG_LINE].strip() - outfh.close() - if flag != DICE_END_FLAG: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - - fh.write( - "p{:02d}> NPT production initiated on {}\n".format(proc, date_time()) - ) - - infh = open("NPT.eq") - outfh = open("NPT.eq.out", "w") - - if shutil.which("bash") != None: - exit_status = subprocess.call( - [ - "bash", - "-c", - "exec -a dice-step{}-p{} {} < {} > {}".format( - cycle, proc, self.progname, infh.name, outfh.name - ), - ] - ) - else: - exit_status = subprocess.call( - self.progname, stin=infh.name, stout=outfh.name - ) - - infh.close() - outfh.close() - - if os.getppid() == 1: - sys.exit() - - if exit_status != 0: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - else: - outfh = open("NPT.eq.out") - flag = outfh.readlines()[DICE_FLAG_LINE].strip() - outfh.close() - if flag != DICE_END_FLAG: - sys.exit( - "Dice process step{:02d}-p{:02d} did not exit properly".format( - cycle, proc - ) - ) - - fh.write( - "p{:02d}> ----- NPT production finished on {}\n".format( - proc, date_time() - ) - ) - - os.chdir(working_dir) - - def __simulation_process(self, cycle: int, proc: int): - setproctitle.setproctitle("diceplayer-step{:0d}-p{:0d}".format(cycle, proc)) - - try: - self.__make_proc_dir(cycle, proc) - self.__make_dice_inputs(cycle, proc) - self.__run_dice(cycle, proc, self.outfile) - except Exception as err: - sys.exit(err) - - def configure(self, step: StepDTO): - self.step = step - - def start(self, cycle: int) -> None: - - procs = [] - sentinels = [] - - for proc in range(1, self.step.nprocs + 1): - - p = Process(target=self.__simulation_process, args=(cycle, proc)) - p.start() - - procs.append(p) - sentinels.append(p.sentinel) - - while procs: - finished = connection.wait(sentinels) - for proc_sentinel in finished: - i = sentinels.index(proc_sentinel) - status = procs[i].exitcode - procs.pop(i) - sentinels.pop(i) - if status != 0: - for p in procs: - p.terminate() - sys.exit(status) - - for proc in range(1, self.step.nprocs + 1): - self.__print_last_config(cycle, proc) - - def reset(self): - del self.step diff --git a/diceplayer/DPpack/External/Gaussian.py b/diceplayer/DPpack/External/Gaussian.py deleted file mode 100644 index 43b9ee1..0000000 --- a/diceplayer/DPpack/External/Gaussian.py +++ /dev/null @@ -1,595 +0,0 @@ -from ast import keyword -from asyncore import read -import os -import shutil -import subprocess -import sys -import textwrap -from typing import Dict, List, TextIO - -import numpy as np - -from diceplayer.DPpack.Environment.Atom import Atom -from diceplayer.DPpack.Environment.Molecule import Molecule -from diceplayer.DPpack.Utils.Misc import * -from diceplayer.DPpack.Utils.PTable import * -from diceplayer.DPpack.Utils.StepDTO import StepDTO -from diceplayer.DPpack.Utils.Validations import NotNull - - -class Gaussian: - - mem = None - chgmult = [0, 1] - gmiddle = None # In each case, if a filename is given, its content will be - gbottom = None # inserted in the gaussian input - pop = "chelpg" - - keywords = "" - - def __init__(self) -> None: - pass - - @NotNull(requiredArgs=["qmprog","level"]) - def updateKeywords(self, **data): - self.__dict__.update(**data) - self.checkKeywords() - - def checkKeywords(self): - - if self.pop not in ["chelpg", "mk", "nbo"]: - self.pop = "chelpg" - - def run_formchk(self, cycle: int, fh: TextIO): - - simdir = "simfiles" - stepdir = "step{:02d}".format(cycle) - path = simdir + os.sep + stepdir + os.sep + "qm" - - work_dir = os.getcwd() - os.chdir(path) - - fh.write("Formatting the checkpoint file... \n") - - exit_status = subprocess.call(["formchk", "asec.chk"], stdout=fh) - - fh.write("Done\n") - - os.chdir(work_dir) - - def readChargesFromFchk(self, file: str, fh: TextIO) -> List[float]: - - try: - with open(file) as fchk: - fchkfile = fchk.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - if self.pop in ["chelpg", "mk"]: - CHARGE_FLAG = "ESP Charges" - else: - CHARGE_FLAG = "ESP Charges" - - start = fchkfile.pop(0).strip() - while start.find(CHARGE_FLAG) != 0: # expression in begining of line - start = fchkfile.pop(0).strip() - - charges: List[float] = [] - while len(charges) < len(self.step.molecule[0].atom): - charges.extend([float(x) for x in fchkfile.pop(0).split()]) - - return charges - - def read_forces_fchk(self, file: str, fh: TextIO) -> np.ndarray: - - forces = [] - try: - with open(file) as tmpfh: - fchkfile = tmpfh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - start = fchkfile.pop(0).strip() - while start.find("Cartesian Gradient") != 0: # expression in begining of line - start = fchkfile.pop(0).strip() - - degrees = 3 * len(self.step.molecule[0].atom) - count = 0 - while len(forces) < degrees: - values = fchkfile.pop(0).split() - forces.extend([float(x) for x in values]) - count += len(values) - if count >= degrees: - forces = forces[:degrees] - break - - gradient = np.array(forces) - - fh.write("\nGradient read from file {}:\n".format(file)) - fh.write( - "-----------------------------------------------------------------------\n" - "Center Atomic Forces (Hartree/Bohr)\n" - "Number Number X Y Z\n" - "-----------------------------------------------------------------------\n" - ) - for i in range(len(self.step.molecule[0].atom)): - fh.write( - " {:>5d} {:>3d} {:>14.9f} {:>14.9f} {:>14.9f}\n".format( - i + 1, - self.step.molecule[0].atom[i].na, - forces.pop(0), - forces.pop(0), - forces.pop(0), - ) - ) - - fh.write( - "-----------------------------------------------------------------------\n" - ) - - force_max = np.amax(np.absolute(gradient)) - force_rms = np.sqrt(np.mean(np.square(gradient))) - - fh.write( - " Max Force = {:>14.9f} RMS Force = {:>14.9f}\n\n".format( - force_max, force_rms - ) - ) - - return gradient - - def read_hessian_fchk(self, file: str) -> np.ndarray: - - force_const = [] - try: - with open(file) as tmpfh: - fchkfile = tmpfh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - start = fchkfile.pop(0).strip() - while start.find("Cartesian Force Constants") != 0: - start = fchkfile.pop(0).strip() - - degrees = 3 * len(self.step.molecule[0].atom) - last = round(degrees * (degrees + 1) / 2) - count = 0 - - while len(force_const) < last: - - value = fchkfile.pop(0).split() - force_const.extend([float(x) for x in value]) - - # while len(force_const) < last: - - # values = fchkfile.pop(0).split() - # force_const.extend([ float(x) for x in values ]) - # count += len(values) - # if count >= last: - # force_const = force_const[:last] - # break - - hessian = np.zeros((degrees, degrees)) - for i in range(degrees): - for j in range(i + 1): - hessian[i, j] = force_const.pop(0) - hessian[j, i] = hessian[i, j] - - return hessian - - def read_hessian_log(self, file: str) -> np.ndarray: - - try: - with open(file) as tmpfh: - logfile = tmpfh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - start = logfile.pop(0).strip() - while start.find("The second derivative matrix:") != 0: - start = logfile.pop(0).strip() - - degrees = 3 * len(self.step.molecule[0].atom) - hessian = np.zeros((degrees, degrees)) - - k = 0 - while k < degrees: - logfile.pop(0) - for i in range(k, degrees): - values = logfile.pop(0).split()[1:] - for j in range(k, min(i + 1, k + 5)): - hessian[i, j] = float(values.pop(0)) - hessian[j, i] = hessian[i, j] - k += 5 - - return hessian - - def print_grad_hessian( - self, cycle: int, cur_gradient: np.ndarray, hessian: np.ndarray - ) -> None: - - try: - fh = open("grad_hessian.dat", "w") - except: - sys.exit("Error: cannot open file grad_hessian.dat") - - fh.write("Optimization cycle: {}\n".format(cycle)) - fh.write("Cartesian Gradient\n") - degrees = 3 * len(self.step.molecule[0].atom) - for i in range(degrees): - fh.write(" {:>11.8g}".format(cur_gradient[i])) - if (i + 1) % 5 == 0 or i == degrees - 1: - fh.write("\n") - - fh.write("Cartesian Force Constants\n") - n = int(np.sqrt(2 * degrees)) - last = degrees * (degrees + 1) / 2 - count = 0 - for i in range(n): - for j in range(i + 1): - count += 1 - fh.write(" {:>11.8g}".format(hessian[i, j])) - if count % 5 == 0 or count == last: - fh.write("\n") - - fh.close() - - # Change the name to make_gaussian_input - def make_gaussian_input(self, cycle: int, asec_charges: List[Dict]) -> None: - - simdir = "simfiles" - stepdir = "step{:02d}".format(cycle) - path = simdir + os.sep + stepdir + os.sep + "qm" - - file = path + os.sep + "asec.gjf" - - try: - fh = open(file, "w") - except: - sys.exit("Error: cannot open file {}".format(file)) - - fh.write("%Chk=asec.chk\n") - if self.mem != None: - fh.write("%Mem={}MB\n".format(self.mem)) - fh.write("%Nprocs={}\n".format(self.step.nprocs * self.step.ncores)) - - kword_line = "#P " + str(self.level) - - if self.keywords != "": - kword_line += " " + self.keywords - - if self.step.opt == "yes": - kword_line += " Force" - - # kword_line += " Charge" - kword_line += " NoSymm" - kword_line += " Pop={} Density=Current".format(self.pop) - - if cycle > 1: - kword_line += " Guess=Read" - - fh.write(textwrap.fill(kword_line, 90)) - fh.write("\n") - - fh.write("\nForce calculation - Cycle number {}\n".format(cycle)) - fh.write("\n") - fh.write("{},{}\n".format(self.chgmult[0], self.chgmult[1])) - - for atom in self.step.molecule[0].atom: - symbol = atomsymb[atom.na] - fh.write( - "{:<2s} {:>10.5f} {:>10.5f} {:>10.5f}\n".format( - symbol, atom.rx, atom.ry, atom.rz - ) - ) - - fh.write("\n") - - for charge in asec_charges: - fh.write( - "{:>10.5f} {:>10.5f} {:>10.5f} {:>11.8f}\n".format( - charge['rx'], charge['ry'], charge['rz'], charge['chg'] - ) - ) - - fh.write("\n") - - fh.close() - - def read_charges(self, file: str, fh: TextIO) -> None: - - try: - with open(file) as tmpfh: - glogfile = tmpfh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - start = glogfile.pop(0).strip() - while start != "Fitting point charges to electrostatic potential": - start = glogfile.pop(0).strip() - - glogfile = glogfile[3:] # Consume 3 more lines - - fh.write("\nAtomic charges:\n") - fh.write("------------------------------------\n") - for atom in self.step.molecule[0].atom: - line = glogfile.pop(0).split() - atom_str = line[1] - charge = float(line[2]) - atom.chg = charge - fh.write(" {:<2s} {:>10.6f}\n".format(atom_str, charge)) - - # if self.pop == "chelpg": - # for ghost in ghost_atoms: - # line = glogfile.pop(0).split() - # atom_str = line[1] - # charge = float(line[2]) - # ghost['chg'] = charge - # fh.write(" {:<2s} {:>10.6f}\n".format(atom_str, charge)) - - # for lp in lp_atoms: - # line = glogfile.pop(0).split() - # atom_str = line[1] - # charge = float(line[2]) - # lp['chg'] = charge - # fh.write(" {:<2s} {:>10.6f}\n".format(atom_str, charge)) - - fh.write("------------------------------------\n") - - def executeOptimizationRoutine(self, cycle: int, outfile: TextIO, readhessian: str): - - try: - gradient - old_gradient = gradient - except: - pass - - gradient = self.read_forces_fchk(file, outfile) - - # If 1st step, read the hessian - if cycle == 1: - - if readhessian == "yes": - - file = "grad_hessian.dat" - outfile.write( - "\nReading the hessian matrix from file {}\n".format(file) - ) - hessian = self.read_hessian_log(file) - - else: - - file = ( - "simfiles" - + os.sep - + "step01" - + os.sep - + "qm" - + os.sep - + "asec.fchk" - ) - outfile.write( - "\nReading the hessian matrix from file {}\n".format(file) - ) - hessian = self.read_hessian_fchk(file) - - # From 2nd step on, update the hessian - else: - outfile.write("\nUpdating the hessian matrix using the BFGS method... ") - hessian = self.step.molecule[0].update_hessian( - step, gradient, old_gradient, hessian - ) - outfile.write("Done\n") - - # Save gradient and hessian - self.print_grad_hessian(cycle, gradient, hessian) - - # Calculate the step and update the position - step = self.calculate_step(cycle, gradient, hessian) - - position += step - - ## If needed, calculate the charges - if cycle < self.step.switchcyc: - - # internal.gaussian.make_charge_input(cycle, asec_charges) - self.run_gaussian(cycle, "charge", outfile) - - file = ( - "simfiles" - + os.sep - + "step{:02d}".format(cycle) - + os.sep - + "qm" - + os.sep - + "asec2.log" - ) - self.read_charges(file, outfile) - else: - file = ( - "simfiles" - + os.sep - + "step{:02d}".format(cycle) - + os.sep - + "qm" - + os.sep - + "asec.log" - ) - self.read_charges(file, outfile) - - self.outfile.write("\nNew values for molecule type 1:\n\n") - self.step.molecule[0].print_mol_info(outfile) - - def run_gaussian(self, cycle: int, type: str, fh: TextIO) -> None: - - simdir = "simfiles" - stepdir = "step{:02d}".format(cycle) - path = simdir + os.sep + stepdir + os.sep + "qm" - work_dir = os.getcwd() - os.chdir(path) - - # if type == "force": - # infile = "asec.gjf" - # elif type == "charge": - # infile = "asec2.gjf" - - infile = "asec.gjf" - - fh.write( - "\nCalculation of {}s initiated with Gaussian on {}\n".format( - type, date_time() - ) - ) - - if shutil.which("bash") != None: - exit_status = subprocess.call( - [ - "bash", - "-c", - "exec -a {}-step{} {} {}".format( - self.qmprog, cycle, self.qmprog, infile - ), - ] - ) - else: - exit_status = subprocess.call([self.qmprog, infile]) - - if exit_status != 0: - sys.exit("Gaussian process did not exit properly") - - fh.write("Calculation of {}s finished on {}\n".format(type, date_time())) - - os.chdir(work_dir) - - # def calculate_step( - # self, cycle: int, gradient: np.ndarray, hessian: np.ndarray - # ) -> np.ndarray: - - # invhessian = np.linalg.inv(hessian) - # pre_step = -1 * np.matmul(invhessian, gradient.T).T - # maxstep = np.amax(np.absolute(pre_step)) - # factor = min(1, self.player.maxstep / maxstep) - # step = factor * pre_step - - # self.outfile.write("\nCalculated step-{}:\n".format(cycle)) - # pre_step_list = pre_step.tolist() - - # self.outfile.write( - # "-----------------------------------------------------------------------\n" - # "Center Atomic Step (Bohr)\n" - # "Number Number X Y Z\n" - # "-----------------------------------------------------------------------\n" - # ) - # for i in range(len(self.system.molecule[0].atom)): - # self.outfile.write( - # " {:>5d} {:>3d} {:>14.9f} {:>14.9f} {:>14.9f}\n".format( - # i + 1, - # self.system.molecule[0].atom[i].na, - # pre_step_list.pop(0), - # pre_step_list.pop(0), - # pre_step_list.pop(0), - # ) - # ) - - # self.outfile.write( - # "-----------------------------------------------------------------------\n" - # ) - - # self.outfile.write("Maximum step is {:>11.6}\n".format(maxstep)) - # self.outfile.write("Scaling factor = {:>6.4f}\n".format(factor)) - # self.outfile.write("\nFinal step (Bohr):\n") - # step_list = step.tolist() - - # self.outfile.write( - # "-----------------------------------------------------------------------\n" - # "Center Atomic Step (Bohr)\n" - # "Number Number X Y Z\n" - # "-----------------------------------------------------------------------\n" - # ) - # for i in range(len(self.system.molecule[0].atom)): - # self.outfile.write( - # " {:>5d} {:>3d} {:>14.9f} {:>14.9f} {:>14.9f}\n".format( - # i + 1, - # self.system.molecule[0].atom[i].na, - # step_list.pop(0), - # step_list.pop(0), - # step_list.pop(0), - # ) - # ) - - # self.outfile.write( - # "-----------------------------------------------------------------------\n" - # ) - - # step_max = np.amax(np.absolute(step)) - # step_rms = np.sqrt(np.mean(np.square(step))) - - # self.outfile.write( - # " Max Step = {:>14.9f} RMS Step = {:>14.9f}\n\n".format( - # step_max, step_rms - # ) - # ) - - # return step - - def configure(self, step: StepDTO): - - self.step = step - - def start(self, cycle: int, outfile: TextIO, asec_charges: List[Dict], readhessian: str) -> StepDTO: - - make_qm_dir(cycle) - - if cycle > 1: - - src = ( - "simfiles" - + os.sep - + "step{:02d}".format(cycle - 1) - + os.sep - + "qm" - + os.sep - + "asec.chk" - ) - dst = ( - "simfiles" - + os.sep - + "step{:02d}".format(cycle) - + os.sep - + "qm" - + os.sep - + "asec.chk" - ) - shutil.copyfile(src, dst) - - self.make_gaussian_input(cycle, asec_charges) - self.run_gaussian(cycle, "force", outfile) - self.run_formchk(cycle, outfile) - - ## Read the gradient - file = ( - "simfiles" - + os.sep - + "step{:02d}".format(cycle) - + os.sep - + "qm" - + os.sep - + "asec.fchk" - ) - - if self.step.opt: - - pass - # position = self.executeOptimizationRoutine(cycle, outfile, readhessian) - # self.step.position = position - - else: - - charges = self.readChargesFromFchk(file, outfile) - self.step.charges = charges - - return self.step - - def reset(self): - - del self.step diff --git a/diceplayer/DPpack/Player.py b/diceplayer/DPpack/Player.py deleted file mode 100644 index 664256e..0000000 --- a/diceplayer/DPpack/Player.py +++ /dev/null @@ -1,801 +0,0 @@ -import os -import shutil -import sys -import textwrap -from typing import Dict, List, TextIO - -import yaml - -from diceplayer.DPpack.Environment.Atom import Atom -from diceplayer.DPpack.Environment.Molecule import Molecule -from diceplayer.DPpack.Environment.System import System -from diceplayer.DPpack.External.Dice import Dice -from diceplayer.DPpack.External.Gaussian import Gaussian -from diceplayer.DPpack.Utils.Misc import * -from diceplayer.DPpack.Utils.PTable import * -from diceplayer.DPpack.Utils.StepDTO import StepDTO -from diceplayer.DPpack.Utils.Validations import NotNull - -env = ["OMP_STACKSIZE"] - - -class Player: - - maxcyc = None - opt = None - nprocs = None - qmprog = None - lps = None - ghosts = None - altsteps = None - combrule = None - - switchcyc = 3 - maxstep = 0.3 - freq = "no" - readhessian = "no" - vdwforces = "no" - tol_factor = 1.2 - - TOL_RMS_FORCE = 3e-4 - TOL_MAX_FORCE = 4.5e-4 - TOL_RMS_STEP = 1.2e-3 - TOL_MAX_SET = 1.8e-3 - TRUST_RADIUS = None - - continued: bool = False - - def __init__(self, infile: TextIO, outfile: TextIO) -> None: - - self.infile = infile - self.outfile = outfile - - self.system = System() - - self.dice = Dice(infile, outfile) - self.dice_keywords = [ - a - for a in dir(self.dice) - if not a.startswith("__") and not callable(getattr(self.dice, a)) - ] - - self.gaussian = Gaussian() - self.gaussian_keywords = [ - a - for a in dir(self.gaussian) - if not a.startswith("__") and not callable(getattr(self.gaussian, a)) - ] - - @NotNull( - requiredArgs=["maxcyc", "opt", "nprocs", "qmprog", "altsteps"] - ) - def updateKeywords(self, **data): - self.__dict__.update(**data) - - def read_keywords(self) -> None: - - with self.infile as f: - data = yaml.load(f, Loader=yaml.SafeLoader) - - self.updateKeywords(**data.get("diceplayer")) - self.dice.updateKeywords(**data.get("dice")) - self.gaussian.updateKeywords(**data.get("gaussian")) - - def check_keywords(self) -> None: - - min_steps = 20000 - - if self.dice.ljname == None: - sys.exit( - "Error: 'ljname' keyword not specified in file {}".format(self.infile) - ) - - if self.dice.outname == None: - sys.exit( - "Error: 'outname' keyword not specified in file {}".format(self.infile) - ) - - if self.dice.dens == None: - sys.exit( - "Error: 'dens' keyword not specified in file {}".format(self.infile) - ) - - if self.dice.nmol == 0: - sys.exit( - "Error: 'nmol' keyword not defined appropriately in file {}".format( - self.infile - ) - ) - - if self.dice.nstep == 0: - sys.exit( - "Error: 'nstep' keyword not defined appropriately in file {}".format( - self.infile - ) - ) - - # Check only if QM program is Gaussian: - if self.qmprog in ("g03", "g09", "g16"): - - if self.gaussian.level == None: - sys.exit( - "Error: 'level' keyword not specified in file {}".format( - self.infile - ) - ) - - if self.gaussian.gmiddle != None: - if not os.path.isfile(self.gaussian.gmiddle): - sys.exit("Error: file {} not found".format(self.gaussian.gmiddle)) - - if self.gaussian.gbottom != None: - if not os.path.isfile(self.gaussian.gbottom): - sys.exit("Error: file {} not found".format(self.gaussian.gbottom)) - - if self.gaussian.pop != "chelpg" and ( - self.ghosts == "yes" or self.lps == "yes" - ): - sys.exit( - "Error: ghost atoms or lone pairs only available with 'pop = chelpg')" - ) - - # Check only if QM program is Molcas: - # if self.qmprog == "molcas": - - # if self.molcas.mbottom == None: - # sys.exit("Error: 'mbottom' keyword not specified in file {}".format(self.infile)) - # else: - # if not os.path.isfile(self.molcas.mbottom): - # sys.exit("Error: file {} not found".format(self.molcas.mbottom)) - - # if self.molcas.basis == None: - # sys.exit("Error: 'basis' keyword not specified in file {}".format(self.infile)) - - if self.altsteps != 0: - - # Verifica se tem mais de 1 molecula QM - # (No futuro usar o RMSD fit para poder substituir todas as moleculas QM - # no arquivo outname.xy - Need to change the __make_init_file!!) - if self.dice.nmol[0] > 1: - sys.exit( - "Error: altsteps > 0 only possible with 1 QM molecule (nmol = 1 n2 n3 n4)" - ) - - # if not zero, altsteps cannot be less than min_steps - self.altsteps = max(min_steps, self.altsteps) - # altsteps value is always the nearest multiple of 1000 - self.altsteps = round(self.altsteps / 1000) * 1000 - - for i in range(len(self.dice.nstep)): - # nstep can never be less than min_steps - self.dice.nstep[i] = max(min_steps, self.dice.nstep[i]) - # nstep values are always the nearest multiple of 1000 - self.dice.nstep[i] = round(self.dice.nstep[i] / 1000) * 1000 - - # isave must be between 100 and 2000 - self.dice.isave = max(100, self.dice.isave) - self.dice.isave = min(2000, self.dice.isave) - # isave value is always the nearest multiple of 100 - self.dice.isave = round(self.dice.isave / 100) * 100 - - def print_keywords(self) -> None: - - self.outfile.write( - "##########################################################################################\n" - "############# Welcome to DICEPLAYER version 1.0 #############\n" - "##########################################################################################\n" - "\n" - ) - self.outfile.write("Your python version is {}\n".format(sys.version)) - self.outfile.write("\n") - self.outfile.write("Program started on {}\n".format(weekday_date_time())) - self.outfile.write("\n") - self.outfile.write("Environment variables:\n") - for var in env: - self.outfile.write( - "{} = {}\n".format( - var, (os.environ[var] if var in os.environ else "Not set") - ) - ) - - self.outfile.write( - "\n==========================================================================================\n" - " CONTROL variables being used in this run:\n" - "------------------------------------------------------------------------------------------\n" - "\n" - ) - - self.outfile.write("\n") - - self.outfile.write( - "------------------------------------------------------------------------------------------\n" - " DICE variables being used in this run:\n" - "------------------------------------------------------------------------------------------\n" - "\n" - ) - - for key in sorted(self.dice_keywords): - if getattr(self.dice, key) != None: - if isinstance(getattr(self.dice, key), list): - string = " ".join(str(x) for x in getattr(self.dice, key)) - self.outfile.write("{} = {}\n".format(key, string)) - else: - self.outfile.write("{} = {}\n".format(key, getattr(self.dice, key))) - - self.outfile.write("\n") - - if self.qmprog in ("g03", "g09", "g16"): - - self.outfile.write( - "------------------------------------------------------------------------------------------\n" - " GAUSSIAN variables being used in this run:\n" - "------------------------------------------------------------------------------------------\n" - "\n" - ) - - for key in sorted(self.gaussian_keywords): - if getattr(self.gaussian, key) != None: - if isinstance(getattr(self.gaussian, key), list): - string = " ".join(str(x) for x in getattr(self.gaussian, key)) - self.outfile.write("{} = {}\n".format(key, string)) - else: - self.outfile.write( - "{} = {}\n".format(key, getattr(self.gaussian, key)) - ) - - self.outfile.write("\n") - - # elif self.qmprog == "molcas": - - # self.outfile.write("------------------------------------------------------------------------------------------\n" - # " MOLCAS variables being used in this run:\n" - # "------------------------------------------------------------------------------------------\n" - # "\n") - - # for key in sorted(molcas): - # if molcas[key] != None: - # if isinstance(molcas[key], list): - # string = " ".join(str(x) for x in molcas[key]) - # self.outfile.write("{} = {}\n".format(key, string)) - # else: - # self.outfile.write("{} = {}\n".format(key, molcas[key])) - - # self.outfile.write("\n") - - def read_potential(self) -> None: # Deve ser atualizado para o uso de - - try: - with open(self.dice.ljname) as file: - ljfile = file.readlines() - except EnvironmentError as err: - sys.exit(err) - - combrule = ljfile.pop(0).split()[0] - if combrule not in ("*", "+"): - sys.exit( - "Error: expected a '*' or a '+' sign in 1st line of file {}".format( - self.dice.ljname - ) - ) - self.dice.combrule = combrule - - ntypes = ljfile.pop(0).split()[0] - if not ntypes.isdigit(): - sys.exit( - "Error: expected an integer in the 2nd line of file {}".format( - self.dice.ljname - ) - ) - ntypes = int(ntypes) - - if ntypes != len(self.dice.nmol): - sys.exit( - "Error: number of molecule types in file {} must match that of 'nmol' keyword in file {}".format( - self.dice.ljname, self.infile - ) - ) - line = 2 - for i in range(ntypes): - - line += 1 - nsites, molname = ljfile.pop(0).split()[:2] - - if not nsites.isdigit(): - sys.exit( - "Error: expected an integer in line {} of file {}".format( - line, self.dice.ljname - ) - ) - - if molname is None: - sys.exit( - "Error: expected a molecule name in line {} of file {}".format( - line, self.dice.ljname - ) - ) - - nsites = int(nsites) - - self.system.add_type(nsites, Molecule(molname)) - - for j in range(nsites): - - line += 1 - new_atom = ljfile.pop(0).split() - - if len(new_atom) < 8: - sys.exit( - "Error: expected at least 8 fields in line {} of file {}".format( - line, self.dice.ljname - ) - ) - - if not new_atom[0].isdigit(): - sys.exit( - "Error: expected an integer in field 1, line {} of file {}".format( - line, self.dice.ljname - ) - ) - lbl = int(new_atom[0]) - - if not new_atom[1].isdigit(): - sys.exit( - "Error: expected an integer in field 2, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - atnumber = int(new_atom[1]) - if ( - atnumber == ghost_number and i == 0 - ): # Ghost atom not allowed in the QM molecule - sys.exit( - "Error: found a ghost atom in line {} of file {}".format( - line, self.dice.ljname - ) - ) - na = atnumber - - try: - rx = float(new_atom[2]) - except: - sys.exit( - "Error: expected a float in field 3, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - try: - ry = float(new_atom[3]) - except: - sys.exit( - "Error: expected a float in field 4, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - try: - rz = float(new_atom[4]) - except: - sys.exit( - "Error: expected a float in field 5, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - try: - chg = float(new_atom[5]) - except: - sys.exit( - "Error: expected a float in field 6, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - try: - eps = float(new_atom[6]) - except: - sys.exit( - "Error: expected a float in field 7, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - try: - sig = float(new_atom[7]) - except: - sys.exit( - "Error: expected a float in field 8, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - mass = atommass[na] - - if len(new_atom) > 8: - masskey, mass = new_atom[8].partition("=")[::2] - if masskey.lower() == "mass" and len(mass) != 0: - try: - new_mass = float(mass) - if new_mass > 0: - mass = new_mass - except: - sys.exit( - "Error: expected a positive float after 'mass=' in field 9, line {} of file {}".format( - line, self.dice.ljname - ) - ) - - self.system.molecule[i].add_atom( - Atom(lbl, na, rx, ry, rz, chg, eps, sig) - ) - - to_delete = ["lbl", "na", "rx", "ry", "rz", "chg", "eps", "sig", "mass"] - for _var in to_delete: - if _var in locals() or _var in globals(): - exec(f"del {_var}") - - def print_potential(self) -> None: - - formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}\n" - self.outfile.write( - "\n" - "==========================================================================================\n" - ) - self.outfile.write( - " Potential parameters from file {}:\n".format( - self.dice.ljname - ) - ) - self.outfile.write( - "------------------------------------------------------------------------------------------\n" - "\n" - ) - - self.outfile.write("Combination rule: {}\n".format(self.dice.combrule)) - self.outfile.write( - "Types of molecules: {}\n\n".format(len(self.system.molecule)) - ) - - i = 0 - for mol in self.system.molecule: - i += 1 - self.outfile.write( - "{} atoms in molecule type {}:\n".format(len(mol.atom), i) - ) - self.outfile.write( - "---------------------------------------------------------------------------------\n" - "Lbl AN X Y Z Charge Epsilon Sigma Mass\n" - ) - self.outfile.write( - "---------------------------------------------------------------------------------\n" - ) - - for atom in mol.atom: - - self.outfile.write( - formatstr.format( - atom.lbl, - atom.na, - atom.rx, - atom.ry, - atom.rz, - atom.chg, - atom.eps, - atom.sig, - atom.mass, - ) - ) - - self.outfile.write("\n") - - if self.ghosts == "yes" or self.lps == "yes": - self.outfile.write( - "\n" - "------------------------------------------------------------------------------------------\n" - " Aditional potential parameters:\n" - "------------------------------------------------------------------------------------------\n" - ) - - # if player['ghosts'] == "yes": - - # self.outfile.write("\n") - # self.outfile.write("{} ghost atoms appended to molecule type 1 at:\n".format(len(ghost_types))) - # self.outfile.write("---------------------------------------------------------------------------------\n") - - # atoms_string = "" - # for ghost in ghost_types: - # for atom in ghost['numbers']: - # atom_sym = atomsymb[ molecules[0][atom - 1]['na'] ].strip() - # atoms_string += "{}{} ".format(atom_sym,atom) - - # if ghost['type'] == "g": - # self.outfile.write(textwrap.fill("* Geometric center of atoms {}".format(atoms_string), 80)) - # elif ghost['type'] == "m": - # self.outfile.write(textwrap.fill("* Center of mass of atoms {}".format(atoms_string), 80)) - # elif ghost['type'] == "z": - # self.outfile.write(textwrap.fill("* Center of atomic number of atoms {}".format(atoms_string), 80)) - - # self.outfile.write("\n") - - # if player['lps'] == 'yes': - - # self.outfile.write("\n") - # self.outfile.write("{} lone pairs appended to molecule type 1:\n".format(len(lp_types))) - # self.outfile.write("---------------------------------------------------------------------------------\n") - - # for lp in lp_types: - # # LP type 1 or 2 - # if lp['type'] in (1, 2): - # atom1_num = lp['numbers'][0] - # atom1_sym = atomsymb[ molecules[0][atom1_num - 1]['na'] ].strip() - # atom2_num = lp['numbers'][1] - # atom2_sym = atomsymb[ molecules[0][atom2_num - 1]['na'] ].strip() - # atom3_num = lp['numbers'][2] - # atom3_sym = atomsymb[ molecules[0][atom3_num - 1]['na'] ].strip() - - # self.outfile.write(textwrap.fill( - # "* Type {} on atom {}{} with {}{} {}{}. Alpha = {:<5.1f} Deg and D = {:<4.2f} Angs".format( - # lp['type'], atom1_sym, atom1_num, atom2_sym, atom2_num, atom3_sym, atom3_num, lp['alpha'], - # lp['dist']), 86)) - # self.outfile.write("\n") - - # # Other LP types - - self.outfile.write( - "\n" - "==========================================================================================\n" - ) - - def check_executables(self) -> None: - - self.outfile.write("\n") - self.outfile.write(90 * "=") - self.outfile.write("\n\n") - - dice_path = shutil.which(self.dice.progname) - if dice_path != None: - self.outfile.write( - "Program {} found at {}\n".format(self.dice.progname, dice_path) - ) - self.dice.path = dice_path - else: - sys.exit("Error: cannot find dice executable") - - qmprog_path = shutil.which(self.gaussian.qmprog) - if qmprog_path != None: - self.outfile.write( - "Program {} found at {}\n".format(self.gaussian.qmprog, qmprog_path) - ) - self.gaussian.path = qmprog_path - else: - sys.exit("Error: cannot find {} executable".format(self.gaussian.qmprog)) - - if self.gaussian.qmprog in ("g03", "g09", "g16"): - formchk_path = shutil.which("formchk") - if formchk_path != None: - self.outfile.write("Program formchk found at {}\n".format(formchk_path)) - else: - sys.exit("Error: cannot find formchk executable") - - def dice_start(self, cycle: int): - - self.dice.configure( - StepDTO( - initcyc=self.initcyc, - nprocs=self.nprocs, - altsteps=self.altsteps, - nmol=self.system.nmols, - molecule=self.system.molecule, - ) - ) - - self.dice.start(cycle) - - self.dice.reset() - - def gaussian_start(self, cycle: int, geomsfh: TextIO): - - self.gaussian.configure( - StepDTO( - initcyc=self.initcyc, - nprocs=self.nprocs, - ncores=self.dice.ncores, - altsteps=self.altsteps, - switchcyc=self.switchcyc, - opt=self.opt, - nmol=self.system.nmols, - molecule=self.system.molecule - ) - ) - - # Make ASEC - self.outfile.write("\nBuilding the ASEC and vdW meanfields... ") - asec_charges = self.populate_asec_vdw(cycle) - - step = self.gaussian.start(cycle, self.outfile, asec_charges, self.readhessian) - - if self.opt: - - position = step.position - - ## Update the geometry of the reference molecule - self.system.update_molecule(position, self.outfile) - - ## Print new geometry in geoms.xyz - self.system.print_geom(cycle, geomsfh) - - else: - - charges = step.charges - - self.system.molecule[0].updateCharges(charges) - - self.system.printChargesAndDipole(cycle, self.outfile) - - self.gaussian.reset() - - def populate_asec_vdw(self, cycle) -> List[Dict]: - - # Both asec_charges and vdw_meanfield will utilize the Molecule() class and Atoms() with some None elements - - asec_charges = [] - - if self.dice.nstep[-1] % self.dice.isave == 0: - nconfigs = round(self.dice.nstep[-1] / self.dice.isave) - else: - nconfigs = int(self.dice.nstep[-1] / self.dice.isave) - - norm_factor = nconfigs * self.nprocs - - nsitesref = len(self.system.molecule[0].atom) - - nsites_total = self.dice.nmol[0] * nsitesref - for i in range(1, len(self.dice.nmol)): - nsites_total += self.dice.nmol[i] * len(self.system.molecule[i].atom) - - thickness = [] - picked_mols = [] - - for proc in range(1, self.nprocs + 1): # Run over folders - - path = ( - "simfiles" - + os.sep - + "step{:02d}".format(cycle) - + os.sep - + "p{:02d}".format(proc) - ) - file = path + os.sep + self.dice.outname + ".xyz" - if not os.path.isfile(file): - sys.exit("Error: cannot find file {}".format(file)) - try: - with open(file) as xyzfh: - xyzfile = xyzfh.readlines() - except: - sys.exit("Error: cannot open file {}".format(file)) - - for config in range(nconfigs): # Run over configs in a folder - - if int(xyzfile.pop(0).split()[0]) != nsites_total: - sys.exit("Error: wrong number of sites in file {}".format(file)) - - box = xyzfile.pop(0).split()[-3:] - box = [float(box[0]), float(box[1]), float(box[2])] - sizes = self.system.molecule[0].sizes_of_molecule() - thickness.append( - min( - [ - (box[0] - sizes[0]) / 2, - (box[1] - sizes[1]) / 2, - (box[2] - sizes[2]) / 2, - ] - ) - ) - - xyzfile = xyzfile[nsitesref:] - mol_count = 0 - for type in range(len(self.dice.nmol)): - - if type == 0: - nmols = self.dice.nmol[0] - 1 - else: - nmols = self.dice.nmol[type] - - for mol in range(nmols): - - new_molecule = Molecule("ASEC TMP MOLECULE") - for site in range(len(self.system.molecule[type].atom)): - - line = xyzfile.pop(0).split() - - if ( - line[0].title() - != atomsymb[self.system.molecule[type].atom[site].na].strip() - ): - sys.exit("Error reading file {}".format(file)) - - new_molecule.add_atom( - Atom( - self.system.molecule[type].atom[site].lbl, - self.system.molecule[type].atom[site].na, - float(line[1]), - float(line[2]), - float(line[3]), - self.system.molecule[type].atom[site].chg, - self.system.molecule[type].atom[site].eps, - self.system.molecule[type].atom[site].sig, - ) - ) - - dist = self.system.molecule[0].minimum_distance(new_molecule) - if dist < thickness[-1]: - mol_count += 1 - for atom in new_molecule.atom: - asec_charges.append({"lbl": atomsymb[atom.na], "rx": atom.rx, "ry": atom.ry, "rz": atom.rz, "chg": atom.chg}) - - # if self.vdwforces == "yes": - # vdw_meanfield[-1]["rx"] = atom["rx"] - # vdw_meanfield[-1]["ry"] = atom["ry"] - # vdw_meanfield[-1]["rz"] = atom["rz"] - # vdw_meanfield[-1]["eps"] = atom["eps"] - # vdw_meanfield[-1]["sig"] = atom["sig"] - - # #### Read lines with ghosts or lps in molecules of type 0 (reference) - # #### and, if dist < thickness, appends to asec - # if type == 0: - # for ghost in ghost_atoms: - # line = xyzfile.pop(0).split() - # if line[0] != dice_ghost_label: - # sys.exit("Error reading file {}".format(file)) - # if dist < thickness[-1]: - # asec_charges.append({}) - # asec_charges[-1]['rx'] = float(line[1]) - # asec_charges[-1]['ry'] = float(line[2]) - # asec_charges[-1]['rz'] = float(line[3]) - # asec_charges[-1]['chg'] = ghost['chg'] / norm_factor - - # for lp in lp_atoms: - # line = xyzfile.pop(0).split() - # if line[0] != dice_ghost_label: - # sys.exit("Error reading file {}".format(file)) - # if dist < thickness[-1]: - # asec_charges.append({}) - # asec_charges[-1]['rx'] = float(line[1]) - # asec_charges[-1]['ry'] = float(line[2]) - # asec_charges[-1]['rz'] = float(line[3]) - # asec_charges[-1]['chg'] = lp['chg'] / norm_factor - - picked_mols.append(mol_count) - - self.outfile.write("Done\n") - - string = "In average, {:^7.2f} molecules ".format( - sum(picked_mols) / norm_factor - ) - string += "were selected from each of the {} configurations ".format( - len(picked_mols) - ) - string += ( - "of the production simulations to form the ASEC, comprising a shell with " - ) - string += "minimum thickness of {:>6.2f} Angstrom\n".format( - sum(thickness) / norm_factor - ) - - self.outfile.write(textwrap.fill(string, 86)) - self.outfile.write("\n") - - otherfh = open("ASEC.xyz", "w", 1) - for charge in asec_charges: - otherfh.write( - "{} {:>10.5f} {:>10.5f} {:>10.5f}\n".format( - charge['lbl'], charge['rx'], charge['ry'], charge['rz'] - ) - ) - otherfh.close() - - for charge in asec_charges: - charge['chg'] /= norm_factor - - return asec_charges diff --git a/diceplayer/DPpack/Utils/Misc.py b/diceplayer/DPpack/Utils/Misc.py deleted file mode 100644 index 06c7e1e..0000000 --- a/diceplayer/DPpack/Utils/Misc.py +++ /dev/null @@ -1,67 +0,0 @@ -import os, sys, time -from posixpath import sep -import shutil, gzip - -####################################### functions ###################################### - -def weekday_date_time(): - - return time.strftime("%A, %d %b %Y at %H:%M:%S") - - -def date_time(): - - return time.strftime("%d %b %Y at %H:%M:%S") - - -def compress_files_1mb(path): - - working_dir = os.getcwd() - os.chdir(path) - - files = filter(os.path.isfile, os.listdir(os.curdir)) - for file in files: - if os.path.getsize(file) > 1024 * 1024: ## If bigger than 1MB - filegz = file + ".gz" - try: - with open(file, 'rb') as f_in: - with gzip.open(filegz, 'wb') as f_out: - shutil.copyfileobj(f_in, f_out) - except: - sys.exit("Error: cannot compress file {}".format(file)) - - os.chdir(working_dir) - - return - -def make_simulation_dir(): - - sim_dir = "simfiles" - if os.path.exists(sim_dir): - sys.exit("Error: a file or a directory {} already exists, move or delete de simfiles directory to continue.".format(sim_dir)) - try: - os.makedirs(sim_dir) - except: - sys.exit("Error: cannot make directory {}".format(sim_dir)) - -def make_step_dir(cycle): - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle) - path = sim_dir + os.sep + step_dir - if os.path.exists(path): - sys.exit("Error: a file or directory {} already exists".format(step_dir)) - try: - os.makedirs(path) - except: - sys.exit("Error: cannot make directory {}".format(step_dir)) - -def make_qm_dir(cycle): - - sim_dir = "simfiles" - step_dir = "step{:02d}".format(cycle) - path = sim_dir + os.sep + step_dir + os.sep + "qm" - try: - os.makedirs(path) - except: - sys.exit("Error: cannot make directory {}".format(path)) \ No newline at end of file diff --git a/diceplayer/DPpack/Utils/Optimization.py b/diceplayer/DPpack/Utils/Optimization.py deleted file mode 100644 index cc8cf91..0000000 --- a/diceplayer/DPpack/Utils/Optimization.py +++ /dev/null @@ -1,263 +0,0 @@ -# import sys, math -# from copy import deepcopy - -# import numpy as np -# from numpy import linalg - -# from diceplayer.DPpack.SetGlobals import * - - -# epsilon = 1e-8 - -# ####################################### functions ###################################### - - -# def best_previous_point(): - -# min_energy = 0 -# idx = 0 -# for energy in internal["energy"][:-1]: -# if energy < min_energy or abs(energy - min_energy) < 1e-10: -# min_energy = energy -# min_idx = idx -# idx += 1 - -# return min_idx - - -# def best_point(): - -# min_energy = 0 -# idx = 0 -# for energy in internal["energy"]: -# if energy < min_energy or abs(energy - min_energy) < 1e-10: -# min_energy = energy -# min_idx = idx -# idx += 1 - -# return min_idx - - -# def line_search(fh): - -# X1 = internal["position"][-1] # numpy array -# e1 = internal["energy"][-1] -# G1 = internal["gradient"][-1] # numpy array - -# idx = best_previous_point() -# X0 = internal["position"][idx] # numpy array -# e0 = internal["energy"][idx] -# G0 = internal["gradient"][idx] # numpy array - -# # First try a quartic fit -# fh.write("Attempting a quartic fit.\n") -# success, y0 = quartic_fit(X0, X1, e0, e1, G0, G1, fh) -# if success and y0 > 0: -# if y0 < 1: -# new_point = X0 + y0 * (X1 - X0) -# new_gradient = interpolate_gradient(G0, G1, y0) -# new_gradient = perpendicular_projection(new_gradient, X1 - X0) -# fh.write("Line search succeded.\n") -# return True, new_point, new_gradient -# else: -# idx = best_point() -# if idx == len(internal["energy"]) - 1: -# new_point = X0 + y0 * (X1 - X0) -# new_gradient = interpolate_gradient(G0, G1, y0) -# new_gradient = perpendicular_projection(new_gradient, X1 - X0) -# fh.write("Line search succeded.\n") -# return True, new_point, new_gradient -# else: -# fh.write("Quartic step is not acceptable. ") -# elif success: -# fh.write("Quartic step is not acceptable. ") - -# # If no condition is met, then y0 is unacceptable. Try the cubic fit next -# fh.write("Attempting a cubic fit.\n") -# success, y0 = cubic_fit(X0, X1, e0, e1, G0, G1, fh) -# if success and y0 > 0: -# if y0 < 1: -# new_point = X0 + y0 * (X1 - X0) -# new_gradient = interpolate_gradient(G0, G1, y0) -# new_gradient = perpendicular_projection(new_gradient, X1 - X0) -# fh.write("Line search succeded.\n") -# return True, new_point, new_gradient -# else: -# previous_step = X1 - internal["position"][-2] -# previous_step_size = linalg.norm(previous_step) -# new_point = X0 + y0 * (X1 - X0) -# step = new_point - X1 -# step_size = linalg.norm(step) -# if step_size < previous_step_size: -# new_gradient = interpolate_gradient(G0, G1, y0) -# new_gradient = perpendicular_projection(new_gradient, X1 - X0) -# fh.write("Line search succeded.\n") -# return True, new_point, new_gradient -# else: -# fh.write("Cubic step is not acceptable. ") -# elif success: -# fh.write("Cubic step is not acceptable. ") - -# # If no condition is met again, then all fits fail. -# fh.write("All fits fail. ") - -# # Then, if the latest point is not the best, use y0 = 0.5 (step to the midpoint) -# idx = best_point() -# if idx < len(internal["energy"]) - 1: -# y0 = 0.5 -# new_point = X0 + y0 * (X1 - X0) -# new_gradient = interpolate_gradient(G0, G1, y0) -# new_gradient = perpendicular_projection(new_gradient, X1 - X0) -# fh.write("Moving to the midpoint.\n") -# return True, new_point, new_gradient - -# # If the latest point is the best point, no linear search is done -# fh.write("No linear search will be used in this step.\n") - -# return False, None, None - - -# ## For cubic and quartic fits, G0 and G1 are the gradient vectors - - -# def cubic_fit(X0, X1, e0, e1, G0, G1, fh): - -# line = X1 - X0 -# line /= linalg.norm(line) - -# g0 = np.dot(G0, line) -# g1 = np.dot(G1, line) - -# De = e1 - e0 - -# fh.write( -# "De = {:<18.15e} g0 = {:<12.8f} g1 = {:<12.8f}\n".format(De, g0, g1) -# ) - -# alpha = g1 + g0 - 2 * De -# if abs(alpha) < epsilon: -# fh.write("Cubic fit failed: alpha too small\n") -# return False, None - -# beta = 3 * De - 2 * g0 - g1 -# discriminant = 4 * (beta**2 - 3 * alpha * g0) -# if discriminant < 0: -# fh.write("Cubic fit failed: no minimum found (negative Delta)\n") -# return False, None -# if abs(discriminant) < epsilon: -# fh.write("Cubic fit failed: no minimum found (null Delta)\n") -# return False, None - -# y0 = (-beta + math.sqrt(discriminant / 4)) / (3 * alpha) -# fh.write("Minimum found with y0 = {:<8.4f}\n".format(y0)) - -# return True, y0 - - -# def quartic_fit(X0, X1, e0, e1, G0, G1, fh): - -# line = X1 - X0 -# line /= linalg.norm(line) - -# g0 = np.dot(G0, line) -# g1 = np.dot(G1, line) - -# De = e1 - e0 -# Dg = g1 - g0 - -# fh.write( -# "De = {:<18.15e} g0 = {:<12.8f} g1 = {:<12.8f}\n".format(De, g0, g1) -# ) - -# if Dg < 0 or De - g0 < 0: -# fh.write("Quartic fit failed: negative alpha\n") -# return False, None -# if abs(Dg) < epsilon or abs(De - g0) < epsilon: -# fh.write("Quartic fit failed: alpha too small\n") -# return False, None - -# discriminant = 16 * (Dg**2 - 3 * (g1 + g0 - 2 * De) ** 2) -# if discriminant < 0: -# fh.write("Quartic fit failed: no minimum found (negative Delta)\n") -# return False, None - -# alpha1 = (Dg + math.sqrt(discriminant / 16)) / 2 -# alpha2 = (Dg - math.sqrt(discriminant / 16)) / 2 - -# fh.write("alpha1 = {:<7.4e} alpha2 = {:<7.4e}\n".format(alpha1, alpha2)) - -# alpha = alpha1 -# beta = g1 + g0 - 2 * De - 2 * alpha -# gamma = De - g0 - alpha - beta - -# y0 = (-1 / (2 * alpha)) * ( -# (beta**3 - 4 * alpha * beta * gamma + 8 * g0 * alpha**2) / 4 -# ) ** (1 / 3) -# fh.write("Minimum found with y0 = {:<8.4f}\n".format(y0)) - -# return True, y0 - - -# def rfo_step(gradient, hessian, type): - -# dim = len(gradient) - -# aug_hessian = [] -# for i in range(dim): -# aug_hessian.extend(hessian[i, :].tolist()) -# aug_hessian.append(gradient[i]) - -# aug_hessian.extend(gradient.tolist()) -# aug_hessian.append(0) - -# aug_hessian = np.array(aug_hessian).reshape(dim + 1, dim + 1) - -# evals, evecs = linalg.eigh(aug_hessian) - -# if type == "min": -# step = np.array(evecs[:-1, 0]) -# elif type == "ts": -# step = np.array(evecs[:-1, 1]) - -# return step - - -# def update_trust_radius(): - -# if internal["trust_radius"] == None: -# internal["trust_radius"] = player["maxstep"] -# elif len(internal["energy"]) > 1: -# X1 = internal["position"][-1] -# X0 = internal["position"][-2] -# Dx = X1 - X0 -# displace = linalg.norm(Dx) -# e1 = internal["energy"][-1] -# e0 = internal["energy"][-2] -# De = e1 - e0 -# g0 = internal["gradient"][-2] -# h0 = internal["hessian"][-2] - -# rho = De / (np.dot(g0, Dx) + 0.5 * np.dot(Dx, np.matmul(h0, Dx.T).T)) - -# if rho > 0.75 and displace > 0.8 * internal["trust_radius"]: -# internal["trust_radius"] = 2 * internal["trust_radius"] -# elif rho < 0.25: -# internal["trust_radius"] = 0.25 * displace - -# return - - -# def interpolate_gradient(G0, G1, y0): - -# DG = G1 - G0 -# gradient = G0 + y0 * DG - -# return gradient - - -# def perpendicular_projection(vector, line): - -# direction = line / linalg.norm(line) -# projection = np.dot(vector, direction) * direction - -# return vector - projection diff --git a/diceplayer/DPpack/Utils/StepDTO.py b/diceplayer/DPpack/Utils/StepDTO.py deleted file mode 100644 index d03d43b..0000000 --- a/diceplayer/DPpack/Utils/StepDTO.py +++ /dev/null @@ -1,21 +0,0 @@ -from dataclasses import dataclass -from typing import List - -from diceplayer.DPpack.Environment.Molecule import Molecule - - -@dataclass -class StepDTO: - - cycle: int = None - initcyc: int = None - nprocs: int = None - ncores: int = None - altsteps: int = None - switchcyc: int = None - opt: str = None - nmol: List[int] = None - molecule: List[Molecule] = None - - charges: List[float] = None - position: List[float] = None \ No newline at end of file diff --git a/diceplayer/DPpack/Environment/__init__.py b/diceplayer/__init__.py similarity index 100% rename from diceplayer/DPpack/Environment/__init__.py rename to diceplayer/__init__.py diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 247b0fa..c461bb8 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -1,21 +1,19 @@ +from diceplayer.player import Player + +from pathlib import Path import argparse -import os +import logging import pickle -import shutil import sys -import setproctitle - -from diceplayer.DPpack.Player import Player -from diceplayer.DPpack.Utils.Misc import * __VERSION = "v0.0.1" -os.nice(+19) -setproctitle.setproctitle("diceplayer-{}".format(__VERSION)) if __name__ == "__main__": - #### Read and store the arguments passed to the program #### - #### and set the usage and help messages #### + """ + Read and store the arguments passed to the program + and set the usage and help messages + """ parser = argparse.ArgumentParser(prog="Diceplayer") parser.add_argument( @@ -38,173 +36,30 @@ if __name__ == "__main__": metavar="OUTFILE", help="output file of diceplayer [default = run.log]" ) - ## Study the option of a parameter for continuing the last process via data from control.in and run.log files - args = parser.parse_args() - #### Open OUTFILE for writing and print keywords and initial info + # Open OUTFILE for writing and print keywords and initial info try: - if args.opt_continue and os.path.exists(args.outfile): + pickle_path = Path("latest-step.pkl") + if args.opt_continue and pickle_path.exists(): + with open(pickle_path) as pickle_file: + save = pickle.load(pickle_file) - save = pickle.load(open("latest-step.pkl", "rb")) - - if os.path.isfile(args.outfile + ".backup"): - os.remove(args.outfile + ".backup") - - os.rename(args.outfile, args.outfile + ".backup") - outfile = open(args.outfile, "w", 1) - - elif os.path.exists(args.outfile): - os.rename(args.outfile, args.outfile + ".backup") - outfile = open(args.outfile, "w", 1) - else: - outfile = open(args.outfile, "w", 1) + output_path = Path(args.outfile) + if output_path.exists(): + output_path.rename(str(output_path)+".backup") except Exception as err: sys.exit(err) - try: + logging.basicConfig( + filename=args.outfile, + format='%(message)s', + level=logging.INFO + ) - if os.path.exists(args.infile): - infile = open(args.infile, "r") + player = Player(args.infile) - except Exception as err: - sys.exit(err) - - #### Read and check the keywords in INFILE - - player = Player(infile, outfile) - - player.read_keywords() - - player.check_keywords() - player.print_keywords() - - if args.opt_continue: - player.initcyc = save[0] + 1 - player.system = save[1] - else: - player.initcyc = 1 - player.read_potential() - - #### Check whether the executables are in the path - #### and print potential to Log File - - player.check_executables() - - player.print_potential() - - #### Bring the molecules to standard orientation and prints info about them - - for i in range(len(player.system.molecule)): - - player.outfile.write( - "\nMolecule type {} - {}:\n\n".format( - i + 1, player.system.molecule[i].molname - ) - ) - player.system.molecule[i].print_mol_info(player.outfile) - player.outfile.write( - " Translating and rotating molecule to standard orientation..." - ) - player.system.molecule[i].standard_orientation() - player.outfile.write(" Done\n\n New values:\n") - player.system.molecule[i].print_mol_info(player.outfile) - - player.outfile.write(90 * "=") - player.outfile.write("\n") - - if not args.opt_continue: - make_simulation_dir() - else: - simdir = "simfiles" - stepdir = "step{:02d}".format(player.initcyc) - if os.path.exists(simdir + os.sep + stepdir): - shutil.rmtree(simdir + os.sep + stepdir) - - #### Open the geoms.xyz file and prints the initial geometry if starting from zero - - if player.initcyc == 1: - try: - path = "geoms.xyz" - geomsfh = open(path, "w", 1) - except EnvironmentError as err: - sys.exit(err) - player.system.print_geom(0, geomsfh) - geomsfh.write(40 * "-" + "\n") - else: - try: - path = "geoms.xyz" - geomsfh = open(path, "a", 1) - except EnvironmentError as err: - sys.exit(err) - - player.outfile.write("\nStarting the iterative process.\n") - - ## Initial position (in Bohr) - position = player.system.molecule[0].read_position() - - ## If restarting, read the last gradient and hessian - # if player.initcyc > 1: - # if player.qmprog in ("g03", "g09", "g16"): - # Gaussian.read_forces("grad_hessian.dat") - # Gaussian.read_hessian_fchk("grad_hessian.dat") - - # if player['qmprog'] == "molcas": - # Molcas.read_forces("grad_hessian.dat") - # Molcas.read_hessian("grad_hessian.dat") - - ### - ### Start the iterative process - ### - - player.outfile.write("\n" + 90 * "-" + "\n") - - for cycle in range(player.initcyc, player.initcyc + player.maxcyc): - - player.outfile.write("{} Step # {}\n".format(40 * " ", cycle)) - player.outfile.write(90 * "-" + "\n\n") - - make_step_dir(cycle) - - #### - #### Start block of parallel simulations - #### - - player.dice_start(cycle) - - ### - ### End of parallel simulations block - ### - - ## After ASEC is built, compress files bigger than 1MB - for proc in range(1, player.nprocs + 1): - path = "simfiles"+os.sep+"step{:02d}".format(cycle) + os.sep + "p{:02d}".format(proc) - compress_files_1mb(path) - - ### - ### Start QM calculation - ### - - player.gaussian_start(cycle, geomsfh) - - player.system.print_geom(cycle, geomsfh) - geomsfh.write(40 * "-" + "\n") - - player.outfile.write("\n+" + 88 * "-" + "+\n") - - pickle.dump([cycle, player.system], open("latest-step.pkl", "wb")) - #### - #### End of the iterative process - #### - - ## imprimir ultimas mensagens, criar um arquivo de potencial para ser usado em eventual - ## continuacao, fechar arquivos (geoms.xyz, run.log, ...) - - player.outfile.write("\nDiceplayer finished normally!\n") - player.outfile.close() -#### -#### End of the program -#### + player.start() diff --git a/diceplayer/player.py b/diceplayer/player.py new file mode 100644 index 0000000..9d196bb --- /dev/null +++ b/diceplayer/player.py @@ -0,0 +1,274 @@ +from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.utils.dataclass_protocol import Dataclass +from diceplayer.shared.config.gaussian_dto import GaussianDTO +from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.environment.system import System +from diceplayer.shared.utils.misc import weekday_date_time +from diceplayer.shared.config.player_dto import PlayerDTO +from diceplayer.shared.external.gaussian import Gaussian +from diceplayer.shared.config.dice_dto import DiceDTO +from diceplayer.shared.external.dice import Dice + +from dataclasses import fields +from pathlib import Path +from typing import Type +import logging +import yaml +import sys +import os + +from diceplayer.shared.utils.ptable import atommass + +ENV = ["OMP_STACKSIZE"] + + +class Player: + __slots__ = [ + 'config', + 'system', + 'dice', + 'gaussian', + ] + + def __init__(self, infile: str): + config_data = self.read_keywords(infile) + + self.system = System() + + self.config = self.set_config( + config_data.get("diceplayer") + ) + + self.gaussian = Gaussian(config_data.get("gaussian")) + self.dice = Dice(config_data.get("dice")) + + def start(self): + self.print_keywords() + + self.create_simulation_dir() + + self.read_potentials() + # self.print_potentials() + + def create_simulation_dir(self): + simulation_dir_path = Path(self.config.simulation_dir) + if simulation_dir_path.exists(): + raise FileExistsError( + f"Error: a file or a directory {self.config.simulation_dir} already exists," + f" move or delete the simfiles directory to continue." + ) + try: + simulation_dir_path.mkdir() + except FileExistsError: + OSError( + f"Error: cannot make directory {self.config.simulation_dir}" + ) + + def print_keywords(self) -> None: + + def log_keywords(config: Dataclass, dto: Type[Dataclass]): + for key in sorted(list(map(lambda f: f.name, fields(dto)))): + if getattr(config, key) is not None: + if isinstance(getattr(config, key), list): + string = " ".join(str(x) for x in getattr(config, key)) + logging.info(f"{key} = [ {string} ]") + else: + logging.info(f"{key} = {getattr(config, key)}") + + logging.info( + "##########################################################################################\n" + "############# Welcome to DICEPLAYER version 1.0 #############\n" + "##########################################################################################\n" + "\n" + ) + logging.info("Your python version is {}\n".format(sys.version)) + logging.info("\n") + logging.info("Program started on {}\n".format(weekday_date_time())) + logging.info("\n") + logging.info("Environment variables:\n") + for var in ENV: + logging.info( + "{} = {}\n".format( + var, (os.environ[var] if var in os.environ else "Not set") + ) + ) + + logging.info( + "\n==========================================================================================\n" + " CONTROL variables being used in this run:\n" + "------------------------------------------------------------------------------------------\n" + "\n" + ) + + logging.info("\n") + + logging.info( + "------------------------------------------------------------------------------------------\n" + " DICE variables being used in this run:\n" + "------------------------------------------------------------------------------------------\n" + "\n" + ) + + log_keywords(self.dice.config, DiceDTO) + + logging.info("\n") + + logging.info( + "------------------------------------------------------------------------------------------\n" + " GAUSSIAN variables being used in this run:\n" + "------------------------------------------------------------------------------------------\n" + "\n" + ) + + log_keywords(self.gaussian.config, GaussianDTO) + + logging.info("\n") + + def read_potentials(self): + try: + with open(self.dice.config.ljname) as file: + ljdata = file.readlines() + except FileNotFoundError: + raise RuntimeError( + f"Potential file {self.dice.config.ljname} not found." + ) + + combrule = ljdata.pop(0).split()[0] + if combrule not in ("*", "+"): + sys.exit( + "Error: expected a '*' or a '+' sign in 1st line of file {}".format( + self.dice.config.ljname + ) + ) + self.dice.combrule = combrule + + ntypes = ljdata.pop(0).split()[0] + if not ntypes.isdigit(): + sys.exit( + "Error: expected an integer in the 2nd line of file {}".format( + self.dice.config.ljname + ) + ) + ntypes = int(ntypes) + + if ntypes != len(self.dice.config.nmol): + sys.exit( + f"Error: number of molecule types in file {self.dice.config.ljname}" + f"must match that of 'nmol' keyword in config file" + ) + + for i in range(ntypes): + + nsites, molname = ljdata.pop(0).split()[:2] + + if not nsites.isdigit(): + raise ValueError( + f"Error: expected nsites to be an integer for molecule type {i}" + ) + + if molname is None: + raise ValueError( + f"Error: expected molecule name for molecule type {i}" + ) + + nsites = int(nsites) + self.system.add_type(nsites, Molecule(molname)) + + atom_fields = ["lbl", "na", "rx", "ry", "rz", "chg", "eps", "sig"] + for j in range(nsites): + new_atom = dict(zip( + atom_fields, + ljdata.pop(0).split() + )) + self.system.molecule[i].add_atom( + Atom(**self.validate_atom_dict(i, j, new_atom)) + ) + + def dice_start(self): + self.dice.start() + + def gaussian_start(self): + self.gaussian.start() + + @staticmethod + def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict: + molecule_type += 1 + molecule_site += 1 + + if len(atom_dict) < 8: + raise ValueError( + f'Invalid number of fields for site {molecule_site} for molecule type {molecule_type}.' + ) + + try: + atom_dict['lbl'] = int(atom_dict['lbl']) + except ValueError: + raise ValueError( + f'Invalid lbl fields for site {molecule_site} for molecule type {molecule_type}.' + ) + + try: + atom_dict['na'] = int(atom_dict['na']) + except ValueError: + raise ValueError( + f'Invalid na fields for site {molecule_site} for molecule type {molecule_type}.' + ) + + try: + atom_dict['rx'] = float(atom_dict['rx']) + except ValueError: + raise ValueError( + f'Invalid rx fields for site {molecule_site} for molecule type {molecule_type}.' + f'Value must be a float.' + ) + + try: + atom_dict['ry'] = float(atom_dict['ry']) + except ValueError: + raise ValueError( + f'Invalid ry fields for site {molecule_site} for molecule type {molecule_type}.' + f'Value must be a float.' + ) + + try: + atom_dict['rz'] = float(atom_dict['rx']) + except ValueError: + raise ValueError( + f'Invalid rz fields for site {molecule_site} for molecule type {molecule_type}.' + f'Value must be a float.' + ) + + try: + atom_dict['chg'] = float(atom_dict['chg']) + except ValueError: + raise ValueError( + f'Invalid chg fields for site {molecule_site} for molecule type {molecule_type}.' + f'Value must be a float.' + ) + + try: + atom_dict['eps'] = float(atom_dict['eps']) + except ValueError: + raise ValueError( + f'Invalid eps fields for site {molecule_site} for molecule type {molecule_type}.' + f'Value must be a float.' + ) + + try: + atom_dict['sig'] = float(atom_dict['sig']) + except ValueError: + raise ValueError( + f'Invalid sig fields for site {molecule_site} for molecule type {molecule_type}.' + f'Value must be a float.' + ) + + return atom_dict + + @staticmethod + def set_config(data: dict) -> PlayerDTO: + return PlayerDTO.from_dict(data) + + @staticmethod + def read_keywords(infile) -> dict: + with open(infile, 'r') as yml_file: + return yaml.load(yml_file, Loader=yaml.SafeLoader) diff --git a/diceplayer/DPpack/External/__init__.py b/diceplayer/shared/__init__.py similarity index 100% rename from diceplayer/DPpack/External/__init__.py rename to diceplayer/shared/__init__.py diff --git a/diceplayer/DPpack/Utils/__init__.py b/diceplayer/shared/config/__init__.py similarity index 100% rename from diceplayer/DPpack/Utils/__init__.py rename to diceplayer/shared/config/__init__.py diff --git a/diceplayer/shared/config/dice_dto.py b/diceplayer/shared/config/dice_dto.py new file mode 100644 index 0000000..832e290 --- /dev/null +++ b/diceplayer/shared/config/dice_dto.py @@ -0,0 +1,54 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass + +from dataclasses import dataclass +from dacite import from_dict +from typing import List + + +@dataclass +class DiceDTO(Dataclass): + + ljname: str + outname: str + ncores: int + dens: float + nmol: List[int] + nstep: List[int] + + upbuf = 360 + combrule = "*" + isave: int = 1000 + press: float = 1.0 + temp: float = 300.0 + randominit: str = 'first' + + def __post_init__(self): + + if self.ljname is None: + raise ValueError( + "Error: 'ljname' keyword not specified in config file" + ) + + if self.outname is None: + raise ValueError( + "Error: 'outname' keyword not specified in config file" + ) + + if self.dens is None: + raise ValueError( + "Error: 'dens' keyword not specified in config file" + ) + + if self.nmol == 0: + raise ValueError( + "Error: 'nmol' keyword not defined appropriately in config file" + ) + + if self.nstep == 0: + raise ValueError( + "Error: 'nstep' keyword not defined appropriately in config file" + ) + + @classmethod + def from_dict(cls, param: dict): + return from_dict(DiceDTO, param) diff --git a/diceplayer/shared/config/gaussian_dto.py b/diceplayer/shared/config/gaussian_dto.py new file mode 100644 index 0000000..6e609a6 --- /dev/null +++ b/diceplayer/shared/config/gaussian_dto.py @@ -0,0 +1,28 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass + +from dataclasses import dataclass +from dacite import from_dict + + +@dataclass +class GaussianDTO(Dataclass): + level: str + qmprog: str + keywords: str + + chgmult = [0, 1] + pop: str = 'chelpg' + + def __post_init__(self): + if self.qmprog not in ("g03", "g09", "g16"): + raise ValueError( + "Error: invalid qmprog value." + ) + if self.level is None: + raise ValueError( + "Error: 'level' keyword not specified in config file." + ) + + @classmethod + def from_dict(cls, param: dict): + return from_dict(GaussianDTO, param) diff --git a/diceplayer/shared/config/player_dto.py b/diceplayer/shared/config/player_dto.py new file mode 100644 index 0000000..be9f25a --- /dev/null +++ b/diceplayer/shared/config/player_dto.py @@ -0,0 +1,24 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass + +from dataclasses import dataclass +from dacite import from_dict + + +@dataclass +class PlayerDTO(Dataclass): + opt: bool + maxcyc: int + nprocs: int + + qmprog: str = 'g16' + altsteps: int = 20000 + simulation_dir = 'simfiles' + + def __post_init__(self): + MIN_STEP = 20000 + # altsteps value is always the nearest multiple of 1000 + self.altsteps = round(max(MIN_STEP, self.altsteps) / 1000) * 1000 + + @classmethod + def from_dict(cls, param: dict): + return from_dict(PlayerDTO, param) diff --git a/diceplayer/DPpack/__init__.py b/diceplayer/shared/environment/__init__.py similarity index 100% rename from diceplayer/DPpack/__init__.py rename to diceplayer/shared/environment/__init__.py diff --git a/diceplayer/DPpack/Environment/Atom.py b/diceplayer/shared/environment/atom.py similarity index 86% rename from diceplayer/DPpack/Environment/Atom.py rename to diceplayer/shared/environment/atom.py index 1da6b06..f093ee5 100644 --- a/diceplayer/DPpack/Environment/Atom.py +++ b/diceplayer/shared/environment/atom.py @@ -1,5 +1,4 @@ -from diceplayer.DPpack.Utils.PTable import * -from diceplayer.DPpack.Utils.Misc import * +from diceplayer.shared.utils.ptable import atommass class Atom: @@ -16,16 +15,17 @@ class Atom: eps (float): quantum number epsilon of the represented atom. sig (float): quantum number sigma of the represented atom. """ + def __init__( - self, - lbl: int, - na: int, - rx: float, - ry: float, - rz: float, - chg: float, - eps: float, - sig: float, + self, + lbl: int, + na: int, + rx: float, + ry: float, + rz: float, + chg: float, + eps: float, + sig: float, ) -> None: """ The constructor function __init__ is used to create new instances of the Atom class. diff --git a/diceplayer/DPpack/Environment/Molecule.py b/diceplayer/shared/environment/molecule.py similarity index 87% rename from diceplayer/DPpack/Environment/Molecule.py rename to diceplayer/shared/environment/molecule.py index 2f41235..8e88d41 100644 --- a/diceplayer/DPpack/Environment/Molecule.py +++ b/diceplayer/shared/environment/molecule.py @@ -1,23 +1,15 @@ -from diceplayer.DPpack.Utils.PTable import * -from diceplayer.DPpack.Utils.Misc import * - -from diceplayer.DPpack.Environment.Atom import Atom - -from typing import IO, Any, Final, Tuple, List, TextIO -from nptyping import Float, NDArray, Shape - -from numpy import linalg -import numpy as np - -from copy import deepcopy -import sys, math -import sys +import logging import math +from copy import deepcopy +from typing import List, Any, Tuple, Final, Union +import numpy as np +from nptyping import NDArray, Shape, Float +from numpy.linalg import linalg -""" Constants of unit conversion """ -BOHR2ANG: Final[float] = 0.52917721092 -ANG2BOHR: Final[float] = 1 / BOHR2ANG +from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.utils.misc import BOHR2ANG +from diceplayer.shared.utils.ptable import ghost_number class Molecule: @@ -52,9 +44,9 @@ class Molecule: self.ghost_atoms: List[Atom] = [] self.lp_atoms: List[Atom] = [] - + self.total_mass: int = 0 - self.com: NDArray[Any, Any] = None + self.com: Union[None, NDArray[Any, Any]] = None def add_atom(self, a: Atom) -> None: """ @@ -67,13 +59,9 @@ class Molecule: self.atom.append(a) self.total_mass += a.mass - if a.na == ghost_number: - - self.ghost_atoms.append(self.atom.index(a)) - self.center_of_mass() - def center_of_mass(self) -> None: + def center_of_mass(self) -> NDArray[Any, Any]: """ Calculates the center of mass of the molecule """ @@ -81,11 +69,12 @@ class Molecule: self.com = np.zeros(3) for atom in self.atom: - self.com += atom.mass * np.array([atom.rx, atom.ry, atom.rz]) self.com = self.com / self.total_mass + return self.com + def center_of_mass_to_origin(self) -> None: """ Updated positions based on the center of mass of the molecule @@ -94,7 +83,6 @@ class Molecule: self.center_of_mass() for atom in self.atom: - atom.rx -= self.com[0] atom.ry -= self.com[1] atom.rz -= self.com[2] @@ -121,7 +109,7 @@ class Molecule: return [charge, dipole[0], dipole[1], dipole[2], total_dipole] - def distances_between_atoms(self) -> NDArray[Shape["Any,Any"],Float]: + def distances_between_atoms(self) -> NDArray[Shape["Any,Any"], Float]: """ Calculates distances between the atoms of the molecule @@ -138,7 +126,7 @@ class Molecule: dx = atom1.rx - atom2.rx dy = atom1.ry - atom2.ry dz = atom1.rz - atom2.rz - distances.append(math.sqrt(dx**2 + dy**2 + dz**2)) + distances.append(math.sqrt(dx ** 2 + dy ** 2 + dz ** 2)) return np.array(distances).reshape(dim, dim) @@ -154,14 +142,13 @@ class Molecule: Ixx = Ixy = Ixz = Iyy = Iyz = Izz = 0.0 for atom in self.atom: - dx = atom.rx - self.com[0] dy = atom.ry - self.com[1] dz = atom.rz - self.com[2] - Ixx += atom.mass * (dy**2 + dz**2) - Iyy += atom.mass * (dz**2 + dx**2) - Izz += atom.mass * (dx**2 + dy**2) + Ixx += atom.mass * (dy ** 2 + dz ** 2) + Iyy += atom.mass * (dz ** 2 + dx ** 2) + Izz += atom.mass * (dx ** 2 + dy ** 2) Ixy += atom.mass * dx * dy * -1 Ixz += atom.mass * dx * dz * -1 @@ -215,7 +202,7 @@ class Molecule: try: evals, evecs = linalg.eigh(self.inertia_tensor()) except: - sys.exit("Error: diagonalization of inertia tensor did not converge") + raise RuntimeError("Error: diagonalization of inertia tensor did not converge") return evals, evecs @@ -235,16 +222,16 @@ class Molecule: return position def updateCharges(self, charges: List[float]) -> None: - + for i, atom in enumerate(self.atom): atom.chg = charges[i] def update_hessian( - self, - step: np.ndarray, - cur_gradient: np.ndarray, - old_gradient: np.ndarray, - hessian: np.ndarray, + self, + step: np.ndarray, + cur_gradient: np.ndarray, + old_gradient: np.ndarray, + hessian: np.ndarray, ) -> np.ndarray: """ Updates the Hessian of the molecule based on the current hessian, the current gradient and the previous gradient @@ -305,21 +292,18 @@ class Molecule: evals, evecs = self.principal_axes() if round(linalg.det(evecs)) == -1: - evecs[0, 2] *= -1 evecs[1, 2] *= -1 evecs[2, 2] *= -1 if round(linalg.det(evecs)) != 1: - - sys.exit( + raise RuntimeError( "Error: could not make a rotation matrix while adopting the standard orientation" ) rot_matrix = evecs.T for atom in self.atom: - position = np.array([atom.rx, atom.ry, atom.rz]) new_position = np.matmul(rot_matrix, position.T).T @@ -332,7 +316,7 @@ class Molecule: Creates a new Molecule object where its' atoms has been translated by a vector Args: - vector (np.ndarray): translation vector + vector (np.ndarray): translation vector Returns: Molecule: new Molecule object translated by a vector @@ -341,22 +325,18 @@ class Molecule: new_molecule = deepcopy(self) for atom in new_molecule.atom: - atom.rx += vector[0] atom.ry += vector[1] atom.rz += vector[2] return new_molecule - def print_mol_info(self, fh: TextIO) -> None: + def print_mol_info(self) -> None: """ Prints the Molecule information into a Output File - - Args: - fh (TextIO): Output File """ - fh.write( + logging.info( " Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )\n".format( self.com[0], self.com[1], self.com[2] ) @@ -364,45 +344,45 @@ class Molecule: inertia = self.inertia_tensor() evals, evecs = self.principal_axes() - fh.write( + logging.info( " Moments of inertia = {:>9E} {:>9E} {:>9E}\n".format( evals[0], evals[1], evals[2] ) ) - fh.write( + logging.info( " Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( evecs[0, 0], evecs[1, 0], evecs[2, 0] ) ) - fh.write( + logging.info( " Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( evecs[0, 1], evecs[1, 1], evecs[2, 1] ) ) - fh.write( + logging.info( " Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( evecs[0, 2], evecs[1, 2], evecs[2, 2] ) ) sizes = self.sizes_of_molecule() - fh.write( + logging.info( " Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )\n".format( sizes[0], sizes[1], sizes[2] ) ) - fh.write(" Total mass = {:>8.2f} au\n".format(self.total_mass)) + logging.info(" Total mass = {:>8.2f} au\n".format(self.total_mass)) chg_dip = self.charges_and_dipole() - fh.write(" Total charge = {:>8.4f} e\n".format(chg_dip[0])) - fh.write( + logging.info(" Total charge = {:>8.4f} e\n".format(chg_dip[0])) + logging.info( " Dipole moment = ( {:>9.4f} , {:>9.4f} , {:>9.4f} ) Total = {:>9.4f} Debye\n\n".format( chg_dip[1], chg_dip[2], chg_dip[3], chg_dip[4] ) ) - def minimum_distance(self, molec: "Molecule") -> float: + def minimum_distance(self, molec: 'Molecule') -> float: """ Return the minimum distance between two molecules @@ -421,6 +401,6 @@ class Molecule: dx = atom1.rx - atom2.rx dy = atom1.ry - atom2.ry dz = atom1.rz - atom2.rz - distances.append(math.sqrt(dx**2 + dy**2 + dz**2)) + distances.append(math.sqrt(dx ** 2 + dy ** 2 + dz ** 2)) return min(distances) \ No newline at end of file diff --git a/diceplayer/DPpack/Environment/System.py b/diceplayer/shared/environment/system.py similarity index 91% rename from diceplayer/DPpack/Environment/System.py rename to diceplayer/shared/environment/system.py index 4783938..2b1389e 100644 --- a/diceplayer/DPpack/Environment/System.py +++ b/diceplayer/shared/environment/system.py @@ -1,21 +1,13 @@ -from diceplayer.DPpack.Utils.PTable import * -from diceplayer.DPpack.Utils.Misc import * - -from diceplayer.DPpack.Environment.Molecule import ANG2BOHR, BOHR2ANG, Molecule -from diceplayer.DPpack.Environment.Atom import Atom - -from typing import IO, Final, Tuple, List, TextIO - -from numpy import linalg -import numpy as np - -from copy import deepcopy -import sys, math -import sys import math +from copy import deepcopy +from typing import List, Tuple, TextIO -BOHR2ANG: Final[float] = 0.52917721092 -ANG2BOHR: Final[float] = 1 / BOHR2ANG +import numpy as np +from numpy import linalg + +from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.utils.misc import BOHR2ANG +from diceplayer.shared.utils.ptable import atomsymb class System: @@ -46,7 +38,7 @@ class System: self.molecule.append(m) self.nmols.append(nmols) - def center_of_mass_distance(self, a: Molecule, b: Molecule) -> float: + def center_of_mass_distance(self, a: int, b: int) -> float: """ Calculates the distance between the center of mass of two molecules @@ -73,7 +65,7 @@ class System: reference_mol = self.molecule[r_index] if len(projecting_mol.atom) != len(reference_mol.atom): - sys.exit( + raise RuntimeError( "Error in RMSD fit procedure: molecules have different number of atoms" ) dim = len(projecting_mol.atom) @@ -102,7 +94,7 @@ class System: try: evals, evecs = linalg.eigh(rr) except: - sys.exit("Error: diagonalization of RR matrix did not converge") + raise RuntimeError("Error: diagonalization of RR matrix did not converge") a1 = evecs[:, 2].T a2 = evecs[:, 1].T @@ -180,7 +172,7 @@ class System: criterium = "com" if criterium != "com" and criterium != "min": - sys.exit("Error in value passed to function nearest_image") + raise RuntimeError("Error in value passed to function nearest_image") min_dist = 1e20 diff --git a/diceplayer/shared/external/__external.py b/diceplayer/shared/external/__external.py new file mode 100644 index 0000000..775ec34 --- /dev/null +++ b/diceplayer/shared/external/__external.py @@ -0,0 +1,26 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass + +from abc import ABC, abstractmethod + + +class External(ABC): + __slots__ = [ + 'config' + ] + + @abstractmethod + def __init__(self, data: dict): + pass + + @staticmethod + @abstractmethod + def set_config(data: dict) -> Dataclass: + pass + + @abstractmethod + def start(self): + pass + + @abstractmethod + def reset(self): + pass diff --git a/diceplayer/shared/external/__init__.py b/diceplayer/shared/external/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/diceplayer/shared/external/dice.py b/diceplayer/shared/external/dice.py new file mode 100644 index 0000000..676209c --- /dev/null +++ b/diceplayer/shared/external/dice.py @@ -0,0 +1,22 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass +from diceplayer.shared.external.__external import External +from diceplayer.shared.config.dice_dto import DiceDTO + + +class Dice(External): + + def __init__(self, data: dict): + self.config: DiceDTO = self.set_config(data) + + @staticmethod + def set_config(data: dict) -> DiceDTO: + return DiceDTO.from_dict(data) + + def configure(self): + pass + + def start(self): + pass + + def reset(self): + pass diff --git a/diceplayer/shared/external/gaussian.py b/diceplayer/shared/external/gaussian.py new file mode 100644 index 0000000..325cc23 --- /dev/null +++ b/diceplayer/shared/external/gaussian.py @@ -0,0 +1,23 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass +from diceplayer.shared.config.gaussian_dto import GaussianDTO +from diceplayer.shared.external.__external import External + + +class Gaussian(External): + + def __init__(self, data: dict): + self.config: GaussianDTO = self.set_config(data) + + @staticmethod + def set_config(data: dict) -> GaussianDTO: + return GaussianDTO.from_dict(data) + + def configure(self): + pass + + def start(self): + pass + + def reset(self): + pass + diff --git a/diceplayer/shared/utils/__init__.py b/diceplayer/shared/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/diceplayer/shared/utils/dataclass_protocol.py b/diceplayer/shared/utils/dataclass_protocol.py new file mode 100644 index 0000000..b3b3dbd --- /dev/null +++ b/diceplayer/shared/utils/dataclass_protocol.py @@ -0,0 +1,6 @@ +from typing import runtime_checkable, Protocol + + +@runtime_checkable +class Dataclass(Protocol): + __dataclass_fields__: dict diff --git a/diceplayer/shared/utils/misc.py b/diceplayer/shared/utils/misc.py new file mode 100644 index 0000000..9e54a1f --- /dev/null +++ b/diceplayer/shared/utils/misc.py @@ -0,0 +1,64 @@ +import gzip +import os +import shutil +import sys +import time +from typing import Final + +####################################### constants ###################################### + + +BOHR2ANG: Final[float] = 0.52917721092 +ANG2BOHR: Final[float] = 1 / BOHR2ANG + + +####################################### functions ###################################### + +def weekday_date_time(): + return time.strftime("%A, %d %b %Y at %H:%M:%S") + + +def date_time(): + return time.strftime("%d %b %Y at %H:%M:%S") + + +def compress_files_1mb(path): + working_dir = os.getcwd() + os.chdir(path) + + files = filter(os.path.isfile, os.listdir(os.curdir)) + for file in files: + if os.path.getsize(file) > 1024 * 1024: ## If bigger than 1MB + filegz = file + ".gz" + try: + with open(file, 'rb') as f_in: + with gzip.open(filegz, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + except: + sys.exit("Error: cannot compress file {}".format(file)) + + os.chdir(working_dir) + + return + + +def make_step_dir(cycle): + sim_dir = "simfiles" + step_dir = "step{:02d}".format(cycle) + path = sim_dir + os.sep + step_dir + if os.path.exists(path): + sys.exit("Error: a file or directory {} already exists".format(step_dir)) + try: + os.makedirs(path) + except: + sys.exit("Error: cannot make directory {}".format(step_dir)) + + +def make_qm_dir(cycle): + sim_dir = "simfiles" + step_dir = "step{:02d}".format(cycle) + path = sim_dir + os.sep + step_dir + os.sep + "qm" + try: + os.makedirs(path) + except: + sys.exit("Error: cannot make directory {}".format(path)) diff --git a/diceplayer/DPpack/Utils/PTable.py b/diceplayer/shared/utils/ptable.py similarity index 100% rename from diceplayer/DPpack/Utils/PTable.py rename to diceplayer/shared/utils/ptable.py diff --git a/diceplayer/DPpack/Utils/Validations.py b/diceplayer/shared/utils/validations.py similarity index 100% rename from diceplayer/DPpack/Utils/Validations.py rename to diceplayer/shared/utils/validations.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/__init__.py b/tests/shared/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/environment/__init__.py b/tests/shared/environment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/environment/atom.py b/tests/shared/environment/atom.py new file mode 100644 index 0000000..fa6de06 --- /dev/null +++ b/tests/shared/environment/atom.py @@ -0,0 +1,19 @@ +from diceplayer.shared.environment.atom import Atom + +import unittest + + +class TestAtom(unittest.TestCase): + def test_class_instantiation(self): + atom = Atom( + lbl=1, + na=1, + rx=1.0, + ry=1.0, + rz=1.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + + self.assertIsInstance(atom, Atom) \ No newline at end of file diff --git a/tests/shared/environment/molecule.py b/tests/shared/environment/molecule.py new file mode 100644 index 0000000..7928af1 --- /dev/null +++ b/tests/shared/environment/molecule.py @@ -0,0 +1,61 @@ +from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.environment.atom import Atom + +import numpy.testing as npt +import unittest + + +class TestMolecule(unittest.TestCase): + def test_class_instantiation(self): + mol = Molecule('test') + + self.assertIsInstance(mol, Molecule) + + def test_add_atom(self): + mol = Molecule('test') + + mol.add_atom( + Atom( + lbl=1, + na=1, + rx=1.0, + ry=1.0, + rz=1.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + ) + + self.assertEqual(len(mol.atom), 1) + npt.assert_equal(mol.com, [1., 1., 1.]) + + def test_center_of_mass(self): + mol = Molecule('test') + + mol.add_atom( + Atom( + lbl=1, + na=1, + rx=1.0, + ry=1.0, + rz=1.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + ) + mol.add_atom( + Atom( + lbl=1, + na=1, + rx=0.0, + ry=0.0, + rz=0.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + ) + + npt.assert_equal(mol.com, [.5, .5, .5])