OSCR

Targeting BCL-2 through Deep Learning-Based Drug Repurposing: A Multimodal Approach Combining Diffusion-Based Generative Modeling, Neural Relational Inference, and In Vitro Validation.

Code ↔ Paper

1 match between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 1 match
  1. [1] § Methods › Chemprop Model Development for pIC50 Prediction ↔ wt/main.py, lines 1–86 · score 0.64 · random seed, trained model, hidden, batch, graph, predict

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 482 lines · 20 KB · MIT · 1 match

  1. import time
  2. import argparse
  3. import pickle
  4. import os
  5. import datetime
  6. import torch
  7. import torch.optim as optim
  8. from torch.optim import lr_scheduler
  9. from utils import *
  10. from modules import *
  11. import copy
  12. import os
  13. parser = argparse.ArgumentParser(
  14. 'Neral relational inference for molecular dynamics simulations')
  15. parser.add_argument('--num-residues', type=int, default=352,
  16. help='Number of residues of the PDB.')
  17. parser.add_argument('--save-folder', type=str, default='logs',
  18. help='Where to save the trained model, leave empty to not save anything.')
  19. parser.add_argument('--load-folder', type=str, default='',
  20. help='Where to load the trained model if finetunning. ' +
  21. 'Leave empty to train from scratch')
  22. parser.add_argument('--edge-types', type=int, default=4,
  23. help='The number of edge types to infer.')
  24. parser.add_argument('--dims', type=int, default=6,
  25. help='The number of input dimensions used in study( position (X,Y,Z) + velocity (X,Y,Z) ). ')
  26. parser.add_argument('--timesteps', type=int, default=20,
  27. help='The number of time steps per sample. Actually is 50')
  28. parser.add_argument('--prediction-steps', type=int, default=1, metavar='N',
  29. help='Num steps to predict before re-using teacher forcing.')
  30. parser.add_argument('--no-cuda', action='store_true', default=False,
  31. help='Disables CUDA training.')
  32. parser.add_argument('--seed', type=int, default=42, help='Random seed.')
  33. parser.add_argument('--epochs', type=int, default=1000,
  34. help='Number of epochs to train.')
  35. parser.add_argument('--batch-size', type=int, default=1,
  36. help='Number of samples per batch.')
  37. parser.add_argument('--lr', type=float, default=0.0005,
  38. help='Initial learning rate.')
  39. parser.add_argument('--encoder-hidden', type=int, default=16,
  40. help='Number of hidden units in encoder.')
  41. parser.add_argument('--decoder-hidden', type=int, default=16,
  42. help='Number of hidden units in decoder.')
  43. parser.add_argument('--temp', type=float, default=0.5,
  44. help='Temperature for Gumbel softmax.')
  45. parser.add_argument('--encoder', type=str, default='mlp',
  46. help='Type of path encoder model (mlp or cnn).')
  47. parser.add_argument('--decoder', type=str, default='rnn',
  48. help='Type of decoder model (mlp, rnn, or sim).')
  49. parser.add_argument('--no-factor', action='store_true', default=False,
  50. help='Disables factor graph model.')
  51. parser.add_argument('--encoder-dropout', type=float, default=0.0,
  52. help='Dropout rate (1 - keep probability) in encoder.')
  53. parser.add_argument('--decoder-dropout', type=float, default=0.0,
  54. help='Dropout rate (1 - keep probability) in decoder.')
  55. parser.add_argument('--lr-decay', type=int, default=200,
  56. help='After how epochs to decay LR by a factor of gamma.')
  57. parser.add_argument('--gamma', type=float, default=0.5,
  58. help='LR decay factor.')
  59. parser.add_argument('--skip-first', action='store_true', default=True,
  60. help='Skip first edge type in decoder, i.e. it represents no-edge.')
  61. parser.add_argument('--var', type=float, default=5e-5,
  62. help='Output variance.')
  63. parser.add_argument('--hard', action='store_true', default=True,
  64. help='Uses discrete samples in training forward pass.')
  65. parser.add_argument('--prior', action='store_true', default=True,
  66. help='Whether to use sparsity prior.')
  67. parser.add_argument('--dynamic-graph', action='store_true', default=True,
  68. help='Whether test with dynamically re-computed graph.')
  69. parser.add_argument('--number-expstart', type=int, default=0,
  70. help='start number of experiments.')
  71. parser.add_argument('--number-exp', type=int, default=100,
  72. help='number of experiments.')
  73. args = parser.parse_args()
  74. args.cuda = not args.no_cuda and torch.cuda.is_available()
  75. args.factor = not args.no_factor
  76. # print all arguments
  77. print(args)
  78. np.random.seed(args.seed)
  79. torch.manual_seed(args.seed)
  80. if args.cuda:
  81. torch.cuda.manual_seed(args.seed)
  82. if args.dynamic_graph:
  83. print("Testing with dynamically re-computed graph.")
  84. # Save model and meta-data. Always saves in a new sub-folder.
  85. if args.save_folder:
  86. exp_counter = 0
  87. now = datetime.datetime.now()
  88. timestamp = now.isoformat()
  89. save_folder = args.save_folder+'/'
  90. if not os.path.isdir(save_folder):
  91. os.mkdir(save_folder)
  92. meta_file = os.path.join(save_folder, 'metadata.pkl')
  93. encoder_file = os.path.join(save_folder, 'encoder.pt')
  94. decoder_file = os.path.join(save_folder, 'decoder.pt')
  95. encoder_file_train = os.path.join(save_folder, 'encoder_train.pt')
  96. decoder_file_train = os.path.join(save_folder, 'decoder_train.pt')
  97. log_file = os.path.join(save_folder, 'log.txt')
  98. log = open(log_file, 'w')
  99. pickle.dump({'args': args}, open(meta_file, "wb"))
  100. log_file_train = os.path.join(save_folder, 'log_train.txt')
  101. log_train = open(log_file_train, 'w')
  102. else:
  103. print("WARNING: No save_folder provided!" +
  104. "Testing (within this script) will throw an error.")
  105. # load data
  106. train_loader, valid_loader, test_loader, loc_max, loc_min, vel_max, vel_min = load_dataset_train_valid_test(
  107. args.batch_size, args.number_exp, args.number_expstart, args.dims)
  108. # Generate off-diagonal interaction graph
  109. off_diag = np.ones([args.num_residues, args.num_residues]
  110. ) - np.eye(args.num_residues)
  111. rel_rec = np.array(encode_onehot(np.where(off_diag)[1]), dtype=np.float32)
  112. rel_send = np.array(encode_onehot(np.where(off_diag)[0]), dtype=np.float32)
  113. rel_rec = torch.FloatTensor(rel_rec)
  114. rel_send = torch.FloatTensor(rel_send)
  115. if args.encoder == 'mlp':
  116. encoder = MLPEncoder(args.timesteps * args.dims, args.encoder_hidden,
  117. args.edge_types,
  118. args.encoder_dropout, args.factor)
  119. elif args.encoder == 'cnn':
  120. encoder = CNNEncoder(args.dims, args.encoder_hidden,
  121. args.edge_types,
  122. args.encoder_dropout, args.factor)
  123. if args.decoder == 'mlp':
  124. decoder = MLPDecoder(n_in_node=args.dims,
  125. edge_types=args.edge_types,
  126. msg_hid=args.decoder_hidden,
  127. msg_out=args.decoder_hidden,
  128. n_hid=args.decoder_hidden,
  129. do_prob=args.decoder_dropout,
  130. skip_first=args.skip_first)
  131. elif args.decoder == 'rnn':
  132. decoder = RNNDecoder(n_in_node=args.dims,
  133. edge_types=args.edge_types,
  134. n_hid=args.decoder_hidden,
  135. do_prob=args.decoder_dropout,
  136. skip_first=args.skip_first)
  137. elif args.decoder == 'sim':
  138. decoder = SimulationDecoder(
  139. loc_max, loc_min, vel_max, vel_min, args.suffix)
  140. if args.load_folder:
  141. encoder_file = os.path.join('/media/arma/DATA/S-Ehsan/NRI_HITMER/wt/logs', 'encoder.pt')
  142. encoder.load_state_dict(torch.load(encoder_file))
  143. decoder_file = os.path.join(args.load_folder, 'decoder.pt')
  144. decoder.load_state_dict(torch.load(decoder_file))
  145. args.save_folder = False
  146. """
  147. encoder_file ='logs/encoder_train.pt'
  148. encoder.load_state_dict(torch.load(encoder_file))
  149. decoder_file = 'logs/decoder_train.pt'
  150. decoder.load_state_dict(torch.load(decoder_file))
  151. """
  152. optimizer = optim.Adam(list(encoder.parameters()) + list(decoder.parameters()),
  153. lr=args.lr)
  154. scheduler = lr_scheduler.StepLR(optimizer, step_size=args.lr_decay,
  155. gamma=args.gamma)
  156. # Linear indices of an upper triangular mx, used for acc calculation
  157. triu_indices = get_triu_offdiag_indices(args.num_residues)
  158. tril_indices = get_tril_offdiag_indices(args.num_residues)
  159. if args.prior:
  160. prior = np.array([0.91, 0.03, 0.03, 0.03]) # TODO: hard coded for now
  161. print("Using prior")
  162. print(prior)
  163. log_prior = torch.FloatTensor(np.log(prior))
  164. log_prior = torch.unsqueeze(log_prior, 0)
  165. log_prior = torch.unsqueeze(log_prior, 0)
  166. log_prior = Variable(log_prior)
  167. if args.cuda:
  168. log_prior = log_prior.cuda()
  169. if args.cuda:
  170. encoder.cuda()
  171. decoder.cuda()
  172. rel_rec = rel_rec.cuda()
  173. rel_send = rel_send.cuda()
  174. triu_indices = triu_indices.cuda()
  175. tril_indices = tril_indices.cuda()
  176. rel_rec = Variable(rel_rec)
  177. rel_send = Variable(rel_send)
  178. from time import process_time
  179. def train(epoch, best_val_loss,epochc):
  180. t = time.time()
  181. nll_train = []
  182. acc_train = []
  183. kl_train = []
  184. mse_train = []
  185. edges_train = []
  186. probs_train = []
  187. encoder.train()
  188. decoder.train()
  189. for batch_idx, (data, relations) in enumerate(train_loader):
  190. print(batch_idx)
  191. t1_start = process_time()
  192. if args.cuda:
  193. data, relations = data.cuda(), relations.cuda()
  194. data, relations = Variable(data), Variable(relations)
  195. optimizer.zero_grad()
  196. logits = encoder(data, rel_rec, rel_send)
  197. edges = gumbel_softmax(logits, tau=args.temp, hard=args.hard)
  198. prob = my_softmax(logits, -1)
  199. if args.decoder == 'rnn':
  200. output = decoder(data, edges, rel_rec, rel_send, 20,
  201. burn_in=True,
  202. burn_in_steps=args.timesteps - args.prediction_steps)
  203. else:
  204. output = decoder(data, edges, rel_rec, rel_send,
  205. args.prediction_steps)
  206. target = data[:, :, 1:, :]
  207. loss_nll = nll_gaussian(output, target, args.var)
  208. if args.prior:
  209. loss_kl = kl_categorical(prob, log_prior, args.num_residues)
  210. else:
  211. loss_kl = kl_categorical_uniform(prob, args.num_residues,
  212. args.edge_types)
  213. loss = loss_nll + loss_kl
  214. acc = edge_accuracy(logits, relations)
  215. acc_train.append(acc)
  216. loss.backward()
  217. optimizer.step()
  218. mse_train.append(F.mse_loss(output, target).item())
  219. nll_train.append(loss_nll.item())
  220. kl_train.append(loss_kl.item())
  221. _, edges_t = edges.max(-1)
  222. edges_train.append(edges_t.data.cpu().numpy())
  223. probs_train.append(prob.data.cpu().numpy())
  224. t1_stop = process_time()
  225. print("Elapsed time during the whole program in seconds:",
  226. t1_stop-t1_start)
  227. scheduler.step()
  228. nll_val = []
  229. acc_val = []
  230. kl_val = []
  231. mse_val = []
  232. encoder.eval()
  233. decoder.eval()
  234. if epochc%10==0:
  235. for batch_idx, (data, relations) in enumerate(valid_loader):
  236. if args.cuda:
  237. data, relations = data.cuda(), relations.cuda()
  238. with torch.no_grad():
  239. logits = encoder(data, rel_rec, rel_send)
  240. edges = gumbel_softmax(logits, tau=args.temp, hard=True)
  241. prob = my_softmax(logits, -1)
  242. # validation output uses teacher forcing
  243. output = decoder(data, edges, rel_rec, rel_send, 1)
  244. target = data[:, :, 1:, :]
  245. loss_nll = nll_gaussian(output, target, args.var)
  246. loss_kl = kl_categorical_uniform(
  247. prob, args.num_residues, args.edge_types)
  248. acc = edge_accuracy(logits, relations)
  249. acc_val.append(acc)
  250. mse_val.append(F.mse_loss(output, target).item())
  251. nll_val.append(loss_nll.item())
  252. kl_val.append(loss_kl.item())
  253. if args.save_folder and np.mean(np.array(nll_val)) < best_val_loss:
  254. torch.save(encoder.state_dict(), encoder_file)
  255. torch.save(decoder.state_dict(), decoder_file)
  256. print('Best model so far, saving...')
  257. print('Epoch: {:04d}'.format(epoch),
  258. 'nll_train: {:.10f}'.format(np.mean(np.array(nll_train))),
  259. 'kl_train: {:.10f}'.format(np.mean(np.array(kl_train))),
  260. 'mse_train: {:.10f}'.format(np.mean(np.array(mse_train))),
  261. 'acc_train: {:.10f}'.format(np.mean(np.array(acc_train))),
  262. 'nll_val: {:.10f}'.format(np.mean(np.array(nll_val))),
  263. 'kl_val: {:.10f}'.format(np.mean(np.array(kl_val))),
  264. 'mse_val: {:.10f}'.format(np.mean(np.array(mse_val))),
  265. 'acc_val: {:.10f}'.format(np.mean(np.array(acc_val))),
  266. 'time: {:.4f}s'.format(time.time() - t), file=log)
  267. log.flush()
  268. print('Epoch: {:04d}'.format(epoch),
  269. 'nll_train: {:.10f}'.format(np.mean(np.array(nll_train))),
  270. 'kl_train: {:.10f}'.format(np.mean(np.array(kl_train))),
  271. 'mse_train: {:.10f}'.format(np.mean(np.array(mse_train))),
  272. 'acc_train: {:.10f}'.format(np.mean(np.array(acc_train))),
  273. 'nll_val: {:.10f}'.format(np.mean(np.array(nll_val))),
  274. 'kl_val: {:.10f}'.format(np.mean(np.array(kl_val))),
  275. 'mse_val: {:.10f}'.format(np.mean(np.array(mse_val))),
  276. 'acc_val: {:.10f}'.format(np.mean(np.array(acc_val))),
  277. 'time: {:.4f}s'.format(time.time() - t))
  278. edges_train = np.concatenate(edges_train)
  279. probs_train = np.concatenate(probs_train)
  280. print('Epoch: {:04d}'.format(epoch),
  281. 'nll_train: {:.10f}'.format(np.mean(np.array(nll_train))),
  282. 'kl_train: {:.10f}'.format(np.mean(np.array(kl_train))),
  283. 'mse_train: {:.10f}'.format(np.mean(np.array(mse_train))),
  284. 'acc_train: {:.10f}'.format(np.mean(np.array(acc_train))),
  285. 'nll_val: {:.10f}'.format(np.mean(np.array(nll_val))),
  286. 'kl_val: {:.10f}'.format(np.mean(np.array(kl_val))),
  287. 'mse_val: {:.10f}'.format(np.mean(np.array(mse_val))),
  288. 'acc_val: {:.10f}'.format(np.mean(np.array(acc_val))),
  289. 'time: {:.4f}s'.format(time.time() - t), file=log_train)
  290. log_train.flush()
  291. torch.save(encoder.state_dict(), encoder_file_train)
  292. torch.save(decoder.state_dict(), decoder_file_train)
  293. return encoder, decoder, edges_train, probs_train, np.mean(np.array(nll_val))
  294. def test():
  295. acc_test = []
  296. nll_test = []
  297. kl_test = []
  298. mse_test = []
  299. edges_test = []
  300. probs_test = []
  301. tot_mse = 0
  302. counter = 0
  303. encoder.eval()
  304. decoder.eval()
  305. encoder.load_state_dict(torch.load(encoder_file))
  306. decoder.load_state_dict(torch.load(decoder_file))
  307. for batch_idx, (data, relations) in enumerate(test_loader):
  308. if args.cuda:
  309. data, relations = data.cuda(), relations.cuda()
  310. with torch.no_grad():
  311. # assert (data.size(2) - args.timesteps) >= args.timesteps
  312. assert (data.size(2)) >= args.timesteps
  313. data_encoder = data[:, :, :args.timesteps, :].contiguous()
  314. data_decoder = data[:, :, -args.timesteps:, :].contiguous()
  315. logits = encoder(data_encoder, rel_rec, rel_send)
  316. edges = gumbel_softmax(logits, tau=args.temp, hard=True)
  317. prob = my_softmax(logits, -1)
  318. output = decoder(data_decoder, edges, rel_rec, rel_send, 1)
  319. target = data_decoder[:, :, 1:, :]
  320. loss_nll = nll_gaussian(output, target, args.var)
  321. loss_kl = kl_categorical_uniform(
  322. prob, args.num_residues, args.edge_types)
  323. acc = edge_accuracy(logits, relations)
  324. acc_test.append(acc)
  325. mse_test.append(F.mse_loss(output, target).item())
  326. nll_test.append(loss_nll.item())
  327. kl_test.append(loss_kl.item())
  328. _, edges_t = edges.max(-1)
  329. edges_test.append(edges_t.data.cpu().numpy())
  330. probs_test.append(prob.data.cpu().numpy())
  331. # For plotting purposes
  332. if args.decoder == 'rnn':
  333. if args.dynamic_graph:
  334. output = decoder(data, edges, rel_rec, rel_send, 20,
  335. burn_in=False, burn_in_steps=args.timesteps,
  336. dynamic_graph=True, encoder=encoder,
  337. temp=args.temp)
  338. else:
  339. output = decoder(data, edges, rel_rec, rel_send, 20,
  340. burn_in=True, burn_in_steps=args.timesteps)
  341. target = data[:, :, 1:, :]
  342. else:
  343. data_plot = data[:, :, 0:0 + 21,
  344. :].contiguous()
  345. output = decoder(data_plot, edges, rel_rec, rel_send, 20)
  346. target = data_plot[:, :, 1:, :]
  347. mse = ((target - output) ** 2).mean(dim=0).mean(dim=0).mean(dim=-1)
  348. tot_mse += mse.data.cpu().numpy()
  349. counter += 1
  350. mean_mse = tot_mse / counter
  351. mse_str = '['
  352. for mse_step in mean_mse[:-1]:
  353. mse_str += " {:.12f} ,".format(mse_step)
  354. mse_str += " {:.12f} ".format(mean_mse[-1])
  355. mse_str += ']'
  356. print('--------------------------------')
  357. print('--------Testing-----------------')
  358. print('--------------------------------')
  359. print('nll_test: {:.10f}'.format(np.mean(nll_test)),
  360. 'kl_test: {:.10f}'.format(np.mean(kl_test)),
  361. 'mse_test: {:.10f}'.format(np.mean(mse_test)),
  362. 'acc_test: {:.10f}'.format(np.mean(acc_test)))
  363. print('MSE: {}'.format(mse_str))
  364. edges_test = np.concatenate(edges_test)
  365. probs_test = np.concatenate(probs_test)
  366. if args.save_folder:
  367. print('--------------------------------', file=log)
  368. print('--------Testing-----------------', file=log)
  369. print('--------------------------------', file=log)
  370. print('nll_test: {:.10f}'.format(np.mean(nll_test)),
  371. 'kl_test: {:.10f}'.format(np.mean(kl_test)),
  372. 'mse_test: {:.10f}'.format(np.mean(mse_test)),
  373. 'acc_test: {:.10f}'.format(np.mean(acc_test)),
  374. file=log)
  375. print('MSE: {}'.format(mse_str), file=log)
  376. log.flush()
  377. return edges_test, probs_test
  378. # Train model
  379. print("Start Training...")
  380. t_total = time.time()
  381. best_val_loss = np.inf
  382. best_epoch = 0
  383. for epoch in range(args.epochs):
  384. """
  385. if epoch==0:
  386. best_enc_wts = copy.deepcopy(encoder.state_dict())
  387. best_dec_wts = copy.deepcopy(decoder.state_dict())
  388. """
  389. encoder, decoder, edges_train, probs_train, val_loss = train(
  390. epoch, best_val_loss,epoch)
  391. # print('Epoch '+str(epoch)+' with val loss:'+str(val_loss))
  392. np.save(str(args.save_folder)+'/out_edges_train.npy', edges_train)
  393. np.save(str(args.save_folder)+'/out_probs_train.npy', probs_train)
  394. if val_loss < best_val_loss:
  395. best_val_loss = val_loss
  396. best_epoch = epoch
  397. best_enc_wts = copy.deepcopy(encoder.state_dict())
  398. best_dec_wts = copy.deepcopy(decoder.state_dict())
  399. np.save(str(args.save_folder)+'/out_edges_val.npy', edges_train)
  400. np.save(str(args.save_folder)+'/out_probs_val.npy', probs_train)
  401. """
  402. encoder.load_state_dict(best_enc_wts)
  403. decoder.load_state_dict(best_dec_wts)
  404. """
  405. np.save(str(args.save_folder)+'/out_edges_train.npy', edges_train)
  406. np.save(str(args.save_folder)+'/out_probs_train.npy', probs_train)
  407. print("Optimization Finished!")
  408. print("Best Epoch: {:04d}".format(best_epoch))
  409. if args.save_folder:
  410. print("Best Epoch: {:04d}".format(best_epoch), file=log)
  411. log.flush()
  412. # Test
  413. edges_test, probs_test = test()
  414. if log is not None:
  415. print(save_folder)
  416. log.close()

