Files
pymol-open-source/layer3/ExecutivePython.cpp
2024-05-20 09:07:33 -04:00

322 lines
9.0 KiB
C++

#include "Executive.h"
#include "ExecutivePython.h"
#ifndef _PYMOL_NOPY
#include "ObjectAlignment.h"
#include "ObjectCGO.h"
#include "ObjectCallback.h"
#include "ObjectMap.h"
#include "P.h"
#include "Feedback.h"
pymol::Result<> ExecutiveLoadObject(PyMOLGlobals* G,
const char* oname, PyObject* model, int frame, int type, int finish,
int discrete, int quiet, int zoom)
{
ObjectNameType valid_name = "";
pymol::CObject *origObj = nullptr, *obj;
OrthoLineType buf;
buf[0] = 0;
ExecutiveProcessObjectName(G, oname, valid_name);
origObj = ExecutiveFindObjectByName(G, valid_name);
/* TODO check for existing object of wrong type */
switch (type) {
case cLoadTypeChemPyModel: {
if (origObj) {
if (origObj->type != cObjectMolecule) {
ExecutiveDelete(G, valid_name);
origObj = nullptr;
}
}
PBlock(G); /*PBlockAndUnlockAPI(); */
obj = ObjectMoleculeLoadChemPyModel(
G, (ObjectMolecule*) origObj, model, frame, discrete);
PUnblock(G); /*PLockAPIAndUnblock(); */
if (!origObj) {
if (obj) {
ObjectSetName(obj, valid_name);
ExecutiveManageObject(G, obj, zoom, quiet);
if (frame < 0)
frame = ((ObjectMolecule*) obj)->NCSet - 1;
sprintf(buf,
" CmdLoad: ChemPy-model loaded into object \"%s\", state %d.\n",
valid_name, frame + 1);
}
} else if (origObj) {
if (finish)
ExecutiveUpdateObjectSelection(G, origObj);
if (frame < 0)
frame = ((ObjectMolecule*) origObj)->NCSet - 1;
sprintf(buf,
" CmdLoad: ChemPy-model appended into object \"%s\", state %d.\n",
valid_name, frame + 1);
}
break;
}
case cLoadTypeChemPyBrick:
if (origObj)
if (origObj->type != cObjectMap) {
ExecutiveDelete(G, valid_name);
origObj = nullptr;
}
PBlock(G); /*PBlockAndUnlockAPI(); */
obj = ObjectMapLoadChemPyBrick(
G, (ObjectMap*) origObj, model, frame, discrete, quiet);
PUnblock(G); /*PLockAPIAndUnblock(); */
if (!origObj) {
if (obj) {
ObjectSetName(obj, valid_name);
ExecutiveManageObject(G, obj, zoom, quiet);
sprintf(buf, " CmdLoad: chempy.brick loaded into object \"%s\"\n",
valid_name);
}
} else if (origObj) {
sprintf(buf, " CmdLoad: chempy.brick appended into object \"%s\"\n",
valid_name);
}
break;
case cLoadTypeChemPyMap:
if (origObj)
if (origObj->type != cObjectMap) {
ExecutiveDelete(G, valid_name);
origObj = nullptr;
}
PBlock(G); /*PBlockAndUnlockAPI(); */
obj = ObjectMapLoadChemPyMap(
G, (ObjectMap*) origObj, model, frame, discrete, quiet);
PUnblock(G); /*PLockAPIAndUnblock(); */
if (!origObj) {
if (obj) {
ObjectSetName(obj, valid_name);
ExecutiveManageObject(G, obj, zoom, quiet);
sprintf(buf, " CmdLoad: chempy.map loaded into object \"%s\"\n",
valid_name);
}
} else if (origObj) {
sprintf(buf, " CmdLoad: chempy.map appended into object \"%s\"\n",
valid_name);
}
break;
case cLoadTypeCallback:
if (origObj)
if (origObj->type != cObjectCallback) {
ExecutiveDelete(G, valid_name);
origObj = nullptr;
}
PBlock(G); /*PBlockAndUnlockAPI(); */
obj = ObjectCallbackDefine(
G, (ObjectCallback*) origObj, model, frame);
PUnblock(G); /*PLockAPIAndUnblock(); */
if (!origObj) {
if (obj) {
ObjectSetName(obj, valid_name);
ExecutiveManageObject(G, obj, zoom, quiet);
sprintf(buf, " CmdLoad: pymol.callback loaded into object \"%s\"\n",
valid_name);
}
} else if (origObj) {
sprintf(buf, " CmdLoad: pymol.callback appended into object \"%s\"\n",
valid_name);
}
break;
case cLoadTypeCGO:
if (origObj)
if (origObj->type != cObjectCGO) {
ExecutiveDelete(G, valid_name);
origObj = nullptr;
}
PBlock(G); /*PBlockAndUnlockAPI(); */
obj = ObjectCGODefine(G, (ObjectCGO*) origObj, model, frame);
PUnblock(G); /*PLockAPIAndUnblock(); */
if (!origObj) {
if (obj) {
ObjectSetName(obj, valid_name);
ExecutiveManageObject(G, obj, zoom, quiet);
sprintf(buf, " CmdLoad: CGO loaded into object \"%s\"\n", valid_name);
}
} else if (origObj) {
sprintf(buf, " CmdLoad: CGO appended into object \"%s\"\n", valid_name);
}
break;
}
if (origObj && !quiet) {
PRINTFB(G, FB_Executive, FB_Actions)
"%s", buf ENDFB(G);
OrthoRestorePrompt(G);
}
return {};
}
pymol::Result<> ExecutiveSetRawAlignment(PyMOLGlobals* G,
pymol::zstring_view alnname, PyObject* raw, pymol::zstring_view guidename,
int state, int quiet)
{
ObjectMolecule* guide = nullptr;
if (!guidename.empty()) {
guide = ExecutiveFindObject<ObjectMolecule>(G, guidename.c_str());
}
if(!PyList_Check(raw)) {
return pymol::make_error("alignment must be list");
}
auto n_cols = PyList_Size(raw);
pymol::vla<int> align_vla(n_cols * 3);
size_t vla_offset = 0;
for(size_t c = 0; c < n_cols; ++c) {
PyObject * col = PyList_GetItem(raw, c);
if(!PyList_Check(col)) {
return pymol::make_error("columns must be list");
}
auto n_idx = PyList_Size(col);
for(size_t i = 0; i < n_idx; ++i) {
const char * model;
int index;
PyObject * idx = PyList_GetItem(col, i);
if(!PyArg_ParseTuple(idx, "si", &model, &index)) {
return pymol::make_error("indices must be (str, int)");
}
auto mol = ExecutiveFindObject<ObjectMolecule>(G, model);
if(!mol) {
return pymol::make_error("object ", model, " not found");
}
if (!guide) {
guide = mol;
}
if (index < 1 || mol->NAtom < index) {
return pymol::make_error("index ('", model, ", ", index, ") out of range");
}
auto uid = AtomInfoCheckUniqueID(G, mol->AtomInfo + index - 1);
*(align_vla.check(vla_offset++)) = uid;
}
*(align_vla.check(vla_offset++)) = 0;
}
align_vla.resize(vla_offset);
// does alignment object already exist?
auto cobj = ExecutiveFindObjectByName(G, alnname.c_str());
if (cobj && cobj->type != cObjectAlignment) {
ExecutiveDelete(G, cobj->Name);
cobj = nullptr;
}
// create alignment object
cobj = ObjectAlignmentDefine(G, (ObjectAlignment*) cobj,
align_vla, state, true, guide, nullptr);
// manage alignment object
ObjectSetName(cobj, alnname.c_str());
ExecutiveManageObject(G, cobj, 0, quiet);
SceneInvalidate(G);
// make available as selection FIXME find better solution
cobj->update();
return {};
}
pymol::Result<float> ExecutiveFitPairs(
PyMOLGlobals* G, PyObject* list, int quiet)
{
auto ln = PyObject_Length(list);
if (!ln) {
return pymol::make_error("No selections provided");
}
if (ln & 0x1) {
return pymol::make_error(
G, "FitPairs", "must supply an even number of selections.");
}
std::vector<SelectorTmp> word(ln);
int a = 0;
while (a < ln) {
unique_PyObject_ptr item(PySequence_GetItem(list, a));
auto tmp = SelectorTmp::make(G, PyString_AsString(item.get()));
p_return_if_error(tmp);
word[a] = std::move(tmp.result());
a++;
}
return ExecutiveRMSPairs(G, word, 2, quiet);
}
/**
* Implementation of ExecutiveGetRawAlignment
* @param alnobj alignment object
* @param active_only only consider active alignments
* @param state state of alignment object
* @return a list of lists of (object, index) tuples containing the
* raw per-atom alignment relationships
*/
static pymol::Result<PyObject*> ExecutiveGetRawAlignmentImpl(
PyMOLGlobals* G, const ObjectAlignment* alnobj, bool active_only, int state)
{
if (state >= alnobj->getNFrame()) {
return pymol::make_error(
"Index Error: state ", state, " >= NState ", alnobj->getNFrame());
}
const auto& vla = alnobj->State[state].alignVLA;
if (!vla) {
return pymol::make_error("state ", state, " not valid");
}
auto hide_underscore = SettingGet<bool>(G, cSetting_hide_underscore_names);
const auto vla_len = VLAGetSize(vla);
PyObject* raw = PyList_New(0);
for (size_t i = 0; i < vla_len; ++i) {
PyObject* col = PyList_New(0);
for (int id; (id = vla[i]); ++i) {
auto eoo = ExecutiveUniqueIDAtomDictGet(G, id);
if (eoo && (!active_only || eoo->obj->Enabled) &&
(!hide_underscore || eoo->obj->Name[0] != '_')) {
PyObject* idx = Py_BuildValue("si", eoo->obj->Name, eoo->atm + 1);
PyList_Append(col, idx);
Py_DECREF(idx);
}
}
if (PyList_Size(col) > 0) {
PyList_Append(raw, col);
}
Py_DECREF(col);
}
return raw;
}
pymol::Result<PyObject*> ExecutiveGetRawAlignment(PyMOLGlobals* G,
pymol::null_safe_zstring_view name, bool active_only, int state)
{
if (name.empty()) {
name = ExecutiveGetActiveAlignment(G);
}
if (!name.empty()) {
if (auto obj = ExecutiveFindObject<ObjectAlignment>(G, name)) {
return ExecutiveGetRawAlignmentImpl(G, obj, active_only, state);
}
}
return pymol::make_error("No such alignment: ", name);
}
#endif