#! ./perl #************************************************************************ #* * #* Perl script: mr_rogers_proc * #* * #************************************************************************ #* #* G.D. Searle & Co. #* #* #* Date: 4/10/96 #* Programmer: Tom Doman #* Modified by: #* 7/96, 8/96 - mjc #* Extensive modifications to the program. #* - Base URL's defined at the top #* - Administrator name/email defined at the top #* - Encryption table definition and basic #* encryption and decryption functions. #* - Daylight environment checking #* - Database information associative arrays #* - Computation of database size and last date #* modified. Passing of information on to next #* call of page. #* - Added neighbor thresholds. #* - Compound and structure table and passing of #* the chosen compounds and their smiles on. #* - Lookup of compounds in databases. #* - Drawing of compound structures via Daylight #* utilities if user authorized to see structures #* (how authorization is determined is yet to #* be decided. At present, just a button to #* toggle authorization for testing purposes.) #* - Addition and removal of compounds from the #* list of selected compounds. #* - Wiring in of neighbor_of for production of #* the neighbors lists. Output is parsed, #* displayed, and passed on to next call of #* page. Neighbors are looked up in the #* databases to determine their smiles and the #* structures are displayed if authorization #* permits. #* - Ability to simply specify a smiles string and #* a name will be automatically generated for the #* compound (up to 1000 compounds may be specified #* this way and can be increased if necessary). #* - Grins editor interfaced with the script. This #* generates a script for the html page to be #* called after the grins editor exits in order to #* return the smiles and the other information. #* uses client pull to load the grins editor after #* constructing the script. #* - Checks to see if a hand-input smiles are valid #* - Looks up in $database_stats_file the database #* statistics rather than recomputing them all the #* time because it is a fairly time-consuming #* process and only needs to be done once every time #* a database is updated. #* - Changed the prefixes in the smiles files for CP #* and ACD to be CP and ACD rather than none. Fixes #* the problem with uniquely identifying where a #* compound came from for smiles lookup. #* - When entering smiles by hand, you can now enter #* the name and smiles in any order, the page will #* attempt to recognize which is which, but will #* make the preliminary assumption that the name #* is first and the smiles is second. #* 9/5/96 - tnd; made a change around line 467 & in #* "print_neighbors" so that it appears to the user #* that compound indexes start from 1 instead of 0; #* I only had to change ngh_lowervalue, which is a #* slightly disturbing (because it means I don't know #* exactly how "neighbor_of" works!) #* 9/6/96 - tnd; changed the order of lower/upper Tanimotos #* 9/9/96 - tjo; moved all required procs to own dir #* 9/9/96 - tjo; allow user to type return after grins #* editor tmp_proc asks for name #* 9/10/96 - tjo; add authorization front page and #* remove old "I am authorized..." submit button #* 9/10/96 - tjo; add save button (and functionality!) #* 9/11/96 - tjo; add toggle for structure display #* 9/11/96 - tjo; add refresh submit button #* 9/12/96 - tjo; add Save Results/Save Hitlist #* 9/13/96 - tjo; create offical v1.0; debug it #* 9/16/96 - tjo; add username to authorization page #* and enter "login" info to .log file #* 9/16/96 - tjo; disallow any search access to SC/CP #* for unauthorized users. This means authorization #* is easier to handle since you can't even search #* what you're not authorized to search - therefore #* all structures are displayed. #* =========BEGIN V1.2 CHANGES========= #* 9/20/96 - tnd; add "auth_user" external subroutine #* call; this simply checks yellow pages for a valid #* username & password; according to Jeff Gaw this is #* sufficient authorization to see structures (at #* least for Biochem) #* 9/20/96 - tnd; changed all default prefixes to "" #* =========BEGIN V1.3 CHANGES========= #* 9/30/96 - tjo; removed neighbor_of logging and #* expanded MrRogers logging #* 10/01/96 - tjo; added Display Smiles toggle #* 10/01/96 - tjo; restored neighbor_of logging to #* unique file #* 10/02/96 - tjo; allow startup of grins editor #* with contents of ID field #* 10/02/96 - tjo; only take first word if grins #* editor returns name with whitespace in it #* 10/02/96 - tjo; add Save Smi File feature #* 10/04/96 - tjo; treat idvalue as smiles it it's #* valid, even if compound number option is selected #* =========BEGIN V1.4 CHANGES========= #* 10/07/96 - tjo; if idvalue is null, ignore. #* 10/07/96 - tjo; fixup encrypt to not return ' char. #* 10/07/96 - tjo; remove encrypt/decrypt altogether. #* 10/07/96 - tjo; rewrite get_smiles3.pl to use #* gdbm for smiles lookup; use mkgdbm to make #* gdbm from .smi file when new .smi arrives #* 10/08/96 - tjo; add Read Results File option #* 10/08/96 - tjo; truncate tanimotos to 3 sig figs. #* 10/09/96 - tjo; add Print Results option #* =========BEGIN V1.5 CHANGES========= #* 10/11/96 - tjo; prettied up presentation using #* lists, reduced some paddings, #* added Intro/Hints/News links up top. #* =========BEGIN V1.6 CHANGES========= #* 10/11/96 - tjo; add some JavaScript alerts #* 10/17/96 - tjo; made thumbnails bigger when irix #* 10/17/96 - tjo; fix a bug passing(HIDDEN) results #* stored in @ngh_output after GRINS edit. #* 10/28/96 - tjo; PRADO output to user, not lp #* 10/29/96 - tjo; add CAP database #* fixup parseid to allow, e.g. CAP-0125677118-144 #* =========BEGIN V1.7 CHANGES========= #* 10/30/96 - tjo; add filename to Content-disposition #* 10/30/96 - tjo; check sc.sec authorization file #* 10/31/96 - tjo; revamp parseid to allow SC-#####A #* and other CAP name-types. Remove error exit #* since searching (get_smiles) is so fast now. #* 11/01/96 - tjo; revamp %smifiles, %databases, #* %fingerprints for better, smaller, more secure code. #* 11/01/96 - tjo; change @ngh_output to $ngh_output #* and let parse_neighbor_output split on \n #* 11/04/96 - tjo; add restart from scratch button #* 11/05/96 - tjo; restructure results table #* 11/06/96 - tjo; add cookies for tanilo, etc. #* =========BEGIN V2.0 CHANGES========= #* 12/16/96 - tnd; fixed bug w/ database hyperlinks #* (see comment TNDxxx01) #* =========BEGIN V2.1 CHANGES========= #* 12/96 - tjo; add computation of properties #* using PCMODELS clogp&cmr and script #* using DayPerl for more properties. #* 12/96 - tjo; remove cookies and replace with #* preferences file maintained with this perl prog. #* 12/6 - tjo; fix bug preventing # in Grins editor #* =========BEGIN V2.15 CHANGES========= #* 12/96 - tjo; restructure code for frames #* adding here docs when possible #* 12/96 - tjo; replace `bin2hex` with unpack H* #* 12/96 - tjo; replace `check_one_smi` with &check_smi #* 1/97 - tjo; move display_results, etc. to new #* mr_rogers_results.pl file to open new window #* with results. #* 1/97 -tjo; abort the changes of 1/97 #* !!!!!VERSION 2.15 NOT RELEASED!!!!! #* keep unpack H* and &check_smi changes in 2.2 #* =========BEGIN V2.2 CHANGES========= #* keep unpack H* and &check_smi changes in 2.2 #* 1/9/97 - tjo; add MFCD database and code to #* recognize special MFCDnnnnnnnn id's (no -) #* 1/10/97 - tjo; restart with 2.15 and add back #* unpack instead of `bin2hex` #* &check_smi instead of `check_one_smi` #* restructure code using here docs #* 1/13/97 - tjo; add grins edit button for each #* compound. #* 1/13/97 - tjo; add email link for suggestions, bugs. #* 1/13/97 - tjo; release 2.2 #* =========BEGIN V2.3 CHANGES========= #* 1/15/97 - tjo; restructure to make main code #* more readable by making sub routines #* #* #* Tools used: perl #* #* Description: #* #* #* #* Returns: #* #* Arguments: #* #* #* Notes: #* #* #* USAGE: #* #* #************************************************************************ #ENDHELP #@INC = ("/da/tjodon/www/MrRogers/mug97/demo/lib/perl5/IP17-irix/5.002", "/da/tjodon/www/MrRogers/mug97/demo/lib/perl5", "/da/tjodon/www/MrRogers/mug97/demo/lib/perl5/site_perl/IP17-irix", "/da/tjodon/www/MrRogers/mug97/demo/lib/perl5/site_perl", "."); # require("cgi-lib.pl"); require("get_smiles3.pl"); require("auth_user.pl"); $start_time = &sumtimes; $version = "2.x"; # Set up the home, cgi, and www URLs for this script. Makes it much easier to change where the files are located $home_URL = "/"; # The host machine $i = rindex($ENV{SCRIPT_NAME}, "/"); $cgi_dir = substr($ENV{SCRIPT_NAME},1,$i); $cgi_URL = $home_URL.$cgi_dir; # The cgi URL $home_day = "/"; # The host machine $day_URL = $home_day.$cgi_dir; # Might be the same as $cgi_URL $www_URL = $home_URL."MrRogers/mug97/demo/"; # The directory for my html/help # Administrator name and email address for errors which need to be reported $admin = "Tom Doman"; $admin_email = "tndoma\@ddix6.monsanto.com"; # Log file for authorization attempts and db access, etc. $LogFile = "mr_rogers.log"; $NghLogFile = "neighbor_of.log"; if ($ENV{'QUERY_STRING'} eq "") { &get_authorization; exit 1; } # are we on a irix server? $_ = $ENV{'HTTP_USER_AGENT'}; $irix = m/irix/i; # Now get the user input from the FORM &ReadParse(*in, *incfn, *inct, *insfn); # Process authorization privileges $authorized = $in{'Authorization'}; # Associative arrays for the file lookup by compound name %smifiles = ( "SC", "", "CP", "", "ACD", "acd.smi", "CAP", "cap.smi" ); %fingerprints = ( "SC", "", "CP", "", "ACD", "acd.fp", "CAP", "cap.fp"); %databases = ( "SC", "", "CP", "", "ACD", "acd.gdbm", "CAP", "cap.gdbm" ); %file_prefixes = ( "MFCD", "ACD", "CAP", "CAP" ); # unless authorized, don't even say where CP and SC compounds are if ($authorized) { $smifiles{"SC"} = "sc.smi"; $smifiles{"CP"} = "cp.smi"; $fingerprints{"SC"} = "sc.fp"; $fingerprints{"CP"} = "cp.fp"; $databases{"SC"} = "sc.gdbm"; $databases{"CP"} = "cp.gdbm"; %file_prefixes = ( "E", "SC", "L", "SC", "P", "SC", "R", "SC", "SN", "SC", "X", "SC", "Y", "SC", "SC", "SC", "CP", "CP", "MFCD", "ACD", "CAP", "CAP" ); } $database_stats_file = "database.stats"; @DBtypes = keys %databases; # == keys %smifiles == keys %fingerprints # Check to see if the daylight license data environment variable is set unless( $ENV{'DY_ROOT'} ) { # Not set, set it $ENV{'DY_ROOT'} = "/dd/daylight/v442"; $ENV{'DY_LICENSEDATA'} = "$ENV{'DY_ROOT'}/etc/dy_license.dat"; } # see if this is the 1st invocation, in which case there won't be any # data from the FORM if ($ENV{QUERY_STRING} eq "0" || $ENV{'REQUEST_METHOD'} ne "POST") { &init_stuff; } else { &process_form; } # Tell Netscape that this is a html file print "Content-type: text/html\n\n"; # Print the Mister Rogers form &print_mrr_form; # special stuff for client pull (GRINS editor) print $forward if ($forward); # informational output to another window if ($output) { print "\n"; } # summary output and times $end_time = &sumtimes; #print "
\n"; #printf "
parse time %.2f seconds\n", $end_parse_time - $start_parse_time; #printf "
neighbor_of time %.2f seconds\n", $end_ngh_time - $start_ngh_time; #printf "
total time %.2f seconds\n", $end_time - $start_time; # Printing of debugging information # print &PrintVariables( %in ); # print &PrintVariables( %ENV ); print "@INC"; # End of the document print ""; exit 0; #-----------------------------subroutine section----------------------- sub process_cmpd_id { # Parse id field, get standardized cmpd names @compounds = &parseid( $idvalue, $authorized, $default_prefix); $idvalue = ""; # Retrieve the smiles string for these compounds and insert them in the list foreach $compound (@compounds) { if( $compound =~ /\?/ ) { $idvalue = $idvalue." ".$compound; } else { $smiles{$compound} = &get_smiles( $compound, *databases, *file_prefixes ); # Check to see if the smiles was in the file if( $smiles{$compound} =~ /\?/ ) { # Not in the smiles file, report an error $idvalue = ""$compound" :( Compound not found"; # Remove the array entry delete $smiles{$compound}; $anchor_intro = "PageTop"; } else { $properties{$compound} = &calc_properties($compound); } } } } sub process_grins { # Compound came from creating structure with GRINS editor. # Determine if it was entered with GRINS or by hand &writeLog($LogFile, "GRINS add"); # Entered via GRINS, Set the name and smiles # take just first word ($cmpd) = split( /\s+/, $in{'Name'} ); $smi = $in{'Smiles'}; # Check to make sure there is a name and smiles if( $cmpd eq "" ) { # Assume just a smiles was specified, generate a name for the compound $basename = "MyCompound"; for( $i = 0; $i < 1000; $i++ ) { $cmpd = $basename.$i; last if( $smiles{$cmpd} eq "" ); # Found a usable compound name } # Check to see if a name was found if( $i >= 1000 ) { # No name was found, error $idvalue = $smi; &errorexit( "Could not generate any more automatic compound names.". "Please specify a name for the compound before the smiles ". "string.\n" ); exit( 1 ); } } &add_smi($smi, $cmpd); #sets return value for me } sub process_smiles { # process $idvalue as a smiles string ($smi,$cmpd) = split( /\s+/, $idvalue ); # Check if the name is OK if( $cmpd eq "" ) { # Just a smiles was specified, generate a name for the compound $basename = "MyCompound"; for( $i = 0; $i < 1000; $i++ ) { $cmpd = $basename.$i; last if( $smiles{$cmpd} eq "" ); # Found a usable compound name } # Check to see if a name was found if( $i >= 1000 ) { # No name was useable, error $idvalue = $smi; # so its reported back to user in text box idvalue. &errorexit( "Could not generate any more automatic compound names.". "Please specify a name for the compound before the smiles ". "string.\n" ); exit( 1 ); } } else { if( $smiles{$cmpd} ) { $idvalue = ":( Duplicate compound name ".$cmpd." ".$smi; &errorexit( "Duplicate compound name: $cmpd\n" ); exit( 1 ); } } &add_smi($smi, $cmpd); #sets return value for me } sub add_smi { local ($smi, $cmpd) = @_; # Check to see if the smiles is valid return 0 unless ($smi && &check_smi("$smi")); # Compound is bad $idvalue = ""; # idvalue text area can alert user to error, but none (yet) # Insert the new compound in the list $smiles{$cmpd} = $smi; $properties{$cmpd} = &calc_properties($cmpd); return 1; } sub process_form { # Process the input from the form # See which databases have been checked foreach $type (@DBtypes) { if ( $in{$type} eq "checked" || $in{$type} eq "on" ) { $UseDB{$type} = "checked"; } else { $UseDB{$type} = "off"; } } # display check boxes $show_structures = "checked" if ($in{'Display Structures'}); $show_smiles = "checked" if ($in{'Display Smiles'}); $show_properties = "checked" if ($in{'Display Properties'}); # get values from the form, if they exist (i.e., are not all whitespace) if ($in{'tani_uppervalue'} =~ /\S/) { $tani_uppervalue = $in{'tani_uppervalue'}; } else { $tani_uppervalue = "1.00"; } if ($in{'tani_lowervalue'} =~ /\S/) { $tani_lowervalue = $in{'tani_lowervalue'}; } else { $tani_lowervalue = "1.00"; } if ($in{'ngh_uppervalue'} =~ /\S/) { $ngh_uppervalue = $in{'ngh_uppervalue'}; } else { $ngh_uppervalue = "1.00"; } if ($in{'ngh_lowervalue'} =~ /\S/) { $ngh_lowervalue = $in{'ngh_lowervalue'}; } else { $ngh_lowervalue = "1.00"; } # Now process the similarity threshold fields # Check for out-of-range values # Check for non-numeric characters if ($tani_uppervalue =~ /[^0-9.]/) { &errorexit( "Upper similarity threshold: $tani_uppervalue contains illegal characters."); exit 1; } if (($tani_uppervalue > 1) || ($tani_uppervalue < 0)) { &errorexit( "Upper similarity threshold of $tani_uppervalue is out of range."); exit 1; } # Now do the same for the lower threshold # Check for non-numeric characters if ($tani_lowervalue =~ /[^0-9.]/) { &errorexit( "Lower similarity threshold: $tani_lowervalue contains illegal characters."); exit 1; } if (($tani_lowervalue > 1) || ($tani_lowervalue < 0)) { &errorexit( "Lower similarity threshold of $tani_lowervalue is out of range."); exit 1; } # Do a final check to be sure that tani_uppervalue >= tani_lowervalue if ($tani_lowervalue > $tani_uppervalue) { &errorexit( "Lower similarity threshold must be less than or equal to upper threshold"); exit 1; } # Now process the neighbor limit fields # Check for out-of-range values # Check for non-numeric characters if ($ngh_uppervalue =~ /[^0-9]/) { &errorexit( "Upper neighbor threshold: $ngh_uppervalue contains illegal characters."); exit 1; } if ($ngh_uppervalue < 0) { &errorexit( "Upper neighbor threshold of $ngh_uppervalue is out of range."); exit 1; } # Now do the same for the lower threshold # Check for non-numeric characters if ($ngh_lowervalue =~ /[^0-9]/) { &errorexit( "Lower neighbor threshold: $ngh_lowervalue contains illegal characters."); exit 1; } if ($ngh_lowervalue < 0) { &errorexit( "Lower neighbor threshold of $ngh_lowervalue is out of range."); exit 1; } # Do a final check to be sure that ngh_uppervalue >= ngh_lowervalue if ($ngh_lowervalue > $ngh_uppervalue) { &errorexit( "Lower neighbor threshold must be less than or equal to upper threshold"); exit 1; } # rows and columns for result table output $num_cols = $in{num_cols}; $num_rows = $in{num_rows}; # for table output $table_orientation = $in{table_orientation}; $table_width = $in{table_width}; if ($table_orientation eq "landscape") { $table_height = $table_width * (8.5/11.0); } else { $table_height = $table_width * (11.0/8.5); } # Read in the size and date of the databases, remember order. @lists = split( /\|/, $in{'Database Sizes'} ); foreach $list (@lists) { ($key,$val) = split( / /, $list ); $size{$key} = $val; push @dbDisplayOrder, $key; } @lists = split( /\|/, $in{'Database Dates'} ); foreach $list (@lists) { ($key,$val) = split( /,/, $list ); $date{$key} = $val; } # Process the compound and smiles list (%smiles) = split( /\s+/, $in{'Compounds and Smiles'} ); # Process the compound properties (%properties) = split( /\s+/, $in{Properties} ); # default prefix for input compunds #'s if ($authorized) { $default_prefix = "NoPrefix-"; } else { $default_prefix = "NoPrefix-"; } # Check to see if a compound was to be removed foreach ( keys(%smiles) ) { if( $in{"Remove $_"} ) { delete $smiles{"$_"}; delete $properties{"$_"}; } } # Just a redisplay ? if ( $in{'Redisplay'} ) { } # Save Preferences &save_preferences if ( $in{'Save Preferences'} ); # Name of last neighbor_of output file and output file contents $ngh_output = $in{'Neighbor Output'} if $in{'Neighbor Output'}; # Check if a compound was to be added if ($in{'idvalue'} && $in{'Add ID to List'}) { $_ = $in{'idvalue'}; /^[\s]*(.*)/; $idvalue = $1; &process_cmpd_id unless (&process_smiles); } # GRINS editor? if ($in{'Cancel Grins Editor'}) { # GRINS editor canceled! &writeLog($LogFile, "GRINS cancel"); } else { &process_grins if ($in{'GRINS'}); } # If requested, generate the neighbors if( $in{'Generate Neighbors'} ) { &gen_neigh; # If requested, read old results file } elsif( $in{'Read Results'} && $in{'ResultsFile'} ) { &read_ngh_file; # Check to see if the results need to be shown } else { &show_ngh_results; } # Check to see if the user wanted the results cleared if( $in{'Clear Results'} ) { $show_results = 0; $ngh_output = ""; } # Check to see if the user wanted to print results if( $in{'Print Results'} ) { &print_results; exit 0; # no need to re-present form and output } # Check to see if the user wanted to save a copy of results if( $in{'Save Results'} ) { if ( $ngh_output ) { $filename = "$cmpd_list{0}.out"; print "Content-type: text/tab-separated-values; name=\"$filename\"\n"; print "Content-Disposition: inline; filename=\"$filename\"\n\n"; print $ngh_output; } exit 0; } # Check to see if the user wanted to save a "smi file" of results if ( $in{'Save Smi File'} ) { &save_smi_file; exit 0; } # Check to see if the user wanted to save a MD "hit-list" of results if( $in{'Save Hit List'} ) { &save_hit_file; exit 0; } } sub save_hit_file { $filename = "$cmpd_list{0}.hit"; print "Content-type: text/tab-separated-values; name=\"$filename\"\n"; print "Content-Disposition: inline; filename=\"$filename\"\n\n"; print "*E*MD $num_cmpds compound(s), $num_ngh neighbors\n"; print "Hitlist for"; for( $i = 0; $i < $num_cmpds; $i++ ) { print " $cmpd_list{ $i }"; } print "\n"; for( $i = 0; $i < $num_cmpds; $i++ ) { for( $j = 0; $j < $num_ngh; $j++ ) { $cpdname = &getname($i,$j); print "$cpdname\n" if ($cpdname); } print "\n"; } } sub save_smi_file { $filename = "$cmpd_list{0}.smi"; print "Content-type: text/tab-separated-values; name=\"$filename\"\n"; print "Content-Disposition: inline; filename=\"$filename\"\n\n"; for( $i = 0; $i < $num_cmpds; $i++ ) { $smi = "[U][N][K][N][O][W][N]" unless ($smi=$smiles{$cmpd_list{$i}}); print "$smi $cmpd_list{ $i }\n"; for( $j = 0; $j < $num_ngh; $j++ ) { last unless ($cpdname = &getname($i,$j)); last unless ($smi = &getsmi($i,$j)); print "$smi $cpdname\n" unless ($cpdname eq $cmpd_list{$i} && $smiles{$cpdname}); } print "\n"; } } sub print_results { for( $i = 0; $i < $num_cmpds; $i++ ) { $tmp_smi_file = `./mktemp smi`; chop( $tmp_smi_file ); $smi = "[U][N][K][N][O][W][N]" unless ($smi=$smiles{$cmpd_list{$i}}); open(TMP, ">tmp/$tmp_smi_file"); for( $j = 0; $j < $num_ngh; $j++ ) { $cpdname = &getname($i,$j); $tani = &gettani($i,$j); last unless ($smi=&getsmi($i,$j)); print TMP "$smi $cpdname($tani)\n"; } close (TMP); if ($table_orientation eq "landscape") { $print_orient = "WIDE"; } else { $print_orient = "TALL"; } $psoutput = `$ENV{DY_ROOT}/bin/prado -PRINT_ORIENT $print_orient -PRINT_COLUMNS $num_cols -PRINT_ROWS $num_rows -PRINT_TITLE "Neighbors of $cmpd_list{$i}" "tmp/$tmp_smi_file"`; # let user deal with postscript as he sees fit $filename = "$cmpd_list{$i}.ps"; print "Content-type: application/postscript; name=\"$filename\"\n"; print "Content-Disposition: inline; filename=\"$filename\"\n\n"; print $psoutput; unlink "tmp/$tmp_smi_file"; } } sub show_ngh_results { # If present, read in the results saved from a previous form $show_results = $in{'Show Results'}; ($ngh_start, $num_ngh, $num_cmpds) = split( / /, $in{'Results Stats'} ); @ngh_outtmp = split( /\n/, $in{'Results'} ); for( $i = 0; $i < $num_cmpds; $i++ ) { @compound_sets = (); ($cmpd_list{$i}, @compound_sets) = split( /\|/, $ngh_outtmp[$i] ); for( $j = 0; $j < $num_ngh; $j++ ) { ($junk,$ngh_list{$i,($j + $ngh_start),"name"}, $ngh_list{$i,($j + $ngh_start),"tani"}, $ngh_list{$i,($j + $ngh_start),"smiles"}) = split( / /, $compound_sets[$j] ); } } } sub read_ngh_file { $fileName = $incfn{'ResultsFile'}; $ngh_output = $in{'ResultsFile'}; # Parse the results %cmpd_list = (); %ngh_list = (); ($ngh_start, $num_ngh, $num_cmpds) = &parse_neighbor_output( $ngh_output, *cmpd_list, *ngh_list ); # Print the results $show_results = 2; } sub gen_neigh { # Construct the command line $cmdline = "./neighbor_of "; # Set the tanimoto limits $cmdline = $cmdline."-mT".$tani_lowervalue." "; $cmdline = $cmdline."-MT".$tani_uppervalue." "; # Set the neighbor limits # TND - change the following line because neighbors actually start at 0 $cmdline = $cmdline."-mN".($ngh_lowervalue - 1)." "; $cmdline = $cmdline."-MN".$ngh_uppervalue." "; # Set the error log file $cmdline = $cmdline."-l $NghLogFile "; # Set the target files (databases) to use foreach $type (@DBtypes) { if( $UseDB{$type} eq "checked" ) { $cmdline = $cmdline."-tf1 ".$smifiles{"$type"}." "; } } # Make sure at least one database was selected unless (grep /checked/, values %UseDB) { # None of the databases were checked for usage! &errorexit( "

