Chemistry-Mol

 view release on metacpan or  search on metacpan

lib/Chemistry/Atom.pm  view on Meta::CPAN

package Chemistry::Atom;

our $VERSION = '0.40'; # VERSION
# $Id$

=head1 NAME

Chemistry::Atom - Chemical atoms as objects in molecules

=head1 SYNOPSIS

    use Chemistry::Atom;

    my $atom = new Chemistry::Atom(
        id => 'a1',
        coords => [$x, $y, $z],
        symbol => 'Br'
    );

    print $atom->print;

=head1 DESCRIPTION

This module includes objects to describe chemical atoms. 
An atom is defined by its symbol and its coordinates, among other attributes.
Atomic coordinates are described by a Math::VectorReal
object, so that they can be easily used in vector operations.

=head2 Atom Attributes

In addition to common attributes such as id, name, and type, 
atoms have the following attributes, which are accessed or
modified through methods defined below: bonds, coords, internal_coords,
Z, symbol, etc.

In general, to get the value of a property, use $atom->method without
any parameters. To set the value, use $atom->method($new_value). When setting
an attribute, the accessor returns the atom object, so that accessors can be
chained:

    $atom->symbol("C")->name("CA")->coords(1,2,3);

=cut

# Considering to add the following attributes:
# mass_number (A)

use 5.006;
use strict;
use warnings;
use Scalar::Util 'weaken';
use Math::VectorReal qw(O vector);
use Math::Trig;
use Carp;
use base qw(Chemistry::Obj Exporter);
use List::Util qw(first);

our @EXPORT_OK = qw(distance angle dihedral angle_deg dihedral_deg);
our %EXPORT_TAGS = (
      all  => \@EXPORT_OK,
);



my $N = 0; # Number of atoms created so far, used to generate default IDs.

our @ELEMENTS = qw(
    n
    H                                                                   He
    Li  Be                                          B   C   N   O   F   Ne
    Na  Mg                                          Al  Si  P   S   Cl  Ar
    K   Ca  Sc  Ti  V   Cr  Mn  Fe  Co  Ni  Cu  Zn  Ga  Ge  As  Se  Br  Kr
    Rb  Sr  Y   Zr  Nb  Mo  Tc  Ru  Rh  Pd  Ag  Cd  In  Sn  Sb  Te  I   Xe
    Cs  Ba
        La  Ce  Pr  Nd  Pm  Sm  Eu  Gd  Tb  Dy  Ho  Er  Tm  Yb
            Lu  Hf  Ta  W   Re  Os  Ir  Pt  Au  Hg  Tl  Pb  Bi  Po  At  Rn
    Fr  Ra
        Ac  Th  Pa  U   Np  Pu  Am  Cm  Bk  Cf  Es  Fm  Md  No
            Lr  Rf  Db  Sg  Bh  Hs  Mt  Ds  Uuu Uub Uut Uuq Uup Uuh Uus Uuo
);

our %ELEMENTS;
for (my $i = 1; $i < @ELEMENTS; ++$i){
    $ELEMENTS{$ELEMENTS[$i]} = $i;
}
$ELEMENTS{D} = $ELEMENTS{T} = 1;

