Skip to content
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

Add force support for HarmonicTorsion #363

Merged
merged 28 commits into from
May 13, 2021
Merged

Add force support for HarmonicTorsion #363

merged 28 commits into from
May 13, 2021

Conversation

mlund
Copy link
Owner

@mlund mlund commented May 7, 2021

This adds force support for HarmonicTorsion and includes some cleanup of BondData and force evaluation.

  • Add bend example for MD/MC testing of harmonic bonds and angles
  • BondData refactoring

@mlund mlund added this to the Version 2.5.0 milestone May 7, 2021
@mlund mlund added bug 🐛 Broken or wrong functionality code quality ⚙️ Code refactoring / restructuring labels May 7, 2021
@mlund mlund removed the bug 🐛 Broken or wrong functionality label May 7, 2021
@mlund mlund requested a review from SHervoe-Hansen May 8, 2021 05:52
@mlund
Copy link
Owner Author

mlund commented May 8, 2021

@SHervoe-Hansen is the force calculation consistent with what you derived?

Copy link
Collaborator

@SHervoe-Hansen SHervoe-Hansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is overall consistent yes, however, I am fearing there is a sign error that cancels out since all tests pass.

src/bonds.cpp Outdated
Comment on lines 210 to 213
if (cosine_angle > 1.0) { // is this needed?
cosine_angle = 1.0;
} else if (cosine_angle < -1.0) {
cosine_angle = -1.0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the need of these lines.

src/bonds.cpp Outdated
sine_angle = std::numeric_limits<double>::epsilon();
}
const auto angle = std::acos(cosine_angle);
const auto du_dangle = 2.0 * half_force_constant * (angle - equilibrium_angle);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minus sign missing.
F = - dU/dr

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's just the direction of the vector (01 vs 10). I checked flipping the sign, and see large differences compared to MC.

src/bonds.cpp Outdated
}
const auto angle = std::acos(cosine_angle);
const auto du_dangle = 2.0 * half_force_constant * (angle - equilibrium_angle);
auto force0 = du_dangle / sine_angle * d01_inv * (r21 * d21_inv - r01 * d01_inv * cosine_angle);
Copy link
Collaborator

@SHervoe-Hansen SHervoe-Hansen May 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In more Eigen friendly manner we could maybe write it as:

force0 = du_dangle / r01 * norm(10x(10x12))

Copy link
Collaborator

@SHervoe-Hansen SHervoe-Hansen May 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the cross product of vector 10 and 12 is used in both expressions so maybe calculate that first and take the norm of the cross product between the newly calculated vector and the vector required.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be faster as it uses one less trigonometric function (sqrt) in exchange of multiplications. However, your suggestion gives NaN and ctest -R unittests -V fails. Would you be willing to double-check with the current code?

src/bonds.cpp Outdated
const auto angle = std::acos(cosine_angle);
const auto du_dangle = 2.0 * half_force_constant * (angle - equilibrium_angle);
auto force0 = du_dangle / sine_angle * d01_inv * (r21 * d21_inv - r01 * d01_inv * cosine_angle);
auto force2 = du_dangle / sine_angle * d21_inv * (r01 * d01_inv - r21 * d21_inv * cosine_angle);
Copy link
Collaborator

@SHervoe-Hansen SHervoe-Hansen May 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

force2 = du_dangle / r12 * norm(21x(10x12))

@SHervoe-Hansen
Copy link
Collaborator

It passes the tests in terms of RDF is the same for Langevin dynamics and Monte Carlo and does not return NaN.

bend_rdf

@mlund
Copy link
Owner Author

mlund commented May 10, 2021

It passes the tests in terms of RDF is the same for Langevin dynamics and Monte Carlo and does not return NaN.

Thanks, the cross-product code works in Debug mode only, but fails on both GCC and Clang if with RelWithDebMode. I tried updating Eigen from 3.3.7 --> 3.3.9 but to no avail. I kept the code, but enclosed it in a constexpr(false) which will be evaluated at compile-time for further testing.