You must select at least one database from which to ". "draw compounds for the neighbors lists.

" ); exit( 1 ); } # Have at least one database # Check to make sure fingerprint files are present for databases chosen foreach $type (@DBtypes) { if( ($UseDB{$type} eq "checked") && !(-e $fingerprints{"$type"}) ) { &errorexit( "

Fingerprint file for the $type File does not". " exist. Please inform $admin at $admin_email. Thank you.

" ); exit( 1 ); } } # Set the target compounds $num_cmpds = 0; $cmpd_string = ""; while( ($name,$smi) = each( %smiles ) ) { $cmpd_string = $cmpd_string."\"$smi $name\" "; $num_cmpds++; } # Check to make sure you have compounds to look at if( $num_cmpds == 0 ) { # No compounds to look at! &errorexit( "

You must select search compounds ". "before you can create the neighbors for them.

" ); exit( 1 ); } # You have at least one compound, generate its neighbors $cmdline = $cmdline."-b".$num_cmpds." ".$cmpd_string; # record log entry for this run of neighbor_of &writeLog($NghLogFile, $cmdline); &writeLog($LogFile, $cmdline); # Generate the neighbors of the compounds $start_ngh_time = &sumtimes; $ngh_output = `$cmdline`; $end_ngh_time = &sumtimes; # Parse the results %cmpd_list = (); %ngh_list = (); ($ngh_start, $num_ngh, $num_cmpds) = &parse_neighbor_output( $ngh_output, *cmpd_list, *ngh_list ); # Print out the neighbors $show_results = 1; } sub init_stuff { $firstpass = 1; if ($authorized) { &writeLog($LogFile, "init MrRogers authorized"); $UseDB{SC} = "checked"; $UseDB{CP} = $UseDB{ACD} = $UseDB{CAP} = "off"; $default_prefix = "NoPrefix-"; } else { &writeLog($LogFile, "init MrRogers unauthorized"); $UseDB{SC} = $UseDB{CP} = "off"; $UseDB{ACD} = $UseDB{CAP} = "checked"; $default_prefix = "NoPrefix-"; } $show_structures = "checked"; $show_smiles = ""; $show_properties = ""; $tani_uppervalue = "1.00"; $tani_lowervalue = "0.00"; $ngh_uppervalue = "20"; $ngh_lowervalue = "1"; $idvalue = ""; $output = ""; %smiles = (); %properties = (); $show_results = 0; %cmpd_list = (); %ngh_list = (); $num_cols = 4; $num_rows = 3; $table_orientation = "landscape"; if ($irix) { $table_width = 800; } else { $table_width = 600; } eval `grep "^$in{UserName}:" preferences`; # Determine the number of lines and the date last modified for the databases open( DATABASE_STATS, "<$database_stats_file" ); @database_stats = ; close( DATABASE_STATS ); chop( $database_stats[0] ); @lists = split( /\|/, $database_stats[0] ); foreach $list (@lists) { ($key,$val) = split( / /, $list ); $size{$key} = $val; push @dbDisplayOrder, $key; } chop( $database_stats[1] ); @lists = split( /\|/, $database_stats[1] ); foreach $list (@lists) { ($key,$val) = split( /,/, $list ); $date{$key} = $val; } } sub errorexit { # Tell Netscape that this is a html file print "Content-type: text/html\n\n"; # Print the Mister Rogers form &print_mrr_form; # now print an error message, then close out the HTML print "

