// ############################## START FUNC ############################################ function groups(atom_sorts, carbonyles, mconn, double_bond_atoms, fattyends, fatty, x, y, z, arom_atoms, ringatoms, arom_red) { // This function works by building strings which describes functional groups in a // linear fashion. To assure that each group will look the same from case to case, // it is necessary to fallow strict priority rules. The string will always be sent // to and linked to the neighbour atom of highest atom weight which is not yet in // the string. Double bonded neighbours and triple bonded neighbours are ranked lower // for the same atom weight. Theese priorities follows already from the listed order // of neighbours in the variable mconn, which must have been gone through the function // sort_connections before. The path will never be exactly repeated, and will go in the // reverse direction only once, when all other possibilities are exhausted. // Therefore, typical functional groups will look like in the function "recognize_features()". // Tracks can only begin with atoms that are neither non carbonyle carbons or hydrogenes. // Hydrogenes are not entranced from carbons. Carbons are always counted, but never passed // (see ether above) unless they are carbonyles (which in the list includes >C=S). All other // atoms are counted and passed by according to their connections. A return to a earlier // visited atom in the track is marked by "r". Arrivance from a double bonded neighbour to // a doule bonded atom is marked by "d". // Also note that an carbonyl acid may not have an hydrygen. Two patterns are needed. var compl=document.form1.compl.checked; var number_of_atoms = atom_sorts.length; var multitrackvector1 = new Array(number_of_atoms); var multitrackvector2 = new Array(number_of_atoms); for(n=0;n0 && multitrackvector1.join("")=="") break; for(n=0;n0) || (p==0 && atom_sorts[n]==1) || (p==0 && atom_sorts[n]==6 && !carbonyles.Check(n) && !fattyends.Check(n))) continue; // --------------------------------------------------------- path_by_path=multitrackvector1[n].split("#"); for(m=0;m"+mconn[n][q]+" "; back_direction=" "+mconn[n][q]+"->"+n+" "; // The while-loop below counts through all atom neighbours which can NOT possible continue when building the // string track. If a good neighbour is found, the action is handed over to *** marker ***. If however, none // atom neighbour is availible, the string is finished and stored on the actual atom, out_from_loop[n]. while(path_by_path[m].indexOf(actual_direction)>-1 || path_by_path[m].indexOf(back_direction)>-1 || check_arom(n,mconn[n][q],arom_red, path_by_path[m],atom_sorts) || path_by_path[m].indexOf("complex")==-1 && ((((atom_sorts[n]==6 && atom_sorts[mconn[n][q]]==6) || (atom_sorts[n]==6 && !carbonyles.Check(n))) && (path_by_path[m].indexOf("@@@")==-1 || (!fatty.Check([n]) || atom_sorts[mconn[n][q]]!=6))))){ if(path_by_path[m].indexOf(back_direction)>-1 && path_by_path[m].indexOf(actual_direction)==-1) next_neighbour=q; // The row above is important. If there are no other ways left, the string will be built in the back_direction, // but only if that direction has never been the actual_direction before. No exact repetitions. q++; if(q==mconn[n].length){ // --------------------- results stored ----------------------------- (if no way left) if(next_neighbour==-1) out_from_loop[n]=out_from_loop[n]+path_by_path[m]+"#"; // ------------------------------------------------------------------ if(next_neighbour!=-1) q=next_neighbour; break; } actual_direction=" "+n+"->"+mconn[n][q]+" "; back_direction=" "+mconn[n][q]+"->"+n+" "; } actual_direction=" "+n+"->"+mconn[n][q]+" "; // q may have changed back_direction=" "+mconn[n][q]+"->"+n+" "; if(q0){ xyzpath[0]=parseInt(parseFloat(xyzpath[0])*1000+parseFloat(x[n])*1000*atom_sorts[n])/1000; xyzpath[1]=parseInt(parseFloat(xyzpath[1])*1000+parseFloat(y[n])*1000*atom_sorts[n])/1000; xyzpath[2]=parseInt(parseFloat(xyzpath[2])*1000+parseFloat(z[n])*1000*atom_sorts[n])/1000; xyzpath[3]=parseInt(xyzpath[3])+parseInt(atom_sorts[n]); // Explicit instead of counting splits "*" and "r", if(xyzpath[4]!="complex"){ if(ringatoms.indexOf(" "+n+" ")>-1 && xyzpath[4]=="n") xyzpath[4]="r"; // && to be safe if(arom_atoms.indexOf(" "+n+" ")>-1 && xyzpath[4]!="i") xyzpath[4]="y"; if(ringatoms.indexOf(" "+n+" ")>-1 && carbonyles.Check(n)) xyzpath[4]="i"; } } path_by_path[m]=xyzpath.join("£"); multitrackvector2[mconn[n][q]]=multitrackvector2[mconn[n][q]]+path_by_path[m]+actual_direction; if(path_by_path[m].indexOf(back_direction)>-1) multitrackvector2[mconn[n][q]]=multitrackvector2[mconn[n][q]]+" r "; if(double_bond_atoms.Check(n) && double_bond_atoms.Check(mconn[n][q])) multitrackvector2[mconn[n][q]]=multitrackvector2[mconn[n][q]]+" d "; multitrackvector2[mconn[n][q]]=multitrackvector2[mconn[n][q]]+"#"; } // !!!!!!!!!!!!!!!! if ends !!!!!!!!!!!!!!!! } } for(n=0;n" for each step is for the eye, if one want to check how the strings are // builded for a couple of loops and within the subroutine. For replacement of each atom-ID with its // atom_sort (which makes the functional groups) all atoms must be surrounded by blanks. vector_prepare_result=string_prepare_result.split("->"); string_prepare_result=vector_prepare_result.join(" "); for(n=0;n