rdkit-rb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +30 -0
- data/README.md +177 -0
- data/lib/rdkit/ffi.rb +91 -0
- data/lib/rdkit/molecule.rb +340 -0
- data/lib/rdkit/reaction.rb +66 -0
- data/lib/rdkit/version.rb +3 -0
- data/lib/rdkit-rb.rb +1 -0
- data/lib/rdkit.rb +41 -0
- data/vendor/aarch64-linux/ChemReactions-license.txt +31 -0
- data/vendor/aarch64-linux/librdkitcffi.so +0 -0
- data/vendor/aarch64-linux/rapidjson-license.txt +57 -0
- data/vendor/aarch64-linux/rdkit-license.txt +29 -0
- data/vendor/arm64-darwin/ChemReactions-license.txt +31 -0
- data/vendor/arm64-darwin/librdkitcffi.dylib +0 -0
- data/vendor/arm64-darwin/rapidjson-license.txt +57 -0
- data/vendor/arm64-darwin/rdkit-license.txt +29 -0
- data/vendor/x64-mingw/ChemReactions-license.txt +31 -0
- data/vendor/x64-mingw/rapidjson-license.txt +57 -0
- data/vendor/x64-mingw/rdkit-license.txt +29 -0
- data/vendor/x64-mingw/rdkitcffi.dll +0 -0
- data/vendor/x86_64-darwin/ChemReactions-license.txt +31 -0
- data/vendor/x86_64-darwin/librdkitcffi.dylib +0 -0
- data/vendor/x86_64-darwin/rapidjson-license.txt +57 -0
- data/vendor/x86_64-darwin/rdkit-license.txt +29 -0
- data/vendor/x86_64-linux/ChemReactions-license.txt +31 -0
- data/vendor/x86_64-linux/librdkitcffi.so +0 -0
- data/vendor/x86_64-linux/rapidjson-license.txt +57 -0
- data/vendor/x86_64-linux/rdkit-license.txt +29 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9182da229ab652e734801366a87d7a75527888aab1d5fc4df16730cd9468dd88
|
4
|
+
data.tar.gz: 4835a455fb34e0270ff568eda78bdb560932cdb96a47b3f7e0c5cf717127f695
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4602becf8e88cdc946b7c92926dbaec2c6dad8579f42016697b89667c8242138675ef407140556b6b1097531e1b13632c1fb408b4a21783d73770ea8752f8a3e
|
7
|
+
data.tar.gz: 7486a4a515a40a99fe7c466deb04be027070d0cc41c16979de00300662ad607f2396df1619eb13cf7c7d493832a9b8d17d90b7fe2febbd67468ebf9c6913c0e6
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2006-2015, Rational Discovery LLC, Greg Landrum, and Julie Penzotti and others
|
4
|
+
Copyright (c) 2024 Andrew Kane
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
9
|
+
|
10
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
11
|
+
list of conditions and the following disclaimer.
|
12
|
+
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
14
|
+
this list of conditions and the following disclaimer in the documentation
|
15
|
+
and/or other materials provided with the distribution.
|
16
|
+
|
17
|
+
3. Neither the name of the copyright holder nor the names of its
|
18
|
+
contributors may be used to endorse or promote products derived from
|
19
|
+
this software without specific prior written permission.
|
20
|
+
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
22
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
24
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
25
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
27
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
28
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
29
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
# RDKit.rb
|
2
|
+
|
3
|
+
Cheminformatics for Ruby, powered by [RDKit](https://github.com/rdkit/rdkit)
|
4
|
+
|
5
|
+
[](https://github.com/ankane/rdkit-ruby/actions)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application’s Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem "rdkit-rb"
|
13
|
+
```
|
14
|
+
|
15
|
+
## Getting Started
|
16
|
+
|
17
|
+
Create a molecule
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
mol = RDKit::Molecule.from_smiles("c1ccccc1O")
|
21
|
+
```
|
22
|
+
|
23
|
+
Get the number of atoms
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
mol.num_atoms
|
27
|
+
```
|
28
|
+
|
29
|
+
Get substructure matches
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
mol.match(RDKit::Molecule.from_smarts("ccO"))
|
33
|
+
```
|
34
|
+
|
35
|
+
Get fragments
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
mol.fragments
|
39
|
+
```
|
40
|
+
|
41
|
+
Generate an SVG
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
mol.to_svg
|
45
|
+
```
|
46
|
+
|
47
|
+
## Fingerprints
|
48
|
+
|
49
|
+
A number of [fingerprints](https://www.rdkit.org/docs/RDKit_Book.html#additional-information-about-the-fingerprints) are supported.
|
50
|
+
|
51
|
+
RDKit
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
mol.rdkit_fingerprint
|
55
|
+
```
|
56
|
+
|
57
|
+
Morgan
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
mol.morgan_fingerprint
|
61
|
+
```
|
62
|
+
|
63
|
+
Pattern
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
mol.pattern_fingerprint
|
67
|
+
```
|
68
|
+
|
69
|
+
Atom pair
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
mol.atom_pair_fingerprint
|
73
|
+
```
|
74
|
+
|
75
|
+
Topological torsion
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
mol.topological_torsion_fingerprint
|
79
|
+
```
|
80
|
+
|
81
|
+
MACCS
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
mol.maccs_fingerprint
|
85
|
+
```
|
86
|
+
|
87
|
+
You can use a library like [pgvector-ruby](https://github.com/pgvector/pgvector-ruby) to find similar molecules. See an [example](https://github.com/pgvector/pgvector-ruby/blob/master/examples/morgan_fingerprints.rb).
|
88
|
+
|
89
|
+
## Updates
|
90
|
+
|
91
|
+
Add or remove hydrogen atoms
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
mol.add_hs!
|
95
|
+
mol.remove_hs!
|
96
|
+
```
|
97
|
+
|
98
|
+
Standardize
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
mol.cleanup!
|
102
|
+
mol.normalize!
|
103
|
+
mol.neutralize!
|
104
|
+
mol.reionize!
|
105
|
+
mol.canonical_tautomer!
|
106
|
+
mol.charge_parent!
|
107
|
+
mol.fragment_parent!
|
108
|
+
```
|
109
|
+
|
110
|
+
## Conversion
|
111
|
+
|
112
|
+
SMILES
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
mol.to_smiles
|
116
|
+
```
|
117
|
+
|
118
|
+
SMARTS
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
mol.to_smarts
|
122
|
+
```
|
123
|
+
|
124
|
+
CXSMILES
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
mol.to_cxsmiles
|
128
|
+
```
|
129
|
+
|
130
|
+
CXSMARTS
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
mol.to_cxsmarts
|
134
|
+
```
|
135
|
+
|
136
|
+
JSON
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
mol.to_json
|
140
|
+
```
|
141
|
+
|
142
|
+
## Reactions
|
143
|
+
|
144
|
+
Create a reaction
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
rxn = RDKit::Reaction.from_smarts("[CH3:1][OH:2]>>[CH2:1]=[OH0:2]")
|
148
|
+
```
|
149
|
+
|
150
|
+
Generate an SVG
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
rxn.to_svg
|
154
|
+
```
|
155
|
+
|
156
|
+
## History
|
157
|
+
|
158
|
+
View the [changelog](https://github.com/ankane/rdkit-ruby/blob/master/CHANGELOG.md)
|
159
|
+
|
160
|
+
## Contributing
|
161
|
+
|
162
|
+
Everyone is encouraged to help improve this project. Here are a few ways you can help:
|
163
|
+
|
164
|
+
- [Report bugs](https://github.com/ankane/rdkit-ruby/issues)
|
165
|
+
- Fix bugs and [submit pull requests](https://github.com/ankane/rdkit-ruby/pulls)
|
166
|
+
- Write, clarify, or fix documentation
|
167
|
+
- Suggest or add new features
|
168
|
+
|
169
|
+
To get started with development:
|
170
|
+
|
171
|
+
```sh
|
172
|
+
git clone https://github.com/ankane/rdkit-ruby.git
|
173
|
+
cd rdkit-ruby
|
174
|
+
bundle install
|
175
|
+
bundle exec rake vendor:all
|
176
|
+
bundle exec rake test
|
177
|
+
```
|
data/lib/rdkit/ffi.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module RDKit
|
2
|
+
module FFI
|
3
|
+
extend Fiddle::Importer
|
4
|
+
|
5
|
+
libs = Array(RDKit.ffi_lib).dup
|
6
|
+
begin
|
7
|
+
dlload Fiddle.dlopen(libs.shift)
|
8
|
+
rescue Fiddle::DLError => e
|
9
|
+
retry if libs.any?
|
10
|
+
raise e
|
11
|
+
end
|
12
|
+
|
13
|
+
# https://github.com/rdkit/rdkit/blob/master/Code/MinimalLib/cffiwrapper.h
|
14
|
+
|
15
|
+
# I/O
|
16
|
+
extern "char *get_mol(const char *input, size_t *mol_sz, const char *details_json)"
|
17
|
+
extern "char *get_qmol(const char *input, size_t *mol_sz, const char *details_json)"
|
18
|
+
extern "char *get_molblock(const char *pkl, size_t pkl_sz, const char *details_json)"
|
19
|
+
extern "char *get_v3kmolblock(const char *pkl, size_t pkl_sz, const char *details_json)"
|
20
|
+
extern "char *get_smiles(const char *pkl, size_t pkl_sz, const char *details_json)"
|
21
|
+
extern "char *get_smarts(const char *pkl, size_t pkl_sz, const char *details_json)"
|
22
|
+
extern "char *get_cxsmiles(const char *pkl, size_t pkl_sz, const char *details_json)"
|
23
|
+
extern "char *get_cxsmarts(const char *pkl, size_t pkl_sz, const char *details_json)"
|
24
|
+
extern "char *get_json(const char *pkl, size_t pkl_sz, const char *details_json)"
|
25
|
+
extern "char *get_rxn(const char *input, size_t *mol_sz, const char *details_json)"
|
26
|
+
extern "char **get_mol_frags(const char *pkl, size_t pkl_sz, size_t **frags_pkl_sz_array, size_t *num_frags, const char *details_json, char **mappings_json)"
|
27
|
+
|
28
|
+
# substructure
|
29
|
+
extern "char *get_substruct_match(const char *mol_pkl, size_t mol_pkl_sz, const char *query_pkl, size_t query_pkl_sz, const char *options_json)"
|
30
|
+
extern "char *get_substruct_matches(const char *mol_pkl, size_t mol_pkl_sz, const char *query_pkl, size_t query_pkl_sz, const char *options_json)"
|
31
|
+
|
32
|
+
# drawing
|
33
|
+
extern "char *get_svg(const char *pkl, size_t pkl_sz, const char *details_json)"
|
34
|
+
extern "char *get_rxn_svg(const char *pkl, size_t pkl_sz, const char *details_json)"
|
35
|
+
|
36
|
+
# calculators
|
37
|
+
extern "char *get_descriptors(const char *pkl, size_t pkl_sz)"
|
38
|
+
extern "char *get_morgan_fp(const char *pkl, size_t pkl_sz, const char *details_json)"
|
39
|
+
extern "char *get_morgan_fp_as_bytes(const char *pkl, size_t pkl_sz, size_t *nbytes, const char *details_json)"
|
40
|
+
extern "char *get_rdkit_fp(const char *pkl, size_t pkl_sz, const char *details_json)"
|
41
|
+
extern "char *get_rdkit_fp_as_bytes(const char *pkl, size_t pkl_sz, size_t *nbytes, const char *details_json)"
|
42
|
+
extern "char *get_pattern_fp(const char *pkl, size_t pkl_sz, const char *details_json)"
|
43
|
+
extern "char *get_pattern_fp_as_bytes(const char *pkl, size_t pkl_sz, size_t *nbytes, const char *details_json)"
|
44
|
+
extern "char *get_topological_torsion_fp(const char *pkl, size_t pkl_sz, const char *details_json)"
|
45
|
+
extern "char *get_topological_torsion_fp_as_bytes(const char *pkl, size_t pkl_sz, size_t *nbytes, const char *details_json)"
|
46
|
+
extern "char *get_atom_pair_fp(const char *pkl, size_t pkl_sz, const char *details_json)"
|
47
|
+
extern "char *get_atom_pair_fp_as_bytes(const char *pkl, size_t pkl_sz, size_t *nbytes, const char *details_json)"
|
48
|
+
extern "char *get_maccs_fp(const char *pkl, size_t pkl_sz)"
|
49
|
+
extern "char *get_maccs_fp_as_bytes(const char *pkl, size_t pkl_sz, size_t *nbytes)"
|
50
|
+
|
51
|
+
# modification
|
52
|
+
extern "short add_hs(char **pkl, size_t *pkl_sz)"
|
53
|
+
extern "short remove_all_hs(char **pkl, size_t *pkl_sz)"
|
54
|
+
|
55
|
+
# standardization
|
56
|
+
extern "short cleanup(char **pkl, size_t *pkl_sz, const char *details_json)"
|
57
|
+
extern "short normalize(char **pkl, size_t *pkl_sz, const char *details_json)"
|
58
|
+
extern "short neutralize(char **pkl, size_t *pkl_sz, const char *details_json)"
|
59
|
+
extern "short reionize(char **pkl, size_t *pkl_sz, const char *details_json)"
|
60
|
+
extern "short canonical_tautomer(char **pkl, size_t *pkl_sz, const char *details_json)"
|
61
|
+
extern "short charge_parent(char **pkl, size_t *pkl_sz, const char *details_json)"
|
62
|
+
extern "short fragment_parent(char **pkl, size_t *pkl_sz, const char *details_json)"
|
63
|
+
|
64
|
+
# coordinates
|
65
|
+
extern "void prefer_coordgen(short val)"
|
66
|
+
extern "short has_coords(char *mol_pkl, size_t mol_pkl_sz)"
|
67
|
+
extern "short set_2d_coords(char **pkl, size_t *pkl_sz)"
|
68
|
+
extern "short set_3d_coords(char **pkl, size_t *pkl_sz, const char *params_json)"
|
69
|
+
extern "short set_2d_coords_aligned(char **pkl, size_t *pkl_sz, const char *template_pkl, size_t template_sz, const char *details_json, char **match_json)"
|
70
|
+
|
71
|
+
# housekeeping
|
72
|
+
# treat as void *ptr since calls free() internally
|
73
|
+
FREE = extern "void free_ptr(char *ptr)"
|
74
|
+
|
75
|
+
# other
|
76
|
+
extern "char *version()"
|
77
|
+
extern "void enable_logging()"
|
78
|
+
extern "void disable_logging()"
|
79
|
+
|
80
|
+
# chirality
|
81
|
+
extern "short use_legacy_stereo_perception(short value)"
|
82
|
+
extern "short allow_non_tetrahedral_chirality(short value)"
|
83
|
+
|
84
|
+
# logging
|
85
|
+
extern "void *set_log_tee(const char *log_name)"
|
86
|
+
extern "void *set_log_capture(const char *log_name)"
|
87
|
+
extern "short destroy_log_handle(void **log_handle)"
|
88
|
+
extern "char *get_log_buffer(void *log_handle)"
|
89
|
+
extern "short clear_log_buffer(void *log_handle)"
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,340 @@
|
|
1
|
+
module RDKit
|
2
|
+
class Molecule
|
3
|
+
private_class_method :new
|
4
|
+
|
5
|
+
def self.from_smiles(input, **options)
|
6
|
+
mol = allocate
|
7
|
+
mol.send(:load_smiles, input, **options)
|
8
|
+
mol
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.from_smarts(input)
|
12
|
+
mol = allocate
|
13
|
+
mol.send(:load_smarts, input)
|
14
|
+
mol
|
15
|
+
end
|
16
|
+
|
17
|
+
def num_atoms(only_explicit: true)
|
18
|
+
if only_explicit
|
19
|
+
json_data["molecules"].sum { |v| v["atoms"].count }
|
20
|
+
else
|
21
|
+
descriptors["NumAtoms"].to_i
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def num_heavy_atoms
|
26
|
+
descriptors["NumHeavyAtoms"].to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def match?(pattern, use_chirality: true)
|
30
|
+
!match(pattern, use_chirality: use_chirality, max_matches: 1).nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def match(pattern, use_chirality: true, max_matches: nil)
|
34
|
+
check_pattern(pattern)
|
35
|
+
|
36
|
+
details = {
|
37
|
+
useChirality: use_chirality
|
38
|
+
}
|
39
|
+
details[:maxMatches] = max_matches.to_i if max_matches
|
40
|
+
json = check_string(FFI.get_substruct_matches(@ptr, @sz, pattern.instance_variable_get(:@ptr), pattern.instance_variable_get(:@sz), to_details(details)))
|
41
|
+
|
42
|
+
matches = JSON.parse(json)
|
43
|
+
if matches.any?
|
44
|
+
matches.map { |v| v["atoms"] }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def fragments(sanitize: true)
|
49
|
+
sz_arr = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
|
50
|
+
num_frags = Fiddle::Pointer.malloc(Fiddle::SIZEOF_SIZE_T)
|
51
|
+
details = {
|
52
|
+
sanitizeFrags: sanitize
|
53
|
+
}
|
54
|
+
arr = FFI.get_mol_frags(@ptr, @sz, sz_arr.ref, num_frags.ref, to_details(details), nil)
|
55
|
+
check_ptr(arr)
|
56
|
+
|
57
|
+
num_frags.to_i.times.map do |i|
|
58
|
+
ptr = (arr + i * Fiddle::SIZEOF_VOIDP).ptr
|
59
|
+
sz = (sz_arr + i * Fiddle::SIZEOF_SIZE_T).ptr
|
60
|
+
|
61
|
+
mol = self.class.allocate
|
62
|
+
mol.send(:load_ptr, ptr, sz)
|
63
|
+
mol
|
64
|
+
end
|
65
|
+
ensure
|
66
|
+
free_ptr(sz_arr)
|
67
|
+
free_ptr(arr)
|
68
|
+
end
|
69
|
+
|
70
|
+
def rdkit_fingerprint(min_path: 1, max_path: 7, length: 2048, bits_per_hash: 2, use_hs: true, branched_paths: true, use_bond_order: true)
|
71
|
+
length = length.to_i
|
72
|
+
check_length(length)
|
73
|
+
|
74
|
+
details = {
|
75
|
+
minPath: min_path.to_i,
|
76
|
+
maxPath: max_path.to_i,
|
77
|
+
nBits: length,
|
78
|
+
nBitsPerHash: bits_per_hash.to_i,
|
79
|
+
useHs: use_hs,
|
80
|
+
branchedPaths: branched_paths,
|
81
|
+
useBondOrder: use_bond_order
|
82
|
+
}
|
83
|
+
check_string(FFI.get_rdkit_fp(@ptr, @sz, to_details(details)))
|
84
|
+
end
|
85
|
+
|
86
|
+
def morgan_fingerprint(radius: 3, length: 2048, use_chirality: false, use_bond_types: true)
|
87
|
+
radius = radius.to_i
|
88
|
+
if radius < 1
|
89
|
+
raise ArgumentError, "radius must be greater than 0"
|
90
|
+
end
|
91
|
+
|
92
|
+
length = length.to_i
|
93
|
+
check_length(length)
|
94
|
+
|
95
|
+
details = {
|
96
|
+
radius: radius,
|
97
|
+
nBits: length,
|
98
|
+
useChirality: use_chirality,
|
99
|
+
useBondTypes: use_bond_types
|
100
|
+
}
|
101
|
+
check_string(FFI.get_morgan_fp(@ptr, @sz, to_details(details)))
|
102
|
+
end
|
103
|
+
|
104
|
+
def pattern_fingerprint(length: 2048, tautomeric: false)
|
105
|
+
length = length.to_i
|
106
|
+
check_length(length)
|
107
|
+
|
108
|
+
details = {
|
109
|
+
nBits: length,
|
110
|
+
tautomericFingerprint: tautomeric
|
111
|
+
}
|
112
|
+
check_string(FFI.get_pattern_fp(@ptr, @sz, to_details(details)))
|
113
|
+
end
|
114
|
+
|
115
|
+
def topological_torsion_fingerprint(length: 2048)
|
116
|
+
length = length.to_i
|
117
|
+
check_length(length)
|
118
|
+
|
119
|
+
details = {
|
120
|
+
nBits: length
|
121
|
+
}
|
122
|
+
check_string(FFI.get_topological_torsion_fp(@ptr, @sz, to_details(details)))
|
123
|
+
end
|
124
|
+
|
125
|
+
def atom_pair_fingerprint(length: 2048, min_length: 1, max_length: 30)
|
126
|
+
length = length.to_i
|
127
|
+
check_length(length)
|
128
|
+
|
129
|
+
details = {
|
130
|
+
nBits: length,
|
131
|
+
minLength: min_length.to_i,
|
132
|
+
maxLength: max_length.to_i
|
133
|
+
}
|
134
|
+
check_string(FFI.get_atom_pair_fp(@ptr, @sz, to_details(details)))
|
135
|
+
end
|
136
|
+
|
137
|
+
def maccs_fingerprint
|
138
|
+
# remove bit 0 for correct length
|
139
|
+
# https://github.com/rdkit/rdkit/issues/1726
|
140
|
+
check_string(FFI.get_maccs_fp(@ptr, @sz))[1..]
|
141
|
+
end
|
142
|
+
|
143
|
+
def add_hs
|
144
|
+
dup.add_hs!
|
145
|
+
end
|
146
|
+
|
147
|
+
def add_hs!
|
148
|
+
check_status(FFI.add_hs(@ptr.ref, @sz.ref))
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
def remove_hs
|
153
|
+
dup.remove_hs!
|
154
|
+
end
|
155
|
+
|
156
|
+
def remove_hs!
|
157
|
+
check_status(FFI.remove_all_hs(@ptr.ref, @sz.ref))
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
def cleanup
|
162
|
+
dup.cleanup!
|
163
|
+
end
|
164
|
+
|
165
|
+
def cleanup!
|
166
|
+
check_status(FFI.cleanup(@ptr.ref, @sz.ref, to_details({})))
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
def normalize
|
171
|
+
dup.normalize!
|
172
|
+
end
|
173
|
+
|
174
|
+
def normalize!
|
175
|
+
check_status(FFI.normalize(@ptr.ref, @sz.ref, to_details({})))
|
176
|
+
self
|
177
|
+
end
|
178
|
+
|
179
|
+
def neutralize
|
180
|
+
dup.neutralize!
|
181
|
+
end
|
182
|
+
|
183
|
+
def neutralize!
|
184
|
+
check_status(FFI.neutralize(@ptr.ref, @sz.ref, to_details({})))
|
185
|
+
self
|
186
|
+
end
|
187
|
+
|
188
|
+
def reionize
|
189
|
+
dup.reionize!
|
190
|
+
end
|
191
|
+
|
192
|
+
def reionize!
|
193
|
+
check_status(FFI.reionize(@ptr.ref, @sz.ref, to_details({})))
|
194
|
+
self
|
195
|
+
end
|
196
|
+
|
197
|
+
def canonical_tautomer
|
198
|
+
dup.canonical_tautomer!
|
199
|
+
end
|
200
|
+
|
201
|
+
def canonical_tautomer!
|
202
|
+
check_status(FFI.canonical_tautomer(@ptr.ref, @sz.ref, to_details({})))
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
def charge_parent
|
207
|
+
dup.charge_parent!
|
208
|
+
end
|
209
|
+
|
210
|
+
def charge_parent!
|
211
|
+
check_status(FFI.charge_parent(@ptr.ref, @sz.ref, to_details({})))
|
212
|
+
self
|
213
|
+
end
|
214
|
+
|
215
|
+
def fragment_parent
|
216
|
+
dup.fragment_parent!
|
217
|
+
end
|
218
|
+
|
219
|
+
def fragment_parent!
|
220
|
+
check_status(FFI.fragment_parent(@ptr.ref, @sz.ref, to_details({})))
|
221
|
+
self
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_smiles
|
225
|
+
check_string(FFI.get_smiles(@ptr, @sz, to_details({})))
|
226
|
+
end
|
227
|
+
|
228
|
+
def to_smarts
|
229
|
+
check_string(FFI.get_smarts(@ptr, @sz, to_details({})))
|
230
|
+
end
|
231
|
+
|
232
|
+
def to_cxsmiles
|
233
|
+
check_string(FFI.get_cxsmiles(@ptr, @sz, to_details({})))
|
234
|
+
end
|
235
|
+
|
236
|
+
def to_cxsmarts
|
237
|
+
check_string(FFI.get_cxsmarts(@ptr, @sz, to_details({})))
|
238
|
+
end
|
239
|
+
|
240
|
+
def to_json
|
241
|
+
check_string(FFI.get_json(@ptr, @sz, to_details({})))
|
242
|
+
end
|
243
|
+
|
244
|
+
def to_svg(width: 250, height: 200)
|
245
|
+
details = {
|
246
|
+
width: width,
|
247
|
+
height: height
|
248
|
+
}
|
249
|
+
check_string(FFI.get_svg(@ptr, @sz, to_details(details)))
|
250
|
+
end
|
251
|
+
|
252
|
+
def to_s
|
253
|
+
"#<#{self.class.name} #{to_smiles}>"
|
254
|
+
end
|
255
|
+
alias_method :inspect, :to_s
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def initialize_copy(other)
|
260
|
+
super
|
261
|
+
load_smiles(other.to_smiles, sanitize: false, kekulize: false, remove_hs: false)
|
262
|
+
end
|
263
|
+
|
264
|
+
def load_smiles(input, sanitize: true, kekulize: true, remove_hs: true)
|
265
|
+
sz = Fiddle::Pointer.malloc(Fiddle::SIZEOF_SIZE_T)
|
266
|
+
details = {
|
267
|
+
sanitize: sanitize,
|
268
|
+
kekulize: kekulize,
|
269
|
+
removeHs: remove_hs
|
270
|
+
}
|
271
|
+
ptr = FFI.get_mol(input.to_str, sz.ref, to_details(details))
|
272
|
+
load_ptr(ptr, sz)
|
273
|
+
end
|
274
|
+
|
275
|
+
def load_smarts(input)
|
276
|
+
sz = Fiddle::Pointer.malloc(Fiddle::SIZEOF_SIZE_T)
|
277
|
+
ptr = FFI.get_qmol(input.to_str, sz.ref, to_details({}))
|
278
|
+
load_ptr(ptr, sz)
|
279
|
+
end
|
280
|
+
|
281
|
+
def load_ptr(ptr, sz)
|
282
|
+
if ptr.null?
|
283
|
+
raise ArgumentError, "invalid input"
|
284
|
+
end
|
285
|
+
|
286
|
+
@ptr = ptr
|
287
|
+
@ptr.free = FFI::FREE
|
288
|
+
@sz = sz
|
289
|
+
end
|
290
|
+
|
291
|
+
def to_details(options)
|
292
|
+
JSON.generate(options)
|
293
|
+
end
|
294
|
+
|
295
|
+
def json_data
|
296
|
+
JSON.parse(to_json)
|
297
|
+
end
|
298
|
+
|
299
|
+
def descriptors
|
300
|
+
JSON.parse(check_string(FFI.get_descriptors(@ptr, @sz)))
|
301
|
+
end
|
302
|
+
|
303
|
+
def check_pattern(pattern)
|
304
|
+
unless pattern.is_a?(self.class)
|
305
|
+
raise ArgumentError, "expected #{self.class.name}"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def check_length(length)
|
310
|
+
if length < 1
|
311
|
+
raise ArgumentError, "length must be greater than 0"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def check_ptr(ptr)
|
316
|
+
if ptr.nil? || ptr.null?
|
317
|
+
raise Error, "bad pointer"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def free_ptr(ptr)
|
322
|
+
FFI.free_ptr(ptr) if ptr
|
323
|
+
end
|
324
|
+
|
325
|
+
def check_string(ptr)
|
326
|
+
check_ptr(ptr)
|
327
|
+
begin
|
328
|
+
ptr.to_s
|
329
|
+
ensure
|
330
|
+
free_ptr(ptr)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def check_status(status)
|
335
|
+
if status != 1
|
336
|
+
raise Error, "bad status: #{status}"
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RDKit
|
2
|
+
class Reaction
|
3
|
+
private_class_method :new
|
4
|
+
|
5
|
+
def self.from_smarts(input)
|
6
|
+
rxn = allocate
|
7
|
+
rxn.send(:load_rxn, input)
|
8
|
+
rxn
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_svg(width: 250, height: 200)
|
12
|
+
details = {
|
13
|
+
width: width,
|
14
|
+
height: height
|
15
|
+
}
|
16
|
+
check_string(FFI.get_rxn_svg(@ptr, @sz, to_details(details)))
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#<#{self.class.name} #{@input}>"
|
21
|
+
end
|
22
|
+
alias_method :inspect, :to_s
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def load_rxn(input)
|
27
|
+
sz = Fiddle::Pointer.malloc(Fiddle::SIZEOF_SIZE_T)
|
28
|
+
@input = input.to_str
|
29
|
+
ptr = FFI.get_rxn(@input, sz.ref, to_details({}))
|
30
|
+
load_ptr(ptr, sz)
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_ptr(ptr, sz)
|
34
|
+
if ptr.null?
|
35
|
+
raise ArgumentError, "invalid input"
|
36
|
+
end
|
37
|
+
|
38
|
+
@ptr = ptr
|
39
|
+
@ptr.free = FFI::FREE
|
40
|
+
@sz = sz
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_details(options)
|
44
|
+
JSON.generate(options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def check_ptr(ptr)
|
48
|
+
if ptr.nil? || ptr.null?
|
49
|
+
raise Error, "bad pointer"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def free_ptr(ptr)
|
54
|
+
FFI.free_ptr(ptr) if ptr
|
55
|
+
end
|
56
|
+
|
57
|
+
def check_string(ptr)
|
58
|
+
check_ptr(ptr)
|
59
|
+
begin
|
60
|
+
ptr.to_s
|
61
|
+
ensure
|
62
|
+
free_ptr(ptr)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|