1 // Copyright (c) 2019 Brian P Kelley
2 // All rights reserved.
3 //
4 // This file is part of the RDKit.
5 // The contents are covered by the terms of the BSD license
6 // which is included in the file license.txt, found at the root
7 // of the RDKit source tree.
8 //
9
10 #include "FilterCatalog.h"
11 #include "Filters.h"
12 #include "FilterMatchers.h"
13 #include <GraphMol/SmilesParse/SmilesParse.h>
14
15 #ifdef RDK_THREADSAFE_SSS
16 #include <RDGeneral/RDThreads.h>
17 #include <thread>
18 #include <future>
19 #endif
20
21 namespace RDKit {
22 namespace {
makeBadSmilesEntry()23 boost::shared_ptr<FilterCatalogEntry> & makeBadSmilesEntry() {
24 static boost::shared_ptr<FilterCatalogEntry> bad_smiles(
25 new FilterCatalogEntry("no valid RDKit molecule",
26 boost::shared_ptr<FilterMatcherBase>()));
27 return bad_smiles;
28 }
CatalogSearcher(const FilterCatalog & fc,const std::vector<std::string> & smiles,std::vector<std::vector<FilterCatalog::CONST_SENTRY>> & results,int start,int numThreads)29 void CatalogSearcher(const FilterCatalog &fc,
30 const std::vector<std::string> &smiles,
31 std::vector<std::vector<FilterCatalog::CONST_SENTRY>> &results,
32 int start,
33 int numThreads) {
34 for(unsigned int idx = start;
35 idx < smiles.size();
36 idx += numThreads) {
37 std::unique_ptr<ROMol> mol(SmilesToMol(smiles[idx]));
38 if(mol.get()) {
39 results[idx] = fc.getMatches(*mol);
40 } else {
41 results[idx].push_back( makeBadSmilesEntry() );
42 }
43 }
44 }
45 }
46
RunFilterCatalog(const FilterCatalog & fc,const std::vector<std::string> & smiles,int numThreads)47 std::vector<std::vector<boost::shared_ptr<const FilterCatalogEntry>>> RunFilterCatalog(
48 const FilterCatalog &fc,
49 const std::vector<std::string> &smiles,
50 int numThreads) {
51 // preallocate results so the threads don't move the vector around in memory
52 // There is one result per input smiles
53 std::vector<std::vector<FilterCatalog::CONST_SENTRY>> results(smiles.size());
54
55 #ifdef RDK_THREADSAFE_SSS
56 if (numThreads == -1) {
57 numThreads = (int)getNumThreadsToUse(numThreads);
58 } else {
59 numThreads = std::min(numThreads, (int)getNumThreadsToUse(numThreads));
60 }
61
62 std::vector<std::future<void>> thread_group;
63 for (int thread_group_idx = 0; thread_group_idx < numThreads+1;
64 ++thread_group_idx) {
65 // need to use std::ref otherwise things are passed by value
66 thread_group.emplace_back(
67 std::async(std::launch::async, CatalogSearcher,
68 std::ref(fc),
69 std::ref(smiles),
70 std::ref(results),
71 thread_group_idx,
72 numThreads));
73 }
74 for (auto &fut : thread_group) {
75 fut.get();
76 }
77
78 #else
79 int start = 0;
80 numThreads = 1;
81 CatalogSearcher(fc, smiles, results, start, numThreads);
82 #endif
83 return results;
84 }
85
86 }
87