-
Notifications
You must be signed in to change notification settings - Fork 184
Implement parallelization for hydrogen bond list setup in gfnff_hbset and gfnff_hbset0 #1362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements OpenMP parallelization for the hydrogen bond list setup routines gfnff_hbset and gfnff_hbset0 in the GFN-FF force field implementation. The approach uses thread-local buffers to collect connection information independently in each thread, then merges the results into global arrays using critical sections.
Key changes:
- File extension changed from
.f90to.F90to enable preprocessor directives for conditional OpenMP compilation gfnff_hbsetparallelized with thread-local buffers and dynamic merginggfnff_hbset0parallelized using OpenMP reduction for simple counting
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/gfnff/meson.build | Updated build file to reference renamed .F90 file for preprocessing support |
| src/gfnff/CMakeLists.txt | Updated CMake build file to reference renamed .F90 file for preprocessing support |
| src/gfnff/gfnff_ini2.F90 | Implemented OpenMP parallelization with thread-local buffers, critical sections for merging, and code reformatting |
Comments suppressed due to low confidence (17)
src/gfnff/gfnff_ini2.F90:1348
- The
nlistparameter is declared asintent(in)but is not used in the subroutine body. This appears to be a leftover from refactoring. Consider removing this unused parameter or documenting why it's needed for the API.
src/gfnff/gfnff_ini2.F90:784 - Typo in comment: 'occured' should be 'occurred' (double 'r').
src/gfnff/gfnff_ini2.F90:927 - The array shape declaration
hblist(5, nhb)is incorrect. Thenhbparameter is modified during execution (reset to 0 when OpenMP is active), but array dimensions in Fortran must be fixed at the time of the subroutine call. Whennhbis used as a dimension, it creates an assumed-shape array with the size based on the value at call time. However, the intent is to usenhbas a counter. The declaration should behblist(:,:)(assumed-shape) orhblist(5, *)(assumed-size) to properly handle the variable-length data.
src/gfnff/gfnff_ini2.F90:939 - The array shape declaration
hblist(5, nxb)is incorrect. Thenxbparameter is modified during execution (reset to 0 when OpenMP is active), but array dimensions in Fortran must be fixed at the time of the subroutine call. Whennxbis used as a dimension, it creates an assumed-shape array with the size based on the value at call time. However, the intent is to usenxbas a counter. The declaration should behblist(:,:)(assumed-shape) orhblist(5, *)(assumed-size) to properly handle the variable-length data.
src/gfnff/gfnff_ini2.F90:781 - The
N_MAX_LISTconstant (800 elements = ~32KB) deserves better documentation. The comment says "keep approx. 32 kb of integer(int64)" but the code uses default integers which are typically 32-bit (4 bytes), not 64-bit (8 bytes). For 800 elements × 5 values × 4 bytes = 16KB per thread per list (not 32KB). If memory usage is a concern, this discrepancy should be clarified. Also, document the rationale for choosing 800 as the buffer size.
src/gfnff/gfnff_ini2.F90:786 - The early return condition logic is confusing. The condition
.not.(rmsd < 1.d-6 .or. rmsd > 0.3d0)is equivalent tormsd >= 1.d-6 .and. rmsd <= 0.3d0, meaning it returns when RMSD is in the normal range [1e-6, 0.3] and continues when RMSD is either very small (< 1e-6, first call) or very large (> 0.3, substantial move). Consider rewriting this for clarity, e.g.,if (rmsd >= 1.d-6 .and. rmsd <= 0.3d0) returnwith a comment explaining the logic.
src/gfnff/gfnff_ini2.F90:941 - The array assignment statement is commented out with
!$, but it's essential for copying thread-local data to the global list. Without this line, only the counter is updated while the actual data is never transferred from the thread-localhblisttoneigh_list%hblist3. This will result in incorrect/uninitialized data in the halogen bond list.
The line should be active when OpenMP is enabled. Change !$ to !$omp or remove the !$ prefix entirely to make it execute in the critical section.
src/gfnff/gfnff_ini2.F90:845
- Buffer overflow logic is incorrect. The sequence is: (1) increment
nhb2, (2) write tohblist2(*, nhb2), (3) check ifnhb2 == N_MAX_LISTand flush. This means whennhb2reachesN_MAX_LIST, the element at indexN_MAX_LISThas already been written. The check should happen BEFORE incrementing and writing, or the buffer size should beN_MAX_LIST + 1. Otherwise, this will write beyond the allocated array bounds whennhb2reaches 800.
src/gfnff/gfnff_ini2.F90:915 - The array shape declaration
hblist(5, nhb)is incorrect. Thenhbparameter is modified during execution (reset to 0 when OpenMP is active), but array dimensions in Fortran must be fixed at the time of the subroutine call. Whennhbis used as a dimension, it creates an assumed-shape array with the size based on the value at call time. However, the intent is to usenhbas a counter. The declaration should behblist(:,:)(assumed-shape) orhblist(5, *)(assumed-size) to properly handle the variable-length data.
src/gfnff/gfnff_ini2.F90:817 - Typo in comment: 'adjustet' should be 'adjusted'.
src/gfnff/gfnff_ini2.F90:1372 - Typo in comment: 'adjustet' should be 'adjusted'.
src/gfnff/gfnff_ini2.F90:917 - The array assignment statement is commented out with
!$, but it's essential for copying thread-local data to the global list. Without this line, only the counter is updated while the actual data is never transferred from the thread-localhblisttoneigh_list%hblist1. This will result in incorrect/uninitialized data in the hydrogen bond list.
The line should be active when OpenMP is enabled. Change !$ to !$omp or remove the !$ prefix entirely to make it execute in the critical section.
src/gfnff/gfnff_ini2.F90:929
- The array assignment statement is commented out with
!$, but it's essential for copying thread-local data to the global list. Without this line, only the counter is updated while the actual data is never transferred from the thread-localhblisttoneigh_list%hblist2. This will result in incorrect/uninitialized data in the hydrogen bond list.
The line should be active when OpenMP is enabled. Change !$ to !$omp or remove the !$ prefix entirely to make it execute in the critical section.
src/gfnff/gfnff_ini2.F90:858
- Buffer overflow logic is incorrect. The sequence is: (1) increment
nhb2, (2) write tohblist2(*, nhb2), (3) check ifnhb2 == N_MAX_LISTand flush. This means whennhb2reachesN_MAX_LIST, the element at indexN_MAX_LISThas already been written. The check should happen BEFORE incrementing and writing, or the buffer size should beN_MAX_LIST + 1. Otherwise, this will write beyond the allocated array bounds whennhb2reaches 800.
src/gfnff/gfnff_ini2.F90:870 - Buffer overflow logic is incorrect. The sequence is: (1) increment
nhb1, (2) write tohblist1(*, nhb1), (3) check ifnhb1 == N_MAX_LISTand flush. This means whennhb1reachesN_MAX_LIST, the element at indexN_MAX_LISThas already been written. The check should happen BEFORE incrementing and writing, or the buffer size should beN_MAX_LIST + 1. Otherwise, this will write beyond the allocated array bounds whennhb1reaches 800.
src/gfnff/gfnff_ini2.F90:893 - Buffer overflow logic is incorrect. The sequence is: (1) increment
nxb, (2) write tohblist3(*, nxb), (3) check ifnxb == N_MAX_LISTand flush. This means whennxbreachesN_MAX_LIST, the element at indexN_MAX_LISThas already been written. The check should happen BEFORE incrementing and writing, or the buffer size should beN_MAX_LIST + 1. Otherwise, this will write beyond the allocated array bounds whennxbreaches 800.
src/gfnff/gfnff_ini2.F90:772 - The
neighparameter is declared asintent(inout)but it's only read in this subroutine (used to accessneigh%transVec,neigh%bpair,neigh%numctr,neigh%nTrans, etc.). It should be declared asintent(in)for clarity and to prevent accidental modifications. This also affects the OpenMP shared clause correctness.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
f3baa13 to
acf9d5e
Compare
|
Well... I do not see any other data races in modified fragment of xtb. Since the different number of iteration happens even in |
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
Signed-off-by: Igor S. Gerasimov <[email protected]>
thfroitzheim
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's open an issue for the different number of iterations in the geometry optimization.
… and gfnff_hbset0 (grimme-lab#1362) * Format gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * Format gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Reorder arguments Signed-off-by: Igor S. Gerasimov <[email protected]> * Replace norm2 in gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * Remove unused variables Signed-off-by: Igor S. Gerasimov <[email protected]> * Fix inout of args of gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * OMP parallelization of gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * Fix inout of gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Use fast exit in gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Replace norm2 with dot_product Signed-off-by: Igor S. Gerasimov <[email protected]> * Preparation for OpenMP Signed-off-by: Igor S. Gerasimov <[email protected]> * Fix style Signed-off-by: Igor S. Gerasimov <[email protected]> * Remove unused variables from gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Add OpenMP parallelization of gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Do not do allocations without OpenMP Signed-off-by: Igor S. Gerasimov <[email protected]> * Avoid barriers Signed-off-by: Igor S. Gerasimov <[email protected]> * Deallocate OpenMP variables Signed-off-by: Igor S. Gerasimov <[email protected]> * Limit allocations in OpenMP Signed-off-by: Igor S. Gerasimov <[email protected]> * Remove free variable Signed-off-by: Igor S. Gerasimov <[email protected]> * Reorder arguments in update lists Signed-off-by: Igor S. Gerasimov <[email protected]> * Sync hbset0 to hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * No need for extra elements in list if allocation is correct Signed-off-by: Igor S. Gerasimov <[email protected]> --------- Signed-off-by: Igor S. Gerasimov <[email protected]> Signed-off-by: lmseidler <[email protected]>
… and gfnff_hbset0 (grimme-lab#1362) * Format gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * Format gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Reorder arguments Signed-off-by: Igor S. Gerasimov <[email protected]> * Replace norm2 in gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * Remove unused variables Signed-off-by: Igor S. Gerasimov <[email protected]> * Fix inout of args of gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * OMP parallelization of gfnff_hbset0 Signed-off-by: Igor S. Gerasimov <[email protected]> * Fix inout of gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Use fast exit in gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Replace norm2 with dot_product Signed-off-by: Igor S. Gerasimov <[email protected]> * Preparation for OpenMP Signed-off-by: Igor S. Gerasimov <[email protected]> * Fix style Signed-off-by: Igor S. Gerasimov <[email protected]> * Remove unused variables from gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Add OpenMP parallelization of gfnff_hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * Do not do allocations without OpenMP Signed-off-by: Igor S. Gerasimov <[email protected]> * Avoid barriers Signed-off-by: Igor S. Gerasimov <[email protected]> * Deallocate OpenMP variables Signed-off-by: Igor S. Gerasimov <[email protected]> * Limit allocations in OpenMP Signed-off-by: Igor S. Gerasimov <[email protected]> * Remove free variable Signed-off-by: Igor S. Gerasimov <[email protected]> * Reorder arguments in update lists Signed-off-by: Igor S. Gerasimov <[email protected]> * Sync hbset0 to hbset Signed-off-by: Igor S. Gerasimov <[email protected]> * No need for extra elements in list if allocation is correct Signed-off-by: Igor S. Gerasimov <[email protected]> --------- Signed-off-by: Igor S. Gerasimov <[email protected]> Signed-off-by: lmseidler <[email protected]>
Now, subroutines gfnff_hbset and gfnff_hbset0 now are parallelized using OpenMP. The idea is to collect information about connections in OpenMP-thread-specific arrays and then dump it to global arrays. I did not test it a lot, but tests now 1.5 s faster on my laptop for 4 threads, mainly from xtb/gfnff test.
I've also reformatted source code of these routines.
Alternative approach is #1240.
Closes #1239
Closes #1262