diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index f0570fb..7a23aa0 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -2,12 +2,14 @@ name: TREXIO CI on: push: - branches: [ master ] + branches: + - master + tags: + # After vMajor.Minor.Patch _anything_ is allowed (without "/") ! + - v[0-9]+.[0-9]+.[0-9]+* pull_request: branches: [ master ] - release: - types: - - published + jobs: diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 5baf3d7..f6b8ded 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -38,7 +38,7 @@ jobs: needs: get_commit_message if: >- contains(needs.get_commit_message.outputs.message, '[wheel build]') || - github.event_name == 'release' + (github.repository == 'TREX-CoE/trexio' && startsWith(github.ref, 'refs/tags/v')) runs-on: ubuntu-latest strategy: matrix: @@ -99,7 +99,7 @@ jobs: needs: get_commit_message if: >- contains(needs.get_commit_message.outputs.message, '[wheel build]') || - github.event_name == 'release' + (github.repository == 'TREX-CoE/trexio' && startsWith(github.ref, 'refs/tags/v')) runs-on: ${{ matrix.os }} strategy: matrix: diff --git a/ChangeLog b/ChangeLog index e73227b..1335fa7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ CHANGES 2.2 --- +- Added support for Python-ic `with` statements - Merged local and non-local pseudopotential integrals in #86 - Fixed backwards incompatibility of the `TREXIO_TEXT` back end in #82 - Added `TREXIO_AUTO` back end for read-only mode (`r`) in PR #80 diff --git a/python/pytrexio/_version.py b/python/pytrexio/_version.py index 6849410..c68196d 100644 --- a/python/pytrexio/_version.py +++ b/python/pytrexio/_version.py @@ -1 +1 @@ -__version__ = "1.1.0" +__version__ = "1.2.0" diff --git a/python/test/test_api.py b/python/test/test_api.py index f3ee2d5..e347c35 100644 --- a/python/test/test_api.py +++ b/python/test/test_api.py @@ -32,7 +32,7 @@ try: elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT: shutil.rmtree(output_filename) except: - print ('Nothing to remove.') + print('Nothing to remove.') #=========================================================# #============ WRITE THE DATA IN THE TEST FILE ============# @@ -40,6 +40,17 @@ except: trexio.info() + +# test with ... as ... block +with trexio.File(output_filename, mode='w', back_end=TEST_TREXIO_BACKEND) as tfile: + trexio.write_metadata_description(tfile, "Test file produced by the Python API") + assert trexio.has_metadata_description(tfile) + assert tfile.isOpen + +# the file handle can remain existing but the file itself is closed upon exit from the `with` block +assert not tfile.isOpen + + # create TREXIO file and open it for writing test_file = trexio.File(output_filename, mode='w', back_end=TEST_TREXIO_BACKEND) assert test_file.exists @@ -281,7 +292,7 @@ assert rpoint_group==point_group # another way to read only if the variable exists if trexio.has_ao_num(test_file2): - rmo_num = trexio.read_ao_num(test_file2) + rao_num = trexio.read_ao_num(test_file2) else: print("Pass on reading the non-existing variable ao_num: checked") @@ -290,12 +301,12 @@ else: # cleaning (remove the TREXIO file) try: - if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5: - os.remove(output_filename) - elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT: - shutil.rmtree(output_filename) + if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5: + os.remove(output_filename) + elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT: + shutil.rmtree(output_filename) except: - print (f'No output file {output_filename} has been produced') + print(f'No output file {output_filename} has been produced') #==========================================================# diff --git a/src/templates_front/templator_front.org b/src/templates_front/templator_front.org index ad8eacb..0e00be8 100644 --- a/src/templates_front/templator_front.org +++ b/src/templates_front/templator_front.org @@ -720,8 +720,7 @@ class File: def __init__(self, filename, mode='r', back_end=TREXIO_HDF5, pytrexio_s=None, info=None): - """This is a TREXIO File constructor.""" - + """TREXIO File class constructor.""" self.filename = filename self.mode = mode self.back_end = back_end @@ -740,9 +739,19 @@ class File: self.info = info + def __enter__(self): + """Enter statement for with ... as ... handling.""" + return self + + + def __exit__(self, *args): + """Exit statement for with ... as ... handling.""" + if self.isOpen: + self.close() + + def close(self): """Close a TREXIO File.""" - if self.isOpen: _close(self.pytrexio_s) self.isOpen = False @@ -752,13 +761,11 @@ class File: def inquire(self): """Inquire whether a TREXIO file exists.""" - self.exists = _inquire(self.filename) def __del__(self): - """This is a TREXIO File destructor.""" - + """TREXIO File class destructor.""" if self.isOpen: _close(self.pytrexio_s) elif self.isOpen is None: @@ -1204,6 +1211,12 @@ trexio_close (trexio_t* file) assert(file->back_end < TREXIO_INVALID_BACK_END); + /* Things to be done before the closing the file in the back-end */ + rc = trexio_pre_close(file); + if (rc != TREXIO_SUCCESS) { + return rc; + } + /* Terminate the back end */ switch (file->back_end) { @@ -1381,6 +1394,80 @@ def _inquire(file_name: str) -> bool: raise Error(rc) #+end_src +** Tasks to be done before closing + + #+begin_src c :tangle trexio_private.h :exports none +trexio_exit_code trexio_pre_close(trexio_t* file); + #+end_src + + #+begin_src c :tangle prefix_front.c +trexio_exit_code +trexio_pre_close (trexio_t* file) +{ + + if (file == NULL) return TREXIO_FILE_ERROR; + + { /* Up-spin and down-spin electrons */ + trexio_exit_code rc; + + int32_t nup, ndn, nelec; + bool has_up = (trexio_has_electron_up_num(file) == TREXIO_SUCCESS); + bool has_dn = (trexio_has_electron_dn_num(file) == TREXIO_SUCCESS); + bool has_updn = (trexio_has_electron_num(file) == TREXIO_SUCCESS); + + if (has_updn && has_up && has_dn) { + rc = trexio_read_electron_up_num(file, &nup); + if (rc != TREXIO_SUCCESS) return rc; + + rc = trexio_read_electron_dn_num(file, &ndn); + if (rc != TREXIO_SUCCESS) return rc; + + rc = trexio_read_electron_elec_num(file, &nelec); + if (rc != TREXIO_SUCCESS) return rc; + + if (nelec != nup + ndn) { + return TREXIO_INVALID_NUM; + } + } else if (has_up && has_dn) { + rc = trexio_read_electron_up_num(file, &nup); + if (rc != TREXIO_SUCCESS) return rc; + + rc = trexio_read_electron_dn_num(file, &ndn); + if (rc != TREXIO_SUCCESS) return rc; + + nelec = nup + ndn; + rc = trexio_write_electron_num(file, nelec); + if (rc != TREXIO_SUCCESS) return rc; + } else if (has_up) { + rc = trexio_read_electron_up_num(file, &nup); + if (rc != TREXIO_SUCCESS) return rc; + + ndn = 0; + rc = trexio_write_electron_dn_num(file, ndn); + if (rc != TREXIO_SUCCESS) return rc; + + nelec = nup; + rc = trexio_write_electron_num(file, nelec); + if (rc != TREXIO_SUCCESS) return rc; + } else if (has_dn) { + rc = trexio_read_electron_dn_num(file, &ndn); + if (rc != TREXIO_SUCCESS) return rc; + + nup = 0; + rc = trexio_write_electron_up_num(file, nup); + if (rc != TREXIO_SUCCESS) return rc; + + nelec = ndn; + rc = trexio_write_electron_num(file, nelec); + if (rc != TREXIO_SUCCESS) return rc; + } + + } + + return TREXIO_SUCCESS; +} + #+end_src + * Templates for front end ** Description diff --git a/tests/test_f.f90 b/tests/test_f.f90 index bc227ad..421ed0b 100644 --- a/tests/test_f.f90 +++ b/tests/test_f.f90 @@ -51,9 +51,9 @@ subroutine test_write(file_name, back_end) character*(*), intent(in) :: file_name integer, intent(in) :: back_end - integer(8) :: trex_file + integer(trexio_t) :: trex_file - integer :: rc = 1 + integer(trexio_exit_code) :: rc = 1 integer :: num, basis_shell_num @@ -186,10 +186,10 @@ subroutine test_read(file_name, back_end) character*(*), intent(in) :: file_name integer, intent(in) :: back_end - integer(8) :: trex_file + integer(trexio_t) :: trex_file integer :: i, j, k, ind, offset, flag - integer :: rc = 1 + integer(trexio_exit_code) :: rc = 1 integer :: num, num_read, basis_shell_num integer :: basis_nucleus_index(24) diff --git a/trex.org b/trex.org index 74ac240..8d1e733 100644 --- a/trex.org +++ b/trex.org @@ -86,6 +86,7 @@ the [[./examples.html][examples]]. #+NAME:electron | Variable | Type | Dimensions | Description | |----------+-------+------------+-------------------------------------| + | ~num~ | ~dim~ | | Number of electrons | | ~up_num~ | ~int~ | | Number of \uparrow-spin electrons | | ~dn_num~ | ~int~ | | Number of \downarrow-spin electrons | @@ -94,7 +95,8 @@ the [[./examples.html][examples]]. :results: #+begin_src python :tangle trex.json "electron": { - "up_num" : [ "int", [] ] + "num" : [ "dim", [] ] + , "up_num" : [ "int", [] ] , "dn_num" : [ "int", [] ] } , #+end_src @@ -179,7 +181,11 @@ ECP that replaces the core electrons. *Note for developers*: avoid having variables with similar prefix in their name. HDF5 back end might cause issues due to the way ~find_dataset~ function works. For example, in the ECP group we use ~max_ang_mom~ and not ~ang_mom_max~. -The latter causes issues when written before ~ang_mom~ in the TREXIO file. +The latter causes issues when written before the ~ang_mom~ array in the TREXIO file. +*Update*: in fact, the aforementioned issue has only been observed when using HDF5 version 1.10.4 +installed via ~apt-get~. Installing the same version from the ~conda-forge~ channel and running it in +an isolated ~conda~ environment works just fine. Thus, it seems to be a bug in the ~apt~-provided package. +If you encounter the aforementioned issue, please report it to our [[https://github.com/TREX-CoE/trexio/issues][issue tracker on GitHub]]. #+CALL: json(data=ecp, title="ecp") @@ -712,23 +718,23 @@ prim_factor = of $\uparrow$-spin and then all the $\downarrow$-spin. #+name: qmc - | Variable | Type | Dimensions | Description | - |----------+---------+--------------------------+---------------------------------------| - | ~num~ | ~dim~ | | Number of 3N-dimensional points | - | ~point~ | ~float~ | ~(3, elec.num, qmc.num)~ | 3N-dimensional points | - | ~psi~ | ~float~ | ~(qmc.num)~ | Wave function evaluated at the points | - | ~e_loc~ | ~float~ | ~(qmc.num)~ | Local energy evaluated at the points | + | Variable | Type | Dimensions | Description | + |----------+---------+------------------------------+---------------------------------------| + | ~num~ | ~dim~ | | Number of 3N-dimensional points | + | ~point~ | ~float~ | ~(3, electron.num, qmc.num)~ | 3N-dimensional points | + | ~psi~ | ~float~ | ~(qmc.num)~ | Wave function evaluated at the points | + | ~e_loc~ | ~float~ | ~(qmc.num)~ | Local energy evaluated at the points | #+CALL: json(data=qmc, title="qmc", last=1) - + #+RESULTS: :results: #+begin_src python :tangle trex.json "qmc": { - "num" : [ "dim" , [] ] - , "point" : [ "float", [ "qmc.num", "elec.num", "3" ] ] - , "psi" : [ "float", [ "qmc.num" ] ] - , "e_loc" : [ "float", [ "qmc.num" ] ] + "num" : [ "dim" , [] ] + , "point" : [ "float", [ "qmc.num", "electron.num", "3" ] ] + , "psi" : [ "float", [ "qmc.num" ] ] + , "e_loc" : [ "float", [ "qmc.num" ] ] } #+end_src :end: