def testIDReprBond(self): rxn = BO4 # noinspection PyTypeChecker event1 = Event(rxn, [1, 2], DEF_RXN_RATES[rxn][(G, S)][MON_OLI], (4, 8)) good_str = "Forming bo4 bond between indices [1, 2] (adjacency_matrix update (4, 8))" self.assertTrue(str(event1) == good_str) self.assertTrue(repr(event1) == good_str)
def testB1BondGenMol(self): ini_mono_type_list = [S, S, S, G, S] sg_ratio = 1.0 max_monos = 12 random_num = 55 initial_monomers = [ Monomer(mono_type, i) for i, mono_type in enumerate(ini_mono_type_list) ] initial_events = create_initial_events(initial_monomers, DEF_RXN_RATES) initial_events.append(Event(GROW, [], rate=1e4)) initial_state = create_initial_state(initial_events, initial_monomers) result = run_kmc(DEF_RXN_RATES, initial_state, initial_events, n_max=max_monos, t_max=2, random_seed=random_num, sg_ratio=sg_ratio) nodes = result[MONO_LIST] adj = result[ADJ_MATRIX] # generate_mol(adj, nodes) with capture_stderr(generate_mol, adj, nodes) as output: self.assertFalse(output) mol = MolFromMolBlock(generate_mol(adj, nodes)) mols = GetMolFrags(mol) analysis = analyze_adj_matrix(adj) frag_sizes = analysis[CHAIN_LEN] # Make sure there are the same number of separate fragments calculated by RDKIT # as we get from just separating the alternate B1 self.assertEqual(np.sum(list(frag_sizes.values())), len(mols))
def create_initial_events(initial_monomers, rxn_rates): """ # Create event_dict that will oxidize every monomer :param initial_monomers: a list of Monomer objects :param rxn_rates: dict of dict of dicts of reaction rates in 1/s :return: a list of oxidation Event objects to initialize the state by allowing oxidation of every monomer """ return [Event(OX, [mon.identity], rxn_rates[OX][mon.type][MONOMER]) for mon in initial_monomers]
def create_sample_kmc_result_c_lignin(num_monos=2, max_monos=12, seed=10): initial_monomers = [Monomer(C, i) for i in range(num_monos)] # noinspection PyTypeChecker initial_events = create_initial_events(initial_monomers, DEF_RXN_RATES) initial_state = create_initial_state(initial_events, initial_monomers) initial_events.append(Event(GROW, [], rate=1e4)) result = run_kmc(DEF_RXN_RATES, initial_state, sorted(initial_events), n_max=max_monos, t_max=2, random_seed=seed) return result
def testMissingRequiredSGRatio(self): # set up variable to allow running run_kmc without specifying sg_ratio initial_sg_ratio = 0.75 num_initial_monos = 3 monomer_draw = np.around(np.random.rand(num_initial_monos), MAX_NUM_DECIMAL) # these are tested separately initial_monomers = create_initial_monomers(initial_sg_ratio, monomer_draw) initial_events = create_initial_events(initial_monomers, DEF_RXN_RATES) initial_state = create_initial_state(initial_events, initial_monomers) events = {initial_events[i] for i in range(num_initial_monos)} events.add(Event(GROW, [], rate=1e4)) try: run_kmc(DEF_RXN_RATES, initial_state, sorted(events), n_max=20, t_max=1, random_seed=10) self.assertFalse("Should not arrive here; An error should have be raised") except InvalidDataError as e: self.assertTrue("A numeric sg_ratio" in e.args[0])
def generate_lignin(num_monomers: int = 1) -> Chem.Mol: """Generates lignin molecule. parameters ---------- num_monomers : int Number of monomers in lignin molecule. """ # Set the percentage of S sg_ratio = 0 pct_s = sg_ratio / (1 + sg_ratio) # Set the initial and maximum number of monomers to be modeled. ini_num_monos = 1 max_num_monos = num_monomers # Maximum time to simulate, in seconds t_max = 1 # seconds mono_add_rate = 1e4 # monomers/second # Use a random number and the given sg_ratio to determine the monolignol types to be initially modeled monomer_draw = np.random.rand(ini_num_monos) initial_monomers = create_initial_monomers(pct_s, monomer_draw) # Initially allow only oxidation events. After they are used to determine the initial state, add # GROW to the events, which allows additional monomers to be added to the reaction at the # specified rate and with the specified ratio initial_events = create_initial_events(initial_monomers, rxn_rates) initial_state = create_initial_state(initial_events, initial_monomers) initial_events.append(Event(GROW, [], rate=mono_add_rate)) # simulate lignin creation result = run_kmc(rxn_rates, initial_state, initial_events, n_max=max_num_monos, t_max=t_max, sg_ratio=sg_ratio) # using RDKit nodes = result[MONO_LIST] adj = result[ADJ_MATRIX] block = generate_mol(adj, nodes) mol = MolFromMolBlock(block) mol = Chem.AddHs(mol) return mol
def testIniRates(self): # Note: this test did not increase coverage. Added to help debug notebook. # run_multi = False # if run_multi: # fun = par.delayed(run_kmc) # num_jobs = num_repeats # else: num_repeats = 4 # fun = None # num_jobs = None sg_ratio = 1.1 # minimize random calls monomer_type_list = [S, G] initial_monomers = [Monomer(mono_type, i) for i, mono_type in enumerate(monomer_type_list)] max_monos = 12 initial_events = create_initial_events(initial_monomers, DEF_RXN_RATES) # FYI: np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)[source] num_rates = 3 add_rates = np.logspace(4, 12, num_rates) add_rates_result_list = [] # will add to random seed in the iterations to insure using a different seed for each repeat random_seed = 2 for add_rate in add_rates: initial_state = create_initial_state(initial_events, initial_monomers) initial_events.append(Event(GROW, [], rate=add_rate)) # if run_multi: # results = par.Parallel(n_jobs=num_jobs)([fun(DEF_RXN_RATES, initial_state, initial_events, # n_max=max_monos, t_max=1, sg_ratio=sg_ratio, # random_seed=(random_seed + i)) # for i in range(num_repeats)]) # else: results = [run_kmc(DEF_RXN_RATES, initial_state, initial_events, n_max=max_monos, t_max=1, sg_ratio=sg_ratio, random_seed=(random_seed + i)) for i in range(num_repeats)] add_rates_result_list.append(results) av_bo4_bonds, std_bo4_bonds = get_avg_num_bonds(BO4, num_rates, add_rates_result_list, num_repeats) good_av_bo4 = [0.3680555555555555, 0.2863636363636364, 0.03125] good_std_bo4 = [0.08187379251771941, 0.013636363636363641, 0.05412658773652741] self.assertTrue(np.allclose(av_bo4_bonds, good_av_bo4)) self.assertTrue(np.allclose(std_bo4_bonds, good_std_bo4))
def initiate_state(add_rate, cfg, rep, sg_ratio): pct_s = sg_ratio / (1 + sg_ratio) ini_num_monos = cfg[INI_MONOS] if cfg[RANDOM_SEED]: # we don't want the same random seed for every iteration np.random.seed(cfg[RANDOM_SEED] + int(add_rate / 100 + sg_ratio * 10) + rep) monomer_draw = np.around(np.random.rand(ini_num_monos), MAX_NUM_DECIMAL) else: monomer_draw = np.random.rand(ini_num_monos) initial_monomers = create_initial_monomers(pct_s, monomer_draw) # initial event must be oxidation to create reactive species; all monomers may be oxidized initial_events = create_initial_events(initial_monomers, cfg[RXN_RATES]) # initial_monomers and initial_events are grouped into the initial state initial_state = create_initial_state(initial_events, initial_monomers) if cfg[MAX_MONOS] > cfg[INI_MONOS]: initial_events.append(Event(GROW, [], rate=add_rate)) elif cfg[MAX_MONOS] < cfg[INI_MONOS]: warning(f"The specified maximum number of monomers ({cfg[MAX_MONOS]}) is less than the " f"specified initial number of monomers ({cfg[INI_MONOS]}). \n The program will " f"proceed with the with the initial number of monomers with no addition of monomers.") return initial_events, initial_state
def create_sample_kmc_result(max_time=1., num_initial_monos=3, max_monos=10, sg_ratio=0.75, seed=10): # The set lists are to minimize randomness in testing (adding while debugging source of randomness in some tests; # leaving because it doesn't hurt a thing; also leaving option to make a monomer_draw of arbitrary length # using a seed, but rounding those numbers because the machine precision differences in floats was the bug np.random.seed(seed) if num_initial_monos == 3: monomer_draw = MONO_DRAW_3 elif num_initial_monos == 20: monomer_draw = [0.77132064, 0.02075195, 0.63364823, 0.74880388, 0.49850701, 0.22479665, 0.19806286, 0.76053071, 0.16911084, 0.08833981, 0.68535982, 0.95339335, 0.00394827, 0.51219226, 0.81262096, 0.61252607, 0.72175532, 0.29187607, 0.91777412, 0.71457578] else: monomer_draw = np.around(np.random.rand(num_initial_monos), MAX_NUM_DECIMAL) # these are tested separately elsewhere initial_monomers = create_initial_monomers(sg_ratio, monomer_draw) initial_events = create_initial_events(initial_monomers, DEF_RXN_RATES) initial_state = OrderedDict(create_initial_state(initial_events, initial_monomers)) initial_events.append(Event(GROW, [], rate=1e4)) result = run_kmc(DEF_RXN_RATES, initial_state, initial_events, n_max=max_monos, t_max=max_time, random_seed=10, sg_ratio=sg_ratio) return result
max_num_monos = 10 # Maximum time to simulate, in seconds t_max = 1 # seconds mono_add_rate = 1e4 # monomers/second # Use a random number and the given sg_ratio to determine the monolignol types to be initially modeled monomer_draw = np.random.rand(ini_num_monos) initial_monomers = create_initial_monomers(pct_s, monomer_draw) # Initially allow only oxidation events. After they are used to determine the initial state, add # GROW to the events, which allows additional monomers to be added to the reaction at the # specified rate and with the specified ratio initial_events = create_initial_events(initial_monomers, rxn_rates) initial_state = create_initial_state(initial_events, initial_monomers) initial_events.append(Event(GROW, [], rate=mono_add_rate)) result = run_kmc(rxn_rates, initial_state, initial_events, n_max=max_num_monos, t_max=t_max, sg_ratio=sg_ratio) # Convert the sparse matrix to a full array before printing print("The adjacency matrix for the simulated lignin is:") print(result[ADJ_MATRIX].toarray()) # From the list of monomers and the adjacency matrix, we can use LigninKMC to write out a tcl script for psfgen to # turn into a .psf file. # fname and sgnames are things that we'd want to change; file name always the same as the segname
def testIDRepr(self): rxn = OX # noinspection PyTypeChecker event1 = Event(rxn, [2], DEF_RXN_RATES[rxn][G][MONOMER]) self.assertTrue(str(event1) == "Performing oxidation on index 2")