Mercurial > repos > fgiacomoni > hr2
changeset 0:86296c048e46 draft
Init repository for [hr2]
author | fgiacomoni |
---|---|
date | Wed, 05 Jun 2019 09:40:20 -0400 |
parents | |
children | e2cbcf6fa22e |
files | HR2.xml README.txt conf_hr2.cfg hr2_manager.pl hr_out.tmpl lib/HR2_v1.04.cpp lib/conf.pm lib/csv.pm lib/hr.pm static/images/hr2.png t/hr2_managerTest.t t/lib/hrTest.pm test-data/out1.html test-data/out1.tabular test-data/out2.html test-data/out2.tabular |
diffstat | 16 files changed, 3210 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HR2.xml Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,303 @@ +<tool id="hr2" name="HR2 formula" version="1.1.1.7"> + <description> + find a chemical formula from a accurate mass + </description> + <requirements> + <requirement type="package" version="2.161">perl-data-dumper</requirement> + <requirement type="package" version="1.97">perl-text-csv</requirement> + <requirement type="package" version="2.97">perl-html-template</requirement> + <requirement type="package" version="1.04">hr2</requirement> + </requirements> + <stdio> + <exit_code range="1" level="fatal" /> + </stdio> + + + <command><![CDATA[ + perl $__tool_directory__/hr2_manager.pl + #if str($input_type.choice) == "YES": + -input "${input_type.input}" + #if str($input_type.header.header_choice) == "yes": + -nblineheader "${$input_type.header.nbHeader}" + #end if + -colId "${input_type.colId}" -colmass "${input_type.colmass}" + #else: + -masse "${input_type.masse}" + #end if + + -tolerance "$tol" + -mode "${mode_condition.mode}" + #if str($mode_condition.mode) == "neutral": + -charge "0" + #else: + -charge "${mode_condition.qtCharge}" + #end if + + -regleOr "$regleOr" -atomes "$atomes_basic" -atomessup "$atomes_sup" + -output1 "$variableMetadata" -outputView "$hr2ResView" + -verbose "$verbose" + ]]></command> + + <inputs> + <conditional name="input_type"> + <param name="choice" type="select" display="radio" label="Would you use a file " help="if 'NO' is selected then one or more mass(es) must be entered manually"> + <option value="YES">YES</option> + <option value="NO">NO</option> + </param> + <when value="YES"> + <param name="input" label="File of masses" format="tabular" type="data" /> + <conditional name="header"> + <param name="header_choice" type="boolean" checked="true" truevalue="yes" falsevalue="no" label="Do you have a header?" help="if 'YES' is selected then enter your number of header lines" /> + <when value="yes"> + <param name="nbHeader" label="Number of header lines" type="integer" value="1" min="1" size="10" help="number of lines not containing masses"/> + </when> + <when value="no"/> + </conditional> + <param name="colId" label="Column of Id" type="data_column" data_ref="input" accept_default="true" /> + <param name="colmass" label="Column of masses (MZ)" type="data_column" data_ref="input" accept_default="true" /> + </when> + <when value="NO"> + <param name="masse" size="20" type="text" label="Mass (MZ) to submit" help="For a masses list, writes : m1 m2 m3. Your values must be separated by spaces. You should use dot (.) like decimal separator"/> + </when> + </conditional> + + <param name="tol" label="Delta of mass (MZ) (in mmu)" type="float" value="1.0" min="0" max="9.0" help="Tolerance should be between 0 and 9.0 mmu. Default value is 1.0 mmu"/> + <conditional name="mode_condition"> + <param name="mode" label="Molecular Species Searched" type="select" display="radio" help="Or ionization type of the molecule list. Use neutral only if only if the masses correspond to molecules and not to ions : query doesn't be a [M+H] or [M-H] ion"> + <option value="positive">positive</option> + <option value="negative">negative</option> + <option value="neutral" selected="true">neutral</option> + </param> + <when value="neutral"/> + <when value="positive"> + <param name="qtCharge" label="Molecule initial charge" type="select" help="Use 'neutral' if the molecule is not charged"> + <option value="1">1</option> + <option value="2">2</option> + <option value="3">3</option> + </param> + </when> + <when value="negative"> + <param name="qtCharge" label="Molecule initial charge" type="select" help="Use 'neutral' if the molecule is not charged"> + <option value="1">1</option> + <option value="2">2</option> + <option value="3">3</option> + </param> + </when> + </conditional> + <param name="atomes_basic" label="Please unselect basic atom(s) from following list you want to exclude" type="select" display="checkboxes" multiple="True" help="Unselect one or more basic atoms to exclude them from the generated formula proposition"> + <option value="C" selected="true">C</option> + <option value="N" selected="true">N</option> + <option value="O" selected="true">O</option> + <option value="H" selected="true">H</option> + <option value="P" selected="true">P</option> + </param> + <param name="regleOr" label="Use all 7 golden rules OR only the first 3 golden rules?" type="select" display="radio" help="Use 'only first 3 rules' if you want more empirical formulas"> + <option value="YES">only first 3 rules</option> + <option value="NO" selected="true">all 7 rules</option> + </param> + <param name="atomes_sup" label="Add some atom(s) from following list if needed" type="select" display="checkboxes" multiple="True" help="C, H, N, O and P are available in basic atom section"> + <option value="S">S</option> + <option value="F">F</option> + <option value="L">Cl</option> + <option value="K">K</option> + <option value="B">Br</option> + <option value="A">Na</option> + <option value="1">13C</option> + </param> + <param name="verbose" type="select" label="Verbose level" display="radio" help=""> + <option value="1" selected="true">Low</option> + <option value="3" >High</option> + </param> + </inputs> + <outputs> + <data name="variableMetadata" format="tabular" label="${tool.name}_TSV"/> + <data name="hr2ResView" format="html" label="${tool.name}_VIEW"/> + </outputs> + + <tests> + <test> + <param name="choice" value="NO"/> + <param name="masse" value="175.125"/> + <param name="tolerance" value="1.0"/> + <param name="mode" value="negative"/> + <param name="qtCharge" value="1"/> + <param name="atomes_basic" value="C,O,N,H"/> + <param name="regleOr" value="NO"/> + <param name="verbose" value="3"/> + <output name="variableMetadata" file="out_test01.tabular"/> + <output name="hr2ResView" file="out_test01.html"/> + </test> + <test> + <param name="choice" value="NO"/> + <param name="masse" value="88.052"/> + <param name="tolerance" value="1.0"/> + <param name="mode" value="neutral"/> + <param name="qtCharge" value="1"/> + <param name="atomes_basic" value="C,O,H"/> + <param name="regleOr" value="NO"/> + <param name="verbose" value="3"/> + <output name="variableMetadata" file="out_test02.tabular"/> + <output name="hr2ResView" file="out_test02.html"/> + </test> + </tests> + + <help><![CDATA[ + +.. class:: infomark + +**Authors** + | HR2 original program and its documentation are Copyright (c) 1992-2005 by Joerg Hau under GNU General Public License ("GPL") + +.. class:: infomark + +**Wrapping** + | Marion Landi - FLAME ; PFEM ; INRA ; MetaboHUB (for xml interface and Perl wrapper) + | Franck Giacomoni - PFEM ; INRA ; MetaboHUB (for xml interface, conda dependancies and Perl wrapper) + +--------------------------------------------------- + +.. class:: infomark + +**Please cite** If you use this tool, please cite + | Tobias Kind and Oliver Fiehn. (2007). "Seven Golden Rules for heuristic filtering of molecular formulas obtained by accurate mass spectrometry." BMC Bioinformatics p8:105 http://www.ncbi.nlm.nih.gov/pubmed/17389044 + | HR2 original program and its documentation are under GNU General Public License ("GPL") : GPL is a"contaminating" license. http://fiehnlab.ucdavis.edu/projects/Seven_Golden_Rules/Software + + +--------------------------------------------------- + +============== +HR2 formula +============== + +----------- +Description +----------- + + | Find a formula for the masses + | only molecules with carbon (C) will be search + + +----------------- +Workflow position +----------------- + + +.. image:: ./static/images/metabolomics/hr2.png + :width: 800 + + + + +----------- +Input files +----------- + ++-------------------------+-----------+ +| Parameter : num + label | Format | ++=========================+===========+ +| 1 : variableMetadata | tabular | ++-------------------------+-----------+ + +File variableMetadata must have at least the 2 following columns : + * Id : column to identify masses in the csv/tsv input file + * Masses : column with all the masses in the csv/tsv input file + + +---------- +Parameters +---------- + +Would you use a file + | Choose whether the masses are in a file or entered manually + | YES (default) : parameters **File of masses ; Column of Id ; Number of header ; Column of masses** are visible + | NO : parameter **Mass of the molecule** is visible + | + + +If 'use file'='YES' + +Column of Id + | Specify the column number for the id in the csv/tsv input file + | + +Number of header lines + | Number of lines not containing values + | + +Column of masses + | Specify the column number for the mass in the csv/tsv input file + | + +If 'use file'='NO' + +Mass (MZ) to submit + | Specify a list of mass to request + | one or more mass(es) entered manually + | For a masses list, writes : m1 m2 m3 + | You must separate yours values with space + | dot (.) is for float number + | + +In all cases : + +Delta + | Tolerance of the gap in the mass + | It should be between 0 and 9.0 mmu + +Ionization + | Type of ionization of the molecule : *positif, negatif, neutral* + | Use neutral if query doesn't be a [M+H] or [M-H] ion + | HR2 knows only the weight of uncharged molecules + | so we made a correction to the masses of the value of a proton before the search + | if the masses are those from a spectrometry in positive or negatif mode. + | **neutral** : will do a search on the mass unchanged. + +Initial charge + | Use 0 if the molecule is not basically charged + +Exclude some basic atom(s) + List of atoms that can be exclude to the molecule : *C, N, O, H, P* + +Golden rules + | There are 7 golden rules + | Some are too stringent, especially for small molecules + | Use 'yes' if you want more empirical formulas + +Add some optionnal atom(s) + List of atoms that can be searched in addition to the molecule : *S, F, Cl, K, Br, Na, 13C* + +------------ +Output files +------------ + +Two types of files + | hr2_VIEW.HTML : for viewing result via HTML. + | hr2_TSV.tabular : for linking with others modules. + | an excel-like output will be available. + +--------------------------------------------------- + + +--------------- +Working example +--------------- + + +.. class:: warningmark + +Refer to the corresponding "W4M HowTo" in http://workflow4metabolomics.org/howto section + | Format Data For Postprocessing + | Perform LCMS Annotations + +.. class:: warningmark + +And their "W4M courses 2018": + | Using Galaxy4Metabolomics - W4M table format for Galaxy + | Les banques d'annotation - Annotation + + ]]></help> + <citations> + <citation type="doi">10.1186/1471-2105-8-105</citation> + </citations> +</tool> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,63 @@ +## ****** HR2 environnemnt : ****** ## +# version sept 2014 M Landi / A LIEURADE, Cl LIONNET, P MARIJON, B RADISSON and L VARRAILHON / F Giacomoni + +## --- PERL compilator / libraries : --- ## +$ perl -v +This is perl, v5.10.1 (*) built for x86_64-linux-thread-multi + +# libs CORE PERL : +use strict ; +use warnings ; +use Carp qw (cluck croak carp) ; +use Data::Dumper ; +use Getopt::Long ; +use FindBin ; + +# libs CPAN PERL : +$ perl -e 'use Text::CSV' +$ sudo perl -MCPAN -e shell +cpan> install Text::CSV + +# libs pfem PERL : already include in the package +use lib::conf qw( :ALL ) ; +use lib::csv qw( :ALL ) ; +-- + +## --- R bin and Packages : --- ## +NA +-- + +## --- Binary dependencies --- ## +Install folowing binaries : +* HR2 : +source : HR2_v1.04.cpp available in the tar ball at lib/HR2_v1.04.cpp +lab : http://jhau.maliwi.de/sci/ms.html for initial project and http://fiehnlab.ucdavis.edu/projects/Seven_Golden_Rules/Software/ for fork +install : in /opt/prog/metabolomics/hr2 (you can change this path in conf file : conf_hr2.cfg +compilation : g++ HR2_v1.04.cpp -o HR2-all-res_v1.04.exe + +The project is available on : +http://fiehnlab.ucdavis.edu/projects/Seven_Golden_Rules/Software/seven-golden-rules-supplement-v46.zip (the launch of the download may take some time) +~/seven-golden-rules-supplement-v46.zip/supplement/HR2-formula-generator/HR2.zip/HR2.cpp +OR +http://sourceforge.net/projects/hires/ : This proposed binary is an fork of the HiRes initial project. +-- + +## --- Config : --- ## +Edit the following lines in the config file : conf_hr2.cfg +lancerHR2=/your_hr2_binary_path/HR2-all-res_v1.04.exe +JS_GALAXY_PATH=http://YOUR_GALAXY_HOSTNAME/static/scripts/libs/outputs +CSS_GALAXY_PATH=http://YOUR_GALAXY_HOSTNAME/static/style +-- + +## --- XML HELP PART --- ## +one image : in the static/images dir +hr2.png +-- + +## --- DATASETS --- ## +No data set ! waiting for galaxy pages +-- + +## --- ??? COMMENTS ??? --- ## +In the PFEM version, the HR2 source (HR2_v*.cpp) is modified to correct atom exact masses. +For more information, please contact us. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf_hr2.cfg Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,36 @@ +## Conf file for hr2.pl script +# +## Version -- edited by F.Giacomoni / M Landi +VERSION=1.1.0 +# +## ARGVT +## hr2 binary path +HR2_EXE=HR2.exe +HR2_VERSION=hr version 20050617 +# +##Default parameter values +tolerance=1.0 +mode=positive +charge=0 +DEFAULT_ATOMS=C,H,O,N +# +## Range in hr cmd for each atom +DEFAULT_MIN=0 +DEFAULT_MAX=10 +C=100 +H=200 +O=70 +N=40 +P=10 +# +## MZ value +proton=1.007825 +electron=0.0005486 +# +## Galaxy url for HTML JS and CSS path +JS_GALAXY_PATH=https://cdn.rawgit.com/fgiacomoni/galaxy_utils/master/scripts +CSS_GALAXY_PATH=https://cdn.rawgit.com/fgiacomoni/galaxy_utils/master/style +# +## HTML OUTPUT : +HTML_ENTRIES_PER_PAGE=4 +HTML_TEMPLATE=hr_out.tmpl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hr2_manager.pl Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,335 @@ +#!perl + +## script : hr2_manager.pl +## VERSIONS : +# - 01/03/2019 : Fix P issue, permit more flexible atom settings and add requirements for conda auto managing. + +#============================================================================= +# Included modules and versions +#============================================================================= +## Perl modules +use strict ; +use warnings ; +use Carp qw (cluck croak carp) ; + +use Data::Dumper ; +use Getopt::Long ; +use POSIX ; +use FindBin ; ## Allows you to locate the directory of original perl script + +## Dedicate Perl Modules (Home made...) +use lib $FindBin::Bin ; +my $binPath = $FindBin::Bin ; +use lib::hr qw( :ALL ) ; +## PFEM Perl Modules +use lib::conf qw( :ALL ) ; +use lib::csv qw( :ALL ) ; + +## Initialized values +use vars qw(%parametre); +my $help = undef ; +my ( $input_file, $line_header, $col_id, $col_mass ) = ( undef, undef, undef, undef ) ; # manage input option file of masses +my ( $mass ) = ( undef ) ; # manage input option masses list +my ( $tolerance, $mode, $charge, $has_golden_rules, $atomes, $atomes_basic ) = ( undef, undef, undef, undef, undef, undef ) ; # manage params +my ( $output_csv, $output_html ) = ( undef, undef) ; # manage ouputs +my $verbose = 2 ; + +#============================================================================= +# Manage EXCEPTIONS +#============================================================================= +&GetOptions ( "h" => \$help, # HELP + "input:s" => \$input_file, + "colId:i" => \$col_id, + "nbHeader:i" => \$line_header, + "colmass:i" => \$col_mass, + "masse:s" => \$mass, + "tolerance:f" => \$tolerance, + "mode:s" => \$mode, + "charge:i" => \$charge, + "regleOr:s" => \$has_golden_rules, + "atomes:s" => \$atomes_basic, # [basic atoms like CNOHP] + "atomessup:s" => \$atomes, + "output1:s" => \$output_csv, + "outputView:s" => \$output_html, + "verbose:i" => \$verbose, + ) ; + +#============================================================================= +# EXCEPTIONS +#============================================================================= +$help and &help ; + +#============================================================================= +# MAIN SCRIPT +#============================================================================= +my %atomsConf = () ; +$atomsConf{'C'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'H'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'N'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'O'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'P'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'S'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'F'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'L'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'K'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'B'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ 'A'} = {'min' => 0, 'max' => 0} ; +$atomsConf{ '1'} = {'min' => 0, 'max' => 0} ; + +## -------------- Conf file and verbose ------------------------ : +my ( $CONF ) = ( undef ) ; ## verbose level is 3 for debugg +my $time_start = time ; + +foreach my $conf ( <$binPath/*.cfg> ) { + my $oConf = lib::conf::new() ; + $CONF = $oConf->as_conf($conf) ; +} +## --------------- Global parameters ---------------- : +my ( $ids, $masses, $hr_cmds, $results, $parsed_results ) = ( undef, undef, undef, undef, undef ) ; +my $complete_rows = undef ; +my ($hr_atoms_list, $hr_atoms_and_ranges, $set_tol, ) = (undef, undef, undef, ) ; + +## Check and manage params +my $ohr = lib::hr->new() ; + +## set tolerance +$set_tol = $ohr->manage_tolerance( \$tolerance, \$CONF->{'tolerance'} ) ; + +## check HR exe envt : +my $hr_check = $ohr->check_hr_exe(\$CONF->{'HR2_EXE'}, \$CONF->{'HR2_VERSION'}) ; +if (!defined $hr_check ) { croak "No hr exe available (wrong path) or wrong version will be used -- end of script\n" ; } + +## manage atoms and their ranges +#$hr_atoms_list = $ohr->manage_atoms(\$atomes, \$CONF->{'DEFAULT_ATOMS'}) ; ## DEPRECATED + +# manage atoms and their ranges with a hash structure +my $atomsCurrentConf = $ohr->manage_atoms_and_ranges(\%atomsConf, $CONF, $atomes_basic, $atomes) ; + +#if ( defined $hr_atoms_list ) { +# ## implements range foreach atom +# foreach my $atom ( (split(",", $$hr_atoms_list )) ) { +# my $range_max = $CONF->{'DEFAULT_MAX'} ; # manage max value in case of +# if ( exists $CONF->{$atom} ) { $range_max = $CONF->{$atom} ; } +# my $ref_range = $ohr->manage_atom_and_range(\$atom, \$CONF->{'DEFAULT_MIN'}, \$range_max ) ; +# $hr_atoms_and_ranges .= $$ref_range ; ## concat ranges +# } +#} +#else { croak "No atom detected with input params\n" ; } + +## Parsing input file with masses/ids or unik mass : +## manage only one mass +if ( ( defined $mass ) and ( $mass ne "" ) and ( $mass > 0 ) ) { + $ids = ['mass_01'] ; + $masses = [$mass] ; + +} ## END IF +## manage csv file containing list of masses +elsif ( ( defined $input_file ) and ( $input_file ne "" ) and ( -e $input_file ) ) { + + ## parse all csv for later : output csv build + my $ocsv_input = lib::csv->new() ; + my $complete_csv = $ocsv_input->get_csv_object( "\t" ) ; + $complete_rows = $ocsv_input->parse_csv_object($complete_csv, \$input_file) ; + + ## parse csv ids and masses + my $is_header = undef ; + my $ocsv = lib::csv->new() ; + my $csv = $ocsv->get_csv_object( "\t" ) ; + if ( ( defined $line_header ) and ( $line_header > 0 ) ) { $is_header = 'yes' ; } else{ $is_header = 'no' ; } + $masses = $ocsv->get_value_from_csv_multi_header( $csv, $input_file, $col_mass, $is_header, $line_header ) ; ## retrieve mz values on csv + $ids = $ocsv->get_value_from_csv_multi_header( $csv, $input_file, $col_id, $is_header, $line_header ) ; ## retrieve ids values on csv + +} +else { + croak "Can't work with HR2 : missing input file or mass (list of masses, ids)\n" ; +} ## end ELSE + +## check using golden rules +if ( $has_golden_rules eq 'NO') { $has_golden_rules = undef ; } + +## ---------------- launch queries -------------------- : + +## prepare cmd +foreach my $mz (@{ $masses }) { + ## computes mass + my $ohr_mode = lib::hr->new() ; + my ( $exact_mass ) = $ohr_mode->manage_mode( \$mode, \$charge, \$CONF->{'electron'}, \$CONF->{'proton'}, \$mz ) ; + print "Current MZ send to HR\n" if $verbose == 3 ; + print Dumper $exact_mass if $verbose == 3 ; + ## build exe line + my $ohr_exe = lib::hr->new() ; + my $hr_cmd = $ohr_exe->config_hr_exe( \$CONF->{'HR2_EXE'}, \$tolerance, $exact_mass, \$has_golden_rules, \$atomsCurrentConf ) ; + print "$hr_cmd\n" if $verbose == 3 ; + push(@{$hr_cmds}, $$hr_cmd) ; +} + +## MultiThreading execution of Hr : +my $threads = lib::hr->new() ; +my $hr_object = lib::hr->new() ; +if ( $hr_object->can('hr_exe') ) { + my $method = $hr_object->can('hr_exe') ; + $results = $threads->threading_hr_exe( $method, $hr_cmds) ; + +} + +## MultiThreading parsing of Hr outputs : +my $hrres_object = lib::hr->new() ; +if ( $hrres_object->can('hr_out_parser') ) { + my $method = $hr_object->can('hr_out_parser') ; + if ( defined $results ) { $parsed_results = $threads->threading_hr_exe( $method, $results ) ; } +} + +## -------------- Produce HTML/CSV output ------------------ : +my $search_condition = 'Mode used: '.$mode.' / Charge: +'.$charge.' / Mass tolerance: '.$$set_tol.' / Composition: '.$atomsCurrentConf ; +## Uses N mz and theirs entries per page (see config file). +# how many pages you need with your input mz list? +my $nb_pages_for_html_out = ceil( scalar(@{$masses} ) / $CONF->{HTML_ENTRIES_PER_PAGE} ) ; + +if ( ( defined $output_html ) and ( defined $parsed_results ) ) { + my $oHtml = lib::hr::new() ; + my ($tbody_object) = $oHtml->set_html_tbody_object( $nb_pages_for_html_out, $CONF->{HTML_ENTRIES_PER_PAGE} ) ; + ($tbody_object) = $oHtml->add_mz_to_tbody_object($tbody_object, $CONF->{HTML_ENTRIES_PER_PAGE}, $masses, $ids, $parsed_results ) ; + ($tbody_object) = $oHtml->add_entries_to_tbody_object($tbody_object, $parsed_results) ; + my $html_file = $binPath.'/'.$CONF->{'HTML_TEMPLATE'} ; + my $output = $oHtml->write_html_skel(\$output_html, $tbody_object, $nb_pages_for_html_out, $search_condition, $html_file, $CONF->{'JS_GALAXY_PATH'}, $CONF->{'CSS_GALAXY_PATH'}) ; + +} ## END IF +else { + croak "Can't create a HTML output for HMDB : no result found or your output file is not defined\n" ; +} + +if ( ( defined $output_csv ) and ( defined $parsed_results ) ) { + # produce a csv based on METLIN format + my $ocsv = lib::hr::new() ; + if (defined $input_file) { + my $lm_matrix = undef ; + if ( ( defined $line_header ) and ( $line_header == 1 ) ) { $lm_matrix = $ocsv->set_hr_matrix_object('hr2', $masses, $parsed_results ) ; } + elsif ( ( defined $line_header ) and ( $line_header == 0 ) ) { $lm_matrix = $ocsv->set_hr_matrix_object(undef, $masses, $parsed_results ) ; } + $lm_matrix = $ocsv->add_hr_matrix_to_input_matrix($complete_rows, $lm_matrix) ; + $ocsv->write_csv_skel(\$output_csv, $lm_matrix) ; + } + elsif (defined $mass) { + $ocsv->write_csv_one_mass($masses, $ids, $parsed_results, $output_csv) ; + } +} ## END IF +else { +# croak "Can't create a tabular output for HR2 : no result found or your output file is not defined\n" ; +} + + + +### VERBOSE OUTPUTs +if ( $verbose == 3 ) { + print "-- Conf file contains :\n" ; + print Dumper $CONF ; + print "-- Atoms input list :\n" ; + print Dumper $atomes_basic ; + print "-- Suppl. atoms input list :\n" ; + print Dumper $atomes ; + print "-- HR envt ready :\n" ; + print Dumper $hr_check ; + print "-- Atoms and ranges :\n" ; + print Dumper $atomsCurrentConf ; + print "-- Tolerance :\n" ; + print Dumper $set_tol ; + print "-- Complete input file :\n" ; + print Dumper $complete_rows ; + print "-- Inputs initiales masses :\n" ; + print Dumper $masses ; + print "-- Inputs initiales ids :\n" ; + print Dumper $ids ; + print "-- Hr_Cmds :\n" ; + print Dumper $hr_cmds ; + print "-- Hr_Results :\n" ; +# print Dumper $results ; + print "-- Hr_parsed Results :\n" ; + print Dumper $parsed_results ; + + my $nb_results = scalar (@{$results}) ; + print "-- Hr_Results return : $nb_results\n" ; +} + +my $time_end = time ; +my $seconds = $time_end-$time_start ; +print "\n------ Time used in threaded mode by 6 : $seconds seconds --------\n\n" ; + + + + + + +#==================================================================================== +# Help subroutine called with -h option +# number of arguments : 0 +# Argument(s) : +# Return : 1 +#==================================================================================== +sub help { + print STDERR " +hr2_manager.pl + +# hr2_manager is a script to elucide chemical formula by their accurate masses. The HiRes program is integrate in this package +# Input : a accurate mass or a file of masses +# Author : Franck Giacomoni and Marion Landi +# Email : fgiacomoni\@clermont.inra.fr or mlandi\@clermont.inra.fr +# Version : 1.1 +# Created : 01/12/2011 +# Last Update : 09032014 +USAGE : + hr2_manager.pl -h or + hr2_manager.pl -input [cvs file of masses] -colId [int] -colmass [int] -nbHeader [int] -tolerance [float] -mode [positive, neutral or negative] -charge [int] -regleOr [yes or no] -atome [P, S, F, Cl, K, B, A, 1 ] -output1 [csv file] -outputView [html file] + hr2_manager.pl -masse [double] -tolerance [float] -mode [positive, neutral or negative] -charge [int] -regleOr [yes or no] -atome [P, S, F, Cl, K, B, A, 1 ] -output1 [csv file] -outputView [html file] + " ; + exit(1); +} + +## END of script - F Giacomoni + +__END__ + +=head1 NAME + + hr2_manager.pl -- script for launch / manage hr2 binary + +=head1 USAGE + + hr2_manager.pl -h or + hr2_manager.pl -input [cvs file of masses] -colId [int] -colmass [int] -nbHeader [int] -tolerance [float] -mode [positive, neutral or negative] -charge [int] -regleOr [yes or no] -atome [P, S, F, Cl, K, B, A, 1 ] -output1 [csv file] -outputView [html file] + hr2_manager.pl -masse [double] -tolerance [float] -mode [positive, neutral or negative] -charge [int] -regleOr [yes or no] -atome [P, S, F, Cl, K, B, A, 1 ] -output1 [csv file] -outputView [html file] + +=head1 SYNOPSIS + +This script manages hr2 binary which elucids raw formula with exact masses. + +=head1 DESCRIPTION + +This main program is a module to elucidate chemical formula with HiRes program. Source is available on Fiehn lab web. + +=over 4 + +=item B<function01> + +=item B<function02> + +=back + +=head1 AUTHOR + +Franck Giacomoni E<lt>franck.giacomoni@clermont.inra.frE<gt> +Marion Landi E<lt>marion.landi@clermont.inra.frE<gt> + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=head1 VERSION + +version 1 : 18/07/2012 + +version 2 : 02/10/2013 + +version 3 : 20/02/2014 + +version 4 : 01/03/2019 + +=cut \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hr_out.tmpl Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE html> +<html lang="en"> + <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content=""><meta name="author" content="INRA de Clermont-Ferrand"><title>Galaxy HR2 queries - All results</title><link rel="stylesheet" href="css.php" media="all"><link rel="stylesheet" href="<TMPL_VAR NAME=CSS_GALAXY_PATH>/simplePagination.css"/><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script><script src="<TMPL_VAR NAME=JS_GALAXY_PATH>/jquery.simplePagination.js"></script><style>body{padding-top:70px} div.lm-table-warning{font-size:1.4em;font-weight:bold;padding-right:25px;color:#21536a;margin-left:3px;}tr.green td{background-color:#eaf2d3;color:black;} tr.blank td{background-color:#9999CC;color:black;} table{font-family:\"Trebuchet MS\", Arial, Helvetica, sans-serif;width:100%;border-collapse:collapse;}table.detail, table.detail tr.parent, table.detail td, table.detail th, table.detail tr.category {border-collapse:collapse;border:1px solid #98bf21;}table.detail th {font-size:1.2em;text-align:center;padding-top:5px;padding-bottom:10px;background-color:#a7c942;color:#ffffff;}td.ca {text-align:center;}footer{margin:50px 0;}</style><script>function test(pageNumber){var page="#page-id-"+pageNumber;$('.select').hide();$(page).show()}</script></head> + <body><div class="container"><div class="lm-table-warning">Results of HR elucidation queries - <TMPL_VAR NAME=CONDITIONS></div><div id="detail_table_source" style="display:none"></div><p><div id="choose"></div><p><div id="ms_search_0" class="ms-search-table"></div><table id="detail_table" class="detail"><col style="width:20px;"><!-- Ids (m/z)--><col style="width:20px;"><!-- Mass (m/z)--><col style="width:20px;"><!-- Formula--><col style="width:60px;"><!-- cpd mw--><col style="width:50px;"><!-- delta--><col style="width:50px;"><!-- total--><thead><th>ID from input</th><th>Mass (m/z)</th><th>Formula</th><th>Compound MW (Da)</th><th>Delta</th><th>Total</th></thead><TMPL_LOOP NAME=PAGES><tbody class="select" id="page-id-<TMPL_VAR NAME=PAGE_NB>"><TMPL_LOOP NAME=MASSES><tr class="<TMPL_VAR NAME=MZ_COLOR>"><td class="ca" ><TMPL_VAR NAME=MASSES_ID_QUERY></td><td id="<TMPL_VAR NAME=MASSES_NB>" class="ca" ><TMPL_VAR NAME=MASSES_MZ_QUERY></td><td class="ca" colspan="3"></td><td class="ca" ><TMPL_VAR NAME=MASSES_TOTAL></td></tr><TMPL_LOOP NAME=ENTRIES><tr class="<TMPL_VAR NAME=ENTRY_COLOR>"><td class="ca" colspan="2"></td><td class="ca"><TMPL_VAR NAME=ENTRY_FORMULA></td><td class="ca"><TMPL_VAR NAME=ENTRY_CPD_MZ></td><td class="ca"><TMPL_VAR NAME=ENTRY_DELTA></td><td class="ca" colspan="1"></td></tr></TMPL_LOOP></TMPL_LOOP></tbody></TMPL_LOOP></table></div><div class="container"><hr><footer><div class="row"><div class="col-lg-12"><p><a href="http://jigsaw.w3.org/css-validator/check/referer" target="_blank"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" /></a></p><p>Copyright © INRA, N Paulhe, F Giacomoni 2014</a></p></div> </div></footer></div><script language="javascript">$(function() {$('#choose').pagination({items: <TMPL_VAR NAME=PAGES_NB>,itemsOnPage: 1,currentPage: 1,onInit: function () { test(1); },cssStyle: 'light-theme',onPageClick: function(pageNumber){test(pageNumber)}}).pagination('redraw');});</script></body> +</html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/HR2_v1.04.cpp Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,1018 @@ +/* + + HR2.C + V1.04 + (Changes: meb) + + A program to calculate elemental compositions for a given mass. + See the file README for details. + +-------------------------------------------------------------------- + Copyright (c) 2001...2005 Joerg Hau <joerg.hau(at)dplanet.ch>. + + mail: joerg.hau@dplanet.ch + www: http://www.mysunrise.ch/users/joerg.hau/ + + *changed version by Tobias Kind (TK), 2006 , Fiehnlab, + *added extended valencies, added implementation of + seven golden rules of molecular formula filtering + + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. See the + file LICENSE for details. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------- + + Creation: somewhere in 1992 by JHa. + Revision: 2001-04-18, GPL'd, first public release (JHa) + 2001-04-21, improved help text (JHa) + 2002-06-27, added sodium (JHa) + 2002-10-09, added 15N (JHa) + 2005-02-25, added -v option; license now GPL *v2* (JHa) + 2005-02-27, optimised code in calc loop (JHa) + 2005-02-28, verified and updated atomic masses (JHa) + 2005-06-17, added GPL text when "-h" is used (JHa) + 2006-01-01, extended version for BMC Bioinformatics publication - HR2 (TK) + 2006-03-03, added element ratio checks, extended valencies, only even electrons - HR2 (TK) + 2006-09-09, 1000x-10000x speedup hand optimized hehe. - HR2 (TK) + -->special version for CHNSOP-F-Cl-Br-Si + 2009-05-28, David Enot introduced the concept of 'Adducts' (nadd) for MZedDB and corrected + some inaccuracies in April 2008. Manfred Beckmann has now corrected the use of + 'nadd' and 'charge' by calculating 'nadd' from 'charge' using abscharge = abs(charge) + (did it manually because I couldn't find 'abs') to correct 'measured_mass' and limits, + but keeping nadd = 0 for rdb calculation of neutral MW (MB) + 2014-08-29, Marion Landi corrected the mass of atoms. + + This is ANSI C and should compile with any C compiler; use + something along the lines of "gcc -Wall -O3 -o hr hr.c". + "g++ -O2 -o myhr HR2.cpp" on a Mac OS X G5 proc + Optimize for speed, you may gain factor 3! + NOW compiled under Visual C++ Express (faster than GCC) in C++ mode for boolean type. + + + --------------------------------------------------------------------- + Example arguments: + 1) -m 1 -t 100000 -C 1-100 -H 1-220 -N 0-10 -O 0-10 -P 0-10 -S 0-10 -L 0-10 -B 0-10 + 2) -m 500 -t 1 -C 50-100 -H 10-220 -N 0-10 -O 0-10 -P 0-10 -S 0-10 -L 0-10 -B 0-10 + 3) hr2-all-res -c "Hexaflumuron_459.982882Da_3ppm" -m 459.982882 -t 1.37995 -C 0-39 -H 0-98 -N 0-34 -O 0-30 -P 0-12 -S 0-12 -F 0-12 -L 0-14 -B 0-7 -I 0-0 + 945 formulas found in 253 seconds. (now 4 seconds, before eternal) + 4) hr2 -m 459.982882 -t 1.37995 -C 10-39 -H 28-98 -N 4-34 -O 0-30 -P 1-12 -S 1-12 -F 0-12 -L 1-14 -B 2-6 -I 0-0 + 1 formula in 0 seconds (former eternal time) + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <time.h> + +/* Uncomment this for windows +#include <windows.h> +#include <process.h> +*/ +#include <math.h> + + +#define VERSION "20050617" /* String ! */ +#define TRUE 1 +#define FALSE 0 +#define MAXLEN 181 /* max. length of input string */ + +#define _CRT_SECURE_NO_DEPRECATE 1 + +typedef struct { + const char *sym; /* symbol */ + const char *symi; /* non iso symbol */ + const double mass; /* accurate mass */ + const float val; /* to calculate unsaturations */ + const int key; /* used for decoding cmd line */ + int min, /* atom count min */ + max, /* atom count max */ + cnt, /* atom count actual */ + save; /* atom count old - for loop exiting*/ + } Element; + + +/* --- atomic masses as published by IUPAC, 2002-10-02 ---------- */ + +Element el[]= +/* array of the elements used here: + Symbol, exact mass, dbe, keycode, number, default-min, default-max + dle: isoptopes are given by iC for 13C, iK for 41K etc.... +*/ +{ +{ "C", "C", 12.000000000, +2.0, 'C', 0, 100, 0,0 }, +{ "iC", "C", 13.0033548378, +2.0, '1', 0, 0, 0 ,0 }, +{ "H", "H", 1.0078250321, -1.0, 'H', 0, 200, 0 ,0}, +{ "iH", "H", 2.0141017780, -1.0, 'D', 0, 0, 0 ,0}, +{ "N", "N", 14.0030740052, +1.0, 'N', 0, 40, 0,0 }, //org +1 = valence = 3: now +3 for valence = 5 +{ "iN", "N", 15.0001088984, +1.0, 'M', 0, 0, 0,0 }, +{ "O", "O", 15.9949146221, 0.0, 'O', 0, 70, 0 ,0}, +{ "F", "F", 18.99840322, -1.0, 'F', 0, 0, 0 ,0}, +{ "Na", "Na", 22.98976928, -1.0, 'A', 0, 0, 0 ,0}, +{ "Si", "Si", 27.9769265327, +2.0, 'I', 0, 0, 0 ,0}, +{ "P", "P", 30.97376163, +3.0, 'P', 0, 10, 0 ,0}, //org +1 valence = 3: now +3 for valence = 5 +{ "S", "S", 31.97207069, +4.0, 'S', 0, 0, 0 ,0}, //org 0 = valence = 2; now +4 for valence = 6 +{ "Cl", "Cl", 34.96885268, -1.0, 'L', 0, 0, 0 ,0}, +{ "iCl", "Cl", 36.96590259, -1.0, 'E', 0, 0, 0 ,0}, // added dle +{ "Br", "Br", 78.9183371, -1.0, 'B', 0, 0, 0 ,0}, +{ "iBr", "Br", 80.9162906, -1.0, 'G', 0, 0, 0 ,0}, // added dle +{ "K", "K", 38.96370668, -1.0, 'K', 0, 0, 0 ,0}, // added dle +{ "iK", "K", 40.96182576, -1.0, 'J', 0, 0, 0 ,0}, // added dle +}; + +const double electron = 0.0005486; + + +/* --- global variables --- */ + +double charge, /* charge on the molecule */ + tol, /* mass tolerance in mmu */ + abscharge, /* abs(charge): to calculate 'measured_mass' and limits - meb */ + nadd; /* nadd now calculated as abs(charge) - meb */ +char comment[MAXLEN]=""; /* some text ;-) */ +int single; /* flag to indicate if we calculate only once and exit */ +int nr_el; /* number of elements in array (above) */ +bool verbose; +bool applygr; + +/* --- some variables needed for reading the cmd line --- */ + +char *optarg; /* global: pointer to argument of current option */ +static int optind = 1; /* global: index of which argument is next. Is used + as a global variable for collection of further + arguments (= not options) via argv pointers. */ + + +/* --- function prototypes ------------------- */ + +int input(char *text, double *zahl); +int readfile(char *whatfile); +double calc_mass(void); +float calc_rdb(void); +long do_calculations(double mass, double tolerance); +int clean (char *buf); +int getopt(int argc, char *argv[], char *optionS); +/* you have to compile with C++ or define yourself this bool type (C99 compiler definition) */ +bool calc_element_ratios(bool element_probability); + +/* --- threading ------------------- */ +/* mass and RDB calculation could be in several other threads +however the loop is very fast, context switching takes longer and +slows down the whole process. Single-Thread multiprocessor (cluster) implementation +seems superior here. */ +/* Uncomment for windows +HANDLE hThread2,hThread3; +unsigned threadID2,threadID3; +*/ + + +/* --- main --- */ + +int main (int argc, char **argv) +{ +double mz; /* mass */ +char buf[MAXLEN]; +int i, tmp; + +static char *id = +"hr version %s. Copyright (C) by Joerg Hau 2001...2005 & Tobias Kind 2006 :-).\n"; + +static char *disclaimer = +"\nThis program is free software; you can redistribute it and/or modify it under\n" +"the terms of version 2 of the GNU General Public License as published by the\n" +"Free Software Foundation.\n\n" +"This program is distributed in the hope that it will be useful, but WITHOUT ANY\n" +"WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n" +"PARTICULAR PURPOSE. See the GNU General Public License for details.\n"; + +static char *msg = +"Calculates possible elemental compositions for a given mass.\n\n" +"usage: hr [options] file\n\nValid command line options are:\n" +"-h This Help screen.\n" +"-v Display version information.\n" +"-t tol Set tolerance to 'tol' mmu (default 5).\n" +"-m mz Set mass to 'mz'.\n" +"-s Print only the results (dle)" +"-c Number of charges i.e -c 1 is equivalent to -p (dle).\n" +"-p Positive ions; electron mass is removed from the formula.\n" +"-n Negative ions; electron mass is added to the formula.\n" +"-g Does not apply 4-7 golden rules (dle).\n" +"-a Maximum num. of adducts. (dle)\n" +"-X a-b For element X, use atom range a to b. List of valid atoms:\n\n" +" X key mass (6 decimals shown)\n" +" -------------------------------------\n"; + +/* initialise variables */ + +nadd = 0.0; /* added dle: number of adducts*/ +single = FALSE; /* run continuously */ +charge = 0.0; /* default charge is neutral */ +tol = 1.0; /* default tolerance in mmu */ +nr_el = sizeof(el)/sizeof(el[0]); /* calculate array size */ +verbose = TRUE; /* added dle: should everything printed out?*/ +applygr = TRUE; /* added dle: should rules 4-7 applied?*/ + + +/* decode and read the command line */ + +while ((tmp = getopt(argc, argv, "hvpnsgt:m:c:a:C:H:N:M:O:D:1:S:F:L:B:P:I:A:K:E:G:J:")) != EOF) + switch (tmp) + { + case 'h': /* help me */ + printf (id, VERSION); + printf (msg); + for (i=0; i < nr_el; i++) + printf (" %4s -%c %15.6lf\n", + el[i].sym, el[i].key, el[i].mass); + printf(disclaimer, "\n"); + return 0; + case 'v': /* version */ + printf (id, VERSION); + return 0; + case 'p': /* positive charge */ + charge = +1.0; + continue; + case 's': /* simple output dle*/ + verbose = FALSE; + continue; + case 'n': /* negative carge */ + charge = -1.0; + continue; + case 'g': /* apply 7GR dle */ + applygr = false; + continue; + case 't': /* tolerance */ + strcpy(buf, optarg); + sscanf(buf, "%lf", &tol); + continue; + case 'a': /* num of adducts dle */ + strcpy(buf, optarg); + sscanf(buf, "%lf", &nadd); + continue; + case 'm': /* single mass */ + strcpy(buf, optarg); + sscanf(buf, "%lf", &mz); + single = TRUE; + continue; + case 'c': /* comment for single mass */ + strcpy(buf, optarg); + sscanf(buf, "%lf", &charge); + continue; + continue; + case 'C': /* C12 */ + case 'H': /* 1H */ + case 'N': /* 14N */ + case 'M': /* 15N */ + case 'O': /* 16O */ + case 'D': /* 2H */ + case '1': /* 13C */ + case 'A': /* Na ('N' is taken for Nitrogen!) */ + case 'S': /* 32S */ + case 'F': /* 19F */ + case 'L': /* 35Cl ('C' is taken!) */ + case 'E': /* 37Cl (chloridE!) */ + case 'B': /* 79Br */ + case 'K': /* 39K */ + case 'J': /* 41K */ + case 'G': /* 81Br */ + case 'P': /* 31P */ + case 'I': /* 28Si ('S' is taken!) */ + i = 0; + /* compare keys until found */ + while ((i < nr_el) && (el[i].key != tmp)) + i++; + strcpy(buf, optarg); + sscanf(buf, "%d-%d", &el[i].min, &el[i].max); /* copy over */ + if (el[i].min > el[i].max) /* swap them */ + { + tmp = el[i].min; + el[i].min = el[i].max; + el[i].max = tmp; + } + + /* printf ("\n %c = %c ... %s (%d-%d)", \ + tmp, el[i].key, el[i].sym, el[i].min, el[i].max); */ + continue; + case '~': /* invalid arg */ + default: + printf ("'%s -h' for help.\n", argv[0]); + return 1; + } + +if (argv[optind] != NULL) /* remaining parameter on cmd line? */ + /* must be a file -- treat it line by line */ + return (readfile (argv[optind])); + +if (single == TRUE) /* only one calculation requested? */ + do_calculations(mz, tol); /* do it, then exit ... */ +else + { /* otherwise run a loop */ + while (input(comment, &mz)) + { + tmp = do_calculations(mz, tol); + printf("\n"); + } + } + +return 0; +} + + +/*************************************************************************** +* INPUT: reads a dataset in "dialog mode". * +* Input: Pointer to comment text, pointer to mass. * +* Returns: Result of sscanf(), 0 if prog is to be finished. * +* Note: This is a fairly primitive way to do it, but it works ;-) * +****************************************************************************/ +int input(char *txt, double *zahl) +{ +char buf[MAXLEN]; /* input line */ + +*zahl = 0.0; /* reset */ + +printf("Comment : "); /* display prompt */ +fgets(buf, MAXLEN-1, stdin); /* read line */ +buf[MAXLEN] = 0x0; /* terminate string */ +clean (buf); /* remove linefeed */ +strcpy(txt, buf); /* copy text over */ + +printf("Mass (ENTER to quit): "); /* display prompt */ +fgets(buf, MAXLEN-1, stdin); /* read line */ +buf[MAXLEN] = 0x0; /* terminate string */ +if (!clean (buf)) /* only a CR ? --> quit */ + return 0; +sscanf(buf,"%lf", zahl); /* scan string */ + +return 1; +} + + +/*************************************************************************** +* READFILE: reads dataset from file. * +* Input: Pointer to comment text, pointer to mass. * +* Returns: 0 if OK, 1 if error. * +****************************************************************************/ +int readfile(char *whatfile) +{ +double mz; /* measured mass */ +char buf[MAXLEN]; /* input line */ +FILE *infile; + +infile = fopen(whatfile, "r"); +if (NULL == infile) + { + fprintf (stderr, "Error: Cannot open %s.", whatfile); + return 1; + } + +while (fgets(buf, MAXLEN-1, infile)) + { + buf[MAXLEN] = 0x0; /* terminate string */ + if (*buf == ';') /* comment line */ + continue; + if (!clean (buf)) /* only a CR ? --> quit */ + return 0; + sscanf(buf,"%s %lf", comment, &mz); /* scan string */ + do_calculations(mz, tol); + mz = 0.0; /* reset */ + } +return 0; +} + + +/************************************************************************ +* CALC_MASS: Calculates mass of an ion from its composition. * +* Input: nothing (uses global variables) * +* Returns. mass of the ion. * +* Note: Takes care of charge and electron mass! * +* (Positive charge means removal of electrons). * +*************************************************************************/ +double calc_mass(void) +{ +int i; +double sum = 0.0; + +for (i=0; i < nr_el; i++) + sum += el[i].mass * el[i].cnt; + +return (sum - (charge * electron)); +} + + +/************************************************************************ +* CALC_RDB: Calculates rings & double bond equivalents. * +* Input: nothing (uses global variables) * +* Returns. RDB. * +*************************************************************************/ +float calc_rdb(void) +{ +int i; +float sum = 2.0; + +for (i=0; i < nr_el; i++) + sum += el[i].val * el[i].cnt; + +return (sum/2.0); +} +/************************************************************************ +* Calculates element ratios , CH2 (more than 8 electrons needed is not handled) +* Calculations element probabilities if element_probability = true +* Input: nothing (uses global variables) +* Returns. true/false. +*************************************************************************/ +bool calc_element_ratios(bool element_probability) +{ +bool CHNOPS_ok; +float HC_ratio; +float NC_ratio; +float OC_ratio; +float PC_ratio; +float SC_ratio; + +/* added the number of isotopes to the calculation - dle*/ +float C_count = (float)el[0].cnt+(float)el[1].cnt; // C_count=12C+13C +float H_count = (float)el[2].cnt+(float)el[3].cnt; +float N_count = (float)el[4].cnt+(float)el[5].cnt; +/* modif end here */ +float O_count = (float)el[6].cnt; +float P_count = (float)el[10].cnt; +float S_count = (float)el[11].cnt; + + + /* ELEMENT RATIOS allowed + MIN MAX (99.99%) + H/C 0.07 6.00 + N/C 0.00 4.00 + O/C 0.00 3.00 + P/C 0.00 2.00 + S/C 0.00 6.00 + */ + + // set CHNOPS_ok = true and assume all ratios are ok + CHNOPS_ok = true; + /*element_probability = false; */ + + + if (C_count && H_count >0) // C and H must have one count anyway (remove for non-organics// + { + HC_ratio = H_count/C_count; + if (element_probability) + { + if ((HC_ratio < 0.2) || (HC_ratio > 3.0)) // this is the H/C probability check ; + CHNOPS_ok = false; + } + else if (HC_ratio > 6.0) // this is the normal H/C ratio check - type cast from int to float is important + CHNOPS_ok = false; + } + + if (N_count >0) // if positive number of nitrogens then thes N/C ratio else just calc normal + { + NC_ratio = N_count/C_count; + if (element_probability) + { + if (NC_ratio > 2.0) // this is the N/C probability check ; + CHNOPS_ok = false; + } + else if (NC_ratio > 4.0) + CHNOPS_ok = false; + } + + if (O_count >0) // if positive number of O then thes O/C ratio else just calc normal + { + OC_ratio = O_count/C_count; + if (element_probability) + { + if (OC_ratio > 1.2) // this is the O/C probability check ; + CHNOPS_ok = false; + } + else if (OC_ratio > 3.0) + CHNOPS_ok = false; + } + + if (P_count >0) // if positive number of P then thes P/C ratio else just calc normal + { + PC_ratio = P_count/C_count; + if (element_probability) + { + if (PC_ratio > 0.32) // this is the P/C probability check ; + CHNOPS_ok = false; + + } + else if (PC_ratio > 6.0) + CHNOPS_ok = false; + } + + if (S_count >0) // if positive number of S then thes S/C ratio else just calc normal + { + SC_ratio = S_count/C_count; + if (element_probability) + { + if (SC_ratio > 0.65) // this is the S/C probability check ; + CHNOPS_ok = false; + } + else if (SC_ratio > 2.0) + CHNOPS_ok = false; + } + +//----------------------------------------------------------------------------- + + // check for multiple element ratios together with probability check + //if N<10, O<20, P<4, S<3 then true + if (element_probability && (N_count > 10) && (O_count > 20) && (P_count > 4) && (S_count > 1)) + CHNOPS_ok = false; + + // NOP check for multiple element ratios together with probability check + // NOP all > 3 and (N<11, O <22, P<6 then true) + if (element_probability && (N_count > 3) && (O_count > 3) && (P_count > 3)) + { + if (element_probability && (N_count > 11) && (O_count > 22) && (P_count > 6)) + CHNOPS_ok = false; + } + + // OPS check for multiple element ratios together with probability check + // O<14, P<3, S<3 then true + if (element_probability && (O_count > 14) && (P_count > 3) && (S_count > 3)) + CHNOPS_ok = false; + + // PSN check for multiple element ratios together with probability check + // P<3, S<3, N<4 then true + if (element_probability && (P_count > 3) && (S_count > 3) && (N_count >4)) + CHNOPS_ok = false; + + + // NOS check for multiple element ratios together with probability check + // NOS all > 6 and (N<19 O<14 S<8 then true) + if (element_probability && (N_count >6) && (O_count >6) && (S_count >6)) + { + if (element_probability && (N_count >19) && (O_count >14) && (S_count >8)) + CHNOPS_ok = false; + } + + // function return value; + if (CHNOPS_ok == true) + return true; + else + return false; +} + +/************************************************************************ +* DO_CALCULATIONS: Does the actual calculation loop. * +* Input: measured mass (in amu), tolerance (in mmu) * +* Returns. number of hits. * +*************************************************************************/ +long do_calculations (double measured_mass, double tolerance) +{ +time_t start, finish; +double elapsed_time; + +double mass; /* calc'd mass */ +double limit_lo, limit_hi; /* mass limits */ +float rdb, lewis, rdbori; /* Rings & double bonds */ +long i,j; +long long hit; /* counts the hits, with long declaration, overflow after 25h with all formulas < 2000 Da + long = FFFFFFFFh = 4,294,967,295d*/ +int niso; +long long counter; +bool elementcheck; +bool set_break; + + +time( &start ); // start time + +/* calculate limits */ +/* correct m/z value 'measured_mass' for z>1 using 'abscharge'; +keep charge = 0 for neutral mass searches (z=0); +additionally, keep the idea of 'adducts' for 'rdb', but use charge state instead -meb */ +if (charge<0) { + abscharge = -charge; + nadd = abscharge; +} else if (charge>0) { + abscharge = charge; + nadd = abscharge; +} else if (charge==0) { + abscharge = 1; /* for limits */ + nadd = 0; /* for rdb */ +} + +limit_lo = (measured_mass * abscharge) - (tolerance / 1000.0); +limit_hi = (measured_mass * abscharge) + (tolerance / 1000.0); + +if(verbose) /* extended output as in original code - dle */ +{ + if (strlen(comment)) /* print only if there is some text to print */ + printf ("Text \t%s\n", comment); + + printf("\n"); /* linefeed */ + printf ("Composition = \t"); + for (i=0; i < nr_el; i++) + if (el[i].max > 0) + printf("%s:%d-%d ", el[i].sym, el[i].min, el[i].max); + printf ("\n"); + + printf ("Mass Tolerance [mmu]: \t%.1f\n",tolerance); + printf ("Measured Mass: \t%.6lf\n", measured_mass); + printf ("Charge: \t%+.0lf\n", charge); /* dle */ + printf ("Num. of Adducts/Losses: \t%.0lf\n", nadd); /* dle */ + printf ("Apply 7GR: \t%d\n\n", applygr); /* dle */ +} + +hit = 0; /* Reset counter */ +counter = 0; +set_break = false; /* set breaker for element counts to false */ + +/* Now let's run the big big loop ... I'd like to do that + recursively but did not yet figure out how ;-) + TK Adds: the loop is just fine. +*/ + +/* now comes the "COOL trick" for calculating all formulae: +sorting the high mass elements to the outer loops, the small weights (H) +to the inner loops; + +This will reduce the computational time by factor ~10-60-1000 +OLD HR: Cangrelor at 1ppm 4465 formulas found in 5866 seconds. +NEW HR2: Cangrelor at 1ppm 4465 formulas found in 96 seconds. +NEW2 HR2: Cangrelor at 1ppm 4465 formulas found in 60 seconds. +NEW3 HR2: Cangrelor at 1ppm 4465 formulas found in 59 seconds. +HR2 Fast: Cangrelor at 1ppm 4465 formulas found in 41 seconds by evaluating 2,003,436,894 formulae. +hr2 -c "Cangrelor" -m 774.948 -t 0.77 -C 1-64 -H 1-112 -N 0-30 -O 0-80 -P 0-12 -S 0-9 -F 0-10 -L 0-10 + +Another additional trick is to end the 2nd.. 3rd.. 4th.. xth innermost loop +to prevent loops which are just higher and higher in mass. +*/ + + /*dle: process new elements */ +el[17].cnt = el[17].min - 1; el[17].save = el[17].cnt; +while (el[17].cnt++ < el[17].max) /*"iK"*/{ + +el[16].cnt = el[16].min - 1; el[16].save = el[16].cnt; +while (el[16].cnt++ < el[16].max) /*"K"*/{ + +el[15].cnt = el[15].min - 1; el[15].save = el[15].cnt; +while (el[15].cnt++ < el[15].max) /* "iBr"*/ { + +el[14].cnt = el[14].min - 1; el[14].save = el[14].cnt; +while (el[14].cnt++ < el[14].max) /* "Br"*/ { + +el[13].cnt = el[13].min - 1; el[13].save = el[13].cnt; +while (el[13].cnt++ < el[13].max) /*"iCl"*/ { + +el[12].cnt = el[12].min - 1; el[12].save = el[12].cnt; +while (el[12].cnt++ < el[12].max) /*"Cl"*/ { + +el[11].cnt = el[11].min - 1; el[11].save = el[11].cnt; +while (el[11].cnt++ < el[11].max) /*"S"*/ { + +el[10].cnt = el[10].min - 1; el[10].save = el[10].cnt; +while (el[10].cnt++ < el[10].max) /*"P"*/ { + +el[9].cnt = el[9].min - 1; el[9].save = el[9].cnt; +while (el[9].cnt++ < el[9].max) /*"Si"*/ { + +el[8].cnt = el[8].min - 1; el[8].save = el[8].cnt; +while (el[8].cnt++ < el[8].max) /*"Na"*/{ + +el[7].cnt = el[7].min - 1; el[7].save = el[7].cnt; +while (el[7].cnt++ < el[7].max) /*"F"*/ { + +el[6].cnt = el[6].min - 1; el[6].save = el[6].cnt; +while (el[6].cnt++ < el[6].max) /*"O"*/ { + +el[5].cnt = el[5].min - 1; el[5].save = el[5].cnt; +while (el[5].cnt++ < el[5].max) /*"15N"*/{ + +el[4].cnt = el[4].min - 1; el[4].save = el[4].cnt; +while (el[4].cnt++ < el[4].max) /*"N"*/{ + +el[1].cnt = el[1].min - 1; el[1].save = el[1].cnt; +while (el[1].cnt++ < el[1].max) /*"13C"*/ { + +el[0].cnt = el[0].min - 1; el[0].save = el[0].cnt; +while (el[0].cnt++ < el[0].max) /* "C"*/ { + +el[3].cnt = el[3].min - 1; el[3].save = el[3].cnt; +while (el[3].cnt++ < el[3].max) /*"D"*/{ + +el[2].cnt = el[2].min - 1; el[2].save = el[2].cnt; +while (el[2].cnt++ < el[2].max) /*"H"*/{ + + mass = calc_mass(); + counter++; + + //just for debug purposes + //if (mass > limit_hi) + //printf("mass: %f\tC: %d H: %d N: %d O: %d P: %d S: %d Cl: %d Br: %d\n",mass,el[0].cnt,el[2].cnt,el[4].cnt,el[6].cnt,el[10].cnt,el[11].cnt,el[12].cnt,el[13].cnt); + + /* if we exceed the upper limit, we can stop the calculation + for this particular element (JHa 20050227). <-- comment TK that will only bust the innermost while loop, which is "H"*/ + + // break H loop + if (mass > limit_hi) break; + + //************************************************************************************************************/ + //Calculus loop with print out + //************************************************************************************************************/ + + if ((mass >= limit_lo) && (mass <= limit_hi)) /* within limits? */ + { + // element check will be performed always, if variable bool element_probability is true also probabilities will be calculated + // not an elegant implementation, but fast. + + elementcheck = calc_element_ratios(applygr); /* pass applygr boolean by dle */ + + if (elementcheck) + { + rdbori = calc_rdb(); /* get RDB */ + + rdb = rdbori + 0.5*nadd; /* dle: if nadd addcuts */ + lewis = (float)(fmod(rdb, 1)); /*calc reminder*/ + if ((rdb >= 0) && (lewis != 0.5) && (lewis !=-0.5))/* less than -0.5 RDB does not make sense */ + { /* NO(!) CH3F10NS2 exists , RDB = -4.0 M= 282.9547*/ + hit ++; + for (i = 0; i < nr_el; i++) /* print composition */ + if (el[i].cnt > 0) /* but only if useful */ + printf("%s%d.", el[i].sym, el[i].cnt); // print formula + + printf("\t"); + /* dle: print out a more explicit molecular formula for further processing and + variable niso counts number of isotope elements in the solution */ + niso=0; + for (i = 0; i < nr_el; i++) + { /* print composition */ + if (el[i].cnt > 0) + { /* but only if useful */ + printf("%s%d", el[i].symi, el[i].cnt); // print formula + if (el[i].symi != el[i].sym) + niso=niso+el[i].cnt; + } + + } + /* dle: end of molecular print out */ + + /* dle: additionnaly print nadd and niso */ + printf("\t%.2f\t%.7lf\t%.0lf\t%d\t%+.2lf\n", rdb, mass, nadd,niso, 1000.0 * ((measured_mass * abscharge) - mass)); + + } /* end of 'rdb' loop */ + + } // end of elementcheck loop + + } /* end of 'limit' loop */ + //************************************************************************************************************/ + + + /* + TK: if the current mass is larger than the limit the loop can be exited. + Each element must point to the element which is in use and before. + This is a static implementation which can be enhanced with a pointer chain to the lower element. + Actually now its only allowed for CHNSOP-Fl-Cl-Br-Si !!! Brute-force <> elegance :-) + */ + } /*"H"*/ + + if ((mass >= limit_lo) && (el[2].save == el[2].cnt-1)) break; + } /*"D"*/ + + if ((mass >= limit_lo) && (el[3].save == el[3].cnt-1)) break; /* dle addons */ + } /* "C"*/ + + if ((mass >= limit_lo) && (el[0].save == el[0].cnt-1)) break; + } /*"13C"*/ + + if ((mass >= limit_lo) && (el[1].save == el[1].cnt-1)) break; /* dle addons */ + } /*"N"*/ + + if ((mass >= limit_lo) && (el[4].save == el[4].cnt-1)) break; + } /*"15N"*/ + + if ((mass >= limit_lo) && (el[5].save == el[5].cnt-1)) break; /* dle addons */ + } /*"O"*/ + + if ((mass >= limit_lo) && (el[6].save == el[6].cnt-1)) break; + } /*"F"*/ + + if ((mass >= limit_lo) && (el[7].save == el[7].cnt-1)) break; + } /*"Na"*/ + + if ((mass >= limit_lo) && (el[8].save == el[8].cnt-1)) break; + } /*"Si"*/ + + if ((mass >= limit_lo) && (el[9].save == el[9].cnt-1)) break; + } /*"P"*/ + + if ((mass >= limit_lo) && (el[10].save == el[10].cnt-1)) break; + } /*"S"*/ + + if ((mass >= limit_lo) && (el[11].save == el[11].cnt-1)) break; + } /*"Cl"*/ + + if ((mass >= limit_lo) && (el[12].save == el[12].cnt-1)) break; + } /*"iCl"*/ + + if ((mass >= limit_lo) && (el[13].save == el[13].cnt-1)) break; /* dle addons */ + } /*"Br"*/ + + if ((mass >= limit_lo) && (el[14].save == el[14].cnt-1)) break; + } /*"iBr"*/ + + if ((mass >= limit_lo) && (el[15].save == el[15].cnt-1)) break; /* dle addons */ + } /*"K"*/ + + if ((mass >= limit_lo) && (el[16].save == el[16].cnt-1)) break; /* dle addons */ + } /*"iK"*/ + +/* close that giant loop thing started above */ + + + + +time(&finish); // stop timer +elapsed_time = difftime(finish , start); // calulate time difference + +if(verbose){ + if (!hit) + printf("No matching combination found in %6.0f seconds.\n", elapsed_time ); + else{ + printf("\n%llu formulas found in %6.0f seconds by evaluating %llu formulae.\n",hit,elapsed_time,counter); + printf("RDBs are overloaded to maximum valence values (N=3,P=5,S=6).\n"); + } +} +return hit; +} + + +/************************************************************************ +* CLEAN: "cleans" a buffer obtained by fgets() * +* Input: Pointer to text buffer * +* Returns: strlen of buffer. * +*************************************************************************/ +int clean (char *buf) +{ +int i; + +for(i = 0; i < strlen(buf); i++) /* search for CR/LF */ + { + if(buf[i] == '\n' || buf[i] == '\r') + { + buf[i] = 0; /* stop at CR or LF */ + break; + } + } +return (strlen(buf)); +} + + + +/*************************************************************************** +* GETOPT: Command line parser, system V style. +* +* This routine is widely (and wildly) adapted from code that was +* made available by Borland International Inc. +* +* Standard option syntax is: +* +* option ::= SW [optLetter]* [argLetter space* argument] +* +* where +* - SW is '-' +* - there is no space before any optLetter or argLetter. +* - opt/arg letters are alphabetic, not punctuation characters. +* - optLetters, if present, must be matched in optionS. +* - argLetters, if present, are found in optionS followed by ':'. +* - argument is any white-space delimited string. Note that it +* can include the SW character. +* - upper and lower case letters are distinct. +* +* There may be multiple option clusters on a command line, each +* beginning with a SW, but all must appear before any non-option +* arguments (arguments not introduced by SW). Opt/arg letters may +* be repeated: it is up to the caller to decide if that is an error. +* +* The character SW appearing alone as the last argument is an error. +* The lead-in sequence SWSW ("--") causes itself and all the rest +* of the line to be ignored (allowing non-options which begin +* with the switch char). +* +* The string *optionS allows valid opt/arg letters to be recognized. +* argLetters are followed with ':'. Getopt () returns the value of +* the option character found, or EOF if no more options are in the +* command line. If option is an argLetter then the global optarg is +* set to point to the argument string (having skipped any white-space). +* +* The global optind is initially 1 and is always left as the index +* of the next argument of argv[] which getopt has not taken. Note +* that if "--" or "//" are used then optind is stepped to the next +* argument before getopt() returns EOF. +* +* If an error occurs, that is an SW char precedes an unknown letter, +* then getopt() will return a '~' character and normally prints an +* error message via perror(). If the global variable opterr is set +* to false (zero) before calling getopt() then the error message is +* not printed. +* +* For example, if +* +* *optionS == "A:F:PuU:wXZ:" +* +* then 'P', 'u', 'w', and 'X' are option letters and 'A', 'F', +* 'U', 'Z' are followed by arguments. A valid command line may be: +* +* aCommand -uPFPi -X -A L someFile +* +* where: +* - 'u' and 'P' will be returned as isolated option letters. +* - 'F' will return with "Pi" as its argument string. +* - 'X' is an isolated option. +* - 'A' will return with "L" as its argument. +* - "someFile" is not an option, and terminates getOpt. The +* caller may collect remaining arguments using argv pointers. +***************************************************************************/ +int getopt(int argc, char *argv[], char *optionS) +{ +static char *letP = NULL; /* remember next option char's location */ +static char SW = '-'; /* switch character */ + +int opterr = 1; /* allow error message */ +unsigned char ch; +char *optP; + +if (argc > optind) + { + if (letP == NULL) + { + if ((letP = argv[optind]) == NULL || *(letP++) != SW) + goto gopEOF; + + if (*letP == SW) + { + optind++; + goto gopEOF; + } + } + if (0 == (ch = *(letP++))) + { + optind++; + goto gopEOF; + } + if (':' == ch || (optP = strchr(optionS, ch)) == NULL) + goto gopError; + if (':' == *(++optP)) + { + optind++; + if (0 == *letP) + { + if (argc <= optind) + goto gopError; + letP = argv[optind++]; + } + optarg = letP; + letP = NULL; + } + else + { + if (0 == *letP) + { + optind++; + letP = NULL; + } + optarg = NULL; + } + return ch; +} + +gopEOF: + optarg = letP = NULL; + return EOF; + +gopError: + optarg = NULL; + errno = EINVAL; + if (opterr) + perror ("Command line option"); + return ('~'); +} + +/* +List of elements sorted according to mass +_______________________ +INo# El Mass +2 H 1.007825032 +3 D 2.014101778 +0 C 12 +1 13C 13.00335484 +4 N 14.00307401 +5 15N 15.0001089 +6 O 15.99491462 +7 F 18.9984032 +8 Na 22.98976967 +9 Si 27.97692653 +10 P 30.97376151 +11 S 31.97207069 +12 Cl 34.96885271 +13 Br 78.9183376 +------------------------ +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/conf.pm Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,259 @@ +package lib::conf ; + +use strict; +use warnings ; +use Exporter ; +use Carp ; +use Data::Dumper ; + +use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS); + +our $VERSION = "1.0" ; +our @ISA = qw(Exporter) ; +our @EXPORT = qw( as_conf get_value_from_conf check_path_and_file ) ; +our %EXPORT_TAGS = ( ALL => [qw( as_conf get_value_from_conf )] ) ; + +=head1 NAME + +conf - A module for manage pfem conf file + +=head1 SYNOPSIS + + use conf ; + my $object = conf->new() ; + +=head1 DESCRIPTION + +This module does manage conf file (extract all or selected fields) + +=head1 METHODS + +Methods are : + +=head2 METHOD new + + ## Description : new + ## Input : $self + ## Ouput : bless $self ; + ## Usage : new() ; + +=cut +## START of SUB +sub new { + ## Variables + my $self={}; + bless($self) ; + return $self ; +} +### END of SUB + +=head2 METHOD as_conf + + ## Description : permet de cr�er l'object conf � partir d'un fichier de conf de type KEY=VALUE + ## Input : $file + ## Ouput : $oConf (a hash) + ## Usage : my ( $oConf ) = as_conf( $file ) ; + +=cut +## START of SUB +sub as_conf { + ## Retrieve Values + my $self = shift ; + my ( $file, $separator ) = @_ ; + +# if (!defined $separator) { $separator = ';' } ## set separator to ; + + if ( !defined $file ) { croak "Can't create object with an none defined file\n" ; } + + my %Conf = () ; ## Hash devant contenir l'ensemble des parametres locaux + + if (-e $file) { + open (CFG, "<$file") or die "Can't open $file\n" ; + while (<CFG>) { + chomp $_ ; + if ( $_ =~ /^#(.*)/) { next ; } + elsif ($_ =~/^(\w+?)=(.*)/) { ## ALPHANUMERIC OR UNDERSCORE ONLY FOR THE KEY AND ANYTHING ELSE FOR VALUE + + my ($key, $value) = ($1, $2) ; + + if (defined $separator) { + if ( $value=~/$separator/ ) { ## is a list to split + my @tmp = split(/$separator/ , $value) ; + $Conf{$key} = \@tmp ; + } + } + else { + $Conf{$key} = $value ; + } + } + } + close(CFG) ; + } + else { + croak "Can't create object with an none existing file\n" ; + } + + return ( \%Conf ) ; +} +## END of SUB + +=head2 METHOD as_conf_list + + ## Description : permet de charger une liste txt en array + ## Input : $file + ## Output : elements + ## Usage : my ( elements ) = as_conf_list( $conf_file ) ; + +=cut +## START of SUB +sub as_conf_list { + ## Retrieve Values + my $self = shift ; + my ( $file ) = @_ ; + + my @elements = () ; + if ( !defined $file ) { croak "Can't create object with an none defined file\n" ; } + + if (-e $file) { + open (CFG, "<$file") or die "Can't open $file\n" ; + while (<CFG>) { + chomp $_ ; + if ( $_ =~ /^#(.*)/) { next ; } + elsif ($_ =~/^(.*)/) { if (defined $1) { push (@elements, $1) ; } } + } + } + else { + croak "Can't create object with an none existing file\n" ; + } + return(\@elements) ; +} +## END of SUB + +=head2 METHOD get_value_from_conf + + ## Description : permet de retourner une valeur du hash de conf � partir d'une key + ## Input : $oConf, $Key + ## Ouput : $Value + ## Usage : my ( $Value ) = get_value_from_conf( $oConf, $Key ) ; + +=cut +## START of SUB +sub get_value_from_conf { + ## Retrieve Values + my $self = shift ; + my ( $oConf, $Key ) = @_ ; + + my $Value = undef ; + + if ( defined $oConf ) { + if ( defined $oConf->{$Key} ) { + $Value = $oConf->{$Key} ; + } + } + else { + croak "Can't manage value with undefined object\n" ; + } + return($Value) ; +} +## END of SUB + +=head2 METHOD get_value_from_conf + + ## Description : permet de retourner une valeur du hash de conf � partir d'une key + ## Input : $oConf, $Key + ## Ouput : $Value + ## Usage : my ( $Value ) = get_value_from_conf( $oConf, $Key ) ; + +=cut +## START of SUB +sub split_value_from_conf { + ## Retrieve Values + my $self = shift ; + my ( $oConf, $Key, $sep ) = @_ ; + + my $value = undef ; + my @values = () ; + + if ( defined $oConf ) { + if ( defined $oConf->{$Key} ) { + $value = $oConf->{$Key} ; + @values = split ( /$sep/, $value) ; + } + } + else { + croak "Can't manage value with undefined object\n" ; + } + return(\@values) ; +} +## END of SUB + + +=head2 METHOD check_path_and_file + + ## Description : permet de v�rifier les path et la pr�sence des exe d�crits dans le file conf. Bloque le script en cas de probleme + ## Input : $oConfs + ## Ouput : NA + ## Usage : &get_value_from_conf( $oConf ) ; + +=cut +## START of SUB +sub check_path_and_file { + + my $self = shift ; + my ( $oConfs ) = @_ ; + + foreach my $conf ( keys %{ $oConfs } ) { + if ( $conf =~ /^FILE/ ) { + if ( -e $oConfs->{$conf} ) { + if ( -s $oConfs->{$conf} ) { next ; } + else { carp "[Warning] : The size of file $oConfs->{$conf} is null\n" ; } + } + else { + carp "[Warning] : The file $oConfs->{$conf} doesn't exist\n" ; + } + } + elsif ( $conf =~ /^PATH/ ) { + if ( -d $oConfs->{$conf} ) { next ; } + else { carp "[Warning] : The dir $oConfs->{$conf} doesn't exist\n" ; } + } + else { next ; } + } + return ; +} +## END of SUB + +1 ; + + +__END__ + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc conf.pm + + +=head1 Exports + +=over 4 + +=item :ALL is as_conf get_value_from_conf + +=back + +=head1 AUTHOR + +Franck Giacomoni E<lt>franck.giacomoni@clermont.inra.frE<gt> + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=head1 VERSION + +version 1 : 10 / 02 / 2013 + +version 2 : ?? + +=cut \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/csv.pm Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,282 @@ +package lib::csv ; + +use strict; +use warnings ; +use Exporter ; +use Carp ; + +use Text::CSV ; + +use Data::Dumper ; + +use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS); + +our $VERSION = "1.0"; +our @ISA = qw(Exporter); +our @EXPORT = qw( get_csv_object get_value_from_csv ); +our %EXPORT_TAGS = ( ALL => [qw( get_csv_object get_value_from_csv )] ); + +=head1 NAME + +My::Module - An example module + +=head1 SYNOPSIS + + use My::Module; + my $object = My::Module->new(); + print $object->as_string; + +=head1 DESCRIPTION + +This module does not really exist, it +was made for the sole purpose of +demonstrating how POD works. + +=head1 METHODS + +Methods are : + +=head2 METHOD new + + ## Description : new + ## Input : $self + ## Ouput : bless $self ; + ## Usage : new() ; + +=cut + +sub new { + ## Variables + my $self={}; + bless($self) ; + return $self ; +} +### END of SUB + +=head2 METHOD get_csv_object + + ## Description : builds a csv object and etablishes format + ## Input : $separator + ## Output : $csv + ## Usage : my ( $csv ) = get_csv_object( $separator ) ; + +=cut +## START of SUB +sub get_csv_object { + ## Retrieve Values + my $self = shift ; + my ( $separator ) = @_ ; + +# my $csv = Text::CSV->new({'sep_char' => "$separator"}); + my $csv = Text::CSV->new ( {'sep_char' => "$separator", binary => 1 } ) # should set binary attribute. + or die "Cannot use CSV: ".Text::CSV->error_diag (); + + return($csv) ; +} +## END of SUB + +=head2 METHOD get_value_from_csv + + ## Description : extract a targeted column in a csv file + ## Input : $csv, $file, $column, $is_header + ## Output : $value + ## Usage : my ( $value ) = get_value_from_csv( $csv, $file, $column, $is_header ) ; + +=cut +## START of SUB +sub get_value_from_csv { + ## Retrieve Values + my $self = shift ; + my ( $csv, $file, $column, $is_header ) = @_ ; + + my @value = () ; + + ## Adapte the number of the colunm : (nb of column to position in array) + $column = $column - 1 ; + + open (CSV, "<", $file) or die $! ; + + my $line = 0 ; + + while (<CSV>) { + $line++ ; + chomp $_ ; + # file has a header + if ( defined $is_header ) { if ($line == 1) { next ; } } + # parsing the targeted column + if ( $csv->parse($_) ) { + my @columns = $csv->fields(); + push ( @value, $columns[$column] ) ; + } + else { + my $err = $csv->error_input; + die "Failed to parse line: $err"; + } + } + close CSV; + return(\@value) ; +} +## END of SUB + +=head2 METHOD get_value_from_csv_multi_header + + ## Description : extract a targeted column in a csv file + ## Input : $csv, $file, $column, $is_header, $nb_header + ## Output : $value + ## Usage : my ( $value ) = get_value_from_csv_multi_header( $csv, $file, $column, $is_header, $nb_header ) ; + +=cut +## START of SUB +sub get_value_from_csv_multi_header { + ## Retrieve Values + my $self = shift ; + my ( $csv, $file, $column, $is_header, $nb_header ) = @_ ; + + my @value = () ; + + ## Adapte the number of the colunm : (nb of column to position in array) + $column = $column - 1 ; + + open (CSV, "<", $file) or die $! ; + + my $line = 0 ; + + while (<CSV>) { + $line++ ; + chomp $_ ; + # file has a header + if ( defined $is_header and $is_header eq 'yes') { if ($line <= $nb_header) { next ; } } + # parsing the targeted column + if ( $csv->parse($_) ) { + my @columns = $csv->fields(); + push ( @value, $columns[$column] ) ; + } + else { + my $err = $csv->error_input; + die "Failed to parse line: $err"; + } + } + close CSV; + return(\@value) ; +} +## END of SUB + +=head2 METHOD parse_csv_object + + ## Description : parse_all csv object and return a array of rows + ## Input : $csv, $file + ## Output : $csv_matrix + ## Usage : my ( $csv_matrix ) = parse_csv_object( $csv, $file ) ; + +=cut +## START of SUB +sub parse_csv_object { + ## Retrieve Values + my $self = shift ; + my ( $csv, $file ) = @_ ; + + my @csv_matrix = () ; + + open my $fh, "<:encoding(utf8)", $$file or die "Can't open csv file $$file: $!"; + + while ( my $row = $csv->getline( $fh ) ) { + push @csv_matrix, $row; + } + $csv->eof or $csv->error_diag(); + close $fh; + + return(\@csv_matrix) ; +} +## END of SUB + +=head2 METHOD parse_allcsv_object + + ## Description : parse_all csv object and return a array of rows with or without header + ## Input : $csv, $file, $keep_header + ## Output : $csv_matrix + ## Usage : my ( $csv_matrix ) = parse_csv_object( $csv, $file, $keep_header ) ; + +=cut +## START of SUB +sub parse_allcsv_object { + ## Retrieve Values + my $self = shift ; + my ( $csv, $file, $keep_header ) = @_ ; + + my @csv_matrix = () ; + my $line = 1 ; + + open my $fh, "<:encoding(utf8)", $$file or die "Can't open csv file $$file: $!"; + + while ( my $row = $csv->getline( $fh ) ) { + if ( ( $keep_header eq 'n' ) and ($line == 1) ) { } + else { push @csv_matrix, $row; } + $line ++ ; + } + my $status = $csv->eof or $csv->error_diag(); + close $fh; + + return(\@csv_matrix, $status) ; +} +## END of SUB + + +=head2 METHOD write_csv_from_arrays + + ## Description : write a csv file from list of rows + ## Input : $csv, $file_name, $rows + ## Output : $csv_file + ## Usage : my ( $csv_file ) = write_csv_from_arrays( $csv, $file_name, $rows ) ; + +=cut +## START of SUB +sub write_csv_from_arrays { + ## Retrieve Values + my $self = shift ; + my ( $csv, $file_name, $rows ) = @_ ; + + my $fh = undef ; + $csv->eol ("\n"); ## end-of-line string to add to rows + open $fh, ">:encoding(utf8)", "$file_name" or die "$file_name: $!"; + + my $status = $csv->print ($fh, $_) for @{$rows}; + close $fh or die "$file_name: $!"; + + return(\$file_name) ; +} +## END of SUB + +1 ; + + +__END__ + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc csv.pm + +=head1 Exports + +=over 4 + +=item :ALL is get_csv_object, get_value_from_csv + +=back + +=head1 AUTHOR + +Franck Giacomoni E<lt>franck.giacomoni@clermont.inra.frE<gt> + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=head1 VERSION + +version 1 : 23 / 10 / 2013 + +version 2 : ?? + +=cut \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/hr.pm Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,775 @@ +package lib::hr ; + +use strict; +no strict "refs" ; +use warnings ; +use Exporter ; +use threads ; +use HTML::Template ; +use Carp ; + +use Data::Dumper ; + +use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS); + +our $VERSION = "1.0"; +our @ISA = qw(Exporter); +our @EXPORT = qw( manage_atoms_and_ranges manage_atoms check_hr_exe manage_atom_and_range manage_tolerance manage_mode config_hr_exe ); +our %EXPORT_TAGS = ( ALL => [qw(manage_atoms_and_ranges manage_atoms check_hr_exe manage_atom_and_range manage_tolerance manage_mode config_hr_exe )] ); + +=head1 NAME + +lib::hr - A module for managing / launching hr binary (structure elucidation c++ progr) + +=head1 SYNOPSIS + + use lib::hr; + my $object = lib::hr->new(); + print $object->as_string; + +=head1 DESCRIPTION + +This module does not really exist, it +was made for the sole purpose of +demonstrating how POD works. + +=head1 METHODS + +Methods are : + +=head2 METHOD new + + ## Description : new + ## Input : $self + ## Ouput : bless $self ; + ## Usage : new() ; + +=cut + +sub new { + ## Variables + my $self={}; + bless($self) ; + return $self ; +} +### END of SUB + +=head2 METHOD manage_atoms_and_ranges + + ## Description : allow from an initial config to add or delete atoms and their range + ## Input : $atomsconfig, $atombasic, $atomsupp + ## Output : $atomcleanconfig + ## Usage : my ( $atomcleanconfig ) = manage_atoms_and_ranges ( $atomsconfig, $atombasic, $atomsupp ) ; + +=cut +## START of SUB +sub manage_atoms_and_ranges { + ## Retrieve Values + my $self = shift ; + my ( $atomsconfig, $CONF, $atombasic, $atomsupp ) = @_; + my ( $atomcleanconfig ) = ( undef ) ; + + # basic atoms case: + foreach my $atom ( (split(",", $atombasic )) ) { + if ( exists $CONF->{$atom} ) { $atomsconfig->{$atom}{'max'} = $CONF->{$atom} ; } + } + + # suppl. atoms case + foreach my $atom ( (split(",", $atomsupp )) ) { + print "*** $atom***\n" ; + if ( exists $atomsconfig->{$atom} ) { $atomsconfig->{$atom} = $CONF->{'DEFAULT_MAX'} ; } + } + + # Create atoms and range parameters: + foreach my $selectedAtom ( keys %{$atomsconfig} ) { + $atomcleanconfig .= ' -'.$selectedAtom.' '.$atomsconfig->{$selectedAtom}{'min'}.'-'.$atomsconfig->{$selectedAtom}{'max'} ; + } + + return ($atomcleanconfig) ; +} +### END of SUB + + + +=head2 METHOD manage_atoms ### DEPRECATED + + ## Description : controles atoms input list and prepare it like hr binary parameter + ## Input : $input_atoms, $conf_atoms + ## Output : $hr_atoms_param + ## Usage : my ( $hr_atoms_param ) = manage_atoms( $input_atoms, $conf_atoms ) ; + ### DEPRECATED + +=cut +## START of SUB +sub manage_atoms { ### DEPRECATED + ## Retrieve Values + my $self = shift ; + my ( $input_atoms, $conf_atoms ) = @_ ; + my $hr_atoms_param = undef ; + + if ( ( defined $$input_atoms ) and ( defined $$conf_atoms ) ) { + if ( ( $$input_atoms eq 'None' ) or ( $$input_atoms eq '' ) or ( $$input_atoms eq ' ' ) ) { $hr_atoms_param = $$conf_atoms ; } + elsif ( $$input_atoms =~ /[P|S|F|L|K|B|A|1|,]+/ ) { $hr_atoms_param = $$conf_atoms.','.$$input_atoms ; } + else { $hr_atoms_param = $$conf_atoms ; } + } ## END IF + elsif ( !defined $$input_atoms ) { $hr_atoms_param = $$conf_atoms ; } + elsif ( !defined $$conf_atoms ) { warn "hr module can't manage any atom list (undef values in conf)\n" ; } + else { warn "hr module musn't manage any atom list\n" ; } + + return(\$hr_atoms_param) ; +} +## END of SUB + +=head2 METHOD manage_atom_and_range ### DEPRECATED + + ## Description : build atom range with defined value in conf file + ## Input : $atom, $min, $max + ## Output : $hr_range + ## Usage : my ( ) = manage_atom_and_range( $atom, $min, $max ) ; + ### DEPRECATED + +=cut +## START of SUB +sub manage_atom_and_range { ### DEPRECATED + ## Retrieve Values + my $self = shift ; + my ( $atom, $min, $max ) = @_ ; + my $hr_range = undef ; + + if ( ( defined $$atom ) and ( defined $$min ) and ( defined $$max ) ) { + ## manage ragne like "-C 0-200" + $hr_range = ' -'.$$atom.' '.$$min.'-'.$$max ; + } ## END IF + else { + warn "Some argvts are missing to build the current atom range line\n" ; + } + return(\$hr_range) ; +} +## END of SUB + +=head2 METHOD manage_tolerance + + ## Description : check range and format of tolerance + ## Input : $tolerance, $default_value + ## Output : $set_tol + ## Usage : my ( $set_tol ) = manage_tolerance( $tolerance, $default_value ) ; + +=cut +## START of SUB +sub manage_tolerance { + ## Retrieve Values + my $self = shift ; + my ( $tolerance, $default_value ) = @_ ; + my ($set_tol, $tmp_tol ) = (undef, undef) ; + + if ( ( defined $$tolerance ) and ( defined $$default_value )) { + $tmp_tol = $$tolerance ; + $tmp_tol =~ tr/,/./; + ## tolerance doit etre >0 et <10 + if ( $tmp_tol <= 0 || $tmp_tol >= 10 ){ + $set_tol = $$default_value ; + warn "The used tolerance is set to $$default_value (out of authorized range)\n" ; + } + else{ $set_tol = $tmp_tol ; } + } + else { warn "Your tolerance or the default tol are not defined\n" ; } + + return(\$set_tol) ; +} +## END of SUB + +=head2 METHOD manage_mode + + ## Description : manage mode and apply mass correction (positive/negative/neutral) + ## Input : $mode, $charge, $electron, $proton, $mass + ## Output : $exact_mass + ## Usage : my ( $exact_mass ) = manage_mode( $mode, $charge, $electron, $proton, $mass ) ; + +=cut +## START of SUB +sub manage_mode { + ## Retrieve Values + my $self = shift ; + my ( $mode, $charge, $electron, $proton, $mass ) = @_ ; + my ($exact_mass, $tmp_mass) = ( undef, undef ) ; + + ## some explanations : + # MS in + mode = adds H+ (proton) and molecule is positive : el+ => $charge = "positive" + # For HR, need to subtrack proton mz and to add electron mz (1 electron per charge) to the input mass which comes neutral! + + if ( ( defined $$electron ) and ( defined $$proton ) ) { + # check mass + if ( defined $$mass ) { $tmp_mass = $$mass ; $tmp_mass =~ tr/,/./ ; } # manage . and , in case of... + else { warn "No mass is defined\n" } + + # manage charge + if ( ( !defined $$charge ) || ($$charge < 0) ){ warn "Charge is not defined or value is less than zero\n" ; } + + # set neutral mass in function of ms mode + if($$mode eq 'positive') { $exact_mass = ( $tmp_mass - $$proton + $$electron) * $$charge ; } + elsif($$mode eq 'negative') { $exact_mass = ( $tmp_mass + $$proton - $$electron) * $$charge ; } + elsif($$mode eq "neutral") { $exact_mass = $tmp_mass ; } + else { warn "This mode doesn't exist : please select positive/negative or neutral mode\n" ; } + } + else { + warn "Missing some parameter values (electron, neutron masses), please check your conf file\n" ; + } + return(\$exact_mass) ; +} +## END of SUB + +=head2 METHOD check_hr_exe + + ## Description : permit to check the path of hr.exe and its full availability + ## Input : $hr_path, $hr_version + ## Output : true/false + ## Usage : my ( $res ) = check_hr_exe( $hr_path, $hr_version ) ; + +=cut +## START of SUB +sub check_hr_exe { + ## Retrieve Values + my $self = shift ; + my ( $hr_path, $hr_version ) = @_ ; + my $success = undef ; + my $check_res = undef ; + + ## test path : + if ( ( defined $$hr_path ) and ( defined $$hr_version ) ) { + if ( defined $$hr_path ) { + $success = `$$hr_path -version`; + print "$success\n" ; + if ($success !~/^$$hr_version/) { warn "You do not use the expected version of hr2 ($$hr_version)\n" ; } + else { $check_res = 1 ; } + } + else { warn "Can't use HR because the binary file doesn't exist at the specified path ($$hr_path)\n" ; } + + } ## END IF + else { warn "No HR path or Hr version defined\n" ; } + + return($check_res) ; +} +## END of SUB + +=head2 METHOD config_hr_exe + + ## Description : builds hr execute line with needed params + ## Input : $hr_path, $hr_delta, $mass, $has_goldenrules, $atoms_and_ranks + ## Output : var2 + ## Usage : my ( var2 ) = config_hr_exe( $hr_path, $hr_delta, $mass, $has_goldenrules, $atoms_and_ranks ) ; + +=cut +## START of SUB +sub config_hr_exe { + ## Retrieve Values + my $self = shift ; + my ( $hr_path, $hr_delta, $mass, $has_goldenrules, $atoms_and_ranks ) = @_ ; + my $hr_cmd = undef ; + + if ( ( defined $$hr_path ) and ( defined $$hr_delta ) and ( defined $$mass ) and ( defined $$atoms_and_ranks ) ) { + $hr_cmd = $$hr_path.' -t '.$$hr_delta.' -m '.$$mass.' '.$$atoms_and_ranks ; + if ( defined $$has_goldenrules ) { $$hr_cmd .= ' -g ' ; } + } ## END IF + else { warn "Some argvts are missing to build the current hr exec line\n" ; } + + return(\$hr_cmd) ; +} +## END of SUB + +=head2 METHOD threading_hr_exe + + ## Description : prepare 5 threads for hr executing + ## Input : $method, $list + ## Output : $results + ## Usage : my ( $results ) = threading_hr_exe( $method, $list ) ; + +=cut +## START of SUB +sub threading_hr_exe { + ## Retrieve Values + my $self = shift ; + my ( $method, $list ) = @_ ; + + my @results = () ; + + if ( ( defined $list ) and ( defined $method )) { + + for (my $i = 0; $i < (scalar @{$list}); $i+=6 ) { + my $thr1 = threads->create($method, $self, $list->[$i]) if $list->[$i] ; + my $thr2 = threads->create($method, $self, $list->[$i+1]) if $list->[$i+1] ; + my $thr3 = threads->create($method, $self, $list->[$i+2]) if $list->[$i+2] ; + my $thr4 = threads->create($method, $self, $list->[$i+3]) if $list->[$i+3] ; + my $thr5 = threads->create($method, $self, $list->[$i+4]) if $list->[$i+4] ; + my $thr6 = threads->create($method, $self, $list->[$i+5]) if $list->[$i+5] ; + push ( @results, $thr1->join ) if $list->[$i] ; + push ( @results, $thr2->join ) if $list->[$i+1] ; + push ( @results, $thr3->join ) if $list->[$i+2] ; + push ( @results, $thr4->join ) if $list->[$i+3] ; + push ( @results, $thr5->join ) if $list->[$i+4] ; + push ( @results, $thr6->join ) if $list->[$i+5] ; + } + } + else { + warn "Your input list or your method is undefined\n" ; + } + + return(\@results) ; +} +## END of SUB + +=head2 METHOD hr_exe + + ## Description : hr_exe launches hr and catches result + ## Input : $cmd + ## Output : $res + ## Usage : my ( $res ) = hr_exe( $cmd ) ; + +=cut +## START of SUB +sub hr_exe { + ## Retrieve Values + my $self = shift ; + my ( $cmd ) = @_ ; + my $res = undef ; + + if (defined $cmd){ + #print "\n--CMD used : $cmd\n" ; + $res = `$cmd` ; + sleep(0.5) ; + #print "Results : $res\n" ; + } + + return (\$res) ; +} +## END of SUB + + +=head2 METHOD hr_out_parser + + ## Description : parse output of hr and return a hash of features + ## Input : $res + ## Output : $parsed_res + ## Usage : my ( $parsed_res ) = hr_out_parser( $res ) ; + +=cut +## START of SUB +sub hr_out_parser { + ## Retrieve Values + my $self = shift ; + my ( $res ) = @_ ; + + my %parsed_res = () ; + my ( @formula, @rings_and_double_bond_equivalents, @formula_mz, @mmus ) = ( (), (), (), () ) ; + my ( $formula_nb, $formula_total, $time ) = ( undef, undef, undef ) ; + + if ( defined $$res ) { + # foreach line + foreach my $line (split(/\n/,$$res)){ + ## v1.02 - parse result line "C7.H17.N5. 2.0 171.1484 +17.2 mmu" + ## v1.03 - parse result line "C10.H25.N5.O5.P2.S2. C10H25N5O5P2S2 8.00 421.0772333 0 0 +0.40" + ## $1 = "C10.H25.N5.O5.P2.S2. " $2 = "C10H25N5O5P2S2" $3 = "8.00" $4="421.0772333" $5="0" $6="0" $7="+0.40" + ## if ( $line =~ /([\w|\.]+)\s+(\d+.?\d*)\s+(\d+.?\d*)\s+([+|-]\d+.?\d*)\s+(.*)/ ) { ## for hr2 1.02 + + if ( $line =~ /([\w|\.]+)\s+(\w+)\s+(\d+.?\d*)\s+(\d+.?\d*)\s+(\d+.?\d*)\s+(\d+.?\d*)\s+([+|-]\d+.?\d*)/ ) { # for hr2 1.03 + my ( $formula, $cleanformula, $rings_and_double_bond_equivalent, $formula_mz, $abscharge, $nadd, $mmu_value ) = ( $1, $2, $3, $4, $5, $6, $7 ) ; + + if (defined $formula ) { $formula =~ s/\.//g ; push (@formula, $formula) ; } # clean \. + if (defined $rings_and_double_bond_equivalent ) { push (@rings_and_double_bond_equivalents, $rings_and_double_bond_equivalent) ; } # + if (defined $formula_mz ) { push (@formula_mz, $formula_mz) ; } + if (defined $mmu_value ) { $mmu_value =~ s/\+// ; push (@mmus, $mmu_value) ; } # clean (+) + } + elsif ( $line =~ /(\d+)\s+formulas.+\s+(\d+)\s+seconds.+\s+(\d+)\s+formulae/ ) { + ( $formula_nb, $time, $formula_total ) = ( $1, $2, $3 ) ; + } + else { next; } + } + # build parser + if ( scalar(@formula) > 0 ){ + $parsed_res{'ENTRY_FORMULA'} = \@formula ; + $parsed_res{'rings_and_double_bond_equivalents'} = \@rings_and_double_bond_equivalents ; + $parsed_res{'ENTRY_CPD_MZ'} = \@formula_mz ; + $parsed_res{'ENTRY_DELTA'} = \@mmus ; + $parsed_res{'MASSES_TOTAL'} = \$formula_nb ; + $parsed_res{'time'} = \$time ; + } + } + return(\%parsed_res) ; +} +## END of SUB + + +=head2 METHOD set_html_tbody_object + + ## Description : initializes and build the tbody object (perl array) need to html template + ## Input : $nb_pages, $nb_items_per_page + ## Output : $tbody_object + ## Usage : my ( $tbody_object ) = set_html_tbody_object($nb_pages, $nb_items_per_page) ; + +=cut +## START of SUB +sub set_html_tbody_object { + my $self = shift ; + my ( $nb_pages, $nb_items_per_page ) = @_ ; + + my ( @tbody_object ) = ( ) ; + + for ( my $i = 1 ; $i <= $nb_pages ; $i++ ) { + + my %pages = ( + # tbody feature + PAGE_NB => $i, + MASSES => [], ## end MASSES + ) ; ## end TBODY N + push (@tbody_object, \%pages) ; + } + return(\@tbody_object) ; +} +## END of SUB + +=head2 METHOD add_mz_to_tbody_object + + ## Description : initializes and build the mz object (perl array) need to html template + ## Input : $tbody_object, $nb_items_per_page, $mz_list + ## Output : $tbody_object + ## Usage : my ( $tbody_object ) = add_mz_to_tbody_object( $tbody_object, $nb_items_per_page, $mz_list ) ; + +=cut +## START of SUB +sub add_mz_to_tbody_object { + my $self = shift ; + my ( $tbody_object, $nb_items_per_page, $mz_list, $ids_list, $totals ) = @_ ; + + my ( $current_page, $mz_index ) = ( 0, 0 ) ; + + foreach my $page ( @{$tbody_object} ) { + + my @colors = ('white', 'green') ; + my ( $current_index, , $icolor ) = ( 0, 0 ) ; + + for ( my $i = 1 ; $i <= $nb_items_per_page ; $i++ ) { + # + if ( $current_index > $nb_items_per_page ) { ## manage exact mz per html page + $current_index = 0 ; + last ; ## + } + else { + $current_index++ ; + if ( $icolor > 1 ) { $icolor = 0 ; } + + if ( exists $mz_list->[$mz_index] ) { + my $total = \0 ; + if ( $totals->[$mz_index]{'MASSES_TOTAL'} ) { $total = $totals->[$mz_index]{'MASSES_TOTAL'} } + + my %mz = ( + # mass feature + MASSES_ID_QUERY => $ids_list->[$mz_index], + MASSES_MZ_QUERY => $mz_list->[$mz_index], + MZ_COLOR => $colors[$icolor], + MASSES_NB => $mz_index+1, + MASSES_TOTAL => $$total , + ENTRIES => [] , + ) ; + push ( @{ $tbody_object->[$current_page]{MASSES} }, \%mz ) ; + # Html attr for mass + $icolor++ ; + } + } + $mz_index++ ; + } ## foreach mz + + $current_page++ ; + } + return($tbody_object) ; +} +## END of SUB + +=head2 METHOD add_entries_to_tbody_object + + ## Description : initializes and build the mz object (perl array) need to html template + ## Input : $tbody_object, $nb_items_per_page, $mz_list, $entries + ## Output : $tbody_object + ## Usage : my ( $tbody_object ) = add_entries_to_tbody_object( $tbody_object, $nb_items_per_page, $mz_list, $entries ) ; + +=cut +## START of SUB +sub add_entries_to_tbody_object { + ## Retrieve Values + my $self = shift ; + my ( $tbody_object, $results ) = @_ ; + + my $index_page = 0 ; + my $index_mz_continous = 0 ; + + foreach my $page (@{$tbody_object}) { + + my $index_mz = 0 ; + + foreach my $mz (@{ $tbody_object->[$index_page]{MASSES} }) { + + my $index_res = 0 ; + if ( $results->[$index_mz_continous]{ENTRY_FORMULA} ){ + + my $entry_nb = scalar( @{ $results->[$index_mz_continous]{ENTRY_FORMULA} } ) ; + for( my $i = 0 ; $i<$entry_nb; $i++ ) { + my %entry = ( + ENTRY_COLOR => $tbody_object->[$index_page]{MASSES}[$index_mz]{MZ_COLOR}, + ENTRY_FORMULA => $results->[$index_mz_continous]->{ENTRY_FORMULA}[$i], + ENTRY_CPD_MZ => $results->[$index_mz_continous]->{ENTRY_CPD_MZ}[$i], + ENTRY_DELTA => $results->[$index_mz_continous]->{ENTRY_DELTA}[$i] + ) ; + push ( @{ $tbody_object->[$index_page]{MASSES}[$index_mz]{ENTRIES} }, \%entry) ; + } + $index_res++ ; + } + $index_mz ++ ; + $index_mz_continous ++ ; + } + $index_page++ ; + } + return($tbody_object) ; +} +## END of SUB + +=head2 METHOD write_html_skel + + ## Description : prepare and write the html output file + ## Input : $html_file_name, $html_object, $html_template + ## Output : $html_file_name + ## Usage : my ( $html_file_name ) = write_html_skel( $html_file_name, $html_object ) ; + +=cut +## START of SUB +sub write_html_skel { + ## Retrieve Values + my $self = shift ; + my ( $html_file_name, $html_object, $pages , $search_condition, $html_template, $js_path, $css_path ) = @_ ; + + my $html_file = $$html_file_name ; + + if ( defined $html_file ) { + open ( HTML, ">$html_file" ) or die "Can't create the output file $html_file " ; + + if (-e $html_template) { + my $ohtml = HTML::Template->new(filename => $html_template); + $ohtml->param( JS_GALAXY_PATH => $js_path, CSS_GALAXY_PATH => $css_path ) ; + $ohtml->param( CONDITIONS => $search_condition ) ; + $ohtml->param( PAGES_NB => $pages ) ; + $ohtml->param( PAGES => $html_object ) ; + print HTML $ohtml->output ; + } + else { + croak "Can't fill any html output : No template available ($html_template)\n" ; + } + + close (HTML) ; + } + else { + croak "No output file name available to write HTML file\n" ; + } + return(\$html_file) ; +} +## END of SUB + +=head2 METHOD write_csv_one_mass + + ## Description : print a csv file + ## Input : $masses, $ids, $results, $file + ## Output : N/A + ## Usage : write_csv_one_mass( $ids, $results, $file ) ; + +=cut +## START of SUB +sub write_csv_one_mass { + ## Retrieve Values + my $self = shift ; + my ( $masses, $ids, $results, $file, ) = @_ ; + + open(CSV, '>:utf8', "$file") or die "Cant' create the file $file\n" ; + print CSV "ID\tMASS_SUBMIT\tCPD_FORMULA\tCPD_MW\tDELTA\n" ; + + my $i = 0 ; + + foreach my $id (@{$ids}) { + my $mass = $masses->[$i] ; + + if ( $results->[$i] ) { ## an requested id has a result in the list of hashes $results. + + my $entry_nb = 0 ; + + ## in case of no results -- Hr_parsed Results : $VAR1 = [ { 'ENTRY_FORMULA' => [] } ]; + if ( !$results->[$i]{'ENTRY_FORMULA'} ) { print CSV "$id\t$mass\tN/A\t0.0\t0.0\n" ; } + + foreach (@{$results->[$i]{'ENTRY_FORMULA'}}) { + + print CSV "$id\t$mass\t" ; + ## print cpd formula + if ( $results->[$i]{'ENTRY_FORMULA'}[$entry_nb] ) { print CSV "$results->[$i]{'ENTRY_FORMULA'}[$entry_nb]\t" ; } + else { print CSV "N/A\t" ; } + ## print cpd name + if ( $results->[$i]{'ENTRY_CPD_MZ'}[$entry_nb] ) { print CSV "$results->[$i]{'ENTRY_CPD_MZ'}[$entry_nb]\t" ; } + else { print CSV "0.0\t" ; } + ## print delta + if ( $results->[$i]{'ENTRY_DELTA'}[$entry_nb] ) { print CSV "$results->[$i]{'ENTRY_DELTA'}[$entry_nb]\n" ; } + else { print CSV "0.0\n" ; } + $entry_nb++ ; + } + } + else { + print CSV "$id\t$mass\tN/A\t0.0\t0.0\n" ; + } + $i++ ; + } + close(CSV) ; + return() ; +} +## END of SUB + +=head2 METHOD add_hr_matrix_to_input_matrix + + ## Description : build a full matrix (input + lm column) + ## Input : $input_matrix_object, $lm_matrix_object + ## Output : $output_matrix_object + ## Usage : my ( $output_matrix_object ) = add_hr_matrix_to_input_matrix( $input_matrix_object, $hr_matrix_object ) ; + +=cut +## START of SUB +sub add_hr_matrix_to_input_matrix { + ## Retrieve Values + my $self = shift ; + my ( $input_matrix_object, $hr_matrix_object ) = @_ ; + + my @output_matrix_object = () ; + my $index_row = 0 ; + + foreach my $row ( @{$input_matrix_object} ) { + my @init_row = @{$row} ; + + if ( $hr_matrix_object->[$index_row] ) { + my $dim = scalar(@{$hr_matrix_object->[$index_row]}) ; + + if ($dim > 1) { warn "the add method can't manage more than one column\n" ;} + my $lm_col = $hr_matrix_object->[$index_row][$dim-1] ; + + push (@init_row, $lm_col) ; + $index_row++ ; + } + push (@output_matrix_object, \@init_row) ; + } + return(\@output_matrix_object) ; +} +## END of SUB + +=head2 METHOD write_csv_skel + + ## Description : prepare and write csv output file + ## Input : $csv_file, $rows + ## Output : $csv_file + ## Usage : my ( $csv_file ) = write_csv_skel( $csv_file, $rows ) ; + +=cut +## START of SUB +sub write_csv_skel { + ## Retrieve Values + my $self = shift ; + my ( $csv_file, $rows ) = @_ ; + + my $ocsv = lib::csv::new() ; + my $csv = $ocsv->get_csv_object("\t") ; + $ocsv->write_csv_from_arrays($csv, $$csv_file, $rows) ; + + return($csv_file) ; +} +## END of SUB + +=head2 METHOD set_hr_matrix_object + + ## Description : build the hr_row under its ref form + ## Input : $header, $init_mzs, $entries + ## Output : $hr_matrix + ## Usage : my ( $hmdb_matrix ) = set_hr_matrix_object( $header, $init_mzs, $entries ) ; + +=cut +## START of SUB +sub set_hr_matrix_object { + ## Retrieve Values + my $self = shift ; + my ( $header, $init_mzs, $entries ) = @_ ; + + my @hr_matrix = () ; + + if ( defined $header ) { + my @headers = () ; + push @headers, $header ; + push @hr_matrix, \@headers ; + } + + my $index_mz = 0 ; + + foreach my $mz ( @{$init_mzs} ) { + + my $index_entries = 0 ; + my @clusters = () ; + my $cluster_col = undef ; + + my $nb_entries = $entries->[$index_mz]{MASSES_TOTAL} ; + + foreach (@{$entries->[$index_mz]{'ENTRY_FORMULA'}}) { + + my $delta = $entries->[$index_mz]{'ENTRY_DELTA'}[$index_entries] ; + my $hr_formula = $entries->[$index_mz]{'ENTRY_FORMULA'}[$index_entries] ; + my $hr_mz = $entries->[$index_mz]{'ENTRY_CPD_MZ'}[$index_entries] ; + + + ## METLIN data display model + ## entry1=VAR1::VAR2::VAR3::VAR4|entry2=VAR1::VAR2::VAR3::VAR4|... + # manage final pipe + if ($index_entries < $$nb_entries-1 ) { $cluster_col .= $delta.'::('.$hr_formula.')::'.$hr_mz.'|' ; } + else { $cluster_col .= $delta.'::('.$hr_formula.')::'.$hr_mz ; } + + $index_entries++ ; + } ## end foreach + if ( !defined $cluster_col ) { $cluster_col = 'No_result_found_with HR' ; } + push (@clusters, $cluster_col) ; + push (@hr_matrix, \@clusters) ; + $index_mz++ ; + } + return(\@hr_matrix) ; +} +## END of SUB + + + +1 ; + + +__END__ + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc hr.pm + +=head1 Exports + +=over 4 + +=item :ALL is manage_atoms, check_hr_exe, manage_tolerance + +=back + +=head1 AUTHOR + +Franck Giacomoni E<lt>franck.giacomoni@clermont.inra.frE<gt> + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=head1 VERSION + +version 1 : 02 / 20 / 2014 + +version 2 : ?? + +=cut \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t/hr2_managerTest.t Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,64 @@ +#! perl +use diagnostics; +use warnings; +no warnings qw/void/; +use strict; +no strict "refs" ; +#use Test::More qw( no_plan ); +use Test::More tests => 29 ; +use FindBin ; + +## Specific Modules +use lib $FindBin::Bin ; +my $binPath = $FindBin::Bin ; +use lib::hrTest qw( :ALL ) ; + +## testing manage_atoms +print "\n-- Test manage_atoms lib\n\n" ; +is( manage_atomsTest('', 'C,H,O,N'),'C,H,O,N', 'Works with void argvt' ) ; +is( manage_atomsTest(undef, 'C,H,O,N'), 'C,H,O,N', 'Works with undef argvt in input'); +isnt( manage_atomsTest('C,H,O,N', undef), 'C,H,O,N', 'Doesn\'t work with undef argvt in conf'); +is( manage_atomsTest(' ', 'C,H,O,N'), 'C,H,O,N', 'Works with \'space\' argvt in input' ) ; +is( manage_atomsTest('None', 'C,H,O,N'), 'C,H,O,N', 'Works with \'None\' argvt in input' ) ; +isnt( manage_atomsTest('C,H,O,N', 'C,H,O,N'), 'C,H,O,N', 'Doesn\'t work with same argvt in conf and input' ); +is( manage_atomsTest('P', 'C,H,O,N'), 'C,H,O,N,P', 'Works with P argvt in input'); +is( manage_atomsTest('1', 'C,H,O,N'), 'C,H,O,N,1', 'Works with 13C argvt in input'); +is( manage_atomsTest('P,S', 'C,H,O,N'), 'C,H,O,N,P,S', 'Works with P and S argvt in input'); +is( manage_atomsTest('X', 'C,H,O,N'), 'C,H,O,N', 'Doesn\'t work with other character diff than [P|S|F|L|K|B|A|1|] in input'); +print "\n--\n" ; + +print "\n-- Test check_hr_exe lib\n\n" ; +is ( check_hr_exeTest('J:\\BioInfoTools\\_BINARIES\\HR2-all-res.exe', 'hr version 20050617'), 1, 'Works with WIN path and good version') ; +is ( check_hr_exeTest('J:\\BioInfoTools\\_BINARIES\\HR2-all-res.exe', undef), undef, 'Doesn\'t work with WIN path and bad version') ; +is ( check_hr_exeTest('Z:\\BioInfoTools\\TOTO\\HR2-all-res.exe', 'hr version 20050617'), undef, 'Doesn\'t work with bullshit path and good version') ; +is ( check_hr_exeTest(undef, 'hr version 20050617'), undef, 'Doesn\'t work with undef path and good version') ; +# need to test unix path +print "\n--\n" ; + +print "\n-- Test manage_tolerance lib --\n\n" ; +is ( manage_toleranceTest( '5.0', '1.0' ), '5.0', 'Works with tolerance of 5.0' ) ; +is ( manage_toleranceTest( '5,0', '1.0' ), '5.0', 'Works with tolerance of 5,0 (french number)' ) ; +is ( manage_toleranceTest( undef, '1.0' ), undef, 'Doesn\'t work with undef tolerance' ) ; +is ( manage_toleranceTest( '5.0', undef ), undef, 'Doesn\'t work with undef default tolerance' ) ; +is ( manage_toleranceTest( '20.0', '1.0' ), '1.0', 'Works with hight tolerance (20.0), use default tolerance' ) ; +is ( manage_toleranceTest( '-10.0', '1.0' ), '1.0', 'Works with negative tolerance (-10.0), use default tolerance' ) ; +print "\n--\n" ; + +print "\n-- Test manage_mode lib\n\n" ; +is ( manage_modeTest('positive', '1', '0.0005486', '1.007825', '100.00'), '98.9927236', 'Works and computes right mass (98.9927236) with positive mode and complete conf') ; +is ( manage_modeTest('negative', '1', '0.0005486', '1.007825', '100.00') , '101.0072764', 'Works and computes right mass (101.0072764) with negative mode and complete conf') ; +is ( manage_modeTest('neutral', '1', '0.0005486', '1.007825', '100.00' ), '100.00', 'Works and computes right mass (100.00) with neutral mode and complete conf') ; +is ( manage_modeTest('banane', '1', '0.0005486', '1.007825', '100.00' ), undef, 'Works and warns with unbelievable argt mode') ; +is ( manage_modeTest('positive', '1', '0.0005486', '1.007825', '100,00' ), '98.9927236', 'Works with french mass format in positive mode') ; +is ( manage_modeTest('neutral', '1', undef, undef, '100.00' ), undef, 'Works and warns when missing some conf paramaters (electron, proton, mass)') ; +is ( manage_modeTest('negative', '0', '0.0005486', '1.007825', '100.00') , '101.0072764', 'Works and computes right mass (101.0072764) with negative mode and charge = 0 become 1 ') ; +is ( manage_modeTest('positive', '3', '0.0005486', '1.007825', '100.00'), '298.9938208', 'Works and computes right mass (298.9938208) with positive mode, charge = 3 and complete conf') ; +is ( manage_modeTest('neutral', undef, '0.0005486', '1.007825', '100.00' ), '100.00', 'Works and warns when missing charge') ; +print "\n--\n" ; + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t/lib/hrTest.pm Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,53 @@ +package lib::hrTest ; + +use diagnostics; # this gives you more debugging information +use warnings; # this warns you of bad practices +use strict; # this prevents silly errors +use Exporter ; +use Carp ; + +our $VERSION = "1.0"; +our @ISA = qw(Exporter); +our @EXPORT = qw( manage_atomsTest check_hr_exeTest manage_toleranceTest manage_modeTest ); +our %EXPORT_TAGS = ( ALL => [qw(manage_atomsTest check_hr_exeTest manage_toleranceTest manage_modeTest )] ); + +use lib '/Users/fgiacomoni/Inra/labs/perl/galaxy_tools/hr2' ; +use lib::hr qw( :ALL ) ; + +sub manage_atomsTest { + + my ($input_atoms, $conf_atoms, ) = @_ ; + + my $oAtom = lib::hr->new() ; + my $ref_atoms = $oAtom->manage_atoms(\$input_atoms, \$conf_atoms) ; + my $atoms = $$ref_atoms ; + + return ($atoms) ; +} + +sub check_hr_exeTest { + my ( $hr_path, $hr_version ) = @_ ; + my $oHr = lib::hr->new() ; + my $res = $oHr->check_hr_exe(\$hr_path, \$hr_version) ; + + return ($res) ; +} + +sub manage_toleranceTest { + my ( $tolerance, $default_value ) = @_ ; + my $oHr = lib::hr->new() ; + my $tol = $oHr->manage_tolerance( \$tolerance, \$default_value ) ; + return ($$tol) ; +} + +sub manage_modeTest { + my ( $mode, $charge, $electron, $proton, $mass ) = @_ ; + my $oHr = lib::hr->new() ; + my $exact_mass = $oHr->manage_mode( \$mode, \$charge, \$electron, \$proton, \$mass ) ; + return ($$exact_mass) ; +} + + + + +1 ; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/out1.html Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE html> +<html lang="en"> + <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content=""><meta name="author" content="INRA de Clermont-Ferrand"><title>Galaxy HR2 queries - All results</title><link rel="stylesheet" href="css.php" media="all"><link rel="stylesheet" href="https://cdn.rawgit.com/fgiacomoni/galaxy_utils/master/style/simplePagination.css"/><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script><script src="https://cdn.rawgit.com/fgiacomoni/galaxy_utils/master/scripts/jquery.simplePagination.js"></script><style>body{padding-top:70px} div.lm-table-warning{font-size:1.4em;font-weight:bold;padding-right:25px;color:#21536a;margin-left:3px;}tr.green td{background-color:#eaf2d3;color:black;} tr.blank td{background-color:#9999CC;color:black;} table{font-family:\"Trebuchet MS\", Arial, Helvetica, sans-serif;width:100%;border-collapse:collapse;}table.detail, table.detail tr.parent, table.detail td, table.detail th, table.detail tr.category {border-collapse:collapse;border:1px solid #98bf21;}table.detail th {font-size:1.2em;text-align:center;padding-top:5px;padding-bottom:10px;background-color:#a7c942;color:#ffffff;}td.ca {text-align:center;}footer{margin:50px 0;}</style><script>function test(pageNumber){var page="#page-id-"+pageNumber;$('.select').hide();$(page).show()}</script></head> + <body><div class="container"><div class="lm-table-warning">Results of HR elucidation queries - Mode used: negative / Charge: +1 / Mass tolerance: 1.0 / Composition: -C 0-100 -A 0-0 -1 0-0 -B 0-0 -K 0-0 -N 0-40 -P 0-0 -S 0-0 -O 0-70 -H 0-200 -F 0-0 -L 0-0</div><div id="detail_table_source" style="display:none"></div><p><div id="choose"></div><p><div id="ms_search_0" class="ms-search-table"></div><table id="detail_table" class="detail"><col style="width:20px;"><!-- Ids (m/z)--><col style="width:20px;"><!-- Mass (m/z)--><col style="width:20px;"><!-- Formula--><col style="width:60px;"><!-- cpd mw--><col style="width:50px;"><!-- delta--><col style="width:50px;"><!-- total--><thead><th>ID from input</th><th>Mass (m/z)</th><th>Formula</th><th>Compound MW (Da)</th><th>Delta</th><th>Total</th></thead><tbody class="select" id="page-id-1"><tr class="white"><td class="ca" >mass_01</td><td id="1" class="ca" >175.125</td><td class="ca" colspan="3"></td><td class="ca" >1</td></tr><tr class="white"><td class="ca" colspan="2"></td><td class="ca">C11H16N2</td><td class="ca">176.1313485</td><td class="ca">0.93</td><td class="ca" colspan="1"></td></tr></tbody></table></div><div class="container"><hr><footer><div class="row"><div class="col-lg-12"><p><a href="http://jigsaw.w3.org/css-validator/check/referer" target="_blank"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" /></a></p><p>Copyright © INRA, N Paulhe, F Giacomoni 2014</a></p></div> </div></footer></div><script language="javascript">$(function() {$('#choose').pagination({items: 1,itemsOnPage: 1,currentPage: 1,onInit: function () { test(1); },cssStyle: 'light-theme',onPageClick: function(pageNumber){test(pageNumber)}}).pagination('redraw');});</script></body> +</html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/out1.tabular Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,2 @@ +ID MASS_SUBMIT CPD_FORMULA CPD_MW DELTA +mass_01 175.125 C11H16N2 176.1313485 0.93
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/out2.html Wed Jun 05 09:40:20 2019 -0400 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE html> +<html lang="en"> + <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content=""><meta name="author" content="INRA de Clermont-Ferrand"><title>Galaxy HR2 queries - All results</title><link rel="stylesheet" href="css.php" media="all"><link rel="stylesheet" href="https://cdn.rawgit.com/fgiacomoni/galaxy_utils/master/style/simplePagination.css"/><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script><script src="https://cdn.rawgit.com/fgiacomoni/galaxy_utils/master/scripts/jquery.simplePagination.js"></script><style>body{padding-top:70px} div.lm-table-warning{font-size:1.4em;font-weight:bold;padding-right:25px;color:#21536a;margin-left:3px;}tr.green td{background-color:#eaf2d3;color:black;} tr.blank td{background-color:#9999CC;color:black;} table{font-family:\"Trebuchet MS\", Arial, Helvetica, sans-serif;width:100%;border-collapse:collapse;}table.detail, table.detail tr.parent, table.detail td, table.detail th, table.detail tr.category {border-collapse:collapse;border:1px solid #98bf21;}table.detail th {font-size:1.2em;text-align:center;padding-top:5px;padding-bottom:10px;background-color:#a7c942;color:#ffffff;}td.ca {text-align:center;}footer{margin:50px 0;}</style><script>function test(pageNumber){var page="#page-id-"+pageNumber;$('.select').hide();$(page).show()}</script></head> + <body><div class="container"><div class="lm-table-warning">Results of HR elucidation queries - Mode used: neutral / Charge: +1 / Mass tolerance: 1.0 / Composition: -K 0-0 -B 0-0 -F 0-0 -H 0-200 -L 0-0 -P 0-0 -C 0-100 -A 0-0 -1 0-0 -O 0-70 -S 0-0 -N 0-0</div><div id="detail_table_source" style="display:none"></div><p><div id="choose"></div><p><div id="ms_search_0" class="ms-search-table"></div><table id="detail_table" class="detail"><col style="width:20px;"><!-- Ids (m/z)--><col style="width:20px;"><!-- Mass (m/z)--><col style="width:20px;"><!-- Formula--><col style="width:60px;"><!-- cpd mw--><col style="width:50px;"><!-- delta--><col style="width:50px;"><!-- total--><thead><th>ID from input</th><th>Mass (m/z)</th><th>Formula</th><th>Compound MW (Da)</th><th>Delta</th><th>Total</th></thead><tbody class="select" id="page-id-1"><tr class="white"><td class="ca" >mass_01</td><td id="1" class="ca" >88.052</td><td class="ca" colspan="3"></td><td class="ca" >1</td></tr><tr class="white"><td class="ca" colspan="2"></td><td class="ca">C4H8O2</td><td class="ca">88.0524295</td><td class="ca">-0.43</td><td class="ca" colspan="1"></td></tr></tbody></table></div><div class="container"><hr><footer><div class="row"><div class="col-lg-12"><p><a href="http://jigsaw.w3.org/css-validator/check/referer" target="_blank"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" /></a></p><p>Copyright © INRA, N Paulhe, F Giacomoni 2014</a></p></div> </div></footer></div><script language="javascript">$(function() {$('#choose').pagination({items: 1,itemsOnPage: 1,currentPage: 1,onInit: function () { test(1); },cssStyle: 'light-theme',onPageClick: function(pageNumber){test(pageNumber)}}).pagination('redraw');});</script></body> +</html> \ No newline at end of file