From 6ac1b0a289b0a5ab28538cc7e3cb58c5362c2f68 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Sat, 13 Jul 2024 00:25:08 -0500 Subject: [PATCH 1/5] improve CLI for TIS networks --- paths_cli/compiling/networks.py | 121 +++++++++------ paths_cli/compiling/schemes.py | 7 + paths_cli/tests/compiling/test_networks.py | 170 +++++++++++++-------- 3 files changed, 187 insertions(+), 111 deletions(-) diff --git a/paths_cli/compiling/networks.py b/paths_cli/compiling/networks.py index 360621d1..019e6584 100644 --- a/paths_cli/compiling/networks.py +++ b/paths_cli/compiling/networks.py @@ -1,5 +1,6 @@ from paths_cli.compiling.core import ( - InstanceCompilerPlugin, Builder, Parameter + InstanceCompilerPlugin, Builder, Parameter, + listify, unlistify ) from paths_cli.compiling.tools import custom_eval from paths_cli.compiling.plugins import ( @@ -38,53 +39,76 @@ description="final state for this transition", ) +def mistis_trans_info_param_builder(dcts): + default = 'volume-interface-set' # TODO: make this flexible? + trans_info = [] + volume_compiler = compiler_for("volume") + interface_set_compiler = compiler_for('interface_set') + for dct in dcts: + dct['type'] = dct.get('type', default) + initial_state = volume_compiler(dct.pop('initial_state')) + final_state = volume_compiler(dct.pop('final_state')) + interface_set = interface_set_compiler(dct) + trans_info.append((initial_state, interface_set, final_state)) + + return trans_info + + +MISTIS_INTERFACE_SETS_PARAM = Parameter( + 'interface_sets', mistis_trans_info_param_builder, + json_type=json_type_list(json_type_ref('interface-set')), + description='interface sets for MISTIS' +) -build_interface_set = InterfaceSetPlugin( +# this is reused in the simple single TIS setup +VOLUME_INTERFACE_SET_PARAMS = [ + Parameter('cv', compiler_for('cv'), json_type=json_type_ref('cv'), + description=("the collective variable for this interface " + "set")), + Parameter('minvals', custom_eval, + json_type=json_type_list(json_type_eval("Float")), + description=("minimum value(s) for interfaces in this" + "interface set")), + Parameter('maxvals', custom_eval, + json_type=json_type_list(json_type_eval("Float")), + description=("maximum value(s) for interfaces in this" + "interface set")), +] + + +VOLUME_INTERFACE_SET_PLUGIN = InterfaceSetPlugin( builder=Builder('openpathsampling.VolumeInterfaceSet'), - parameters=[ - Parameter('cv', compiler_for('cv'), json_type=json_type_ref('cv'), - description=("the collective variable for this interface " - "set")), - Parameter('minvals', custom_eval, - json_type=json_type_list(json_type_eval("Float")), - description=("minimum value(s) for interfaces in this" - "interface set")), - Parameter('maxvals', custom_eval, - json_type=json_type_list(json_type_eval("Float")), - description=("maximum value(s) for interfaces in this" - "interface set")), - ], - name='interface-set', + parameters=VOLUME_INTERFACE_SET_PARAMS, + name='volume-interface-set', description="Interface set used in transition interface sampling.", ) def mistis_trans_info(dct): dct = dct.copy() - transitions = dct.pop('transitions') - volume_compiler = compiler_for('volume') - trans_info = [ - ( - volume_compiler(trans['initial_state']), - build_interface_set(trans['interfaces']), - volume_compiler(trans['final_state']) - ) - for trans in transitions - ] - dct['trans_info'] = trans_info + dct['trans_info'] = dct.pop('interface_sets') return dct + # interface_sets = dct.pop('interface_sets') + # volume_compiler = compiler_for('volume') + # interface_set_compiler = compiler_for('interface_set') + + # trans_info = [] + # for iset in interface_sets: + # initial_state = volume_compiler(iset.pop("initial_state")) + # final_state = volume_compiler(iset.pop("final_state")) + # iset['type'] = iset.get('type', 'volume-interface-set') + # interface_set = interface_set_compiler(iset) + # trans_info.append((initial_state, interface_set, final_state)) + + # dct['trans_info'] = trans_info + # return dct def tis_trans_info(dct): # remap TIS into MISTIS format dct = dct.copy() - initial_state = dct.pop('initial_state') - final_state = dct.pop('final_state') - interface_set = dct.pop('interfaces') - dct['transitions'] = [{'initial_state': initial_state, - 'final_state': final_state, - 'interfaces': interface_set}] - return mistis_trans_info(dct) + remapped = {'interface_sets': [dct]} + return mistis_trans_info(remapped) TPS_NETWORK_PLUGIN = NetworkCompilerPlugin( @@ -96,18 +120,27 @@ def tis_trans_info(dct): ) -# MISTIS_NETWORK_PLUGIN = NetworkCompilerPlugin( -# parameters=[Parameter('trans_info', mistis_trans_info)], -# builder=Builder('openpathsampling.MISTISNetwork'), -# name='mistis' -# ) +MISTIS_NETWORK_PLUGIN = NetworkCompilerPlugin( + parameters=[MISTIS_INTERFACE_SETS_PARAM], + builder=Builder('openpathsampling.MISTISNetwork', + remapper=mistis_trans_info), + name='mistis' +) +def single_tis_builder(initial_state, final_state, cv, minvals, maxvals): + import openpathsampling as paths + interface_set = paths.VolumeInterfaceSet(cv, minvals, maxvals) + return paths.MISTISNetwork([ + (initial_state, interface_set, final_state) + ]) + +TIS_NETWORK_PLUGIN = NetworkCompilerPlugin( + builder=single_tis_builder, + parameters=([INITIAL_STATE_PARAM, FINAL_STATE_PARAM] + + VOLUME_INTERFACE_SET_PARAMS), + name='tis' +) -# TIS_NETWORK_PLUGIN = NetworkCompilerPlugin( -# builder=Builder('openpathsampling.MISTISNetwork'), -# parameters=[Parameter('trans_info', tis_trans_info)], -# name='tis' -# ) # old names not yet replaced in testing THESE ARE WHY WE'RE DOUBLING! GET # RID OF THEM! (also, use an is-check) diff --git a/paths_cli/compiling/schemes.py b/paths_cli/compiling/schemes.py index a52276d7..3270a3ea 100644 --- a/paths_cli/compiling/schemes.py +++ b/paths_cli/compiling/schemes.py @@ -99,4 +99,11 @@ def __call__(self, **dct): "that type (i.e., ``OrganizeByMoveGroupStrategy``)"), ) +DEFAULT_TIS_SCHEME_PLUGIN = SchemeCompilerPlugin( + builder=Builder('openpathsampling.DefaultScheme'), + parameters=[NETWORK_PARAMETER, ENGINE_PARAMETER], + name='default-tis', + description="", +) + SCHEME_COMPILER = CategoryPlugin(SchemeCompilerPlugin, aliases=['schemes']) diff --git a/paths_cli/tests/compiling/test_networks.py b/paths_cli/tests/compiling/test_networks.py index 9e29b468..4830de14 100644 --- a/paths_cli/tests/compiling/test_networks.py +++ b/paths_cli/tests/compiling/test_networks.py @@ -10,74 +10,77 @@ _COMPILERS_LOC = 'paths_cli.compiling.root_compiler._COMPILERS' - -def check_unidirectional_tis(results, state_A, state_B, cv): - assert len(results) == 1 - trans_info = results['trans_info'] - assert len(trans_info) == 1 - assert len(trans_info[0]) == 3 - trans = trans_info[0] - assert isinstance(trans, tuple) - assert trans[0] == state_A - assert trans[2] == state_B - assert isinstance(trans[1], paths.VolumeInterfaceSet) - ifaces = trans[1] - assert ifaces.cv == cv - assert ifaces.minvals == float("-inf") - np.testing.assert_allclose(ifaces.maxvals, - [0, np.pi / 10.0, np.pi / 5.0]) - - -def test_mistis_trans_info(cv_and_states): +@pytest.fixture +def unidirectional_tis_compiler(cv_and_states): cv, state_A, state_B = cv_and_states - dct = { - 'transitions': [{ - 'initial_state': "A", - 'final_state': "B", - 'interfaces': { - 'cv': 'cv', - 'minvals': 'float("-inf")', - 'maxvals': "np.array([0, 0.1, 0.2]) * np.pi" - } - }] - } - patch_base = 'paths_cli.compiling.networks' - compiler = { - 'cv': mock_compiler('cv', named_objs={'cv': cv}), - 'volume': mock_compiler('volume', named_objs={ - "A": state_A, "B": state_B - }), - } - with mock.patch.dict(_COMPILERS_LOC, compiler): - results = mistis_trans_info(dct) - - check_unidirectional_tis(results, state_A, state_B, cv) - paths.InterfaceSet._reset() - - -def test_tis_trans_info(cv_and_states): - cv, state_A, state_B = cv_and_states - dct = { - 'initial_state': "A", - 'final_state': "B", - 'interfaces': { - 'cv': 'cv', - 'minvals': 'float("-inf")', - 'maxvals': 'np.array([0, 0.1, 0.2]) * np.pi', - } - } - - compiler = { + return { 'cv': mock_compiler('cv', named_objs={'cv': cv}), 'volume': mock_compiler('volume', named_objs={ "A": state_A, "B": state_B }), + 'interface_set': mock_compiler( + 'interface_set', + type_dispatch={ + 'volume-interface-set': VOLUME_INTERFACE_SET_PLUGIN + } + ), } - with mock.patch.dict(_COMPILERS_LOC, compiler): - results = tis_trans_info(dct) - check_unidirectional_tis(results, state_A, state_B, cv) - paths.InterfaceSet._reset() +# def check_unidirectional_tis(results, state_A, state_B, cv): +# assert len(results) == 1 +# trans_info = results['trans_info'] +# assert len(trans_info) == 1 +# assert len(trans_info[0]) == 3 +# trans = trans_info[0] +# assert isinstance(trans, tuple) +# assert trans[0] == state_A +# assert trans[2] == state_B +# assert isinstance(trans[1], paths.VolumeInterfaceSet) +# ifaces = trans[1] +# assert ifaces.cv == cv +# assert ifaces.minvals == float("-inf") +# np.testing.assert_allclose(ifaces.maxvals, +# [0, np.pi / 10.0, np.pi / 5.0]) + + +# def test_mistis_trans_info(cv_and_states, mistis_dict, +# unidirectional_tis_compiler): +# cv, state_A, state_B = cv_and_states +# patch_base = 'paths_cli.compiling.networks' +# with mock.patch.dict(_COMPILERS_LOC, unidirectional_tis_compiler): +# results = mistis_trans_info(mistis_dict) + +# check_unidirectional_tis(results, state_A, state_B, cv) +# paths.InterfaceSet._reset() + + +# def test_tis_trans_info(cv_and_states): +# cv, state_A, state_B = cv_and_states +# dct = { +# 'initial_state': "A", +# 'final_state': "B", +# 'cv': 'cv', +# 'minvals': 'float("-inf")', +# 'maxvals': 'np.array([0, 0.1, 0.2]) * np.pi', +# } + +# compiler = { +# 'cv': mock_compiler('cv', named_objs={'cv': cv}), +# 'volume': mock_compiler('volume', named_objs={ +# "A": state_A, "B": state_B +# }), +# 'interface_set': mock_compiler( +# 'interface_set', +# type_dispatch={ +# 'volume-interface-set': VOLUME_INTERFACE_SET_PLUGIN +# } +# ), +# } +# with mock.patch.dict(_COMPILERS_LOC, compiler): +# results = tis_trans_info(dct) + +# check_unidirectional_tis(results, state_A, state_B, cv) +# paths.InterfaceSet._reset() def test_build_tps_network(cv_and_states): @@ -86,17 +89,50 @@ def test_build_tps_network(cv_and_states): dct = yaml.load(yml, yaml.FullLoader) compiler = { 'volume': mock_compiler('volume', named_objs={"A": state_A, - "B": state_B}), + "B": state_B}), } with mock.patch.dict(_COMPILERS_LOC, compiler): - network = build_tps_network(dct) + network = TPS_NETWORK_PLUGIN(dct) assert isinstance(network, paths.TPSNetwork) assert len(network.initial_states) == len(network.final_states) == 1 assert network.initial_states[0] == state_A assert network.final_states[0] == state_B -def test_build_mistis_network(): - pytest.skip() -def test_build_tis_network(): - pytest.skip() +def test_build_mistis_network(cv_and_states, unidirectional_tis_compiler): + cv, state_A, state_B = cv_and_states + mistis_dict = { + 'interface_sets': [{ + 'initial_state': "A", + 'final_state': "B", + 'cv': 'cv', + 'minvals': 'float("-inf")', + 'maxvals': "np.array([0, 0.1, 0.2]) * np.pi" + }] + } + + with mock.patch.dict(_COMPILERS_LOC, unidirectional_tis_compiler): + network = MISTIS_NETWORK_PLUGIN(mistis_dict) + + assert isinstance(network, paths.MISTISNetwork) + assert len(network.sampling_transitions) == 1 + assert len(network.transitions) == 1 + assert list(network.transitions) == [(state_A, state_B)] + +def test_build_tis_network(cv_and_states, unidirectional_tis_compiler): + cv, state_A, state_B = cv_and_states + tis_dict = { + 'initial_state': "A", + 'final_state': "B", + 'cv': "cv", + 'minvals': 'float("inf")', + 'maxvals': "np.array([0, 0.1, 0.2]) * np.pi", + } + + with mock.patch.dict(_COMPILERS_LOC, unidirectional_tis_compiler): + network = TIS_NETWORK_PLUGIN(tis_dict) + + assert isinstance(network, paths.MISTISNetwork) + assert len(network.sampling_transitions) == 1 + assert len(network.transitions) == 1 + assert list(network.transitions) == [(state_A, state_B)] From fba6fd524a816740fea555e689ccfbf4d6a8b2c3 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Wed, 21 Aug 2024 19:16:03 -0500 Subject: [PATCH 2/5] Use InterfaceSet._reset before interface set tests --- paths_cli/tests/compiling/test_networks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/paths_cli/tests/compiling/test_networks.py b/paths_cli/tests/compiling/test_networks.py index 4830de14..a70111d8 100644 --- a/paths_cli/tests/compiling/test_networks.py +++ b/paths_cli/tests/compiling/test_networks.py @@ -12,6 +12,7 @@ @pytest.fixture def unidirectional_tis_compiler(cv_and_states): + paths.InterfaceSet._reset() cv, state_A, state_B = cv_and_states return { 'cv': mock_compiler('cv', named_objs={'cv': cv}), From 0efe35cbdc1c2384f3854fa6fcef68b1bbe63db6 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Wed, 21 Aug 2024 19:29:25 -0500 Subject: [PATCH 3/5] cleanup for TIS compiling --- paths_cli/compiling/networks.py | 21 -------- paths_cli/tests/compiling/test_networks.py | 56 ---------------------- 2 files changed, 77 deletions(-) diff --git a/paths_cli/compiling/networks.py b/paths_cli/compiling/networks.py index 019e6584..a571d1d5 100644 --- a/paths_cli/compiling/networks.py +++ b/paths_cli/compiling/networks.py @@ -88,27 +88,6 @@ def mistis_trans_info(dct): dct = dct.copy() dct['trans_info'] = dct.pop('interface_sets') return dct - # interface_sets = dct.pop('interface_sets') - # volume_compiler = compiler_for('volume') - # interface_set_compiler = compiler_for('interface_set') - - # trans_info = [] - # for iset in interface_sets: - # initial_state = volume_compiler(iset.pop("initial_state")) - # final_state = volume_compiler(iset.pop("final_state")) - # iset['type'] = iset.get('type', 'volume-interface-set') - # interface_set = interface_set_compiler(iset) - # trans_info.append((initial_state, interface_set, final_state)) - - # dct['trans_info'] = trans_info - # return dct - - -def tis_trans_info(dct): - # remap TIS into MISTIS format - dct = dct.copy() - remapped = {'interface_sets': [dct]} - return mistis_trans_info(remapped) TPS_NETWORK_PLUGIN = NetworkCompilerPlugin( diff --git a/paths_cli/tests/compiling/test_networks.py b/paths_cli/tests/compiling/test_networks.py index a70111d8..78bd7e53 100644 --- a/paths_cli/tests/compiling/test_networks.py +++ b/paths_cli/tests/compiling/test_networks.py @@ -27,62 +27,6 @@ def unidirectional_tis_compiler(cv_and_states): ), } -# def check_unidirectional_tis(results, state_A, state_B, cv): -# assert len(results) == 1 -# trans_info = results['trans_info'] -# assert len(trans_info) == 1 -# assert len(trans_info[0]) == 3 -# trans = trans_info[0] -# assert isinstance(trans, tuple) -# assert trans[0] == state_A -# assert trans[2] == state_B -# assert isinstance(trans[1], paths.VolumeInterfaceSet) -# ifaces = trans[1] -# assert ifaces.cv == cv -# assert ifaces.minvals == float("-inf") -# np.testing.assert_allclose(ifaces.maxvals, -# [0, np.pi / 10.0, np.pi / 5.0]) - - -# def test_mistis_trans_info(cv_and_states, mistis_dict, -# unidirectional_tis_compiler): -# cv, state_A, state_B = cv_and_states -# patch_base = 'paths_cli.compiling.networks' -# with mock.patch.dict(_COMPILERS_LOC, unidirectional_tis_compiler): -# results = mistis_trans_info(mistis_dict) - -# check_unidirectional_tis(results, state_A, state_B, cv) -# paths.InterfaceSet._reset() - - -# def test_tis_trans_info(cv_and_states): -# cv, state_A, state_B = cv_and_states -# dct = { -# 'initial_state': "A", -# 'final_state': "B", -# 'cv': 'cv', -# 'minvals': 'float("-inf")', -# 'maxvals': 'np.array([0, 0.1, 0.2]) * np.pi', -# } - -# compiler = { -# 'cv': mock_compiler('cv', named_objs={'cv': cv}), -# 'volume': mock_compiler('volume', named_objs={ -# "A": state_A, "B": state_B -# }), -# 'interface_set': mock_compiler( -# 'interface_set', -# type_dispatch={ -# 'volume-interface-set': VOLUME_INTERFACE_SET_PLUGIN -# } -# ), -# } -# with mock.patch.dict(_COMPILERS_LOC, compiler): -# results = tis_trans_info(dct) - -# check_unidirectional_tis(results, state_A, state_B, cv) -# paths.InterfaceSet._reset() - def test_build_tps_network(cv_and_states): _, state_A, state_B = cv_and_states From a3e95c3386f316fd1088b528e5adf7c287a729c9 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Thu, 22 Aug 2024 18:34:58 -0500 Subject: [PATCH 4/5] updates following code review --- paths_cli/compiling/networks.py | 1 + paths_cli/tests/compiling/test_networks.py | 30 ++++++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/paths_cli/compiling/networks.py b/paths_cli/compiling/networks.py index a571d1d5..13273637 100644 --- a/paths_cli/compiling/networks.py +++ b/paths_cli/compiling/networks.py @@ -45,6 +45,7 @@ def mistis_trans_info_param_builder(dcts): volume_compiler = compiler_for("volume") interface_set_compiler = compiler_for('interface_set') for dct in dcts: + dct = dct.copy() dct['type'] = dct.get('type', default) initial_state = volume_compiler(dct.pop('initial_state')) final_state = volume_compiler(dct.pop('final_state')) diff --git a/paths_cli/tests/compiling/test_networks.py b/paths_cli/tests/compiling/test_networks.py index 78bd7e53..6578d82e 100644 --- a/paths_cli/tests/compiling/test_networks.py +++ b/paths_cli/tests/compiling/test_networks.py @@ -47,22 +47,32 @@ def test_build_tps_network(cv_and_states): def test_build_mistis_network(cv_and_states, unidirectional_tis_compiler): cv, state_A, state_B = cv_and_states mistis_dict = { - 'interface_sets': [{ - 'initial_state': "A", - 'final_state': "B", - 'cv': 'cv', - 'minvals': 'float("-inf")', - 'maxvals': "np.array([0, 0.1, 0.2]) * np.pi" - }] + 'interface_sets': [ + { + 'initial_state': "A", + 'final_state': "B", + 'cv': 'cv', + 'minvals': 'float("-inf")', + 'maxvals': "np.array([0, 0.1, 0.2]) * np.pi" + }, + { + 'initial_state': "B", + 'final_state': "A", + 'cv': 'cv', + 'minvals': "np.array([1.0, 0.9, 0.8])", + 'maxvals': "float('inf')", + } + ] } with mock.patch.dict(_COMPILERS_LOC, unidirectional_tis_compiler): network = MISTIS_NETWORK_PLUGIN(mistis_dict) assert isinstance(network, paths.MISTISNetwork) - assert len(network.sampling_transitions) == 1 - assert len(network.transitions) == 1 - assert list(network.transitions) == [(state_A, state_B)] + assert len(network.sampling_transitions) == 2 + assert len(network.transitions) == 2 + assert list(network.transitions) == [(state_A, state_B), + (state_B, state_A)] def test_build_tis_network(cv_and_states, unidirectional_tis_compiler): cv, state_A, state_B = cv_and_states From e3bd4433b5a52e45a30e2202e83a2b58c264e742 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Thu, 22 Aug 2024 18:35:26 -0500 Subject: [PATCH 5/5] Update paths_cli/compiling/networks.py Co-authored-by: Sander Roet --- paths_cli/compiling/networks.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/paths_cli/compiling/networks.py b/paths_cli/compiling/networks.py index 13273637..c733de52 100644 --- a/paths_cli/compiling/networks.py +++ b/paths_cli/compiling/networks.py @@ -1,6 +1,5 @@ from paths_cli.compiling.core import ( - InstanceCompilerPlugin, Builder, Parameter, - listify, unlistify + InstanceCompilerPlugin, Builder, Parameter ) from paths_cli.compiling.tools import custom_eval from paths_cli.compiling.plugins import (