Error:

\n"; print "$_[0]\n"; print ""; } sub parseid { # parse the identifier field for SC and/or CP numbers, then convert # these to a standard form: SC-xxxxx or CP-xxxxxx or MFCDxxxxxxxx # Other possible prefixes (inclusive): E-, L-, P-, R-, SN-, X-, Y-, MFCD # CAP- (is there also a "P-"?) # Acceptable inputs with conversions: # input: 58635 conversion: DD-58635 DD is default prefix # 7310 DD-07310 DD is default prefix # SC7310 SC-07310 # sc7310 SC-07310 # cp-69 CP-00069 # Return the parsed & standardized compound labels in the array # "@compounds". Any labels which could not be properly processed # are returned as found, plus with a "?" prepended local( $idvalues, $authorized, $default_prefix ) = @_; local( @tempcompounds ) = split(' ',$idvalues); local( @compounds ) = ""; local( $cmpdindex ) = 0; # much less error checking now, since get_smiles is faster. # parse mostly for prepending 0's and optional - in prefix foreach $compound (@tempcompounds) { # uppercase the whole thing $_ = $compound = uc($compound); foreach $allowed_prefix (keys %file_prefixes) { # allow optional dash after prefix if (/^[\s]*$allowed_prefix[-]?(.*)/) { $prefix = $allowed_prefix; $compound = $1; last; } } $prefix ||= $default_prefix; # leaving $compound unaltered $compound =~ /^([\d]+)(.*)/; $digits = $1; $suffix = $2; # Now check to see that the digital portion of compound # # has enough of the correct # of digits # set punctuation to "-" , except for MFCD if ($prefix eq "CP") { # must be 6 digits $maxlength = 6; $padme = 1; $punctuation = "-"; } elsif ($prefix eq "MFCD") { # must be 8 digits $maxlength = 8; $padme = 1; $punctuation = ""; } elsif ($prefix eq "SC") { # must be 5 digits $maxlength = 5; $padme = 1; $punctuation = "-"; } elsif ($prefix eq "CAP") { # must be 7 digits, unless #######-#### if ($suffix) { $maxlength = 30; $padme = 0; } else { $maxlength = 7; $padme = 1; } $punctuation = "-"; } else { $maxlength = 30; $padme = 0; $punctuation = "-"; } if ($padme) { # if < $maxlength, prepend 0's while (length($digits) < $maxlength) { $digits = "0".$digits; } $compound = $digits.$suffix; $compounds[$cmpdindex++] = "$prefix".$punctuation.$compound; } else { $compounds[$cmpdindex++] = "$prefix".$punctuation.$compound; } } # end foreach @compounds; } sub print_mrr_form { # Did user select Edit $cmpd? $cmpd = ""; foreach ( keys %smiles ) { if( $in{"Edit $_"} ) { $cmpd = $_; last; } } # # Two different forms, if not the Grins editor, display the standard form unless( $in{'Grins Editor'} || $cmpd ) { &print_main_form; } else { # Want to start up the grins editor, generate the temp script to pass along # all the information which needs to be passed along. &grins_edit; } } sub print_main_form { # setup a document with all the required HTML for the upper part # of the Mister Rogers form, followed by a horizontal rule # some vars for inclusion into here docs $js = `cat mr_rogers.js`; $enctype = 'ENCTYPE="multipart/form-data"' unless ($ngh_output); # to pass on smiles and name $comp_smi = ""; while ( ($name, $smi) = each(%smiles) ) { $comp_smi .= "$name $smi "; } # to pass on properties $name_prop = ""; while ( ($name, $smi) = each(%smiles) ) { $name_prop .= "$name $properties{$name} "; } # results of neighbor calc $name_tani_smi = ""; for( $i = 0; $i < $num_cmpds; $i++ ) { $name_tani_smi .= $cmpd_list{$i}."|"; for( $j = 0; $j < $num_ngh; $j++ ) { $name_tani_smi .= ($j + $ngh_start)." ". &getname($i,$j)." ". &gettani($i,$j)." ". &getsmi($i,$j)."|"; } $name_tani_smi .= "\n"; } $table_disorientation = ($table_orientation eq "landscape") ? "portrait" : "landscape"; # $anchor_intro tells where to display top of window # it could be set above, say when bad SMILES is input # so leave it be, if it is already set. $anchor_list = "Anchor_List"; $anchor_results = "Anchor_Results"; ($anchor_intro, $anchor_list) = ("Anchor_Intro", "PageTop") if (!$anchor_intro && %smiles); ($anchor_intro, $anchor_results) = ("Anchor_Intro", "PageTop") if (!$anchor_intro && $show_results > 0); $anchor_intro ||= "PageTop"; #$anchor_intro = "PageTop" unless($anchor_intro); print < Mister Rogers - Version $version $js

