From e9b0260b0abcca10672a7e3ace381c1a642b786c Mon Sep 17 00:00:00 2001 From: donerancl Date: Tue, 30 Jan 2024 14:55:44 -0500 Subject: [PATCH] squashed --- ipython/fragment_reattachment_example.ipynb | 1021 ++++++++++--------- rmgpy/molecule/fragment_utils.py | 312 ++++++ 2 files changed, 875 insertions(+), 458 deletions(-) create mode 100644 rmgpy/molecule/fragment_utils.py diff --git a/ipython/fragment_reattachment_example.ipynb b/ipython/fragment_reattachment_example.ipynb index a3de845210..9c45b4cc7a 100644 --- a/ipython/fragment_reattachment_example.ipynb +++ b/ipython/fragment_reattachment_example.ipynb @@ -32,17 +32,17 @@ } ], "source": [ - "from rdkit.Chem.rdmolops import *\n", + "import sys\n", + "rmgpy_loc = \"/home/gridsan/adoner/RMG-Py/\"\n", + "sys.path.append(rmgpy_loc)\n", "from rmgpy.molecule.fragment import Fragment\n", "from rmgpy.tools.canteramodel import Cantera\n", - "from rmgpy.chemkin import *\n", + "from rmgpy.chemkin import load_chemkin_file\n", + "from rmgpy.molecule.fragment_utils import match_sequences, match_concentrations_with_same_sums, match_concentrations_with_different_sums, shuffle, flatten, merge_frag_to_frag, merge_frag_list\n", "import re\n", "import os\n", "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import sys\n", - "rmgpy_loc = \"/home/gridsan/adoner/RMG-Py/\"\n", - "sys.path.append(rmgpy_loc)" + "import matplotlib.pyplot as plt" ] }, { @@ -56,7 +56,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 7, "id": "9802cd48-4a7b-4244-acf8-cba0fc1aab69", "metadata": {}, "outputs": [], @@ -64,12 +64,12 @@ "class FragList():\n", " '''\n", " to instantiate a FragList:\n", - " fl = Fraglist(frag_list) \n", + " fl = Fraglist(frag_list)\n", " where frag_list is a list of tuples of fragments and their amounts\n", " '''\n", "\n", " def __init__(self, frag_list):\n", - " self.raw = frag_list\n", + " self.raw_fragment_output = frag_list\n", "\n", " def sort(self):\n", " '''\n", @@ -78,7 +78,7 @@ " general_L_list - 2L fragments\n", " rr_ll_list - 2R or 2L fragments\n", " r_l_moles - 1R and 1L fragments\n", - " multi_label_frag_3 - fragments with 3 cutting labels \n", + " multi_label_frag_3 - fragments with 3 cutting labels\n", " multi_label_frag_4 - fragments with 4 cutting labels\n", "\n", " note: in our experience fragments with more than 4 cutting labels has never happened, but a warning will be printed if it does happen\n", @@ -93,41 +93,44 @@ " multi_label_frag_3 = []\n", " multi_label_frag_4 = []\n", "\n", - " for i, item in enumerate(self.raw):\n", + " for i, item in enumerate(self.raw_fragment_output):\n", " frag, amt = item\n", " if amt > 1e-6 and '[' not in frag:\n", - " if len(re.findall(r'R', frag)) == 0 and len(re.findall(r'L', frag)) == 0:\n", + " count_of_L_labels = len(re.findall(r'L', frag))\n", + " count_of_R_labels = len(re.findall(r'R', frag))\n", + " count_of_cutting_labels = count_of_L_labels + count_of_R_labels\n", + " if count_of_R_labels == 0 and count_of_L_labels == 0:\n", " moles_remain.append((frag, amt))\n", - " elif len(re.findall(r'R', frag)) == 1 and len(re.findall(r'L', frag)) == 0:\n", + " elif count_of_R_labels == 1 and count_of_L_labels == 0:\n", " one_R_dict[frag] = amt\n", - " elif len(re.findall(r'R', frag)) == 2 and len(re.findall(r'L', frag)) == 0:\n", + " elif count_of_R_labels == 2 and count_of_L_labels == 0:\n", " general_R_list.append((frag, amt * 2))\n", " rr_ll_list.append(frag)\n", - " elif len(re.findall(r'R', frag)) == 0 and len(re.findall(r'L', frag)) == 1:\n", + " elif count_of_R_labels == 0 and count_of_L_labels == 1:\n", " one_L_dict[frag] = amt\n", - " elif len(re.findall(r'R', frag)) == 0 and len(re.findall(r'L', frag)) == 2:\n", + " elif count_of_R_labels == 0 and count_of_L_labels == 2:\n", " general_L_list.append((frag, amt * 2))\n", " rr_ll_list.append(frag)\n", - " elif len(re.findall(r'R', frag)) == 1 and len(re.findall(r'L', frag)) == 1:\n", + " elif count_of_R_labels == 1 and count_of_L_labels == 1:\n", " r_l_moles.append((frag, amt))\n", " else:\n", - " if len(re.findall(r'[LR]', frag)) == 3:\n", + " if count_of_cutting_labels == 3:\n", " multi_label_frag_3.append(\n", " (frag, amt)) # 2R1L, 1R2L, 3R, 3L\n", - " elif len(re.findall(r'[LR]', frag)) == 4:\n", + " elif count_of_cutting_labels == 4:\n", " multi_label_frag_4.append((frag, amt))\n", " else:\n", " print(\n", - " f\"Warning! {len(re.findall(r'[LR]',frag))} cutting labels in {frag}\")\n", - " self.R1dict = one_R_dict\n", - " self.L1dict = one_L_dict\n", - " self.Rlist = general_R_list\n", - " self.Llist = general_L_list\n", - " self.RRLLlist = rr_ll_list\n", - " self.RLlist = r_l_moles\n", - " self.CL3 = multi_label_frag_3\n", - " self.CL4 = multi_label_frag_4\n", - " self.molesremain = moles_remain\n", + " f\"Warning! {count_of_cutting_labels} cutting labels in {frag}\")\n", + " self.R1dict=one_R_dict\n", + " self.L1dict=one_L_dict\n", + " self.Rlist=general_R_list\n", + " self.Llist=general_L_list\n", + " self.RRLLlist=rr_ll_list\n", + " self.RLlist=r_l_moles\n", + " self.CL3=multi_label_frag_3\n", + " self.CL4=multi_label_frag_4\n", + " self.molesremain=moles_remain\n", "\n", " def random_pick_frag(target_dict):\n", " '''\n", @@ -138,11 +141,11 @@ " '''\n", " import random\n", " import re\n", - " frag_dict_list = [x for x in target_dict.items() if len(\n", + " frag_dict_list=[x for x in target_dict.items() if len(\n", " re.findall(r'[LR]', x[0])) == 1]\n", - " sum_dict = sum([x[1] for x in frag_dict_list])\n", - " frag_dict_prob = [x[1]/sum_dict for x in frag_dict_list]\n", - " item = np.random.choice(frag_dict_list, 1, p=frag_dict_prob)\n", + " sum_dict=sum([x[1] for x in frag_dict_list])\n", + " frag_dict_prob=[x[1] / sum_dict for x in frag_dict_list]\n", + " item=np.random.choice(frag_dict_list, 1, p = frag_dict_prob)\n", "\n", " return item\n", "\n", @@ -152,31 +155,31 @@ " target_dict - dictionary of species smiles and moles\n", " returns: the target_dict with 1 randomly chosen 1-cutting label fragment fully paired with other randomly chosen 1-cutting label fragments\n", " '''\n", - " additional_frag_list = []\n", - " frag1 = FragList.random_pick_frag(target_dict)\n", + " additional_frag_list=[]\n", + " frag1=FragList.random_pick_frag(target_dict)\n", "\n", " if target_dict[frag1] >= amount:\n", " target_dict[frag1] -= amount\n", " additional_frag_list.append((frag1, amount))\n", "\n", " else:\n", - " remain = amount - target_dict[frag1]\n", + " remain=amount - target_dict[frag1]\n", " additional_frag_list.append((frag1, amount))\n", - " target_dict[frag1] = 0\n", + " target_dict[frag1]=0\n", "\n", " while remain > 0:\n", - " frag1 = FragList.random_pick_frag(target_dict)\n", + " frag1=FragList.random_pick_frag(target_dict)\n", "\n", " if target_dict[frag1] >= remain:\n", " target_dict[frag1] -= remain\n", " additional_frag_list.append((frag1, remain))\n", - " remain = 0\n", + " remain=0\n", "\n", " else:\n", - " frag_amt = target_dict[frag1]\n", - " target_dict[frag1] = 0\n", + " frag_amt=target_dict[frag1]\n", + " target_dict[frag1]=0\n", " additional_frag_list.append((frag1, frag_amt))\n", - " remain = remain - frag_amt\n", + " remain=remain - frag_amt\n", " return additional_frag_list\n", "\n", " def pair_CL4s(self):\n", @@ -185,60 +188,56 @@ " '''\n", "\n", " for species, amount in self.CL4: # 4R, 3R1L, 2R2L, 1R3L, 4L\n", - "\n", - " if len(re.findall(r'R', species)) == 4 and len(re.findall(r'L', species)) == 0:\n", - " paired_frag_list = FragList.pair_frag(amount, self.L1dict)\n", + " ount_of_R_labels=len(re.findall(r'R', species))\n", + " count_of_L_labels=len(re.findall(r'L', species))\n", + " if count_of_R_labels == 4 and count_of_L_labels == 0:\n", + " paired_frag_list=FragList.pair_frag(amount, self.L1dict)\n", " for frag_amt in paired_frag_list:\n", - " frag = frag_amt[0]\n", - " amt = frag_amt[1]\n", - " frag1 = frag # 1L\n", - " frag2 = species # 4R\n", - " frag_new = FragList.merge_frag_to_frag(\n", - " frag1, frag2, 'R') # L,R,R -> 3\n", + " frag=frag_amt[0]\n", + " amt=frag_amt[1]\n", + " frag1=frag # 1L\n", + " frag2=species # 4R\n", + " frag_new=FragList.merge_frag_to_frag(frag1, frag2, 'R') # L,R,R -> 3\n", " self.CL3.append((frag_new, amt))\n", "\n", - " elif len(re.findall(r'R', species)) == 0 and len(re.findall(r'L', species)) == 4:\n", + " elif count_of_R_labels == 0 and count_of_L_labels == 4:\n", " paired_frag_list = FragList.pair_frag(amount, self.R1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", " amt = frag_amt[1]\n", " frag1 = frag # 1R\n", " frag2 = species # 4L\n", - " frag_new = FragList.merge_frag_to_frag(\n", - " frag2, frag1, 'R') # L,R,R -> 3L\n", + " frag_new = FragList.merge_frag_to_frag(frag2, frag1, 'R') # L,R,R -> 3L\n", " self.CL3.append((frag_new, amt))\n", "\n", - " elif len(re.findall(r'R', species)) == 2 and len(re.findall(r'L', species)) == 2:\n", + " elif count_of_R_labels == 2 and count_of_L_labels == 2:\n", " paired_frag_list = FragList.pair_frag(amount, self.L1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", " amt = frag_amt[1]\n", " frag1 = frag # 1L\n", " frag2 = species # 2R2L\n", - " frag_new = FragList.merge_frag_to_frag(\n", - " frag1, frag2, 'R') # L,R,R -> 1R2L\n", + " frag_new = FragList.merge_frag_to_frag(frag1, frag2, 'R') # L,R,R -> 1R2L\n", " self.CL3.append((frag_new, amt))\n", "\n", - " elif len(re.findall(r'R', species)) == 3 and len(re.findall(r'L', species)) == 1:\n", + " elif count_of_R_labels == 3 and count_of_L_labels == 1:\n", " paired_frag_list = FragList.pair_frag(amount, self.R1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", " amt = frag_amt[1]\n", " frag1 = frag # 1R\n", " frag2 = species # 3R1L\n", - " frag_new = FragList.merge_frag_to_frag(\n", - " frag2, frag1, 'R') # L,R,R -> 3R\n", + " frag_new = FragList.merge_frag_to_frag(frag2, frag1, 'R') # L,R,R -> 3R\n", " self.CL3.append((frag_new, amt))\n", "\n", - " elif len(re.findall(r'R', species)) == 1 and len(re.findall(r'L', species)) == 3:\n", + " elif count_of_R_labels == 1 and count_of_L_labels == 3:\n", " paired_frag_list = FragList.pair_frag(amount, self.L1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", " amt = frag_amt[1]\n", " frag1 = frag # 1L\n", " frag2 = species # 1R3L\n", - " frag_new = FragList.merge_frag_to_frag(\n", - " frag1, frag2, 'R') # L,R,R -> 3L\n", + " frag_new = FragList.merge_frag_to_frag(frag1, frag2, 'R') # L,R,R -> 3L\n", " self.CL3.append((frag_new, amt))\n", "\n", " def pair_CL3s(self):\n", @@ -247,7 +246,9 @@ " '''\n", "\n", " for species, amount in self.CL3:\n", - " if len(re.findall(r'R', species)) == 2 and len(re.findall(r'L', species)) == 1:\n", + " count_of_R_labels = len(re.findall(r'R', species))\n", + " count_of_L_labels = len(re.findall(r'L', species))\n", + " if count_of_R_labels == 2 and count_of_L_labels == 1:\n", " paired_frag_list = FragList.pair_frag(amount, self.R1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", @@ -258,7 +259,7 @@ " self.Rlist.append((frag_new, amt * 2))\n", " self.RRLLlist.append(frag_new)\n", "\n", - " elif len(re.findall(r'R', species)) == 1 and len(re.findall(r'L', species)) == 2:\n", + " elif count_of_R_labels == 1 and count_of_L_labels == 2:\n", " paired_frag_list = FragList.pair_frag(amount, self.L1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", @@ -269,7 +270,7 @@ " self.Llist.append((frag_new, amt * 2))\n", " self.RRLLlist.append(frag_new)\n", "\n", - " elif len(re.findall(r'R', species)) == 3 and len(re.findall(r'L', species)) == 0:\n", + " elif count_of_R_labels == 3 and count_of_L_labels == 0:\n", " paired_frag_list = FragList.pair_frag(amount, self.L1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", @@ -281,7 +282,7 @@ " self.RRLLlist.append(frag_new)\n", "\n", " # 3L\n", - " elif len(re.findall(r'R', species)) == 0 and len(re.findall(r'L', species)) == 3:\n", + " elif count_of_R_labels == 0 and count_of_L_labels == 3:\n", " paired_frag_list = FragList.pair_frag(amount, self.R1dict)\n", " for frag_amt in paired_frag_list:\n", " frag = frag_amt[0]\n", @@ -302,9 +303,9 @@ " self.Llist.append((one_L_frag, amt))\n", "\n", " def grind(conc, size):\n", - " \"\"\"\n", + " '''\n", " Split fragment concentrations into several repeating concentration units with specified size\n", - " \"\"\"\n", + " '''\n", " grinded_conc = []\n", " for label, c in conc:\n", " times = int(c / size)\n", @@ -315,306 +316,6 @@ "\n", " return grinded_conc\n", "\n", - " def match_sequences(seq1, seq2, diff_tol=1e-6):\n", - " \"\"\"\n", - " Given two lists (each item is int or float):\n", - " seq1 and seq2 with same sum, the method returns\n", - " matched indices and values.\n", - " Example:\n", - " seq1 = [1, 3, 1]\n", - " seq2 = [2, 1, 2]\n", - " return: [[(0,0),1],\n", - " [(1,0),1],\n", - " [(1,1),1],\n", - " [(1,2),1],\n", - " [(2,2),1]]\n", - " \"\"\"\n", - " # check if sums are close to same\n", - " sum_diff = sum(seq2) - sum(seq1)\n", - " assert (\n", - " abs(sum_diff / 1.0 / sum(seq1)) <= diff_tol\n", - " ), \"seq1 has different sum (diff={0}) than seq2.\".format(sum_diff)\n", - "\n", - " # force the sum to be same if the difference\n", - " # is small enough\n", - " if sum_diff >= 0:\n", - " seq1[-1] = seq1[-1] + sum_diff\n", - " else:\n", - " seq2[-1] = seq2[-1] - sum_diff\n", - "\n", - " # make cumulative sequences\n", - " cum_seq1 = [seq1[0]]\n", - " for item1 in seq1[1:]:\n", - " cum_seq1.append(cum_seq1[-1] + item1)\n", - "\n", - " cum_seq2 = [seq2[0]]\n", - " for item2 in seq2[1:]:\n", - " cum_seq2.append(cum_seq2[-1] + item2)\n", - "\n", - " # add index tags two both cumulative seqs\n", - " pin1 = 0\n", - " pin2 = 0\n", - " matched_indices = []\n", - " matched_cum_values = []\n", - " while pin1 < len(cum_seq1) and pin2 < len(cum_seq2):\n", - " matched_indices.append((pin1, pin2))\n", - "\n", - " if cum_seq1[pin1] > cum_seq2[pin2]:\n", - " matched_cum_values.append(cum_seq2[pin2])\n", - " pin2 += 1\n", - " elif cum_seq1[pin1] < cum_seq2[pin2]:\n", - " matched_cum_values.append(cum_seq1[pin1])\n", - " pin1 += 1\n", - " else:\n", - " matched_cum_values.append(cum_seq2[pin2])\n", - " pin1 += 1\n", - " pin2 += 1\n", - "\n", - " # get matches\n", - " matches = []\n", - " for i in range(len(matched_indices)):\n", - " matched_index_tup = matched_indices[i]\n", - " matched_cum_value = matched_cum_values[i]\n", - " if i == 0:\n", - " previous_cum_value = 0\n", - " else:\n", - " previous_cum_value = matched_cum_values[i - 1]\n", - "\n", - " matches.append(\n", - " [matched_index_tup, matched_cum_value - previous_cum_value])\n", - "\n", - " return matches\n", - "\n", - " def match_concentrations_with_same_sums(conc1, conc2, diff_tol=1e-6):\n", - " \"\"\"match_concentrations_with_same_sums\n", - " Given two lists with each item to be a tuple\n", - " (species label, concentration)\n", - " conc1 and conc2 with same total concentrations,\n", - " the method returns matched species labels and\n", - " concentrations.\n", - " Example:\n", - " conc1 = [('a', 1),\n", - " ('b', 3),\n", - " ('c', 1)]\n", - " conc2 = [('x', 2),\n", - " ('y', 1),\n", - " ('z', 2)]\n", - " return: [(('a','x'),1),\n", - " (('b','x'),1),\n", - " (('b','y'),1),\n", - " (('b','z'),1),\n", - " (('c','z'),1)]\n", - " \"\"\"\n", - " labels1 = [tup[0] for tup in conc1]\n", - " labels2 = [tup[0] for tup in conc2]\n", - "\n", - " seq1 = [tup[1] for tup in conc1]\n", - " seq2 = [tup[1] for tup in conc2]\n", - "\n", - " matches_seq = FragList.match_sequences(seq1, seq2, diff_tol)\n", - "\n", - " matches_conc = []\n", - " for match_seq in matches_seq:\n", - " matched_label_index1 = match_seq[0][0]\n", - " matched_label_index2 = match_seq[0][1]\n", - " matched_value = match_seq[1]\n", - "\n", - " matched_label1 = labels1[matched_label_index1]\n", - " matched_label2 = labels2[matched_label_index2]\n", - " match_conc = ((matched_label1, matched_label2), matched_value)\n", - " matches_conc.append(match_conc)\n", - " return matches_conc\n", - "\n", - " def match_concentrations_with_different_sums(conc1, conc2):\n", - " \"\"\"\n", - " Given two lists with each item to be a tuple\n", - " (species label, concentration)\n", - " conc1 and conc2 with different total concentrations,\n", - " the method returns matched species labels and\n", - " concentrations.\n", - " Example:\n", - " conc1 = [('a', 1),\n", - " ('b', 3),\n", - " ('c', 1)]\n", - " conc2 = [('x', 2),\n", - " ('y', 1),\n", - " ('z', 10)]\n", - " return: [(('a','x', 'z', 'z'),1),\n", - " (('b','x', 'z', 'z'),1),\n", - " (('b','y', 'z', 'z'),1),\n", - " (('b','z', 'z'),1),\n", - " (('c','z', 'z'),1)]\n", - " \"\"\"\n", - " labels1 = [tup[0] for tup in conc1]\n", - " labels2 = [tup[0] for tup in conc2]\n", - "\n", - " seq1 = [tup[1] for tup in conc1]\n", - " seq2 = [tup[1] for tup in conc2]\n", - "\n", - " matches_conc = []\n", - " pin1 = 0\n", - " pin2 = 0\n", - " val1 = seq1[pin1]\n", - " val2 = seq2[pin2]\n", - "\n", - " while True:\n", - " if val1 > val2:\n", - " match = ((labels1[pin1], labels2[pin2]), val2)\n", - " matches_conc.append(match)\n", - " val1 = val1 - val2\n", - " pin2 += 1\n", - " if pin2 == len(seq2):\n", - " break\n", - " val2 = seq2[pin2]\n", - " elif val1 < val2:\n", - " match = ((labels1[pin1], labels2[pin2]), val1)\n", - " matches_conc.append(match)\n", - " val2 = val2 - val1\n", - " pin1 += 1\n", - " if pin1 == len(seq1):\n", - " break\n", - " val1 = seq1[pin1]\n", - " else:\n", - " match = ((labels1[pin1], labels2[pin2]), val1)\n", - " matches_conc.append(match)\n", - " pin1 += 1\n", - " pin2 += 1\n", - " if pin1 == len(seq1):\n", - " break\n", - " val1 = seq1[pin1]\n", - " if pin2 == len(seq2):\n", - " break\n", - " val2 = seq2[pin2]\n", - "\n", - " # if pin2 first reaches the end\n", - " # append all the remaining seq1 to matches_conc\n", - " if pin2 == len(seq2) and pin1 < len(seq1):\n", - " remain_conc1 = [(labels1[pin1], val1)] + conc1[(pin1 + 1):]\n", - " matches_conc.extend(remain_conc1)\n", - "\n", - " # if pin1 first reaches the end\n", - " # let matches_conc match with remaining seq2\n", - " elif pin1 == len(seq1) and pin2 < len(seq2):\n", - " remain_conc2 = [(labels2[pin2], val2)] + conc2[(pin2 + 1):]\n", - " matches_conc = FragList.match_concentrations_with_different_sums(\n", - " matches_conc, remain_conc2\n", - " )\n", - "\n", - " # if pin1 and pin2 reach the ends at same time\n", - " # matches_conc is ready to return\n", - " return matches_conc\n", - "\n", - " def shuffle(conc, seed=None):\n", - " \"\"\"\n", - " Randomly shuffle a list of fragments\n", - " \"\"\"\n", - " idx_arr = np.arange(len(conc))\n", - "\n", - " if seed is not None:\n", - " np.random.seed(seed)\n", - " np.random.shuffle(idx_arr)\n", - "\n", - " return [conc[idx] for idx in idx_arr]\n", - "\n", - " def flatten(combo):\n", - " \"\"\"\n", - " Given a combo nested `tuple`, e.g.,\n", - " ((('LY', 'XR'), ('LWL', 'RUR'))\n", - " return a list of labels contained in\n", - " the combo ['LY', 'XR', 'LWL', 'RUR']\n", - " \"\"\"\n", - " return_list = []\n", - " for i in combo:\n", - " if isinstance(i, tuple):\n", - " return_list.extend(FragList.flatten(i))\n", - " else:\n", - " return_list.append(i)\n", - " return return_list\n", - "\n", - " def merge_frag_to_frag(frag1, frag2, label): # label should match the desired merging l/'abel on frag2\n", - " from rmgpy.molecule import Bond\n", - " from rmgpy.molecule.fragment import Fragment, CuttingLabel\n", - " \n", - " frag_spe1 = Fragment().from_smiles_like_string(frag1)\n", - " frag_spe2 = Fragment().from_smiles_like_string(frag2)\n", - " # find position of desired CuttingLabel\n", - " # need to find CuttingLabel on frag2 first\n", - " for vertex in frag_spe2.vertices:\n", - " if isinstance(vertex, CuttingLabel):\n", - " if vertex.symbol == label:\n", - " cut2 = vertex\n", - " \n", - " atom2 = list(cut2.edges.keys())[0]\n", - " frag_spe2.remove_atom(cut2)\n", - " break\n", - "\n", - " if cut2.symbol[0] == 'L':\n", - " Ctl = cut2.symbol.replace('L', 'R')\n", - " else: # that means this CuttingLabel is R something\n", - " \n", - " Ctl = cut2.symbol.replace('R', 'L')\n", - " \n", - " # merge to frag_spe1\n", - " for vertex in frag_spe1.vertices:\n", - " if isinstance(vertex, CuttingLabel):\n", - " if vertex.symbol == Ctl:\n", - " cut1 = vertex\n", - " atom1 = list(cut1.edges.keys())[0]\n", - " frag_spe1.remove_atom(cut1)\n", - " break\n", - " \n", - " # new merged fragment\n", - " new_frag = frag_spe1.merge(frag_spe2)\n", - " new_frag.add_bond(Bond(atom1=atom1, atom2=atom2, order=1))\n", - " new_frag = new_frag.copy(deep=True)\n", - " new_frag.update()\n", - " return new_frag # return Fragment obtl\n", - "\n", - " def merge_frag_list(to_be_merged):\n", - " import os\n", - " # merges fragments in list from right to left\n", - " species_list = []\n", - " ethylene = []\n", - " newlist = []\n", - " warnings = []\n", - "\n", - " while len(to_be_merged) > 1:\n", - "\n", - " # second to last fragmentin list\n", - " frag1 = to_be_merged[-2].smiles\n", - " frag2 = to_be_merged[-1].smiles # last fragment in list\n", - "\n", - " if 'R' in frag1 and 'L' in frag2:\n", - " newfrag = FragList.merge_frag_to_frag(frag1, frag2, 'L')\n", - "\n", - " elif 'L' in frag1 and 'R' in frag2:\n", - " newfrag = FragList.merge_frag_to_frag(frag1, frag2, 'R')\n", - "\n", - " # warn user if last two fragments in list cannot be merged (no R/L combo to be made)\n", - " else:\n", - " print('Warning! Could not merge fragments {} and {}'.format(\n", - " frag1, frag2))\n", - "\n", - " if 'L' in frag1 and 'L' in frag2:\n", - " newfrag = FragList.merge_frag_to_frag(\n", - " frag1.replace('L', 'R'), frag2, 'L')\n", - " if len(to_be_merged) > 2:\n", - " cut = len(to_be_merged)-2\n", - " newfraglist = to_be_merged[:cut]\n", - "\n", - " newfraglist.append(newfrag)\n", - " elif len(to_be_merged) == 2:\n", - "\n", - " newfraglist = [newfrag]\n", - "\n", - " to_be_merged = newfraglist\n", - "\n", - " to_be_merged = newfraglist\n", - " # newlist.append(newfraglist) # if done merging list, write final structure to list of smiles structures\n", - "\n", - " # print('{}% of fragments fully merged...'.format(np.round(100*(i+1)/len(flattened_matches_random)),1))\n", - " # print(newfraglist)\n", - " return newfraglist\n", "\n", " def grind_endcaps(self, grindsize=1, repeats=1):\n", " '''\n", @@ -640,7 +341,7 @@ " '''\n", " matches = FragList.match_concentrations_with_same_sums(self.glmoles,\n", " self.grmoles,\n", - " diff_tol=1e-3)\n", + " rtol=1e-3)\n", " self.endcaps = []\n", " self.middles = []\n", " for match in matches:\n", @@ -726,6 +427,12 @@ " self.grouped.extend(flattened_matches_random)\n", "\n", " def get_mwd(self, bins=10, fname='mwd.png'):\n", + " '''\n", + " loop through molecules i.e. grouped fragments\n", + " calculate molecular weight\n", + " create histogram of molecular weights, weighted by molar amount\n", + " store histogram data in histdata\n", + " '''\n", " self.mwd_amts = [x[1] for x in self.grouped]\n", " self.mwd_mws = []\n", " for fraglist, amt in self.grouped:\n", @@ -736,7 +443,22 @@ " self.histdata = plt.hist(\n", " self.mwd_mws, bins=bins, weights=self.mwd_amts)\n", " plt.xlabel(\"Molecular Weight (g/mol)\")\n", - " plt.ylabel(\"Moles\")\n" + " plt.ylabel(\"Moles\")\n", + "\n", + " def reattach(self, grindsize = 1):\n", + " '''\n", + " this parent function combines the steps of reattachment into one\n", + " '''\n", + " self.sort() # sort the fragments by number and type of cutting labels\n", + " self.pair_CL4s() # reattach 4-cutting label fragments to make 3-cutting label fragments\n", + " self.pair_CL3s() # reattach 3-cutting label fragments to make 2-cutting label fragments\n", + " self.update_lists() # add 1-cutting label fragments to either Rlist or Llist\n", + " self.grind_endcaps(grindsize=grindsize) # grind the concentrations of fragments into smaller sub-concentrations\n", + " self.pair_endcaps() # pair together 1R and 1L fragments to make endcap pairs\n", + " self.grind_middles() # grind the concentrations of middle LR fragments into smaller sub-concentrations of same size as above\n", + " self.distribute_middles() # randomly select an endcap pair for each middle LR fragment\n", + " return self\n", + "\n" ] }, { @@ -750,12 +472,12 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "9d5bd8fb-2a97-487b-8cc2-e1349f5612e1", "metadata": {}, "outputs": [], "source": [ - "working_dir = os.path.join('./')\n", + "working_dir = os.getcwd()\n", "chemkin_path = os.path.join(working_dir, 'data/chem_annotated.inp')\n", "species_dict_path = os.path.join(working_dir, 'data/species_dictionary.txt')\n", "results_path = os.path.join(working_dir, 'results')\n", @@ -778,7 +500,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "id": "2f9f50fc-eba0-4156-8d87-1ed68294560d", "metadata": {}, "outputs": [], @@ -806,7 +528,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "6d69f465-2eff-4549-b9af-9531d77de360", "metadata": {}, "outputs": [], @@ -829,7 +551,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "100d1e81-0c4a-499d-bb45-63ed17fc605c", "metadata": {}, "outputs": [], @@ -851,12 +573,12 @@ "metadata": {}, "source": [ "## 2. Random Reattachment Procedure\n", - "- make a list of tuples of the each fragment species and its final concentration" + "- make a list of tuples of each fragment species and its final concentration" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "2082ed31-adaf-4346-bcd2-9ff09666faed", "metadata": {}, "outputs": [], @@ -900,7 +622,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "id": "ebe147a1-ad99-4320-8813-45b2141353f8", "metadata": { "tags": [] @@ -910,17 +632,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "grinding endcaps to 0.0005\n", - "grinding middle pieces to 0.0005\n", - "grinding endcaps to 0.0005\n", - "grinding middle pieces to 0.0005\n", - "grinding endcaps to 0.0005\n", - "grinding middle pieces to 0.0005\n" + "grinding endcaps to 0.001\n", + "grinding middle pieces to 0.001\n", + "grinding endcaps to 0.001\n", + "grinding middle pieces to 0.001\n", + "grinding endcaps to 0.001\n", + "grinding middle pieces to 0.001\n" ] }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAGwCAYAAABVdURTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAxtUlEQVR4nO3de1xVZd7///eWw8ZUMDVREow8NJZoCml4yEyFyEyb7oem3YppTaSmRqVSM2rezWBNNeltHiqPkykz4yF7xG1ylyipzSRCofI1z5BBpBngIVS4fn/4c9+zBRW2GzYsX8/HYz8es699rbU+65Jhv7vWtRY2Y4wRAACARdTzdAEAAADuRLgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACW4u3pAmpaWVmZfvjhBzVq1Eg2m83T5QAAgEowxqi4uFhBQUGqV+/qczM3XLj54YcfFBwc7OkyAACAC3Jzc9WqVaur9rnhwk2jRo0kXRwcf39/D1cDAAAqo6ioSMHBwY7v8au54cLNpUtR/v7+hBsAAOqYyiwpYUExAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFMINAACwFG9PF4CLwpaHVXmbrNisaqgEAIC6jZkbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKYQbAABgKR4NN1u3btWgQYMUFBQkm82m9evXV3rbbdu2ydvbW3fffXe11QcAAOoej4ab06dPq3Pnzpo3b16VtissLNSoUaPUr1+/aqoMAADUVd6ePHhMTIxiYmKqvN0zzzyjESNGyMvL65qzPSUlJSopKXG8LyoqqvLxAABA3VHn1twsXbpUBw8e1IwZMyrVPzExUQEBAY5XcHBwNVcIAAA8qU6Fm/3792vatGlauXKlvL0rN+mUkJCgwsJCxys3N7eaqwQAAJ7k0ctSVVFaWqoRI0bo1VdfVfv27Su9nd1ul91ur8bKAABAbVJnwk1xcbF27typjIwMTZgwQZJUVlYmY4y8vb21adMmPfDAAx6uEgAAeFqdCTf+/v7Kyspyaps/f76++OIL/eMf/1BoaKiHKgMAALWJR8PNqVOndODAAcf7w4cPKzMzU02aNFFISIgSEhJ07NgxrVixQvXq1VPHjh2dtm/evLn8/PzKtQMAgBuXR8PNzp071bdvX8f7+Ph4SVJsbKyWLVumvLw85eTkeKo8AABQB9mMMcbTRdSkoqIiBQQEqLCwUP7+/p4uxyFseViVt8mKzbp2JwAALKAq3991Zs0NynMlEEmEIgCAtdWp59wAAABcC+EGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYCuEGAABYikfDzdatWzVo0CAFBQXJZrNp/fr1V+2/du1aDRgwQLfccov8/f0VGRmpzz77rGaKBQAAdYJHw83p06fVuXNnzZs3r1L9t27dqgEDBig5OVnp6enq27evBg0apIyMjGquFAAA1BXenjx4TEyMYmJiKt3/nXfecXr/pz/9SR9//LE++eQTdenSxc3VAQCAusij4eZ6lZWVqbi4WE2aNLlin5KSEpWUlDjeFxUV1URpAADAQ+r0guK33npLp0+f1tChQ6/YJzExUQEBAY5XcHBwDVYIAABqWp0NN6tWrdLMmTOVlJSk5s2bX7FfQkKCCgsLHa/c3NwarBIAANS0OnlZKikpSWPHjtXf//539e/f/6p97Xa77HZ7DVUGAAA8rc7N3KxatUqjR4/WRx99pIEDB3q6HAAAUMt4dObm1KlTOnDggOP94cOHlZmZqSZNmigkJEQJCQk6duyYVqxYIelisBk1apTmzJmje++9V/n5+ZKk+vXrKyAgwCPnAAAAahePztzs3LlTXbp0cdzGHR8fry5dumj69OmSpLy8POXk5Dj6L1q0SBcuXND48ePVsmVLx2vSpEkeqR8AANQ+Hp25uf/++2WMueLny5Ytc3qfmppavQUBAIA6r86tuQEAALgawg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUwg0AALAUj4abrVu3atCgQQoKCpLNZtP69euvuc2WLVsUHh4uPz8/3X777Vq4cGH1FwoAAOoMj4ab06dPq3Pnzpo3b16l+h8+fFgPPfSQevfurYyMDL388suaOHGi1qxZU82VAgCAusLbkwePiYlRTExMpfsvXLhQISEheueddyRJHTp00M6dO/Xmm2/qscceq6YqAQBAXVKn1tzs2LFDUVFRTm3R0dHauXOnzp8/X+E2JSUlKioqcnoBAADrqlPhJj8/X4GBgU5tgYGBunDhgo4fP17hNomJiQoICHC8goODa6JUAADgIXUq3EiSzWZzem+MqbD9koSEBBUWFjpeubm51V4jAADwHI+uuamqFi1aKD8/36mtoKBA3t7eatq0aYXb2O122e32migPAADUAnVq5iYyMlIpKSlObZs2bVJERIR8fHw8VBUAAKhNPBpuTp06pczMTGVmZkq6eKt3ZmamcnJyJF28pDRq1ChH/7i4OB09elTx8fHKzs7WkiVLtHjxYr344oueKB8AANRCHr0stXPnTvXt29fxPj4+XpIUGxurZcuWKS8vzxF0JCk0NFTJycl6/vnn9e677yooKEhz587lNnAAAOBgM5dW5N4gioqKFBAQoMLCQvn7+3u6HIew5WE1dqys2KwaOxYAAO5Qle/vOrXmBgAA4FoINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFIINwAAwFLcEm6Kioq0fv16ZWdnu2N3AAAALnMp3AwdOlTz5s2TJJ09e1YREREaOnSo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p7bs7GzZbDaNHDnSqf2vf/2rfHx8dOrUqWvu98UXX9Tnn3/u1lolyWazaf369dfsV1JSounTp+sPf/iDS8cZPXq0pk2b5tK2rggLC1O3bt30l7/8pcaOCbgD4QbwoODgYK1evVpnz551tP36669atWqVQkJCPFhZzTl//ny5tr59++r//b//p/z8fEdbamqqgoODtXnzZqe+qamp6tatmxo2bHjNYzVs2FBNmza9/qJdtGbNGjVs2FC9e/eu8rZlZWX69NNPNXjw4Gqo7MqefPJJLViwQKWlpTV6XOB6EG4AD+ratatCQkK0du1aR9vatWsVHBysLl26OPUtKSnRxIkT1bx5c/n5+alXr176+uuvr7r/7du367777lP9+vUVHBysiRMnOl1iKCkp0ZQpUxQcHCy73a527dpp8eLFkqRly5apcePGTvtbv369bDbbFY/39ddfa8CAAWrWrJkCAgLUp08f7dq1y6mPzWbTwoULNXjwYDVo0ECvvfZauf306tVLPj4+Sk1NdbSlpqZq/PjxKi4u1oEDB5za+/btK0kqLCzU7373OzVv3lz+/v564IEH9M033zj6Xn5Z6sKFC5o4caIaN26spk2baurUqYqNjdWQIUOc6ikrK9OUKVPUpEkTtWjRQjNnznR8dtttt0mSHn30UdlsNsf7iqxevVqPPPKIU1tla9i2bZvq1aun7t27Oy4f/e1vf1Pv3r1Vv3593XPPPfruu+/09ddfKyIiQg0bNtSDDz6on376yek8Zs2apVatWslut+vuu+/Wxo0br1ivJEVHR+vEiRPasmXLVfsBtQnhBvCwJ598UkuXLnW8X7JkicaMGVOu35QpU7RmzRotX75cu3btUtu2bRUdHa2ff/65wv1mZWUpOjpav/3tb/Xtt98qKSlJX375pSZMmODoM2rUKK1evVpz585Vdna2Fi5cWKkZkCspLi5WbGys0tLS9NVXX6ldu3Z66KGHVFxc7NRvxowZGjx4sLKysio81wYNGuiee+5xmqXZsmWL+vXrp549ezrac3NzdejQIfXt21fGGA0cOFD5+flKTk5Wenq6unbtqn79+l1xjF5//XWtXLlSS5cu1bZt21RUVFTh5aXly5erQYMG+uc//6k33nhDs2bNUkpKiiQ5AubSpUuVl5d31cCZlpamiIgIl2rYsGGDBg0apHr1/u/X9owZM/T73/9eu3btkre3t4YPH64pU6Zozpw5SktL08GDBzV9+nRH/zlz5uitt97Sm2++qW+//VbR0dF65JFHtH///ivW7Ovrq86dOystLe2KfYBaxy1/WxxAlcXGxprBgwebn376ydjtdnP48GFz5MgR4+fnZ3766SczePBgExsba4wx5tSpU8bHx8esXLnSsf25c+dMUFCQeeONN4wxxmzevNlIMidPnjTGGDNy5Ejzu9/9zumYaWlppl69eubs2bNm3759RpJJSUmpsL6lS5eagIAAp7Z169aZf/+1MWPGDNO5c+crnuOFCxdMo0aNzCeffOJok2QmT558reExL7/8smnfvr0xxpg9e/YYf39/c+HCBTN79mwzYsQIY4wxy5cvN3a73Zw5c8Z8/vnnxt/f3/z6669O+2nTpo1ZtGhRhfUGBgaaP//5z071hoSEmMGDBzva+vTpY3r16uW0z3vuucdMnTrV6ZzWrVt31fM5efKkkWS2bt3q1F6ZGowxpn379mbDhg3GGGMOHz5sJJkPPvjA8fmqVauMJPP555872hITE80dd9zheB8UFGT++Mc/ljuXcePGOe03IyPDqc+jjz5qRo8efdXzA2oTb4+lKgCSpGbNmmngwIFavny5Y/ahWbNmTn0OHjyo8+fPq2fPno42Hx8fdevWTdnZ2RXuNz09XQcOHNDKlSsdbcYYlZWV6fDhw8rKypKXl5f69OnjtnMpKCjQ9OnT9cUXX+jHH39UaWmpzpw5o5ycHKd+l89eVKRv377605/+pB9++EGpqanq1auXo965c+dKunhJ6t5771X9+vWVnp6uU6dOlVtTc/bsWR08eLDc/gsLC/Xjjz+qW7dujjYvLy+Fh4errKzMqW+nTp2c3rds2VIFBQXXPIfL65AkPz+/KteQnZ2t77//Xv37979iXYGBgZIuLgL+97ZLdRYVFemHH35w+hmSpJ49ezpduqtI/fr1debMmUqdJ1AbEG6AWmDMmDGOy0Xvvvtuuc+NMZJUbr2LMeaKa2DKysr0zDPPaOLEieU+CwkJcVq3UpF69eo5jntJRYt//93o0aP1008/6Z133lHr1q1lt9sVGRmpc+fOOfVr0KDBVfcjXfzS9fX1VWpqqjZv3uwIYRERESosLNR3332nzZs3O+4oKysrU8uWLZ3W6Vxy+dqhf1fRmF7Ox8en3DaXB6Bradq0qWw2m06ePFnlGjZs2KABAwaofv36V6zr0j4ub7u8zqr8DF3y888/q02bNlftA9QmrLkBaoEHH3xQ586d07lz5xQdHV3u87Zt28rX11dffvmlo+38+fPauXNnuVumL+natav27Nmjtm3blnv5+voqLCxMZWVlV1woesstt6i4uNhpAfKl559cSVpamiZOnKiHHnpId911l+x2u44fP16JESivfv366t69u1JTU7V161bdf//9kiRvb2/16NFDK1as0JEjRxyLibt27ar8/Hx5e3uXO9/LZ8IkKSAgQIGBgfrXv/7laCstLVVGRkaVa/Xx8bnm3US+vr668847tXfv3irX8PHHH5dbiFxV/v7+CgoKcvoZki4uOr/Sz9Alu3fvLrfAHajNCDdALeDl5aXs7GxlZ2fLy8ur3OcNGjTQs88+q5deekkbN27U3r179fTTT+vMmTMaO3ZshfucOnWqduzYofHjxyszM1P79+/Xhg0b9Nxzz0m6eJdPbGysxowZo/Xr1+vw4cNKTU3V3/72N0lS9+7dddNNN+nll1/WgQMH9NFHH2nZsmVXPY+2bdvqr3/9q7Kzs/XPf/5TTzzxRLnZhqro27ev41b5rl27OtovXZq6FIAkqX///oqMjNSQIUP02Wef6ciRI9q+fbt+//vfa+fOnRXu/7nnnlNiYqI+/vhj7du3T5MmTdLJkyevOZNxudtuu02ff/658vPzK5yZuSQ6OrpcuLhWDQUFBfr666/18MMPV6mmirz00kt6/fXXlZSUpH379mnatGnKzMzUpEmTrrjNkSNHdOzYsXKXxIDajHAD1BL+/v7y9/e/4uezZ8/WY489ppEjR6pr1646cOCAPvvsM918880V9u/UqZO2bNmi/fv3q3fv3urSpYv+8Ic/qGXLlo4+CxYs0H/8x39o3Lhx+s1vfqOnn37aMVPTpEkTffjhh0pOTlZYWJhWrVrldAt0RZYsWaKTJ0+qS5cuGjlypOPWdVf17dtXxcXF6tmzp7y9/+8qep8+fVRcXKwePXrIbrdLuni5JTk5Wffdd5/GjBmj9u3b6/HHH9eRI0cc61EuN3XqVA0fPlyjRo1SZGSkGjZsqOjoaKd1MZXx1ltvKSUlpcJb+P/d008/reTkZBUWFla6hk8++UTdu3e/rnG8ZOLEiXrhhRf0wgsvKCwsTBs3btSGDRvUrl27K26zatUqRUVFqXXr1td9fKCm2ExFF5gB4AZUVlamDh06aOjQofqv//qvajnG0KFD1aVLFyUkJFSqhkceeUS9evXSlClTqqWeqykpKVG7du20atWqcguRgdqMBcUAblhHjx7Vpk2b1KdPH5WUlGjevHk6fPiwRowYUW3H/POf/6wNGzZUuoZevXpp+PDh1VbP1Rw9elSvvPIKwQZ1DjM3AG5Yubm5evzxx7V7924ZY9SxY0fNnj1b99133w1VA2A1hBsAAGApLCgGAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACWQrgBAACW8v8BRdHuOUB3VFsAAAAASUVORK5CYII=", + "image/png": "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//0yxpT7/ooVK5xep6SkVG1BAACg1qt1a24AAACuhXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAsxaPhZvv27Ro0aJCCgoJks9m0cePG6+6zbds2hYeHy9fXV3fccYeWLFlS9YUCAIBaw6Ph5uzZs+rUqZMWLlxYof5Hjx7VQw89pF69eiktLU3Tp0/XhAkTtG7duiquFAAA1BZenjz5gAEDNGDAgAr3X7JkiUJCQjRv3jxJUrt27bR792699dZbevzxx6uoSgAAUJvUqjU3u3btUlRUlFNbdHS0du/erYsXL5a5T1FRkQoKCpw2AABgXbUq3OTm5iowMNCpLTAwUJcuXdLJkyfL3CchIUEBAQGOLTg4uDpKBQAAHlKrwo0k2Ww2p9fGmDLbr4iPj1d+fr5jy87OrvIaAQCA53h0zU1lNWvWTLm5uU5teXl58vLyUuPGjcvcx263y263V0d5AACgBqhVMzeRkZFKTk52atuyZYsiIiLk7e3toaoAAEBN4tFwc+bMGaWnpys9PV3S5Ue909PTlZWVJenyLaWYmBhH/7i4OB0/flyTJ09WZmamli1bpqVLl+rFF1/0RPkAAKAG8uhtqd27d6tPnz6O15MnT5YkxcbGasWKFcrJyXEEHUkKDQ1VUlKSnn/+eb3zzjsKCgrSggULeAwcAAA42MyVFbk3iYKCAgUEBCg/P1/+/v6eLschbGVYtZ0rIzaj2s4FAIA7VObvd61acwMAAHA9hBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGApbgk3BQUF2rhxozIzM91xOAAAAJe5FG6GDBmihQsXSpLOnz+viIgIDRkyRB07dtS6devcWiAAAEBluBRutm/frl69ekmSNmzYIGOMfvnlFy1YsECvvvqqWwsEAACoDJfCTX5+vho1aiRJ2rx5sx5//HHdcsstGjhwoA4ePOjWAgEAACrDpXATHBysXbt26ezZs9q8ebOioqIkSadPn5avr69bCwQAAKgML1d2mjRpkp588knVr19fISEhuv/++yVdvl0VFhbmzvoAAAAqxaVwM3bsWHXt2lXZ2dnq37+/6tS5PAF0xx13sOYGAAB4lEvhRpIiIiLUsWNHHT16VK1atZKXl5cGDhzoztoAAAAqzaU1N+fOndPo0aN1yy23qH379srKypIkTZgwQXPmzHFrgQAAAJXhUriJj4/XN998o5SUFKcFxP369VNiYqLbigMAAKgsl25Lbdy4UYmJibr33ntls9kc7XfddZcOHz7stuIAAAAqy6WZm59++klNmzYt1X727FmnsAMAAFDdXAo399xzjz755BPH6yuB5v3331dkZGSljrVo0SKFhobK19dX4eHh2rFjxzX7r169Wp06ddItt9yi5s2b66mnntKpU6cqfxEAAMCSXLotlZCQoAcffFD79+/XpUuXNH/+fO3bt0+7du3Stm3bKnycxMRETZo0SYsWLVKPHj307rvvasCAAdq/f79CQkJK9f/iiy8UExOjP//5zxo0aJBOnDihuLg4jRkzRhs2bHDlUgAAgMW4NHPTvXt3ffnllzp37pxatWqlLVu2KDAwULt27VJ4eHiFjzN37lyNHj1aY8aMUbt27TRv3jwFBwdr8eLFZfb/6quvdPvtt2vChAkKDQ1Vz5499cwzz2j37t3lnqOoqEgFBQVOGwAAsC6Xwo0khYWFaeXKldq7d6/279+vv/71r5X6dOILFy4oNTXV8dUNV0RFRWnnzp1l7tO9e3d9//33SkpKkjFGP/74o/7xj39c8/N1EhISFBAQ4NiCg4MrXCMAAKh9Khxurp79uNZWESdPnlRxcbECAwOd2gMDA5Wbm1vmPt27d9fq1as1dOhQ+fj4qFmzZmrYsKH++7//u9zzxMfHKz8/37FlZ2dX9JIBAEAtVOE1Nw0bNrzuk1DGGNlsNhUXF1e4gKuPeeUYZdm/f78mTJigl19+WdHR0crJydFLL72kuLg4LV26tMx97Ha77HZ7hesBAAC1W4XDzdatW9164iZNmqhu3bqlZmny8vJKzeZckZCQoB49euill16SJHXs2FH16tVTr1699Oqrr6p58+ZurREAANQ+FQ43vXv3duuJfXx8FB4eruTkZD322GOO9uTkZA0ePLjMfc6dOycvL+eS69atK+nyjA8AAIDLX5z5yy+/aOnSpcrMzJTNZtNdd92lUaNGKSAgoMLHmDx5skaMGKGIiAhFRkbqvffeU1ZWluLi4iRdXi9z4sQJrVq1SpI0aNAgPf3001q8eLHjttSkSZPUtWtXBQUFuXopAADAQlwKN7t371Z0dLT8/PzUtWtXGWM0d+5c/elPf9KWLVvUpUuXCh1n6NChOnXqlGbPnq2cnBx16NBBSUlJatmypSQpJyfH8aWckjRy5EgVFhZq4cKFeuGFF9SwYUM98MADev311125DAAAYEE248L9nF69eql169Z6//33HbeJLl26pDFjxujIkSPavn272wt1l4KCAgUEBCg/P1/+/v6eLschbGXFH6O/URmxGdV2LgAA3KEyf79dnrn592AjSV5eXpoyZYoiIiJcOSQAAIBbuPQhfv7+/k63i67Izs5WgwYNbrgoAAAAV7kUboYOHarRo0crMTFR2dnZ+v7777V27VqNGTNGw4YNc3eNAAAAFebSbam33npLNptNMTExunTpkowx8vHx0bPPPqs5c+a4u0YAAIAKcync+Pj4aP78+UpISNDhw4dljFHr1q11yy23uLs+AACASqlUuBk1alSF+i1btsylYgAAAG5UpcLNihUr1LJlS3Xu3JlPBAYAADVSpcJNXFyc1q5dqyNHjmjUqFH6z//8TzVq1KiqagMAAKi0Sj0ttWjRIuXk5Gjq1Kn6+OOPFRwcrCFDhujTTz9lJgcAANQIlX4U3G63a9iwYUpOTtb+/fvVvn17jR07Vi1bttSZM2eqokYAAIAKc+lzbq6w2Wyy2WwyxqikpMRdNQEAALis0uGmqKhIa9asUf/+/XXnnXcqIyNDCxcuVFZWlurXr18VNQIAAFRYpRYUjx07VmvXrlVISIieeuoprV27Vo0bN66q2gAAACqtUuFmyZIlCgkJUWhoqLZt26Zt27aV2W/9+vVuKQ4AAKCyKhVuYmJiZLPZqqoWAACAG1bpD/EDAACoyW7oaSkAAICahnADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAsxePhZtGiRQoNDZWvr6/Cw8O1Y8eOa/YvKirSjBkz1LJlS9ntdrVq1UrLli2rpmoBAEBN5+XJkycmJmrSpElatGiRevTooXfffVcDBgzQ/v37FRISUuY+Q4YM0Y8//qilS5eqdevWysvL06VLl6q5cgAAUFPZjDHGUyfv1q2bunTposWLFzva2rVrp0cffVQJCQml+m/evFlPPPGEjhw5okaNGrl0zoKCAgUEBCg/P1/+/v4u1+5uYSvDqu1cGbEZ1XYuAADcoTJ/vz12W+rChQtKTU1VVFSUU3tUVJR27txZ5j6bNm1SRESE3njjDf3mN79R27Zt9eKLL+r8+fPlnqeoqEgFBQVOGwAAsC6P3ZY6efKkiouLFRgY6NQeGBio3NzcMvc5cuSIvvjiC/n6+mrDhg06efKkxo4dq59//rncdTcJCQl65ZVX3F4/AAComTy+oNhmszm9NsaUaruipKRENptNq1evVteuXfXQQw9p7ty5WrFiRbmzN/Hx8crPz3ds2dnZbr8GAABQc3hs5qZJkyaqW7duqVmavLy8UrM5VzRv3ly/+c1vFBAQ4Ghr166djDH6/vvv1aZNm1L72O122e129xYPAABqLI/N3Pj4+Cg8PFzJyclO7cnJyerevXuZ+/To0UM//PCDzpw542j77rvvVKdOHbVo0aJK6wUAALWDR29LTZ48WR988IGWLVumzMxMPf/888rKylJcXJyky7eUYmJiHP2HDx+uxo0b66mnntL+/fu1fft2vfTSSxo1apT8/Pw8dRkAAKAG8ejn3AwdOlSnTp3S7NmzlZOTow4dOigpKUktW7aUJOXk5CgrK8vRv379+kpOTtZzzz2niIgINW7cWEOGDNGrr77qqUsAAAA1jEc/58YT+JwbPucGAFD71IrPuQEAAKgKhBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsA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+eWX9cc//tGl84wcOVLTpk1zaV9XhIWFqWvXrvrzn/9cbecE3IFwA3hQcHCw1q5dq/Pnzzvafv31V61Zs0YhISEerKz6XLx4sVRbnz599H//93/Kzc11tKWkpCg4OFhbt2516puSkqKuXbuqfv361z1X/fr11bhx4xsv2kXr1q1T/fr11atXr0rvW1JSok8++USDBw+ugsrK99RTT2nx4sUqLi6u1vMCN4JwA3hQly5dFBISovXr1zva1q9fr+DgYHXu3Nmpb1FRkSZMmKCmTZvK19dXPXv21Ndff33N4+/cuVP33Xef/Pz8FBwcrAkTJjjdYigqKtKUKVMUHBwsu92uNm3aaOnSpZKkFStWqGHDhk7H27hxo2w2W7nn+/rrr9W/f381adJEAQEB6t27t/bs2ePUx2azacmSJRo8eLDq1aunV199tdRxevbsKW9vb6WkpDjaUlJSNG7cOBUWFurQoUNO7X369JEk5efn6/e//72aNm0qf39/PfDAA/rmm28cfa++LXXp0iVNmDBBDRs2VOPGjTV16lTFxsbq0UcfdaqnpKREU6ZMUaNGjdSsWTPNmjXL8d7tt98uSXrsscdks9kcr8uydu1aPfLII05tFa3hyy+/VJ06ddStWzfH7aO//e1v6tWrl/z8/HTPPffou+++09dff62IiAjVr19fDz74oH766Sen65g9e7ZatGghu92uu+++W5s3by63XkmKjo7WqVOntG3btmv2A2oSwg3gYU899ZSWL1/ueL1s2TKNGjWqVL8pU6Zo3bp1Wrlypfbs2aPWrVsrOjpaP//8c5nHzcjIUHR0tH73u9/p22+/VWJior744guNHz/e0ScmJkZr167VggULlJmZqSVLllRoBqQ8hYWFio2N1Y4dO/TVV1+pTZs2euihh1RYWOjUb+bMmRo8eLAyMjLKvNZ69erpnnvucZql2bZtm/r27asePXo42rOzs3XkyBH16dNHxhgNHDhQubm5SkpKUmpqqrp06aK+ffuWO0avv/66Vq9ereXLl+vLL79UQUFBmbeXVq5cqXr16umf//yn3njjDc2ePVvJycmS5AiYy5cvV05OzjUD544dOxQREeFSDZs2bdKgQYNUp87//7U9c+ZM/eEPf9CePXvk5eWlYcOGacqUKZo/f7527Nihw4cP6+WXX3b0nz9/vt5++2299dZb+vbb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", "text/plain": [ "
" ] @@ -933,30 +655,10 @@ "%matplotlib inline\n", "hdl = []\n", "hdl = []\n", - "for i in range(3): # perform reattachment n times for repeatability analysis\n", - "\n", - " fl = FragList(frag_list) # instantiate fraglist object\n", - "\n", - " fl.sort() # sort the fragments by number and type of cutting labels\n", - "\n", - " fl.pair_CL4s() # reattach 4-cutting label fragments to make 3-cutting label fragments\n", - "\n", - " fl.pair_CL3s() # reattach 3-cutting label fragments to make 2-cutting label fragments\n", - "\n", - " fl.update_lists() # add 1-cutting label fragments to either Rlist or Llist\n", - "\n", - " # grind the concentrations of fragments into smaller sub-concentrations\n", - " fl.grind_endcaps(grindsize=0.0005)\n", - "\n", - " fl.pair_endcaps() # pair together 1R and 1L fragments to make endcap pairs\n", - "\n", - " fl.grind_middles() # grind the concentrations of middle LR fragments into smaller sub-concentrations of same size as above\n", - "\n", - " fl.distribute_middles() # randomly select an endcap pair for each middle LR fragment\n", - "\n", - " # calculate and plot the molecular weight distribution of the resulting fragment groups\n", + "for i in range(3): \n", + " fl = FragList(frag_list)\n", + " fl.reattach(grindsize=0.001)\n", " fl.get_mwd(bins=range(0, 501, 15))\n", - "\n", " hdl.append(fl.histdata) # save histogram data for repeatability analysis\n", "\n" ] @@ -974,13 +676,13 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "id": "83a0e056-66dd-4e79-b4b0-f6b74c518a58", "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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9dVav359UAUDAIDuJTrQAcXFxVqwYIGKioo0btw4rVmzRjk5OTp8+LCGDRvW5php06bp448/1rp163TNNdeovr5e586d+8bFAwCAyOcwxphABowdO1ZjxozR6tWrfW0jR47U1KlTVVhY2Kr/q6++qrvvvlvHjh3TgAEDgirS6/XK5XLJ4/EoLi4uqOcItV27wnes7OzwHQsAgFDp6Od3QKdpmpubVVFRoaysLL/2rKwsHThwoM0xO3fuVHp6un7729/qiiuu0IgRI/TII4/o888/b/c4TU1N8nq9fhsAAOieAjpN09DQoJaWFsXHx/u1x8fHq66urs0xx44d0xtvvKHY2Fi9/PLLamho0OzZs/XJJ5+0e91IYWGhli1bFkhpAAAgQgV1AavD4fDbN8a0arvg/Pnzcjgc2rx5s2666SbdcccdWrFihTZu3Nju6khBQYE8Ho9vq62tDaZMAAAQAQJaGRk0aJCioqJarYLU19e3Wi25IDExUVdccYVcLpevbeTIkTLG6KOPPtK1117baozT6ZTT6QykNAAAEKECWhmJiYlRWlqaSktL/dpLS0uVmZnZ5phx48bp1KlTOnPmjK/tX//6l3r16qWhQ4cGUTIAAOhOAj5Nk5+fr7Vr12r9+vU6cuSIFi5cqJqaGuXl5Un66hRLbm6ur/+MGTM0cOBA3XfffTp8+LDKysr06KOP6v7771efPn1C90oAAEBECvh7RqZPn67Tp09r+fLlcrvdSk1NVUlJiYYPHy5Jcrvdqqmp8fW/7LLLVFpaqoceekjp6ekaOHCgpk2bpieeeCJ0rwIAAESsgL9nxAa+ZyR8xwIAIFQ65XtGAAAAQo0wAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKuCCiNFRUVKSUlRbGys0tLStG/fvg6N279/v6Kjo3XjjTcGc1gAANANBRxGiouLtWDBAi1evFiVlZUaP368cnJyVFNT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ur7CwkJ973vfU79+/TRkyBBNnTpV77//vl8f5jo0Vq9erRtuuMH3ZU8ZGRn629/+5nucee48hYWFcjgcWrBgga+N+Q6dpUuXyuFw+G0JCQm+x63Otemhtm7danr37m3++Mc/msOHD5v58+ebvn37mhMnTtguLaKUlJSYxYsXm23bthlJ5uWXX/Z7/MknnzT9+vUz27ZtM9XV1Wb69OkmMTHReL1eX5+8vDxzxRVXmNLSUnPw4EEzYcIEM2rUKHPu3Lkwv5quKzs722zYsMG89957pqqqykyePNkMGzbMnDlzxteHuQ6NnTt3mr/+9a/m/fffN++//7557LHHTO/evc17771njGGeO8s///lPc+WVV5obbrjBzJ8/39fOfIfOkiVLzHXXXWfcbrdvq6+v9z1uc657bBi56aabTF5enl/bd77zHbNo0SJLFUW+r4eR8+fPm4SEBPPkk0/62r744gvjcrnMc889Z4wx5tNPPzW9e/c2W7du9fU5efKk6dWrl3n11VfDVnukqa+vN5LM3r17jTHMdWe7/PLLzdq1a5nnTtLY2GiuvfZaU1paam699VZfGGG+Q2vJkiVm1KhRbT5me6575Gma5uZmVVRUKCsry689KytLBw4csFRV93P8+HHV1dX5zbPT6dStt97qm+eKigp9+eWXfn2SkpKUmprKv8VFeDweSdKAAQMkMdedpaWlRVu3btXZs2eVkZHBPHeSOXPmaPLkybr99tv92pnv0Dt69KiSkpKUkpKiu+++W8eOHZNkf66D+tXeSNfQ0KCWlpZWP+4XHx/f6kf9ELwLc9nWPJ84ccLXJyYmRpdffnmrPvxbtM0Yo/z8fN1yyy1KTU2VxFyHWnV1tTIyMvTFF1/osssu08svv6zvfve7vv/gMs+hs3XrVh08eFBvv/12q8d4X4fW2LFjtWnTJo0YMUIff/yxnnjiCWVmZurQoUPW57pHhpELHA6H374xplUbvrlg5pl/i/bNnTtX7777rt54441WjzHXofHtb39bVVVV+vTTT7Vt2zbNnDlTe/fu9T3OPIdGbW2t5s+fr927dys2Nrbdfsx3aOTk5Pj+9/XXX6+MjAxdffXV+tOf/qSbb75Zkr257pGnaQYNGqSoqKhWSa6+vr5VKkTwLlylfbF5TkhIUHNzs/773/+22wf/56GHHtLOnTv12muvaejQob525jq0YmJidM011yg9PV2FhYUaNWqUnn76aeY5xCoqKlRfX6+0tDRFR0crOjpae/fu1TPPPKPo6GjffDHfnaNv3766/vrrdfToUevv7R4ZRmJiYpSWlqbS0lK/9tLSUmVmZlqqqvtJSUlRQkKC3zw3Nzdr7969vnlOS0tT7969/fq43W699957/Fv8P8YYzZ07V9u3b9eePXuUkpLi9zhz3bmMMWpqamKeQ2zixImqrq5WVVWVb0tPT9fPfvYzVVVV6aqrrmK+O1FTU5OOHDmixMRE++/tb3T5awS7cGvvunXrzOHDh82CBQtM3759zb///W/bpUWUxsZGU1lZaSorK40ks2LFClNZWem7RfrJJ580LpfLbN++3VRXV5uf/vSnbd4qNnToUPP3v//dHDx40Nx2223clvc1v/jFL4zL5TKvv/663215n332ma8Pcx0aBQUFpqyszBw/fty8++675rHHHjO9evUyu3fvNsYwz53t/99NYwzzHUoPP/ywef31182xY8fMW2+9Ze68807Tr18/3+eezbnusWHEGGOeffZZM3z4cBMTE2PGjBnju00SHffaa68ZSa22mTNnGmO+ul1syZIlJiEhwTidTvP973/fVFdX+z3H559/bubOnWsGDBhg+vTpY+68805TU1Nj4dV0XW3NsSSzYcMGXx/mOjTuv/9+338XBg8ebCZOnOgLIsYwz53t62GE+Q6dC98b0rt3b5OUlGR+8pOfmEOHDvketznXDmOM+WZrKwAAAMHrkdeMAACAroMwAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwKr/AccZN27BrqREAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -1006,10 +708,458 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 10, "id": "c2b46571-b217-4962-9578-631740a17466", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "species mole percent\n", + "C.......................................................................................................24.35%\n", + "C=CC....................................................................................................20.65%\n", + "miscillaneous large molecules............................................................................9.93%\n", + "CCC......................................................................................................1.39%\n", + "C=CC=CC..................................................................................................1.29%\n", + "C=CCCC...................................................................................................1.09%\n", + "C=CCC(C)C=CC.............................................................................................1.06%\n", + "C=C(C)C=CC...............................................................................................0.84%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.....................................................................0.77%\n", + "CC=CCC...................................................................................................0.77%\n", + "C=C(C)CCC................................................................................................0.76%\n", + "CC=CC(C)CCC..............................................................................................0.74%\n", + "C=CCC(C)CC(C)CC(C)CCC....................................................................................0.71%\n", + "C=CCC(=C)C...............................................................................................0.67%\n", + "C=CCC=C..................................................................................................0.66%\n", + "C=C(C)C...................................................................................................0.6%\n", + "CC=CC(C)C=CC.............................................................................................0.59%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...............................................................0.58%\n", + "CC1=CCCC1................................................................................................0.57%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC..................................................................0.55%\n", + "CCCCC....................................................................................................0.52%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.................................................................0.5%\n", + "C=C(C)CC(C)C=CC..........................................................................................0.49%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C........................................................................0.45%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC............................................................0.45%\n", + "C=CCC(C)CC(C)CC(C)CC(C)C=CC..............................................................................0.44%\n", + "CC=CC(C)C................................................................................................0.44%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC....................................................................0.42%\n", + "C=C(C)CC(C)CC(C)CC(C)CCC.................................................................................0.42%\n", + "C=CCC(C)CCC..............................................................................................0.41%\n", + "C=CCC(C)CC(=C)C..........................................................................................0.41%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC......................................................................0.4%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CCC................................................................................0.4%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.......................................................0.4%\n", + "CCCC(C)CC(C)CC(C)C.......................................................................................0.39%\n", + "CC1=CC=CC1...............................................................................................0.39%\n", + "C=CCC(C)CC(C)CC(C)C......................................................................................0.38%\n", + "C=C(C)CC(C)CCC...........................................................................................0.38%\n", + "CC=CC(C)CC(C)CC(C)CCC....................................................................................0.38%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.......................................................................0.37%\n", + "CCCC(C)CC(C)CC(C)CCC.....................................................................................0.37%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.................................................................0.36%\n", + "CC=CC(C)CC(C)CC(C)CC(C)C.................................................................................0.35%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC......................................................................0.35%\n", + "CC=CC(C)CC(C)C=CC........................................................................................0.34%\n", + "C=CCC(C)CC(C)CC(C)C=CC...................................................................................0.34%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.................................................................0.33%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC................................................0.33%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...................................................0.32%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)C=CC...........................................................................0.32%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.....................................................0.31%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C....................................................................0.29%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(=C)C...........................................................................0.28%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..................................................................0.28%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.........................................................0.28%\n", + "CC1=CCC=C1...............................................................................................0.28%\n", + "C=C(C)CC(C)CC(C)CC(C)C=CC................................................................................0.28%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.................................................0.25%\n", + "C=CCC(C)CC(C)CC(C)CC=C...................................................................................0.25%\n", + "C=CCC(C)CC(C)C=CC........................................................................................0.25%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C............................................................0.24%\n", + "C=CCC(C)CC(C)CC(C)CC(=C)C................................................................................0.24%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...............................................................0.24%\n", + "C=C(C)CC(C)CC(C)C=CC.....................................................................................0.24%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.........................................................................0.24%\n", + "C=C(C)CC(C)C.............................................................................................0.22%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C....................................................................0.22%\n", + "C=CCC(C)C................................................................................................0.22%\n", + "C=C(C)CC(C)CC(C)CC(C)C...................................................................................0.21%\n", + "C=CCC(C)CC(C)CC(C)CC(C)C.................................................................................0.21%\n", + "C=CCC(C)CC=C.............................................................................................0.21%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC......................................................0.21%\n", + "C=C(C)CC(=C)C............................................................................................0.21%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.........................................................0.2%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...........................................................0.2%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.............................................0.19%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.............................................................0.19%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC................................................................0.19%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C..................................................0.19%\n", + "C1=CCCC1.................................................................................................0.18%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CCC...............................................................................0.18%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(=C)C.............................................................................0.17%\n", + "C=C(C)CC(C)CC(=C)C.......................................................................................0.17%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC..........................................................0.17%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C........................................................................0.17%\n", + "CCC=C(C)C................................................................................................0.17%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC..................................................0.16%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)C=CC.........................................................................0.16%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.......................................................0.16%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...................................................0.16%\n", + "CC=CC(C)CC(C)CC(C)CC(C)C=CC..............................................................................0.16%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..................................................................0.16%\n", + "CC=CC(C)CC(C)C...........................................................................................0.16%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...........................................0.16%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC................................................0.15%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.........................................................0.15%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C..............................................................0.14%\n", + "CC=CC(C)CC(C)CCC.........................................................................................0.14%\n", + "C=C......................................................................................................0.13%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.............................................0.13%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CCC............................................................................0.12%\n", + "C1=CCC=C1................................................................................................0.12%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC..............................................0.12%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC=C..............................................................................0.11%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.......................................................0.11%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C.....................................................0.11%\n", + "CCCC(C)C.................................................................................................0.11%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC......................................................................0.11%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.....................................................0.11%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C................................................................0.1%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..............................................................0.1%\n", + "C=CC=CCC=C................................................................................................0.1%\n", + "C=CCC(C)CC(C)C............................................................................................0.1%\n", + "CC=CC(C)=CCC..............................................................................................0.1%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.........................................0.1%\n", + "CCC=C(C)CCC...............................................................................................0.1%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.................................................0.09%\n", + "C=C(C)CC(C)=CCC..........................................................................................0.09%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...............................................................0.09%\n", + "C=C(C)C=C(C)C............................................................................................0.09%\n", + "C=CCC(C)CC(C)CC(=C)C.....................................................................................0.09%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..............................................0.09%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...................................................0.09%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C....................................................................0.09%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.................................................................0.09%\n", + "CC(C)C...................................................................................................0.09%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)C............................................................................0.09%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C..........................................0.09%\n", + "CC=CCC(C)CC(C)CC(C)C.....................................................................................0.09%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C................................................0.09%\n", + "C=CC=CCC(=C)C............................................................................................0.08%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C................................................0.08%\n", + "C=CC=CC=CC...............................................................................................0.08%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C......................................................................0.08%\n", + "C=C(C)CC(C)CC(C)C........................................................................................0.07%\n", + "CC=CC(C)CC(C)=CCC........................................................................................0.07%\n", + "CCC(C)CC(C)CC(C)C........................................................................................0.07%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...........................................................0.07%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...........................................0.07%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C..............................................................0.07%\n", + "CC=CC(C)C=C(C)C..........................................................................................0.07%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C...............................................0.07%\n", + "CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.....................................................................0.07%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.................................................................0.07%\n", + "C=CC=C(C)C...............................................................................................0.06%\n", + "C=CCC(C)CC(C)CC=C........................................................................................0.06%\n", + "C=CCC(C)CC(C)CC(C)C=C(C)C................................................................................0.06%\n", + "C=CC=CCC(C)C=CC..........................................................................................0.06%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)=CCC...........................................................................0.06%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)C=CC...........................................................................0.06%\n", + "C=CCC(C)CC(C)CC(C)CC(C)=CCC..............................................................................0.06%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC...............................................................0.05%\n", + "CC(C)CC(C)C..............................................................................................0.05%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC............................................0.05%\n", + "CC=CC(C)CCC(C)CC(C)CC(C)C................................................................................0.05%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C............................................................0.05%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.................................................................0.05%\n", + "C=C(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C...................................................................0.05%\n", + "C=C(C)C=CCCC.............................................................................................0.05%\n", + "C=CC=CCCC................................................................................................0.05%\n", + "C=CCC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C......................................................................0.05%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)C............................................................................0.05%\n", + "CC=CC(C)CC(C)CC(C)CC(C)=CCC..............................................................................0.05%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC................................................................0.05%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C..............................................................0.05%\n", + "CCCC(C)CC(C)CC(C)CC(C)C..................................................................................0.05%\n", + "CCC=C(C)CC(C)CC(C)CC(C)C.................................................................................0.05%\n", + "CC=CC(C)CC(C)CC(C)C......................................................................................0.05%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.....................................................0.05%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C...............................................0.05%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.......................................................0.05%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C............................................................0.05%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C.................................................................0.05%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC..................................................................0.05%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.............................................................0.04%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C..................................................................0.04%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC............................................................0.04%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CCC...............................................................................0.04%\n", + "C=CCC(C)CC(C)CCC.........................................................................................0.04%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC..........................................................0.04%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.......................................................0.04%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...........................................................0.04%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)C..............................................................................0.04%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC....................................................................0.04%\n", + "C=CC=CCC(C)CC(=C)C.......................................................................................0.04%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...................................................................0.04%\n", + "C=CC=CCC(C)CC(C)CC(C)C=CC................................................................................0.04%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.............................................................0.04%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.........................................0.04%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C........................................0.04%\n", + "CC=CC(C)CC(C)C=C(C)C.....................................................................................0.04%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)C................................................................................0.04%\n", + "CC(C)CC(C)CC(C)CC(C)C....................................................................................0.04%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC..................................................0.04%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC...............................................................0.04%\n", + "CCCCC(C)CC(C)CC(C)C......................................................................................0.04%\n", + "CC(C)=CC(C)C.............................................................................................0.03%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC.................................................0.03%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...................................................0.03%\n", + "C=CCCC(C)CC(C)CC(C)C.....................................................................................0.03%\n", + "CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..........................................................0.03%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C....................................................0.03%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..........................................0.03%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(=C)C........................................................................0.03%\n", + "C=CCC(C)CC(C)=CCC........................................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.......................................................................0.03%\n", + "C=C1C=CCC1...............................................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC................................................0.03%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C........................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)=CCC...................................................................................0.03%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C...................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.........................................0.03%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C........................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC...........................................0.03%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.....................................................0.03%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C...................................................0.03%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(=C)C.............................................................................0.03%\n", + "C=CC=CCC(C)CC(C)CC(C)C...................................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC......................................0.03%\n", + "CCCC(C)CC(C)C............................................................................................0.03%\n", + "C=C(C)CC(C)CC(C)CC(C)C=C(C)C.............................................................................0.03%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...................................................0.03%\n", + "C=CCC(C)C=C(C)C..........................................................................................0.03%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.........................................................................0.03%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C......................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.......................................................0.03%\n", + "CCCC(C)CC(C)CC(C)C=C(C)C.................................................................................0.03%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.............................................0.03%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C......................................0.02%\n", + "C=C(C)CC(C)CC(C)C=C(C)C..................................................................................0.02%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.........................................................0.02%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..........................................................0.02%\n", + "CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.........................................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC................................................0.02%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)C..............................................................................0.02%\n", + "C=C(C)C=CCC(=C)C.........................................................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)C=C(C)C...........................................................................0.02%\n", + "C=C(C)CC(C)C=C(C)C.......................................................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC......................................0.02%\n", + "C=C(C)C=CCC(C)C=CC.......................................................................................0.02%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.........................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C...........................................0.02%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)C.........................................................................0.02%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...............................................0.02%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...............................................................0.02%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C..................................................0.02%\n", + "CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C......................................................0.02%\n", + "CC=CC(C)CC(C)CC(C)C=CC...................................................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC=C.........................................................................0.02%\n", + "CCCC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.......................................................................0.02%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C........................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC............................................0.02%\n", + "C=CC=CCC(C)CC(C)CC(C)CC=C................................................................................0.02%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C............................................0.02%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC..............................................................0.02%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C...............................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C..........................................................0.02%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC............................................................0.02%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC.......................................................0.02%\n", + "C=C(C)CCC(C)CC(C)CC(C)C..................................................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..............................................0.02%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.....................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C........................................0.02%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC.............................................0.02%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(=C)C.....................................................................0.02%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..........................................................0.02%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C..................................................0.02%\n", + "C=C(C)CC(C)CC(C)=CCC.....................................................................................0.02%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)=CCC.........................................................................0.02%\n", + "C=CCC(C)=CCC.............................................................................................0.02%\n", + "C=CC=C(C)CC(C)CC=C.......................................................................................0.02%\n", + "C=C(C)C=CCC(C)CC(=C)C....................................................................................0.02%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)=CCC...........................................................................0.02%\n", + "CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C................................................................0.02%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.........................................................0.02%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC=CC..................................................................0.02%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...............................................................0.02%\n", + "C=CCC(C)CC=CC............................................................................................0.02%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.......................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC...........................................0.01%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CCC..............................................................................0.01%\n", + "CCCC(C)=CC(C)C...........................................................................................0.01%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...............................................0.01%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.....................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)C=C(C)C.............................................................................0.01%\n", + "CC=CC(C)=CC(C)CC(C)CC(C)CC(C)C=CC........................................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C..................................................0.01%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C....................................................0.01%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC=C.............................................................................0.01%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)C................................................................................0.01%\n", + "CCCC(C)C=C(C)C...........................................................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.............................................0.01%\n", + "CCCC(C)CC(C)CC(C)C1C=CC=C1C..............................................................................0.01%\n", + "CCCC(C)CCC...............................................................................................0.01%\n", + "CC(C)=CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C...................................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C..........................................0.01%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...............................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC..........................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CCC..........................................................................0.01%\n", + "C=CCC=CC(=C)C............................................................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC........................................0.01%\n", + "C=CCC=CC.................................................................................................0.01%\n", + "C=C(C)C=C(C)C=CC.........................................................................................0.01%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.................................................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)C..............................................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.................................................................0.01%\n", + "C=CCC(C)CC(C)C=C(C)C.....................................................................................0.01%\n", + "CC=CC(C)=CC(C)C=CC.......................................................................................0.01%\n", + "C=CC=C(C)C=CC............................................................................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C..........................................0.01%\n", + "CCC=C(C)CC(C)CC(C)CC(C)C=C(C)C...........................................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)=CCC.........................................................................0.01%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC...........................................0.01%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C....................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.....................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...................................0.01%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..............................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C....................................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C..............................................................0.01%\n", + "C=C(C)CCC=CC.............................................................................................0.01%\n", + "C=C1CC=CC1...............................................................................................0.01%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C..............................................0.01%\n", + "C=CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C..................................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...........................................0.01%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)C.............................................................................0.01%\n", + "C=CCC(C)=CC(C)C..........................................................................................0.01%\n", + "C=CCC(C)CC=CC(=C)C.......................................................................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC............................................................0.01%\n", + "CCC=C(C)C=C(C)C..........................................................................................0.01%\n", + "C=CC=CC(C)CC(C)CC(C)CC=C.................................................................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)CCC.................................................................................0.01%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C...................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C..............................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(=C)C..................................................................................0.01%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.............................................0.01%\n", + "C=C(C)CC(C)CCC(C)CC(C)CC(C)C.............................................................................0.01%\n", + "CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...................................................................0.01%\n", + "C=CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...................................................................0.01%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C...............................................0.01%\n", + "CCC=C(C)CC(C)C...........................................................................................0.01%\n", + "C=CC=C(C)CC=C............................................................................................0.01%\n", + "C=CC=C(C)CC(C)C=CC.......................................................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=CC(=C)C..............................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C...................................0.01%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C......................................................0.01%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC....................................................................0.01%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CCC..........................................................................0.01%\n", + "CCCC(C)CC(C)CC(C)CC(C)C=C(C)C............................................................................0.01%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C...........................................................0.01%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C................................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=CC...................................................................0.01%\n", + "CCC=CCC(C)C=CCC(C)C......................................................................................0.01%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..................................................0.01%\n", + "CC=CC....................................................................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=CC................................................................0.01%\n", + "C=CCC(C)C(C)CC=C.........................................................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C....................................................0.01%\n", + "C=C(C)C=CC=C(C)C.........................................................................................0.01%\n", + "CCC=C(C)CCC(C)CC(C)CC(C)C................................................................................0.01%\n", + "C=CC=C(C)CC(=C)C.........................................................................................0.01%\n", + "CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.................................................0.01%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC................................................0.01%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC.............................................0.01%\n", + "C=CC=CC=C(C)C............................................................................................0.01%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C......................................................................0.01%\n", + "C=C(C)C=CC=CC............................................................................................0.01%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C....................................0.01%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC=CC...................................................0.01%\n", + "CCC=C(C)CC(C)CC(C)C......................................................................................0.01%\n", + "C=CC=CC=CCCC=CC=CC=C......................................................................................0.0%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.....................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=CC(=C)C...........................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=CC.....................................................0.0%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.........................................0.0%\n", + "CCCC(C)CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC...............................................................0.0%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC......................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=CC(=C)C................................................0.0%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C..............................................0.0%\n", + "CCCC(C)CC=CC(C)CC(C)CC(C)CCC..............................................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC=CC(=C)C..............................................................................0.0%\n", + "CC=CC(C)CC(C)CC(C)CC(C)C=C(C)C............................................................................0.0%\n", + "CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C............................................0.0%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C................................................0.0%\n", + "C=CC=CCC(C)C..............................................................................................0.0%\n", + "CC=CC=CC..................................................................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C=CC................................................0.0%\n", + "CC=CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC....................................................0.0%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C....................................................................0.0%\n", + "C=C(C)CC(C)CC(C)CC(C)CC=CC................................................................................0.0%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...........................................0.0%\n", + "CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C............................................0.0%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC...........................................................0.0%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C................................0.0%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC..........................................................0.0%\n", + "CCC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.............................................................0.0%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C.........................................0.0%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..................................0.0%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C................................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CCC(C)CC(C)CC(C)C...................................................0.0%\n", + "CC=CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC...................................................................0.0%\n", + "CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.......................................................................0.0%\n", + "C=C(C)CC(C)CC(C)C(C)CC(C)C(C)CCC..........................................................................0.0%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CCC...............................................................................0.0%\n", + "CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CC(C)C..............................................0.0%\n", + "C=CC=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C....................................................0.0%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C...................................................0.0%\n", + "C=C(C)CC(C)CC(C)C(C)CC(C)C(C)CC(C)C(C)CCC.................................................................0.0%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.............................................0.0%\n", + "CC=CC(C)C1C=CC=C1C........................................................................................0.0%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C.............................................................0.0%\n", + "CCCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C1C=CC=C1C................................................................0.0%\n", + "C=CCCC=C..................................................................................................0.0%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C....................................0.0%\n", + "CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C........................................................0.0%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC=C...............................................................0.0%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C..................................................................0.0%\n", + "CC=CC(C)=CC(C)CC(C)C=CC...................................................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C.........................................0.0%\n", + "CC=CC(C)=CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=CC..........................................................0.0%\n", + "CCC=CCC(C)C=CCC(C)C=CCC(C)C...............................................................................0.0%\n", + "C=C1C=CC=C1...............................................................................................0.0%\n", + "C=CCC(C)CC(C)CC(C)CCC=CC..................................................................................0.0%\n", + "CC=CCC(C)CC(C)CC(C)C=CC...................................................................................0.0%\n", + "C=CC=CC(C)CC(C)CC(C)CCC...................................................................................0.0%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)=CCC.......................................................................0.0%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)C=CC..............................................................................0.0%\n", + "C=CC=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C.............................................0.0%\n", + "C=CC=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C.......................................0.0%\n", + "C=C(C)C=CCC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(=C)C........................................0.0%\n", + "C=CCC(C)CCC(=C)C..........................................................................................0.0%\n", + "C=C(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)CC(C)C=C(C)C=CC........................................0.0%\n", + "C=CCC(C=C)CC..............................................................................................0.0%\n", + "C=CC=C(C)CCC(C)CC(C)=CC=C.................................................................................0.0%\n", + "C=CC=CCCC=CC=C............................................................................................0.0%\n", + "CC(C)CCC(C)CC(C)CC(C)C....................................................................................0.0%\n", + "CC1=CC(C2C=C(C)CC2)CC1....................................................................................0.0%\n", + "C=CC=CCCC=C...............................................................................................0.0%\n", + "C=CCCC1=CC=CC1............................................................................................0.0%\n" + ] + } + ], "source": [ "results_dictionary = {}\n", "for fraglist, amt in fl.grouped:\n", @@ -1031,51 +1181,6 @@ " print(str(x).ljust(80, '.') +\n", " str(str(np.round(y/total*100, 2))+'%').rjust(30, '.'))" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57e2ce0d-875f-4dcf-9927-4dc0b4d6481f", - "metadata": {}, - "outputs": [], - "source": [ - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ebff6236-0ccf-442d-965f-03b555db725a", - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "19573d77-561a-4863-8fba-918da68b652b", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "628e779b-acba-45e6-a864-744c1eb4db91", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "357db984-42cd-4acd-9e27-bd82b8873df4", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/rmgpy/molecule/fragment_utils.py b/rmgpy/molecule/fragment_utils.py new file mode 100644 index 0000000000..25fe5e5cb5 --- /dev/null +++ b/rmgpy/molecule/fragment_utils.py @@ -0,0 +1,312 @@ +from rmgpy.molecule.fragment import Fragment +from rmgpy.tools.canteramodel import Cantera +from rmgpy.chemkin import load_chemkin_file +import re +import os +import numpy as np +import matplotlib.pyplot as plt + + +def match_sequences(seq1, seq2, rtol=1e-6): + ''' + Given two lists (each item is int or float): + seq1 and seq2 with same sum, the method returns + matched indices and values. + Example: + seq1 = [1, 3, 1] + seq2 = [2, 1, 2] + return: [[(0,0),1], + [(1,0),1], + [(1,1),1], + [(1,2),1], + [(2,2),1]] + ''' + sum_diff = sum(seq2) - sum(seq1) + assert ( + np.isclose(sum(seq1), sum(seq2), rtol=rtol) + ), "seq1 has different sum (diff={0}) than seq2.".format(sum_diff) + + # force the sum to be same if the difference + # is small enough + if sum_diff >= 0: + seq1[-1] = seq1[-1] + sum_diff + else: + seq2[-1] = seq2[-1] - sum_diff + + # make cumulative sequences + cum_seq1 = np.cumsum(seq1) + cum_seq2 = np.cumsum(seq2) + + # add index tags two both cumulative seqs + pin1 = 0 + pin2 = 0 + matched_indices = [] + matched_cum_values = [] + while pin1 < len(cum_seq1) and pin2 < len(cum_seq2): + matched_indices.append((pin1, pin2)) + + if cum_seq1[pin1] > cum_seq2[pin2]: + matched_cum_values.append(cum_seq2[pin2]) + pin2 += 1 + elif cum_seq1[pin1] < cum_seq2[pin2]: + matched_cum_values.append(cum_seq1[pin1]) + pin1 += 1 + else: + matched_cum_values.append(cum_seq2[pin2]) + pin1 += 1 + pin2 += 1 + + # get matches + matches = [] + for i in range(len(matched_indices)): + matched_index_tup = matched_indices[i] + matched_cum_value = matched_cum_values[i] + if i == 0: + previous_cum_value = 0 + else: + previous_cum_value = matched_cum_values[i - 1] + + matches.append( + [matched_index_tup, matched_cum_value - previous_cum_value]) + + return matches + + +def match_concentrations_with_same_sums(conc1, conc2, rtol=1e-6): + '''match_concentrations_with_same_sums + Given two lists with each item to be a tuple + (species label, concentration) + conc1 and conc2 with same total concentrations, + the method returns matched species labels and + concentrations. + Example: + conc1 = [('a', 1), + ('b', 3), + ('c', 1)] + conc2 = [('x', 2), + ('y', 1), + ('z', 2)] + return: [(('a','x'),1), + (('b','x'),1), + (('b','y'),1), + (('b','z'),1), + (('c','z'),1)] + ''' + labels1 = [tup[0] for tup in conc1] + labels2 = [tup[0] for tup in conc2] + + seq1 = [tup[1] for tup in conc1] + seq2 = [tup[1] for tup in conc2] + + matches_seq = FragList.match_sequences(seq1, seq2, rtol) + + matches_conc = [] + for match_seq in matches_seq: + matched_label_index1 = match_seq[0][0] + matched_label_index2 = match_seq[0][1] + matched_value = match_seq[1] + + matched_label1 = labels1[matched_label_index1] + matched_label2 = labels2[matched_label_index2] + match_conc = ((matched_label1, matched_label2), matched_value) + matches_conc.append(match_conc) + return matches_conc + + +def match_concentrations_with_different_sums(conc1, conc2): + """ + Given two lists with each item to be a tuple + (species label, concentration) + conc1 and conc2 with different total concentrations, + the method returns matched species labels and + concentrations. + Example: + conc1 = [('a', 1), + ('b', 3), + ('c', 1)] + conc2 = [('x', 2), + ('y', 1), + ('z', 10)] + return: [(('a','x', 'z', 'z'),1), + (('b','x', 'z', 'z'),1), + (('b','y', 'z', 'z'),1), + (('b','z', 'z'),1), + (('c','z', 'z'),1)] + """ + labels1 = [tup[0] for tup in conc1] + labels2 = [tup[0] for tup in conc2] + + seq1 = [tup[1] for tup in conc1] + seq2 = [tup[1] for tup in conc2] + + matches_conc = [] + pin1 = 0 + pin2 = 0 + val1 = seq1[pin1] + val2 = seq2[pin2] + + while True: + if val1 > val2: + match = ((labels1[pin1], labels2[pin2]), val2) + matches_conc.append(match) + val1 = val1 - val2 + pin2 += 1 + if pin2 == len(seq2): + break + val2 = seq2[pin2] + elif val1 < val2: + match = ((labels1[pin1], labels2[pin2]), val1) + matches_conc.append(match) + val2 = val2 - val1 + pin1 += 1 + if pin1 == len(seq1): + break + val1 = seq1[pin1] + else: + match = ((labels1[pin1], labels2[pin2]), val1) + matches_conc.append(match) + pin1 += 1 + pin2 += 1 + if pin1 == len(seq1): + break + val1 = seq1[pin1] + if pin2 == len(seq2): + break + val2 = seq2[pin2] + + # if pin2 first reaches the end + # append all the remaining seq1 to matches_conc + if pin2 == len(seq2) and pin1 < len(seq1): + remain_conc1 = [(labels1[pin1], val1)] + conc1[(pin1 + 1):] + matches_conc.extend(remain_conc1) + + # if pin1 first reaches the end + # let matches_conc match with remaining seq2 + elif pin1 == len(seq1) and pin2 < len(seq2): + remain_conc2 = [(labels2[pin2], val2)] + conc2[(pin2 + 1):] + matches_conc = FragList.match_concentrations_with_different_sums( + matches_conc, remain_conc2 + ) + + # if pin1 and pin2 reach the ends at same time + # matches_conc is ready to return + return matches_conc + + +def shuffle(conc, seed=None): + """ + Randomly shuffle a list of fragments + """ + idx_arr = np.arange(len(conc)) + + if seed is not None: + np.random.seed(seed) + np.random.shuffle(idx_arr) + + return [conc[idx] for idx in idx_arr] + + +def flatten(combo): + """ + Given a combo nested `tuple`, e.g., + ((('LY', 'XR'), ('LWL', 'RUR')) + return a list of labels contained in + the combo ['LY', 'XR', 'LWL', 'RUR'] + """ + return_list = [] + for i in combo: + if isinstance(i, tuple): + return_list.extend(FragList.flatten(i)) + else: + return_list.append(i) + return return_list + + +# label should match the desired merging l/'abel on frag2 +def merge_frag_to_frag(frag1, frag2, label): + from rmgpy.molecule import Bond + from rmgpy.molecule.fragment import Fragment, CuttingLabel + + frag_spe1 = Fragment().from_smiles_like_string(frag1) + frag_spe2 = Fragment().from_smiles_like_string(frag2) + # find position of desired CuttingLabel + # need to find CuttingLabel on frag2 first + for vertex in frag_spe2.vertices: + if isinstance(vertex, CuttingLabel): + if vertex.symbol == label: + cut2 = vertex + + atom2 = list(cut2.edges.keys())[0] + frag_spe2.remove_atom(cut2) + break + + if cut2.symbol[0] == 'L': + Ctl = cut2.symbol.replace('L', 'R') + else: # that means this CuttingLabel is R something + + Ctl = cut2.symbol.replace('R', 'L') + + # merge to frag_spe1 + for vertex in frag_spe1.vertices: + if isinstance(vertex, CuttingLabel): + if vertex.symbol == Ctl: + cut1 = vertex + atom1 = list(cut1.edges.keys())[0] + frag_spe1.remove_atom(cut1) + break + + # new merged fragment + new_frag = frag_spe1.merge(frag_spe2) + new_frag.add_bond(Bond(atom1=atom1, atom2=atom2, order=1)) + new_frag = new_frag.copy(deep=True) + new_frag.update() + return new_frag # return Fragment obtl + + +def merge_frag_list(to_be_merged): + import os + # merges fragments in list from right to left + species_list = [] + ethylene = [] + newlist = [] + warnings = [] + + while len(to_be_merged) > 1: + + # second to last fragmentin list + frag1 = to_be_merged[-2].smiles + frag2 = to_be_merged[-1].smiles # last fragment in list + + if 'R' in frag1 and 'L' in frag2: + newfrag = FragList.merge_frag_to_frag(frag1, frag2, 'L') + + elif 'L' in frag1 and 'R' in frag2: + newfrag = FragList.merge_frag_to_frag(frag1, frag2, 'R') + + # warn user if last two fragments in list cannot be merged (no R/L + # combo to be made) + else: + print('Warning! Could not merge fragments {} and {}'.format( + frag1, frag2)) + + if 'L' in frag1 and 'L' in frag2: + newfrag = FragList.merge_frag_to_frag( + frag1.replace('L', 'R'), frag2, 'L') + if len(to_be_merged) > 2: + cut = len(to_be_merged) - 2 + newfraglist = to_be_merged[:cut] + + newfraglist.append(newfrag) + elif len(to_be_merged) == 2: + + newfraglist = [newfrag] + + to_be_merged = newfraglist + + to_be_merged = newfraglist + # newlist.append(newfraglist) # if done merging list, write final + # structure to list of smiles structures + + # print('{}% of fragments fully merged...'.format(np.round(100*(i+1)/len(flattened_matches_random)),1)) +# print(newfraglist) + return newfraglist