Skip to content

Commit

Permalink
New command: delete_states
Browse files Browse the repository at this point in the history
Delete states from multistate objects. Currently only supports
non-discrete molecular objects.
  • Loading branch information
JarrettSJohnson committed Aug 30, 2024
1 parent fa134b6 commit d82b626
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 0 deletions.
25 changes: 25 additions & 0 deletions layer2/ObjectMolecule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11208,6 +11208,31 @@ int ObjectMoleculeSetStateOrder(ObjectMolecule * I, int * order, int len) {
return false;
}

/*========================================================================*/
pymol::Result<> ObjectMoleculeDeleteStates(ObjectMolecule* I, const std::vector<int>& states)
{
auto& CSet = I->CSet;

// first pass, check for invalid states
for (auto state : states) {
if (state < 0 || state >= I->NCSet) {
auto msg = pymol::string_format("Invalid state index: %d", state);
I->G->Feedback->addColored(msg.c_str(), FB_Errors);
return {};
}
}

// second pass, delete states
for (auto it = states.rbegin(); it != states.rend(); ++it) {
int state = *it;
DeleteP(CSet[state]);
CSet.erase(state, 1);
}
I->NCSet -= states.size();
CSet.resize(I->NCSet);
return {};
}

/*========================================================================*/
ObjectMolecule::~ObjectMolecule()
{
Expand Down
8 changes: 8 additions & 0 deletions layer2/ObjectMolecule.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,14 @@ int ObjectMoleculeCheckFullStateSelection(ObjectMolecule * I, int sele, int stat

int ObjectMoleculeSetStateOrder(ObjectMolecule * I, int * order, int len);

/**
* @brief Deletes a CoordSet/State from a molecule object
* @param I ObjectMolecule
* @param states state indices (0-based)
* @note This function only works on non-discrete molecular objects
*/
pymol::Result<> ObjectMoleculeDeleteStates(ObjectMolecule* I, const std::vector<int>& state);

int ObjectMoleculeAddPseudoatom(ObjectMolecule * I, int sele_index, const char *name,
const char *resn, const char *resi, const char *chain,
const char *segi, const char *elem, float vdw,
Expand Down
24 changes: 24 additions & 0 deletions layer3/Executive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14278,6 +14278,30 @@ pymol::Result<std::vector<DiscardedRec>> ExecutiveDelete(PyMOLGlobals * G, pymol
return discardedRecs;
}

pymol::Result<> ExecutiveDeleteStates(
PyMOLGlobals* G, std::string_view name, const std::vector<int>& states)
{
for (auto& rec : ExecutiveGetSpecRecsFromPattern(G, name.data())) {
if (rec.type != cExecObject) {
continue;
}
auto* obj = rec.obj;
if (obj->type != cObjectMolecule) {
continue;
}
auto* mol = static_cast<ObjectMolecule*>(obj);
if (mol->DiscreteFlag) {
G->Feedback->addColored(
"Error: Cannot delete states from discrete objects.\n", FB_Warnings);
continue;
}
ObjectMoleculeDeleteStates(mol, states);
}
SceneChanged(G);
ExecutiveInvalidatePanelList(G);
return {};
}

void ExecutiveReAddSpec(PyMOLGlobals* G, std::vector<DiscardedRec>& specs)
{
auto I = G->Executive;
Expand Down
10 changes: 10 additions & 0 deletions layer3/Executive.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,16 @@ pymol::CObject** ExecutiveFindObjectsByType(PyMOLGlobals * G, int objType);
int ExecutiveIterateObject(PyMOLGlobals * G, pymol::CObject ** obj, void **hidden);
pymol::Result<std::vector<DiscardedRec>> ExecutiveDelete(PyMOLGlobals * G, pymol::zstring_view nameView, bool save = false);

/**
* @brief Deletes states from an object
* @param name name of the object
* @param states list of states to be deleted (0-based, must be sorted and
* unique)
* @note Currently only works on non-discrete molecular objects
*/
pymol::Result<> ExecutiveDeleteStates(
PyMOLGlobals* G, std::string_view name, const std::vector<int>& states);

/**
* @brief Unregisters the specification record from PyMOL
* @param rec specification record to be purged/removed
Expand Down
15 changes: 15 additions & 0 deletions layer4/Cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5178,6 +5178,20 @@ static PyObject *CmdDelete(PyObject * self, PyObject * args)
return APISuccess();
}

static PyObject *CmdDeleteStates(PyObject * self, PyObject * args)
{
PyMOLGlobals* G = nullptr;
const char* objName;
PyObject* statesPyList;
API_SETUP_ARGS(G, self, args, "OsO", &self, &objName, &statesPyList);
std::vector<int> states;
PConvFromPyObject(G, statesPyList, states);
API_ASSERT(APIEnterNotModal(G));
auto result = ExecutiveDeleteStates(G, objName, states);
APIExit(G);
return APIResult(G, result);
}

static PyObject *CmdCartoon(PyObject * self, PyObject * args)
{
PyMOLGlobals *G = nullptr;
Expand Down Expand Up @@ -6275,6 +6289,7 @@ static PyMethodDef Cmd_methods[] = {
{"del_colorection", CmdDelColorection, METH_VARARGS},
{"fake_drag", CmdFakeDrag, METH_VARARGS},
{"delete", CmdDelete, METH_VARARGS},
{"delete_states", CmdDeleteStates, METH_VARARGS},
{"dirty", CmdDirty, METH_VARARGS},
{"dirty_wizard", CmdDirtyWizard, METH_VARARGS},
{"dihedral", CmdDihedral, METH_VARARGS},
Expand Down
1 change: 1 addition & 0 deletions modules/pymol/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
async_, \
cls, \
delete, \
delete_states, \
do, \
log, \
log_close, \
Expand Down
58 changes: 58 additions & 0 deletions modules/pymol/commanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ def delete(name, *, _self=cmd):
SEE ALSO
remove
delete_states
'''
r = DEFAULT_ERROR
try:
Expand All @@ -538,6 +539,63 @@ def delete(name, *, _self=cmd):
if _self._raising(r,_self): raise pymol.CmdException
return r

def delete_states(name: str, states: str, *, _self=cmd):
'''
DESCRIPTION
USAGE
delete_states name, states
ARGUMENTS
name = name(s) of object(s), supports wildcards (*)
states = string: space separated list of state numbers or ranges
EXAMPLES
delete_state 1nmr, 1-5 # delete states 1 to 5 from 1nmr
delete_state *, 1-3 10-40 # deletes states 1 to 3 and 10 to 40 from all applicable objects
PYMOL API
cmd.delete_states(string name = object-name, string states = states string)
SEE ALSO
delete
'''

def get_state_list(states_str):
output=[]
input_str = re.sub(r"\s"," ", states_str)
input_str = input_str.replace("-"," -")
input_str = input_str.replace("- ","-")
input_str = input_str.strip().split()

last = -1
for x in input_str:
if not x.isdigit():
if x.startswith("-"):
direction = 1
current = last
last = int(x[1:]) - 1
if last < current:
direction = -1
while current != last:
current += direction
output.append(str(current))
else:
val = int(x) - 1
output.append(str(val))
last = val
return output

with _self.lockcm:
output = get_state_list(states)
states_list = sorted(set(map(int, output)))
return _cmd.delete_states(_self._COb, name, states_list)

class Selection(str):
pass
Expand Down
1 change: 1 addition & 0 deletions modules/pymol/keywords.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def get_command_keywords(self_cmd=cmd):
'create' : [ self_cmd.create , 0 , 0 , '' , parsing.LEGACY ],
'decline' : [ self_cmd.decline , 0 , 0 , '' , parsing.STRICT ],
'delete' : [ self_cmd.delete , 0 , 0 , '' , parsing.STRICT ],
'delete_states' : [ self_cmd.delete_states , 0 , 0 , '' , parsing.STRICT ],
'def' : [ self_cmd.python_help , 0 , 0 , '' , parsing.PYTHON ],
'del' : [ self_cmd.python_help , 0 , 0 , '' , parsing.PYTHON ],
'deprotect' : [ self_cmd.deprotect , 0 , 0 , '' , parsing.STRICT ],
Expand Down
6 changes: 6 additions & 0 deletions testing/tests/api/commanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ def testDelete(self):
cmd.delete('m1 m2')
self.assertEqual(cmd.get_names(), ['m3'])

def testDeleteStates(self):
cmd.pseudoatom('m1', state=10)
self.assertEqual(cmd.count_states('m1'), 10)
cmd.delete_states('m1', '4-8')
self.assertEqual(cmd.count_states('m1'), 5)

def testDo(self):
# tested with other methods
pass
Expand Down

1 comment on commit d82b626

@JarrettSJohnson
Copy link
Member Author

Choose a reason for hiding this comment

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

Please sign in to comment.