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
13#include <RDGeneral/Invariant.h>
14
15#include <map>
16#include <boost/lexical_cast.hpp>
17#include <boost/tokenizer.hpp>
18#include <algorithm>
19
20typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
21
22namespace RDKit {
23namespace MolEnumerator {
24
25struct LinkNode {
26 unsigned int minRep = 0;
27 unsigned int maxRep = 0;
28 unsigned int nBonds = 0;
29 std::vector<std::pair<unsigned int, unsigned int>> bondAtoms;
30};
31
32namespace utils {
33inline std::vector<LinkNode> getMolLinkNodes(
34 const ROMol &mol, bool strict = true,
35 const std::map<unsigned, Atom *> *atomIdxMap = nullptr) {
36 std::vector<LinkNode> res;
37 std::string pval;
39 return res;
40 }
41 std::vector<int> mapping;
42
43 boost::char_separator<char> pipesep("|");
44 boost::char_separator<char> spacesep(" ");
45 for (auto linknodetext : tokenizer(pval, pipesep)) {
46 LinkNode node;
47 tokenizer tokens(linknodetext, spacesep);
48 std::vector<unsigned int> data;
49 try {
50 std::transform(tokens.begin(), tokens.end(), std::back_inserter(data),
51 [](const std::string &token) -> unsigned int {
52 return boost::lexical_cast<unsigned int>(token);
53 });
54 } catch (boost::bad_lexical_cast &) {
55 std::ostringstream errout;
56 errout << "Cannot convert values in LINKNODE '" << linknodetext
57 << "' to unsigned ints";
58 if (strict) {
59 throw ValueErrorException(errout.str());
60 } else {
61 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
62 continue;
63 }
64 }
65 // the second test here is for the atom-pairs defining the bonds
66 // data[2] contains the number of bonds
67 if (data.size() < 5 || data.size() < 3 + 2 * data[2]) {
68 std::ostringstream errout;
69 errout << "not enough values in LINKNODE '" << linknodetext << "'";
70 if (strict) {
71 throw ValueErrorException(errout.str());
72 } else {
73 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
74 continue;
75 }
76 }
77
78 node.minRep = data[0];
79 node.maxRep = data[1];
80 if (node.minRep == 0 || node.maxRep < node.minRep) {
81 std::ostringstream errout;
82 errout << "bad counts in LINKNODE '" << linknodetext << "'";
83 if (strict) {
84 throw ValueErrorException(errout.str());
85 } else {
86 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
87 continue;
88 }
89 }
90 node.nBonds = data[2];
91 if (node.nBonds != 2) {
92 if (strict) {
94 "only link nodes with 2 bonds are currently supported");
95 } else {
97 << "only link nodes with 2 bonds are currently supported"
98 << std::endl;
99 continue;
100 }
101 }
102 // both bonds must start from the same atom:
103 if (data[3] != data[5]) {
104 std::ostringstream errout;
105 errout << "bonds don't start at the same atom for LINKNODE '"
106 << linknodetext << "'";
107 if (strict) {
108 throw ValueErrorException(errout.str());
109 } else {
110 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
111 continue;
112 }
113 }
114
115 if (atomIdxMap) {
116 // map the indices back to the original atom numbers
117 for (unsigned int i = 3; i <= 6; ++i) {
118 const auto aidx = atomIdxMap->find(data[i] - 1);
119 if (aidx == atomIdxMap->end()) {
120 std::ostringstream errout;
121 errout << "atom index " << data[i]
122 << " cannot be found in molecule for LINKNODE '"
123 << linknodetext << "'";
124 if (strict) {
125 throw ValueErrorException(errout.str());
126 } else {
127 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
128 continue;
129 }
130 } else {
131 data[i] = aidx->second->getIdx();
132 }
133 }
134 } else {
135 for (unsigned int i = 3; i <= 6; ++i) {
136 --data[i];
137 }
138 }
139 node.bondAtoms.push_back(std::make_pair(data[3], data[4]));
140 node.bondAtoms.push_back(std::make_pair(data[5], data[6]));
141 if (!mol.getBondBetweenAtoms(data[4], data[3]) ||
142 !mol.getBondBetweenAtoms(data[6], data[5])) {
143 std::ostringstream errout;
144 errout << "bond not found between atoms in LINKNODE '" << linknodetext
145 << "'";
146 if (strict) {
147 throw ValueErrorException(errout.str());
148 } else {
149 BOOST_LOG(rdWarningLog) << errout.str() << std::endl;
150 continue;
151 }
152 }
153 res.push_back(std::move(node));
154 }
155 return res;
156}
157
158} // namespace utils
159} // namespace MolEnumerator
160
161} // namespace RDKit
162#endif // RD_MOLENUMERATOR_LINKNODE_H
#define UNDER_CONSTRUCTION(fn)
Definition Invariant.h:124
boost::tokenizer< boost::char_separator< char > > tokenizer
Definition LinkNode.h:20
#define BOOST_LOG(__arg__)
Definition RDLog.h:110
RDKIT_RDGENERAL_EXPORT RDLogger rdWarningLog
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:33
constexpr std::string_view molFileLinkNodes
Definition types.h:169
Std stuff.
std::vector< std::pair< unsigned int, unsigned int > > bondAtoms
Definition LinkNode.h:29