From 60115f5a05b2969662ee115f6c78638d86d52203 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 31 Jan 2022 13:09:54 +0100 Subject: [PATCH 01/13] refactor: basic HDF5Driver update --- .../second_quantization/hdf5d/hdf5driver.py | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index 53cf9ef76d..63d890f712 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -12,14 +12,20 @@ """ HDF5 Driver """ +import logging import os import warnings +import h5py + +from qiskit_nature.hdf5 import load_from_hdf5 from qiskit_nature.properties.second_quantization.electronic import ElectronicStructureDriverResult from ...qmolecule import QMolecule from ..electronic_structure_driver import ElectronicStructureDriver +LOGGER = logging.getLogger(__name__) + class HDF5Driver(ElectronicStructureDriver): """ @@ -62,8 +68,38 @@ def run(self) -> ElectronicStructureDriverResult: if not os.path.isfile(hdf5_file): raise LookupError(f"HDF5 file not found: {hdf5_file}") - warnings.filterwarnings("ignore", category=DeprecationWarning) - molecule = QMolecule(hdf5_file) - warnings.filterwarnings("default", category=DeprecationWarning) - molecule.load() - return ElectronicStructureDriverResult.from_legacy_driver_result(molecule) + legacy_hdf5_file = False + + with h5py.File(hdf5_file, "r") as file: + if "origin_driver" in file.keys(): + legacy_hdf5_file = True + LOGGER.warning( + "Your HDF5 file contains the legacy QMolecule object! You should consider " + "converting it to the new property framework." + ) + + if legacy_hdf5_file: + warnings.filterwarnings("ignore", category=DeprecationWarning) + molecule = QMolecule(hdf5_file) + warnings.filterwarnings("default", category=DeprecationWarning) + molecule.load() + return ElectronicStructureDriverResult.from_legacy_driver_result(molecule) + + driver_result: ElectronicStructureDriverResult = None + for prop in load_from_hdf5(hdf5_file): + if not isinstance(prop, ElectronicStructureDriverResult): + LOGGER.warning( + "Ignoring the %s object encountered in your HDF5 file. The HDF5Driver must " + "return an ElectronicStructureDriverResult!", + type(prop), + ) + continue + if driver_result is None: + driver_result = prop + else: + LOGGER.error( + "The HDF5Driver can only handle a single ElectronicStructureDriverResult within" + " an HDF5 file!" + ) + break + return driver_result From 2e108f6aea0e6586c3fc0506766852275db17467 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 31 Jan 2022 13:22:55 +0100 Subject: [PATCH 02/13] test: test both HDF5 type supports --- .../hdf5d/test_driver_hdf5.hdf5 | Bin 15664 -> 48475 bytes .../hdf5d/test_driver_hdf5.py | 14 +++++ .../hdf5d/test_driver_hdf5_legacy.hdf5 | Bin 0 -> 15664 bytes .../hdf5d/test_driver_hdf5_save.py | 53 ------------------ 4 files changed, 14 insertions(+), 53 deletions(-) create mode 100644 test/drivers/second_quantization/hdf5d/test_driver_hdf5_legacy.hdf5 delete mode 100644 test/drivers/second_quantization/hdf5d/test_driver_hdf5_save.py diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.hdf5 b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.hdf5 index 1f6b7af0cd8a6a56c1f6ede2b4f53a555094f86f..30005d318bda96344b57e1811fbef5d539c7ed3e 100644 GIT binary patch literal 48475 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 literal 15664 zcmeGjOKcle@HwC28jzCk3#HJdDkY(%geEO%0oj$3)F3`?6Ci?v?Ko?D!S-7IL{6a< z5)uUEQX~%C;J_i`LJlCx$vGeuRY(+s5C_y4RMHlT1OiGANa5|yjNN^!UB|8?$B8#e z=FOXVpP8MR_vXFL+uos(n_XL6OnaP8*2X&YBK=v$r|)s7A)M#|EI1I(Ae?J~f`e&4 zjCEsuC-yJ$jU62xW}K7yCy32hp&d$2s%XLur2+5oA)hAjJW4%|aPT20SlOAcALz+_ z*q}mS)vvb|I*OuQmb2dgx>eJDD|`X#gq`e{?3Uu;4B8KgnFz*ZtsGJlVI`tPM0h+1 zD+Qy^JUirIo0#rAyz!UCxC}js{z3B^L_?+VPjvzR54QsB1Hh!apg?>J+W{}^0O$e0 zyaL|`yMeH<2cU#}r*Hz)Ux6ls?a6;6^grSg{SmvX8PIg7kA(v|7|evmZ{@gFzJ>p3 zdQ>FK(rzwh7K@)Be3m56JwWEB@hJMoP^F%VZ{awr>< zrRZMiRhJ}5ebU1k@JfAq`si1zc%*-y>$uC6mNR;riC|huOX-aIV1IaB%U@{Ln}LME~1-!Hp(f^d0>La2Hq>uDCsCV#`2faR3yaFPU(f&UCOD1tVt=F;vA&5nHPF;RQv*#6tQQTy{66*XZb7jp`UIuKxaKZQK7Q*vX*=V1dkvVmpHXRZDA z3-nuxkT9^>Z)b!V)fc7sPqX&jWpS|{jUA%J@6z;jG1I}^`2t@y-qPEvb$f9}xNnhx%r;GiD8srCBs-3tBq zBu!yWL0Bi+8LiWQY_p#ptrKVOw&&|Xa^W6(K2#pd;W@Jvx0eX_Qekbu+S}ES4Q*Go z*T?yFrjH)ofE{p6!RUYt%qrZNzLJ5Lp}!IQ19xP`&&& zZ3bC73?iB3&l%|TLK4}yUrkLYnP4of%|XM1v1Bxe6VmVrIYTImtNxHGhr={qYzx_w zBI|upOaDJv|$PIvOhf?pHO3Z|2m$VK1PF4Jg0a?_0>YNJwqT8 z_vd(AT->h{Uj6=bKfYgzfFObS{YI-5t*UnA_IFoty3VS4Z#HUl4bc8>90dVyVXT1P z6_R{BKT#91>{k*Q-L*L`r<5XE%u9^cPpz$?no=T4!atc(rsNc7qsydgb0@8JL{{T+ zCPmjwjL$=kq%gVS^hqVjzmhBEMgrf~sM$wKc#jCfwH_`51H@q3M-NAefOxJ;wU9a{- z=M<-|W2k1+2GjtpSMxacD8l5Ut1FDzPr(AkeWjIuR_}+K;D5`QWDwBoholJu+o~br zeN*6|{ZKw6OOM&}Igxy^%>Nq|*PTK8{@^X~^U?$MeD$K%&#rc^NxQ0_K1LcuA7J@( zzf#Iu!Gf!gGhvjUJPZ0W$C+HcT*WYM&d+!Jex8M3LNYDj#{`_dOM^UtH;l`P4DT@| z^SmQ1Yur44@TZkXLLZ0DCA@}FD@V-s3=xj{Z)H7t?$pf}4y{f*&jy;4jU0MvbePwT Y9eqv%I>GvU=>)z%>RE5W*4q2~AI5V#_y7O^ diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py index a7cd8f8058..bdf72d07ff 100644 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py +++ b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py @@ -13,6 +13,7 @@ """ Test Driver HDF5 """ import unittest + from test import QiskitNatureTestCase from test.drivers.second_quantization.test_driver import TestDriver from qiskit_nature.drivers.second_quantization import HDF5Driver @@ -31,5 +32,18 @@ def setUp(self): self.driver_result = driver.run() +class TestDriverHDF5Legacy(QiskitNatureTestCase, TestDriver): + """HDF5 Driver legacy file-support tests.""" + + def setUp(self): + super().setUp() + driver = HDF5Driver( + hdf5_input=self.get_resource_path( + "test_driver_hdf5_legacy.hdf5", "drivers/second_quantization/hdf5d" + ) + ) + self.driver_result = driver.run() + + if __name__ == "__main__": unittest.main() diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5_legacy.hdf5 b/test/drivers/second_quantization/hdf5d/test_driver_hdf5_legacy.hdf5 new file mode 100644 index 0000000000000000000000000000000000000000..1f6b7af0cd8a6a56c1f6ede2b4f53a555094f86f GIT binary patch literal 15664 zcmeGjOKcle@HwC28jzCk3#HJdDkY(%geEO%0oj$3)F3`?6Ci?v?Ko?D!S-7IL{6a< z5)uUEQX~%C;J_i`LJlCx$vGeuRY(+s5C_y4RMHlT1OiGANa5|yjNN^!UB|8?$B8#e z=FOXVpP8MR_vXFL+uos(n_XL6OnaP8*2X&YBK=v$r|)s7A)M#|EI1I(Ae?J~f`e&4 zjCEsuC-yJ$jU62xW}K7yCy32hp&d$2s%XLur2+5oA)hAjJW4%|aPT20SlOAcALz+_ z*q}mS)vvb|I*OuQmb2dgx>eJDD|`X#gq`e{?3Uu;4B8KgnFz*ZtsGJlVI`tPM0h+1 zD+Qy^JUirIo0#rAyz!UCxC}js{z3B^L_?+VPjvzR54QsB1Hh!apg?>J+W{}^0O$e0 zyaL|`yMeH<2cU#}r*Hz)Ux6ls?a6;6^grSg{SmvX8PIg7kA(v|7|evmZ{@gFzJ>p3 zdQ>FK(rzwh7K@)Be3m56JwWEB@hJMoP^F%VZ{awr>< zrRZMiRhJ}5ebU1k@JfAq`si1zc%*-y>$uC6mNR;riC|huOX-aIV1IaB%U@{Ln}LME~1-!Hp(f^d0>La2Hq>uDCsCV#`2faR3yaFPU(f&UCOD1tVt=F;vA&5nHPF;RQv*#6tQQTy{66*XZb7jp`UIuKxaKZQK7Q*vX*=V1dkvVmpHXRZDA z3-nuxkT9^>Z)b!V)fc7sPqX&jWpS|{jUA%J@6z;jG1I}^`2t@y-qPEvb$f9}xNnhx%r;GiD8srCBs-3tBq zBu!yWL0Bi+8LiWQY_p#ptrKVOw&&|Xa^W6(K2#pd;W@Jvx0eX_Qekbu+S}ES4Q*Go z*T?yFrjH)ofE{p6!RUYt%qrZNzLJ5Lp}!IQ19xP`&&& zZ3bC73?iB3&l%|TLK4}yUrkLYnP4of%|XM1v1Bxe6VmVrIYTImtNxHGhr={qYzx_w zBI|upOaDJv|$PIvOhf?pHO3Z|2m$VK1PF4Jg0a?_0>YNJwqT8 z_vd(AT->h{Uj6=bKfYgzfFObS{YI-5t*UnA_IFoty3VS4Z#HUl4bc8>90dVyVXT1P z6_R{BKT#91>{k*Q-L*L`r<5XE%u9^cPpz$?no=T4!atc(rsNc7qsydgb0@8JL{{T+ zCPmjwjL$=kq%gVS^hqVjzmhBEMgrf~sM$wKc#jCfwH_`51H@q3M-NAefOxJ;wU9a{- z=M<-|W2k1+2GjtpSMxacD8l5Ut1FDzPr(AkeWjIuR_}+K;D5`QWDwBoholJu+o~br zeN*6|{ZKw6OOM&}Igxy^%>Nq|*PTK8{@^X~^U?$MeD$K%&#rc^NxQ0_K1LcuA7J@( zzf#Iu!Gf!gGhvjUJPZ0W$C+HcT*WYM&d+!Jex8M3LNYDj#{`_dOM^UtH;l`P4DT@| z^SmQ1Yur44@TZkXLLZ0DCA@}FD@V-s3=xj{Z)H7t?$pf}4y{f*&jy;4jU0MvbePwT Y9eqv%I>GvU=>)z%>RE5W*4q2~AI5V#_y7O^ literal 0 HcmV?d00001 diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5_save.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5_save.py deleted file mode 100644 index 304222ef16..0000000000 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5_save.py +++ /dev/null @@ -1,53 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2020, 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" Test Driver HDF5 via saved QMolecule on new HDF5 """ - -import unittest -import tempfile -import os - -from test import QiskitNatureTestCase -from test.drivers.second_quantization.test_driver import TestDriver -from qiskit_nature.drivers.second_quantization import HDF5Driver - - -@unittest.skip("Until the Property framework supports HDF5 storage") -class TestDriverHDF5Save(QiskitNatureTestCase, TestDriver): - """Use HDF5 Driver to test saved HDF5 from QMolecule""" - - def setUp(self): - super().setUp() - driver = HDF5Driver( - hdf5_input=self.get_resource_path( - "test_driver_hdf5.hdf5", "drivers/second_quantization/hdf5d" - ) - ) - temp_qmolecule = driver.run() - file, self.save_file = tempfile.mkstemp(suffix=".hdf5") - os.close(file) - # pylint: disable=no-member - temp_qmolecule.save(self.save_file) - # Tests are run on self.qmolecule which is from new saved HDF5 file - # so save is tested based on getting expected values as per original - driver = HDF5Driver(hdf5_input=self.save_file) - self.qmolecule = driver.run() - - def tearDown(self): - try: - os.remove(self.save_file) - except OSError: - pass - - -if __name__ == "__main__": - unittest.main() From 1dc81110fcfde7b7e119d765cc4cf3ef7e745171 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Thu, 10 Feb 2022 17:50:04 +0100 Subject: [PATCH 03/13] Fix copyright --- qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py | 2 +- test/drivers/second_quantization/hdf5d/test_driver_hdf5.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index 63d890f712..238c2f0aa1 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2018, 2021. +# (C) Copyright IBM 2018, 2022. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py index bdf72d07ff..0875c3b047 100644 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py +++ b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2018, 2021. +# (C) Copyright IBM 2018, 2022. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory From f2b17357f4ecf3626f68b252d7e05532b1c15410 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Thu, 10 Feb 2022 17:54:16 +0100 Subject: [PATCH 04/13] test: update new expected HDF5 file --- .../hdf5d/test_driver_hdf5.hdf5 | Bin 48475 -> 48547 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.hdf5 b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.hdf5 index 30005d318bda96344b57e1811fbef5d539c7ed3e..132945b7c111480e105a38769a7895168bcebb16 100644 GIT binary patch delta 363 zcmccpi)rz1rU@F1i#KZ43n>~gKmZ4ncFapJE-A{-g>o4jHg6O%XWb-mM3{x$nKfy0 zKyJfk51lKVVBTg0vmRCmYlC$N6GX)Z>ww80tY%OCY^R7UFl#cCgA!a|QnJM62@Wj~ zVj)#nxB{O$3J_L6F3jKq?H!v93QR;HhJYOMqV)oe>%9D45@Gu%pKCovt01dZtSpWb4 delta 319 zcmZ4do9Xs1rU@F1(Hk}Eg(f#7axg`(ZoVj_&pPpd{3eMb!YpSle@~noklV1?L+1)7 zn73KMtcMlC+F%{R1W~cUI$-h#tJ#x3+bJRo%$m&Ppad6~lq|7%fHDsuE6Jx0)!Qi3p4mYd&g#j0uxb)As~mmXuSeef1rI2M0|6@Tx9hL3-)kB z%u!ea6IU=R+WczW2A0WD65^XTZeGqJH-iBJ{5@QPm~=q?M8=cLc06QR(2+H7bM#J_ Tea5?aAU02S-qSRhckeU+YvY>L From 08de4887b5172d900cc471f0449a106db70fb64d Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 14 Feb 2022 09:04:56 +0100 Subject: [PATCH 05/13] ref: align new HDF5Driver with #554 --- .../second_quantization/hdf5d/hdf5driver.py | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index 238c2f0aa1..57dee9b414 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -19,19 +19,23 @@ import h5py from qiskit_nature.hdf5 import load_from_hdf5 +from qiskit_nature.properties.second_quantization.second_quantized_property import ( + GroupedSecondQuantizedProperty, +) from qiskit_nature.properties.second_quantization.electronic import ElectronicStructureDriverResult from ...qmolecule import QMolecule -from ..electronic_structure_driver import ElectronicStructureDriver +from ..base_driver import BaseDriver LOGGER = logging.getLogger(__name__) -class HDF5Driver(ElectronicStructureDriver): +class HDF5Driver(BaseDriver): """ Qiskit Nature driver for reading an HDF5 file. - The HDF5 file is one as saved from a :class:`~qiskit_nature.drivers.QMolecule` instance. + The HDF5 file is one constructed with :func:`~qiskit_nature.hdf5.save_to_hdf5` or a file + containing a legacy :class:`~qiskit_nature.drivers.QMolecule` instance. """ def __init__(self, hdf5_input: str = "molecule.hdf5") -> None: @@ -53,10 +57,10 @@ def work_path(self, new_work_path): """Sets work path.""" self._work_path = new_work_path - def run(self) -> ElectronicStructureDriverResult: + def run(self) -> GroupedSecondQuantizedProperty: """ Returns: - ElectronicStructureDriverResult re-constructed from the HDF5 file. + GroupedSecondQuantizedProperty re-constructed from the HDF5 file. Raises: LookupError: file not found. @@ -85,21 +89,5 @@ def run(self) -> ElectronicStructureDriverResult: molecule.load() return ElectronicStructureDriverResult.from_legacy_driver_result(molecule) - driver_result: ElectronicStructureDriverResult = None - for prop in load_from_hdf5(hdf5_file): - if not isinstance(prop, ElectronicStructureDriverResult): - LOGGER.warning( - "Ignoring the %s object encountered in your HDF5 file. The HDF5Driver must " - "return an ElectronicStructureDriverResult!", - type(prop), - ) - continue - if driver_result is None: - driver_result = prop - else: - LOGGER.error( - "The HDF5Driver can only handle a single ElectronicStructureDriverResult within" - " an HDF5 file!" - ) - break + driver_result = load_from_hdf5(hdf5_file) return driver_result From 24009289bf21d1fea37a42f3d8d1b4a1c45d3a62 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 14 Feb 2022 09:43:06 +0100 Subject: [PATCH 06/13] feat: add HDF5Driver.convert utility method --- .../second_quantization/hdf5d/hdf5driver.py | 46 +++++++++++++--- .../hdf5d/test_driver_hdf5.py | 53 +++++++++++++++++++ 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index 57dee9b414..d50c4737c8 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -18,7 +18,7 @@ import h5py -from qiskit_nature.hdf5 import load_from_hdf5 +from qiskit_nature.hdf5 import load_from_hdf5, save_to_hdf5 from qiskit_nature.properties.second_quantization.second_quantized_property import ( GroupedSecondQuantizedProperty, ) @@ -57,13 +57,11 @@ def work_path(self, new_work_path): """Sets work path.""" self._work_path = new_work_path - def run(self) -> GroupedSecondQuantizedProperty: - """ - Returns: - GroupedSecondQuantizedProperty re-constructed from the HDF5 file. + def _get_path(self) -> str: + """Returns the absolute path to the HDF5 file. Raises: - LookupError: file not found. + LoopupError: file not found. """ hdf5_file = self._hdf5_input if self.work_path is not None and not os.path.isabs(hdf5_file): @@ -72,6 +70,40 @@ def run(self) -> GroupedSecondQuantizedProperty: if not os.path.isfile(hdf5_file): raise LookupError(f"HDF5 file not found: {hdf5_file}") + return hdf5_file + + def convert(self, replace: bool = True) -> None: + """Converts a legacy QMolecule HDF5 file into the new Property-framework. + + Args: + replace: if True, will replace the original HDF5 file. Otherwise `.new` will be used as + a suffix. + + Raises: + LookupError: file not found. + """ + hdf5_file = self._get_path() + + warnings.filterwarnings("ignore", category=DeprecationWarning) + q_mol = QMolecule(hdf5_file) + warnings.filterwarnings("default", category=DeprecationWarning) + q_mol.load() + + new_hdf5_file = hdf5_file if replace else hdf5_file + ".new" + + driver_result = ElectronicStructureDriverResult.from_legacy_driver_result(q_mol) + save_to_hdf5(driver_result, new_hdf5_file, replace=replace) + + def run(self) -> GroupedSecondQuantizedProperty: + """ + Returns: + GroupedSecondQuantizedProperty re-constructed from the HDF5 file. + + Raises: + LookupError: file not found. + """ + hdf5_file = self._get_path() + legacy_hdf5_file = False with h5py.File(hdf5_file, "r") as file: @@ -79,7 +111,7 @@ def run(self) -> GroupedSecondQuantizedProperty: legacy_hdf5_file = True LOGGER.warning( "Your HDF5 file contains the legacy QMolecule object! You should consider " - "converting it to the new property framework." + "converting it to the new property framework. See also HDF5Driver.convert" ) if legacy_hdf5_file: diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py index 0875c3b047..80ca61caad 100644 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py +++ b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py @@ -12,6 +12,9 @@ """ Test Driver HDF5 """ +import os +import shutil +import tempfile import unittest from test import QiskitNatureTestCase @@ -31,6 +34,56 @@ def setUp(self): ) self.driver_result = driver.run() + def test_convert(self): + """Test the legacy-conversion method.""" + legacy_file_path = self.get_resource_path( + "test_driver_hdf5_legacy.hdf5", "drivers/second_quantization/hdf5d" + ) + + with self.subTest("replace=True"): + # pylint: disable=consider-using-with + tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".hdf5") + tmp_file.close() + os.unlink(tmp_file.name) + shutil.copy(legacy_file_path, tmp_file.name) + try: + driver = HDF5Driver(tmp_file.name) + driver.convert() + with self.assertRaises(AssertionError): + # NOTE: we can use assertNoLogs once Python 3.10 is the default + with self.assertLogs( + logger="qiskit_nature.drivers.second_quantization.hdf5d.hdf5driver", + level="WARNING", + ): + driver.run() + finally: + os.unlink(tmp_file.name) + + with self.subTest("replace=False"): + # pylint: disable=consider-using-with + tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".hdf5") + tmp_file.close() + os.unlink(tmp_file.name) + shutil.copy(legacy_file_path, tmp_file.name) + try: + driver = HDF5Driver(tmp_file.name) + driver.convert(replace=False) + with self.assertLogs( + logger="qiskit_nature.drivers.second_quantization.hdf5d.hdf5driver", + level="WARNING", + ): + driver.run() + with self.assertRaises(AssertionError): + # NOTE: we can use assertNoLogs once Python 3.10 is the default + with self.assertLogs( + logger="qiskit_nature.drivers.second_quantization.hdf5d.hdf5driver", + level="WARNING", + ): + HDF5Driver(tmp_file.name + ".new").run() + finally: + os.unlink(tmp_file.name) + os.unlink(tmp_file.name + ".new") + class TestDriverHDF5Legacy(QiskitNatureTestCase, TestDriver): """HDF5 Driver legacy file-support tests.""" From 11abf8beb07596c68ac097b7f76779bb1ca59f21 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 14 Feb 2022 09:50:21 +0100 Subject: [PATCH 07/13] Add reno --- releasenotes/notes/hdf5-driver-bafbbd8e70ee15a6.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 releasenotes/notes/hdf5-driver-bafbbd8e70ee15a6.yaml diff --git a/releasenotes/notes/hdf5-driver-bafbbd8e70ee15a6.yaml b/releasenotes/notes/hdf5-driver-bafbbd8e70ee15a6.yaml new file mode 100644 index 0000000000..38945bcbc8 --- /dev/null +++ b/releasenotes/notes/hdf5-driver-bafbbd8e70ee15a6.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + The HDF5Driver has been refactored to leverage the new HDF5-integration + protocol of Qiskit Nature. The driver still supports loading legacy + QMolecule HDF5 files and also provides a conversion utility: + + .. code-block:: python + + driver = HDF5Driver("path_to_qmolecule.hdf5") + driver.convert(replace=True) From da1bec7663f984b15876f00fc0c402355da7ea87 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 14 Feb 2022 10:22:02 +0100 Subject: [PATCH 08/13] Fix linters --- .../second_quantization/hdf5d/hdf5driver.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index d50c4737c8..33e8c6b789 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -18,6 +18,7 @@ import h5py +from qiskit_nature import QiskitNatureError from qiskit_nature.hdf5 import load_from_hdf5, save_to_hdf5 from qiskit_nature.properties.second_quantization.second_quantized_property import ( GroupedSecondQuantizedProperty, @@ -60,8 +61,11 @@ def work_path(self, new_work_path): def _get_path(self) -> str: """Returns the absolute path to the HDF5 file. + Returns: + The absolute path to the HDF5 file. + Raises: - LoopupError: file not found. + LookupError: file not found. """ hdf5_file = self._hdf5_input if self.work_path is not None and not os.path.isabs(hdf5_file): @@ -101,6 +105,7 @@ def run(self) -> GroupedSecondQuantizedProperty: Raises: LookupError: file not found. + QiskitNatureError: if the HDF5 file did not contain a GroupedSecondQuantizedProperty. """ hdf5_file = self._get_path() @@ -122,4 +127,11 @@ def run(self) -> GroupedSecondQuantizedProperty: return ElectronicStructureDriverResult.from_legacy_driver_result(molecule) driver_result = load_from_hdf5(hdf5_file) + + if not isinstance(driver_result, GroupedSecondQuantizedProperty): + raise QiskitNatureError( + f"Expected a GroupedSecondQuantizedProperty but found a {type(driver_result)} " + "object instead." + ) + return driver_result From 8ba1655175a92136cbda27a587b797e9b201d109 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 21 Feb 2022 14:15:46 +0100 Subject: [PATCH 09/13] refactor: do not replace by default --- qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py | 2 +- test/drivers/second_quantization/hdf5d/test_driver_hdf5.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index 33e8c6b789..fcbdeaab37 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -76,7 +76,7 @@ def _get_path(self) -> str: return hdf5_file - def convert(self, replace: bool = True) -> None: + def convert(self, replace: bool = False) -> None: """Converts a legacy QMolecule HDF5 file into the new Property-framework. Args: diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py index 80ca61caad..203806586a 100644 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py +++ b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py @@ -48,7 +48,7 @@ def test_convert(self): shutil.copy(legacy_file_path, tmp_file.name) try: driver = HDF5Driver(tmp_file.name) - driver.convert() + driver.convert(replace=True) with self.assertRaises(AssertionError): # NOTE: we can use assertNoLogs once Python 3.10 is the default with self.assertLogs( From dd3bee1c1a9634de0726cbfad620c966b1f4ef84 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 21 Feb 2022 14:24:02 +0100 Subject: [PATCH 10/13] refactor: use `_new.hdf5` instead of `.hdf5.new` --- .../second_quantization/hdf5d/hdf5driver.py | 20 ++++++++++--------- .../hdf5d/test_driver_hdf5.py | 8 ++++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index fcbdeaab37..d3a569d28a 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -13,7 +13,7 @@ """ HDF5 Driver """ import logging -import os +import pathlib import warnings import h5py @@ -58,7 +58,7 @@ def work_path(self, new_work_path): """Sets work path.""" self._work_path = new_work_path - def _get_path(self) -> str: + def _get_path(self) -> pathlib.Path: """Returns the absolute path to the HDF5 file. Returns: @@ -67,11 +67,11 @@ def _get_path(self) -> str: Raises: LookupError: file not found. """ - hdf5_file = self._hdf5_input - if self.work_path is not None and not os.path.isabs(hdf5_file): - hdf5_file = os.path.abspath(os.path.join(self.work_path, hdf5_file)) + hdf5_file = pathlib.Path(self._hdf5_input) + if self.work_path is not None and not hdf5_file.is_absolute(): + hdf5_file = pathlib.Path(self.work_path) / hdf5_file - if not os.path.isfile(hdf5_file): + if not hdf5_file.is_file(): raise LookupError(f"HDF5 file not found: {hdf5_file}") return hdf5_file @@ -93,10 +93,12 @@ def convert(self, replace: bool = False) -> None: warnings.filterwarnings("default", category=DeprecationWarning) q_mol.load() - new_hdf5_file = hdf5_file if replace else hdf5_file + ".new" + new_hdf5_file = hdf5_file + if not replace: + new_hdf5_file = hdf5_file.with_stem(str(hdf5_file.stem) + "_new") driver_result = ElectronicStructureDriverResult.from_legacy_driver_result(q_mol) - save_to_hdf5(driver_result, new_hdf5_file, replace=replace) + save_to_hdf5(driver_result, str(new_hdf5_file), replace=replace) def run(self) -> GroupedSecondQuantizedProperty: """ @@ -126,7 +128,7 @@ def run(self) -> GroupedSecondQuantizedProperty: molecule.load() return ElectronicStructureDriverResult.from_legacy_driver_result(molecule) - driver_result = load_from_hdf5(hdf5_file) + driver_result = load_from_hdf5(str(hdf5_file)) if not isinstance(driver_result, GroupedSecondQuantizedProperty): raise QiskitNatureError( diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py index 203806586a..7497208f58 100644 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py +++ b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py @@ -13,6 +13,7 @@ """ Test Driver HDF5 """ import os +import pathlib import shutil import tempfile import unittest @@ -63,6 +64,9 @@ def test_convert(self): # pylint: disable=consider-using-with tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".hdf5") tmp_file.close() + new_file_name = pathlib.Path(tmp_file.name).with_stem( + str(pathlib.Path(tmp_file.name).stem) + "_new" + ) os.unlink(tmp_file.name) shutil.copy(legacy_file_path, tmp_file.name) try: @@ -79,10 +83,10 @@ def test_convert(self): logger="qiskit_nature.drivers.second_quantization.hdf5d.hdf5driver", level="WARNING", ): - HDF5Driver(tmp_file.name + ".new").run() + HDF5Driver(new_file_name).run() finally: os.unlink(tmp_file.name) - os.unlink(tmp_file.name + ".new") + os.unlink(new_file_name) class TestDriverHDF5Legacy(QiskitNatureTestCase, TestDriver): From 5abfbe4c41e45f240f0f60472e6d6bcb4040eea1 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 21 Feb 2022 14:28:09 +0100 Subject: [PATCH 11/13] refactor: update wording --- qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index d3a569d28a..6740e132ac 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -118,7 +118,7 @@ def run(self) -> GroupedSecondQuantizedProperty: legacy_hdf5_file = True LOGGER.warning( "Your HDF5 file contains the legacy QMolecule object! You should consider " - "converting it to the new property framework. See also HDF5Driver.convert" + "converting it to the new property framework, see HDF5Driver.convert" ) if legacy_hdf5_file: From 5766690be7fdb47313180642060a953d05f8ddc0 Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 21 Feb 2022 15:04:40 +0100 Subject: [PATCH 12/13] fix: Python <3.9 compatibility --- qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py | 2 +- test/drivers/second_quantization/hdf5d/test_driver_hdf5.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index 6740e132ac..cfd47e9559 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -95,7 +95,7 @@ def convert(self, replace: bool = False) -> None: new_hdf5_file = hdf5_file if not replace: - new_hdf5_file = hdf5_file.with_stem(str(hdf5_file.stem) + "_new") + new_hdf5_file = hdf5_file.with_name(str(hdf5_file.stem) + "_new.hdf5") driver_result = ElectronicStructureDriverResult.from_legacy_driver_result(q_mol) save_to_hdf5(driver_result, str(new_hdf5_file), replace=replace) diff --git a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py index 7497208f58..2f1a27aec9 100644 --- a/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py +++ b/test/drivers/second_quantization/hdf5d/test_driver_hdf5.py @@ -64,8 +64,8 @@ def test_convert(self): # pylint: disable=consider-using-with tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".hdf5") tmp_file.close() - new_file_name = pathlib.Path(tmp_file.name).with_stem( - str(pathlib.Path(tmp_file.name).stem) + "_new" + new_file_name = pathlib.Path(tmp_file.name).with_name( + str(pathlib.Path(tmp_file.name).stem) + "_new.hdf5" ) os.unlink(tmp_file.name) shutil.copy(legacy_file_path, tmp_file.name) From 0df43efc854f09ba15959350b5091207fc821b6f Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Mon, 21 Feb 2022 17:07:13 +0100 Subject: [PATCH 13/13] Update docstring --- qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py index cfd47e9559..4b8ef77f1d 100644 --- a/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py +++ b/qiskit_nature/drivers/second_quantization/hdf5d/hdf5driver.py @@ -80,8 +80,8 @@ def convert(self, replace: bool = False) -> None: """Converts a legacy QMolecule HDF5 file into the new Property-framework. Args: - replace: if True, will replace the original HDF5 file. Otherwise `.new` will be used as - a suffix. + replace: if True, will replace the original HDF5 file. Otherwise `_new.hdf5` will be + used as a suffix. Raises: LookupError: file not found.