main.py at commit 6b4f7bd, under MIT · at the source

Overview

Authors: Ehsan Sayyah1, Hüseyin Tunç2, Asuman Çelebi3, Timuçin Avşar3, Serdar Durdağı1,4,5
  1. Lab for Innovative Drugs (Lab4IND), Computational Drug Design Center (HİTMER), Bahçeşehir University, İstanbul 34349, Türkiye
  2. Department of Biostatistics and Medical Informatics, School of Medicine, Bahçeşehir University, Istanbul 34349, Türkiye
  3. Department of Medical Biology, School of Medicine, Bahçeşehir University, Istanbul 34349, Türkiye
  4. Molecular Therapy Lab, Department of Pharmaceutical Chemistry, School of Pharmacy, Bahçeşehir University, Istanbul 34353, Türkiye
  5. Quantitative System Biology Lab, Faculty of Medicine, Biruni University, İstanbul 34010, Türkiye
Institutions: Bahçeşehir University (Türkiye); Biruni University (Türkiye)
Journal: Journal of chemical information and modeling, volume 66, issue 17, pages 11361-11376
Dates: received 25 April 2026; accepted 7 July 2026; published online 14 August 2026; in print September 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1021/acs.jcim.6c01299 · PMID 42734502 · PMCID PMC13580121 · OpenAlex W7203477433
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: computational modeling (no new data) (modality), human (organism), other condition (population), cellular / molecular (subfield)
Methods: Connectivity, Machine learning, Statistics
MeSH: Antineoplastic Agents*, Deep Learning*, Drug Repositioning*, Proto-Oncogene Proteins c-bcl-2*, Cell Line, Tumor, Diffusion, Humans, Ligands, Molecular Docking Simulation, Molecular Dynamics Simulation, Quantitative Structure-Activity Relationship (* major topic)
Topic: Computational Drug Discovery Methods (Computational Theory and Mathematics, Computer Science), according to OpenAlex
Funding: Bah?esehir ?niversitesi (BAP.2024-01.42, BAP.2022-02.59); Istanbul Kalkinma Ajansi (TR10/21/YEP/0133)
Citations: not cited yet (Europe PMC); 33 references in the paper

