From 7a872041816cf32ebbf9571c2909860dca822cda Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Tue, 8 Nov 2022 12:12:05 -0300 Subject: [PATCH 01/18] Updated Dependencies --- Pipfile | 4 + Pipfile.lock | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 Pipfile.lock diff --git a/Pipfile b/Pipfile index 26334cf..fe71db5 100644 --- a/Pipfile +++ b/Pipfile @@ -10,8 +10,12 @@ argparse = "*" pyinstaller = "*" setproctitle = "*" pyyaml = "*" +nptyping = "*" +intel-openmp = "*" +typing = "*" [dev-packages] +pyinstaller = "*" [requires] python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..b528f76 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,290 @@ +{ + "_meta": { + "hash": { + "sha256": "37db6602bae8a383e7907bd2bfb346daf1051cfb240564b5d23de92a0cdd7536" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "altgraph": { + "hashes": [ + "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd", + "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe" + ], + "version": "==0.17.3" + }, + "argparse": { + "hashes": [ + "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4", + "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314" + ], + "index": "pypi", + "version": "==1.4.0" + }, + "intel-openmp": { + "hashes": [ + "sha256:22e09934d9f8f8b864ae68cab95bf43667f00d24e4675eb6d2a4ee089754c439", + "sha256:342c9e2b6e1500a9fb8d39828293ab5f9bb310b81fad7eba5c9d865001b95a7e", + "sha256:6ae4a878135ec08aa16dd97b6d72ac16bb92fad4c6ba40f28b3558d70b1f447a", + "sha256:77414289c14cb48d7f99926da69c9ced9e70c27feb825b0608f304f9d49844ae", + "sha256:c8b95fc493e2945b259153f7b0dd34a3d849e8e1e43b6c14ac04f613b3b45433" + ], + "index": "pypi", + "version": "==2022.2.1" + }, + "nptyping": { + "hashes": [ + "sha256:23e8164b1e2c55e872f392ca7516b9b1b0cb400b03b70accaa63998b4106b0b3", + "sha256:57ba684ee5fc5eb681ee04270ee94adb879e4372ce6b640defa08ace8e1df295" + ], + "index": "pypi", + "version": "==2.4.1" + }, + "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" + ], + "index": "pypi", + "version": "==1.23.4" + }, + "pickle5": { + "hashes": [ + "sha256:7e013be68ba7dde1de5a8dbcc241f201dab1126e326715916ce4a26c27919ffc" + ], + "index": "pypi", + "version": "==0.0.11" + }, + "pyinstaller": { + "hashes": [ + "sha256:04ecf805bde2ef25b8e3642410871e6747c22fa7254107f155b8cd179c2a13b6", + "sha256:05df5d2b9ca645cc6ef61d8a85451d2aabe5501997f1f50cd94306fd6bc0485d", + "sha256:0d167d57036219914188f1400427dd297b975707e78c32a5511191e607be920a", + "sha256:181856ade585b090379ae26b7017dc2c30620e36e3a804b381417a6dc3b2a82b", + "sha256:1b1e3b37a22fb36555d917f0c3dfb998159ff4af6d8fa7cc0074d630c6fe81ad", + "sha256:32727232f446aa96e394f01b0c35b3de0dc3513c6ba3e26d1ef64c57edb1e9e5", + "sha256:77888f52b61089caa0bee70809bbce9e9b1c613c88b6cb0742ff2a45f1511cbb", + "sha256:865025b6809d777bb0f66d8f8ab50cc97dc3dbe0ff09a1ef1f2fd646432714fc", + "sha256:d888db9afedff290d362ee296d30eb339abeba707ca1565916ce1cd5947131c3", + "sha256:e026adc92c60158741d0bfca27eefaa2414801f61328cb84d0c88241fe8c2087", + "sha256:eb083c25f711769af0898852ea30dcb727ba43990bbdf9ffbaa9c77a7bd0d720" + ], + "index": "pypi", + "version": "==5.6.2" + }, + "pyinstaller-hooks-contrib": { + "hashes": [ + "sha256:91ecb30db757a8db8b6661d91d5df99e0998245f05f5cfaade0550922c7030a3", + "sha256:e06d0881e599d94dc39c6ed1917f0ad9b1858a2478b9892faac18bd48bcdc2de" + ], + "markers": "python_version >= '3.7'", + "version": "==2022.13" + }, + "pyyaml": { + "hashes": [ + "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + ], + "index": "pypi", + "version": "==6.0" + }, + "setproctitle": { + "hashes": [ + "sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b", + "sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9", + "sha256:1f0cde41857a644b7353a0060b5f94f7ba7cf593ebde5a1094da1be581ac9a31", + "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83", + "sha256:1fa1a0fbee72b47dc339c87c890d3c03a72ea65c061ade3204f285582f2da30f", + "sha256:1ff863a20d1ff6ba2c24e22436a3daa3cd80be1dfb26891aae73f61b54b04aca", + "sha256:265ecbe2c6eafe82e104f994ddd7c811520acdd0647b73f65c24f51374cf9494", + "sha256:288943dec88e178bb2fd868adf491197cc0fc8b6810416b1c6775e686bab87fe", + "sha256:2e3ac25bfc4a0f29d2409650c7532d5ddfdbf29f16f8a256fc31c47d0dc05172", + "sha256:2fbd8187948284293f43533c150cd69a0e4192c83c377da837dbcd29f6b83084", + "sha256:4058564195b975ddc3f0462375c533cce310ccdd41b80ac9aed641c296c3eff4", + "sha256:4749a2b0c9ac52f864d13cee94546606f92b981b50e46226f7f830a56a9dc8e1", + "sha256:4d8938249a7cea45ab7e1e48b77685d0f2bab1ebfa9dde23e94ab97968996a7c", + "sha256:5194b4969f82ea842a4f6af2f82cd16ebdc3f1771fb2771796e6add9835c1973", + "sha256:55ce1e9925ce1765865442ede9dca0ba9bde10593fcd570b1f0fa25d3ec6b31c", + "sha256:589be87172b238f839e19f146b9ea47c71e413e951ef0dc6db4218ddacf3c202", + "sha256:5b932c3041aa924163f4aab970c2f0e6b4d9d773f4d50326e0ea1cd69240e5c5", + "sha256:5fb4f769c02f63fac90989711a3fee83919f47ae9afd4758ced5d86596318c65", + "sha256:630f6fe5e24a619ccf970c78e084319ee8be5be253ecc9b5b216b0f474f5ef18", + "sha256:65d884e22037b23fa25b2baf1a3316602ed5c5971eb3e9d771a38c3a69ce6e13", + "sha256:6c877691b90026670e5a70adfbcc735460a9f4c274d35ec5e8a43ce3f8443005", + "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02", + "sha256:7a55fe05f15c10e8c705038777656fe45e3bd676d49ad9ac8370b75c66dd7cd7", + "sha256:7aa0aac1711fadffc1d51e9d00a3bea61f68443d6ac0241a224e4d622489d665", + "sha256:7f0bed90a216ef28b9d227d8d73e28a8c9b88c0f48a082d13ab3fa83c581488f", + "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1", + "sha256:7fe9df7aeb8c64db6c34fc3b13271a363475d77bc157d3f00275a53910cb1989", + "sha256:8ff3c8cb26afaed25e8bca7b9dd0c1e36de71f35a3a0706b5c0d5172587a3827", + "sha256:9124bedd8006b0e04d4e8a71a0945da9b67e7a4ab88fdad7b1440dc5b6122c42", + "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927", + "sha256:a149a5f7f2c5a065d4e63cb0d7a4b6d3b66e6e80f12e3f8827c4f63974cbf122", + "sha256:a47d97a75fd2d10c37410b180f67a5835cb1d8fdea2648fd7f359d4277f180b9", + "sha256:a499fff50387c1520c085a07578a000123f519e5f3eee61dd68e1d301659651f", + "sha256:ab45146c71ca6592c9cc8b354a2cc9cc4843c33efcbe1d245d7d37ce9696552d", + "sha256:b2c9cb2705fc84cb8798f1ba74194f4c080aaef19d9dae843591c09b97678e98", + "sha256:b34baef93bfb20a8ecb930e395ccd2ae3268050d8cf4fe187de5e2bd806fd796", + "sha256:b617f12c9be61e8f4b2857be4a4319754756845dbbbd9c3718f468bbb1e17bcb", + "sha256:b9fb97907c830d260fa0658ed58afd48a86b2b88aac521135c352ff7fd3477fd", + "sha256:bae283e85fc084b18ffeb92e061ff7ac5af9e183c9d1345c93e178c3e5069cbe", + "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806", + "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484", + "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e", + "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575", + "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76", + "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246", + "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb", + "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099", + "sha256:e43f315c68aa61cbdef522a2272c5a5b9b8fd03c301d3167b5e1343ef50c676c", + "sha256:e49ae693306d7624015f31cb3e82708916759d592c2e5f72a35c8f4cc8aef258", + "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865", + "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b", + "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d", + "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10", + "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f", + "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94", + "sha256:faec934cfe5fd6ac1151c02e67156c3f526e82f96b24d550b5d51efa4a5527c6", + "sha256:fcd3cf4286a60fdc95451d8d14e0389a6b4f5cebe02c7f2609325eb016535963", + "sha256:fe8a988c7220c002c45347430993830666e55bc350179d91fcee0feafe64e1d4", + "sha256:fed18e44711c5af4b681c2b3b18f85e6f0f1b2370a28854c645d636d5305ccd8", + "sha256:ffc61a388a5834a97953d6444a2888c24a05f2e333f9ed49f977a87bb1ad4761" + ], + "index": "pypi", + "version": "==1.3.2" + }, + "setuptools": { + "hashes": [ + "sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31", + "sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f" + ], + "markers": "python_version >= '3.7'", + "version": "==65.5.1" + }, + "typing": { + "hashes": [ + "sha256:1187fb9c82fd670d10aa07bbb6cfcfe4bdda42d6fab8d5134f04e8c4d0b71cc9", + "sha256:283d868f5071ab9ad873e5e52268d611e851c870a2ba354193026f2dfb29d8b5" + ], + "index": "pypi", + "version": "==3.7.4.3" + } + }, + "develop": { + "altgraph": { + "hashes": [ + "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd", + "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe" + ], + "version": "==0.17.3" + }, + "pyinstaller": { + "hashes": [ + "sha256:04ecf805bde2ef25b8e3642410871e6747c22fa7254107f155b8cd179c2a13b6", + "sha256:05df5d2b9ca645cc6ef61d8a85451d2aabe5501997f1f50cd94306fd6bc0485d", + "sha256:0d167d57036219914188f1400427dd297b975707e78c32a5511191e607be920a", + "sha256:181856ade585b090379ae26b7017dc2c30620e36e3a804b381417a6dc3b2a82b", + "sha256:1b1e3b37a22fb36555d917f0c3dfb998159ff4af6d8fa7cc0074d630c6fe81ad", + "sha256:32727232f446aa96e394f01b0c35b3de0dc3513c6ba3e26d1ef64c57edb1e9e5", + "sha256:77888f52b61089caa0bee70809bbce9e9b1c613c88b6cb0742ff2a45f1511cbb", + "sha256:865025b6809d777bb0f66d8f8ab50cc97dc3dbe0ff09a1ef1f2fd646432714fc", + "sha256:d888db9afedff290d362ee296d30eb339abeba707ca1565916ce1cd5947131c3", + "sha256:e026adc92c60158741d0bfca27eefaa2414801f61328cb84d0c88241fe8c2087", + "sha256:eb083c25f711769af0898852ea30dcb727ba43990bbdf9ffbaa9c77a7bd0d720" + ], + "index": "pypi", + "version": "==5.6.2" + }, + "pyinstaller-hooks-contrib": { + "hashes": [ + "sha256:91ecb30db757a8db8b6661d91d5df99e0998245f05f5cfaade0550922c7030a3", + "sha256:e06d0881e599d94dc39c6ed1917f0ad9b1858a2478b9892faac18bd48bcdc2de" + ], + "markers": "python_version >= '3.7'", + "version": "==2022.13" + }, + "setuptools": { + "hashes": [ + "sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31", + "sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f" + ], + "markers": "python_version >= '3.7'", + "version": "==65.5.1" + } + } +} From 71744641ffe6a1e490837383e1f7d4dbef43f427 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sat, 4 Mar 2023 16:20:25 -0300 Subject: [PATCH 02/18] 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]) From b869ee74fb8f3e80b5b371c00777509c32af2d22 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sat, 22 Apr 2023 11:27:20 -0300 Subject: [PATCH 03/18] Implements More Tests and Begins Dice Refactor Implementation --- Pipfile | 3 +- Pipfile.lock | 149 ++++++++++---- diceplayer/__main__.py | 7 +- diceplayer/shared/config/dice_dto.py | 10 +- diceplayer/shared/config/step_dto.py | 18 ++ diceplayer/shared/environment/molecule.py | 121 ++++------- diceplayer/shared/environment/system.py | 194 +++++++++--------- diceplayer/shared/external/__external.py | 2 +- diceplayer/shared/external/__init__.py | 1 + diceplayer/shared/external/dice.py | 45 +++- diceplayer/shared/external/gaussian.py | 3 +- tests/shared/config/__init__.py | 0 tests/shared/config/test_dice_dto.py | 89 ++++++++ tests/shared/environment/molecule.py | 61 ------ .../environment/{atom.py => test_atom.py} | 0 tests/shared/environment/test_molecule.py | 147 +++++++++++++ tests/shared/environment/test_system.py | 50 +++++ tests/shared/external/__init__.py | 0 tests/shared/external/test_dice.py | 116 +++++++++++ 19 files changed, 719 insertions(+), 297 deletions(-) create mode 100644 diceplayer/shared/config/step_dto.py create mode 100644 tests/shared/config/__init__.py create mode 100644 tests/shared/config/test_dice_dto.py delete mode 100644 tests/shared/environment/molecule.py rename tests/shared/environment/{atom.py => test_atom.py} (100%) create mode 100644 tests/shared/environment/test_molecule.py create mode 100644 tests/shared/environment/test_system.py create mode 100644 tests/shared/external/__init__.py create mode 100644 tests/shared/external/test_dice.py diff --git a/Pipfile b/Pipfile index ed75480..c8b8028 100644 --- a/Pipfile +++ b/Pipfile @@ -17,6 +17,7 @@ dacite = "*" [dev-packages] pyinstaller = "*" +coverage = "*" [requires] -python_version = "3.10" +python_version = ">3.8" diff --git a/Pipfile.lock b/Pipfile.lock index d61ee4f..68f88c5 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "f68e7183744102bdc470014dfc368a947097de4d482f891b1c9b31d17160fd64" + "sha256": "9af00878e9f259614f72d3c11de93c16ede78176a30d8337c741be06c048c8a8" }, "pipfile-spec": 6, "requires": { - "python_version": "3.10" + "python_version": ">3.8" }, "sources": [ { @@ -41,12 +41,14 @@ }, "intel-openmp": { "hashes": [ - "sha256:1ebce47df0b5ddad77992a70689fd3185df25f47cf901dd8384fd6d05a974f81", - "sha256:77131c2cda75ace2060f6e9cdcc9f9c672ec838c4602fc544ce0858cfe8f416e", - "sha256:adfb32b0dde6b3a95ced62608b05a45a7cfad928054136ddbfe0563e16cbf33c" + "sha256:0ca275fd223bda7b835f3b30221ee462e934468738dcbb26741c57e795f09818", + "sha256:0e3166732d0a2105988e538baaffff1182fd5a23883da255b3bf62c187475b46", + "sha256:39308882e7bcdbd17e2d2b3be96e34ed475f60205bc90cb86694d0bcfc955bbc", + "sha256:523094cd2593d31c71ce2d6b2942389fa9d231dce9f8825bfec9e2fdc545e037", + "sha256:7bd67f60ca3da7dbe39ab2a296b5322f8e8248d59d7573068deeeb9b0f901895" ], "index": "pypi", - "version": "==2023.0.0" + "version": "==2023.1.0" }, "nptyping": { "hashes": [ @@ -99,29 +101,29 @@ }, "pyinstaller": { "hashes": [ - "sha256:314fb883caf3cbf06adbea2b77671bb73c3481568e994af0467ea7e47eb64755", - "sha256:3b74f50a57b1413047042e47033480b7324b091f23dff790a4494af32b377d94", - "sha256:4f4d818588e2d8de4bf24ed018056c3de0c95898ad25719e12d68626161b4933", - "sha256:502a2166165a8e8c3d99c19272e923d2548bac2132424d78910ef9dd8bb11705", - "sha256:5c9632a20faecd6d79f0124afb31e6557414d19be271e572765b474f860f8d76", - "sha256:8d004699c5d71c704c14a5f81eec233faa4f87a3bf0ae68e222b87d63f5dd17e", - "sha256:a62ee598b137202ef2e99d8dbaee6bc7379a6565c3ddf0331decb41b98eff1a2", - "sha256:bacf236b5c2f8f674723a39daca399646dceb470881f842f52e393b9a67ff2f8", - "sha256:bf1f7b7e88b467d7aefcdb2bc9cbd2e856ca88c5ab232c0efe0848f146d3bd5f", - "sha256:ded780f0d3642d7bfc21d97b98d4ec4b41d2fe70c3f5c5d243868612f536e011", - "sha256:e68bcadf32edc1171ccb06117699a6a4f8e924b7c2c8812cfa00fd0186ade4ee", - "sha256:f9361eff44c7108c2312f39d85ed768c4ada7e0aa729046bbcef3ef3c1577d18" + "sha256:247b99c52dc3cf69eba905da30dbca0a8ea309e1058cab44658ac838d9b8f2f0", + "sha256:2d16641a495593d174504263b038a6d3d46b3b15a381ccb216cf6cce67723512", + "sha256:333b4ffda38d9c0a561c38429dd9848d37aa78f3b8ea8a6f2b2e69a60d523c02", + "sha256:6afc7aa4885ffd3e6121a8cf2138830099f874c18cb5869bed8c1a42db82d060", + "sha256:6ecc464bf56919bf2d6bff275f38d85ff08ae747b8ead3a0c26cf85573b3c723", + "sha256:7a1db833bb0302b66ae3ae337fbd5487699658ce869ca4d538b5359b8179e83a", + "sha256:85e39e36d03355423636907a26a9bfa06fdc93cb1086441b19d2d0ca448479fa", + "sha256:915a502802c751bafd92d568ac57468ec6cdf252b8308aa9a167bbc2c565ad2d", + "sha256:9e9a38f41f8280c8e29b294716992852281b41fbe64ba330ebab671efe27b26d", + "sha256:bb7de35cd209a0a0358aec761a273ae951d2161c03728f15d9a640d06a88e472", + "sha256:df97aaf1103a1c485aa3c9947792a86675e370f5ce9b436b4a84e34a4180c8d2", + "sha256:f677fbc151db1eb00ada94e86ed128e7b359cbd6bf3f6ea815afdde687692d46" ], "index": "pypi", - "version": "==5.8.0" + "version": "==5.10.1" }, "pyinstaller-hooks-contrib": { "hashes": [ - "sha256:29d052eb73e0ab8f137f11df8e73d464c1c6d4c3044d9dc8df2af44639d8bfbf", - "sha256:bd578781cd6a33ef713584bf3726f7cd60a3e656ec08a6cc7971e39990808cc0" + "sha256:7fb856a81fd06a717188a3175caa77e902035cc067b00b583c6409c62497b23f", + "sha256:e02c5f0ee3d4f5814588c2128caf5036c058ba764aaf24d957bb5311ad8690ad" ], "markers": "python_version >= '3.7'", - "version": "==2023.0" + "version": "==2023.2" }, "pyyaml": { "hashes": [ @@ -249,11 +251,11 @@ }, "setuptools": { "hashes": [ - "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330", - "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251" + "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67", + "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c" ], "markers": "python_version >= '3.7'", - "version": "==67.4.0" + "version": "==67.7.1" }, "typing": { "hashes": [ @@ -280,39 +282,96 @@ ], "version": "==0.17.3" }, - "pyinstaller": { + "coverage": { "hashes": [ - "sha256:314fb883caf3cbf06adbea2b77671bb73c3481568e994af0467ea7e47eb64755", - "sha256:3b74f50a57b1413047042e47033480b7324b091f23dff790a4494af32b377d94", - "sha256:4f4d818588e2d8de4bf24ed018056c3de0c95898ad25719e12d68626161b4933", - "sha256:502a2166165a8e8c3d99c19272e923d2548bac2132424d78910ef9dd8bb11705", - "sha256:5c9632a20faecd6d79f0124afb31e6557414d19be271e572765b474f860f8d76", - "sha256:8d004699c5d71c704c14a5f81eec233faa4f87a3bf0ae68e222b87d63f5dd17e", - "sha256:a62ee598b137202ef2e99d8dbaee6bc7379a6565c3ddf0331decb41b98eff1a2", - "sha256:bacf236b5c2f8f674723a39daca399646dceb470881f842f52e393b9a67ff2f8", - "sha256:bf1f7b7e88b467d7aefcdb2bc9cbd2e856ca88c5ab232c0efe0848f146d3bd5f", - "sha256:ded780f0d3642d7bfc21d97b98d4ec4b41d2fe70c3f5c5d243868612f536e011", - "sha256:e68bcadf32edc1171ccb06117699a6a4f8e924b7c2c8812cfa00fd0186ade4ee", - "sha256:f9361eff44c7108c2312f39d85ed768c4ada7e0aa729046bbcef3ef3c1577d18" + "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93", + "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013", + "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f", + "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21", + "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462", + "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc", + "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df", + "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1", + "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235", + "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934", + "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9", + "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1", + "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48", + "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4", + "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe", + "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a", + "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b", + "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21", + "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d", + "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa", + "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367", + "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535", + "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152", + "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e", + "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539", + "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1", + "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925", + "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0", + "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2", + "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab", + "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841", + "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30", + "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91", + "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c", + "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257", + "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9", + "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040", + "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911", + "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623", + "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259", + "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c", + "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79", + "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5", + "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4", + "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4", + "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22", + "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd", + "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1", + "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910", + "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859", + "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312" ], "index": "pypi", - "version": "==5.8.0" + "version": "==7.2.3" + }, + "pyinstaller": { + "hashes": [ + "sha256:247b99c52dc3cf69eba905da30dbca0a8ea309e1058cab44658ac838d9b8f2f0", + "sha256:2d16641a495593d174504263b038a6d3d46b3b15a381ccb216cf6cce67723512", + "sha256:333b4ffda38d9c0a561c38429dd9848d37aa78f3b8ea8a6f2b2e69a60d523c02", + "sha256:6afc7aa4885ffd3e6121a8cf2138830099f874c18cb5869bed8c1a42db82d060", + "sha256:6ecc464bf56919bf2d6bff275f38d85ff08ae747b8ead3a0c26cf85573b3c723", + "sha256:7a1db833bb0302b66ae3ae337fbd5487699658ce869ca4d538b5359b8179e83a", + "sha256:85e39e36d03355423636907a26a9bfa06fdc93cb1086441b19d2d0ca448479fa", + "sha256:915a502802c751bafd92d568ac57468ec6cdf252b8308aa9a167bbc2c565ad2d", + "sha256:9e9a38f41f8280c8e29b294716992852281b41fbe64ba330ebab671efe27b26d", + "sha256:bb7de35cd209a0a0358aec761a273ae951d2161c03728f15d9a640d06a88e472", + "sha256:df97aaf1103a1c485aa3c9947792a86675e370f5ce9b436b4a84e34a4180c8d2", + "sha256:f677fbc151db1eb00ada94e86ed128e7b359cbd6bf3f6ea815afdde687692d46" + ], + "index": "pypi", + "version": "==5.10.1" }, "pyinstaller-hooks-contrib": { "hashes": [ - "sha256:29d052eb73e0ab8f137f11df8e73d464c1c6d4c3044d9dc8df2af44639d8bfbf", - "sha256:bd578781cd6a33ef713584bf3726f7cd60a3e656ec08a6cc7971e39990808cc0" + "sha256:7fb856a81fd06a717188a3175caa77e902035cc067b00b583c6409c62497b23f", + "sha256:e02c5f0ee3d4f5814588c2128caf5036c058ba764aaf24d957bb5311ad8690ad" ], "markers": "python_version >= '3.7'", - "version": "==2023.0" + "version": "==2023.2" }, "setuptools": { "hashes": [ - "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330", - "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251" + "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67", + "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c" ], "markers": "python_version >= '3.7'", - "version": "==67.4.0" + "version": "==67.7.1" } } } diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index c461bb8..c4dd5db 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -1,3 +1,4 @@ +from diceplayer.shared.external.dice import Dice from diceplayer.player import Player from pathlib import Path @@ -9,7 +10,8 @@ import sys __VERSION = "v0.0.1" -if __name__ == "__main__": + +def main(): """ Read and store the arguments passed to the program and set the usage and help messages @@ -63,3 +65,6 @@ if __name__ == "__main__": player = Player(args.infile) player.start() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/diceplayer/shared/config/dice_dto.py b/diceplayer/shared/config/dice_dto.py index 832e290..935665f 100644 --- a/diceplayer/shared/config/dice_dto.py +++ b/diceplayer/shared/config/dice_dto.py @@ -24,27 +24,27 @@ class DiceDTO(Dataclass): def __post_init__(self): - if self.ljname is None: + if not isinstance(self.ljname, str): raise ValueError( "Error: 'ljname' keyword not specified in config file" ) - if self.outname is None: + if not isinstance(self.outname, str): raise ValueError( "Error: 'outname' keyword not specified in config file" ) - if self.dens is None: + if not isinstance(self.dens, float): raise ValueError( "Error: 'dens' keyword not specified in config file" ) - if self.nmol == 0: + if not isinstance(self.nmol, list): raise ValueError( "Error: 'nmol' keyword not defined appropriately in config file" ) - if self.nstep == 0: + if not isinstance(self.nstep, list): raise ValueError( "Error: 'nstep' keyword not defined appropriately in config file" ) diff --git a/diceplayer/shared/config/step_dto.py b/diceplayer/shared/config/step_dto.py new file mode 100644 index 0000000..2a1145f --- /dev/null +++ b/diceplayer/shared/config/step_dto.py @@ -0,0 +1,18 @@ +from diceplayer.shared.environment.molecule import Molecule + +from dataclasses import dataclass +from typing import List + + +@dataclass +class StepDTO: + 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/shared/environment/molecule.py b/diceplayer/shared/environment/molecule.py index 8e88d41..390f3fc 100644 --- a/diceplayer/shared/environment/molecule.py +++ b/diceplayer/shared/environment/molecule.py @@ -79,14 +79,13 @@ class Molecule: """ Updated positions based on the center of mass of the 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] + self.center_of_mass() + def charges_and_dipole(self) -> List[float]: """ Calculates the charges and dipole of the molecule atoms @@ -119,16 +118,15 @@ class Molecule: distances = [] dim = len(self.atom) - for atom1 in self.atom: - if atom1.na != ghost_number: - for atom2 in self.atom: - if atom2.na != ghost_number: - 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)) + for index1, atom1 in enumerate(self.atom): + for index2, atom2 in enumerate(self.atom): + if index1 != index2: + 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)) - return np.array(distances).reshape(dim, dim) + return np.array(distances).reshape(dim, dim-1) def inertia_tensor(self) -> NDArray[Shape["3, 3"], Float]: """ @@ -156,40 +154,6 @@ class Molecule: return np.array([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]]) - def axes(self) -> NDArray[Shape["3, 3"], Float]: - """ - Calculates the axes of the molecule - - Returns: - NDArray[Shape["3, 3"], Float]: Returns the axes of molecule - """ - - eixos = np.zeros(3) - if len(self.atom) == 2: - - position1 = np.array([self.atom[0].rx, self.atom[0].ry, self.atom[0].rz]) - position2 = np.array([self.atom[1].rx, self.atom[1].ry, self.atom[1].rz]) - eixos = position2 - position1 - eixos /= linalg.norm(eixos) - - elif len(self.atom) > 2: - - position1 = np.array([self.atom[0].rx, self.atom[0].ry, self.atom[0].rz]) - position2 = np.array([self.atom[1].rx, self.atom[1].ry, self.atom[1].rz]) - position3 = np.array([self.atom[2].rx, self.atom[2].ry, self.atom[2].rz]) - v1 = position2 - position1 - v2 = position3 - position1 - v3 = np.cross(v1, v2) - v2 = np.cross(v1, v3) - v1 /= linalg.norm(v1) - v2 /= linalg.norm(v2) - v3 /= linalg.norm(v3) - eixos = np.array( - [[v1[0], v1[1], v1[2]], [v2[0], v2[1], v2[2]], [v3[0], v3[1], v3[2]]] - ) - - return eixos - def principal_axes(self) -> Tuple[np.ndarray, np.ndarray]: """ Calculates the principal axes of the molecule @@ -201,7 +165,7 @@ class Molecule: try: evals, evecs = linalg.eigh(self.inertia_tensor()) - except: + except ValueError: raise RuntimeError("Error: diagonalization of inertia tensor did not converge") return evals, evecs @@ -221,38 +185,38 @@ class Molecule: return position - def updateCharges(self, charges: List[float]) -> None: + def update_charges(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, - ) -> np.ndarray: - """ - Updates the Hessian of the molecule based on the current hessian, the current gradient and the previous gradient - - Args: - step (np.ndarray): step value of the iteration - cur_gradient (np.ndarray): current gradient - old_gradient (np.ndarray): previous gradient - hessian (np.ndarray): current hessian - - Returns: - np.ndarray: updated hessian of the molecule - """ - - dif_gradient = cur_gradient - old_gradient - - mat1 = 1 / np.dot(dif_gradient, step) * np.matmul(dif_gradient.T, dif_gradient) - mat2 = 1 / np.dot(step, np.matmul(hessian, step.T).T) - mat2 *= np.matmul(np.matmul(hessian, step.T), np.matmul(step, hessian)) - - return hessian + mat1 - mat2 + # @staticmethod + # def update_hessian( + # 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 + # + # Args: + # step (np.ndarray): step value of the iteration + # cur_gradient (np.ndarray): current gradient + # old_gradient (np.ndarray): previous gradient + # hessian (np.ndarray): current hessian + # + # Returns: + # np.ndarray: updated hessian of the molecule + # """ + # + # dif_gradient = cur_gradient - old_gradient + # + # mat1 = 1 / np.dot(dif_gradient, step) * np.matmul(dif_gradient.T, dif_gradient) + # mat2 = 1 / np.dot(step, np.matmul(hessian, step.T).T) + # mat2 *= np.matmul(np.matmul(hessian, step.T), np.matmul(step, hessian)) + # + # return hessian + mat1 - mat2 def sizes_of_molecule(self) -> List[float]: """ @@ -267,10 +231,9 @@ class Molecule: z_list = [] for atom in self.atom: - if atom.na != ghost_number: - x_list.append(atom.rx) - y_list.append(atom.ry) - z_list.append(atom.rz) + x_list.append(atom.rx) + y_list.append(atom.ry) + z_list.append(atom.rz) x_max = max(x_list) x_min = min(x_list) diff --git a/diceplayer/shared/environment/system.py b/diceplayer/shared/environment/system.py index 2b1389e..b34449b 100644 --- a/diceplayer/shared/environment/system.py +++ b/diceplayer/shared/environment/system.py @@ -1,64 +1,47 @@ -import math -from copy import deepcopy -from typing import List, Tuple, TextIO - -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 +from diceplayer.shared.utils.misc import BOHR2ANG + +from typing import List, Tuple, TextIO +from copy import deepcopy +from numpy import linalg +import numpy as np +import math class System: """ - System class declaration. This class is used throughout the DicePlayer program to represent the system containing the molecules. + System class declaration. This class is used throughout the DicePlayer program to represent the system containing the molecules. - Atributes: - molecule (List[Molecule]): List of molecules of the system - nmols (List[int]): List of number of molecules in the system - """ + Atributes: + molecule (List[Molecule]): List of molecules of the system + nmols (List[int]): List of number of molecules in the system + """ def __init__(self) -> None: """ - Initializes a empty system object that will be populated afterwards - """ + Initializes a empty system object that will be populated afterwards + """ self.molecule: List[Molecule] = [] self.nmols: List[int] = [] def add_type(self, nmols: int, m: Molecule) -> None: """ - Adds a new molecule type to the system + Adds a new molecule type to the system - Args: - nmols (int): Number of molecules of the new type in the system - m (Molecule): The instance of the new type of molecule - """ + Args: + nmols (int): Number of molecules of the new type in the system + m (Molecule): The instance of the new type of molecule + """ + if isinstance(m, Molecule) is False: + raise TypeError("Error: molecule is not a Molecule instance") self.molecule.append(m) + + if isinstance(nmols, int) is False: + raise TypeError("Error: nmols is not an integer") self.nmols.append(nmols) - def center_of_mass_distance(self, a: int, b: int) -> float: - """ - Calculates the distance between the center of mass of two molecules - - Args: - a (Molecule): First Molecule Instance - b (Molecule): Second Molecule Instance - - Returns: - float: module of the distance between the two center of masses - """ - - com1 = self.molecule[a].center_of_mass() - com2 = self.molecule[b].center_of_mass() - dx = com1[0] - com2[0] - dy = com1[1] - com2[1] - dz = com1[2] - com2[2] - distance = math.sqrt(dx**2 + dy**2 + dz**2) - - return distance - def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]: projecting_mol = self.molecule[p_index] @@ -118,9 +101,9 @@ class System: rmsd = 0 for i in range(dim): rmsd += ( - (x[i, 0] - y[i, 0]) ** 2 - + (x[i, 1] - y[i, 1]) ** 2 - + (x[i, 2] - y[i, 2]) ** 2 + (x[i, 0] - y[i, 0]) ** 2 + + (x[i, 1] - y[i, 1]) ** 2 + + (x[i, 2] - y[i, 2]) ** 2 ) rmsd = math.sqrt(rmsd / dim) @@ -135,13 +118,71 @@ class System: return rmsd, projected_mol + # def center_of_mass_distance(self, a: int, b: int) -> float: + # """ + # Calculates the distance between the center of mass of two molecules + # + # Args: + # a (Molecule): First Molecule Instance + # b (Molecule): Second Molecule Instance + # + # Returns: + # float: module of the distance between the two center of masses + # """ + # + # com1 = self.molecule[a].center_of_mass() + # com2 = self.molecule[b].center_of_mass() + # dx = com1[0] - com2[0] + # dy = com1[1] - com2[1] + # dz = com1[2] - com2[2] + # distance = math.sqrt(dx**2 + dy**2 + dz**2) + # + # return distance + + # def nearest_image( + # self, + # index_r: int, + # index_m: int, + # lx: float, + # ly: float, + # lz: float, + # criterium=None, + # ) -> Tuple[float, Molecule]: + # + # if criterium in None: + # criterium = "com" + # + # if criterium != "com" and criterium != "min": + # raise RuntimeError("Error in value passed to function nearest_image") + # + # min_dist = 1e20 + # + # for i in range(-1, 2): + # for j in range(-1, 2): + # for k in range(-1, 2): + # + # tr_vector = [i * lx, j * ly, k * lz] + # self.add_molecule(self.molecule[index_m].translate(tr_vector)) + # + # if criterium == "com": + # dist = self.center_of_mass_distance(index_r, -1) + # else: + # dist = self.minimum_distance(index_r, -1) + # + # if dist < min_dist: + # min_dist = dist + # nearestmol = deepcopy(self.molecule[-1]) + # + # self.molecule.pop(-1) + # + # return min_dist, nearestmol def update_molecule(self, position: np.ndarray, fh: TextIO) -> None: """Updates the position of the molecule in the Output file - Args: - position (np.ndarray): numpy position vector - fh (TextIO): Output file - """ + Args: + position (np.ndarray): numpy position vector + fh (TextIO): Output file + """ position_in_ang = (position * BOHR2ANG).tolist() self.add_type(self.nmols[0], deepcopy(self.molecule[0])) @@ -158,52 +199,15 @@ class System: fh.write("\nProjected new conformation of reference molecule with RMSD fit\n") fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd)) - def nearest_image( - self, - index_r: int, - index_m: int, - lx: float, - ly: float, - lz: float, - criterium=None, - ) -> Tuple[float, Molecule]: - - if criterium in None: - criterium = "com" - - if criterium != "com" and criterium != "min": - raise RuntimeError("Error in value passed to function nearest_image") - - min_dist = 1e20 - - for i in range(-1, 2): - for j in range(-1, 2): - for k in range(-1, 2): - - tr_vector = [i * lx, j * ly, k * lz] - self.add_molecule(self.molecule[index_m].translate(tr_vector)) - - if criterium == "com": - dist = self.center_of_mass_distance(index_r, -1) - else: - dist = self.minimum_distance(index_r, -1) - - if dist < min_dist: - min_dist = dist - nearestmol = deepcopy(self.molecule[-1]) - - self.molecule.pop(-1) - - return min_dist, nearestmol def print_geom(self, cycle: int, fh: TextIO) -> None: """ - Print the geometry of the molecule in the Output file + Print the geometry of the molecule in the Output file - Args: - cycle (int): Number of the cycle - fh (TextIO): Output file - """ + Args: + cycle (int): Number of the cycle + fh (TextIO): Output file + """ fh.write("Cycle # {}\n".format(cycle)) fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) @@ -217,12 +221,12 @@ class System: def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None: """ - Print the charges and dipole of the molecule in the Output file + Print the charges and dipole of the molecule in the Output file - Args: - cycle (int): Number of the cycle - fh (TextIO): Output file - """ + Args: + cycle (int): Number of the cycle + fh (TextIO): Output file + """ fh.write("Cycle # {}\n".format(cycle)) fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) diff --git a/diceplayer/shared/external/__external.py b/diceplayer/shared/external/__external.py index 775ec34..030d4bf 100644 --- a/diceplayer/shared/external/__external.py +++ b/diceplayer/shared/external/__external.py @@ -18,7 +18,7 @@ class External(ABC): pass @abstractmethod - def start(self): + def start(self, cycle: int): pass @abstractmethod diff --git a/diceplayer/shared/external/__init__.py b/diceplayer/shared/external/__init__.py index e69de29..25c400b 100644 --- a/diceplayer/shared/external/__init__.py +++ b/diceplayer/shared/external/__init__.py @@ -0,0 +1 @@ +from .__external import External diff --git a/diceplayer/shared/external/dice.py b/diceplayer/shared/external/dice.py index 676209c..464d6eb 100644 --- a/diceplayer/shared/external/dice.py +++ b/diceplayer/shared/external/dice.py @@ -1,9 +1,13 @@ -from diceplayer.shared.utils.dataclass_protocol import Dataclass -from diceplayer.shared.external.__external import External from diceplayer.shared.config.dice_dto import DiceDTO +from diceplayer.shared.external import External + +from multiprocessing import Process, connection +from setproctitle import setproctitle +import sys class Dice(External): + __slots__ = ['config', 'step'] def __init__(self, data: dict): self.config: DiceDTO = self.set_config(data) @@ -12,11 +16,38 @@ class Dice(External): def set_config(data: dict) -> DiceDTO: return DiceDTO.from_dict(data) - def configure(self): - pass + def configure(self, step: any): + self.step = step - def start(self): - pass + def start(self, cycle: int): + procs = [ + Process(target=self._simulation_process, args=(cycle, proc)) + for proc in range(1, self.config.ncores+1) + ] + + for proc in procs: + proc.start() + + connection.wait(p.sentinel for p in procs) def reset(self): - pass + del self.step + + def _simulation_process(self, cycle: int, proc: int): + setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}") + + try: + self._make_proc_dir(cycle, proc) + self._make_dice_inputs(cycle, proc) + self._run_dice(cycle, proc) + except Exception as err: + sys.exit(err) + + def _make_proc_dir(self, cycle, proc): + raise NotImplementedError + + def _make_dice_inputs(self, cycle, proc): + raise NotImplementedError + + def _run_dice(self, cycle, proc): + raise NotImplementedError diff --git a/diceplayer/shared/external/gaussian.py b/diceplayer/shared/external/gaussian.py index 325cc23..c96ebd4 100644 --- a/diceplayer/shared/external/gaussian.py +++ b/diceplayer/shared/external/gaussian.py @@ -1,6 +1,5 @@ -from diceplayer.shared.utils.dataclass_protocol import Dataclass from diceplayer.shared.config.gaussian_dto import GaussianDTO -from diceplayer.shared.external.__external import External +from diceplayer.shared.external import External class Gaussian(External): diff --git a/tests/shared/config/__init__.py b/tests/shared/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/config/test_dice_dto.py b/tests/shared/config/test_dice_dto.py new file mode 100644 index 0000000..cd6a8c5 --- /dev/null +++ b/tests/shared/config/test_dice_dto.py @@ -0,0 +1,89 @@ +from diceplayer.shared.config.dice_dto import DiceDTO + +import unittest + + +class TestDiceDto(unittest.TestCase): + def test_class_instantiation(self): + dice_dto = DiceDTO( + ljname='test', + outname='test', + ncores=1, + dens=1.0, + nmol=[1], + nstep=[1], + ) + + self.assertIsInstance(dice_dto, DiceDTO) + + def test_validate_jname(self): + with self.assertRaises(ValueError) as ex: + DiceDTO( + ljname=None, + outname='test', + ncores=1, + dens=1.0, + nmol=[1], + nstep=[1], + ) + self.assertEqual(ex.exception, "Error: 'ljname' keyword not specified in config file") + + def test_validate_outname(self): + with self.assertRaises(ValueError) as ex: + DiceDTO( + ljname='test', + outname=None, + ncores=1, + dens=1.0, + nmol=[1], + nstep=[1], + ) + self.assertEqual(ex.exception, "Error: 'outname' keyword not specified in config file") + + def test_validate_dens(self): + with self.assertRaises(ValueError) as ex: + DiceDTO( + ljname='test', + outname='test', + ncores=1, + dens=None, + nmol=[1], + nstep=[1], + ) + self.assertEqual(ex.exception, "Error: 'dens' keyword not specified in config file") + + def test_validate_nmol(self): + with self.assertRaises(ValueError) as ex: + DiceDTO( + ljname='test', + outname='test', + ncores=1, + dens=1.0, + nmol=0, + nstep=[1], + ) + self.assertEqual(ex.exception, "Error: 'nmol' keyword not defined appropriately in config file") + + def test_validate_nstep(self): + with self.assertRaises(ValueError) as ex: + DiceDTO( + ljname='test', + outname='test', + ncores=1, + dens=1.0, + nmol=[1], + nstep=0, + ) + self.assertEqual(ex.exception, "Error: 'nstep' keyword not defined appropriately in config file") + + def test_from_dict(self): + dice_dto = DiceDTO.from_dict({ + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + }) + + self.assertIsInstance(dice_dto, DiceDTO) \ No newline at end of file diff --git a/tests/shared/environment/molecule.py b/tests/shared/environment/molecule.py deleted file mode 100644 index 7928af1..0000000 --- a/tests/shared/environment/molecule.py +++ /dev/null @@ -1,61 +0,0 @@ -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]) diff --git a/tests/shared/environment/atom.py b/tests/shared/environment/test_atom.py similarity index 100% rename from tests/shared/environment/atom.py rename to tests/shared/environment/test_atom.py diff --git a/tests/shared/environment/test_molecule.py b/tests/shared/environment/test_molecule.py new file mode 100644 index 0000000..1eb8c2e --- /dev/null +++ b/tests/shared/environment/test_molecule.py @@ -0,0 +1,147 @@ +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]) + + def test_center_of_mass_to_origin(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.center_of_mass_to_origin() + + npt.assert_equal(mol.com, [0, 0, 0]) + + def test_charges_and_dipole(self): + mol = Molecule('test') + + 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) + ) + + actual_charge_dipole_array = mol.charges_and_dipole() + + expected_charge_dipole_array = [1.0, 0.0, 0.0, 0.0, 0.0] + + npt.assert_equal( + actual_charge_dipole_array, + expected_charge_dipole_array + ) + + def test_distances_between_atoms(self): + mol = Molecule('test') + + 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) + ) + 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) + ) + + expected_distance_between_atoms = [[1.73205081], [1.73205081]] + actual_distance_between_atoms = mol.distances_between_atoms() + + npt.assert_almost_equal( + expected_distance_between_atoms, + actual_distance_between_atoms + ) + + def test_inertia_tensor(self): + mol = Molecule('test') + + 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) + ) + 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) + ) + + expected_inertia_tensor = [[1.00790, -0.50395, -0.50395], + [-0.50395, 1.0079, -0.50395], + [-0.50395, -0.50395, 1.0079]] + + actual_inertia_tensor = mol.inertia_tensor() + + npt.assert_equal( + expected_inertia_tensor, + actual_inertia_tensor + ) + + def test_principal_axes(self): + mol = Molecule('test') + + 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) + ) + + expected_evals, expected_evecs = [0., 0., 0.], [[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]] + + evals, evecs = mol.principal_axes() + + npt.assert_equal(expected_evals, evals) + npt.assert_equal(expected_evecs, evecs) + + def test_read_position(self): + mol = Molecule('test') + + 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) + ) + + expected_position = mol.read_position() + + actual_position = mol.read_position() + + npt.assert_equal( + expected_position, + actual_position + ) + + def test_update_charges(self): + mol = Molecule('test') + + 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) + ) + + expected_charges = [2.] + mol.update_charges(expected_charges) + + actual_charges = list(map(lambda a: a.chg, mol.atom)) + + npt.assert_equal( + expected_charges, + actual_charges + ) \ No newline at end of file diff --git a/tests/shared/environment/test_system.py b/tests/shared/environment/test_system.py new file mode 100644 index 0000000..cab9cbe --- /dev/null +++ b/tests/shared/environment/test_system.py @@ -0,0 +1,50 @@ +from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.environment.system import System + +import unittest + + +class TestSystem(unittest.TestCase): + def test_class_instantiation(self): + system = System() + + self.assertIsInstance(system, System) + + def test_add_type(self): + system = System() + system.add_type(0, Molecule('test')) + + self.assertIsInstance(system.molecule, list) + self.assertIsInstance(system.nmols, list) + + with self.assertRaises(TypeError) as ex: + system.add_type(0, 'test') + self.assertEqual(ex.exception, 'Error: molecule is not a Molecule instance') + + with self.assertRaises(TypeError) as ex: + system.add_type('test', Molecule('test')) + self.assertEqual(ex.exception, 'Error: nmols is not an integer') + + def test_center_of_mass_distance(self): + system = System() + + a = Molecule('test') + a.add_atom( + Atom(lbl=0, na=1, rx=0, ry=0, rz=0, chg=0, eps=0, sig=0) + ) + system.add_type(1, a) + + b = Molecule('test') + b.add_atom( + Atom(lbl=0, na=1, rx=0, ry=0, rz=0, chg=0, eps=0, sig=0) + ) + system.add_type(1, b) + + self.assertIsInstance(system.center_of_mass_distance(0, 1), float) + + + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/shared/external/__init__.py b/tests/shared/external/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/external/test_dice.py b/tests/shared/external/test_dice.py new file mode 100644 index 0000000..8c51f95 --- /dev/null +++ b/tests/shared/external/test_dice.py @@ -0,0 +1,116 @@ +from diceplayer.shared.external.dice import Dice + +from unittest import mock +import unittest + + +class TestDice(unittest.TestCase): + def test_class_instantiation(self): + dice = Dice( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + } + ) + + self.assertIsInstance(dice, Dice) + + def test_configure(self): + dice = Dice( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + } + ) + + self.assertFalse(hasattr(dice, 'step')) + + dice.configure('test') + + self.assertTrue(hasattr(dice, 'step')) + + def test_reset(self): + dice = Dice( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + } + ) + + dice.configure('test') + + self.assertTrue(hasattr(dice, 'step')) + + dice.reset() + + self.assertFalse(hasattr(dice, 'step')) + + @mock.patch('diceplayer.shared.external.dice.connection') + @mock.patch('diceplayer.shared.external.dice.Process') + def test_start(self, mock_process, mock_connection): + dice = Dice( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + } + ) + dice.start(1) + + self.assertTrue(mock_process.called) + self.assertTrue(mock_connection.wait.called) + + def test_simulation_process_raises_exception(self): + dice = Dice( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + } + ) + + with self.assertRaises(SystemExit): + dice._simulation_process(1, 1) + + @mock.patch('diceplayer.shared.external.dice.Dice._make_proc_dir') + @mock.patch('diceplayer.shared.external.dice.Dice._make_dice_inputs') + @mock.patch('diceplayer.shared.external.dice.Dice._run_dice') + def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir): + dice = Dice( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1], + } + ) + + dice._simulation_process(1, 1) + + self.assertTrue(dice._make_proc_dir.called) + self.assertTrue(dice._make_dice_inputs.called) + self.assertTrue(dice._run_dice.called) + + +if __name__ == '__main__': + unittest.main() From 92023318520f92d3e05484ef990fe391dea8168c Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Mon, 24 Apr 2023 12:15:51 -0300 Subject: [PATCH 04/18] Finishes DiceInterface Refactoring and Continues Tests Implementation --- control.example.yml | 9 +- diceplayer/__main__.py | 8 +- diceplayer/player.py | 31 +- diceplayer/shared/config/dice_dto.py | 8 +- diceplayer/shared/config/gaussian_dto.py | 3 + diceplayer/shared/config/player_dto.py | 4 + diceplayer/shared/config/step_dto.py | 18 +- diceplayer/shared/external/__init__.py | 1 - diceplayer/shared/external/dice.py | 53 --- diceplayer/shared/interface/__init__.py | 1 + .../__interface.py} | 2 +- diceplayer/shared/interface/dice_interface.py | 388 ++++++++++++++++++ .../gaussian_interface.py} | 4 +- setup.py | 62 --- tests/shared/config/test_dice_dto.py | 19 +- tests/shared/config/test_gaussian_dto.py | 45 ++ tests/shared/config/test_player_dto.py | 28 ++ tests/shared/environment/test_system.py | 19 - tests/shared/external/test_dice.py | 116 +++++- 19 files changed, 629 insertions(+), 190 deletions(-) delete mode 100644 diceplayer/shared/external/__init__.py delete mode 100644 diceplayer/shared/external/dice.py create mode 100644 diceplayer/shared/interface/__init__.py rename diceplayer/shared/{external/__external.py => interface/__interface.py} (95%) create mode 100644 diceplayer/shared/interface/dice_interface.py rename diceplayer/shared/{external/gaussian.py => interface/gaussian_interface.py} (81%) delete mode 100755 setup.py create mode 100644 tests/shared/config/test_gaussian_dto.py create mode 100644 tests/shared/config/test_player_dto.py diff --git a/control.example.yml b/control.example.yml index cd02ce9..99f5ae4 100644 --- a/control.example.yml +++ b/control.example.yml @@ -1,21 +1,22 @@ diceplayer: maxcyc: 3 opt: no + ncores: 4 nprocs: 4 qmprog: 'g16' lps: no ghosts: no - altsteps: 20000 + altsteps: 20000 dice: - ncores: 3 nmol: [1, 50] dens: 0.75 - nstep: [2000, 3000] + nstep: [2000, 3000, 4000] isave: 1000 outname: 'phb' + progname: '~/.local/bin/dice' ljname: 'phb.ljc' - randominit: 'always' + randominit: 'first' gaussian: qmprog: 'g16' diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index c4dd5db..12fa4c3 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -1,4 +1,4 @@ -from diceplayer.shared.external.dice import Dice +from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.player import Player from pathlib import Path @@ -7,7 +7,6 @@ import logging import pickle import sys - __VERSION = "v0.0.1" @@ -51,7 +50,7 @@ def main(): output_path = Path(args.outfile) if output_path.exists(): - output_path.rename(str(output_path)+".backup") + output_path.rename(str(output_path) + ".backup") except Exception as err: sys.exit(err) @@ -66,5 +65,6 @@ def main(): player.start() + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/diceplayer/player.py b/diceplayer/player.py index 9d196bb..4229e08 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,3 +1,4 @@ +from diceplayer.shared.config.step_dto import StepDTO from diceplayer.shared.environment.atom import Atom from diceplayer.shared.utils.dataclass_protocol import Dataclass from diceplayer.shared.config.gaussian_dto import GaussianDTO @@ -5,9 +6,9 @@ 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.interface.gaussian_interface import GaussianInterface from diceplayer.shared.config.dice_dto import DiceDTO -from diceplayer.shared.external.dice import Dice +from diceplayer.shared.interface.dice_interface import DiceInterface from dataclasses import fields from pathlib import Path @@ -39,8 +40,8 @@ class Player: config_data.get("diceplayer") ) - self.gaussian = Gaussian(config_data.get("gaussian")) - self.dice = Dice(config_data.get("dice")) + self.gaussian = GaussianInterface(config_data.get("gaussian")) + self.dice = DiceInterface(config_data.get("dice")) def start(self): self.print_keywords() @@ -50,6 +51,9 @@ class Player: self.read_potentials() # self.print_potentials() + self.dice_start(1) + self.dice_start(2) + def create_simulation_dir(self): simulation_dir_path = Path(self.config.simulation_dir) if simulation_dir_path.exists(): @@ -140,7 +144,7 @@ class Player: self.dice.config.ljname ) ) - self.dice.combrule = combrule + self.dice.config.combrule = combrule ntypes = ljdata.pop(0).split()[0] if not ntypes.isdigit(): @@ -184,8 +188,21 @@ class Player: Atom(**self.validate_atom_dict(i, j, new_atom)) ) - def dice_start(self): - self.dice.start() + def dice_start(self, cycle: int): + self.dice.configure( + StepDTO( + ncores=self.config.ncores, + nprocs=self.config.nprocs, + simulation_dir=self.config.simulation_dir, + altsteps=self.config.altsteps, + molecule=self.system.molecule, + nmol=self.system.nmols, + ) + ) + + self.dice.start(cycle) + + self.dice.reset() def gaussian_start(self): self.gaussian.start() diff --git a/diceplayer/shared/config/dice_dto.py b/diceplayer/shared/config/dice_dto.py index 935665f..07feab0 100644 --- a/diceplayer/shared/config/dice_dto.py +++ b/diceplayer/shared/config/dice_dto.py @@ -7,10 +7,11 @@ from typing import List @dataclass class DiceDTO(Dataclass): - + """ + Data Transfer Object for the Dice configuration. + """ ljname: str outname: str - ncores: int dens: float nmol: List[int] nstep: List[int] @@ -20,6 +21,7 @@ class DiceDTO(Dataclass): isave: int = 1000 press: float = 1.0 temp: float = 300.0 + progname: str = "dice" randominit: str = 'first' def __post_init__(self): @@ -44,7 +46,7 @@ class DiceDTO(Dataclass): "Error: 'nmol' keyword not defined appropriately in config file" ) - if not isinstance(self.nstep, list): + if not isinstance(self.nstep, list) or len(self.nstep) not in (2, 3): raise ValueError( "Error: 'nstep' keyword not defined appropriately in config file" ) diff --git a/diceplayer/shared/config/gaussian_dto.py b/diceplayer/shared/config/gaussian_dto.py index 6e609a6..7ede18f 100644 --- a/diceplayer/shared/config/gaussian_dto.py +++ b/diceplayer/shared/config/gaussian_dto.py @@ -6,6 +6,9 @@ from dacite import from_dict @dataclass class GaussianDTO(Dataclass): + """ + Data Transfer Object for the Gaussian configuration. + """ level: str qmprog: str keywords: str diff --git a/diceplayer/shared/config/player_dto.py b/diceplayer/shared/config/player_dto.py index be9f25a..e4fa7bf 100644 --- a/diceplayer/shared/config/player_dto.py +++ b/diceplayer/shared/config/player_dto.py @@ -6,9 +6,13 @@ from dacite import from_dict @dataclass class PlayerDTO(Dataclass): + """ + Data Transfer Object for the player configuration. + """ opt: bool maxcyc: int nprocs: int + ncores: int qmprog: str = 'g16' altsteps: int = 20000 diff --git a/diceplayer/shared/config/step_dto.py b/diceplayer/shared/config/step_dto.py index 2a1145f..32ab6d9 100644 --- a/diceplayer/shared/config/step_dto.py +++ b/diceplayer/shared/config/step_dto.py @@ -1,4 +1,5 @@ from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.config.player_dto import PlayerDTO from dataclasses import dataclass from typing import List @@ -6,13 +7,16 @@ from typing import List @dataclass class StepDTO: - nprocs: int = None - ncores: int = None - altsteps: int = None - switchcyc: int = None - opt: str = None + """ + Data Transfer Object for the step configuration. + """ + ncores: int + nprocs: int + simulation_dir: str + + altsteps: int + nmol: List[int] = None molecule: List[Molecule] = None - charges: List[float] = None - position: List[float] = None \ No newline at end of file + position: List[float] = None diff --git a/diceplayer/shared/external/__init__.py b/diceplayer/shared/external/__init__.py deleted file mode 100644 index 25c400b..0000000 --- a/diceplayer/shared/external/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .__external import External diff --git a/diceplayer/shared/external/dice.py b/diceplayer/shared/external/dice.py deleted file mode 100644 index 464d6eb..0000000 --- a/diceplayer/shared/external/dice.py +++ /dev/null @@ -1,53 +0,0 @@ -from diceplayer.shared.config.dice_dto import DiceDTO -from diceplayer.shared.external import External - -from multiprocessing import Process, connection -from setproctitle import setproctitle -import sys - - -class Dice(External): - __slots__ = ['config', 'step'] - - 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, step: any): - self.step = step - - def start(self, cycle: int): - procs = [ - Process(target=self._simulation_process, args=(cycle, proc)) - for proc in range(1, self.config.ncores+1) - ] - - for proc in procs: - proc.start() - - connection.wait(p.sentinel for p in procs) - - def reset(self): - del self.step - - def _simulation_process(self, cycle: int, proc: int): - setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}") - - try: - self._make_proc_dir(cycle, proc) - self._make_dice_inputs(cycle, proc) - self._run_dice(cycle, proc) - except Exception as err: - sys.exit(err) - - def _make_proc_dir(self, cycle, proc): - raise NotImplementedError - - def _make_dice_inputs(self, cycle, proc): - raise NotImplementedError - - def _run_dice(self, cycle, proc): - raise NotImplementedError diff --git a/diceplayer/shared/interface/__init__.py b/diceplayer/shared/interface/__init__.py new file mode 100644 index 0000000..4337de4 --- /dev/null +++ b/diceplayer/shared/interface/__init__.py @@ -0,0 +1 @@ +from .__interface import Interface diff --git a/diceplayer/shared/external/__external.py b/diceplayer/shared/interface/__interface.py similarity index 95% rename from diceplayer/shared/external/__external.py rename to diceplayer/shared/interface/__interface.py index 030d4bf..c468cf4 100644 --- a/diceplayer/shared/external/__external.py +++ b/diceplayer/shared/interface/__interface.py @@ -3,7 +3,7 @@ from diceplayer.shared.utils.dataclass_protocol import Dataclass from abc import ABC, abstractmethod -class External(ABC): +class Interface(ABC): __slots__ = [ 'config' ] diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py new file mode 100644 index 0000000..fbb639a --- /dev/null +++ b/diceplayer/shared/interface/dice_interface.py @@ -0,0 +1,388 @@ +from __future__ import annotations + +from diceplayer.shared.config.dice_dto import DiceDTO +from diceplayer.shared.config.step_dto import StepDTO +from diceplayer.shared.interface import Interface + +from multiprocessing import Process, connection +from setproctitle import setproctitle +from typing import Final, TextIO +from pathlib import Path +import subprocess +import shutil +import random +import time +import sys +import os + +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 DiceInterface(Interface): + __slots__ = ['config', 'step'] + + title = "Diceplayer run" + + def __init__(self, data: dict): + self.config: DiceDTO = self.set_config(data) + self.step: StepDTO | None = None + + @staticmethod + def set_config(data: dict) -> DiceDTO: + return DiceDTO.from_dict(data) + + def configure(self, step: any): + self.step = step + + def start(self, cycle: int): + 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) + + def reset(self): + del self.step + + def _simulation_process(self, cycle: int, proc: int): + setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}") + + try: + self._make_proc_dir(cycle, proc) + self._make_dice_inputs(cycle, proc) + self._run_dice(cycle, proc) + except Exception as err: + sys.exit(err) + + def _make_proc_dir(self, cycle, proc): + simulation_dir = Path(self.step.simulation_dir) + if not simulation_dir.exists(): + simulation_dir.mkdir(parents=True) + + proc_dir = Path( + simulation_dir, + f"step{cycle:02d}", + f"p{proc:02d}" + ) + proc_dir.mkdir(parents=True, exist_ok=True) + + def _make_dice_inputs(self, cycle, proc): + proc_dir = Path( + self.step.simulation_dir, + f"step{cycle:02d}", + f"p{proc:02d}" + ) + + self._make_potentials(proc_dir) + + random.seed(self._make_dice_seed()) + + # This is logic is used to make the initial configuration file + # for the next cycle using the last.xyz file from the previous cycle. + if self.config.randominit == 'first' and cycle > 1: + last_xyz = Path( + self.step.simulation_dir, + f"step{(cycle - 1):02d}", + f"p{proc:02d}", + "last.xyz" + ) + if not last_xyz.exists(): + raise FileNotFoundError(f"File {last_xyz} not found.") + + with open(last_xyz, 'r') as last_xyz_file: + self._make_init_file(proc_dir, last_xyz_file) + last_xyz_file.seek(0) + self.config.dens = self._new_density(last_xyz_file) + + else: + self._make_nvt_ter(cycle, proc_dir) + + if len(self.config.nstep) == 2: + self._make_nvt_eq(proc_dir) + + elif len(self.config.nstep) == 3: + self._make_npt_ter(cycle, proc_dir) + self._make_npt_eq(proc_dir) + + def _run_dice(self, cycle: int, proc: int): + working_dir = os.getcwd() + + proc_dir = Path( + self.step.simulation_dir, + f"step{cycle:02d}", + f"p{proc:02d}" + ) + os.chdir(proc_dir) + + if not (self.config.randominit == 'first' and cycle > 1): + self.run_dice_file(cycle, proc, "NVT.ter") + + if len(self.config.nstep) == 2: + self.run_dice_file(cycle, proc, "NVT.eq") + + elif len(self.config.nstep) == 3: + self.run_dice_file(cycle, proc, "NPT.ter") + self.run_dice_file(cycle, proc, "NPT.eq") + + os.chdir(working_dir) + + xyz_file = Path(proc_dir, "phb.xyz") + last_xyz_file = Path(proc_dir, "last.xyz") + + if xyz_file.exists(): + shutil.copy(xyz_file, last_xyz_file) + else: + raise FileNotFoundError(f"File {xyz_file} not found.") + + @staticmethod + def _make_dice_seed() -> int: + num = time.time() + num = (num - int(num)) * 1e6 + + num = int((num - int(num)) * 1e6) + + return (os.getpid() * num) % (MAX_SEED + 1) + + def _make_init_file(self, proc_dir: Path, last_xyz_file: TextIO): + xyz_lines = last_xyz_file.readlines() + + nsites_mm = 0 + for i in range(len(self.step.nmol)): + nsites_mm += self.step.nmol[i] * len(self.step.molecule[i].atom) + + xyz_lines = xyz_lines[-nsites_mm:] + + input_file = Path(proc_dir, self.config.outname + ".xy") + with open(input_file, 'w') as f: + + for atom in self.step.molecule[0].atom: + f.write( + f"{atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n" + ) + + for line in xyz_lines: + atom = line.split() + rx = float(atom[1]) + ry = float(atom[2]) + rz = float(atom[3]) + f.write(f"{rx:>10.6f} {ry:>10.6f} {rz:>10.6f}\n") + + f.write("$end") + + def _new_density(self, last_xyz_file: TextIO): + last_xyz_lines = last_xyz_file.readlines() + + box = last_xyz_lines[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 _make_nvt_ter(self, cycle, proc_dir): + file = Path(proc_dir, "NVT.ter") + with open(file, 'w') as f: + f.write(f"title = {self.title} - NVT Thermalization\n") + f.write(f"ncores = {self.step.ncores}\n") + f.write(f"ljname = {self.config.ljname}\n") + f.write(f"outname = {self.config.outname}\n") + + mol_string = " ".join(str(x) for x in self.config.nmol) + f.write(f"nmol = {mol_string}\n") + + f.write(f"dens = {self.config.dens}\n") + f.write(f"temp = {self.config.temp}\n") + + if self.config.randominit == "first" and cycle > 1: + f.write(f"init = yesreadxyz\n") + f.write(f"nstep = {self.step.altsteps}\n") + else: + f.write(f"init = yes\n") + f.write(f"nstep = {self.config.nstep[0]}\n") + + f.write("vstep = 0\n") + f.write("mstop = 1\n") + f.write("accum = no\n") + f.write("iprint = 1\n") + f.write("isave = 0\n") + f.write("irdf = 0\n") + + seed = int(1e6 * random.random()) + f.write(f"seed = {seed}\n") + f.write(f"upbuf = {self.config.upbuf}") + + def _make_nvt_eq(self, proc_dir): + + file = Path(proc_dir, "NVT.eq") + with open(file, 'w') as f: + f.write(f"title = {self.title} - NVT Production\n") + f.write(f"ncores = {self.step.ncores}\n") + f.write(f"ljname = {self.config.ljname}\n") + f.write(f"outname = {self.config.outname}\n") + + mol_string = " ".join(str(x) for x in self.config.nmol) + f.write(f"nmol = {mol_string}\n") + + f.write(f"dens = {self.config.dens}\n") + f.write(f"temp = {self.config.temp}\n") + f.write("init = no\n") + f.write(f"nstep = {self.config.nstep[1]}\n") + f.write("vstep = 0\n") + f.write("mstop = 1\n") + f.write("accum = no\n") + f.write("iprint = 1\n") + + f.write(f"isave = {self.config.isave}\n") + f.write(f"irdf = {10 * self.step.nprocs}\n") + + seed = int(1e6 * random.random()) + f.write("seed = {}\n".format(seed)) + + def _make_npt_ter(self, cycle, proc_dir): + + file = Path(proc_dir, "NPT.ter") + with open(file, 'w') as f: + f.write(f"title = {self.title} - NPT Thermalization\n") + f.write(f"ncores = {self.step.ncores}\n") + f.write(f"ljname = {self.config.ljname}\n") + f.write(f"outname = {self.config.outname}\n") + + mol_string = " ".join(str(x) for x in self.config.nmol) + f.write(f"nmol = {mol_string}\n") + + f.write(f"press = {self.config.press}\n") + f.write(f"temp = {self.config.temp}\n") + + if self.config.randominit == "first" and cycle > 1: + f.write("init = yesreadxyz\n") + f.write(f"dens = {self.config.dens:<8.4f}\n") + f.write(f"vstep = {int(self.step.altsteps / 5)}\n") + else: + f.write("init = no\n") + f.write(f"vstep = {int(self.config.nstep[1] / 5)}\n") + + f.write("nstep = 5\n") + f.write("mstop = 1\n") + f.write("accum = no\n") + f.write("iprint = 1\n") + f.write("isave = 0\n") + f.write("irdf = 0\n") + + seed = int(1e6 * random.random()) + f.write(f"seed = {seed}\n") + + def _make_npt_eq(self, proc_dir): + file = Path(proc_dir, "NPT.eq") + with open(file, 'w') as f: + f.write(f"title = {self.title} - NPT Production\n") + f.write(f"ncores = {self.step.ncores}\n") + f.write(f"ljname = {self.config.ljname}\n") + f.write(f"outname = {self.config.outname}\n") + + mol_string = " ".join(str(x) for x in self.config.nmol) + f.write(f"nmol = {mol_string}\n") + + f.write(f"press = {self.config.press}\n") + f.write(f"temp = {self.config.temp}\n") + + f.write(f"nstep = 5\n") + + f.write(f"vstep = {int(self.config.nstep[2] / 5)}\n") + f.write("init = no\n") + f.write("mstop = 1\n") + f.write("accum = no\n") + f.write("iprint = 1\n") + f.write(f"isave = {self.config.isave}\n") + f.write(f"irdf = {10 * self.step.nprocs}\n") + + seed = int(1e6 * random.random()) + f.write(f"seed = {seed}\n") + + def _make_potentials(self, proc_dir): + fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n" + + file = Path(proc_dir, self.config.ljname) + with open(file, 'w') as f: + f.write(f"{self.config.combrule}\n") + f.write(f"{len(self.step.nmol)}\n") + + nsites_qm = len(self.step.molecule[0].atom) + f.write(f"{nsites_qm} {self.step.molecule[0].molname}\n") + + for atom in self.step.molecule[0].atom: + f.write( + fstr.format( + atom.lbl, + atom.na, + atom.rx, + atom.ry, + atom.rz, + atom.chg, + atom.eps, + atom.sig, + ) + ) + + for mol in self.step.molecule[1:]: + f.write(f"{len(mol.atom)} {mol.molname}\n") + for atom in mol.atom: + f.write( + fstr.format( + atom.lbl, + atom.na, + atom.rx, + atom.ry, + atom.rz, + atom.chg, + atom.eps, + atom.sig, + ) + ) + + def run_dice_file(self, cycle: int, proc: int, file_name: str): + with open(Path(file_name), 'r') as infile, open(Path(file_name + ".out"), 'w') as outfile: + if shutil.which("bash") is not None: + exit_status = subprocess.call( + [ + "bash", + "-c", + f"exec -a dice-step{cycle}-p{proc} {self.config.progname} < {infile.name} > {outfile.name}", + ] + ) + else: + exit_status = subprocess.call( + self.config.progname, stdin=infile, stdout=outfile + ) + + if exit_status != 0: + raise Exception(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") + + with open(Path(file_name + ".out"), 'r') as outfile: + flag = outfile.readlines()[DICE_FLAG_LINE].strip() + if flag != DICE_END_FLAG: + raise Exception(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") diff --git a/diceplayer/shared/external/gaussian.py b/diceplayer/shared/interface/gaussian_interface.py similarity index 81% rename from diceplayer/shared/external/gaussian.py rename to diceplayer/shared/interface/gaussian_interface.py index c96ebd4..71bdf54 100644 --- a/diceplayer/shared/external/gaussian.py +++ b/diceplayer/shared/interface/gaussian_interface.py @@ -1,8 +1,8 @@ from diceplayer.shared.config.gaussian_dto import GaussianDTO -from diceplayer.shared.external import External +from diceplayer.shared.interface import Interface -class Gaussian(External): +class GaussianInterface(Interface): def __init__(self, data: dict): self.config: GaussianDTO = self.set_config(data) diff --git a/setup.py b/setup.py deleted file mode 100755 index 925add5..0000000 --- a/setup.py +++ /dev/null @@ -1,62 +0,0 @@ -import argparse -from distutils.command.clean import clean -import os -import shutil -import sys - -import PyInstaller.__main__ - -name = "diceplayer" - -parser = argparse.ArgumentParser(prog="Diceplayer Setup") - -parser.add_argument( - "-b", "--build", - dest="build", - default=False, - action="store_true", - help="Builds the Diceplayer Binary", -) -parser.add_argument( - "-c", "--clean", - dest="clean", - default=False, - action="store_true", - help="Cleans the Development Environment" -) - -args = parser.parse_args() - - -def __build(): - - PyInstaller.__main__.run( - ["diceplayer/__main__.py", "--onefile", "-n{}".format(name)] - ) - - -def __clean(): - - try: - - shutil.rmtree("build") - shutil.rmtree("dist") - os.remove("diceplayer.spec") - - except: - - print("Workspace clean.") - - - - - -if __name__ == "__main__": - - if args.build: - __build() - elif args.clean: - __clean() - else: - parser.print_help(sys.stderr) - sys.exit(1) diff --git a/tests/shared/config/test_dice_dto.py b/tests/shared/config/test_dice_dto.py index cd6a8c5..553e1f1 100644 --- a/tests/shared/config/test_dice_dto.py +++ b/tests/shared/config/test_dice_dto.py @@ -8,10 +8,9 @@ class TestDiceDto(unittest.TestCase): dice_dto = DiceDTO( ljname='test', outname='test', - ncores=1, dens=1.0, nmol=[1], - nstep=[1], + nstep=[1, 1], ) self.assertIsInstance(dice_dto, DiceDTO) @@ -21,10 +20,9 @@ class TestDiceDto(unittest.TestCase): DiceDTO( ljname=None, outname='test', - ncores=1, dens=1.0, nmol=[1], - nstep=[1], + nstep=[1, 1], ) self.assertEqual(ex.exception, "Error: 'ljname' keyword not specified in config file") @@ -33,10 +31,9 @@ class TestDiceDto(unittest.TestCase): DiceDTO( ljname='test', outname=None, - ncores=1, dens=1.0, nmol=[1], - nstep=[1], + nstep=[1, 1], ) self.assertEqual(ex.exception, "Error: 'outname' keyword not specified in config file") @@ -45,10 +42,9 @@ class TestDiceDto(unittest.TestCase): DiceDTO( ljname='test', outname='test', - ncores=1, dens=None, nmol=[1], - nstep=[1], + nstep=[1, 1], ) self.assertEqual(ex.exception, "Error: 'dens' keyword not specified in config file") @@ -57,10 +53,9 @@ class TestDiceDto(unittest.TestCase): DiceDTO( ljname='test', outname='test', - ncores=1, dens=1.0, nmol=0, - nstep=[1], + nstep=[1, 1], ) self.assertEqual(ex.exception, "Error: 'nmol' keyword not defined appropriately in config file") @@ -69,7 +64,6 @@ class TestDiceDto(unittest.TestCase): DiceDTO( ljname='test', outname='test', - ncores=1, dens=1.0, nmol=[1], nstep=0, @@ -80,10 +74,9 @@ class TestDiceDto(unittest.TestCase): dice_dto = DiceDTO.from_dict({ 'ljname': 'test', 'outname': 'test', - 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], }) self.assertIsInstance(dice_dto, DiceDTO) \ No newline at end of file diff --git a/tests/shared/config/test_gaussian_dto.py b/tests/shared/config/test_gaussian_dto.py new file mode 100644 index 0000000..67d013f --- /dev/null +++ b/tests/shared/config/test_gaussian_dto.py @@ -0,0 +1,45 @@ +from diceplayer.shared.config.gaussian_dto import GaussianDTO + +import unittest + + +class TestGaussianDTO(unittest.TestCase): + def test_class_instantiation(self): + gaussian_dto = GaussianDTO( + level='test', + qmprog='g16', + keywords='test', + ) + + self.assertIsInstance(gaussian_dto, GaussianDTO) + + def test_is_valid_qmprog(self): + with self.assertRaises(ValueError): + gaussian_dto = GaussianDTO( + level='test', + qmprog='test', + keywords='test', + ) + + def test_is_valid_level(self): + with self.assertRaises(ValueError): + gaussian_dto = GaussianDTO( + level=None, + qmprog='g16', + keywords='test', + ) + + def test_from_dict(self): + gaussian_dto = GaussianDTO.from_dict( + { + 'level': 'test', + 'qmprog': 'g16', + 'keywords': 'test', + } + ) + + self.assertIsInstance(gaussian_dto, GaussianDTO) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/shared/config/test_player_dto.py b/tests/shared/config/test_player_dto.py new file mode 100644 index 0000000..a514fb1 --- /dev/null +++ b/tests/shared/config/test_player_dto.py @@ -0,0 +1,28 @@ +from diceplayer.shared.config.player_dto import PlayerDTO + +import unittest + + +class TestPlayerDTO(unittest.TestCase): + def test_class_instantiation(self): + player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4) + + self.assertIsInstance(player_dto, PlayerDTO) + + def test_min_altsteps(self): + player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, altsteps=100) + + self.assertEqual(player_dto.altsteps, 20000) + + def test_from_dict(self): + player_dto = PlayerDTO.from_dict({ + 'opt': True, + 'maxcyc': 100, + 'nprocs': 4 + }) + + self.assertIsInstance(player_dto, PlayerDTO) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/shared/environment/test_system.py b/tests/shared/environment/test_system.py index cab9cbe..cff560e 100644 --- a/tests/shared/environment/test_system.py +++ b/tests/shared/environment/test_system.py @@ -26,25 +26,6 @@ class TestSystem(unittest.TestCase): system.add_type('test', Molecule('test')) self.assertEqual(ex.exception, 'Error: nmols is not an integer') - def test_center_of_mass_distance(self): - system = System() - - a = Molecule('test') - a.add_atom( - Atom(lbl=0, na=1, rx=0, ry=0, rz=0, chg=0, eps=0, sig=0) - ) - system.add_type(1, a) - - b = Molecule('test') - b.add_atom( - Atom(lbl=0, na=1, rx=0, ry=0, rz=0, chg=0, eps=0, sig=0) - ) - system.add_type(1, b) - - self.assertIsInstance(system.center_of_mass_distance(0, 1), float) - - - if __name__ == '__main__': unittest.main() diff --git a/tests/shared/external/test_dice.py b/tests/shared/external/test_dice.py index 8c51f95..d019d85 100644 --- a/tests/shared/external/test_dice.py +++ b/tests/shared/external/test_dice.py @@ -1,4 +1,5 @@ -from diceplayer.shared.external.dice import Dice +from diceplayer.shared.config.step_dto import StepDTO +from diceplayer.shared.interface.dice_interface import DiceInterface from unittest import mock import unittest @@ -6,28 +7,28 @@ import unittest class TestDice(unittest.TestCase): def test_class_instantiation(self): - dice = Dice( + dice = DiceInterface( { 'ljname': 'test', 'outname': 'test', 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], } ) - self.assertIsInstance(dice, Dice) + self.assertIsInstance(dice, DiceInterface) def test_configure(self): - dice = Dice( + dice = DiceInterface( { 'ljname': 'test', 'outname': 'test', 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], } ) @@ -38,14 +39,14 @@ class TestDice(unittest.TestCase): self.assertTrue(hasattr(dice, 'step')) def test_reset(self): - dice = Dice( + dice = DiceInterface( { 'ljname': 'test', 'outname': 'test', 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], } ) @@ -60,30 +61,41 @@ class TestDice(unittest.TestCase): @mock.patch('diceplayer.shared.external.dice.connection') @mock.patch('diceplayer.shared.external.dice.Process') def test_start(self, mock_process, mock_connection): - dice = Dice( + dice = DiceInterface( { 'ljname': 'test', 'outname': 'test', 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], } ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + dice.start(1) self.assertTrue(mock_process.called) self.assertTrue(mock_connection.wait.called) def test_simulation_process_raises_exception(self): - dice = Dice( + dice = DiceInterface( { 'ljname': 'test', 'outname': 'test', 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], } ) @@ -94,14 +106,14 @@ class TestDice(unittest.TestCase): @mock.patch('diceplayer.shared.external.dice.Dice._make_dice_inputs') @mock.patch('diceplayer.shared.external.dice.Dice._run_dice') def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir): - dice = Dice( + dice = DiceInterface( { 'ljname': 'test', 'outname': 'test', 'ncores': 1, 'dens': 1.0, 'nmol': [1], - 'nstep': [1], + 'nstep': [1, 1], } ) @@ -111,6 +123,82 @@ class TestDice(unittest.TestCase): self.assertTrue(dice._make_dice_inputs.called) self.assertTrue(dice._run_dice.called) + @mock.patch('diceplayer.shared.external.dice.Path.mkdir') + @mock.patch('diceplayer.shared.external.dice.Path.exists') + def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + mock_path_exists.return_value = False + + dice._make_proc_dir(1, 1) + + self.assertEqual(mock_path_mkdir.call_count, 2) + + @mock.patch('diceplayer.shared.external.dice.Path.mkdir') + @mock.patch('diceplayer.shared.external.dice.Path.exists') + def test_make_proc_dir_if_simdir_doesnt_exists(self, mock_path_exists, mock_path_mkdir): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + mock_path_exists.return_value = False + + dice._make_proc_dir(1, 1) + + self.assertEqual(mock_path_mkdir.call_count, 2) + + def test_make_dice_seed(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + seed = dice._make_dice_seed() + + self.assertIsInstance(seed, int) + if __name__ == '__main__': unittest.main() From e9a246812cc5c296b694648f3f55ee1b1fe13a8b Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Tue, 25 Apr 2023 10:05:18 -0300 Subject: [PATCH 05/18] Implements More Tests for the DiceInterface Class --- diceplayer/shared/interface/dice_interface.py | 2 - tests/{shared/external => mocks}/__init__.py | 0 tests/mocks/mock_proc.py | 31 + tests/shared/external/test_dice.py | 204 ------- tests/shared/interface/__init__.py | 0 tests/shared/interface/test/step01/p01/test | 2 + tests/shared/interface/test_dice_interface.py | 565 ++++++++++++++++++ 7 files changed, 598 insertions(+), 206 deletions(-) rename tests/{shared/external => mocks}/__init__.py (100%) create mode 100644 tests/mocks/mock_proc.py delete mode 100644 tests/shared/external/test_dice.py create mode 100644 tests/shared/interface/__init__.py create mode 100644 tests/shared/interface/test/step01/p01/test create mode 100644 tests/shared/interface/test_dice_interface.py diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index fbb639a..90630e8 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -23,8 +23,6 @@ MAX_SEED: Final[int] = 4294967295 class DiceInterface(Interface): - __slots__ = ['config', 'step'] - title = "Diceplayer run" def __init__(self, data: dict): diff --git a/tests/shared/external/__init__.py b/tests/mocks/__init__.py similarity index 100% rename from tests/shared/external/__init__.py rename to tests/mocks/__init__.py diff --git a/tests/mocks/mock_proc.py b/tests/mocks/mock_proc.py new file mode 100644 index 0000000..1319766 --- /dev/null +++ b/tests/mocks/mock_proc.py @@ -0,0 +1,31 @@ +from typing import List +import itertools + + +class MockProc: + pid_counter = itertools.count() + + def __init__(self, *args, **kwargs): + self.pid = next(MockProc.pid_counter) + + if 'exitcode' in kwargs: + self.exitcode = kwargs['exitcode'] + else: + self.exitcode = 0 + + self.sentinel = self.pid + + def __call__(self, *args, **kwargs): + return self + + def start(self): + pass + + def terminate(self): + pass + + +class MockConnection: + @staticmethod + def wait(sentinels: List[int]): + return sentinels diff --git a/tests/shared/external/test_dice.py b/tests/shared/external/test_dice.py deleted file mode 100644 index d019d85..0000000 --- a/tests/shared/external/test_dice.py +++ /dev/null @@ -1,204 +0,0 @@ -from diceplayer.shared.config.step_dto import StepDTO -from diceplayer.shared.interface.dice_interface import DiceInterface - -from unittest import mock -import unittest - - -class TestDice(unittest.TestCase): - def test_class_instantiation(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - self.assertIsInstance(dice, DiceInterface) - - def test_configure(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - self.assertFalse(hasattr(dice, 'step')) - - dice.configure('test') - - self.assertTrue(hasattr(dice, 'step')) - - def test_reset(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - dice.configure('test') - - self.assertTrue(hasattr(dice, 'step')) - - dice.reset() - - self.assertFalse(hasattr(dice, 'step')) - - @mock.patch('diceplayer.shared.external.dice.connection') - @mock.patch('diceplayer.shared.external.dice.Process') - def test_start(self, mock_process, mock_connection): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) - - dice.start(1) - - self.assertTrue(mock_process.called) - self.assertTrue(mock_connection.wait.called) - - def test_simulation_process_raises_exception(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - with self.assertRaises(SystemExit): - dice._simulation_process(1, 1) - - @mock.patch('diceplayer.shared.external.dice.Dice._make_proc_dir') - @mock.patch('diceplayer.shared.external.dice.Dice._make_dice_inputs') - @mock.patch('diceplayer.shared.external.dice.Dice._run_dice') - def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - dice._simulation_process(1, 1) - - self.assertTrue(dice._make_proc_dir.called) - self.assertTrue(dice._make_dice_inputs.called) - self.assertTrue(dice._run_dice.called) - - @mock.patch('diceplayer.shared.external.dice.Path.mkdir') - @mock.patch('diceplayer.shared.external.dice.Path.exists') - def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) - - mock_path_exists.return_value = False - - dice._make_proc_dir(1, 1) - - self.assertEqual(mock_path_mkdir.call_count, 2) - - @mock.patch('diceplayer.shared.external.dice.Path.mkdir') - @mock.patch('diceplayer.shared.external.dice.Path.exists') - def test_make_proc_dir_if_simdir_doesnt_exists(self, mock_path_exists, mock_path_mkdir): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) - - mock_path_exists.return_value = False - - dice._make_proc_dir(1, 1) - - self.assertEqual(mock_path_mkdir.call_count, 2) - - def test_make_dice_seed(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - seed = dice._make_dice_seed() - - self.assertIsInstance(seed, int) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/shared/interface/__init__.py b/tests/shared/interface/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/interface/test/step01/p01/test b/tests/shared/interface/test/step01/p01/test new file mode 100644 index 0000000..b85075d --- /dev/null +++ b/tests/shared/interface/test/step01/p01/test @@ -0,0 +1,2 @@ +* +0 diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py new file mode 100644 index 0000000..1f54445 --- /dev/null +++ b/tests/shared/interface/test_dice_interface.py @@ -0,0 +1,565 @@ +from diceplayer.shared.interface.dice_interface import DiceInterface +from diceplayer.shared.config.step_dto import StepDTO + +from tests.mocks.mock_proc import MockConnection, MockProc + +from unittest import mock +import unittest + + +class TestDiceInterface(unittest.TestCase): + def test_class_instantiation(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + self.assertIsInstance(dice, DiceInterface) + + def test_configure(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + self.assertFalse(hasattr(dice, 'step')) + + dice.configure('test') + + self.assertTrue(hasattr(dice, 'step')) + + def test_reset(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + dice.configure('test') + + self.assertTrue(hasattr(dice, 'step')) + + dice.reset() + + self.assertFalse(hasattr(dice, 'step')) + + @mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc()) + @mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection) + def test_start(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice.start(1) + + @mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection) + @mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc(exitcode=1)) + def test_start_with_process_error(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=2, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + with self.assertRaises(SystemExit): + dice.start(1) + + def test_simulation_process_raises_exception(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + with self.assertRaises(SystemExit): + dice._simulation_process(1, 1) + + @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._make_proc_dir') + @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._make_dice_inputs') + @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._run_dice') + def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + dice._simulation_process(1, 1) + + self.assertTrue(dice._make_proc_dir.called) + self.assertTrue(dice._make_dice_inputs.called) + self.assertTrue(dice._run_dice.called) + + @mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir') + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists') + def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + mock_path_exists.return_value = False + + dice._make_proc_dir(1, 1) + + self.assertEqual(mock_path_mkdir.call_count, 2) + + @mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir') + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists') + def test_make_proc_dir_if_simdir_doesnt_exists(self, mock_path_exists, mock_path_mkdir): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + mock_path_exists.return_value = False + + dice._make_proc_dir(1, 1) + + self.assertEqual(mock_path_mkdir.call_count, 2) + + def test_make_dice_seed(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + seed = dice._make_dice_seed() + + self.assertIsInstance(seed, int) + + def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_one(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_potentials = mock.Mock() + + dice._make_init_file = mock.Mock() + dice._new_density = mock.Mock() + + dice._make_nvt_ter = mock.Mock() + dice._make_nvt_eq = mock.Mock() + dice._make_npt_ter = mock.Mock() + dice._make_npt_eq = mock.Mock() + + dice._make_dice_inputs(1, 1) + + self.assertTrue(dice._make_potentials.called) + + self.assertFalse(dice._make_init_file.called) + self.assertFalse(dice._new_density.called) + + self.assertTrue(dice._make_nvt_ter.called) + self.assertTrue(dice._make_nvt_eq.called) + + self.assertFalse(dice._make_npt_ter.called) + self.assertFalse(dice._make_npt_eq.called) + + @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='test') + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) + def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_two(self, mock_path_exists, mock_open): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_potentials = mock.Mock() + + dice._make_init_file = mock.Mock() + dice._new_density = mock.Mock() + + dice._make_nvt_ter = mock.Mock() + dice._make_nvt_eq = mock.Mock() + dice._make_npt_ter = mock.Mock() + dice._make_npt_eq = mock.Mock() + + dice._make_dice_inputs(2, 1) + + self.assertTrue(dice._make_potentials.called) + + self.assertTrue(dice._make_init_file.called) + self.assertTrue(dice._new_density.called) + + self.assertFalse(dice._make_nvt_ter.called) + self.assertTrue(dice._make_nvt_eq.called) + + self.assertFalse(dice._make_npt_ter.called) + self.assertFalse(dice._make_npt_eq.called) + + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False) + def test_make_dice_inputs_raises_exception_on_last_not_found(self, mock_path_exists): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_potentials = mock.Mock() + + dice._make_init_file = mock.Mock() + dice._new_density = mock.Mock() + + dice._make_nvt_ter = mock.Mock() + dice._make_nvt_eq = mock.Mock() + dice._make_npt_ter = mock.Mock() + dice._make_npt_eq = mock.Mock() + + with self.assertRaises(FileNotFoundError): + dice._make_dice_inputs(2, 1) + + def test_make_dice_inputs_nstep_len_three_with_randoninit_first_cycle_one(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_potentials = mock.Mock() + + dice._make_init_file = mock.Mock() + dice._new_density = mock.Mock() + + dice._make_nvt_ter = mock.Mock() + dice._make_nvt_eq = mock.Mock() + dice._make_npt_ter = mock.Mock() + dice._make_npt_eq = mock.Mock() + + dice._make_dice_inputs(1, 1) + + self.assertTrue(dice._make_potentials.called) + + self.assertFalse(dice._make_init_file.called) + self.assertFalse(dice._new_density.called) + + self.assertTrue(dice._make_nvt_ter.called) + self.assertFalse(dice._make_nvt_eq.called) + + self.assertTrue(dice._make_npt_ter.called) + self.assertTrue(dice._make_npt_eq.called) + + @mock.patch('diceplayer.shared.interface.dice_interface.os') + @mock.patch('diceplayer.shared.interface.dice_interface.shutil') + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) + def test_run_dice_on_first_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice.run_dice_file = mock.Mock() + + dice._run_dice(1, 1) + + self.assertTrue(mock_os.getcwd.called) + self.assertTrue(mock_os.chdir.called) + + self.assertEqual(dice.run_dice_file.call_count, 3) + self.assertTrue(mock_shutils.copy.called) + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice.run_dice_file = mock.Mock() + + dice._run_dice(1, 1) + + self.assertTrue(mock_os.getcwd.called) + self.assertTrue(mock_os.chdir.called) + + self.assertEqual(dice.run_dice_file.call_count, 2) + self.assertTrue(mock_shutils.copy.called) + + @mock.patch('diceplayer.shared.interface.dice_interface.os') + @mock.patch('diceplayer.shared.interface.dice_interface.shutil') + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) + def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice.run_dice_file = mock.Mock() + + dice._run_dice(2, 1) + + self.assertTrue(mock_os.getcwd.called) + self.assertTrue(mock_os.chdir.called) + + self.assertEqual(dice.run_dice_file.call_count, 2) + self.assertTrue(mock_shutils.copy.called) + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice.run_dice_file = mock.Mock() + + dice._run_dice(2, 1) + + self.assertTrue(mock_os.getcwd.called) + self.assertTrue(mock_os.chdir.called) + + self.assertEqual(dice.run_dice_file.call_count, 1) + self.assertTrue(mock_shutils.copy.called) + + @mock.patch('diceplayer.shared.interface.dice_interface.os') + @mock.patch('diceplayer.shared.interface.dice_interface.shutil') + @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False) + def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice.run_dice_file = mock.Mock() + + with self.assertRaises(FileNotFoundError): + dice._run_dice(1, 1) + + +if __name__ == '__main__': + unittest.main() From a13088c409c7f530be0f14db36fa452d5a26344d Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Nakazone Batista Date: Tue, 25 Apr 2023 14:01:32 +0000 Subject: [PATCH 06/18] Fixes Test for configure Method in DiceInterface --- .gitignore | 6 ++++++ diceplayer/player.py | 12 ++++++------ tests/shared/interface/test_dice_interface.py | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b272ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class +.vscode/settings.json diff --git a/diceplayer/player.py b/diceplayer/player.py index 4229e08..2312d90 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,14 +1,15 @@ -from diceplayer.shared.config.step_dto import StepDTO -from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.interface.gaussian_interface import GaussianInterface +from diceplayer.shared.interface.dice_interface import DiceInterface 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.interface.gaussian_interface import GaussianInterface +from diceplayer.shared.environment.system import System +from diceplayer.shared.config.step_dto import StepDTO from diceplayer.shared.config.dice_dto import DiceDTO -from diceplayer.shared.interface.dice_interface import DiceInterface +from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.utils.ptable import atommass from dataclasses import fields from pathlib import Path @@ -18,7 +19,6 @@ import yaml import sys import os -from diceplayer.shared.utils.ptable import atommass ENV = ["OMP_STACKSIZE"] diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 1f54445..4698751 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -34,11 +34,11 @@ class TestDiceInterface(unittest.TestCase): } ) - self.assertFalse(hasattr(dice, 'step')) + self.assertIsNone(dice.step) dice.configure('test') - self.assertTrue(hasattr(dice, 'step')) + self.assertIsNotNone(dice.step) def test_reset(self): dice = DiceInterface( From 420b36b8727866924dc9b8e3e1497ce4909e253b Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Nakazone Batista Date: Wed, 26 Apr 2023 21:25:00 +0000 Subject: [PATCH 07/18] Implementa Test para Metodo make_init_file --- diceplayer/shared/interface/dice_interface.py | 1 + tests/shared/config/test_player_dto.py | 7 ++-- tests/shared/interface/test_dice_interface.py | 35 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index 90630e8..91b091e 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -15,6 +15,7 @@ import time import sys import os + DICE_END_FLAG: Final[str] = "End of simulation" DICE_FLAG_LINE: Final[int] = -2 UMAANG3_TO_GCM3: Final[float] = 1.6605 diff --git a/tests/shared/config/test_player_dto.py b/tests/shared/config/test_player_dto.py index a514fb1..98440af 100644 --- a/tests/shared/config/test_player_dto.py +++ b/tests/shared/config/test_player_dto.py @@ -5,12 +5,12 @@ import unittest class TestPlayerDTO(unittest.TestCase): def test_class_instantiation(self): - player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4) + player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, ncores=4) self.assertIsInstance(player_dto, PlayerDTO) def test_min_altsteps(self): - player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, altsteps=100) + player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, ncores=4, altsteps=100) self.assertEqual(player_dto.altsteps, 20000) @@ -18,7 +18,8 @@ class TestPlayerDTO(unittest.TestCase): player_dto = PlayerDTO.from_dict({ 'opt': True, 'maxcyc': 100, - 'nprocs': 4 + 'nprocs': 4, + 'ncores': 4, }) self.assertIsInstance(player_dto, PlayerDTO) diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 4698751..1f2c6c4 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -1,6 +1,9 @@ from diceplayer.shared.interface.dice_interface import DiceInterface +from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.config.step_dto import StepDTO +import io + from tests.mocks.mock_proc import MockConnection, MockProc from unittest import mock @@ -560,6 +563,38 @@ class TestDiceInterface(unittest.TestCase): with self.assertRaises(FileNotFoundError): dice._run_dice(1, 1) + def test_make_init_file(self): + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[ + + ], + nmol=[], + ) + ) + + last_xyz_file = io.StringIO() + last_xyz_file.writelines([ + 'TEST', + 'TEST', + 'TEST', + 'TEST', + ]) + if __name__ == '__main__': unittest.main() From f1deff478688f61c94f2f5ae205f97d36b8a167a Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Thu, 27 Apr 2023 03:48:23 -0300 Subject: [PATCH 08/18] Implementation of Logger and Finishes DiceInterface Tests --- .gitignore | 9 + diceplayer/shared/interface/dice_interface.py | 6 +- diceplayer/shared/utils/logger.py | 39 ++ diceplayer/shared/utils/validations.py | 15 - tests/shared/environment/test_molecule.py | 67 +++- tests/shared/interface/test_dice_interface.py | 373 +++++++++++++++++- tests/shared/utils/__init__.py | 0 tests/shared/utils/test_logger.py | 34 ++ 8 files changed, 517 insertions(+), 26 deletions(-) create mode 100644 diceplayer/shared/utils/logger.py delete mode 100644 diceplayer/shared/utils/validations.py create mode 100644 tests/shared/utils/__init__.py create mode 100644 tests/shared/utils/test_logger.py diff --git a/.gitignore b/.gitignore index 7b272ac..f9cca34 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,12 @@ __pycache__/ *.py[cod] *$py.class .vscode/settings.json + +*.ljc +*.log +*.log.backup + +simfiles/* + +.vscode/* +.idea/* \ No newline at end of file diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index 91b091e..89bcbd1 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -167,7 +167,7 @@ class DiceInterface(Interface): xyz_lines = last_xyz_file.readlines() nsites_mm = 0 - for i in range(len(self.step.nmol)): + for i in range(1, len(self.step.nmol)): nsites_mm += self.step.nmol[i] * len(self.step.molecule[i].atom) xyz_lines = xyz_lines[-nsites_mm:] @@ -379,9 +379,9 @@ class DiceInterface(Interface): ) if exit_status != 0: - raise Exception(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") + raise RuntimeError(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") with open(Path(file_name + ".out"), 'r') as outfile: flag = outfile.readlines()[DICE_FLAG_LINE].strip() if flag != DICE_END_FLAG: - raise Exception(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") + raise RuntimeError(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") diff --git a/diceplayer/shared/utils/logger.py b/diceplayer/shared/utils/logger.py new file mode 100644 index 0000000..30fa6ee --- /dev/null +++ b/diceplayer/shared/utils/logger.py @@ -0,0 +1,39 @@ +import logging + + +class Logger: + outfile = None + + _logger = None + _instance = None + + def __new__(cls, *args, **kwargs): + if not getattr(cls, '_instance'): + cls._instance = super(Logger, cls).__new__(cls) + return cls._instance + + def set_logger(self, logger_name, outfile='run.log', level=logging.INFO): + self.outfile = outfile + + self._logger = logging.getLogger(logger_name) + + if level is not None: + self._logger.setLevel(level) + + self._create_handlers() + + def _create_handlers(self): + handlers = [] + if self.outfile is not None: + handlers.append(logging.FileHandler(self.outfile, mode='a+')) + else: + handlers.append(logging.StreamHandler()) + + for handler in handlers: + handler.setFormatter(logging.Formatter('%(message)s')) + self._logger.addHandler(handler) + + def close(self): + for handler in self._logger.handlers: + handler.close() + self._logger.removeHandler(handler) diff --git a/diceplayer/shared/utils/validations.py b/diceplayer/shared/utils/validations.py deleted file mode 100644 index a25257c..0000000 --- a/diceplayer/shared/utils/validations.py +++ /dev/null @@ -1,15 +0,0 @@ -def NotNull(requiredArgs=[]): - def _NotNull(function): - def wrapper(*args, **kwargs): - for arg in requiredArgs: - try: - assert ( - kwargs.get(arg) is not None - ), "Invalid Config File. Keyword {} is required".format(arg) - except AssertionError as err: - print(err) - return function(*args, **kwargs) - - return wrapper - - return _NotNull \ No newline at end of file diff --git a/tests/shared/environment/test_molecule.py b/tests/shared/environment/test_molecule.py index 1eb8c2e..5a65815 100644 --- a/tests/shared/environment/test_molecule.py +++ b/tests/shared/environment/test_molecule.py @@ -1,3 +1,5 @@ +import numpy as np + from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.atom import Atom @@ -144,4 +146,67 @@ class TestMolecule(unittest.TestCase): npt.assert_equal( expected_charges, actual_charges - ) \ No newline at end of file + ) + + def test_sizes_of_molecule(self): + mol = Molecule('test') + + 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) + ) + + sizes = mol.sizes_of_molecule() + + expected_sizes = [0.0, 0.0, 0.0] + + npt.assert_equal(sizes, expected_sizes) + + def test_standard_orientation(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.standard_orientation() + + expected_position = [0.0, 0.0, 0.0] + + self.assertEqual(mol.read_position().tolist(), expected_position) + + def test_translate(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) + ) + + new_mol = mol.translate(np.array([-1, -1, -1])) + + expected_position = [0.0, 0.0, 0.0] + + self.assertEqual( + new_mol.read_position().tolist(), + expected_position + ) + + def test_minimum_distance(self): + mol1 = Molecule('test1') + mol1.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) + ) + + mol2 = Molecule('test2') + mol2.add_atom( + Atom(lbl=1, na=1, rx=1.0, ry=0.0, rz=0.0, chg=1.0, eps=1.0, sig=1.0) + ) + + expected_distance = 1.0 + + actual_distance = mol1.minimum_distance(mol2) + + self.assertEqual(expected_distance, actual_distance) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 1f2c6c4..c6bbfdb 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -1,5 +1,6 @@ from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.environment.atom import Atom from diceplayer.shared.config.step_dto import StepDTO import io @@ -563,7 +564,25 @@ class TestDiceInterface(unittest.TestCase): with self.assertRaises(FileNotFoundError): dice._run_dice(1, 1) - def test_make_init_file(self): + @mock.patch('builtins.open', new_callable=mock.mock_open) + def test_make_init_file(self, mock_open): + example_atom = Atom( + lbl=1, + na=1, + rx=1.0, + ry=1.0, + rz=1.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + + main_molecule = Molecule('main_molecule') + main_molecule.add_atom(example_atom) + + secondary_molecule = Molecule('secondary_molecule') + secondary_molecule.add_atom(example_atom) + dice = DiceInterface( { 'ljname': 'test', @@ -581,19 +600,359 @@ class TestDiceInterface(unittest.TestCase): simulation_dir='test', altsteps=1, molecule=[ - + main_molecule, + secondary_molecule, + ], + nmol=[ + len(main_molecule.atom), + len(secondary_molecule.atom), ], - nmol=[], ) ) last_xyz_file = io.StringIO() last_xyz_file.writelines([ - 'TEST', - 'TEST', - 'TEST', - 'TEST', + ' TEST\n', + ' Configuration number : TEST = TEST TEST TEST\n', + ' H 1.00000 1.00000 1.00000\n', + ' H 1.00000 1.00000 1.00000\n', ]) + last_xyz_file.seek(0) + + dice._make_init_file('test', last_xyz_file) + + mock_handler = mock_open() + calls = mock_handler.write.call_args_list + + lines = list(map(lambda x: x[0][0], calls)) + + expected_lines = [ + ' 1.000000 1.000000 1.000000\n', + ' 1.000000 1.000000 1.000000\n', + '$end' + ] + + self.assertEqual(lines, expected_lines) + + @mock.patch('builtins.open', new_callable=mock.mock_open) + def test_new_density(self, mock_open): + example_atom = Atom( + lbl=1, + na=1, + rx=1.0, + ry=1.0, + rz=1.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + + main_molecule = Molecule('main_molecule') + main_molecule.add_atom(example_atom) + + secondary_molecule = Molecule('secondary_molecule') + secondary_molecule.add_atom(example_atom) + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[ + main_molecule, + secondary_molecule, + ], + nmol=[ + len(main_molecule.atom), + len(secondary_molecule.atom), + ], + ) + ) + + last_xyz_file = io.StringIO() + last_xyz_file.writelines([ + ' TEST\n', + ' Configuration number : TEST = 1 1 1\n', + ' H 1.00000 1.00000 1.00000\n', + ' H 1.00000 1.00000 1.00000\n', + ]) + last_xyz_file.seek(0) + + density = dice._new_density(last_xyz_file) + + self.assertEqual(density, 3.3472359000000003) + + @mock.patch('builtins.open', new_callable=mock.mock_open) + @mock.patch('diceplayer.shared.interface.dice_interface.random') + def test_make_nvt_ter(self, mock_random, mock_open): + mock_random.random.return_value = 1 + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_nvt_ter(1, 'test') + + mock_handler = mock_open() + calls = mock_handler.write.call_args_list + + lines = list(map(lambda x: x[0][0], calls)) + + expected_lines = ['title = Diceplayer run - NVT Thermalization\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'dens = 1.0\n', 'temp = 300.0\n', 'init = yes\n', 'nstep = 1\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n', 'upbuf = 360'] + + self.assertEqual(lines, expected_lines) + + @mock.patch('builtins.open', new_callable=mock.mock_open) + @mock.patch('diceplayer.shared.interface.dice_interface.random') + def test_make_nvt_eq(self, mock_random, mock_open): + mock_random.random.return_value = 1 + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_nvt_eq('test') + + mock_handler = mock_open() + calls = mock_handler.write.call_args_list + + lines = list(map(lambda x: x[0][0], calls)) + + expected_lines = ['title = Diceplayer run - NVT Production\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'dens = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'nstep = 1\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 10\n', 'seed = 1000000\n'] + + self.assertEqual(lines, expected_lines) + + @mock.patch('builtins.open', new_callable=mock.mock_open) + @mock.patch('diceplayer.shared.interface.dice_interface.random') + def test_make_npt_ter(self, mock_random, mock_open): + mock_random.random.return_value = 1 + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_npt_ter(1, 'test') + + mock_handler = mock_open() + calls = mock_handler.write.call_args_list + + lines = list(map(lambda x: x[0][0], calls)) + + expected_lines = ['title = Diceplayer run - NPT Thermalization\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'press = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'vstep = 0\n', 'nstep = 5\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n'] + + self.assertEqual(lines, expected_lines) + + @mock.patch('builtins.open', new_callable=mock.mock_open) + @mock.patch('diceplayer.shared.interface.dice_interface.random') + def test_make_npt_eq(self, mock_random, mock_open): + mock_random.random.return_value = 1 + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[], + nmol=[], + ) + ) + + dice._make_npt_eq('test') + + mock_handler = mock_open() + calls = mock_handler.write.call_args_list + + lines = list(map(lambda x: x[0][0], calls)) + + expected_lines = ['title = Diceplayer run - NPT Production\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'press = 1.0\n', 'temp = 300.0\n', 'nstep = 5\n', 'vstep = 0\n', 'init = no\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 10\n', 'seed = 1000000\n'] + + self.assertEqual(lines, expected_lines) + + @mock.patch('builtins.open', new_callable=mock.mock_open) + def test_make_potentials(self, mock_open): + example_atom = Atom( + lbl=1, + na=1, + rx=1.0, + ry=1.0, + rz=1.0, + chg=1.0, + eps=1.0, + sig=1.0, + ) + + main_molecule = Molecule('main_molecule') + main_molecule.add_atom(example_atom) + + secondary_molecule = Molecule('secondary_molecule') + secondary_molecule.add_atom(example_atom) + + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + dice.configure( + StepDTO( + ncores=1, + nprocs=1, + simulation_dir='test', + altsteps=1, + molecule=[ + main_molecule, + secondary_molecule, + ], + nmol=[ + len(main_molecule.atom), + len(secondary_molecule.atom), + ], + ) + ) + + dice._make_potentials('test') + + mock_handler = mock_open() + calls = mock_handler.write.call_args_list + + lines = list(map(lambda x: x[0][0], calls)) + + expected_lines = ['*\n', '2\n', '1 main_molecule\n', '1 1 1.00000 1.00000 1.00000 1.000000 1.00000 1.0000\n', '1 secondary_molecule\n', '1 1 1.00000 1.00000 1.00000 1.000000 1.00000 1.0000\n'] + + self.assertEqual(lines, expected_lines) + + @mock.patch('diceplayer.shared.interface.dice_interface.subprocess') + @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA') + def test_run_dice_file(self, mock_open, mock_subprocess): + mock_subprocess.call.return_value = 0 + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + dice.run_dice_file(1, 1, 'test') + + self.assertTrue(mock_subprocess.call.called) + self.assertTrue(mock_open.called) + + @mock.patch('diceplayer.shared.interface.dice_interface.subprocess') + @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='Error\nBLABLA') + def test_run_dice_file_raises_runtime_error_on_dice_file(self, mock_open, mock_subprocess): + mock_subprocess.call.return_value = 0 + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + with self.assertRaises(RuntimeError): + dice.run_dice_file(1, 1, 'test') + + @mock.patch('diceplayer.shared.interface.dice_interface.subprocess') + @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA') + def test_run_dice_file_raises_runtime_error_of_dice_exit_code(self, mock_open, mock_subprocess): + mock_subprocess.call.return_value = 1 + dice = DiceInterface( + { + 'ljname': 'test', + 'outname': 'test', + 'ncores': 1, + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + } + ) + + with self.assertRaises(RuntimeError): + dice.run_dice_file(1, 1, 'test') if __name__ == '__main__': diff --git a/tests/shared/utils/__init__.py b/tests/shared/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/utils/test_logger.py b/tests/shared/utils/test_logger.py new file mode 100644 index 0000000..f97ec54 --- /dev/null +++ b/tests/shared/utils/test_logger.py @@ -0,0 +1,34 @@ +from diceplayer.shared.utils.logger import Logger + +import unittest + + +class TestLogger(unittest.TestCase): + def test_class_instantiation(self): + logger = Logger() + + self.assertIsInstance(logger, Logger) + + def test_singleton(self): + logger1 = Logger() + logger2 = Logger() + + self.assertIs(logger1, logger2) + + def test_set_logger(self): + logger = Logger() + logger.set_logger('test_logger') + + self.assertIsNotNone(logger._logger) + self.assertEqual(logger._logger.name, 'test_logger') + + def test_close(self): + logger = Logger() + logger.set_logger('test_logger') + logger.close() + + self.assertEqual(len(logger._logger.handlers), 0) + + +if __name__ == '__main__': + unittest.main() From 2d488bd749cfe23ea574e773e3fb9bdeaf3329a3 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Thu, 27 Apr 2023 04:08:37 -0300 Subject: [PATCH 09/18] Setting CI/CD --- .github/workflows/python-tests.yml | 30 ++++++++++++ Pipfile | 2 +- Pipfile.lock | 74 +++++++++++++++--------------- 3 files changed, 68 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/python-tests.yml diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml new file mode 100644 index 0000000..554cb0f --- /dev/null +++ b/.github/workflows/python-tests.yml @@ -0,0 +1,30 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push + +permissions: + contents: read + +jobs: + + run-unitest: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v3 + with: + python-version: "3.8" + - name: Install dependencies + run: | + python -m pip install --upgrade pip pipenv + if [ -f Pipfile ]; then pipenv install; fi + - name: Test with unittest + run: | + pipenv run python -m unittest -v \ No newline at end of file diff --git a/Pipfile b/Pipfile index c8b8028..ae70530 100644 --- a/Pipfile +++ b/Pipfile @@ -20,4 +20,4 @@ pyinstaller = "*" coverage = "*" [requires] -python_version = ">3.8" +python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 68f88c5..65b18c9 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "9af00878e9f259614f72d3c11de93c16ede78176a30d8337c741be06c048c8a8" + "sha256": "6d97338a51c2b51f6dcbcdbee2533e22d29634f07914cfc05b32f8476e9346ed" }, "pipfile-spec": 6, "requires": { - "python_version": ">3.8" + "python_version": "3.8" }, "sources": [ { @@ -60,37 +60,37 @@ }, "numpy": { "hashes": [ - "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" + "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187", + "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812", + "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7", + "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4", + "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6", + "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0", + "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4", + "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570", + "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4", + "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f", + "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80", + "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289", + "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385", + "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078", + "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c", + "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463", + "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3", + "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950", + "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155", + "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7", + "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c", + "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096", + "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17", + "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf", + "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4", + "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02", + "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c", + "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b" ], "index": "pypi", - "version": "==1.24.2" + "version": "==1.24.3" }, "pickle5": { "hashes": [ @@ -251,11 +251,11 @@ }, "setuptools": { "hashes": [ - "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67", - "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c" + "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b", + "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990" ], "markers": "python_version >= '3.7'", - "version": "==67.7.1" + "version": "==67.7.2" }, "typing": { "hashes": [ @@ -367,11 +367,11 @@ }, "setuptools": { "hashes": [ - "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67", - "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c" + "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b", + "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990" ], "markers": "python_version >= '3.7'", - "version": "==67.7.1" + "version": "==67.7.2" } } } From 9c822c6848096033fb075a80f44a288500de8674 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Thu, 27 Apr 2023 05:14:07 -0300 Subject: [PATCH 10/18] Adds Functionality to Logger --- diceplayer/__init__.py | 4 + diceplayer/__main__.py | 8 +- diceplayer/shared/environment/system.py | 121 ++++++++++++------------ diceplayer/shared/utils/logger.py | 43 +++++++-- tests/shared/utils/test_logger.py | 88 ++++++++++++++--- 5 files changed, 177 insertions(+), 87 deletions(-) diff --git a/diceplayer/__init__.py b/diceplayer/__init__.py index e69de29..b2344e9 100644 --- a/diceplayer/__init__.py +++ b/diceplayer/__init__.py @@ -0,0 +1,4 @@ +from diceplayer.shared.utils.logger import Logger + + +logger = Logger(__name__) diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 12fa4c3..5de9c32 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -1,5 +1,6 @@ from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.player import Player +from diceplayer import logger from pathlib import Path import argparse @@ -40,6 +41,7 @@ def main(): args = parser.parse_args() # Open OUTFILE for writing and print keywords and initial info + logger.set_logger(args.outfile, logging.INFO) try: @@ -55,12 +57,6 @@ def main(): except Exception as err: sys.exit(err) - logging.basicConfig( - filename=args.outfile, - format='%(message)s', - level=logging.INFO - ) - player = Player(args.infile) player.start() diff --git a/diceplayer/shared/environment/system.py b/diceplayer/shared/environment/system.py index b34449b..1a6aff7 100644 --- a/diceplayer/shared/environment/system.py +++ b/diceplayer/shared/environment/system.py @@ -42,6 +42,29 @@ class System: raise TypeError("Error: nmols is not an integer") self.nmols.append(nmols) + def update_molecule(self, position: np.ndarray, fh: TextIO) -> None: + """Updates the position of the molecule in the Output file + + Args: + position (np.ndarray): numpy position vector + fh (TextIO): Output file + """ + + position_in_ang = (position * BOHR2ANG).tolist() + self.add_type(self.nmols[0], deepcopy(self.molecule[0])) + + for atom in self.molecule[-1].atom: + + atom.rx = position_in_ang.pop(0) + atom.ry = position_in_ang.pop(0) + atom.rz = position_in_ang.pop(0) + + rmsd, self.molecule[0] = self.rmsd_fit(-1, 0) + self.molecule.pop(-1) + + fh.write("\nProjected new conformation of reference molecule with RMSD fit\n") + fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd)) + def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]: projecting_mol = self.molecule[p_index] @@ -176,65 +199,43 @@ class System: # self.molecule.pop(-1) # # return min_dist, nearestmol - def update_molecule(self, position: np.ndarray, fh: TextIO) -> None: - """Updates the position of the molecule in the Output file - - Args: - position (np.ndarray): numpy position vector - fh (TextIO): Output file - """ - - position_in_ang = (position * BOHR2ANG).tolist() - self.add_type(self.nmols[0], deepcopy(self.molecule[0])) - - for atom in self.molecule[-1].atom: - - atom.rx = position_in_ang.pop(0) - atom.ry = position_in_ang.pop(0) - atom.rz = position_in_ang.pop(0) - - rmsd, self.molecule[0] = self.rmsd_fit(-1, 0) - self.molecule.pop(-1) - - fh.write("\nProjected new conformation of reference molecule with RMSD fit\n") - fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd)) - def print_geom(self, cycle: int, fh: TextIO) -> None: - """ - Print the geometry of the molecule in the Output file - - Args: - cycle (int): Number of the cycle - fh (TextIO): Output file - """ - - fh.write("Cycle # {}\n".format(cycle)) - fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) - for atom in self.molecule[0].atom: - symbol = atomsymb[atom.na] - fh.write( - "{:<2s} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( - symbol, atom.rx, atom.ry, atom.rz - ) - ) - - def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None: - """ - Print the charges and dipole of the molecule in the Output file - - Args: - cycle (int): Number of the cycle - fh (TextIO): Output file - """ - - fh.write("Cycle # {}\n".format(cycle)) - fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) - - chargesAndDipole = self.molecule[0].charges_and_dipole() - - fh.write( - "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( - chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4] - ) - ) + # def print_geom(self, cycle: int, fh: TextIO) -> None: + # """ + # Print the geometry of the molecule in the Output file + # + # Args: + # cycle (int): Number of the cycle + # fh (TextIO): Output file + # """ + # + # fh.write("Cycle # {}\n".format(cycle)) + # fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) + # for atom in self.molecule[0].atom: + # symbol = atomsymb[atom.na] + # fh.write( + # "{:<2s} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( + # symbol, atom.rx, atom.ry, atom.rz + # ) + # ) + # + # def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None: + # """ + # Print the charges and dipole of the molecule in the Output file + # + # Args: + # cycle (int): Number of the cycle + # fh (TextIO): Output file + # """ + # + # fh.write("Cycle # {}\n".format(cycle)) + # fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) + # + # chargesAndDipole = self.molecule[0].charges_and_dipole() + # + # fh.write( + # "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( + # chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4] + # ) + # ) diff --git a/diceplayer/shared/utils/logger.py b/diceplayer/shared/utils/logger.py index 30fa6ee..52430d9 100644 --- a/diceplayer/shared/utils/logger.py +++ b/diceplayer/shared/utils/logger.py @@ -1,27 +1,54 @@ import logging +def valid_logger(func): + def wrapper(*args, **kwargs): + logger = args[0] + assert logger._was_set, \ + "Logger is not set. Please call set_logger() first." + + return func(*args, **kwargs) + + return wrapper + + class Logger: outfile = None _logger = None - _instance = None - def __new__(cls, *args, **kwargs): - if not getattr(cls, '_instance'): - cls._instance = super(Logger, cls).__new__(cls) - return cls._instance + _was_set = False - def set_logger(self, logger_name, outfile='run.log', level=logging.INFO): + def __init__(self, logger_name): + if self._logger is None: + self._logger = logging.getLogger(logger_name) + + def set_logger(self, outfile='run.log', level=logging.INFO): self.outfile = outfile - self._logger = logging.getLogger(logger_name) - if level is not None: self._logger.setLevel(level) self._create_handlers() + self._was_set = True + + @valid_logger + def info(self, message): + self._logger.info(message) + + @valid_logger + def debug(self, message): + self._logger.debug(message) + + @valid_logger + def warning(self, message): + self._logger.warning(message) + + @valid_logger + def error(self, message): + self._logger.error(message) + def _create_handlers(self): handlers = [] if self.outfile is not None: diff --git a/tests/shared/utils/test_logger.py b/tests/shared/utils/test_logger.py index f97ec54..03d47b5 100644 --- a/tests/shared/utils/test_logger.py +++ b/tests/shared/utils/test_logger.py @@ -1,34 +1,96 @@ -from diceplayer.shared.utils.logger import Logger +from diceplayer.shared.utils.logger import Logger, valid_logger +import logging + +from unittest import mock import unittest +class TestValidateLogger(unittest.TestCase): + def test_validate_logger(self): + class MockLogger: + _was_set = True + + @valid_logger + def test_func(self): + pass + + MockLogger().test_func() + + def test_validate_logger_exception(self): + class MockLogger: + _was_set = False + + @valid_logger + def test_func(self): + pass + + with self.assertRaises(AssertionError): + MockLogger().test_func() + + class TestLogger(unittest.TestCase): def test_class_instantiation(self): - logger = Logger() + logger = Logger('test') self.assertIsInstance(logger, Logger) - def test_singleton(self): - logger1 = Logger() - logger2 = Logger() - - self.assertIs(logger1, logger2) - + @mock.patch('builtins.open', mock.mock_open()) def test_set_logger(self): - logger = Logger() - logger.set_logger('test_logger') + logger = Logger('test') + logger.set_logger() self.assertIsNotNone(logger._logger) - self.assertEqual(logger._logger.name, 'test_logger') + self.assertEqual(logger._logger.name, 'test') + @mock.patch('builtins.open', mock.mock_open()) def test_close(self): - logger = Logger() - logger.set_logger('test_logger') + logger = Logger('test') + logger.set_logger() logger.close() self.assertEqual(len(logger._logger.handlers), 0) + @mock.patch('builtins.open', mock.mock_open()) + def test_info(self): + logger = Logger('test') + logger.set_logger() + + with self.assertLogs(level='INFO') as cm: + logger.info('test') + + self.assertEqual(cm.output, ['INFO:test:test']) + + @mock.patch('builtins.open', mock.mock_open()) + def test_debug(self): + logger = Logger('test') + logger.set_logger(level=logging.DEBUG) + + with self.assertLogs(level='DEBUG') as cm: + logger.debug('test') + + self.assertEqual(cm.output, ['DEBUG:test:test']) + + @mock.patch('builtins.open', mock.mock_open()) + def test_warning(self): + logger = Logger('test') + logger.set_logger() + + with self.assertLogs(level='WARNING') as cm: + logger.warning('test') + + self.assertEqual(cm.output, ['WARNING:test:test']) + + @mock.patch('builtins.open', mock.mock_open()) + def test_error(self): + logger = Logger('test') + logger.set_logger() + + with self.assertLogs(level='ERROR') as cm: + logger.error('test') + + self.assertEqual(cm.output, ['ERROR:test:test']) + if __name__ == '__main__': unittest.main() From 5666eb8c2837b47cc3dd8548c93a51282b3c79d9 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Fri, 28 Apr 2023 03:45:47 -0300 Subject: [PATCH 11/18] Removes Unnecessary Files Generated by Unittests --- tests/shared/interface/test/step01/p01/test | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 tests/shared/interface/test/step01/p01/test diff --git a/tests/shared/interface/test/step01/p01/test b/tests/shared/interface/test/step01/p01/test deleted file mode 100644 index b85075d..0000000 --- a/tests/shared/interface/test/step01/p01/test +++ /dev/null @@ -1,2 +0,0 @@ -* -0 From 56994dba2772607249b7821b021547680fc88a79 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Fri, 28 Apr 2023 03:55:07 -0300 Subject: [PATCH 12/18] Renames Old Log File if It Exists --- diceplayer/__main__.py | 4 ---- diceplayer/shared/utils/logger.py | 5 ++++- tests/shared/utils/test_logger.py | 20 +++++++++++++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 5de9c32..9a3071c 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -50,10 +50,6 @@ def main(): with open(pickle_path) as pickle_file: save = pickle.load(pickle_file) - output_path = Path(args.outfile) - if output_path.exists(): - output_path.rename(str(output_path) + ".backup") - except Exception as err: sys.exit(err) diff --git a/diceplayer/shared/utils/logger.py b/diceplayer/shared/utils/logger.py index 52430d9..2ed8372 100644 --- a/diceplayer/shared/utils/logger.py +++ b/diceplayer/shared/utils/logger.py @@ -1,3 +1,4 @@ +from pathlib import Path import logging @@ -24,7 +25,9 @@ class Logger: self._logger = logging.getLogger(logger_name) def set_logger(self, outfile='run.log', level=logging.INFO): - self.outfile = outfile + self.outfile = Path(outfile) + if self.outfile.exists(): + self.outfile.rename(str(self.outfile) + ".backup") if level is not None: self._logger.setLevel(level) diff --git a/tests/shared/utils/test_logger.py b/tests/shared/utils/test_logger.py index 03d47b5..482341f 100644 --- a/tests/shared/utils/test_logger.py +++ b/tests/shared/utils/test_logger.py @@ -36,10 +36,28 @@ class TestLogger(unittest.TestCase): self.assertIsInstance(logger, Logger) @mock.patch('builtins.open', mock.mock_open()) - def test_set_logger(self): + @mock.patch('diceplayer.shared.utils.logger.Path.exists') + @mock.patch('diceplayer.shared.utils.logger.Path.rename') + def test_set_logger_if_file_exists(self, mock_rename, mock_exists): logger = Logger('test') + + mock_exists.return_value = True logger.set_logger() + self.assertTrue(mock_rename.called) + self.assertIsNotNone(logger._logger) + self.assertEqual(logger._logger.name, 'test') + + @mock.patch('builtins.open', mock.mock_open()) + @mock.patch('diceplayer.shared.utils.logger.Path.exists') + @mock.patch('diceplayer.shared.utils.logger.Path.rename') + def test_set_logger_if_file_not_exists(self, mock_rename, mock_exists): + logger = Logger('test') + + mock_exists.return_value = False + logger.set_logger() + + self.assertFalse(mock_rename.called) self.assertIsNotNone(logger._logger) self.assertEqual(logger._logger.name, 'test') From b440a0f05d151cf791835d32bc4f87cd0b2918f8 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 3 May 2023 03:14:26 -0300 Subject: [PATCH 13/18] Implements Additional Logs and class Player Tests --- control.example.yml | 2 +- diceplayer/player.py | 173 ++++--- diceplayer/shared/interface/dice_interface.py | 14 +- .../shared/interface/gaussian_interface.py | 2 +- diceplayer/shared/utils/logger.py | 20 +- tests/shared/interface/test_dice_interface.py | 4 + tests/shared/utils/test_logger.py | 27 +- tests/test_player.py | 424 ++++++++++++++++++ 8 files changed, 586 insertions(+), 80 deletions(-) create mode 100644 tests/test_player.py diff --git a/control.example.yml b/control.example.yml index 99f5ae4..b664d27 100644 --- a/control.example.yml +++ b/control.example.yml @@ -6,8 +6,8 @@ diceplayer: qmprog: 'g16' lps: no ghosts: no - altsteps: 20000 + dice: nmol: [1, 50] dens: 0.75 diff --git a/diceplayer/player.py b/diceplayer/player.py index 2312d90..25c10a5 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -9,7 +9,7 @@ from diceplayer.shared.environment.system import System from diceplayer.shared.config.step_dto import StepDTO from diceplayer.shared.config.dice_dto import DiceDTO from diceplayer.shared.environment.atom import Atom -from diceplayer.shared.utils.ptable import atommass +from diceplayer import logger from dataclasses import fields from pathlib import Path @@ -24,13 +24,6 @@ ENV = ["OMP_STACKSIZE"] class Player: - __slots__ = [ - 'config', - 'system', - 'dice', - 'gaussian', - ] - def __init__(self, infile: str): config_data = self.read_keywords(infile) @@ -43,16 +36,16 @@ class Player: self.gaussian = GaussianInterface(config_data.get("gaussian")) self.dice = DiceInterface(config_data.get("dice")) - def start(self): + def start(self, initial_cycle: int = 1): self.print_keywords() self.create_simulation_dir() self.read_potentials() - # self.print_potentials() + self.print_potentials() - self.dice_start(1) - self.dice_start(2) + for cycle in range(initial_cycle, self.config.maxcyc + 1): + self.dice_start(cycle) def create_simulation_dir(self): simulation_dir_path = Path(self.config.simulation_dir) @@ -61,12 +54,7 @@ class Player: 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}" - ) + simulation_dir_path.mkdir() def print_keywords(self) -> None: @@ -75,38 +63,38 @@ class Player: 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} ]") + logger.info(f"{key} = [ {string} ]") else: - logging.info(f"{key} = {getattr(config, key)}") + logger.info(f"{key} = {getattr(config, key)}") - logging.info( + logger.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") + logger.info("Your python version is {}\n".format(sys.version)) + logger.info("\n") + logger.info("Program started on {}\n".format(weekday_date_time())) + logger.info("\n") + logger.info("Environment variables:\n") for var in ENV: - logging.info( + logger.info( "{} = {}\n".format( var, (os.environ[var] if var in os.environ else "Not set") ) ) - logging.info( + logger.info( "\n==========================================================================================\n" " CONTROL variables being used in this run:\n" "------------------------------------------------------------------------------------------\n" "\n" ) - logging.info("\n") + logger.info("\n") - logging.info( + logger.info( "------------------------------------------------------------------------------------------\n" " DICE variables being used in this run:\n" "------------------------------------------------------------------------------------------\n" @@ -115,9 +103,9 @@ class Player: log_keywords(self.dice.config, DiceDTO) - logging.info("\n") + logger.info("\n") - logging.info( + logger.info( "------------------------------------------------------------------------------------------\n" " GAUSSIAN variables being used in this run:\n" "------------------------------------------------------------------------------------------\n" @@ -126,18 +114,19 @@ class Player: log_keywords(self.gaussian.config, GaussianDTO) - logging.info("\n") + logger.info("\n") def read_potentials(self): - try: + ljname_path = Path(self.dice.config.ljname) + if ljname_path.exists(): with open(self.dice.config.ljname) as file: - ljdata = file.readlines() - except FileNotFoundError: + ljc_data = file.readlines() + else: raise RuntimeError( f"Potential file {self.dice.config.ljname} not found." ) - combrule = ljdata.pop(0).split()[0] + combrule = ljc_data.pop(0).split()[0] if combrule not in ("*", "+"): sys.exit( "Error: expected a '*' or a '+' sign in 1st line of file {}".format( @@ -146,7 +135,7 @@ class Player: ) self.dice.config.combrule = combrule - ntypes = ljdata.pop(0).split()[0] + ntypes = ljc_data.pop(0).split()[0] if not ntypes.isdigit(): sys.exit( "Error: expected an integer in the 2nd line of file {}".format( @@ -157,22 +146,22 @@ class Player: if ntypes != len(self.dice.config.nmol): sys.exit( - f"Error: number of molecule types in file {self.dice.config.ljname}" + 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] + try: + nsites, molname = ljc_data.pop(0).split()[:2] + except ValueError: + raise ValueError( + f"Error: expected nsites and molname for the molecule type {i+1}" + ) 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}" + f"Error: expected nsites to be an integer for molecule type {i+1}" ) nsites = int(nsites) @@ -182,12 +171,68 @@ class Player: for j in range(nsites): new_atom = dict(zip( atom_fields, - ljdata.pop(0).split() + ljc_data.pop(0).split() )) self.system.molecule[i].add_atom( Atom(**self.validate_atom_dict(i, j, new_atom)) ) + def print_potentials(self) -> None: + + formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}" + logger.info( + "==========================================================================================\n" + ) + logger.info( + f" Potential parameters from file {self.dice.config.ljname}:" + ) + logger.info( + "------------------------------------------------------------------------------------------" + "\n" + ) + + logger.info(f"Combination rule: {self.dice.config.combrule}") + logger.info( + f"Types of molecules: {len(self.system.molecule)}\n" + ) + + i = 0 + for mol in self.system.molecule: + i += 1 + logger.info( + "{} atoms in molecule type {}:".format(len(mol.atom), i) + ) + logger.info( + "---------------------------------------------------------------------------------" + ) + logger.info( + "Lbl AN X Y Z Charge Epsilon Sigma Mass" + ) + logger.info( + "---------------------------------------------------------------------------------" + ) + + for atom in mol.atom: + logger.info( + formatstr.format( + atom.lbl, + atom.na, + atom.rx, + atom.ry, + atom.rz, + atom.chg, + atom.eps, + atom.sig, + atom.mass, + ) + ) + + logger.info("\n") + + logger.info( + "==========================================================================================" + ) + def dice_start(self, cycle: int): self.dice.configure( StepDTO( @@ -204,8 +249,8 @@ class Player: self.dice.reset() - def gaussian_start(self): - self.gaussian.start() + def gaussian_start(self, cycle: int): + self.gaussian.start(cycle) @staticmethod def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict: @@ -219,63 +264,63 @@ class Player: try: atom_dict['lbl'] = int(atom_dict['lbl']) - except ValueError: + except Exception: 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: + except Exception: 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: + except Exception: raise ValueError( - f'Invalid rx fields for site {molecule_site} for molecule type {molecule_type}.' + 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: + except Exception: raise ValueError( - f'Invalid ry fields for site {molecule_site} for molecule type {molecule_type}.' + 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: + atom_dict['rz'] = float(atom_dict['rz']) + except Exception: raise ValueError( - f'Invalid rz fields for site {molecule_site} for molecule type {molecule_type}.' + 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: + except Exception: raise ValueError( - f'Invalid chg fields for site {molecule_site} for molecule type {molecule_type}.' + 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: + except Exception: raise ValueError( - f'Invalid eps fields for site {molecule_site} for molecule type {molecule_type}.' + 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: + except Exception: raise ValueError( - f'Invalid sig fields for site {molecule_site} for molecule type {molecule_type}.' + f'Invalid sig fields for site {molecule_site} for molecule type {molecule_type}. ' f'Value must be a float.' ) diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index 89bcbd1..68d4be8 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -3,6 +3,7 @@ from __future__ import annotations from diceplayer.shared.config.dice_dto import DiceDTO from diceplayer.shared.config.step_dto import StepDTO from diceplayer.shared.interface import Interface +from diceplayer import logger from multiprocessing import Process, connection from setproctitle import setproctitle @@ -15,7 +16,6 @@ import time import sys import os - DICE_END_FLAG: Final[str] = "End of simulation" DICE_FLAG_LINE: Final[int] = -2 UMAANG3_TO_GCM3: Final[float] = 1.6605 @@ -41,8 +41,9 @@ class DiceInterface(Interface): procs = [] sentinels = [] - for proc in range(1, self.step.nprocs + 1): + logger.info(f"---------------------- DICE - CYCLE {cycle} --------------------------\n") + for proc in range(1, self.step.nprocs + 1): p = Process(target=self._simulation_process, args=(cycle, proc)) p.start() @@ -61,6 +62,8 @@ class DiceInterface(Interface): p.terminate() sys.exit(status) + logger.info("\n") + def reset(self): del self.step @@ -132,6 +135,11 @@ class DiceInterface(Interface): f"step{cycle:02d}", f"p{proc:02d}" ) + + logger.info( + f"Simulation process {str(proc_dir)} initiated with pid {os.getpid()}" + ) + os.chdir(proc_dir) if not (self.config.randominit == 'first' and cycle > 1): @@ -385,3 +393,5 @@ class DiceInterface(Interface): flag = outfile.readlines()[DICE_FLAG_LINE].strip() if flag != DICE_END_FLAG: raise RuntimeError(f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly") + + logger.info(f"Dice {file_name} - step{cycle:02d}-p{proc:02d} exited properly") diff --git a/diceplayer/shared/interface/gaussian_interface.py b/diceplayer/shared/interface/gaussian_interface.py index 71bdf54..113878a 100644 --- a/diceplayer/shared/interface/gaussian_interface.py +++ b/diceplayer/shared/interface/gaussian_interface.py @@ -14,7 +14,7 @@ class GaussianInterface(Interface): def configure(self): pass - def start(self): + def start(self, cycle: int): pass def reset(self): diff --git a/diceplayer/shared/utils/logger.py b/diceplayer/shared/utils/logger.py index 2ed8372..2404f20 100644 --- a/diceplayer/shared/utils/logger.py +++ b/diceplayer/shared/utils/logger.py @@ -24,15 +24,17 @@ class Logger: if self._logger is None: self._logger = logging.getLogger(logger_name) - def set_logger(self, outfile='run.log', level=logging.INFO): - self.outfile = Path(outfile) - if self.outfile.exists(): - self.outfile.rename(str(self.outfile) + ".backup") + def set_logger(self, outfile='run.log', level=logging.INFO, stream=None): + outfile_path = None + if outfile is not None and stream is None: + outfile_path = Path(outfile) + if outfile_path.exists(): + outfile_path.rename(str(outfile_path) + ".backup") if level is not None: self._logger.setLevel(level) - self._create_handlers() + self._create_handlers(outfile_path, stream) self._was_set = True @@ -52,10 +54,12 @@ class Logger: def error(self, message): self._logger.error(message) - def _create_handlers(self): + def _create_handlers(self, outfile_path: Path, stream): handlers = [] - if self.outfile is not None: - handlers.append(logging.FileHandler(self.outfile, mode='a+')) + if outfile_path is not None: + handlers.append(logging.FileHandler(outfile_path, mode='a+')) + elif stream is not None: + handlers.append(logging.StreamHandler(stream)) else: handlers.append(logging.StreamHandler()) diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index c6bbfdb..6d39c4f 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -2,6 +2,7 @@ from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.atom import Atom from diceplayer.shared.config.step_dto import StepDTO +from diceplayer import logger import io @@ -12,6 +13,9 @@ import unittest class TestDiceInterface(unittest.TestCase): + def setUp(self): + logger.set_logger(stream=io.StringIO()) + def test_class_instantiation(self): dice = DiceInterface( { diff --git a/tests/shared/utils/test_logger.py b/tests/shared/utils/test_logger.py index 482341f..abe41a8 100644 --- a/tests/shared/utils/test_logger.py +++ b/tests/shared/utils/test_logger.py @@ -1,6 +1,7 @@ from diceplayer.shared.utils.logger import Logger, valid_logger import logging +import io from unittest import mock import unittest @@ -35,6 +36,23 @@ class TestLogger(unittest.TestCase): self.assertIsInstance(logger, Logger) + @mock.patch('builtins.open', mock.mock_open()) + def test_set_logger_to_file(self): + logger = Logger('test') + + logger.set_logger(stream=io.StringIO()) + + self.assertIsNotNone(logger._logger) + self.assertEqual(logger._logger.name, 'test') + + def test_set_logger_to_stream(self): + logger = Logger('test') + + logger.set_logger(stream=io.StringIO()) + + self.assertIsNotNone(logger._logger) + self.assertEqual(logger._logger.name, 'test') + @mock.patch('builtins.open', mock.mock_open()) @mock.patch('diceplayer.shared.utils.logger.Path.exists') @mock.patch('diceplayer.shared.utils.logger.Path.rename') @@ -64,6 +82,7 @@ class TestLogger(unittest.TestCase): @mock.patch('builtins.open', mock.mock_open()) def test_close(self): logger = Logger('test') + logger.set_logger() logger.close() @@ -72,7 +91,7 @@ class TestLogger(unittest.TestCase): @mock.patch('builtins.open', mock.mock_open()) def test_info(self): logger = Logger('test') - logger.set_logger() + logger.set_logger(stream=io.StringIO()) with self.assertLogs(level='INFO') as cm: logger.info('test') @@ -82,7 +101,7 @@ class TestLogger(unittest.TestCase): @mock.patch('builtins.open', mock.mock_open()) def test_debug(self): logger = Logger('test') - logger.set_logger(level=logging.DEBUG) + logger.set_logger(stream=io.StringIO(), level=logging.DEBUG) with self.assertLogs(level='DEBUG') as cm: logger.debug('test') @@ -92,7 +111,7 @@ class TestLogger(unittest.TestCase): @mock.patch('builtins.open', mock.mock_open()) def test_warning(self): logger = Logger('test') - logger.set_logger() + logger.set_logger(stream=io.StringIO()) with self.assertLogs(level='WARNING') as cm: logger.warning('test') @@ -102,7 +121,7 @@ class TestLogger(unittest.TestCase): @mock.patch('builtins.open', mock.mock_open()) def test_error(self): logger = Logger('test') - logger.set_logger() + logger.set_logger(stream=io.StringIO()) with self.assertLogs(level='ERROR') as cm: logger.error('test') diff --git a/tests/test_player.py b/tests/test_player.py new file mode 100644 index 0000000..e421331 --- /dev/null +++ b/tests/test_player.py @@ -0,0 +1,424 @@ +from diceplayer.player import Player +from diceplayer import logger + +import io + +from unittest import mock +import unittest + + +def get_config_example(): + return """ +diceplayer: + maxcyc: 3 + opt: no + ncores: 4 + nprocs: 4 + qmprog: 'g16' + lps: no + ghosts: no + altsteps: 20000 + +dice: + nmol: [1, 50] + dens: 0.75 + nstep: [2000, 3000, 4000] + isave: 1000 + outname: 'phb' + progname: '~/.local/bin/dice' + ljname: 'phb.ljc' + randominit: 'first' + +gaussian: + qmprog: 'g16' + level: 'MP2/aug-cc-pVDZ' + keywords: 'freq' +""" + + +def get_potentials_exemple(): + return """\ +* +2 +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_combrule(): + return """\ +. +2 +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_ntypes(): + return """\ +* +a +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_ntypes_config(): + return """\ +* +3 +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_nsites(): + return """\ +* +2 +. TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_molname(): + return """\ +* +2 +1 + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def mock_open(file, *args, **kwargs): + values = { + "control.test.yml": get_config_example(), + "phb.ljc": get_potentials_exemple(), + "phb.error.combrule.ljc": get_potentials_error_combrule(), + "phb.error.ntypes.ljc": get_potentials_error_ntypes(), + "phb.error.ntypes.config.ljc": get_potentials_error_ntypes_config(), + "phb.error.nsites.ljc": get_potentials_error_nsites(), + "phb.error.molname.ljc": get_potentials_error_molname(), + } + mock_file = mock.mock_open(read_data=values[file]) + return mock_file() + + +class TestPlayer(unittest.TestCase): + def setUp(self): + logger.set_logger(stream=io.StringIO()) + + @mock.patch("builtins.open", mock_open) + def test_class_instantiation(self): + # This file does not exist and it will be mocked + player = Player("control.test.yml") + + self.assertIsInstance(player, Player) + + @mock.patch("builtins.open", mock_open) + def test_start(self): + player = Player("control.test.yml") + + player.print_keywords = mock.MagicMock() + player.create_simulation_dir = mock.MagicMock() + player.read_potentials = mock.MagicMock() + player.print_potentials = mock.MagicMock() + player.dice_start = mock.MagicMock() + + player.start(1) + + self.assertTrue(player.print_keywords.called) + self.assertTrue(player.create_simulation_dir.called) + self.assertTrue(player.read_potentials.called) + self.assertTrue(player.print_potentials.called) + self.assertEqual(player.dice_start.call_count, 3) + + @mock.patch("builtins.open", mock_open) + @mock.patch("diceplayer.player.Path") + def test_create_simulation_dir_if_already_exists(self, mock_path): + player = Player("control.test.yml") + mock_path.return_value.exists.return_value = True + + with self.assertRaises(FileExistsError): + player.create_simulation_dir() + + self.assertTrue(mock_path.called) + + @mock.patch("builtins.open", mock_open) + @mock.patch("diceplayer.player.Path") + def test_create_simulation_dir_if_not_exists(self, mock_path): + player = Player("control.test.yml") + mock_path.return_value.exists.return_value = False + + player.create_simulation_dir() + + self.assertTrue(mock_path.called) + + @mock.patch("diceplayer.player.sys") + @mock.patch("diceplayer.player.weekday_date_time") + @mock.patch("builtins.open", mock_open) + def test_print_keywords(self, mock_date_func, mock_sys): + player = Player("control.test.yml") + + mock_sys.version = 'TEST' + mock_date_func.return_value = '00 Test 0000 at 00:00:00' + + with self.assertLogs() as cm: + player.print_keywords() + + expected_output = ['INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n\n', 'INFO:diceplayer:Your python version is TEST\n', 'INFO:diceplayer:\n', 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', 'INFO:diceplayer:\n', 'INFO:diceplayer:Environment variables:\n', 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', 'INFO:diceplayer:\n==========================================================================================\n CONTROL variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', 'INFO:diceplayer:\n', 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', 'INFO:diceplayer:dens = 0.75', 'INFO:diceplayer:isave = 1000', 'INFO:diceplayer:ljname = phb.ljc', 'INFO:diceplayer:nmol = [ 1 50 ]', 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', 'INFO:diceplayer:outname = phb', 'INFO:diceplayer:press = 1.0', 'INFO:diceplayer:progname = ~/.local/bin/dice', 'INFO:diceplayer:randominit = first', 'INFO:diceplayer:temp = 300.0', 'INFO:diceplayer:\n', 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', 'INFO:diceplayer:keywords = freq', 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', 'INFO:diceplayer:pop = chelpg', 'INFO:diceplayer:qmprog = g16', 'INFO:diceplayer:\n'] + + self.assertEqual(cm.output, expected_output) + + def test_validate_atom_dict(self): + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 0, "na": 1, "rx": 1.0, "ry": 1.0, "rz": 1.0, "chg": 1.0, "eps": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid number of fields for site 1 for molecule type 1." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": '', "na": 1, "rx": 1.0, "ry": 1.0, "rz": 1.0, "chg": 1.0, "eps": 1.0, "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid lbl fields for site 1 for molecule type 1." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": '', "rx": 1.0, "ry": 1.0, "rz": 1.0, "chg": 1.0, "eps": 1.0, "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid na fields for site 1 for molecule type 1." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": 1, "rx": '', "ry": 1.0, "rz": 1.0, "chg": 1.0, "eps": 1.0, "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid rx fields for site 1 for molecule type 1. Value must be a float." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": 1, "rx": 1.0, "ry": '', "rz": 1.0, "chg": 1.0, "eps": 1.0, "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid ry fields for site 1 for molecule type 1. Value must be a float." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": 1, "rx": 1.0, "ry": 1.0, "rz": '', "chg": 1.0, "eps": 1.0, "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid rz fields for site 1 for molecule type 1. Value must be a float." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": 1, "rx": 1.0, "ry": 1.0, "rz": 1.0, "chg": '', "eps": 1.0, "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid chg fields for site 1 for molecule type 1. Value must be a float." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": 1, "rx": 1.0, "ry": 1.0, "rz": 1.0, "chg": 1.0, "eps": '', "sig": 1.0 + } + ) + self.assertEqual( + str(context.exception), + "Invalid eps fields for site 1 for molecule type 1. Value must be a float." + ) + + with self.assertRaises(ValueError) as context: + Player.validate_atom_dict( + molecule_type=0, + molecule_site=0, + atom_dict={ + "lbl": 1.0, "na": 1, "rx": 1.0, "ry": 1.0, "rz": 1.0, "chg": 1.0, "eps": 1.0, "sig": '' + } + ) + self.assertEqual( + str(context.exception), + "Invalid sig fields for site 1 for molecule type 1. Value must be a float." + ) + + @mock.patch("builtins.open", mock_open) + @mock.patch("diceplayer.player.Path.exists", return_value=True) + def test_read_potentials(self, mock_path_exists): + player = Player("control.test.yml") + + player.read_potentials() + + self.assertEqual(player.system.molecule[0].molname, "TEST") + self.assertEqual(len(player.system.molecule[0].atom), 1) + + self.assertEqual(player.system.molecule[1].molname, "PLACEHOLDER") + self.assertEqual(len(player.system.molecule[1].atom), 1) + + @mock.patch("builtins.open", mock_open) + @mock.patch("diceplayer.player.Path.exists") + def test_read_potentials_error(self, mock_path_exists): + player = Player("control.test.yml") + + # Testing file not found error + mock_path_exists.return_value = False + with self.assertRaises(RuntimeError) as context: + player.read_potentials() + + self.assertEqual( + str(context.exception), + "Potential file phb.ljc not found." + ) + + # Enabling file found for next tests + mock_path_exists.return_value = True + + # Testing combrule error + with self.assertRaises(SystemExit) as context: + player.dice.config.ljname = "phb.error.combrule.ljc" + player.read_potentials() + + self.assertEqual( + str(context.exception), + "Error: expected a '*' or a '+' sign in 1st line of file phb.error.combrule.ljc" + ) + + # Testing ntypes error + with self.assertRaises(SystemExit) as context: + player.dice.config.ljname = "phb.error.ntypes.ljc" + player.read_potentials() + + self.assertEqual( + str(context.exception), + "Error: expected an integer in the 2nd line of file phb.error.ntypes.ljc" + ) + + # Testing ntypes error on config + with self.assertRaises(SystemExit) as context: + player.dice.config.ljname = "phb.error.ntypes.config.ljc" + player.read_potentials() + + self.assertEqual( + str(context.exception), + "Error: number of molecule types in file phb.error.ntypes.config.ljc " + "must match that of 'nmol' keyword in config file" + ) + + # Testing nsite error + with self.assertRaises(ValueError) as context: + player.dice.config.ljname = "phb.error.nsites.ljc" + player.read_potentials() + + self.assertEqual( + str(context.exception), + "Error: expected nsites to be an integer for molecule type 1" + ) + + # Testing molname error + with self.assertRaises(ValueError) as context: + player.dice.config.ljname = "phb.error.molname.ljc" + player.read_potentials() + + self.assertEqual( + str(context.exception), + "Error: expected nsites and molname for the molecule type 1" + ) + + @mock.patch("builtins.open", mock_open) + @mock.patch("diceplayer.player.Path.exists", return_value=True) + def test_print_potentials(self, mock_path_exists): + player = Player("control.test.yml") + player.read_potentials() + + with self.assertLogs(level='INFO') as context: + player.print_potentials() + + expected_output = ['INFO:diceplayer:==========================================================================================\n', 'INFO:diceplayer: Potential parameters from file phb.ljc:', 'INFO:diceplayer:------------------------------------------------------------------------------------------\n', 'INFO:diceplayer:Combination rule: *', 'INFO:diceplayer:Types of molecules: 2\n', 'INFO:diceplayer:1 atoms in molecule type 1:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', 'INFO:diceplayer:\n', 'INFO:diceplayer:1 atoms in molecule type 2:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', 'INFO:diceplayer:\n', 'INFO:diceplayer:=========================================================================================='] + + self.assertEqual( + context.output, + expected_output + ) + + @mock.patch("builtins.open", mock_open) + def test_dice_start(self): + player = Player("control.test.yml") + player.dice = mock.MagicMock() + player.dice.start = mock.MagicMock() + + player.dice_start(1) + + player.dice.start.assert_called_once() + + @mock.patch("builtins.open", mock_open) + def test_gaussian_start(self): + player = Player("control.test.yml") + player.gaussian = mock.MagicMock() + player.gaussian.start = mock.MagicMock() + + player.gaussian_start(1) + + player.gaussian.start.assert_called_once() + + + +if __name__ == '__main__': + unittest.main() From 33612f2d7b690cd876781b215bf2df88c5f0666c Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Fri, 2 Jun 2023 20:20:38 -0300 Subject: [PATCH 14/18] Implements Refactoring in Player Class and Initial Working Version --- control.example.yml | 30 +- diceplayer/__main__.py | 17 + diceplayer/player.py | 198 ++++-- .../config/{dice_dto.py => dice_config.py} | 4 +- .../{gaussian_dto.py => gaussian_config.py} | 3 +- diceplayer/shared/config/player_config.py | 47 ++ diceplayer/shared/config/player_dto.py | 28 - diceplayer/shared/config/step_dto.py | 22 - diceplayer/shared/environment/molecule.py | 64 +- diceplayer/shared/environment/system.py | 92 ++- diceplayer/shared/interface/__interface.py | 17 +- diceplayer/shared/interface/dice_interface.py | 134 ++-- .../shared/interface/gaussian_interface.py | 380 ++++++++++- tests/mocks/mock_inputs.py | 111 ++++ tests/shared/config/test_dice_dto.py | 20 +- tests/shared/config/test_gaussian_dto.py | 2 +- tests/shared/config/test_player_dto.py | 82 ++- tests/shared/environment/test_system.py | 8 +- tests/shared/interface/test_dice_interface.py | 613 +++--------------- .../interface/test_gaussian_interface.py | 113 ++++ tests/test_player.py | 191 ++---- 21 files changed, 1193 insertions(+), 983 deletions(-) rename diceplayer/shared/config/{dice_dto.py => dice_config.py} (95%) rename diceplayer/shared/config/{gaussian_dto.py => gaussian_config.py} (93%) create mode 100644 diceplayer/shared/config/player_config.py delete mode 100644 diceplayer/shared/config/player_dto.py delete mode 100644 diceplayer/shared/config/step_dto.py create mode 100644 tests/mocks/mock_inputs.py create mode 100644 tests/shared/interface/test_gaussian_interface.py diff --git a/control.example.yml b/control.example.yml index b664d27..f475b7d 100644 --- a/control.example.yml +++ b/control.example.yml @@ -1,24 +1,24 @@ diceplayer: - maxcyc: 3 opt: no - ncores: 4 + mem: 24 + maxcyc: 10 + ncores: 5 nprocs: 4 qmprog: 'g16' lps: no ghosts: no altsteps: 20000 -dice: - nmol: [1, 50] - dens: 0.75 - nstep: [2000, 3000, 4000] - isave: 1000 - outname: 'phb' - progname: '~/.local/bin/dice' - ljname: 'phb.ljc' - randominit: 'first' + dice: + nmol: [1, 1000] + dens: 1.0 + nstep: [2000, 3000] + isave: 1000 + outname: 'phb' + progname: '~/.local/bin/dice' + ljname: 'phb.ljc' + randominit: 'first' -gaussian: - qmprog: 'g16' - level: 'MP2/aug-cc-pVDZ' - keywords: 'freq' + gaussian: + qmprog: 'g16' + level: 'MP2/aug-cc-pVDZ' \ No newline at end of file diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 9a3071c..3bfd18d 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -55,8 +55,25 @@ def main(): player = Player(args.infile) + player.print_keywords() + + player.create_simulation_dir() + + player.read_potentials() + player.print_potentials() + + player.prepare_system() + player.start() + logger.info("\n+" + 88 * "-" + "+\n") + + player.print_results() + + logger.info("\n+" + 88 * "-" + "+\n") + + logger.info("Diceplayer finished successfully \n") + if __name__ == "__main__": main() diff --git a/diceplayer/player.py b/diceplayer/player.py index 25c10a5..7300bd3 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,19 +1,18 @@ from diceplayer.shared.interface.gaussian_interface import GaussianInterface from diceplayer.shared.interface.dice_interface import DiceInterface 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.config.gaussian_config import GaussianDTO +from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.shared.config.dice_config import DiceConfig from diceplayer.shared.utils.misc import weekday_date_time -from diceplayer.shared.config.player_dto import PlayerDTO +from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.system import System -from diceplayer.shared.config.step_dto import StepDTO -from diceplayer.shared.config.dice_dto import DiceDTO from diceplayer.shared.environment.atom import Atom from diceplayer import logger from dataclasses import fields from pathlib import Path -from typing import Type +from typing import Type, List import logging import yaml import sys @@ -33,20 +32,50 @@ class Player: config_data.get("diceplayer") ) - self.gaussian = GaussianInterface(config_data.get("gaussian")) - self.dice = DiceInterface(config_data.get("dice")) + self.dice_interface = DiceInterface() + self.gaussian_interface = GaussianInterface() def start(self, initial_cycle: int = 1): - self.print_keywords() - - self.create_simulation_dir() - - self.read_potentials() - self.print_potentials() + logger.info( + "==========================================================================================\n" + "Starting the iterative process.\n" + "==========================================================================================\n" + ) for cycle in range(initial_cycle, self.config.maxcyc + 1): + + logger.info( + f"------------------------------------------------------------------------------------------\n" + f" Step # {cycle}\n" + f"------------------------------------------------------------------------------------------\n" + ) + self.dice_start(cycle) + try: + self.gaussian_start(cycle) + except StopIteration as e: + break + + def prepare_system(self): + for i, mol in enumerate(self.system.molecule): + logger.info( + f"Molecule {i + 1} - {mol.molname}" + ) + + mol.print_mol_info() + logger.info( + "\n Translating and rotating molecule to standard orientation..." + ) + + mol.standard_orientation() + logger.info("\n Done") + logger.info("\nNew values:\n") + mol.print_mol_info() + + logger.info("\n") + + def create_simulation_dir(self): simulation_dir_path = Path(self.config.simulation_dir) if simulation_dir_path.exists(): @@ -71,13 +100,10 @@ class Player: "##########################################################################################\n" "############# Welcome to DICEPLAYER version 1.0 #############\n" "##########################################################################################\n" - "\n" ) logger.info("Your python version is {}\n".format(sys.version)) - logger.info("\n") logger.info("Program started on {}\n".format(weekday_date_time())) - logger.info("\n") - logger.info("Environment variables:\n") + logger.info("Environment variables:") for var in ENV: logger.info( "{} = {}\n".format( @@ -85,68 +111,55 @@ class Player: ) ) - logger.info( - "\n==========================================================================================\n" - " CONTROL variables being used in this run:\n" - "------------------------------------------------------------------------------------------\n" - "\n" - ) - - logger.info("\n") - logger.info( "------------------------------------------------------------------------------------------\n" " DICE variables being used in this run:\n" "------------------------------------------------------------------------------------------\n" - "\n" ) - log_keywords(self.dice.config, DiceDTO) - - logger.info("\n") + log_keywords(self.config.dice, DiceConfig) logger.info( "------------------------------------------------------------------------------------------\n" " GAUSSIAN variables being used in this run:\n" "------------------------------------------------------------------------------------------\n" - "\n" ) - log_keywords(self.gaussian.config, GaussianDTO) + log_keywords(self.config.gaussian, GaussianDTO) logger.info("\n") def read_potentials(self): - ljname_path = Path(self.dice.config.ljname) + ljname_path = Path(self.config.dice.ljname) if ljname_path.exists(): - with open(self.dice.config.ljname) as file: + with open(self.config.dice.ljname) as file: ljc_data = file.readlines() else: raise RuntimeError( - f"Potential file {self.dice.config.ljname} not found." + f"Potential file {self.config.dice.ljname} not found." ) combrule = ljc_data.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.config.dice.ljname ) ) - self.dice.config.combrule = combrule + self.config.dice.combrule = combrule ntypes = ljc_data.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 + self.config.dice.ljname ) ) ntypes = int(ntypes) - if ntypes != len(self.dice.config.nmol): + if ntypes != len(self.config.dice.nmol): sys.exit( - f"Error: number of molecule types in file {self.dice.config.ljname} " + f"Error: number of molecule types in file {self.config.dice.ljname} " f"must match that of 'nmol' keyword in config file" ) @@ -165,7 +178,7 @@ class Player: ) nsites = int(nsites) - self.system.add_type(nsites, Molecule(molname)) + self.system.add_type(Molecule(molname)) atom_fields = ["lbl", "na", "rx", "ry", "rz", "chg", "eps", "sig"] for j in range(nsites): @@ -178,20 +191,15 @@ class Player: ) def print_potentials(self) -> None: - formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}" logger.info( "==========================================================================================\n" - ) - logger.info( - f" Potential parameters from file {self.dice.config.ljname}:" - ) - logger.info( + f" Potential parameters from file {self.config.dice.ljname}:\n" "------------------------------------------------------------------------------------------" "\n" ) - logger.info(f"Combination rule: {self.dice.config.combrule}") + logger.info(f"Combination rule: {self.config.dice.combrule}") logger.info( f"Types of molecules: {len(self.system.molecule)}\n" ) @@ -229,28 +237,50 @@ class Player: logger.info("\n") - logger.info( - "==========================================================================================" - ) - def dice_start(self, cycle: int): - self.dice.configure( - StepDTO( - ncores=self.config.ncores, - nprocs=self.config.nprocs, - simulation_dir=self.config.simulation_dir, - altsteps=self.config.altsteps, - molecule=self.system.molecule, - nmol=self.system.nmols, - ) + self.dice_interface.configure( + self.config, + self.system, ) - self.dice.start(cycle) + self.dice_interface.start(cycle) - self.dice.reset() + self.dice_interface.reset() def gaussian_start(self, cycle: int): - self.gaussian.start(cycle) + self.gaussian_interface.configure( + self.config, + self.system, + ) + + result = self.gaussian_interface.start(cycle) + + self.gaussian_interface.reset() + + if self.config.opt: + if 'position' not in result: + raise RuntimeError( + 'Optimization failed. No position found in result.' + ) + + self.system.update_molecule(result['position']) + + else: + if 'charges' not in result: + raise RuntimeError( + 'Charges optimization failed. No charges found in result.' + ) + + diff = self.system.molecule[0]\ + .update_charges(result['charges']) + + self.system.print_charges_and_dipole(cycle) + + if diff < self.config.gaussian.chg_tol: + logger.info( + f'Charges converged after {cycle} cycles.' + ) + raise StopIteration() @staticmethod def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict: @@ -326,9 +356,43 @@ class Player: return atom_dict + def print_results(self): + formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}" + + mol = self.system.molecule[0] + logger.info( + "{} atoms in molecule type {}:".format(len(mol.atom), 1) + ) + logger.info( + "---------------------------------------------------------------------------------" + ) + logger.info( + "Lbl AN X Y Z Charge Epsilon Sigma Mass" + ) + logger.info( + "---------------------------------------------------------------------------------" + ) + + for atom in mol.atom: + logger.info( + formatstr.format( + atom.lbl, + atom.na, + atom.rx, + atom.ry, + atom.rz, + atom.chg, + atom.eps, + atom.sig, + atom.mass, + ) + ) + + logger.info("\n") + @staticmethod - def set_config(data: dict) -> PlayerDTO: - return PlayerDTO.from_dict(data) + def set_config(data: dict) -> PlayerConfig: + return PlayerConfig.from_dict(data) @staticmethod def read_keywords(infile) -> dict: diff --git a/diceplayer/shared/config/dice_dto.py b/diceplayer/shared/config/dice_config.py similarity index 95% rename from diceplayer/shared/config/dice_dto.py rename to diceplayer/shared/config/dice_config.py index 07feab0..b2a5b66 100644 --- a/diceplayer/shared/config/dice_dto.py +++ b/diceplayer/shared/config/dice_config.py @@ -6,7 +6,7 @@ from typing import List @dataclass -class DiceDTO(Dataclass): +class DiceConfig(Dataclass): """ Data Transfer Object for the Dice configuration. """ @@ -53,4 +53,4 @@ class DiceDTO(Dataclass): @classmethod def from_dict(cls, param: dict): - return from_dict(DiceDTO, param) + return from_dict(DiceConfig, param) diff --git a/diceplayer/shared/config/gaussian_dto.py b/diceplayer/shared/config/gaussian_config.py similarity index 93% rename from diceplayer/shared/config/gaussian_dto.py rename to diceplayer/shared/config/gaussian_config.py index 7ede18f..b5b24ce 100644 --- a/diceplayer/shared/config/gaussian_dto.py +++ b/diceplayer/shared/config/gaussian_config.py @@ -11,10 +11,11 @@ class GaussianDTO(Dataclass): """ level: str qmprog: str - keywords: str chgmult = [0, 1] pop: str = 'chelpg' + chg_tol: float = 0.01 + keywords: str = None def __post_init__(self): if self.qmprog not in ("g03", "g09", "g16"): diff --git a/diceplayer/shared/config/player_config.py b/diceplayer/shared/config/player_config.py new file mode 100644 index 0000000..75e2b12 --- /dev/null +++ b/diceplayer/shared/config/player_config.py @@ -0,0 +1,47 @@ +from diceplayer.shared.utils.dataclass_protocol import Dataclass +from diceplayer.shared.config.gaussian_config import GaussianDTO +from diceplayer.shared.config.dice_config import DiceConfig + +from dataclasses import dataclass +from dacite import from_dict + + +@dataclass +class PlayerConfig(Dataclass): + """ + Data Transfer Object for the player configuration. + """ + opt: bool + maxcyc: int + nprocs: int + ncores: int + + dice: DiceConfig + gaussian: GaussianDTO + + mem: int = None + switchcyc: int = 3 + 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): + if param['dice'] is None: + raise ValueError( + "Error: 'dice' keyword not specified in config file." + ) + param['dice'] = DiceConfig.from_dict(param['dice']) + + if param['gaussian'] is None: + raise ValueError( + "Error: 'gaussian' keyword not specified in config file." + ) + param['gaussian'] = GaussianDTO.from_dict(param['gaussian']) + + return from_dict(PlayerConfig, param) diff --git a/diceplayer/shared/config/player_dto.py b/diceplayer/shared/config/player_dto.py deleted file mode 100644 index e4fa7bf..0000000 --- a/diceplayer/shared/config/player_dto.py +++ /dev/null @@ -1,28 +0,0 @@ -from diceplayer.shared.utils.dataclass_protocol import Dataclass - -from dataclasses import dataclass -from dacite import from_dict - - -@dataclass -class PlayerDTO(Dataclass): - """ - Data Transfer Object for the player configuration. - """ - opt: bool - maxcyc: int - nprocs: int - ncores: 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/shared/config/step_dto.py b/diceplayer/shared/config/step_dto.py deleted file mode 100644 index 32ab6d9..0000000 --- a/diceplayer/shared/config/step_dto.py +++ /dev/null @@ -1,22 +0,0 @@ -from diceplayer.shared.environment.molecule import Molecule -from diceplayer.shared.config.player_dto import PlayerDTO - -from dataclasses import dataclass -from typing import List - - -@dataclass -class StepDTO: - """ - Data Transfer Object for the step configuration. - """ - ncores: int - nprocs: int - simulation_dir: str - - altsteps: int - - nmol: List[int] = None - molecule: List[Molecule] = None - charges: List[float] = None - position: List[float] = None diff --git a/diceplayer/shared/environment/molecule.py b/diceplayer/shared/environment/molecule.py index 390f3fc..6b89278 100644 --- a/diceplayer/shared/environment/molecule.py +++ b/diceplayer/shared/environment/molecule.py @@ -1,15 +1,18 @@ -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 +from __future__ import annotations +from diceplayer.shared.utils.ptable import ghost_number from diceplayer.shared.environment.atom import Atom from diceplayer.shared.utils.misc import BOHR2ANG -from diceplayer.shared.utils.ptable import ghost_number +from diceplayer import logger + +from nptyping import NDArray, Shape, Float +from numpy.linalg import linalg +import numpy as np + +from typing import List, Any, Tuple, Union +from copy import deepcopy +import logging +import math class Molecule: @@ -185,11 +188,18 @@ class Molecule: return position - def update_charges(self, charges: List[float]) -> None: - + def update_charges(self, charges: NDArray) -> int: + """ + Updates the charges of the atoms of the molecule and + returns the max difference between the new and old charges + """ + diff = 0 for i, atom in enumerate(self.atom): + diff = max(diff, abs(atom.chg - charges[i])) atom.chg = charges[i] + return diff + # @staticmethod # def update_hessian( # step: np.ndarray, @@ -299,48 +309,48 @@ class Molecule: Prints the Molecule information into a Output File """ - logging.info( - " Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )\n".format( + logger.info( + " Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )".format( self.com[0], self.com[1], self.com[2] ) ) inertia = self.inertia_tensor() evals, evecs = self.principal_axes() - logging.info( - " Moments of inertia = {:>9E} {:>9E} {:>9E}\n".format( + logger.info( + " Moments of inertia = {:>9E} {:>9E} {:>9E}".format( evals[0], evals[1], evals[2] ) ) - logging.info( - " Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( + logger.info( + " Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format( evecs[0, 0], evecs[1, 0], evecs[2, 0] ) ) - logging.info( - " Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( + logger.info( + " Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format( evecs[0, 1], evecs[1, 1], evecs[2, 1] ) ) - logging.info( - " Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( + logger.info( + " Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format( evecs[0, 2], evecs[1, 2], evecs[2, 2] ) ) sizes = self.sizes_of_molecule() - logging.info( - " Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )\n".format( + logger.info( + " Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )".format( sizes[0], sizes[1], sizes[2] ) ) - logging.info(" Total mass = {:>8.2f} au\n".format(self.total_mass)) + logger.info(" Total mass = {:>8.2f} au".format(self.total_mass)) chg_dip = self.charges_and_dipole() - 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( + logger.info(" Total charge = {:>8.4f} e".format(chg_dip[0])) + logger.info( + " Dipole moment = ( {:>9.4f} , {:>9.4f} , {:>9.4f} ) Total = {:>9.4f} Debye".format( chg_dip[1], chg_dip[2], chg_dip[3], chg_dip[4] ) ) diff --git a/diceplayer/shared/environment/system.py b/diceplayer/shared/environment/system.py index 1a6aff7..8034877 100644 --- a/diceplayer/shared/environment/system.py +++ b/diceplayer/shared/environment/system.py @@ -1,6 +1,7 @@ from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.utils.ptable import atomsymb from diceplayer.shared.utils.misc import BOHR2ANG +from diceplayer import logger from typing import List, Tuple, TextIO from copy import deepcopy @@ -11,50 +12,42 @@ import math class System: """ - System class declaration. This class is used throughout the DicePlayer program to represent the system containing the molecules. + System class declaration. This class is used throughout the DicePlayer program to represent the system containing the molecules. - Atributes: - molecule (List[Molecule]): List of molecules of the system - nmols (List[int]): List of number of molecules in the system - """ + Atributes: + molecule (List[Molecule]): List of molecules of the system + nmols (List[int]): List of number of molecules in the system + """ def __init__(self) -> None: """ - Initializes a empty system object that will be populated afterwards - """ - - self.molecule: List[Molecule] = [] - self.nmols: List[int] = [] - - def add_type(self, nmols: int, m: Molecule) -> None: + Initializes an empty system object that will be populated afterwards """ - Adds a new molecule type to the system + self.nmols: List[int] = [] + self.molecule: List[Molecule] = [] - Args: - nmols (int): Number of molecules of the new type in the system - m (Molecule): The instance of the new type of molecule - """ + def add_type(self, m: Molecule) -> None: + """ + Adds a new molecule type to the system + + Args: + m (Molecule): The instance of the new type of molecule + """ if isinstance(m, Molecule) is False: raise TypeError("Error: molecule is not a Molecule instance") self.molecule.append(m) - if isinstance(nmols, int) is False: - raise TypeError("Error: nmols is not an integer") - self.nmols.append(nmols) - - def update_molecule(self, position: np.ndarray, fh: TextIO) -> None: + def update_molecule(self, position: np.ndarray) -> None: """Updates the position of the molecule in the Output file - Args: - position (np.ndarray): numpy position vector - fh (TextIO): Output file - """ + Args: + position (np.ndarray): numpy position vector + """ position_in_ang = (position * BOHR2ANG).tolist() - self.add_type(self.nmols[0], deepcopy(self.molecule[0])) + self.add_type(deepcopy(self.molecule[0])) for atom in self.molecule[-1].atom: - atom.rx = position_in_ang.pop(0) atom.ry = position_in_ang.pop(0) atom.rz = position_in_ang.pop(0) @@ -62,8 +55,8 @@ class System: rmsd, self.molecule[0] = self.rmsd_fit(-1, 0) self.molecule.pop(-1) - fh.write("\nProjected new conformation of reference molecule with RMSD fit\n") - fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd)) + logger.info("Projected new conformation of reference molecule with RMSD fit") + logger.info(f"RMSD = {rmsd:>8.5f} Angstrom") def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]: @@ -200,7 +193,6 @@ class System: # # return min_dist, nearestmol - # def print_geom(self, cycle: int, fh: TextIO) -> None: # """ # Print the geometry of the molecule in the Output file @@ -220,22 +212,22 @@ class System: # ) # ) # - # def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None: - # """ - # Print the charges and dipole of the molecule in the Output file - # - # Args: - # cycle (int): Number of the cycle - # fh (TextIO): Output file - # """ - # - # fh.write("Cycle # {}\n".format(cycle)) - # fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) - # - # chargesAndDipole = self.molecule[0].charges_and_dipole() - # - # fh.write( - # "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( - # chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4] - # ) - # ) + def print_charges_and_dipole(self, cycle: int) -> None: + """ + Print the charges and dipole of the molecule in the Output file + + Args: + cycle (int): Number of the cycle + fh (TextIO): Output file + """ + + logger.info("Cycle # {}\n".format(cycle)) + logger.info("Number of site: {}\n".format(len(self.molecule[0].atom))) + + chargesAndDipole = self.molecule[0].charges_and_dipole() + + logger.info( + "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( + chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4] + ) + ) diff --git a/diceplayer/shared/interface/__interface.py b/diceplayer/shared/interface/__interface.py index c468cf4..bede652 100644 --- a/diceplayer/shared/interface/__interface.py +++ b/diceplayer/shared/interface/__interface.py @@ -1,20 +1,23 @@ -from diceplayer.shared.utils.dataclass_protocol import Dataclass +from __future__ import annotations + +from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.shared.environment.system import System from abc import ABC, abstractmethod class Interface(ABC): __slots__ = [ - 'config' + 'step', + 'system' ] - @abstractmethod - def __init__(self, data: dict): - pass + def __init__(self): + self.system: System | None = None + self.step: PlayerConfig | None = None - @staticmethod @abstractmethod - def set_config(data: dict) -> Dataclass: + def configure(self, step: PlayerConfig, system: System): pass @abstractmethod diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index 68d4be8..5b754a6 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -1,7 +1,7 @@ from __future__ import annotations -from diceplayer.shared.config.dice_dto import DiceDTO -from diceplayer.shared.config.step_dto import StepDTO +from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.shared.environment.system import System from diceplayer.shared.interface import Interface from diceplayer import logger @@ -26,23 +26,14 @@ MAX_SEED: Final[int] = 4294967295 class DiceInterface(Interface): title = "Diceplayer run" - def __init__(self, data: dict): - self.config: DiceDTO = self.set_config(data) - self.step: StepDTO | None = None - - @staticmethod - def set_config(data: dict) -> DiceDTO: - return DiceDTO.from_dict(data) - - def configure(self, step: any): + def configure(self, step: PlayerConfig, system: System): self.step = step + self.system = system def start(self, cycle: int): procs = [] sentinels = [] - logger.info(f"---------------------- DICE - CYCLE {cycle} --------------------------\n") - for proc in range(1, self.step.nprocs + 1): p = Process(target=self._simulation_process, args=(cycle, proc)) p.start() @@ -66,6 +57,7 @@ class DiceInterface(Interface): def reset(self): del self.step + del self.system def _simulation_process(self, cycle: int, proc: int): setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}") @@ -102,7 +94,7 @@ class DiceInterface(Interface): # This is logic is used to make the initial configuration file # for the next cycle using the last.xyz file from the previous cycle. - if self.config.randominit == 'first' and cycle > 1: + if self.step.dice.randominit == 'first' and cycle > 1: last_xyz = Path( self.step.simulation_dir, f"step{(cycle - 1):02d}", @@ -115,15 +107,15 @@ class DiceInterface(Interface): with open(last_xyz, 'r') as last_xyz_file: self._make_init_file(proc_dir, last_xyz_file) last_xyz_file.seek(0) - self.config.dens = self._new_density(last_xyz_file) + self.step.dice.dens = self._new_density(last_xyz_file) else: self._make_nvt_ter(cycle, proc_dir) - if len(self.config.nstep) == 2: - self._make_nvt_eq(proc_dir) + if len(self.step.dice.nstep) == 2: + self._make_nvt_eq(cycle, proc_dir) - elif len(self.config.nstep) == 3: + elif len(self.step.dice.nstep) == 3: self._make_npt_ter(cycle, proc_dir) self._make_npt_eq(proc_dir) @@ -142,13 +134,13 @@ class DiceInterface(Interface): os.chdir(proc_dir) - if not (self.config.randominit == 'first' and cycle > 1): + if not (self.step.dice.randominit == 'first' and cycle > 1): self.run_dice_file(cycle, proc, "NVT.ter") - if len(self.config.nstep) == 2: + if len(self.step.dice.nstep) == 2: self.run_dice_file(cycle, proc, "NVT.eq") - elif len(self.config.nstep) == 3: + elif len(self.step.dice.nstep) == 3: self.run_dice_file(cycle, proc, "NPT.ter") self.run_dice_file(cycle, proc, "NPT.eq") @@ -175,15 +167,15 @@ class DiceInterface(Interface): xyz_lines = last_xyz_file.readlines() nsites_mm = 0 - for i in range(1, len(self.step.nmol)): - nsites_mm += self.step.nmol[i] * len(self.step.molecule[i].atom) + for i in range(1, len(self.step.dice.nmol)): + nsites_mm += self.step.dice.nmol[i] * len(self.system.molecule[i].atom) xyz_lines = xyz_lines[-nsites_mm:] - input_file = Path(proc_dir, self.config.outname + ".xy") + input_file = Path(proc_dir, self.step.dice.outname + ".xy") with open(input_file, 'w') as f: - for atom in self.step.molecule[0].atom: + for atom in self.system.molecule[0].atom: f.write( f"{atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n" ) @@ -204,8 +196,8 @@ class DiceInterface(Interface): 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] + for i in range(len(self.system.molecule)): + total_mass += self.system.molecule[i].total_mass * self.step.dice.nmol[i] density = (total_mass / volume) * UMAANG3_TO_GCM3 @@ -216,21 +208,21 @@ class DiceInterface(Interface): with open(file, 'w') as f: f.write(f"title = {self.title} - NVT Thermalization\n") f.write(f"ncores = {self.step.ncores}\n") - f.write(f"ljname = {self.config.ljname}\n") - f.write(f"outname = {self.config.outname}\n") + f.write(f"ljname = {self.step.dice.ljname}\n") + f.write(f"outname = {self.step.dice.outname}\n") - mol_string = " ".join(str(x) for x in self.config.nmol) + mol_string = " ".join(str(x) for x in self.step.dice.nmol) f.write(f"nmol = {mol_string}\n") - f.write(f"dens = {self.config.dens}\n") - f.write(f"temp = {self.config.temp}\n") + f.write(f"dens = {self.step.dice.dens}\n") + f.write(f"temp = {self.step.dice.temp}\n") - if self.config.randominit == "first" and cycle > 1: + if self.step.dice.randominit == "first" and cycle > 1: f.write(f"init = yesreadxyz\n") f.write(f"nstep = {self.step.altsteps}\n") else: f.write(f"init = yes\n") - f.write(f"nstep = {self.config.nstep[0]}\n") + f.write(f"nstep = {self.step.dice.nstep[0]}\n") f.write("vstep = 0\n") f.write("mstop = 1\n") @@ -241,30 +233,36 @@ class DiceInterface(Interface): seed = int(1e6 * random.random()) f.write(f"seed = {seed}\n") - f.write(f"upbuf = {self.config.upbuf}") + f.write(f"upbuf = {self.step.dice.upbuf}") - def _make_nvt_eq(self, proc_dir): + def _make_nvt_eq(self, cycle, proc_dir): file = Path(proc_dir, "NVT.eq") with open(file, 'w') as f: f.write(f"title = {self.title} - NVT Production\n") f.write(f"ncores = {self.step.ncores}\n") - f.write(f"ljname = {self.config.ljname}\n") - f.write(f"outname = {self.config.outname}\n") + f.write(f"ljname = {self.step.dice.ljname}\n") + f.write(f"outname = {self.step.dice.outname}\n") - mol_string = " ".join(str(x) for x in self.config.nmol) + mol_string = " ".join(str(x) for x in self.step.dice.nmol) f.write(f"nmol = {mol_string}\n") - f.write(f"dens = {self.config.dens}\n") - f.write(f"temp = {self.config.temp}\n") - f.write("init = no\n") - f.write(f"nstep = {self.config.nstep[1]}\n") + f.write(f"dens = {self.step.dice.dens}\n") + f.write(f"temp = {self.step.dice.temp}\n") + + if self.step.dice.randominit == "first" and cycle > 1: + f.write("init = yesreadxyz\n") + else: + f.write("init = no\n") + + f.write(f"nstep = {self.step.dice.nstep[1]}\n") + f.write("vstep = 0\n") f.write("mstop = 1\n") f.write("accum = no\n") f.write("iprint = 1\n") - f.write(f"isave = {self.config.isave}\n") + f.write(f"isave = {self.step.dice.isave}\n") f.write(f"irdf = {10 * self.step.nprocs}\n") seed = int(1e6 * random.random()) @@ -276,22 +274,22 @@ class DiceInterface(Interface): with open(file, 'w') as f: f.write(f"title = {self.title} - NPT Thermalization\n") f.write(f"ncores = {self.step.ncores}\n") - f.write(f"ljname = {self.config.ljname}\n") - f.write(f"outname = {self.config.outname}\n") + f.write(f"ljname = {self.step.dice.ljname}\n") + f.write(f"outname = {self.step.dice.outname}\n") - mol_string = " ".join(str(x) for x in self.config.nmol) + mol_string = " ".join(str(x) for x in self.step.dice.nmol) f.write(f"nmol = {mol_string}\n") - f.write(f"press = {self.config.press}\n") - f.write(f"temp = {self.config.temp}\n") + f.write(f"press = {self.step.dice.press}\n") + f.write(f"temp = {self.step.dice.temp}\n") - if self.config.randominit == "first" and cycle > 1: + if self.step.dice.randominit == "first" and cycle > 1: f.write("init = yesreadxyz\n") - f.write(f"dens = {self.config.dens:<8.4f}\n") + f.write(f"dens = {self.step.dice.dens:<8.4f}\n") f.write(f"vstep = {int(self.step.altsteps / 5)}\n") else: f.write("init = no\n") - f.write(f"vstep = {int(self.config.nstep[1] / 5)}\n") + f.write(f"vstep = {int(self.step.dice.nstep[1] / 5)}\n") f.write("nstep = 5\n") f.write("mstop = 1\n") @@ -308,23 +306,23 @@ class DiceInterface(Interface): with open(file, 'w') as f: f.write(f"title = {self.title} - NPT Production\n") f.write(f"ncores = {self.step.ncores}\n") - f.write(f"ljname = {self.config.ljname}\n") - f.write(f"outname = {self.config.outname}\n") + f.write(f"ljname = {self.step.dice.ljname}\n") + f.write(f"outname = {self.step.dice.outname}\n") - mol_string = " ".join(str(x) for x in self.config.nmol) + mol_string = " ".join(str(x) for x in self.step.dice.nmol) f.write(f"nmol = {mol_string}\n") - f.write(f"press = {self.config.press}\n") - f.write(f"temp = {self.config.temp}\n") + f.write(f"press = {self.step.dice.press}\n") + f.write(f"temp = {self.step.dice.temp}\n") f.write(f"nstep = 5\n") - f.write(f"vstep = {int(self.config.nstep[2] / 5)}\n") + f.write(f"vstep = {int(self.step.dice.nstep[2] / 5)}\n") f.write("init = no\n") f.write("mstop = 1\n") f.write("accum = no\n") f.write("iprint = 1\n") - f.write(f"isave = {self.config.isave}\n") + f.write(f"isave = {self.step.dice.isave}\n") f.write(f"irdf = {10 * self.step.nprocs}\n") seed = int(1e6 * random.random()) @@ -333,15 +331,15 @@ class DiceInterface(Interface): def _make_potentials(self, proc_dir): fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n" - file = Path(proc_dir, self.config.ljname) + file = Path(proc_dir, self.step.dice.ljname) with open(file, 'w') as f: - f.write(f"{self.config.combrule}\n") - f.write(f"{len(self.step.nmol)}\n") + f.write(f"{self.step.dice.combrule}\n") + f.write(f"{len(self.step.dice.nmol)}\n") - nsites_qm = len(self.step.molecule[0].atom) - f.write(f"{nsites_qm} {self.step.molecule[0].molname}\n") + nsites_qm = len(self.system.molecule[0].atom) + f.write(f"{nsites_qm} {self.system.molecule[0].molname}\n") - for atom in self.step.molecule[0].atom: + for atom in self.system.molecule[0].atom: f.write( fstr.format( atom.lbl, @@ -355,7 +353,7 @@ class DiceInterface(Interface): ) ) - for mol in self.step.molecule[1:]: + for mol in self.system.molecule[1:]: f.write(f"{len(mol.atom)} {mol.molname}\n") for atom in mol.atom: f.write( @@ -378,12 +376,12 @@ class DiceInterface(Interface): [ "bash", "-c", - f"exec -a dice-step{cycle}-p{proc} {self.config.progname} < {infile.name} > {outfile.name}", + f"exec -a dice-step{cycle}-p{proc} {self.step.dice.progname} < {infile.name} > {outfile.name}", ] ) else: exit_status = subprocess.call( - self.config.progname, stdin=infile, stdout=outfile + self.step.dice.progname, stdin=infile, stdout=outfile ) if exit_status != 0: diff --git a/diceplayer/shared/interface/gaussian_interface.py b/diceplayer/shared/interface/gaussian_interface.py index 113878a..ee9dc00 100644 --- a/diceplayer/shared/interface/gaussian_interface.py +++ b/diceplayer/shared/interface/gaussian_interface.py @@ -1,22 +1,380 @@ -from diceplayer.shared.config.gaussian_dto import GaussianDTO +from __future__ import annotations + +from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.environment.system import System +from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.utils.misc import date_time +from diceplayer.shared.utils.ptable import atomsymb from diceplayer.shared.interface import Interface +from diceplayer import logger + +from typing import Tuple, List, Dict, Any + +from nptyping import NDArray +import numpy as np + +from pathlib import Path +import subprocess +import textwrap +import shutil +import os class GaussianInterface(Interface): + def configure(self, step_dto: PlayerConfig, system: System): + self.system = system + self.step = step_dto - def __init__(self, data: dict): - self.config: GaussianDTO = self.set_config(data) + def start(self, cycle: int) -> Dict[str, NDArray]: + self._make_qm_dir(cycle) - @staticmethod - def set_config(data: dict) -> GaussianDTO: - return GaussianDTO.from_dict(data) + if cycle > 1: + self._copy_chk_file_from_previous_step(cycle) - def configure(self): - pass + asec_charges = self.populate_asec_vdw(cycle) + self._make_gaussian_input_file( + cycle, + asec_charges + ) - def start(self, cycle: int): - pass + self._run_gaussian(cycle) + self._run_formchk(cycle) + + return_value = {} + if self.step.opt: + # return_value['position'] = np.array( + # self._run_optimization(cycle) + # ) + raise NotImplementedError("Optimization not implemented yet.") + + else: + return_value['charges'] = np.array( + self._read_charges_from_fchk(cycle) + ) + + return return_value def reset(self): - pass + del self.step + del self.system + def _make_qm_dir(self, cycle: int): + qm_dir_path = Path( + self.step.simulation_dir, + f"step{cycle:02d}", + "qm" + ) + if not qm_dir_path.exists(): + qm_dir_path.mkdir() + + def _copy_chk_file_from_previous_step(self, cycle: int): + current_chk_file_path = Path( + self.step.simulation_dir, + f"step{cycle:02d}", + "qm", + f"asec.chk" + ) + if current_chk_file_path.exists(): + raise FileExistsError( + f"File {current_chk_file_path} already exists." + ) + + previous_chk_file_path = Path( + self.step.simulation_dir, + f"step{(cycle - 1):02d}", + "qm", + f"asec.chk" + ) + if not previous_chk_file_path.exists(): + raise FileNotFoundError( + f"File {previous_chk_file_path} does not exist." + ) + + shutil.copy(previous_chk_file_path, current_chk_file_path) + + def populate_asec_vdw(self, cycle: int) -> list[dict]: + norm_factor = self._calculate_norm_factor() + + nsitesref = len(self.system.molecule[0].atom) + + nsites_total = self._calculate_total_number_of_sites(nsitesref) + + proc_charges = [] + for proc in range(1, self.step.nprocs + 1): + proc_charges.append(self._read_charges_from_last_step(cycle, proc)) + + asec_charges, thickness, picked_mols = \ + self._evaluate_proc_charges(nsites_total, proc_charges) + + logger.info(f"In average, {(sum(picked_mols) / norm_factor):^7.2f} molecules\n" + f"were selected from each of the {len(picked_mols)} configurations\n" + f"of the production simulations to form the ASEC, comprising a shell with\n" + f"minimum thickness of {(sum(thickness) / norm_factor):>6.2f} Angstrom\n" + ) + + for charge in asec_charges: + charge['chg'] = charge['chg'] / norm_factor + + return asec_charges + + def _calculate_norm_factor(self) -> int: + if self.step.dice.nstep[-1] % self.step.dice.isave == 0: + nconfigs = round(self.step.dice.nstep[-1] / self.step.dice.isave) + else: + nconfigs = int(self.step.dice.nstep[-1] / self.step.dice.isave) + + return nconfigs * self.step.nprocs + + def _calculate_total_number_of_sites(self, nsitesref) -> int: + nsites_total = self.step.dice.nmol[0] * nsitesref + for i in range(1, len(self.step.dice.nmol)): + nsites_total += self.step.dice.nmol[i] * len(self.system.molecule[i].atom) + + return nsites_total + + def _read_charges_from_last_step(self, cycle: int, proc: int) -> list[str]: + last_xyz_file_path = Path( + self.step.simulation_dir, + f"step{cycle:02d}", + f"p{proc:02d}", + "last.xyz" + ) + if not last_xyz_file_path.exists(): + raise FileNotFoundError( + f"File {last_xyz_file_path} does not exist." + ) + + with open(last_xyz_file_path, 'r') as last_xyz_file: + lines = last_xyz_file.readlines() + + return lines + + def _evaluate_proc_charges(self, total_nsites: int, proc_charges: list[list[str]]) -> Tuple[ + List[Dict[str, float | Any]], List[float], List[int]]: + asec_charges = [] + + thickness = [] + picked_mols = [] + + for charges in proc_charges: + charges_nsites = int(charges.pop(0)) + if int(charges_nsites) != total_nsites: + raise ValueError( + f"Number of sites does not match total number of sites." + ) + + thickness.append( + self._calculate_proc_thickness(charges) + ) + nsites_ref_mol = len(self.system.molecule[0].atom) + charges = charges[nsites_ref_mol:] + + mol_count = 0 + for type in range(len(self.step.dice.nmol)): + if type == 0: + # Reference Molecule must be ignored from type 0 + nmols = self.step.dice.nmol[type] - 1 + else: + nmols = self.step.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 = charges.pop(0).split() + + if line[0].title() != atomsymb[self.system.molecule[type].atom[site].na].strip(): + raise SyntaxError( + f"Error: Invalid Dice Output. Atom type does not match." + ) + + 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, + ) + ) + + distance = self.system.molecule[0] \ + .minimum_distance(new_molecule) + + if distance < thickness[-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} + ) + mol_count += 1 + + picked_mols.append(mol_count) + + return asec_charges, thickness, picked_mols + + def _calculate_proc_thickness(self, charges: list[str]) -> float: + box = charges.pop(0).split()[-3:] + box = [float(box[0]), float(box[1]), float(box[2])] + sizes = self.system.molecule[0].sizes_of_molecule() + + return min( + [ + (box[0] - sizes[0]) / 2, + (box[1] - sizes[1]) / 2, + (box[2] - sizes[2]) / 2, + ] + ) + + def _make_gaussian_input_file(self, cycle: int, asec_charges: list[dict]) -> None: + gaussian_input_file_path = Path( + self.step.simulation_dir, + f"step{cycle:02d}", + "qm", + f"asec.gjf" + ) + + with open(gaussian_input_file_path, 'w') as gaussian_input_file: + gaussian_input_file.writelines( + self._generate_gaussian_input(cycle, asec_charges) + ) + + def _generate_gaussian_input(self, cycle: int, asec_charges: list[dict]) -> list[str]: + gaussian_input = ["%Chk=asec.chk\n"] + + if self.step.mem is not None: + gaussian_input.append(f"%Mem={self.step.mem}GB\n") + + gaussian_input.append(f"%Nprocs={self.step.nprocs * self.step.ncores}\n") + + kwords_line = f"#P {self.step.gaussian.level}" + + if self.step.gaussian.keywords: + kwords_line += " " + self.step.gaussian.keywords + + if self.step.opt == "yes": + kwords_line += " Force" + + kwords_line += " NoSymm" + kwords_line += f" Pop={self.step.gaussian.pop} Density=Current" + + if cycle > 1: + kwords_line += " Guess=Read" + + gaussian_input.append(textwrap.fill(kwords_line, 90)) + gaussian_input.append("\n") + + gaussian_input.append("\nForce calculation - Cycle number {}\n".format(cycle)) + gaussian_input.append("\n") + gaussian_input.append(f"{self.step.gaussian.chgmult[0]},{self.step.gaussian.chgmult[1]}\n") + + for atom in self.system.molecule[0].atom: + symbol = atomsymb[atom.na] + gaussian_input.append( + "{:<2s} {:>10.5f} {:>10.5f} {:>10.5f}\n".format( + symbol, atom.rx, atom.ry, atom.rz + ) + ) + + gaussian_input.append("\n") + + for charge in asec_charges: + gaussian_input.append( + "{:>10.5f} {:>10.5f} {:>10.5f} {:>11.8f}\n".format( + charge['rx'], charge['ry'], charge['rz'], charge['chg'] + ) + ) + + gaussian_input.append("\n") + + return gaussian_input + + def _run_gaussian(self, cycle: int) -> None: + qm_dir = Path( + self.step.simulation_dir, + f"step{(cycle):02d}", + "qm" + ) + + working_dir = os.getcwd() + os.chdir(qm_dir) + + infile = "asec.gjf" + + operation = None + if self.step.opt: + operation = "forces" + else: + operation = "charges" + + logger.info( + f"Calculation of {operation} initiated with Gaussian on {date_time()}\n" + ) + + if shutil.which("bash") is not None: + exit_status = subprocess.call( + [ + "bash", + "-c", + "exec -a {}-step{} {} {}".format( + self.step.gaussian.qmprog, cycle, self.step.gaussian.qmprog, infile + ), + ] + ) + else: + exit_status = subprocess.call([self.step.gaussian.qmprog, infile]) + + if exit_status != 0: + raise SystemError("Gaussian process did not exit properly") + + logger.info(f"Calculation of {operation} finished on {date_time()}") + + os.chdir(working_dir) + + def _run_formchk(self, cycle: int): + qm_dir = Path( + self.step.simulation_dir, + f"step{(cycle):02d}", + "qm" + ) + + work_dir = os.getcwd() + os.chdir(qm_dir) + + logger.info("Formatting the checkpoint file... \n") + + exit_status = subprocess.call(["formchk", "asec.chk"], stdout=subprocess.DEVNULL) + + if exit_status != 0: + raise SystemError("Formchk process did not exit properly") + + logger.info("Done\n") + + os.chdir(work_dir) + + def _read_charges_from_fchk(self, cycle: int): + fchk_file_path = Path( + "simfiles", + f"step{cycle:02d}", + "qm", + "asec.fchk" + ) + with open(fchk_file_path) as fchk: + fchkfile = fchk.readlines() + + if self.step.gaussian.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.system.molecule[0].atom): + charges.extend([float(x) for x in fchkfile.pop(0).split()]) + + return charges diff --git a/tests/mocks/mock_inputs.py b/tests/mocks/mock_inputs.py new file mode 100644 index 0000000..406a35a --- /dev/null +++ b/tests/mocks/mock_inputs.py @@ -0,0 +1,111 @@ +from unittest import mock + + +def get_config_example(): + return """ +diceplayer: + opt: no + mem: 12 + maxcyc: 3 + ncores: 4 + nprocs: 4 + qmprog: 'g16' + lps: no + ghosts: no + altsteps: 20000 + + dice: + nmol: [1, 50] + dens: 0.75 + nstep: [2000, 3000, 4000] + isave: 1000 + outname: 'phb' + progname: '~/.local/bin/dice' + ljname: 'phb.ljc' + randominit: 'first' + + gaussian: + qmprog: 'g16' + level: 'MP2/aug-cc-pVDZ' + keywords: 'freq' +""" + + +def get_potentials_exemple(): + return """\ +* +2 +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_combrule(): + return """\ +. +2 +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_ntypes(): + return """\ +* +a +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_ntypes_config(): + return """\ +* +3 +1 TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_nsites(): + return """\ +* +2 +. TEST + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def get_potentials_error_molname(): + return """\ +* +2 +1 + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +1 PLACEHOLDER + 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 +""" + + +def mock_open(file, *args, **kwargs): + values = { + "control.test.yml": get_config_example(), + "phb.ljc": get_potentials_exemple(), + "phb.error.combrule.ljc": get_potentials_error_combrule(), + "phb.error.ntypes.ljc": get_potentials_error_ntypes(), + "phb.error.ntypes.config.ljc": get_potentials_error_ntypes_config(), + "phb.error.nsites.ljc": get_potentials_error_nsites(), + "phb.error.molname.ljc": get_potentials_error_molname(), + } + mock_file = mock.mock_open(read_data=values[file]) + return mock_file() \ No newline at end of file diff --git a/tests/shared/config/test_dice_dto.py b/tests/shared/config/test_dice_dto.py index 553e1f1..9117e46 100644 --- a/tests/shared/config/test_dice_dto.py +++ b/tests/shared/config/test_dice_dto.py @@ -1,11 +1,11 @@ -from diceplayer.shared.config.dice_dto import DiceDTO +from diceplayer.shared.config.dice_config import DiceConfig import unittest class TestDiceDto(unittest.TestCase): def test_class_instantiation(self): - dice_dto = DiceDTO( + dice_dto = DiceConfig( ljname='test', outname='test', dens=1.0, @@ -13,11 +13,11 @@ class TestDiceDto(unittest.TestCase): nstep=[1, 1], ) - self.assertIsInstance(dice_dto, DiceDTO) + self.assertIsInstance(dice_dto, DiceConfig) def test_validate_jname(self): with self.assertRaises(ValueError) as ex: - DiceDTO( + DiceConfig( ljname=None, outname='test', dens=1.0, @@ -28,7 +28,7 @@ class TestDiceDto(unittest.TestCase): def test_validate_outname(self): with self.assertRaises(ValueError) as ex: - DiceDTO( + DiceConfig( ljname='test', outname=None, dens=1.0, @@ -39,7 +39,7 @@ class TestDiceDto(unittest.TestCase): def test_validate_dens(self): with self.assertRaises(ValueError) as ex: - DiceDTO( + DiceConfig( ljname='test', outname='test', dens=None, @@ -50,7 +50,7 @@ class TestDiceDto(unittest.TestCase): def test_validate_nmol(self): with self.assertRaises(ValueError) as ex: - DiceDTO( + DiceConfig( ljname='test', outname='test', dens=1.0, @@ -61,7 +61,7 @@ class TestDiceDto(unittest.TestCase): def test_validate_nstep(self): with self.assertRaises(ValueError) as ex: - DiceDTO( + DiceConfig( ljname='test', outname='test', dens=1.0, @@ -71,7 +71,7 @@ class TestDiceDto(unittest.TestCase): self.assertEqual(ex.exception, "Error: 'nstep' keyword not defined appropriately in config file") def test_from_dict(self): - dice_dto = DiceDTO.from_dict({ + dice_dto = DiceConfig.from_dict({ 'ljname': 'test', 'outname': 'test', 'dens': 1.0, @@ -79,4 +79,4 @@ class TestDiceDto(unittest.TestCase): 'nstep': [1, 1], }) - self.assertIsInstance(dice_dto, DiceDTO) \ No newline at end of file + self.assertIsInstance(dice_dto, DiceConfig) \ No newline at end of file diff --git a/tests/shared/config/test_gaussian_dto.py b/tests/shared/config/test_gaussian_dto.py index 67d013f..e719786 100644 --- a/tests/shared/config/test_gaussian_dto.py +++ b/tests/shared/config/test_gaussian_dto.py @@ -1,4 +1,4 @@ -from diceplayer.shared.config.gaussian_dto import GaussianDTO +from diceplayer.shared.config.gaussian_config import GaussianDTO import unittest diff --git a/tests/shared/config/test_player_dto.py b/tests/shared/config/test_player_dto.py index 98440af..909e5fd 100644 --- a/tests/shared/config/test_player_dto.py +++ b/tests/shared/config/test_player_dto.py @@ -1,28 +1,84 @@ -from diceplayer.shared.config.player_dto import PlayerDTO +from diceplayer.shared.config.gaussian_config import GaussianDTO +from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.shared.config.dice_config import DiceConfig import unittest -class TestPlayerDTO(unittest.TestCase): - def test_class_instantiation(self): - player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, ncores=4) +def get_config_dict(): + return { + 'opt': True, + 'mem': 12, + 'maxcyc': 100, + 'nprocs': 4, + 'ncores': 4, + 'dice': { + 'ljname': 'test', + 'outname': 'test', + 'dens': 1.0, + 'nmol': [1], + 'nstep': [1, 1], + }, + 'gaussian': { + 'level': 'test', + 'qmprog': 'g16', + 'keywords': 'test', + } + } - self.assertIsInstance(player_dto, PlayerDTO) + +class TestPlayerDTO(unittest.TestCase): + def setUp(self) -> None: + self.dice_dto = DiceConfig( + ljname='test', + outname='test', + dens=1.0, + nmol=[1], + nstep=[1, 1], + ) + self.gaussian_dto = GaussianDTO( + level='test', + qmprog='g16', + keywords='test', + ) + + def test_class_instantiation(self): + player_dto = PlayerConfig( + opt=True, + mem=12, + maxcyc=100, + nprocs=4, + ncores=4, + dice=self.dice_dto, + gaussian=self.gaussian_dto + ) + + self.assertIsInstance(player_dto, PlayerConfig) + self.assertIsInstance(player_dto.dice, DiceConfig) + self.assertIsInstance(player_dto.gaussian, GaussianDTO) def test_min_altsteps(self): - player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, ncores=4, altsteps=100) + player_dto = PlayerConfig( + opt=True, + mem=12, + maxcyc=100, + nprocs=4, + ncores=4, + altsteps=100, + dice=self.dice_dto, + gaussian=self.gaussian_dto + ) self.assertEqual(player_dto.altsteps, 20000) def test_from_dict(self): - player_dto = PlayerDTO.from_dict({ - 'opt': True, - 'maxcyc': 100, - 'nprocs': 4, - 'ncores': 4, - }) + player_dto = PlayerConfig.from_dict( + get_config_dict() + ) - self.assertIsInstance(player_dto, PlayerDTO) + self.assertIsInstance(player_dto, PlayerConfig) + self.assertIsInstance(player_dto.dice, DiceConfig) + self.assertIsInstance(player_dto.gaussian, GaussianDTO) if __name__ == '__main__': diff --git a/tests/shared/environment/test_system.py b/tests/shared/environment/test_system.py index cff560e..8fad46c 100644 --- a/tests/shared/environment/test_system.py +++ b/tests/shared/environment/test_system.py @@ -13,18 +13,14 @@ class TestSystem(unittest.TestCase): def test_add_type(self): system = System() - system.add_type(0, Molecule('test')) + system.add_type(Molecule('test')) self.assertIsInstance(system.molecule, list) - self.assertIsInstance(system.nmols, list) with self.assertRaises(TypeError) as ex: - system.add_type(0, 'test') + system.add_type('test') self.assertEqual(ex.exception, 'Error: molecule is not a Molecule instance') - with self.assertRaises(TypeError) as ex: - system.add_type('test', Molecule('test')) - self.assertEqual(ex.exception, 'Error: nmols is not an integer') if __name__ == '__main__': diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 6d39c4f..4a0ec90 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -1,11 +1,14 @@ from diceplayer.shared.interface.dice_interface import DiceInterface +from diceplayer.shared.config.player_config import PlayerConfig from diceplayer.shared.environment.molecule import Molecule +from diceplayer.shared.environment.system import System from diceplayer.shared.environment.atom import Atom -from diceplayer.shared.config.step_dto import StepDTO from diceplayer import logger +import yaml import io +from tests.mocks.mock_inputs import get_config_example from tests.mocks.mock_proc import MockConnection, MockProc from unittest import mock @@ -16,122 +19,58 @@ class TestDiceInterface(unittest.TestCase): def setUp(self): logger.set_logger(stream=io.StringIO()) + config = yaml.load(get_config_example(), Loader=yaml.Loader) + self.config = PlayerConfig.from_dict(config['diceplayer']) + def test_class_instantiation(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() self.assertIsInstance(dice, DiceInterface) def test_configure(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() self.assertIsNone(dice.step) + self.assertIsNone(dice.system) - dice.configure('test') + # Ignoring the types for testing purposes + dice.configure(self.config, System()) self.assertIsNotNone(dice.step) + self.assertIsNotNone(dice.system) def test_reset(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() - dice.configure('test') + dice.configure(self.config, System()) self.assertTrue(hasattr(dice, 'step')) + self.assertTrue(hasattr(dice, 'system')) dice.reset() self.assertFalse(hasattr(dice, 'step')) + self.assertFalse(hasattr(dice, 'system')) @mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc()) @mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection) def test_start(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice.start(1) @mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection) @mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc(exitcode=1)) def test_start_with_process_error(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=2, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) with self.assertRaises(SystemExit): dice.start(1) def test_simulation_process_raises_exception(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() with self.assertRaises(SystemExit): dice._simulation_process(1, 1) @@ -140,16 +79,7 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._make_dice_inputs') @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._run_dice') def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() dice._simulation_process(1, 1) @@ -160,26 +90,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists') def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) mock_path_exists.return_value = False @@ -190,26 +102,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists') def test_make_proc_dir_if_simdir_doesnt_exists(self, mock_path_exists, mock_path_mkdir): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) mock_path_exists.return_value = False @@ -218,42 +112,15 @@ class TestDiceInterface(unittest.TestCase): self.assertEqual(mock_path_mkdir.call_count, 2) def test_make_dice_seed(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - - seed = dice._make_dice_seed() + seed = DiceInterface._make_dice_seed() self.assertIsInstance(seed, int) def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_one(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) + + dice.step.dice.nstep = [1, 1] dice._make_potentials = mock.Mock() @@ -281,26 +148,10 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='test') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_two(self, mock_path_exists, mock_open): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) + + dice.step.dice.nstep = [1, 1] dice._make_potentials = mock.Mock() @@ -327,26 +178,10 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False) def test_make_dice_inputs_raises_exception_on_last_not_found(self, mock_path_exists): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) + + dice.step.dice.nstep = [1, 1] dice._make_potentials = mock.Mock() @@ -362,26 +197,8 @@ class TestDiceInterface(unittest.TestCase): dice._make_dice_inputs(2, 1) def test_make_dice_inputs_nstep_len_three_with_randoninit_first_cycle_one(self): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice._make_potentials = mock.Mock() @@ -410,26 +227,10 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.shutil') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) def test_run_dice_on_first_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) + + dice.step.dice.nstep = [1, 1, 1] dice.run_dice_file = mock.Mock() @@ -441,26 +242,10 @@ class TestDiceInterface(unittest.TestCase): self.assertEqual(dice.run_dice_file.call_count, 3) self.assertTrue(mock_shutils.copy.called) - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) + + dice.step.dice.nstep = [1, 1] dice.run_dice_file = mock.Mock() @@ -476,26 +261,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.shutil') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice.run_dice_file = mock.Mock() @@ -507,26 +274,8 @@ class TestDiceInterface(unittest.TestCase): self.assertEqual(dice.run_dice_file.call_count, 2) self.assertTrue(mock_shutils.copy.called) - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice.run_dice_file = mock.Mock() @@ -542,26 +291,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('diceplayer.shared.interface.dice_interface.shutil') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False) def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice.run_dice_file = mock.Mock() @@ -587,32 +318,14 @@ class TestDiceInterface(unittest.TestCase): secondary_molecule = Molecule('secondary_molecule') secondary_molecule.add_atom(example_atom) - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[ - main_molecule, - secondary_molecule, - ], - nmol=[ - len(main_molecule.atom), - len(secondary_molecule.atom), - ], - ) - ) + system = System() + system.add_type(main_molecule) + system.add_type(secondary_molecule) + + dice = DiceInterface() + dice.configure(self.config, system) + + dice.step.dice.nmol = [1, 1] last_xyz_file = io.StringIO() last_xyz_file.writelines([ @@ -657,32 +370,12 @@ class TestDiceInterface(unittest.TestCase): secondary_molecule = Molecule('secondary_molecule') secondary_molecule.add_atom(example_atom) - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[ - main_molecule, - secondary_molecule, - ], - nmol=[ - len(main_molecule.atom), - len(secondary_molecule.atom), - ], - ) - ) + system = System() + system.add_type(main_molecule) + system.add_type(secondary_molecule) + + dice = DiceInterface() + dice.configure(self.config, system) last_xyz_file = io.StringIO() last_xyz_file.writelines([ @@ -695,33 +388,15 @@ class TestDiceInterface(unittest.TestCase): density = dice._new_density(last_xyz_file) - self.assertEqual(density, 3.3472359000000003) + self.assertEqual(density, 85.35451545000001) @mock.patch('builtins.open', new_callable=mock.mock_open) @mock.patch('diceplayer.shared.interface.dice_interface.random') def test_make_nvt_ter(self, mock_random, mock_open): mock_random.random.return_value = 1 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice._make_nvt_ter(1, 'test') @@ -730,7 +405,7 @@ class TestDiceInterface(unittest.TestCase): lines = list(map(lambda x: x[0][0], calls)) - expected_lines = ['title = Diceplayer run - NVT Thermalization\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'dens = 1.0\n', 'temp = 300.0\n', 'init = yes\n', 'nstep = 1\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n', 'upbuf = 360'] + expected_lines = ['title = Diceplayer run - NVT Thermalization\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'dens = 0.75\n', 'temp = 300.0\n', 'init = yes\n', 'nstep = 2000\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n', 'upbuf = 360'] self.assertEqual(lines, expected_lines) @@ -739,26 +414,8 @@ class TestDiceInterface(unittest.TestCase): def test_make_nvt_eq(self, mock_random, mock_open): mock_random.random.return_value = 1 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice._make_nvt_eq('test') @@ -767,7 +424,7 @@ class TestDiceInterface(unittest.TestCase): lines = list(map(lambda x: x[0][0], calls)) - expected_lines = ['title = Diceplayer run - NVT Production\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'dens = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'nstep = 1\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 10\n', 'seed = 1000000\n'] + expected_lines = ['title = Diceplayer run - NVT Production\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'dens = 0.75\n', 'temp = 300.0\n', 'init = no\n', 'nstep = 3000\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 40\n', 'seed = 1000000\n'] self.assertEqual(lines, expected_lines) @@ -776,26 +433,8 @@ class TestDiceInterface(unittest.TestCase): def test_make_npt_ter(self, mock_random, mock_open): mock_random.random.return_value = 1 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice._make_npt_ter(1, 'test') @@ -804,7 +443,7 @@ class TestDiceInterface(unittest.TestCase): lines = list(map(lambda x: x[0][0], calls)) - expected_lines = ['title = Diceplayer run - NPT Thermalization\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'press = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'vstep = 0\n', 'nstep = 5\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n'] + expected_lines = ['title = Diceplayer run - NPT Thermalization\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'press = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'vstep = 600\n', 'nstep = 5\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n'] self.assertEqual(lines, expected_lines) @@ -813,26 +452,8 @@ class TestDiceInterface(unittest.TestCase): def test_make_npt_eq(self, mock_random, mock_open): mock_random.random.return_value = 1 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[], - nmol=[], - ) - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice._make_npt_eq('test') @@ -841,7 +462,7 @@ class TestDiceInterface(unittest.TestCase): lines = list(map(lambda x: x[0][0], calls)) - expected_lines = ['title = Diceplayer run - NPT Production\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'press = 1.0\n', 'temp = 300.0\n', 'nstep = 5\n', 'vstep = 0\n', 'init = no\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 10\n', 'seed = 1000000\n'] + expected_lines = ['title = Diceplayer run - NPT Production\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'press = 1.0\n', 'temp = 300.0\n', 'nstep = 5\n', 'vstep = 800\n', 'init = no\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 40\n', 'seed = 1000000\n'] self.assertEqual(lines, expected_lines) @@ -864,32 +485,12 @@ class TestDiceInterface(unittest.TestCase): secondary_molecule = Molecule('secondary_molecule') secondary_molecule.add_atom(example_atom) - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) - dice.configure( - StepDTO( - ncores=1, - nprocs=1, - simulation_dir='test', - altsteps=1, - molecule=[ - main_molecule, - secondary_molecule, - ], - nmol=[ - len(main_molecule.atom), - len(secondary_molecule.atom), - ], - ) - ) + system = System() + system.add_type(main_molecule) + system.add_type(secondary_molecule) + + dice = DiceInterface() + dice.configure(self.config, system) dice._make_potentials('test') @@ -906,16 +507,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA') def test_run_dice_file(self, mock_open, mock_subprocess): mock_subprocess.call.return_value = 0 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() + dice.configure(self.config, System()) dice.run_dice_file(1, 1, 'test') @@ -926,16 +519,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='Error\nBLABLA') def test_run_dice_file_raises_runtime_error_on_dice_file(self, mock_open, mock_subprocess): mock_subprocess.call.return_value = 0 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() + dice.configure(self.config, System()) with self.assertRaises(RuntimeError): dice.run_dice_file(1, 1, 'test') @@ -944,16 +529,8 @@ class TestDiceInterface(unittest.TestCase): @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA') def test_run_dice_file_raises_runtime_error_of_dice_exit_code(self, mock_open, mock_subprocess): mock_subprocess.call.return_value = 1 - dice = DiceInterface( - { - 'ljname': 'test', - 'outname': 'test', - 'ncores': 1, - 'dens': 1.0, - 'nmol': [1], - 'nstep': [1, 1], - } - ) + dice = DiceInterface() + dice.configure(self.config, System()) with self.assertRaises(RuntimeError): dice.run_dice_file(1, 1, 'test') diff --git a/tests/shared/interface/test_gaussian_interface.py b/tests/shared/interface/test_gaussian_interface.py new file mode 100644 index 0000000..b59cd93 --- /dev/null +++ b/tests/shared/interface/test_gaussian_interface.py @@ -0,0 +1,113 @@ +from diceplayer.shared.interface.gaussian_interface import GaussianInterface +from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.shared.environment.system import System +from diceplayer import logger + +from tests.mocks.mock_inputs import get_config_example + +import yaml +import io + + +from unittest import mock +import unittest + + +class TestGaussianInterface(unittest.TestCase): + def setUp(self) -> None: + logger.set_logger(stream=io.StringIO()) + + config = yaml.load(get_config_example(), Loader=yaml.Loader) + self.config = PlayerConfig.from_dict(config['diceplayer']) + + def test_class_instantiation(self): + gaussian_interface = GaussianInterface() + self.assertIsInstance(gaussian_interface, GaussianInterface) + + def test_configure(self): + gaussian_interface = GaussianInterface() + + self.assertIsNone(gaussian_interface.step) + self.assertIsNone(gaussian_interface.system) + + gaussian_interface.configure(self.config, System()) + + self.assertIsNotNone(gaussian_interface.step) + self.assertIsNotNone(gaussian_interface.system) + + def test_reset(self): + gaussian_interface = GaussianInterface() + + gaussian_interface.configure(self.config, System()) + + self.assertIsNotNone(gaussian_interface.step) + self.assertIsNotNone(gaussian_interface.system) + + gaussian_interface.reset() + + self.assertFalse(hasattr(gaussian_interface, 'step')) + self.assertFalse(hasattr(gaussian_interface, 'system')) + + @mock.patch('diceplayer.shared.interface.gaussian_interface.Path.mkdir') + @mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists') + def test_make_qm_dir(self, mock_exists, mock_mkdir): + mock_exists.return_value = False + + gaussian_interface = GaussianInterface() + gaussian_interface.configure(self.config, System()) + + gaussian_interface._make_qm_dir(1) + + mock_exists.assert_called_once() + mock_mkdir.assert_called_once() + + @mock.patch('diceplayer.shared.interface.gaussian_interface.shutil.copy') + @mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists') + def test_copy_chk_file_from_previous_step(self, mock_exists, mock_copy): + gaussian_interface = GaussianInterface() + gaussian_interface.configure(self.config, System()) + + mock_exists.side_effect = [False, True] + + gaussian_interface._copy_chk_file_from_previous_step(2) + + self.assertTrue(mock_exists.called) + self.assertTrue(mock_copy.called) + + @mock.patch('diceplayer.shared.interface.gaussian_interface.shutil.copy') + @mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists') + def test_copy_chk_file_from_previous_step_no_previous_step(self, mock_exists, mock_copy): + gaussian_interface = GaussianInterface() + gaussian_interface.configure(self.config, System()) + + mock_exists.side_effect = [False, False] + + with self.assertRaises(FileNotFoundError): + gaussian_interface._copy_chk_file_from_previous_step(2) + + @mock.patch('diceplayer.shared.interface.gaussian_interface.shutil.copy') + @mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists') + def test_copy_chk_file_from_previous_step_current_exists(self, mock_exists, mock_copy): + gaussian_interface = GaussianInterface() + gaussian_interface.configure(self.config, System()) + + mock_exists.side_effect = [True, True] + + with self.assertRaises(FileExistsError): + gaussian_interface._copy_chk_file_from_previous_step(2) + + # def test_start(self): + # gaussian_interface = GaussianInterface() + # gaussian_interface.configure(self.config, System()) + # + # gaussian_interface._make_qm_dir = mock.Mock() + # gaussian_interface._copy_chk_file_from_previous_step = mock.Mock() + # + # gaussian_interface.start(2) + # + # gaussian_interface._make_qm_dir.assert_called_once_with(2) + # gaussian_interface._copy_chk_file_from_previous_step.assert_called_once_with(2) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_player.py b/tests/test_player.py index e421331..65e45d5 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -3,119 +3,12 @@ from diceplayer import logger import io +from tests.mocks.mock_inputs import mock_open + from unittest import mock import unittest -def get_config_example(): - return """ -diceplayer: - maxcyc: 3 - opt: no - ncores: 4 - nprocs: 4 - qmprog: 'g16' - lps: no - ghosts: no - altsteps: 20000 - -dice: - nmol: [1, 50] - dens: 0.75 - nstep: [2000, 3000, 4000] - isave: 1000 - outname: 'phb' - progname: '~/.local/bin/dice' - ljname: 'phb.ljc' - randominit: 'first' - -gaussian: - qmprog: 'g16' - level: 'MP2/aug-cc-pVDZ' - keywords: 'freq' -""" - - -def get_potentials_exemple(): - return """\ -* -2 -1 TEST - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -1 PLACEHOLDER - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -""" - - -def get_potentials_error_combrule(): - return """\ -. -2 -1 TEST - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -1 PLACEHOLDER - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -""" - - -def get_potentials_error_ntypes(): - return """\ -* -a -1 TEST - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -1 PLACEHOLDER - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -""" - - -def get_potentials_error_ntypes_config(): - return """\ -* -3 -1 TEST - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -1 PLACEHOLDER - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -""" - - -def get_potentials_error_nsites(): - return """\ -* -2 -. TEST - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -1 PLACEHOLDER - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -""" - - -def get_potentials_error_molname(): - return """\ -* -2 -1 - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -1 PLACEHOLDER - 1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000 -""" - - -def mock_open(file, *args, **kwargs): - values = { - "control.test.yml": get_config_example(), - "phb.ljc": get_potentials_exemple(), - "phb.error.combrule.ljc": get_potentials_error_combrule(), - "phb.error.ntypes.ljc": get_potentials_error_ntypes(), - "phb.error.ntypes.config.ljc": get_potentials_error_ntypes_config(), - "phb.error.nsites.ljc": get_potentials_error_nsites(), - "phb.error.molname.ljc": get_potentials_error_molname(), - } - mock_file = mock.mock_open(read_data=values[file]) - return mock_file() - - class TestPlayer(unittest.TestCase): def setUp(self): logger.set_logger(stream=io.StringIO()) @@ -131,19 +24,13 @@ class TestPlayer(unittest.TestCase): def test_start(self): player = Player("control.test.yml") - player.print_keywords = mock.MagicMock() - player.create_simulation_dir = mock.MagicMock() - player.read_potentials = mock.MagicMock() - player.print_potentials = mock.MagicMock() + player.gaussian_start = mock.MagicMock() player.dice_start = mock.MagicMock() player.start(1) - self.assertTrue(player.print_keywords.called) - self.assertTrue(player.create_simulation_dir.called) - self.assertTrue(player.read_potentials.called) - self.assertTrue(player.print_potentials.called) self.assertEqual(player.dice_start.call_count, 3) + self.assertEqual(player.gaussian_start.call_count, 3) @mock.patch("builtins.open", mock_open) @mock.patch("diceplayer.player.Path") @@ -178,7 +65,22 @@ class TestPlayer(unittest.TestCase): with self.assertLogs() as cm: player.print_keywords() - expected_output = ['INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n\n', 'INFO:diceplayer:Your python version is TEST\n', 'INFO:diceplayer:\n', 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', 'INFO:diceplayer:\n', 'INFO:diceplayer:Environment variables:\n', 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', 'INFO:diceplayer:\n==========================================================================================\n CONTROL variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', 'INFO:diceplayer:\n', 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', 'INFO:diceplayer:dens = 0.75', 'INFO:diceplayer:isave = 1000', 'INFO:diceplayer:ljname = phb.ljc', 'INFO:diceplayer:nmol = [ 1 50 ]', 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', 'INFO:diceplayer:outname = phb', 'INFO:diceplayer:press = 1.0', 'INFO:diceplayer:progname = ~/.local/bin/dice', 'INFO:diceplayer:randominit = first', 'INFO:diceplayer:temp = 300.0', 'INFO:diceplayer:\n', 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', 'INFO:diceplayer:keywords = freq', 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', 'INFO:diceplayer:pop = chelpg', 'INFO:diceplayer:qmprog = g16', 'INFO:diceplayer:\n'] + expected_output = [ + 'INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n\n', + 'INFO:diceplayer:Your python version is TEST\n', 'INFO:diceplayer:\n', + 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', 'INFO:diceplayer:\n', + 'INFO:diceplayer:Environment variables:\n', 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', + 'INFO:diceplayer:\n==========================================================================================\n CONTROL variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', + 'INFO:diceplayer:\n', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', + 'INFO:diceplayer:dens = 0.75', 'INFO:diceplayer:isave = 1000', 'INFO:diceplayer:ljname = phb.ljc', + 'INFO:diceplayer:nmol = [ 1 50 ]', 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', + 'INFO:diceplayer:outname = phb', 'INFO:diceplayer:press = 1.0', + 'INFO:diceplayer:progname = ~/.local/bin/dice', 'INFO:diceplayer:randominit = first', + 'INFO:diceplayer:temp = 300.0', 'INFO:diceplayer:\n', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', + 'INFO:diceplayer:keywords = freq', 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', + 'INFO:diceplayer:pop = chelpg', 'INFO:diceplayer:qmprog = g16', 'INFO:diceplayer:\n'] self.assertEqual(cm.output, expected_output) @@ -333,7 +235,7 @@ class TestPlayer(unittest.TestCase): # Testing combrule error with self.assertRaises(SystemExit) as context: - player.dice.config.ljname = "phb.error.combrule.ljc" + player.config.dice.ljname = "phb.error.combrule.ljc" player.read_potentials() self.assertEqual( @@ -343,7 +245,7 @@ class TestPlayer(unittest.TestCase): # Testing ntypes error with self.assertRaises(SystemExit) as context: - player.dice.config.ljname = "phb.error.ntypes.ljc" + player.config.dice.ljname = "phb.error.ntypes.ljc" player.read_potentials() self.assertEqual( @@ -353,7 +255,7 @@ class TestPlayer(unittest.TestCase): # Testing ntypes error on config with self.assertRaises(SystemExit) as context: - player.dice.config.ljname = "phb.error.ntypes.config.ljc" + player.config.dice.ljname = "phb.error.ntypes.config.ljc" player.read_potentials() self.assertEqual( @@ -364,7 +266,7 @@ class TestPlayer(unittest.TestCase): # Testing nsite error with self.assertRaises(ValueError) as context: - player.dice.config.ljname = "phb.error.nsites.ljc" + player.config.dice.ljname = "phb.error.nsites.ljc" player.read_potentials() self.assertEqual( @@ -374,7 +276,7 @@ class TestPlayer(unittest.TestCase): # Testing molname error with self.assertRaises(ValueError) as context: - player.dice.config.ljname = "phb.error.molname.ljc" + player.config.dice.ljname = "phb.error.molname.ljc" player.read_potentials() self.assertEqual( @@ -391,7 +293,23 @@ class TestPlayer(unittest.TestCase): with self.assertLogs(level='INFO') as context: player.print_potentials() - expected_output = ['INFO:diceplayer:==========================================================================================\n', 'INFO:diceplayer: Potential parameters from file phb.ljc:', 'INFO:diceplayer:------------------------------------------------------------------------------------------\n', 'INFO:diceplayer:Combination rule: *', 'INFO:diceplayer:Types of molecules: 2\n', 'INFO:diceplayer:1 atoms in molecule type 1:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', 'INFO:diceplayer:\n', 'INFO:diceplayer:1 atoms in molecule type 2:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', 'INFO:diceplayer:\n', 'INFO:diceplayer:=========================================================================================='] + expected_output = [ + 'INFO:diceplayer:==========================================================================================\n', + 'INFO:diceplayer: Potential parameters from file phb.ljc:', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:Combination rule: *', 'INFO:diceplayer:Types of molecules: 2\n', + 'INFO:diceplayer:1 atoms in molecule type 1:', + 'INFO:diceplayer:---------------------------------------------------------------------------------', + 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', + 'INFO:diceplayer:---------------------------------------------------------------------------------', + 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', + 'INFO:diceplayer:\n', 'INFO:diceplayer:1 atoms in molecule type 2:', + 'INFO:diceplayer:---------------------------------------------------------------------------------', + 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', + 'INFO:diceplayer:---------------------------------------------------------------------------------', + 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', + 'INFO:diceplayer:\n', + 'INFO:diceplayer:=========================================================================================='] self.assertEqual( context.output, @@ -401,23 +319,22 @@ class TestPlayer(unittest.TestCase): @mock.patch("builtins.open", mock_open) def test_dice_start(self): player = Player("control.test.yml") - player.dice = mock.MagicMock() - player.dice.start = mock.MagicMock() + player.dice_interface = mock.MagicMock() + player.dice_interface.start = mock.MagicMock() player.dice_start(1) - player.dice.start.assert_called_once() - - @mock.patch("builtins.open", mock_open) - def test_gaussian_start(self): - player = Player("control.test.yml") - player.gaussian = mock.MagicMock() - player.gaussian.start = mock.MagicMock() - - player.gaussian_start(1) - - player.gaussian.start.assert_called_once() + player.dice_interface.start.assert_called_once() + # @mock.patch("builtins.open", mock_open) + # def test_gaussian_start(self): + # player = Player("control.test.yml") + # player.gaussian_interface = mock.MagicMock() + # player.gaussian_interface.start = mock.MagicMock() + # + # player.gaussian_start(1) + # + # player.gaussian_interface.start.assert_called_once() if __name__ == '__main__': From d0be244d3c536f44c54f5965092dd687e24cc5db Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Mon, 5 Jun 2023 19:01:36 -0300 Subject: [PATCH 15/18] Implements Saves for Last Successful Run --- .gitignore | 3 +- control.example.yml | 6 +- diceplayer/__main__.py | 18 ++-- diceplayer/player.py | 83 +++++++++++++++---- tests/mocks/mock_inputs.py | 6 +- tests/shared/interface/test_dice_interface.py | 2 +- tests/test_player.py | 55 +++++++----- 7 files changed, 116 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index f9cca34..a987b49 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ __pycache__/ simfiles/* .vscode/* -.idea/* \ No newline at end of file +.idea/* +*.pkl diff --git a/control.example.yml b/control.example.yml index f475b7d..fddc56c 100644 --- a/control.example.yml +++ b/control.example.yml @@ -1,16 +1,16 @@ diceplayer: opt: no mem: 24 - maxcyc: 10 + maxcyc: 5 ncores: 5 nprocs: 4 qmprog: 'g16' lps: no ghosts: no - altsteps: 20000 + altsteps: 2000 dice: - nmol: [1, 1000] + nmol: [1, 100] dens: 1.0 nstep: [2000, 3000] isave: 1000 diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 3bfd18d..2be65fc 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -43,23 +43,17 @@ def main(): # Open OUTFILE for writing and print keywords and initial info logger.set_logger(args.outfile, logging.INFO) - try: + if args.opt_continue: + player = Player.from_save() + else: + player = Player.from_file(args.infile) - 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) + player.read_potentials() - except Exception as err: - sys.exit(err) - - player = Player(args.infile) + player.create_simulation_dir() player.print_keywords() - player.create_simulation_dir() - - player.read_potentials() player.print_potentials() player.prepare_system() diff --git a/diceplayer/player.py b/diceplayer/player.py index 7300bd3..11814d5 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,3 +1,5 @@ +import pickle + from diceplayer.shared.interface.gaussian_interface import GaussianInterface from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.utils.dataclass_protocol import Dataclass @@ -11,38 +13,54 @@ from diceplayer.shared.environment.atom import Atom from diceplayer import logger from dataclasses import fields +from typing import Type, Tuple from pathlib import Path -from typing import Type, List -import logging import yaml import sys import os - ENV = ["OMP_STACKSIZE"] class Player: - def __init__(self, infile: str): - config_data = self.read_keywords(infile) + def __init__(self, infile: str = None, optimization: bool = False): + if infile is None and optimization is False: + raise ValueError("Must specify either infile or optimization") - self.system = System() + elif infile is not None: + config_data = self.read_keywords(infile) - self.config = self.set_config( - config_data.get("diceplayer") - ) + self.config = self.set_config( + config_data.get("diceplayer") + ) + + self.system = System() + + self.initial_cycle = 1 + + elif optimization is True: + save = self.load_run_from_pickle() + + self.config = save[0] + + self.system = save[1] + + self.initial_cycle = save[2] + + else: + raise ValueError("Must specify either infile or config") self.dice_interface = DiceInterface() self.gaussian_interface = GaussianInterface() - def start(self, initial_cycle: int = 1): + def start(self): logger.info( "==========================================================================================\n" "Starting the iterative process.\n" "==========================================================================================\n" ) - for cycle in range(initial_cycle, self.config.maxcyc + 1): + for cycle in range(self.initial_cycle, self.config.maxcyc + 1): logger.info( f"------------------------------------------------------------------------------------------\n" @@ -54,9 +72,12 @@ class Player: try: self.gaussian_start(cycle) + pass except StopIteration as e: break + self.save_run_in_pickle(cycle) + def prepare_system(self): for i, mol in enumerate(self.system.molecule): logger.info( @@ -75,7 +96,6 @@ class Player: logger.info("\n") - def create_simulation_dir(self): simulation_dir_path = Path(self.config.simulation_dir) if simulation_dir_path.exists(): @@ -169,12 +189,12 @@ class Player: nsites, molname = ljc_data.pop(0).split()[:2] except ValueError: raise ValueError( - f"Error: expected nsites and molname for the molecule type {i+1}" + f"Error: expected nsites and molname for the molecule type {i + 1}" ) if not nsites.isdigit(): raise ValueError( - f"Error: expected nsites to be an integer for molecule type {i+1}" + f"Error: expected nsites to be an integer for molecule type {i + 1}" ) nsites = int(nsites) @@ -271,7 +291,7 @@ class Player: 'Charges optimization failed. No charges found in result.' ) - diff = self.system.molecule[0]\ + diff = self.system.molecule[0] \ .update_charges(result['charges']) self.system.print_charges_and_dipole(cycle) @@ -390,6 +410,31 @@ class Player: logger.info("\n") + def save_run_in_pickle(self, cycle): + try: + with open('latest-step.pkl', 'wb') as pickle_file: + pickle.dump( + (self.config, self.system, cycle), + pickle_file + ) + except Exception: + raise RuntimeError( + f'Could not save pickle file latest-step.pkl.' + ) + + @staticmethod + def load_run_from_pickle() -> Tuple[PlayerConfig, System, int]: + pickle_path = Path("latest-step.pkl") + try: + with open(pickle_path, 'rb') as pickle_file: + save = pickle.load(pickle_file) + return save[0], save[1], save[2] + 1 + + except Exception: + raise RuntimeError( + f'Could not load pickle file {pickle_path}.' + ) + @staticmethod def set_config(data: dict) -> PlayerConfig: return PlayerConfig.from_dict(data) @@ -398,3 +443,11 @@ class Player: def read_keywords(infile) -> dict: with open(infile, 'r') as yml_file: return yaml.load(yml_file, Loader=yaml.SafeLoader) + + @classmethod + def from_file(cls, infile: str) -> 'Player': + return cls(infile=infile) + + @classmethod + def from_save(cls): + return cls(optimization=True) diff --git a/tests/mocks/mock_inputs.py b/tests/mocks/mock_inputs.py index 406a35a..eadf05b 100644 --- a/tests/mocks/mock_inputs.py +++ b/tests/mocks/mock_inputs.py @@ -107,5 +107,7 @@ def mock_open(file, *args, **kwargs): "phb.error.nsites.ljc": get_potentials_error_nsites(), "phb.error.molname.ljc": get_potentials_error_molname(), } - mock_file = mock.mock_open(read_data=values[file]) - return mock_file() \ No newline at end of file + if file in values: + return mock.mock_open(read_data=values[file])() + + return mock.mock_open(read_data="")() diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 4a0ec90..0c5b931 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -417,7 +417,7 @@ class TestDiceInterface(unittest.TestCase): dice = DiceInterface() dice.configure(self.config, System()) - dice._make_nvt_eq('test') + dice._make_nvt_eq(1, 'test') mock_handler = mock_open() calls = mock_handler.write.call_args_list diff --git a/tests/test_player.py b/tests/test_player.py index 65e45d5..d1b50e9 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -27,7 +27,7 @@ class TestPlayer(unittest.TestCase): player.gaussian_start = mock.MagicMock() player.dice_start = mock.MagicMock() - player.start(1) + player.start() self.assertEqual(player.dice_start.call_count, 3) self.assertEqual(player.gaussian_start.call_count, 3) @@ -66,21 +66,30 @@ class TestPlayer(unittest.TestCase): player.print_keywords() expected_output = [ - 'INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n\n', - 'INFO:diceplayer:Your python version is TEST\n', 'INFO:diceplayer:\n', - 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', 'INFO:diceplayer:\n', - 'INFO:diceplayer:Environment variables:\n', 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', - 'INFO:diceplayer:\n==========================================================================================\n CONTROL variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', - 'INFO:diceplayer:\n', - 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', - 'INFO:diceplayer:dens = 0.75', 'INFO:diceplayer:isave = 1000', 'INFO:diceplayer:ljname = phb.ljc', - 'INFO:diceplayer:nmol = [ 1 50 ]', 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', - 'INFO:diceplayer:outname = phb', 'INFO:diceplayer:press = 1.0', - 'INFO:diceplayer:progname = ~/.local/bin/dice', 'INFO:diceplayer:randominit = first', - 'INFO:diceplayer:temp = 300.0', 'INFO:diceplayer:\n', - 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', - 'INFO:diceplayer:keywords = freq', 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', - 'INFO:diceplayer:pop = chelpg', 'INFO:diceplayer:qmprog = g16', 'INFO:diceplayer:\n'] + 'INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n', + 'INFO:diceplayer:Your python version is TEST\n', + 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', + 'INFO:diceplayer:Environment variables:', + 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:dens = 0.75', + 'INFO:diceplayer:isave = 1000', + 'INFO:diceplayer:ljname = phb.ljc', + 'INFO:diceplayer:nmol = [ 1 50 ]', + 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', + 'INFO:diceplayer:outname = phb', + 'INFO:diceplayer:press = 1.0', + 'INFO:diceplayer:progname = ~/.local/bin/dice', + 'INFO:diceplayer:randominit = first', + 'INFO:diceplayer:temp = 300.0', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:chg_tol = 0.01', + 'INFO:diceplayer:keywords = freq', + 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', + 'INFO:diceplayer:pop = chelpg', + 'INFO:diceplayer:qmprog = g16', + 'INFO:diceplayer:\n' + ] self.assertEqual(cm.output, expected_output) @@ -294,22 +303,22 @@ class TestPlayer(unittest.TestCase): player.print_potentials() expected_output = [ - 'INFO:diceplayer:==========================================================================================\n', - 'INFO:diceplayer: Potential parameters from file phb.ljc:', - 'INFO:diceplayer:------------------------------------------------------------------------------------------\n', - 'INFO:diceplayer:Combination rule: *', 'INFO:diceplayer:Types of molecules: 2\n', + 'INFO:diceplayer:==========================================================================================\n Potential parameters from file phb.ljc:\n------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:Combination rule: *', + 'INFO:diceplayer:Types of molecules: 2\n', 'INFO:diceplayer:1 atoms in molecule type 1:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', - 'INFO:diceplayer:\n', 'INFO:diceplayer:1 atoms in molecule type 2:', + 'INFO:diceplayer:\n', + 'INFO:diceplayer:1 atoms in molecule type 2:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', - 'INFO:diceplayer:\n', - 'INFO:diceplayer:=========================================================================================='] + 'INFO:diceplayer:\n' + ] self.assertEqual( context.output, From 8bed68c45195349450e2fb4d6119476c859de6a0 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sat, 10 Jun 2023 23:56:57 -0300 Subject: [PATCH 16/18] Fixes Continue from Last Run and Implements Geoms File --- .gitignore | 2 + control.example.yml | 4 +- diceplayer/__main__.py | 1 + diceplayer/player.py | 44 +++++++++++++++---- diceplayer/shared/config/player_config.py | 1 + diceplayer/shared/interface/dice_interface.py | 11 +++-- 6 files changed, 49 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index a987b49..58f5f60 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ simfiles/* .vscode/* .idea/* *.pkl + +*.xyz diff --git a/control.example.yml b/control.example.yml index fddc56c..0830d4d 100644 --- a/control.example.yml +++ b/control.example.yml @@ -11,13 +11,13 @@ diceplayer: dice: nmol: [1, 100] - dens: 1.0 + dens: 1.5 nstep: [2000, 3000] isave: 1000 outname: 'phb' progname: '~/.local/bin/dice' ljname: 'phb.ljc' - randominit: 'first' + randominit: 'always' gaussian: qmprog: 'g16' diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 2be65fc..1e4fa0e 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -51,6 +51,7 @@ def main(): player.read_potentials() player.create_simulation_dir() + player.create_geoms_file() player.print_keywords() diff --git a/diceplayer/player.py b/diceplayer/player.py index 11814d5..677ec3d 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -10,6 +10,7 @@ from diceplayer.shared.utils.misc import weekday_date_time from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.system import System from diceplayer.shared.environment.atom import Atom +from diceplayer.shared.utils.ptable import atomsymb from diceplayer import logger from dataclasses import fields @@ -19,6 +20,7 @@ import yaml import sys import os + ENV = ["OMP_STACKSIZE"] @@ -28,10 +30,8 @@ class Player: raise ValueError("Must specify either infile or optimization") elif infile is not None: - config_data = self.read_keywords(infile) - self.config = self.set_config( - config_data.get("diceplayer") + self.read_keywords(infile) ) self.system = System() @@ -45,7 +45,7 @@ class Player: self.system = save[1] - self.initial_cycle = save[2] + self.initial_cycle = save[2] + 1 else: raise ValueError("Must specify either infile or config") @@ -60,7 +60,7 @@ class Player: "==========================================================================================\n" ) - for cycle in range(self.initial_cycle, self.config.maxcyc + 1): + for cycle in range(self.initial_cycle, self.initial_cycle + self.config.maxcyc + 1): logger.info( f"------------------------------------------------------------------------------------------\n" @@ -72,8 +72,7 @@ class Player: try: self.gaussian_start(cycle) - pass - except StopIteration as e: + except StopIteration: break self.save_run_in_pickle(cycle) @@ -105,6 +104,15 @@ class Player: ) simulation_dir_path.mkdir() + def create_geoms_file(self): + geoms_file_path = Path(self.config.geoms_file) + if geoms_file_path.exists(): + raise FileExistsError( + f"Error: a file or a directory {self.config.geoms_file} already exists," + f" move or delete the simfiles directory to continue." + ) + geoms_file_path.touch() + def print_keywords(self) -> None: def log_keywords(config: Dataclass, dto: Type[Dataclass]): @@ -295,6 +303,7 @@ class Player: .update_charges(result['charges']) self.system.print_charges_and_dipole(cycle) + self.print_geoms(cycle) if diff < self.config.gaussian.chg_tol: logger.info( @@ -302,6 +311,18 @@ class Player: ) raise StopIteration() + def print_geoms(self, cycle: int): + with open(self.config.geoms_file, 'a') as file: + file.write(f'Cycle # {cycle}\n') + + for atom in self.system.molecule[0].atom: + symbol = atomsymb[atom.na] + file.write( + f'{symbol:<2s} {atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n' + ) + + file.write('\n') + @staticmethod def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict: molecule_type += 1 @@ -442,7 +463,14 @@ class Player: @staticmethod def read_keywords(infile) -> dict: with open(infile, 'r') as yml_file: - return yaml.load(yml_file, Loader=yaml.SafeLoader) + config = yaml.load(yml_file, Loader=yaml.SafeLoader) + + if "diceplayer" in config: + return config.get("diceplayer") + + raise RuntimeError( + f'Could not find diceplayer section in {infile}.' + ) @classmethod def from_file(cls, infile: str) -> 'Player': diff --git a/diceplayer/shared/config/player_config.py b/diceplayer/shared/config/player_config.py index 75e2b12..ce1f7d9 100644 --- a/diceplayer/shared/config/player_config.py +++ b/diceplayer/shared/config/player_config.py @@ -23,6 +23,7 @@ class PlayerConfig(Dataclass): switchcyc: int = 3 qmprog: str = 'g16' altsteps: int = 20000 + geoms_file = 'geoms.xyz' simulation_dir = 'simfiles' def __post_init__(self): diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index 5b754a6..f79bc0a 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -166,11 +166,14 @@ class DiceInterface(Interface): def _make_init_file(self, proc_dir: Path, last_xyz_file: TextIO): xyz_lines = last_xyz_file.readlines() - nsites_mm = 0 - for i in range(1, len(self.step.dice.nmol)): - nsites_mm += self.step.dice.nmol[i] * len(self.system.molecule[i].atom) + HEADER_LENGTH = 2 + MAIN_MOLECULE_LENGTH = len(self.system.molecule[0].atom) - xyz_lines = xyz_lines[-nsites_mm:] + SECONDARY_MOLECULES_LENGTH = HEADER_LENGTH + MAIN_MOLECULE_LENGTH + for i in range(1, len(self.step.dice.nmol)): + SECONDARY_MOLECULES_LENGTH += self.step.dice.nmol[i] * len(self.system.molecule[i].atom) + + xyz_lines = xyz_lines[HEADER_LENGTH + MAIN_MOLECULE_LENGTH: SECONDARY_MOLECULES_LENGTH] input_file = Path(proc_dir, self.step.dice.outname + ".xy") with open(input_file, 'w') as f: From 753a8cb964aebdfb7608d466ab555c5acca4b582 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 11 Jun 2023 01:20:00 -0300 Subject: [PATCH 17/18] Changes Versioning System for Better Publicly --- Pipfile | 23 -- Pipfile.lock | 377 ------------------ diceplayer/player.py | 3 +- diceplayer/shared/interface/dice_interface.py | 9 +- poetry.lock | 264 ++++++++++++ pyproject.toml | 22 + 6 files changed, 290 insertions(+), 408 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/Pipfile b/Pipfile deleted file mode 100644 index ae70530..0000000 --- a/Pipfile +++ /dev/null @@ -1,23 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -numpy = "*" -pickle5 = "*" -argparse = "*" -pyinstaller = "*" -setproctitle = "*" -pyyaml = "*" -nptyping = "*" -intel-openmp = "*" -typing = "*" -dacite = "*" - -[dev-packages] -pyinstaller = "*" -coverage = "*" - -[requires] -python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 65b18c9..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,377 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "6d97338a51c2b51f6dcbcdbee2533e22d29634f07914cfc05b32f8476e9346ed" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.8" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "altgraph": { - "hashes": [ - "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd", - "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe" - ], - "version": "==0.17.3" - }, - "argparse": { - "hashes": [ - "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4", - "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314" - ], - "index": "pypi", - "version": "==1.4.0" - }, - "dacite": { - "hashes": [ - "sha256:6257a5e505b61a8cafee7ef3ad08cf32ee9b885718f42395d017e0a9b4c6af65", - "sha256:f7b1205cc5d9b62835aac8cbc1e6e37c1da862359a401f1edbe2ae08fbdc6193" - ], - "index": "pypi", - "version": "==1.8.0" - }, - "intel-openmp": { - "hashes": [ - "sha256:0ca275fd223bda7b835f3b30221ee462e934468738dcbb26741c57e795f09818", - "sha256:0e3166732d0a2105988e538baaffff1182fd5a23883da255b3bf62c187475b46", - "sha256:39308882e7bcdbd17e2d2b3be96e34ed475f60205bc90cb86694d0bcfc955bbc", - "sha256:523094cd2593d31c71ce2d6b2942389fa9d231dce9f8825bfec9e2fdc545e037", - "sha256:7bd67f60ca3da7dbe39ab2a296b5322f8e8248d59d7573068deeeb9b0f901895" - ], - "index": "pypi", - "version": "==2023.1.0" - }, - "nptyping": { - "hashes": [ - "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8", - "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a" - ], - "index": "pypi", - "version": "==2.5.0" - }, - "numpy": { - "hashes": [ - "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187", - "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812", - "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7", - "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4", - "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6", - "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0", - "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4", - "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570", - "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4", - "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f", - "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80", - "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289", - "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385", - "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078", - "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c", - "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463", - "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3", - "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950", - "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155", - "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7", - "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c", - "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096", - "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17", - "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf", - "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4", - "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02", - "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c", - "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b" - ], - "index": "pypi", - "version": "==1.24.3" - }, - "pickle5": { - "hashes": [ - "sha256:7e013be68ba7dde1de5a8dbcc241f201dab1126e326715916ce4a26c27919ffc" - ], - "index": "pypi", - "version": "==0.0.11" - }, - "pyinstaller": { - "hashes": [ - "sha256:247b99c52dc3cf69eba905da30dbca0a8ea309e1058cab44658ac838d9b8f2f0", - "sha256:2d16641a495593d174504263b038a6d3d46b3b15a381ccb216cf6cce67723512", - "sha256:333b4ffda38d9c0a561c38429dd9848d37aa78f3b8ea8a6f2b2e69a60d523c02", - "sha256:6afc7aa4885ffd3e6121a8cf2138830099f874c18cb5869bed8c1a42db82d060", - "sha256:6ecc464bf56919bf2d6bff275f38d85ff08ae747b8ead3a0c26cf85573b3c723", - "sha256:7a1db833bb0302b66ae3ae337fbd5487699658ce869ca4d538b5359b8179e83a", - "sha256:85e39e36d03355423636907a26a9bfa06fdc93cb1086441b19d2d0ca448479fa", - "sha256:915a502802c751bafd92d568ac57468ec6cdf252b8308aa9a167bbc2c565ad2d", - "sha256:9e9a38f41f8280c8e29b294716992852281b41fbe64ba330ebab671efe27b26d", - "sha256:bb7de35cd209a0a0358aec761a273ae951d2161c03728f15d9a640d06a88e472", - "sha256:df97aaf1103a1c485aa3c9947792a86675e370f5ce9b436b4a84e34a4180c8d2", - "sha256:f677fbc151db1eb00ada94e86ed128e7b359cbd6bf3f6ea815afdde687692d46" - ], - "index": "pypi", - "version": "==5.10.1" - }, - "pyinstaller-hooks-contrib": { - "hashes": [ - "sha256:7fb856a81fd06a717188a3175caa77e902035cc067b00b583c6409c62497b23f", - "sha256:e02c5f0ee3d4f5814588c2128caf5036c058ba764aaf24d957bb5311ad8690ad" - ], - "markers": "python_version >= '3.7'", - "version": "==2023.2" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "index": "pypi", - "version": "==6.0" - }, - "setproctitle": { - "hashes": [ - "sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b", - "sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9", - "sha256:1f0cde41857a644b7353a0060b5f94f7ba7cf593ebde5a1094da1be581ac9a31", - "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83", - "sha256:1fa1a0fbee72b47dc339c87c890d3c03a72ea65c061ade3204f285582f2da30f", - "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", - "sha256:630f6fe5e24a619ccf970c78e084319ee8be5be253ecc9b5b216b0f474f5ef18", - "sha256:65d884e22037b23fa25b2baf1a3316602ed5c5971eb3e9d771a38c3a69ce6e13", - "sha256:6c877691b90026670e5a70adfbcc735460a9f4c274d35ec5e8a43ce3f8443005", - "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02", - "sha256:7a55fe05f15c10e8c705038777656fe45e3bd676d49ad9ac8370b75c66dd7cd7", - "sha256:7aa0aac1711fadffc1d51e9d00a3bea61f68443d6ac0241a224e4d622489d665", - "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", - "sha256:b617f12c9be61e8f4b2857be4a4319754756845dbbbd9c3718f468bbb1e17bcb", - "sha256:b9fb97907c830d260fa0658ed58afd48a86b2b88aac521135c352ff7fd3477fd", - "sha256:bae283e85fc084b18ffeb92e061ff7ac5af9e183c9d1345c93e178c3e5069cbe", - "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806", - "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484", - "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e", - "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc", - "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de", - "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575", - "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7", - "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76", - "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246", - "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb", - "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099", - "sha256:e43f315c68aa61cbdef522a2272c5a5b9b8fd03c301d3167b5e1343ef50c676c", - "sha256:e49ae693306d7624015f31cb3e82708916759d592c2e5f72a35c8f4cc8aef258", - "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865", - "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b", - "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d", - "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e", - "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10", - "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f", - "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94", - "sha256:faec934cfe5fd6ac1151c02e67156c3f526e82f96b24d550b5d51efa4a5527c6", - "sha256:fcd3cf4286a60fdc95451d8d14e0389a6b4f5cebe02c7f2609325eb016535963", - "sha256:fe8a988c7220c002c45347430993830666e55bc350179d91fcee0feafe64e1d4", - "sha256:fed18e44711c5af4b681c2b3b18f85e6f0f1b2370a28854c645d636d5305ccd8", - "sha256:ffc61a388a5834a97953d6444a2888c24a05f2e333f9ed49f977a87bb1ad4761" - ], - "index": "pypi", - "version": "==1.3.2" - }, - "setuptools": { - "hashes": [ - "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b", - "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990" - ], - "markers": "python_version >= '3.7'", - "version": "==67.7.2" - }, - "typing": { - "hashes": [ - "sha256:1187fb9c82fd670d10aa07bbb6cfcfe4bdda42d6fab8d5134f04e8c4d0b71cc9", - "sha256:283d868f5071ab9ad873e5e52268d611e851c870a2ba354193026f2dfb29d8b5" - ], - "index": "pypi", - "version": "==3.7.4.3" - }, - "typing-extensions": { - "hashes": [ - "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb", - "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4" - ], - "markers": "python_version < '3.10'", - "version": "==4.5.0" - } - }, - "develop": { - "altgraph": { - "hashes": [ - "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd", - "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe" - ], - "version": "==0.17.3" - }, - "coverage": { - "hashes": [ - "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93", - "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013", - "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f", - "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21", - "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462", - "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc", - "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df", - "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1", - "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235", - "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934", - "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9", - "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1", - "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48", - "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4", - "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe", - "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a", - "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b", - "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21", - "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d", - "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa", - "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367", - "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535", - "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152", - "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e", - "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539", - "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1", - "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925", - "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0", - "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2", - "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab", - "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841", - "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30", - "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91", - "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c", - "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257", - "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9", - "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040", - "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911", - "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623", - "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259", - "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c", - "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79", - "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5", - "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4", - "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4", - "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22", - "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd", - "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1", - "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910", - "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859", - "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312" - ], - "index": "pypi", - "version": "==7.2.3" - }, - "pyinstaller": { - "hashes": [ - "sha256:247b99c52dc3cf69eba905da30dbca0a8ea309e1058cab44658ac838d9b8f2f0", - "sha256:2d16641a495593d174504263b038a6d3d46b3b15a381ccb216cf6cce67723512", - "sha256:333b4ffda38d9c0a561c38429dd9848d37aa78f3b8ea8a6f2b2e69a60d523c02", - "sha256:6afc7aa4885ffd3e6121a8cf2138830099f874c18cb5869bed8c1a42db82d060", - "sha256:6ecc464bf56919bf2d6bff275f38d85ff08ae747b8ead3a0c26cf85573b3c723", - "sha256:7a1db833bb0302b66ae3ae337fbd5487699658ce869ca4d538b5359b8179e83a", - "sha256:85e39e36d03355423636907a26a9bfa06fdc93cb1086441b19d2d0ca448479fa", - "sha256:915a502802c751bafd92d568ac57468ec6cdf252b8308aa9a167bbc2c565ad2d", - "sha256:9e9a38f41f8280c8e29b294716992852281b41fbe64ba330ebab671efe27b26d", - "sha256:bb7de35cd209a0a0358aec761a273ae951d2161c03728f15d9a640d06a88e472", - "sha256:df97aaf1103a1c485aa3c9947792a86675e370f5ce9b436b4a84e34a4180c8d2", - "sha256:f677fbc151db1eb00ada94e86ed128e7b359cbd6bf3f6ea815afdde687692d46" - ], - "index": "pypi", - "version": "==5.10.1" - }, - "pyinstaller-hooks-contrib": { - "hashes": [ - "sha256:7fb856a81fd06a717188a3175caa77e902035cc067b00b583c6409c62497b23f", - "sha256:e02c5f0ee3d4f5814588c2128caf5036c058ba764aaf24d957bb5311ad8690ad" - ], - "markers": "python_version >= '3.7'", - "version": "==2023.2" - }, - "setuptools": { - "hashes": [ - "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b", - "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990" - ], - "markers": "python_version >= '3.7'", - "version": "==67.7.2" - } - } -} diff --git a/diceplayer/player.py b/diceplayer/player.py index 677ec3d..11a3df2 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,5 +1,3 @@ -import pickle - from diceplayer.shared.interface.gaussian_interface import GaussianInterface from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.utils.dataclass_protocol import Dataclass @@ -16,6 +14,7 @@ from diceplayer import logger from dataclasses import fields from typing import Type, Tuple from pathlib import Path +import pickle import yaml import sys import os diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index f79bc0a..4b28774 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -166,14 +166,11 @@ class DiceInterface(Interface): def _make_init_file(self, proc_dir: Path, last_xyz_file: TextIO): xyz_lines = last_xyz_file.readlines() - HEADER_LENGTH = 2 - MAIN_MOLECULE_LENGTH = len(self.system.molecule[0].atom) - - SECONDARY_MOLECULES_LENGTH = HEADER_LENGTH + MAIN_MOLECULE_LENGTH + SECONDARY_MOLECULE_LENGTH = 0 for i in range(1, len(self.step.dice.nmol)): - SECONDARY_MOLECULES_LENGTH += self.step.dice.nmol[i] * len(self.system.molecule[i].atom) + SECONDARY_MOLECULE_LENGTH += self.step.dice.nmol[i] * len(self.system.molecule[i].atom) - xyz_lines = xyz_lines[HEADER_LENGTH + MAIN_MOLECULE_LENGTH: SECONDARY_MOLECULES_LENGTH] + xyz_lines = xyz_lines[-SECONDARY_MOLECULE_LENGTH:] input_file = Path(proc_dir, self.step.dice.outname + ".xy") with open(input_file, 'w') as f: diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..88d56fe --- /dev/null +++ b/poetry.lock @@ -0,0 +1,264 @@ +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + +[[package]] +name = "argparse" +version = "1.4.0" +description = "Python command-line parsing library" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "argparse-1.4.0-py2.py3-none-any.whl", hash = "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314"}, + {file = "argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4"}, +] + +[[package]] +name = "coverage" +version = "7.2.7" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "numpy" +version = "1.24.3" +description = "Fundamental package for array computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"}, + {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"}, + {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"}, + {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"}, + {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"}, + {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"}, + {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"}, + {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"}, + {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"}, + {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"}, +] + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "setproctitle" +version = "1.3.2" +description = "A Python module to customize the process title" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setproctitle-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:288943dec88e178bb2fd868adf491197cc0fc8b6810416b1c6775e686bab87fe"}, + {file = "setproctitle-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:630f6fe5e24a619ccf970c78e084319ee8be5be253ecc9b5b216b0f474f5ef18"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c877691b90026670e5a70adfbcc735460a9f4c274d35ec5e8a43ce3f8443005"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a55fe05f15c10e8c705038777656fe45e3bd676d49ad9ac8370b75c66dd7cd7"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab45146c71ca6592c9cc8b354a2cc9cc4843c33efcbe1d245d7d37ce9696552d"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:265ecbe2c6eafe82e104f994ddd7c811520acdd0647b73f65c24f51374cf9494"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, + {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, + {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, + {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, + {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, + {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e49ae693306d7624015f31cb3e82708916759d592c2e5f72a35c8f4cc8aef258"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1ff863a20d1ff6ba2c24e22436a3daa3cd80be1dfb26891aae73f61b54b04aca"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:55ce1e9925ce1765865442ede9dca0ba9bde10593fcd570b1f0fa25d3ec6b31c"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7fe9df7aeb8c64db6c34fc3b13271a363475d77bc157d3f00275a53910cb1989"}, + {file = "setproctitle-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865"}, + {file = "setproctitle-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a499fff50387c1520c085a07578a000123f519e5f3eee61dd68e1d301659651f"}, + {file = "setproctitle-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b932c3041aa924163f4aab970c2f0e6b4d9d773f4d50326e0ea1cd69240e5c5"}, + {file = "setproctitle-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd3cf4286a60fdc95451d8d14e0389a6b4f5cebe02c7f2609325eb016535963"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fb4f769c02f63fac90989711a3fee83919f47ae9afd4758ced5d86596318c65"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5194b4969f82ea842a4f6af2f82cd16ebdc3f1771fb2771796e6add9835c1973"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cde41857a644b7353a0060b5f94f7ba7cf593ebde5a1094da1be581ac9a31"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9124bedd8006b0e04d4e8a71a0945da9b67e7a4ab88fdad7b1440dc5b6122c42"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:8ff3c8cb26afaed25e8bca7b9dd0c1e36de71f35a3a0706b5c0d5172587a3827"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:589be87172b238f839e19f146b9ea47c71e413e951ef0dc6db4218ddacf3c202"}, + {file = "setproctitle-1.3.2-cp38-cp38-win32.whl", hash = "sha256:4749a2b0c9ac52f864d13cee94546606f92b981b50e46226f7f830a56a9dc8e1"}, + {file = "setproctitle-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:e43f315c68aa61cbdef522a2272c5a5b9b8fd03c301d3167b5e1343ef50c676c"}, + {file = "setproctitle-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76"}, + {file = "setproctitle-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4058564195b975ddc3f0462375c533cce310ccdd41b80ac9aed641c296c3eff4"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffc61a388a5834a97953d6444a2888c24a05f2e333f9ed49f977a87bb1ad4761"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fa1a0fbee72b47dc339c87c890d3c03a72ea65c061ade3204f285582f2da30f"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8a988c7220c002c45347430993830666e55bc350179d91fcee0feafe64e1d4"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bae283e85fc084b18ffeb92e061ff7ac5af9e183c9d1345c93e178c3e5069cbe"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fed18e44711c5af4b681c2b3b18f85e6f0f1b2370a28854c645d636d5305ccd8"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:b34baef93bfb20a8ecb930e395ccd2ae3268050d8cf4fe187de5e2bd806fd796"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7f0bed90a216ef28b9d227d8d73e28a8c9b88c0f48a082d13ab3fa83c581488f"}, + {file = "setproctitle-1.3.2-cp39-cp39-win32.whl", hash = "sha256:4d8938249a7cea45ab7e1e48b77685d0f2bab1ebfa9dde23e94ab97968996a7c"}, + {file = "setproctitle-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:a47d97a75fd2d10c37410b180f67a5835cb1d8fdea2648fd7f359d4277f180b9"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:2fbd8187948284293f43533c150cd69a0e4192c83c377da837dbcd29f6b83084"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:faec934cfe5fd6ac1151c02e67156c3f526e82f96b24d550b5d51efa4a5527c6"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b617f12c9be61e8f4b2857be4a4319754756845dbbbd9c3718f468bbb1e17bcb"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b2c9cb2705fc84cb8798f1ba74194f4c080aaef19d9dae843591c09b97678e98"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a149a5f7f2c5a065d4e63cb0d7a4b6d3b66e6e80f12e3f8827c4f63974cbf122"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e3ac25bfc4a0f29d2409650c7532d5ddfdbf29f16f8a256fc31c47d0dc05172"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65d884e22037b23fa25b2baf1a3316602ed5c5971eb3e9d771a38c3a69ce6e13"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7aa0aac1711fadffc1d51e9d00a3bea61f68443d6ac0241a224e4d622489d665"}, + {file = "setproctitle-1.3.2.tar.gz", hash = "sha256:b9fb97907c830d260fa0658ed58afd48a86b2b88aac521135c352ff7fd3477fd"}, +] + +[package.extras] +test = ["pytest"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "9d6162d0b954236bf441f7fdd3b4b56e47865eb3c11fbd37fda44c30042a68cb" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b340753 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,22 @@ +[tool.poetry] +name = "diceplayer" +version = "0.0.1" +description = "" +authors = ["Vitor Hideyoshi ", "Herbert Georg "] +license = "GPL-2.0-only" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.8" +numpy = "^1.24.3" +argparse = "^1.4.0" +setproctitle = "^1.3.2" +pyyaml = "^6.0" + + +[tool.poetry.group.dev.dependencies] +coverage = "^7.2.7" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" From 6e10d07416e30197568937ec5bbd1a871974e697 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 11 Jun 2023 15:36:08 -0300 Subject: [PATCH 18/18] Changes Project to Poetry --- .github/workflows/python-tests.yml | 6 ++-- .gitignore | 2 ++ diceplayer/player.py | 2 +- poetry.lock | 51 +++++++++++++++++++++++++++++- pyproject.toml | 2 ++ tests/test_player.py | 10 ------ 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 554cb0f..86f6811 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -23,8 +23,8 @@ jobs: python-version: "3.8" - name: Install dependencies run: | - python -m pip install --upgrade pip pipenv - if [ -f Pipfile ]; then pipenv install; fi + python -m pip install --upgrade pip poetry; + [ -f pyproject.toml ] && poetry install; - name: Test with unittest run: | - pipenv run python -m unittest -v \ No newline at end of file + poetry run python -m unittest -v \ No newline at end of file diff --git a/.gitignore b/.gitignore index 58f5f60..080d9dc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ simfiles/* *.pkl *.xyz + +dist/ diff --git a/diceplayer/player.py b/diceplayer/player.py index 11a3df2..a7aa562 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -59,7 +59,7 @@ class Player: "==========================================================================================\n" ) - for cycle in range(self.initial_cycle, self.initial_cycle + self.config.maxcyc + 1): + for cycle in range(self.initial_cycle, self.initial_cycle + self.config.maxcyc): logger.info( f"------------------------------------------------------------------------------------------\n" diff --git a/poetry.lock b/poetry.lock index 88d56fe..cd030c8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -85,6 +85,43 @@ files = [ [package.extras] toml = ["tomli"] +[[package]] +name = "dacite" +version = "1.8.1" +description = "Simple creation of data classes from dictionaries." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "dacite-1.8.1-py3-none-any.whl", hash = "sha256:cc31ad6fdea1f49962ea42db9421772afe01ac5442380d9a99fcf3d188c61afe"}, +] + +[package.extras] +dev = ["black", "coveralls", "mypy", "pre-commit", "pylint", "pytest (>=5)", "pytest-benchmark", "pytest-cov"] + +[[package]] +name = "nptyping" +version = "2.5.0" +description = "Type hints for NumPy." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8"}, + {file = "nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a"}, +] + +[package.dependencies] +numpy = {version = ">=1.20.0,<2.0.0", markers = "python_version >= \"3.8\""} +typing-extensions = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +build = ["invoke (>=1.6.0)", "pip-tools (>=6.5.0)"] +complete = ["pandas", "pandas-stubs-fork"] +dev = ["autoflake", "beartype (<0.10.0)", "beartype (>=0.10.0)", "black", "codecov (>=2.1.0)", "coverage", "feedparser", "invoke (>=1.6.0)", "isort", "mypy", "pandas", "pandas-stubs-fork", "pip-tools (>=6.5.0)", "pylint", "pyright", "setuptools", "typeguard", "wheel"] +pandas = ["pandas", "pandas-stubs-fork"] +qa = ["autoflake", "beartype (<0.10.0)", "beartype (>=0.10.0)", "black", "codecov (>=2.1.0)", "coverage", "feedparser", "isort", "mypy", "pylint", "pyright", "setuptools", "typeguard", "wheel"] + [[package]] name = "numpy" version = "1.24.3" @@ -258,7 +295,19 @@ files = [ [package.extras] test = ["pytest"] +[[package]] +name = "typing-extensions" +version = "4.6.3" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, + {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, +] + [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "9d6162d0b954236bf441f7fdd3b4b56e47865eb3c11fbd37fda44c30042a68cb" +content-hash = "5767445dc10a28eeb01ba23bfbf781b68d8c158df80be696d53cb0c962d409ab" diff --git a/pyproject.toml b/pyproject.toml index b340753..1d79fae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,8 @@ numpy = "^1.24.3" argparse = "^1.4.0" setproctitle = "^1.3.2" pyyaml = "^6.0" +dacite = "^1.8.1" +nptyping = "^2.5.0" [tool.poetry.group.dev.dependencies] diff --git a/tests/test_player.py b/tests/test_player.py index d1b50e9..f6071a0 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -335,16 +335,6 @@ class TestPlayer(unittest.TestCase): player.dice_interface.start.assert_called_once() - # @mock.patch("builtins.open", mock_open) - # def test_gaussian_start(self): - # player = Player("control.test.yml") - # player.gaussian_interface = mock.MagicMock() - # player.gaussian_interface.start = mock.MagicMock() - # - # player.gaussian_start(1) - # - # player.gaussian_interface.start.assert_called_once() - if __name__ == '__main__': unittest.main()