my %Atomic_masses = (
   "H" => 1.00794, "D" => 2.014101, "T" => 3.016049, "He" => 4.002602,
   "Li" => 6.941, "Be" => 9.012182, "B" => 10.811, "C" => 12.0107,
   "N" => 14.00674, "O" => 15.9994, "F" => 18.9984032, "Ne" => 20.1797,
   "Na" => 22.989770, "Mg" => 24.3050, "Al" => 26.981538, "Si" => 28.0855,
   "P" => 30.973761, "S" => 32.066, "Cl" => 35.4527, "Ar" => 39.948,
   "K" => 39.0983, "Ca" => 40.078, "Sc" => 44.955910, "Ti" => 47.867,
   "V" => 50.9415, "Cr" => 51.9961, "Mn" => 54.938049, "Fe" => 55.845,
   "Co" => 58.933200, "Ni" => 58.6934, "Cu" => 63.546, "Zn" => 65.39,
   "Ga" => 69.723, "Ge" => 72.61, "As" => 74.92160, "Se" => 78.96,
   "Br" => 79.904, "Kr" => 83.80, "Rb" => 85.4678, "Sr" => 87.62,
   "Y" => 88.90585, "Zr" => 91.224, "Nb" => 92.90638, "Mo" => 95.94,
   "Tc" => 98, "Ru" => 101.07, "Rh" => 102.90550, "Pd" => 106.42,
   "Ag" => 107.8682, "Cd" => 112.411, "In" => 114.818, "Sn" => 118.710,
   "Sb" => 121.760, "Te" => 127.60, "I" => 126.90447, "Xe" => 131.29,
   "Cs" => 132.90545, "Ba" => 137.327, "La" => 138.9055, "Ce" => 140.116,
   "Pr" => 140.90765, "Nd" => 144.24, "Pm" => 145, "Sm" => 150.36,
   "Eu" => 151.964, "Gd" => 157.25, "Tb" => 158.92534, "Dy" => 162.50,
   "Ho" => 164.93032, "Er" => 167.26, "Tm" => 168.93421, "Yb" => 173.04,
   "Lu" => 174.967, "Hf" => 178.49, "Ta" => 180.9479, "W" => 183.84,
   "Re" => 186.207, "Os" => 190.23, "Ir" => 192.217, "Pt" => 195.078,
   "Au" => 196.96655, "Hg" => 200.59, "Tl" => 204.3833, "Pb" => 207.2,
   "Bi" => 208.98038, "Po" => 209, "At" => 210, "Rn" => 222,
   "Fr" => 223, "Ra" => 226, "Ac" => 227, "Th" => 232.038,

lib/Chemistry/Atom.pm  view on Meta::CPAN


It returns the atom object.

=cut

sub add_implicit_hydrogens {
    my ($self) = @_;
    my $h_count = $self->calc_implicit_hydrogens;
    $self->implicit_hydrogens($h_count);
}

=item $atom->aromatic($bool)

Set or get whether the atom is considered to be aromatic. This property may be
set arbitrarily, it doesn't imply any kind of "intelligent aromaticity
detection"! (For that, look at the L<Chemistry::Ring> module).

=cut

Chemistry::Obj::accessor('aromatic');

=item $atom->valence

Returns the sum of the bond orders of the bonds in which the atom participates,
including implicit hydrogens (which are assumed to have bond orders of one).

=cut

sub valence {
    my ($self) = @_;
    my $valence = 0;
    $valence += $_->order for $self->bonds;
    $valence += $self->hydrogens || 0;
    $valence;
}

=item $atom->explicit_valence

Like C<valence>, but excluding implicit hydrogen atoms. To get the raw number
of bonds, without counting bond orders, call $atom->bonds in scalar context.

=cut

sub explicit_valence {
    my ($self) = @_;
    my $valence = 0;
    $valence += $_->order for $self->bonds;
    $valence;
}

# this method is for internal use only; called by $mol->add_bond
sub add_bond {
    my $self = shift;
    my $bond = shift;
    my %seen;
    #return if first { $_ eq $bond } @{$self->{bonds}}; 

    for my $atom (@{$bond->{atoms}}){ #for each atom...
        if ($atom ne $self) {
            my $b = {to=>$atom, bond=>$bond};
            weaken($b->{to});
            weaken($b->{bond});
            push @{$self->{bonds}}, $b;
        }
    }
}

# make sure the atom doesn't cause circular references
sub _weaken {
    my $self = shift;
    for my $b (@{$self->{bonds}}) {
        weaken($b->{to});
        weaken($b->{bond});
    }
    weaken($self->{parent});
}

# This method is private. Bonds should be deleted from the 
# mol object. These methods should only be called by 
# $bond->delete_atoms, which is called by $mol->delete_bond
sub delete_bond {
    my ($self, $bond) = @_;
    $self->{bonds} = [ grep { $_->{bond} ne $bond } @{$self->{bonds}} ];
}

=item $atom->delete

Calls $mol->delete_atom($atom) on the atom's parent molecule.

=cut

sub delete {
    my ($self) = @_;
    $self->{parent}->_delete_atom($self);
}

=item $atom->parent

Returns the atom's containing object (the molecule to which the atom belongs).
An atom can only have one parent.

=cut

sub parent {
    my $self = shift;
    if (@_) {
        ($self->{parent}) = @_;
        weaken($self->{parent});
        $self;
    } else {
        $self->{parent};
    }
}

=item $atom->neighbors($from)

Return a list of neighbors. If an atom object $from is specified, it will be
excluded from the list (this is useful if an atom wants to know who its 
neighbor's neighbors are, without counting itself).

=cut

sub neighbors {
    my $self = shift;
    my $from = shift;
    my @ret = ();

    for my $b (@{$self->{bonds}}) {
        push @ret, $b->{to} unless $from && $b->{to} eq $from;
    }
    @ret;
}

=item $atom->bonds($from)

Return a list of bonds. If an atom object $from is specified, bonds to
that atom will be excluded from the list.

=cut

sub bonds {
    my $self = shift;
    my $from = shift;
    my @ret = ();

    for my $b (@{$self->{bonds}}) {
        push @ret, $b->{bond} unless $from && $b->{to} eq $from;
    }
    @ret;
}

=item $atom->bonds_neighbors($from)

Return a list of hash references, representing the bonds and neighbors from the
atom. If an atom object $from is specified, it will be excluded from the list.
The elements of the hash are 'to', and atom reference, and 'bond', a bond
reference. For example, 

    for my $bn ($atom->bonds_neighbors) {
        print "bond $bn->{bond} point to atom $bn->{to}\n";
    }

=cut

sub bonds_neighbors {
    my $self = shift;
    my $from = shift;
    my @ret = ();



( run in 1.697 second using v1.01-cache-2.11-cpan-524268b4103 )