Abstract

Accurate identification of repurposable BCL-2 ligands requires not only plausible bound complex structures but also a dynamic description of how ligand binding reshapes residue-level communication. Here, we present a multimodal BCL-2 repurposing workflow built with diffusion-based generative modeling for ligand-specific complex generation and an extended neural relational inference (NRI) framework for trajectory-level interaction analysis. NeuralPlexer was applied to a library of 3094 FDA-approved drugs to generate BCL-2-ligand complex conformations at scale, yielding 1294 structurally acceptable complexes for downstream prioritization. To complement static scoring, filtered candidates were evaluated by molecular docking, anticancer QSAR classification, all-atom molecular dynamics (MD) simulations, and MM/GBSA binding free-energy calculations. We then extended NRI to protein–ligand trajectories to quantify residue-ligand and residue–residue dynamic couplings, enabling comparison of candidate-specific interaction signatures against the reference BCL-2 inhibitor Venetoclax. Among the prioritized compounds, Relugolix emerged as one of the most compelling hits, combining favorable binding energetics with an NRI-derived interaction pattern closely resembling that of Venetoclax. In vitro experiments supported BCL-2 inhibition by Relugolix in a TR-FRET assay and reduced viability of LN-18 glioma cells (IC50 = 23.55 μM). Together, these results establish a strategy that couples generative complex prediction with graph-based dynamic inference for structure-guided drug repurposing and identify Relugolix as a tractable scaffold for future BCL-2 inhibitor design.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 1 match between paragraphs and lines of code.