@mlund
Copy link
Owner Author

mlund commented May 11, 2021

@SHervoe-Hansen in the unittest,bonds.cpp:312, the distance function is defined as b - a, whereas in Cuboid::vdist() (and all other geometries, see energy.h:471) it's a - b. Is there a lucky cancellation of signs somewhere?

@SHervoe-Hansen
Copy link
Collaborator

SHervoe-Hansen commented May 11, 2021

@SHervoe-Hansen in the unittest,bonds.cpp:312, the distance function is defined as b - a, whereas in Cuboid::vdist() (and all other geometries, see energy.h:471) it's a - b. Is there a lucky cancellation of signs somewhere?

We are partly saved because of my poor memory in terms of vector notation: like we wanted to use the vector ab = b - a however I had named it ba so we might gain our sign cancelation from that.

I will go over the math and code ones more in the near future!

@SHervoe-Hansen
Copy link
Collaborator

I have been testing for more odd behaviour, it turns out the debug only code can run in release mode if you insert std::cout << force0; and std::cout << force2 before the calculation of force1, which I can only associate with uninitialised variable behaviour.

@mlund
Copy link
Owner Author

mlund commented May 11, 2021

I have been testing for more odd behaviour, it turns out the debug only code can run in release mode if you insert std::cout << force0; and std::cout << force2 before the calculation of force1, which I can only associate with uninitialised variable behaviour.

I think we just ran into one of Eigen's common pitfalls :-) Fixed in latest commit. Still a bit worried about the force sign more generally in Faunus (bonds, pair potential).

@SHervoe-Hansen
Copy link
Collaborator

Still a bit worried about the force sign more generally in Faunus (bonds, pair potential).

Let me do a worked out example for unit testing and such that we can compare and I will also check the code for the angular potential. It seems the major problem is the correct usage of the calculateDistance function. We could maybe look into documentation for future purposes to avoid these mistakes?

Direction of force vector was unclear this commit
brings renaming to explicitly give directions of
input arguments and calculated forces. Unit test for
NewCoulomb is also added. It seems OK, but the documentation
in the external CoulombGalore library may need updating
@mlund
Copy link
Owner Author

mlund commented May 11, 2021

Still a bit worried about the force sign more generally in Faunus (bonds, pair potential).

Let me do a worked out example for unit testing and such that we can compare and I will also check the code for the angular potential. It seems the major problem is the correct usage of the calculateDistance function. We could maybe look into documentation for future purposes to avoid these mistakes?

Yes, good idea with more unittests. I made a commit clarifying both vdist() and force() and renamed arguments to reflect directions. I think documentation for the external CoulombGalore library might need updating as it should state on which particle the resulting force acts upon (ping @bjornstenqvist).

@SHervoe-Hansen
Copy link
Collaborator

SHervoe-Hansen commented May 12, 2021

The commit 4e34050 now reflects the addition of a unit test checking the direction of the force vectors to be correct. The unit test system is illustrated here.
AngularUnitTest

The angular harmonic potential now passes this test. Agreement between MC and MD however still remains to be tested in addition to the speed of the two implementations.

@mlund
Copy link
Owner Author

mlund commented May 12, 2021

The angular harmonic potential now passes this test. Agreement between MC and MD however still remains to be tested in addition to the speed of the two implementations.

Now ctest -R bend fails and with the latest "cross product" variant we get the graph below (green), indicating a sign is flipped somewhere. You can switch version by simple changing the bool in if constexpr(); no need to uncomment.

Screenshot 2021-05-12 at 23 05 44

Copy link
Collaborator

@SHervoe-Hansen SHervoe-Hansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code and physics now match and passes all tests. Ready for merge.

@mlund mlund merged commit 8ada37f into master May 13, 2021
@mlund mlund deleted the bond-force branch May 13, 2021 10:12
@mlund mlund linked an issue May 17, 2021 that may be closed by this pull request
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code quality ⚙️ Code refactoring / restructuring enhancement 💪
Projects
None yet
2 participants