RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
LinkNode.h
Go to the documentation of this file.
1//
2// Copyright (C) 2020 Greg Landrum and T5 Informatics GmbH
3//
4// @@ All Rights Reserved @@
5// This file is part of the RDKit.
6// The contents are covered by the terms of the BSD license
7// which is included in the file license.txt, found at the root
8// of the RDKit source tree.
9//
10#ifndef RD_MOLENUMERATOR_LINKNODE_H
11#define RD_MOLENUMERATOR_LINKNODE_H
12#include <GraphMol/ROMol.h>
13
14#include <RDGeneral/Invariant.h>
15
16#include <map>
17#include <sstream>
18#include <boost/lexical_cast.hpp>
19#include <boost/tokenizer.hpp>
20#include <algorithm>
21
22typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
23
24namespace RDKit {
25namespace MolEnumerator {
26
27struct LinkNode {
28 unsigned int minRep = 0;
29 unsigned int maxRep = 0;
30 unsigned int nBonds = 0;
31 std::vector<std::pair<unsigned int, unsigned int>> bondAtoms;
32};
33
34namespace utils {
35inline std::vector<LinkNode> getMolLinkNodes(
36 const ROMol &mol, bool strict = true,
37 const std::map<unsigned, Atom *> *atomIdxMap = nullptr) {
38 std::vector<LinkNode> res;
39 std::string pval;
41 return res;
42 }
43 std::vector<int> mapping;
44
45 boost::char_separator<char> pipesep("|");
46 boost::char_separator<char> spacesep(" ");
47 for (auto linknodetext : tokenizer(pval, pipesep)) {
48 LinkNode node;
49 tokenizer tokens(linknodetext, spacesep);
50 std::vector<unsigned int> data;
51 try {
52 std::transform(tokens.begin(), tokens.end(), std::back_inserter(data),
53 [](const std::string &token) -> unsigned int {
54 return boost::lexical_cast<unsigned int>(token);
55 });
56 } catch (boost::bad_lexical_cast &) {
57 std::ostringstream errout;
58 errout << "Cannot convert values in LINKNODE '" << linknodetext
59 << "' to unsigned ints";
60 if (strict) {
61 throw ValueErrorException(errout.str());
62 } else {
63 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
64 continue;
65 }
66 }
67 // the second test here is for the atom-pairs defining the bonds
68 // data[2] contains the number of bonds
69 if (data.size() < 5 || data.size() < 3 + 2 * data[2]) {
70 std::ostringstream errout;
71 errout << "not enough values in LINKNODE '" << linknodetext << "'";
72 if (strict) {
73 throw ValueErrorException(errout.str());
74 } else {
75 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
76 continue;
77 }
78 }
79
80 node.minRep = data[0];
81 node.maxRep = data[1];
82 if (node.minRep == 0 || node.maxRep < node.minRep) {
83 std::ostringstream errout;
84 errout << "bad counts in LINKNODE '" << linknodetext << "'";
85 if (strict) {
86 throw ValueErrorException(errout.str());
87 } else {
88 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
89 continue;
90 }
91 }
92 node.nBonds = data[2];
93 if (node.nBonds != 2) {
94 if (strict) {
96 "only link nodes with 2 bonds are currently supported");
97 } else {
99 << "only link nodes with 2 bonds are currently supported"
100 << std::endl;
101 continue;
102 }
103 }
104 // both bonds must start from the same atom:
105 if (data[3] != data[5]) {
106 std::ostringstream errout;
107 errout << "bonds don't start at the same atom for LINKNODE '"
108 << linknodetext << "'";
109 if (strict) {
110 throw ValueErrorException(errout.str());
111 } else {
112 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
113 continue;
114 }
115 }
116
117 if (atomIdxMap) {
118 // map the indices back to the original atom numbers
119 for (unsigned int i = 3; i <= 6; ++i) {
120 const auto aidx = atomIdxMap->find(data[i] - 1);
121 if (aidx == atomIdxMap->end()) {
122 std::ostringstream errout;
123 errout << "atom index " << data[i]
124 << " cannot be found in molecule for LINKNODE '"
125 << linknodetext << "'";
126 if (strict) {
127 throw ValueErrorException(errout.str());
128 } else {
129 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
130 continue;
131 }
132 } else {
133 data[i] = aidx->second->getIdx();
134 }
135 }
136 } else {
137 for (unsigned int i = 3; i <= 6; ++i) {
138 --data[i];
139 }
140 }
141 node.bondAtoms.push_back(std::make_pair(data[3], data[4]));
142 node.bondAtoms.push_back(std::make_pair(data[5], data[6]));
143 if (!mol.getBondBetweenAtoms(data[4], data[3]) ||
144 !mol.getBondBetweenAtoms(data[6], data[5])) {
145 std::ostringstream errout;
146 errout << "bond not found between atoms in LINKNODE '" << linknodetext
147 << "'";
148 if (strict) {
149 throw ValueErrorException(errout.str());
150 } else {
151 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
152 continue;
153 }
154 }
155 res.push_back(std::move(node));
156 }
157 return res;
158}
159
160} // namespace utils
161} // namespace MolEnumerator
162
163} // namespace RDKit
164#endif // RD_MOLENUMERATOR_LINKNODE_H
#define UNDER_CONSTRUCTION(fn)
Definition Invariant.h:124
boost::tokenizer< boost::char_separator< char > > tokenizer
Definition LinkNode.h:22
#define BOOST_LOG(__arg__)
Definition RDLog.h:109
RDKIT_RDGENERAL_EXPORT RDLogger rdWarningLog
Defines the primary molecule class ROMol as well as associated typedefs.
bool getPropIfPresent(const std::string_view key, T &res) const
Definition RDProps.h:127
Bond * getBondBetweenAtoms(unsigned int idx1, unsigned int idx2)
returns a pointer to the bond between two atoms, Null on failure
Class to allow us to throw a ValueError from C++ and have it make it back to Python.
Definition Exceptions.h:41
std::vector< LinkNode > getMolLinkNodes(const ROMol &mol, bool strict=true, const std::map< unsigned, Atom * > *atomIdxMap=nullptr)
Definition LinkNode.h:35
constexpr std::string_view molFileLinkNodes
Definition types.h:168
Std stuff.
std::vector< std::pair< unsigned int, unsigned int > > bondAtoms
Definition LinkNode.h:31