DurdagiLab/Neuralplexer_Ligand_Scoring

License: MIT
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: 7057748744fc580fa1fc1052a26bff7649769409, 18 July 2024
Languages: Python (2)
Size: 4 files, 2 scripts
Software Heritage: not archived
Found in: the text, “Glide-Based Pose Refinement and Binding Score Es”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (2 files), RDKit (2 files)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
4 files

DurdagiLab/Automate-Neural-relational-inference-NRI-

License: MIT
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: 6b4f7bd16cba9fb8e963d11e2aafc2a42d96f597, 18 July 2024
Languages: Python (11)
Size: 31 files, 11 scripts
Software Heritage: not archived
Found in: the text, “NRI-Based Analysis of Protein–Ligand Dynamic Int”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (7 files), Matplotlib (6 files), pandas (4 files), PyTorch (4 files), seaborn (4 files), SciPy (3 files), NetworkX (1 file)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
13 files

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 13 scripts, each with its path and the digest of its content;
  • 1 match between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data Availability Statement

The simulations were conducted with Desmond program and the MD data collected as trajectory files, and NeuralPlexer structures of top candidates were made available via the following repository: https://zenodo.org/records/19727467.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 3, 28 September 2026

  • Publisher: n/a → American Chemical Society

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 5 authors, 11 MeSH terms, 2 funders, 32 references.

