Chemistry-Ring-0.20/0000755000076400007640000000000011201641531013675 5ustar tuberttubertChemistry-Ring-0.20/META.yml0000644000076400007640000000061011201641531015143 0ustar tuberttubert# http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: Chemistry-Ring version: 0.20 version_from: lib/Chemistry/Ring.pm installdirs: site requires: Chemistry::Mol: 0.24 Statistics::Regression: 0.15 distribution_type: module generated_by: ExtUtils::MakeMaker version 6.30 Chemistry-Ring-0.20/MANIFEST0000644000076400007640000000130610222437720015033 0ustar tuberttubertChanges MANIFEST This list of files MANIFEST.SKIP Makefile.PL README lib/Chemistry/Ring.pm lib/Chemistry/Ring/Find.pm t/mem.t t/find_ring.t t/find_rings.t t/pod.t t/ring.t t/ring_find.t t/rings/benzene_kekule.ring t/rings/byciclic.ring t/rings/byciclic_bond.ring t/rings/byciclic_bond2.ring t/rings/contained.ring t/rings/contained2.ring t/rings/cyclobutadiene.ring t/rings/cycloheptatriene.ring t/rings/cyclopentadiene.ring t/rings/furan.ring t/rings/mirror.ring t/rings/pyridine.ring t/rings/pyrrole.ring t/rings2/biphenyl.ring t/rings2/cubane.ring t/rings2/cubane_sssr.ring t/rings2/disconnected.ring t/rings2/norbornane.ring META.yml Module meta-data (added by MakeMaker) Chemistry-Ring-0.20/lib/0000755000076400007640000000000011201641531014443 5ustar tuberttubertChemistry-Ring-0.20/lib/Chemistry/0000755000076400007640000000000011201641531016412 5ustar tuberttubertChemistry-Ring-0.20/lib/Chemistry/Ring.pm0000644000076400007640000001351311201641514017653 0ustar tuberttubertpackage Chemistry::Ring; $VERSION = '0.20'; #$Id: Ring.pm,v 1.2 2009/05/10 21:12:44 itubert Exp $ =head1 NAME Chemistry::Ring - Represent a ring as a substructure of a molecule =head1 SYNOPSIS use Chemistry::Ring; # already have a molecule in $mol... # create a ring with the first six atoms in $mol my $ring = Chemistry::Ring->new; $ring->add_atom($_) for $mol->atoms(1 .. 6); # find the centroid my $vector = $ring->centroid; # find the plane that fits the ring my ($normal, $distance) = $ring->plane; # is the ring aromatic? print "is aromatic!\n" if $ring->is_aromatic; # "aromatize" a molecule Chemistry::Ring::aromatize_mol($mol); # get the rings involving an atom (after aromatizing) my $rings = $mol->atoms(3)->attr('ring/rings'); =head1 DESCRIPTION This module provides some basic methods for representing a ring. A ring is a subclass of molecule, because it has atoms and bonds. Besides that, it has some useful geometric methods for finding the centroid and the ring plane, and methods for aromaticity detection. This module does not detect the rings by itself; for that, look at L. This module is part of the PerlMol project, L. =cut use strict; use warnings; use Math::VectorReal qw(:axis vector); use Statistics::Regression; use Chemistry::Mol; use base 'Chemistry::Mol', 'Exporter'; use Scalar::Util 'weaken'; our @EXPORT_OK = qw(aromatize_mol); our %EXPORT_TAGS = ( all => \@EXPORT_OK ); our $N = 0; our $DEBUG = 0; =head1 METHODS =over 4 =item Chemistry::Ring->new(name => value, ...) Create a new Ring object with the specified attributes. Same as C<< Chemistry::Mol->new >>. =cut sub nextID { "ring".++$N; } # make sure we don't become parent of the atoms added to us sub add_atom { shift->SUPER::add_atom_np(@_) } sub add_bond { shift->SUPER::add_bond_np(@_) } sub print { my $self = shift; return <{id} atoms: @{$self->{atoms}} bonds: @{$self->{bonds}} EOF } =item $ring->centroid Returs a vector with the centroid, defined as the average of the coordinates of all the atoms in the ring. The vecotr is a L object. =cut sub centroid { my $self = shift; my $c = O; # origin my $n = 0; for my $a ($self->atoms) { $c += $a->coords; ++$n; } $c = $c / $n; } =item my ($norm, $d) = $ring->plane Returns the normal and distance to the origin that define the plane that best fits the atoms in the ring, by using multivariate regression. The normal vector is a L object. =cut sub plane { my $self = shift; my $reg = Statistics::Regression->new(3, "plane for $self", [qw(b mx my)]); for my $atom ($self->atoms) { my ($x, $y, $z) = $atom->coords->array; $reg->include($z, [1.0, $x, $y]); } $reg->print if $DEBUG; # convert the theta vector (z = a + bx + cy) to a normal vector and # distance to the origin my @coef = (@{$reg->theta}, -1.0); # -1 is d in a + bx + cx + dz = 0 my $d = shift @coef; # distance (not normalized) my $sum_sq = 0; # normalization constant $sum_sq += $_*$_ for @coef; $sum_sq ||= 1; ($d, @coef) = map { $_ / $sum_sq } ($d, @coef); # normalize return (vector(@coef)->norm, $d); } =item $ring->is_aromatic Naively guess whether ring is aromatic from the molecular graph, with a method based on Huckel's rule. This method is not very accurate, but works for simple molecules. Returns true or false. =cut sub is_aromatic { my ($self) = @_; my $n_pi = 0; for my $atom ($self->atoms) { no warnings 'uninitialized'; return 0 if ($atom->bonds + $atom->hydrogens > 3); # build bond order histogram my @order_freq = (0,0,0,0); for my $bond ($atom->bonds) { $order_freq[$bond->order]++; } return 0 if ($order_freq[3] or $order_freq[2] > 1); if ($order_freq[2] == 1) { $n_pi += 1; } elsif ($atom->symbol =~ /^[NOS]$/) { $n_pi += 2; } } #print "n_pi = $n_pi\n"; return ($n_pi % 4 == 2) ? 1 : 0; } 1; =back =head1 EXPORTABLE SUBROUTINES Nothing is exported by default, but you can export these subroutines explicitly, or all of them by using the ':all' tag. =over =item aromatize_mol($mol) Finds all the aromatic rings in the molecule and marks all the atoms and bonds in those rings as aromatic. It also adds the 'ring/rings' attribute to the molecule and to all ring atoms and bonds; this attribute is an array reference containing the list of rings that involve that atom or bond (or all the rings in the case of the molecule). NOTE (the ring/rings attribute is experimental and might change in future versions). =cut sub aromatize_mol { my ($mol) = @_; require Chemistry::Ring::Find; $_->aromatic(0) for ($mol->atoms, $mol->bonds); my @rings = Chemistry::Ring::Find::find_rings($mol); $mol->attr("ring/rings", \@rings); $_->attr("ring/rings", []) for ($mol->atoms, $mol->bonds); for my $ring (@rings) { if ($ring->is_aromatic) { $_->aromatic(1) for ($ring->atoms, $ring->bonds); } for ($ring->atoms, $ring->bonds) { my $ringlist = $_->attr("ring/rings") || []; push @$ringlist, $ring; weaken($ringlist->[-1]); $_->attr("ring/rings", $ringlist); } } @rings; } =back =head1 VERSION 0.20 =head1 SEE ALSO L, L, L, L. =head1 AUTHOR Ivan Tubert-Brohman =head1 COPYRIGHT Copyright (c) 2009 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Chemistry-Ring-0.20/lib/Chemistry/Ring/0000755000076400007640000000000011201641531017311 5ustar tuberttubertChemistry-Ring-0.20/lib/Chemistry/Ring/Find.pm0000644000076400007640000002463011201641514020535 0ustar tuberttubertpackage Chemistry::Ring::Find; $VERSION = 0.20; # $Id: Find.pm,v 1.2 2009/05/10 21:12:44 itubert Exp $ =head1 NAME Chemistry::Ring::Find - Find the rings (cycles) in a molecule =head1 SYNOPSIS use Chemistry::Ring::Find ':all'; # find the smallest ring containing $atom my $ring = find_ring($atom); # find all the rings containing $bond my @rings = find_ring($bond, all => 1); # see below for more options # find the six 4-atom rings in cubane @rings = find_rings($cubane); # find a cubane SSSR with five rings @rings = find_rings($cubane, sssr => 1); =head1 DESCRIPTION The Chemistry::Ring::Find module implements a breadth-first ring finding algorithm, and it can find all rings that contain a given atom or bond, the Smallest Set of Smallest Rings (SSSR), or the "almost SSSR", which is an unambiguous set of rings for cases such as cubane.The algorithms are based on ideas from: 1) Leach, A. R.; Dolata, D. P.; Prout, P. Automated Conformational Analysis and Structure Generation: Algorithms for Molecular Perception J. Chem. Inf. Comput. Sci. 1990, 30, 316-324 2) Figueras, J. Ring perception using breadth-first search. J. Chem. Inf. Comput. Sci. 1996, 36, 986-991. Ref. 2 is only used for find_ring, not for find_rings, because it has been shown that the overall SSSR method in ref 2 has bugs. Ref 1 inspired find_rings, which depends on find_ring. This module is part of the PerlMol project, L. =head1 FUNCTIONS These functions may be exported explicitly, or all by using the :all tag, but nothing is exported by default. =over =cut use strict; use warnings; no warnings qw(recursion); use Chemistry::Ring; our @ISA = qw(Exporter); our @EXPORT_OK = qw(find_ring find_rings); our %EXPORT_TAGS = ( all => \@EXPORT_OK ); our $DEBUG = 0; =item find_ring($origin, %opts) Find the smallest ring containg $origin, which may be either an atom or a bond. Returns a Chemistry::Ring object. Options: =over =item all If true, find all the rings containing $origin. If false, return the first ring found. Defaults to false. "All" is supposed to include only "simple" rings, that is, rings that are not a combination of smaller rings. =item min Only find rings with a the given minimum size. Defaults to zero. =item max Only find rings up to the given maximium size. Defaults to unlimited size. =item size Only find rings with this size. Same as setting min and max to the same size. Default: unspecified. =item exclude An array reference containing a list of atoms that must NOT be present in the ring. Defaults to the empty list. =item mirror If true, find each ring twice (forwards and backwards). Defaults to false. =back =cut # $origin is an atom # options: min, max, size, all, mirror, exclude sub find_ring { no warnings qw(uninitialized); my ($origin, %opts) = @_; my $min_size = $opts{min} || $opts{size} || 0; my $max_size = $opts{max} || $opts{size}; my %paths; my %bond_paths; my @q; my @rings; my %used_end_nodes; my $required_bond; my %exclude; @exclude{ @{$opts{exclude} || []} } = (); if ($origin->isa("Chemistry::Bond")) { $required_bond = $origin; ($origin) = $origin->atoms; } @q = ($origin); $paths{$origin} = [$origin]; $bond_paths{$origin} = []; # $path{$atom} means how to get to $atom from $origin my $a; while ($a = shift @q) { my $from = $paths{$a}[-2]; print "at $a from $from\n" if $DEBUG; for my $bn ($a->bonds_neighbors($from)) { my $nei = $bn->{to}; my $bond = $bn->{bond}; next if exists $exclude{$nei}; print " -> $nei\n" if $DEBUG; if ($paths{$nei}) { # a hypothetical check_collision() would have to do this: # %paths, $min_size, $max_size, $used_end_nodes # %bond_paths, $required_bond, @rings # check_size # check_redundant # check_required_bond # check_contains_ring # push print "found a path collision... " if $DEBUG; # check to make sure that the ring really started at $origin # and the size is what was requested my $size = @{$paths{$nei}} + @{$paths{$a}} - 1; #if($paths{$nei}[1] != $paths{$a}[1] if($paths{$nei}[1] ne $paths{$a}[1] and $size >= $min_size and !$max_size || $size <= $max_size) { print "VALID\n" if $DEBUG; my @atoms = (@{$paths{$a}}, reverse @{$paths{$nei}}); print "RING = ", print_path(\@atoms) if $DEBUG; pop @atoms; if ($used_end_nodes{$atoms[1]} and !$opts{mirror}) { print "skipping redundant ring\n" if $DEBUG; next; # don't want to find rings twice } my @bonds = (@{$bond_paths{$a}}, $bond, reverse @{$bond_paths{$nei}}); if ($required_bond and not grep {$_ eq $required_bond} @bonds) { print "does not include required bond (" . join(" ", $required_bond->atoms) . ")\n" if $DEBUG; next; } if (contains_ring(\@atoms, \@rings)) { print "contains another ring\n" if $DEBUG; next; } my $r = Chemistry::Ring->new; $r->add_atom(@atoms); $r->add_bond(@bonds); return $r unless $opts{all}; # FOUND VALID RING push @rings, $r; $used_end_nodes{$atoms[-1]} = 1; #@used_nodes{@atoms} = (); } else { print "NOT VALID", print_path( [@{$paths{$a}}, reverse @{$paths{$nei->id}}]) if $DEBUG; } } else { if (!$max_size || @{$paths{$a}} < ($max_size / 2) + 0.1) { push @q, $nei; print " pushing path\n" if $DEBUG; $paths{$nei} = [@{$paths{$a}}, $nei]; $bond_paths{$nei} = [@{$bond_paths{$a}}, $bond]; print print_path($paths{$nei}) if $DEBUG; } else { print "path too long; " if $DEBUG; print print_path($paths{$a}) if $DEBUG; #path too long } } } } @rings; } sub print_path { my $p = shift; my $ret = " PATH: "; for my $a (@$p) { $ret .= "$a - "; } $ret .= "\n"; } # contains_ring($atoms, $rings) # returns true if one of the rings in the array ref $rings is a proper subset # of the atom list in the array ref $atom. sub contains_ring { my ($atoms, $rings) = @_; my %seen; @seen{@$atoms} = (); for my $ring (@$rings) { my $unique_atoms = $ring->atoms; next if $unique_atoms >= @$atoms; # ring is same size or bigger # make sure that $ring has at least one atom not in $atoms for my $atom ($ring->atoms) { if (exists $seen{$atom}) { $unique_atoms--; } else { last; # there's at least one unique atom! } } return 1 unless $unique_atoms; } 0; } =item @rings = find_rings($mol, %options) Find "all" the rings in the molecule. In general it return the Smallest Set of Smallest Rings (SSSR). However, since it is well known that the SSSR is not unique for molecules such as cubane (where the SSSR consists of five unspecified four-member rings, even if the symmetry of the molecule would suggest that the six faces of the cube are equivalent), in such cases find_rings will return a non-ambiguous "non-smallest" set of smallest rings, unless the "sssr" option is given. For example, @rings = find_rings($cubane); # returns SIX four-member rings @rings = find_rings($cubane, sssr => 1); # returns FIVE four-member rings (an unspecified subset of # the six rings above.) =cut sub find_rings { my ($mol, %opts) = @_; my $visited = {}; my @ring_bonds; for my $atom ($mol->atoms) { next if $visited->{$atom}; push @ring_bonds, find_ring_bonds($mol, \%opts, $atom, $visited); } #print "rb($_; @{$_->{atoms}})\n" for @ring_bonds; my @rings; my $n_rings = @ring_bonds; #print "cyclomatic number=$n_rings\n"; for my $ring_bond (@ring_bonds) { push @rings, find_ring($ring_bond, all => 1) } my %seen; my @ring_keys = map { join " ", sort $_->atoms } @rings; #print "key($_)\n" for @ring_keys; @seen{@ring_keys} = @rings; @rings = sort { $a->atoms <=> $b->atoms } values %seen; if (!$opts{sssr} and @rings > $n_rings) { $n_rings++ if $rings[$n_rings]->atoms == $rings[$n_rings-1]->atoms; } splice @rings, $n_rings if defined $rings[$n_rings]; #splice @rings, $n_rings; @rings; } # find a set of "ring closure bonds" by doing a depth-first search # it will find a number of bonds equal to the cyclomatic number sub find_ring_bonds { my ($mol, $opts, $atom, $visited) = @_; my @ring_bonds; $visited->{$atom} = 1; for my $bn ($atom->bonds_neighbors) { my $nei = $bn->{to}; my $bond = $bn->{bond}; #next if $visited->{$bond}; next if not defined $bond or $visited->{$bond}; $visited->{$bond} = 1; if ($visited->{$nei}) { # closed ring #print "closing ring\n"; push @ring_bonds, $bond; } else { push @ring_bonds, find_ring_bonds($mol, $opts, $nei, $visited); } } @ring_bonds; } 1; =back =head1 BUGS The "all" option in find_ring doesn't quite work as expected. It finds all simple rings and some bridged rings. It never finds fused rings (which is good). =head1 VERSION 0.20 =head1 SEE ALSO L, L. =head1 AUTHOR Ivan Tubert-Brohman Eitub@cpan.orgE =head1 COPYRIGHT Copyright (c) 2009 Ivan Tubert-Brohman. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Chemistry-Ring-0.20/Makefile.PL0000755000076400007640000000041410222437720015656 0ustar tuberttubertuse 5.006; use ExtUtils::MakeMaker; WriteMakefile( 'NAME' => 'Chemistry::Ring', 'VERSION_FROM' => 'lib/Chemistry/Ring.pm', # finds $VERSION 'PREREQ_PM' => {qw( Chemistry::Mol 0.24 Statistics::Regression 0.15 )}, ); Chemistry-Ring-0.20/README0000755000076400007640000000244011201641373014564 0ustar tuberttubertChemistry::Ring version 0.20 ============================ The Chemistry::Ring module provides some basic methods for representing a ring. A ring is a subclass of molecule, because it has atoms and bonds. Besides that, it has some useful geometric methods for finding the centroid and the ring plane, and methods for aromaticity detection. The Chemistry::Ring::Find module implements a breadth-first ring finding algorithm, and it can find all rings that contain a given atom or bond, the Smallest Set of Smallest Rings (SSSR), or the "almost SSSR", which is an unambiguous set of rings for cases such as cubane. This module is part of the PerlMol project, L. CHANGES SINCE VERSION 0.19 - Silence some warnings. - Minor changes by Liliana Felix Avila for compatibility with Chemistry::Artificial. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules and libraries: Chemistry::Mol 0.24 Statistics::Regression 0.15 COPYRIGHT AND LICENSE Copyright (C) 2009 Ivan Tubert-Brohman This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Chemistry-Ring-0.20/t/0000755000076400007640000000000011201641531014140 5ustar tuberttubertChemistry-Ring-0.20/t/ring.t0000755000076400007640000000010010222437720015263 0ustar tuberttubertuse Test::More tests => 1; BEGIN { use_ok('Chemistry::Ring') }; Chemistry-Ring-0.20/t/pod.t0000755000076400007640000000044610222437720015123 0ustar tuberttubertuse Test::More; my @files = (glob("lib/Chemistry/*.pm lib/Chemistry/Ring/*.pm")); my $n = @files; eval 'use Test::Pod'; if ($@) { plan skip_all => "You don't have Test::Pod installed"; } else { plan tests => $n; } for my $file (@files) { pod_file_ok($file, "POD for '$file'"); } Chemistry-Ring-0.20/t/rings/0000755000076400007640000000000011201641531015262 5ustar tuberttubertChemistry-Ring-0.20/t/rings/byciclic.ring0000755000076400007640000000022010222437720017726 0ustar tuberttubertMol: C12CC1C2 Origin: a1 Options: all 1 Ring: atoms(a1 a2 a3); bonds(b1 b2 b3); aromatic(0) Ring: atoms(a1 a4 a3); bonds(b5 b4 b3); aromatic(0) Chemistry-Ring-0.20/t/rings/contained2.ring0000755000076400007640000000015010222437720020175 0ustar tuberttubertMol: C12CC1C2 Origin: a2 Options: min 4 all 1 Ring: atoms(a2 a3 a4 a1); bonds(b2 b4 b5 b1); aromatic(0) Chemistry-Ring-0.20/t/rings/cyclopentadiene.ring0000755000076400007640000000014410222437720021320 0ustar tuberttubertMol: C1=CC=CC1 Origin: a1 Options: Ring: atoms(a1 a2 a3 a4 a5); bonds(b1 b2 b3 b4 b5); aromatic(0) Chemistry-Ring-0.20/t/rings/benzene_kekule.ring0000755000076400007640000000015410222437720021141 0ustar tuberttubertMol: C1=CC=CC=C1 Origin: a1 Options: Ring: atoms(a1 a6 a5 a4 a3 a2); bonds(b6 b5 b4 b3 b2 b1); aromatic(1) Chemistry-Ring-0.20/t/rings/pyrrole.ring0000755000076400007640000000014410222437720017646 0ustar tuberttubertMol: C1=CC=CN1 Origin: a1 Options: Ring: atoms(a1 a2 a3 a4 a5); bonds(b1 b2 b3 b4 b5); aromatic(1) Chemistry-Ring-0.20/t/rings/contained.ring0000755000076400007640000000013410222437720020115 0ustar tuberttubertMol: C12CC1C2 Origin: a2 Options: all 1 Ring: atoms(a2 a1 a3); bonds(b1 b3 b2); aromatic(0) Chemistry-Ring-0.20/t/rings/byciclic_bond.ring0000755000076400007640000000022010222437720020730 0ustar tuberttubertMol: C12CC1C2 Origin: b3 Options: all 1 Ring: atoms(a1 a2 a3); bonds(b1 b2 b3); aromatic(0) Ring: atoms(a1 a4 a3); bonds(b5 b4 b3); aromatic(0) Chemistry-Ring-0.20/t/rings/mirror.ring0000755000076400007640000000022610222437720017465 0ustar tuberttubertMol: C1CC1 Origin: a1 Options: mirror 1 all 1 Ring: atoms(a1 a2 a3); bonds(b1 b2 b3); aromatic(0) Ring: atoms(a1 a3 a2); bonds(b3 b2 b1); aromatic(0) Chemistry-Ring-0.20/t/rings/cyclobutadiene.ring0000755000076400007640000000013510222437720021144 0ustar tuberttubertMol: C1=CC=C1 Origin: a1 Options: Ring: atoms(a1 a4 a3 a2); bonds(b4 b3 b2 b1); aromatic(0) Chemistry-Ring-0.20/t/rings/byciclic_bond2.ring0000755000076400007640000000013410222437720021016 0ustar tuberttubertMol: C12CC1C2 Origin: b1 Options: all 1 Ring: atoms(a1 a2 a3); bonds(b1 b2 b3); aromatic(0) Chemistry-Ring-0.20/t/rings/cycloheptatriene.ring0000755000076400007640000000016310222437720021515 0ustar tuberttubertMol: C1=CC=CC=CC1 Origin: a1 Options: Ring: atoms(a1 a2 a3 a4 a5 a6 a7); bonds(b1 b2 b3 b4 b5 b6 b7); aromatic(0) Chemistry-Ring-0.20/t/rings/furan.ring0000755000076400007640000000014410222437720017265 0ustar tuberttubertMol: C1=CC=CO1 Origin: a1 Options: Ring: atoms(a1 a2 a3 a4 a5); bonds(b1 b2 b3 b4 b5); aromatic(1) Chemistry-Ring-0.20/t/rings/pyridine.ring0000755000076400007640000000015410222437720017776 0ustar tuberttubertMol: C1=CC=CC=N1 Origin: a1 Options: Ring: atoms(a1 a6 a5 a4 a3 a2); bonds(b6 b5 b4 b3 b2 b1); aromatic(1) Chemistry-Ring-0.20/t/rings2/0000755000076400007640000000000011201641531015344 5ustar tuberttubertChemistry-Ring-0.20/t/rings2/norbornane.ring0000755000076400007640000000023510222437720020400 0ustar tuberttubertMol: C12CC(CC1)CC2 Options: Ring: atoms(a1 a2 a3 a4 a5); bonds(b1 b2 b3 b4 b5); aromatic(0) Ring: atoms(a1 a2 a3 a6 a7); bonds(b1 b2 b6 b7 b8); aromatic(0) Chemistry-Ring-0.20/t/rings2/biphenyl.ring0000755000076400007640000000026310222437720020050 0ustar tuberttubertMol: c1ccccc1c1ccccc1 Options: Ring: atoms(a1 a6 a5 a4 a3 a2); bonds(b6 b5 b4 b3 b2 b1); aromatic(1) Ring: atoms(a7 a12 a11 a10 a9 a8); bonds(b13 b12 b11 b10 b9 b8); aromatic(1) Chemistry-Ring-0.20/t/rings2/cubane.ring0000755000076400007640000000060410222437720017472 0ustar tuberttubertMol: C12C3C4C1C5C4C3C25 Options: Ring: atoms(a1 a4 a3 a2); bonds(b4 b3 b2 b1); aromatic(0) Ring: atoms(a1 a8 a7 a2); bonds(b11 b10 b9 b1); aromatic(0) Ring: atoms(a2 a7 a6 a3); bonds(b9 b8 b7 b2); aromatic(0) Ring: atoms(a3 a6 a5 a4); bonds(b7 b6 b5 b3); aromatic(0) Ring: atoms(a5 a8 a1 a4); bonds(b12 b11 b4 b5); aromatic(0) Ring: atoms(a5 a8 a7 a6); bonds(b12 b10 b8 b6); aromatic(0) Chemistry-Ring-0.20/t/rings2/cubane_sssr.ring0000755000076400007640000000051610222437720020546 0ustar tuberttubertMol: C12C3C4C1C5C4C3C25 Options: sssr 1 Ring: atoms(a1 a4 a3 a2); bonds(b4 b3 b2 b1); aromatic(0) Ring: atoms(a2 a7 a6 a3); bonds(b9 b8 b7 b2); aromatic(0) Ring: atoms(a3 a6 a5 a4); bonds(b7 b6 b5 b3); aromatic(0) Ring: atoms(a5 a8 a1 a4); bonds(b12 b11 b4 b5); aromatic(0) Ring: atoms(a5 a8 a7 a6); bonds(b12 b10 b8 b6); aromatic(0) Chemistry-Ring-0.20/t/rings2/disconnected.ring0000755000076400007640000000011310222437720020672 0ustar tuberttubertMol: C.C1CC1 Options: Ring: atoms(a2 a3 a4); bonds(b1 b2 b3); aromatic(0) Chemistry-Ring-0.20/t/ring_find.t0000755000076400007640000000010010222437720016263 0ustar tuberttubertuse Test::More tests => 1; BEGIN { use_ok('Chemistry::Ring') }; Chemistry-Ring-0.20/t/find_ring.t0000755000076400007640000000177210222437720016303 0ustar tuberttubertuse Test::More; use Chemistry::Mol; use Chemistry::Ring::Find ':all'; use strict; my @files = glob "t/rings/*.ring"; eval "use Chemistry::File::SMILES"; if ($@) { plan skip_all => "You don't have Chemistry::File::SMILES installed"; } else { plan tests => 0 + @files; } for my $file (@files) { open F, $file or die "couldn't open $file: $!\n"; my ($smiles, $origin, $options, @expected_rings) = map { /: ([^\n\r]*)/g } ; my ($mol, $patt); Chemistry::Atom->reset_id; Chemistry::Bond->reset_id; $mol = Chemistry::Mol->parse($smiles, format => 'smiles'); my %opts = split " ", $options; my @rings = find_ring($mol->by_id($origin), %opts); my @got_rings; for my $ring (@rings) { my @atoms = $ring->atoms; my @bonds = $ring->bonds; my $aromatic = $ring->is_aromatic; push @got_rings, "atoms(@atoms); bonds(@bonds); aromatic($aromatic)"; } is_deeply(\@got_rings, \@expected_rings, "$file: $smiles"); } Chemistry-Ring-0.20/t/find_rings.t0000755000076400007640000000241610222437720016462 0ustar tuberttubertuse Test::More; use Chemistry::Mol; use Chemistry::Ring::Find ':all'; use strict; my @files = glob "t/rings2/*.ring"; eval "use Chemistry::File::SMILES"; if ($@) { plan skip_all => "You don't have Chemistry::File::SMILES installed"; } else { plan tests => 0 + @files; } for my $file (@files) { open F, $file or die "couldn't open $file: $!\n"; my ($smiles, $options, @expected_rings) = map { /: ([^\n\r]*)/g } ; my ($mol, $patt); Chemistry::Atom->reset_id; Chemistry::Bond->reset_id; $mol = Chemistry::Mol->parse($smiles, format => 'smiles'); my %opts = split " ", $options; my @rings = find_rings($mol, %opts); #use List::Util 'shuffle'; @rings = shuffle @rings; @rings = map { $_->[1] } sort { $a->[0] cmp $b->[0] } map { [ join(" ", $_->atoms) => $_ ] } @rings; my @got_rings; for my $ring (@rings) { my @atoms = $ring->atoms; my @bonds = $ring->bonds; my $aromatic = $ring->is_aromatic; push @got_rings, "atoms(@atoms); bonds(@bonds); aromatic($aromatic)"; } if ($opts{sssr}) { is(scalar @got_rings, scalar @expected_rings, "$file: $smiles"); } else { is_deeply(\@got_rings, \@expected_rings, "$file: $smiles"); } } Chemistry-Ring-0.20/t/mem.t0000755000076400007640000000252610222437720015120 0ustar tuberttubertuse Test::More; # These tests try to make sure that objects are destroyed when they # fall out of scope; these requires avoiding circular strong references use strict; use warnings; use Chemistry::Ring; plan tests => 10; #plan 'no_plan'; my $dead_atoms = 0; my $dead_bonds = 0; my $dead_mols = 0; my $dead_rings = 0; my $badatom; { # make a cyclopropane my $mol = Chemistry::Mol->new; $mol->new_atom(symbol => 'C'); $mol->new_atom(symbol => 'C'); $mol->new_atom(symbol => 'C'); $mol->new_bond(atoms => [$mol->atoms(1,2)]); $mol->new_bond(atoms => [$mol->atoms(2,3)]); $mol->new_bond(atoms => [$mol->atoms(3,1)]); isa_ok( $mol, 'Chemistry::Mol' ); is( scalar $mol->atoms, 3, 'atoms before'); Chemistry::Ring::aromatize_mol($mol); is( $dead_atoms, 0, "before gc - atoms" ); is( $dead_bonds, 0, "before gc - bonds" ); is( $dead_mols, 0, "before gc - mols" ); is( $dead_rings, 0, "before gc - rings" ); } is( $dead_atoms, 3, "after gc - atoms" ); is( $dead_bonds, 3, "after gc - bonds" ); is( $dead_mols, 1, "after gc - mols" ); is( $dead_rings, 1, "after gc - rings" ); sub Chemistry::Mol::DESTROY { $dead_mols++ } sub Chemistry::Atom::DESTROY { $dead_atoms++ } sub Chemistry::Bond::DESTROY { $dead_bonds++ } sub Chemistry::Ring::DESTROY { $dead_rings++ } Chemistry-Ring-0.20/Changes0000755000076400007640000000172011201641346015177 0ustar tuberttubertRevision history for Perl extension Chemistry::Ring 0.20 May 10 2009 - Silence some warnings. - Minor changes by Liliana Felix Avila for compatibility with Chemistry::Artificial. 0.19 Mar 29 2005 - Fixed memory leak. - Added 'ring/rings' attribute to molecule on aromatize_mol. 0.18 Aug 12 2004 - Fixed non-deterministic ring order test failure. 0.17 Aug 11 2004 - Fixed bug where find_rings didn't find all the rings in disconnected structures. 0.16 Aug 2 2004 - Make it warnings-clean. - ring/rings attribute added by aromatize_mol 0.15 Jun 30 2004 - Find the "almost SSSR" in the molecule. - Improved aromatize_mol. 0.11 Jun 17 2004 - New subroutine in Chemistry::Ring: aromatize_mol - Added some tests. - Fixed mirror bug in ring_find. - Fixed is_aromatic to use implicit hydrogens. 0.10 Jun 16 2004 - First CPAN release Chemistry-Ring-0.20/MANIFEST.SKIP0000644000076400007640000000013410222437720015576 0ustar tuberttubert\.mol$ \.gz$ \.pl$ \.BAK$ \.bak$ TODO swp$ ^.$ ^Makefile$ Makefile.old ^blib pm_to_blib CVS