Skip to content

Commit f618cd4

Browse files
committed
include additional unit tests within test_entropy.py in relation to changes within PR #267
1 parent 9bcaa37 commit f618cd4

1 file changed

Lines changed: 174 additions & 0 deletions

File tree

tests/test_CodeEntropy/test_entropy.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import MDAnalysis as mda
1010
import numpy as np
11+
import numpy.linalg as la
1112
import pytest
1213

1314
import tests.data as data
@@ -753,6 +754,77 @@ def test_process_vibrational_only_levels(self):
753754
self.assertIn(1.11, results)
754755
self.assertIn(2.22, results)
755756

757+
def test_process_vibrational_entropy_else_branch(self):
758+
"""
759+
Atomic unit test for EntropyManager._process_vibrational_entropy else-branch:
760+
- forcetorque_matrix is None
761+
- force/torque matrices are filtered
762+
- ve.vibrational_entropy_calculation called for force & torque
763+
- results logged as Transvibrational/Rovibrational
764+
- group label added from mol_container residues/atoms
765+
"""
766+
manager = MagicMock()
767+
manager._args = MagicMock(temperature=300)
768+
769+
manager._level_manager = MagicMock()
770+
manager._data_logger = MagicMock()
771+
772+
force_matrix = np.eye(3)
773+
torque_matrix = np.eye(3) * 2
774+
775+
filtered_force = np.eye(3) * 7
776+
filtered_torque = np.eye(3) * 9
777+
manager._level_manager.filter_zero_rows_columns.side_effect = [
778+
filtered_force,
779+
filtered_torque,
780+
]
781+
782+
ve = MagicMock()
783+
ve.vibrational_entropy_calculation.side_effect = [1.11, 2.22]
784+
785+
res1 = MagicMock(resname="ALA")
786+
res2 = MagicMock(resname="GLY")
787+
res3 = MagicMock(resname="ALA")
788+
mol_container = MagicMock()
789+
mol_container.residues = [res1, res2, res3]
790+
mol_container.atoms = [MagicMock(), MagicMock(), MagicMock(), MagicMock()]
791+
792+
EntropyManager._process_vibrational_entropy(
793+
manager,
794+
group_id=0,
795+
mol_container=mol_container,
796+
number_frames=10,
797+
ve=ve,
798+
level="Vibrational",
799+
force_matrix=force_matrix,
800+
torque_matrix=torque_matrix,
801+
forcetorque_matrix=None,
802+
highest=True,
803+
)
804+
805+
filter_calls = manager._level_manager.filter_zero_rows_columns.call_args_list
806+
assert len(filter_calls) == 2
807+
808+
np.testing.assert_array_equal(filter_calls[0].args[0], force_matrix)
809+
np.testing.assert_array_equal(filter_calls[1].args[0], torque_matrix)
810+
811+
ve_calls = ve.vibrational_entropy_calculation.call_args_list
812+
assert len(ve_calls) == 2
813+
814+
np.testing.assert_array_equal(ve_calls[0].args[0], filtered_force)
815+
assert ve_calls[0].args[1:] == ("force", 300, True)
816+
817+
np.testing.assert_array_equal(ve_calls[1].args[0], filtered_torque)
818+
assert ve_calls[1].args[1:] == ("torque", 300, True)
819+
820+
manager._data_logger.add_results_data.assert_any_call(
821+
0, "Vibrational", "Transvibrational", 1.11
822+
)
823+
manager._data_logger.add_results_data.assert_any_call(
824+
0, "Vibrational", "Rovibrational", 2.22
825+
)
826+
manager._data_logger.add_group_label.assert_called_once_with(0, "ALA_GLY", 3, 4)
827+
756828
def test_compute_entropies_polymer_branch(self):
757829
"""
758830
Test _compute_entropies triggers _process_vibrational_entropy for 'polymer'
@@ -1546,6 +1618,108 @@ def test_vibrational_entropy_polymer_torque(self):
15461618

15471619
assert S_vib == pytest.approx(48.45003266069881)
15481620

1621+
def test_vibrational_entropy_calculation_forcetorqueTRANS(self):
1622+
"""
1623+
Test for matrix_type='forcetorqueTRANS':
1624+
- verifies S_vib_total = sum(S_components[:3])
1625+
"""
1626+
run_manager = MagicMock()
1627+
run_manager.change_lambda_units.side_effect = lambda x: x
1628+
kT = 2.47e-21
1629+
run_manager.get_KT2J.return_value = kT
1630+
1631+
ve = VibrationalEntropy(
1632+
run_manager,
1633+
MagicMock(),
1634+
MagicMock(),
1635+
MagicMock(),
1636+
MagicMock(),
1637+
MagicMock(),
1638+
MagicMock(),
1639+
MagicMock(),
1640+
)
1641+
1642+
orig_eigvals = la.eigvals
1643+
la.eigvals = lambda m: np.array(
1644+
[1.0] * 6
1645+
) # length 6 -> 6 frequencies/components
1646+
1647+
try:
1648+
freqs = np.array([6.0, 5.0, 4.0, 3.0, 2.0, 1.0])
1649+
ve.frequency_calculation = MagicMock(return_value=freqs)
1650+
1651+
matrix = np.identity(6)
1652+
1653+
result = ve.vibrational_entropy_calculation(
1654+
matrix=matrix,
1655+
matrix_type="forcetorqueTRANS",
1656+
temp=298,
1657+
highest_level=True,
1658+
)
1659+
1660+
sorted_freqs = np.sort(freqs)
1661+
exponent = ve._PLANCK_CONST * sorted_freqs / kT
1662+
power_positive = np.exp(exponent)
1663+
power_negative = np.exp(-exponent)
1664+
S_components = exponent / (power_positive - 1) - np.log(1 - power_negative)
1665+
S_components *= ve._GAS_CONST
1666+
1667+
expected = float(np.sum(S_components[:3]))
1668+
self.assertAlmostEqual(result, expected, places=12)
1669+
1670+
finally:
1671+
la.eigvals = orig_eigvals
1672+
1673+
def test_vibrational_entropy_calculation_forcetorqueROT(self):
1674+
"""
1675+
Test for matrix_type='forcetorqueROT':
1676+
- verifies S_vib_total = sum(S_components[3:])
1677+
"""
1678+
run_manager = MagicMock()
1679+
run_manager.change_lambda_units.side_effect = lambda x: x
1680+
kT = 2.47e-21
1681+
run_manager.get_KT2J.return_value = kT
1682+
1683+
ve = VibrationalEntropy(
1684+
run_manager,
1685+
MagicMock(),
1686+
MagicMock(),
1687+
MagicMock(),
1688+
MagicMock(),
1689+
MagicMock(),
1690+
MagicMock(),
1691+
MagicMock(),
1692+
)
1693+
1694+
orig_eigvals = la.eigvals
1695+
la.eigvals = lambda m: np.array([1.0] * 6)
1696+
1697+
try:
1698+
freqs = np.array([6.0, 5.0, 4.0, 3.0, 2.0, 1.0])
1699+
ve.frequency_calculation = MagicMock(return_value=freqs)
1700+
1701+
matrix = np.identity(6)
1702+
1703+
result = ve.vibrational_entropy_calculation(
1704+
matrix=matrix,
1705+
matrix_type="forcetorqueROT",
1706+
temp=298,
1707+
highest_level=True,
1708+
)
1709+
1710+
sorted_freqs = np.sort(freqs)
1711+
exponent = ve._PLANCK_CONST * sorted_freqs / kT
1712+
power_positive = np.exp(exponent)
1713+
power_negative = np.exp(-exponent)
1714+
S_components = exponent / (power_positive - 1) - np.log(1 - power_negative)
1715+
S_components *= ve._GAS_CONST
1716+
1717+
expected = float(np.sum(S_components[3:]))
1718+
self.assertAlmostEqual(result, expected, places=12)
1719+
1720+
finally:
1721+
la.eigvals = orig_eigvals
1722+
15491723
def test_calculate_water_orientational_entropy(self):
15501724
"""
15511725
Test that orientational entropy values are correctly extracted from Sorient_dict

0 commit comments

Comments
 (0)