Cite

This paper

Sayyah, E., Tunç, H., Çelebi, A., Avşar, T., & Durdağı, S. (2026). Targeting BCL-2 through Deep Learning-Based Drug Repurposing: A Multimodal Approach Combining Diffusion-Based Generative Modeling, Neural Relational Inference, and In Vitro Validation. Journal of chemical information and modeling, 66(17), 11361-11376. https://doi.org/10.1021/acs.jcim.6c01299

BibTeX

@article{sayyah2026targeting,
author = {Sayyah, Ehsan and Tunç, Hüseyin and Çelebi, Asuman and Avşar, Timuçin and Durdağı, Serdar},
title = {{Targeting BCL-2 through Deep Learning-Based Drug Repurposing: A Multimodal Approach Combining Diffusion-Based Generative Modeling, Neural Relational Inference, and In Vitro Validation}},
journal = {Journal of chemical information and modeling},
year = {2026},
month = sep,
volume = {66},
number = {17},
pages = {11361--11376},
publisher = {American Chemical Society},
issn = {1549-9596},
doi = {10.1021/acs.jcim.6c01299},
url = {https://doi.org/10.1021/acs.jcim.6c01299},
pmid = {42734502},
pmcid = {PMC13580121}
}

RIS

TY - JOUR
AU - Sayyah, Ehsan
AU - Tunç, Hüseyin
AU - Çelebi, Asuman
AU - Avşar, Timuçin
AU - Durdağı, Serdar
TI - Targeting BCL-2 through Deep Learning-Based Drug Repurposing: A Multimodal Approach Combining Diffusion-Based Generative Modeling, Neural Relational Inference, and In Vitro Validation
T2 - Journal of chemical information and modeling
J2 - J Chem Inf Model
PY - 2026
DA - 2026/09/01
VL - 66
IS - 17
SP - 11361
EP - 11376
SN - 1549-9596
PB - American Chemical Society
DO - 10.1021/acs.jcim.6c01299
UR - https://doi.org/10.1021/acs.jcim.6c01299
LA - en
ER -

CSL-JSON

{
"id": "10.1021/acs.jcim.6c01299",
"type": "article-journal",
"title": "Targeting BCL-2 through Deep Learning-Based Drug Repurposing: A Multimodal Approach Combining Diffusion-Based Generative Modeling, Neural Relational Inference, and In Vitro Validation",
"container-title": "Journal of chemical information and modeling",
"author": [
{
"family": "Sayyah",
"given": "Ehsan"
},
{
"family": "Tunç",
"given": "Hüseyin"
},
{
"family": "Çelebi",
"given": "Asuman"
},
{
"family": "Avşar",
"given": "Timuçin"
},
{
"family": "Durdağı",
"given": "Serdar"
}
],
"container-title-short": "J Chem Inf Model",
"volume": "66",
"issue": "17",
"page": "11361-11376",
"DOI": "10.1021/acs.jcim.6c01299",
"PMID": "42734502",
"PMCID": "PMC13580121",
"ISSN": "1549-9596",
"publisher": "American Chemical Society",
"URL": "https://doi.org/10.1021/acs.jcim.6c01299",
"language": "en",
"issued": {
"date-parts": [
[
2026,
9,
1
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1093/bib/bbag118 [code]
Drug screening for α-synuclein aggregation inhibitors via multimodal graph neural network.
Journal: Briefings in bioinformatics
In common: RDKit, NetworkX, PyTorch, 5 other tools, computational modeling (no new data), cellular / molecular
[2] doi:10.1038/s41586-026-10670-w [code]
Zero-shot design of drug-binding proteins via neural iterative selection-expansion.
Journal: Nature
In common: RDKit, PyTorch, seaborn, 4 other tools, computational modeling (no new data), cellular / molecular, 1 reference
[3] doi:10.1371/journal.pone.0345854 [code]
Shedding light on neural learning to rank models for anticancer drug prioritization.
Journal: PloS one
In common: RDKit, NetworkX, PyTorch, 5 other tools, other condition
[4] doi:10.1021/acsomega.5c09368 [code]
Structure-Based and AI-Assisted Identification of AGPS Inhibitors for Glioma via Integrated Docking, Molecular Dynamics, and Binding Affinity Screening.
Journal: ACS omega
In common: RDKit, PyTorch, seaborn, 4 other tools, other condition, 1 reference
[5] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: RDKit, NetworkX, PyTorch, 5 other tools, cellular / molecular
[6] doi:10.1038/s41467-026-75444-4 [code]
Structural insights enable drug discovery for the neuronal NBCn2 carbonate transporter.
Journal: Nature communications
In common: RDKit, pandas, SciPy, 2 other tools, cellular / molecular, 2 references
[7] doi:10.1093/nar/gkag706 [code]
scDifformer: diffusion-based post-training for virtual cell modeling across large-scale single-cell data.
Journal: Nucleic acids research
In common: RDKit, NetworkX, PyTorch, 5 other tools
[8] doi:10.1186/s13321-026-01177-7 [code]
A pipeline for developing AI-driven models to predict molecular initiating events: a case study on neural tube defects.
Journal: Journal of cheminformatics
In common: RDKit, NetworkX, PyTorch, 5 other tools
[9] doi:10.1038/s41467-026-71759-4 [code]
CellNiche represents cellular microenvironments in atlas-scale spatial omics data with contrastive learning.
Journal: Nature communications
In common: NetworkX, PyTorch, seaborn, 4 other tools, computational modeling (no new data), other condition, cellular / molecular
[10] doi:10.1038/s41598-026-53415-5 [code]
Computational design and immunoinformatics validation of a T cell multi-epitope vaccine targeting glioblastoma stem cells.
Journal: Scientific reports
In common: RDKit, PyTorch, pandas, 3 other tools, computational modeling (no new data), other condition, cellular / molecular

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.