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