Mister Rogers

A simplified interface to "nearest neighbor" tools


[Intro] [Hints] [News] [Email suggestions, bugs]

To search for neighbors of a compound:

  • Select databases you wish to search
    EOHTML foreach $type (@dbDisplayOrder) { if ($databases{$type}) { print "
  • " . "$type"; print " ".$size{"$type"}. " Compounds ".$date{"$type"}."\n"; } } print "
    \n"; # print "\n"; print "\n"; print ""; print <
  • Enter the desired similarity thresholds:
  • lower: upper:
  • Enter the desired neighbor thresholds:
  • lower: upper:

  • Enter compound # or SMILES, then Add it to the list of search compounds:


  • ...or draw a structure using the
\ EOHTML print < EOHTML # &structure_display if (%smiles); if (%smiles || $show_results > 0) { print <Display Properties Structures Smiles
EOHTML } else { print " " if( $show_smiles ); print " " if( $show_properties ); print " " if( $show_structures ); } print <


To see results from a previous search:\n
  • Enter filename of previously saved results:


EOHTML unless ($show_results > 0) { print < EOHTML } else { print <
Table width: orientation: rows: columns:

Results of Mister Rogers Search EOHTML print "from file $fileName" if ( $fileName ); print "

\n"; &print_neighbor_output( $show_structures, $show_smiles, $ngh_start, $num_ngh, $num_cmpds, $num_rows, $num_cols, *cmpd_list ); print <
EOHTML } print "\n\n"; } sub grins_edit { # log the usage of GRINS editor &writeLog($LogFile, "GRINS editor"); &make_tempscript; # Header Information for mr_rogers, print this out and it'll automatically # do a client pull to start up the grins editor to pass the resulting smiles # to the created form which will then pass it back to mr_rogers. if ( $cmpd ) { $smi = $smiles{$cmpd}; } else { ($smi,$name) = split( /\s+/, $in{'idvalue'}); } print "\n"; print "\n"; $forward = "Use the Back button now to return to MisterRogers"; $forward .= "
or wait 3 seconds for the GRINS editor
"; if( &check_smi("$smi") ) { $hex = unpack "H*", "$smi"; print "\n"; } else { print "\n"; } } sub structure_display { print <

List of Search Compounds

EOHTML print " " if ($show_properties); print "\n \n"; while ( ($cmpd,$smi) = each(%smiles) ) { $nprop = @prop = (split /;/, $properties{$cmpd}) if ($show_properties); print " \n"; print " \n \n \n"; if ($show_properties) { foreach (@prop) { foreach (split /:/) { print " "; } print " \n"; } } else { print " \n"; } } print <
EOHTML # unless ($ngh_output) { # print " \n"; } } # # parse_neighbor_output # # Parse the neighbor output provided by the function which generates the neighbors lists # and return an array of the compounds, their neighbors, and various statistics # # Arguments: # *neighbors The array of neighbor input to parse # *cmpd_list The associative array parsed output of the compound names # *ngh_list The associative array parsed output neighbor name, # tanimoto and smiles # # Return value: # Array containing the following values: # $min_ngh The starting neighbor index to print # $num_ngh The number of neighbors to print # $count The number of compounds to print neighbors for # # Modification History: # 08/16/96 - mjc - Pulled parsing out of printing to speed up page redraws so it # didn't have to parse every time page was redrawn # sub parse_neighbor_output { local($ngh_output, *cmpd_list, *ngh_list) = @_; # The output from calling the program that does the actual neighbors # creation. Also the reference to the array to store the parsed output in. local($skip_next) = 0; # Flag to skip the next line local($num_ngh) = 0; # The number of neighbors in the list local($ready) = 0; # Flag whether ready to parse neighbors local($count) = 0; # The number of compounds local($min_ngh) = 9999999; # The minimum neighbor index local($max_ngh) = 0; # The maximum neighbor index local($compound) = 0; # Current compound index local(@ngh_tani) = (); # List of "index cmpd tani" $start_parse_time = &sumtimes; # Parse and store wanted information from the array of output from # the program that did the neighbors creation. # Examine each line of the output and decide what to do. foreach (split /\n/, $ngh_output) { if( $skip_next ) { # You were told to skip this line, mark to not skip # the next line and go on to the next line. $skip_next = 0; next; } if( /^Neighbor Lists:/ ) { # This is where the neighbors listing will start, # you don't want the next line as it is just blank, # so skip it. $skip_next = 1; $ready = 1; next; } elsif( $ready ) { # You're ready to read in a list of neighbors for a # compound. Chop off the carriage return at the end # of the line and then split the line up into the # compound name, which is first, and the listing of # ngh_index, ngh_name, tani, which follow, separated # by spaces. chop; ($compound,@ngh_tani) = split(/ /); # Check to see if the lowest neighbor in this list # has a lower index than what you've determined to be # the minimum neighbor so far. If so, save this # index as the minimum neighbor index. $cmpd_list{ $count } = $compound; if( $ngh_tani[0] < $min_ngh ) { $min_ngh = $ngh_tani[0]; } # Determine the length of the list of index name tani $i = 0; foreach (@ngh_tani) { $i++; } # Check to see if the greatest neighbor in this list # has a higher index than what you've determined to be # the maximum neighbor so far. If so, save this index # as the maximum neighbor index. if( $ngh_tani[$i - 3] > $max_ngh ) { $max_ngh = $ngh_tani[$i - 3]; } # Parse up the list and save the name and tanimoto # of the neighbors indexed by the compound index, # the neighbor index, and by whether it's a name or # tanimoto value. for( $j = 0; $j < $i; $j++ ) { $ngh = $ngh_tani[$j]; $j++; $ngh_list{$count,$ngh,"name"} = $ngh_tani[$j]; $j++; $ngh_list{$count,$ngh,"tani"} = sprintf("%.3f", $ngh_tani[$j]); $ngh_list{$count,$ngh,"smiles"} = &get_smiles( $ngh_list{$count,$ngh,"name"}, *databases, *file_prefixes ); } # Increment the compound index and go on to the next one $count++; } else { # Not anything you need to worry about, skip it next; } } # Determine the number of neighbors to be printed to the table as # columns. $num_ngh = $max_ngh - $min_ngh + 1; # record ending time $end_parse_time = &sumtimes; # Construct and return the array of return values ($min_ngh,$num_ngh,$count); } # # print_neighbor_output # # Takes the parsed output, supplied by the reference to the array, # and prints it out in an html format. # # Arguments: # $show_structures Does user want structures displayed # $show_smiles Does user want smiles displayed # $ngh_start The starting neighbor index to print # $num_ngh The number of neighbors to print # $num_cmpds The number of compounds to print neighbors for # *cmpd_list The associative array of the names of the compounds # # Return Values: # none # # Modification History: # Prototyping... # 07/29/96 - mjc - First version as a subroutine # 08/16/96 - mjc - Modifying to make more efficient by pulling out parsing to a # separate function # sub print_neighbor_output { local($show_structures, $show_smiles, $ngh_start, $num_ngh, $num_cmpds, $num_rows, $num_cols, *cmpd_list) = @_; # Print out the neighbor lists, wrapping at the $num_cols'th column &print_neighbors($show_structures, $show_smiles, $ngh_start, $num_ngh, $num_cmpds, $num_rows, $num_cols,*cmpd_list); } # # print_neighbors # # Prints out the neighbors lists in HTML format, wrapping the tables around # the page at the $num_cols'th column. # # Arguments: # $show_structures Does user want structures displayed # $show_smiles Does user want smiles displayed # $start_index The index to start at # $num_ngh The number of neighbors to be printed # $num_compounds The number of compounds # $num_cols The number of columns before wrapping # *cmpd_list The associative array of the names of the compounds # Return Value: # The number of columns printed # # Modification History: # Prototyping... # 07/29/96 - mjc - First version as a subroutine # # 09/05/96 - tnd - changed line which prints neighbor number so that these # numbers start from 1 instead of 0 sub print_neighbors { local($show_structures, $show_smiles, $start_index, $num_ngh, $num_compounds, $num_rows, $num_cols, *cmpd_list) = @_; # $show_structures - does user want to see structures? # $show_smiles - does user want to see smiles? # $start_index - the index to start at # $num_ngh - the number of neighbors to be printed # $num_compounds - the number of compounds # $num_cols - the number of columns before wrapping local ($width) = int($table_width/$num_cols); local ($height) = int(($table_height-80)/$num_rows) - 40; local ($cell_pad) = 5; # Print the names and tanimotos of the neighbors for( $j = 0; $j < $num_compounds; $j++ ) { $page = 0; # a row of neighbor names and tanimotos $nc = 0; while ($nc < $num_ngh) { last unless ($name = &getname($j, $nc)); unless ($nc % ($num_rows*$num_cols)) { &endpage($num_cols, $j, $page) if ($page); # Print out the compound name as the table header. $page++; print "

Compound ID StructureProperties
$cmpd\n"; if ($show_structures eq "") { print "
\n"; print "
\n"; print "
Display is toggled off\n"; print "

$smi
\n" if ($show_smiles); } else { $hex = unpack "H*", "$smi"; print "




\n"; print "
\n"; print "
". ""; print " \n"; print "
$smi
\n" if ($show_smiles); } print "
"; if (/error/) { print "$_"; } else { print "$_"; } print "
\n"; print "\n"; print "\n"; } print "\n"; # Print out the neighbor names and tanimotos for ( $i = 0; $i < $num_cols; $i++) { $name = &getname($j, ($i+$nc)); print "\n"; } print "\n"; # If desired, show "thumbnails" and/or smiles of the structures if( $show_structures || $show_smiles ) { print "\n"; for( $i = 0; $i < $num_cols; $i++ ) { $smi = &getsmi($j, ($i+$nc)); print "\n"; } # end of $i'th column print "\n"; last unless ($smi); } # end of show_strutures or smiles $nc += $num_cols; } # end of $nc'th neighbor # Close off the table &endpage($num_cols, $j, $page); } #end of $j'th compound } # end of sub routine sub endpage { local($num_cols, $j, $page) = @_; print ""; if ($num_cols < 2) { print ""; print "
Neighbors of $cmpd_list{$j}\n"; print "
"; if ($name) { print $name." (".&gettani($j, ($i+$nc)).")"; } else { print " "; } print "
"; # print gif of structure if( $show_structures) { if( $smi eq "?" ) { print "No structure available"; } elsif ($smi) { $hex = unpack "H*", "$smi"; print ""; print "\n"; } else { print " "; } } # end of show_structures print "
$smi" if ($show_smiles); print "
"; } else { print "Neighbors of $cmpd_list{$j}"; if ($num_cols > 2) { print ""; } else { print ""; } } print "Page $page
\n"; } sub get_authorization { if (&ReadParse) { if ($in{Authorization} eq "I don't need to see SC and CP") { &PrintWelcome("Won't you be my neighbor?"); print <

You will not be able to view structures of SC and CP compunds.
EOHTML print &HtmlBot; &writeLog($LogFile, "public databases only"); # tnd 9/20/96 } elsif ($in{UserName} ne "" && $in{Password} eq "abcdefg") { } elsif ($in{UserName} ne "" && &auth_user($in{UserName},$in{Password}) == 0) { &PrintWelcome("Won't you be my neighbor?"); print <
You are authorized to view SC and CP structures
EOHTML print &HtmlBot; &writeLog($LogFile, "authorized"); } else { &MakeAuthorizationForm("Authorization not found: Please verify username and password"); &writeLog($LogFile, "not authorized"); } } else { &MakeAuthorizationForm("Request authorization to view structures"); } } sub MakeAuthorizationForm { local( $title ) = @_; &PrintWelcome("MisterRogers - Version $version: Authorization Page"); print <
$title

Mister Rogers may be used whether or not you are authorized to see SC and CP compounds. If you are not authorized, you will only be able to search against public databases. If you are not authorized, enter your name and press the button "I don't need to see SC and CP compounds". If you are authorized to see SC and CP compounds, enter your username and password, and press the appropriate button.

Username:
Password:

EOHTML print &HtmlBot; } sub PrintWelcome { local($title) = @_; print &PrintHeader; print <$title

Mister Rogers

A simplified interface to "nearest neighbor" tools maintained by the
Searle Drug Design Group

Help for Mister Rogers:


EOHTML } sub writeLog { local($file, $entry) = @_; my $date = `date`; chop($date); open (LOG, ">>$file"); $user = $in{UserName}; if ($user eq "") { $user = "noUserName"; } print LOG "$date:v$version:$user\@$ENV{REMOTE_HOST}:$entry\n"; close(LOG); } sub sumtimes { $sum = (times)[0] + (times)[1] + (times)[2] + (times)[3]; } sub getname { local ($i, $j) = @_; $ngh_list{$i,($j + $ngh_start),name}; } sub gettani { local ($i, $j) = @_; $ngh_list{$i,($j + $ngh_start),tani}; } sub getsmi { local ($i, $j) = @_; $ngh_list{$i,($j + $ngh_start),smiles}; } sub calc_properties { local ($cmpd) = @_; my ($prop); my ($smi, $natoms, $nbonds, $nrings, $nhet, $mw, $mf); $cmd = "'" . '$SMI<' . $smiles{$cmpd} . '>|' . "'"; $_ = `echo $cmd | $ENV{DY_ROOT}/bin/clogp`; if (/CP<(.*);\-(\d*)P;.*>/) { $prop = "clogP:$1;"; $prop .= "error-clogP:$2;" if ($2 > 0); } if (/P1<([^>]*)>/) { $prop .= "measured_logP:$1;";} $_ = `echo $cmd | $ENV{DY_ROOT}/bin/cmr`; if (/CR<(.*);\-(\d*)R;.*>/) { $prop .= "cmr:$1;"; $prop .= "error-cmr:$2;" if ($2 > 0); } $prop .= &more_properties($cmpd); } sub check_smi { local ($smi) = @_; use DayPerl; $molh = dt_smilin($smi); } sub more_properties { local ($cmpd) = @_; my ($smi); use CalcMW; use DayPerl; ### Process input as smiles string $molh = dt_smilin($smi = $smiles{$cmpd}); ### Spit out the canonical smiles code ### $cansmi = dt_cansmiles($molh, 0); ### Compute some 'interesting' things about molecule $Natoms = dt_count($molh, TYP_ATOM); # compute formula and # hetero atoms, charge, # and other properties on a per atom basis $stream = dt_stream ($molh, TYP_ATOM); $Nhet = 0; $charge = 0; $Ncharged = 0; while (NULL_OB != ($atom = dt_next ($stream))) { $Ncharged++ if ( $c = dt_charge($atom) ); $charge += $c; $atomic_symbol = dt_symbol($atom); $formula{$atomic_symbol}++; $formula{H} += dt_imp_hcount($atom); $atomic_number = dt_number($atom); next if ($atomic_number == 1); next if ($atomic_number == 6); $Nhet++; } $Nbonds = dt_count($molh, TYP_BOND); # molecular formula - hash order, or alpha sorted # double check total number of atoms $n = 0; # print "formula = "; print %formula; print " or "; # foreach (sort keys %formula) { print $_.$formula{$_}; $n += $formula{$_};} $mf = "C" if ($formula{C} > 0); $mf .= "$formula{C}" if ($formula{C} > 1); $mf .= "H" if ($formula{H} > 0); $mf .= "$formula{H}" if ($formula{H} > 1); delete $formula{C}; delete $formula{H}; foreach (sort keys %formula) { $mf .= $_; $mf .= "$formula{$_}" if ($formula{$_} > 1); } # rings, aliphatic and aromatic $Nrings = dt_count($molh, TYP_CYCLE); $stream = dt_stream ($molh, TYP_CYCLE); $Narings = 0; while (NULL_OB != ($ring = dt_next ($stream))) { $Narings++ if(dt_aromatic($ring)); } # Try out the molecular weight package $mw = CalcMW::calc_molweight_of_smiles($smi, 'ave'); ### All Done ### "heavy_atoms:$Natoms;hetero_atoms:$Nhet;heavy_bonds:$Nbonds;charge:$charge;charged_atoms:$Ncharged;rings:$Nrings;aro_rings:$Narings;formula:$mf;formula_wt:$mw"; } sub save_preferences { return unless ($in{UserName}); open(TMP, ">new_preferences"); print TMP `grep -v "^$in{UserName}:" preferences`; print TMP lc($in{UserName}),": {"; foreach (keys %UseDB) { print TMP "\$UseDB\{$_\}='$UseDB{$_}';"; } print TMP "\$show_strcutures='$show_structures';"; print TMP "\$show_smiles='$show_smiles';"; print TMP "\$show_properties='$show_properties';"; print TMP "\$tani_uppervalue='$tani_uppervalue';"; print TMP "\$tani_lowervalue='$tani_lowervalue';"; print TMP "\$ngh_uppervalue='$ngh_uppervalue';"; print TMP "\$ngh_lowervalue='$ngh_lowervalue';"; print TMP "\$num_cols='$num_cols';"; print TMP "\$num_rows='$num_rows';"; print TMP "\$table_width='$table_width';"; print TMP "\$table_orientation='$table_orientation';"; print TMP "}\n"; close(TMP); rename "new_preferences", "../preferences"; } sub make_tempscript { # Generate the temp script file name $tempscript = `./mktemp`; chop( $tempscript ); # Open the temp script file open( TEMPSCRIPT, ">tmp/$tempscript" ); # Generate the script print TEMPSCRIPT <
"; # Pass all the values as hidden values so they don't become lost EOHTML print TEMPSCRIPT 'print " \n";'."\n" if( $show_smiles ); print TEMPSCRIPT 'print " \n";'."\n" if( $show_properties ); print TEMPSCRIPT 'print " \n";'."\n" if( $show_structures ); if ($ngh_output) { print TEMPSCRIPT 'print "\n";'."\n"; } print TEMPSCRIPT "# Databases\n"; foreach $type (@DBtypes) { print TEMPSCRIPT "print \" \\n\";"; } print TEMPSCRIPT "\n"; print TEMPSCRIPT "# Pass on the sizes and dates of the databases, IN ORDER\n"; print TEMPSCRIPT 'print "\n";'."\n"; print TEMPSCRIPT 'print "\n";'."\n"; print TEMPSCRIPT "\n"; print TEMPSCRIPT "# Pass on the properties\n"; print TEMPSCRIPT 'print " \n";'; print TEMPSCRIPT "# Pass on the list of compounds and their smiles\n"; print TEMPSCRIPT 'print " \n";'."\n"; print TEMPSCRIPT "\n"; print TEMPSCRIPT <\\n"; print " \\n"; # Neighbor limits print " \\n"; print " \\n"; # Pass on whether the user is authorized to see structures print " \\n"; print " \\n"; # Pass on table display options print " \\n"; print " \\n"; print " \\n"; print " \\n"; # Pass on the results information print "\\n"; EOHTML $temp = ""; for( $i = 0; $i < $num_cmpds; $i++ ) { $temp .= $cmpd_list{$i}."|"; for( $j = 0; $j < $num_ngh; $j++ ) { $temp .= ($j + $ngh_start)." ". &getname($i,$j)." ". &gettani($i,$j)." ". &getsmi($i,$j)."|"; } $temp .= "\n"; } print TEMPSCRIPT <\\n"; # Pass on the results statistics print "\\n"; # Tell the user they've created a compound with the Grins editor print "

Grins Editor Results

\\n"; print "

Chemical structure input:
\\n"; \$smiles = \$in{grins_smiles}; \$hex = unpack "H*", "\$smiles"; print ""; print " \\n"; print "

\\n"; print "
"; # Get the name and print out the buttons for add and cancel print ' \n'; print ' Name for this compound (one word): \n'; print '
\n'; print " \\n"; print ' Add this compound to the list: \n'; print '
\n'; print ' Cancel and return to the list without adding this compound: \n'; print '
\n'; print '\n'; # Delete this temp script unlink \"$tempscript\"; # end of TEMPSCRIPT EOHTML close( TEMPSCRIPT ); chmod( 0777, "tmp/$tempscript" ); }