Chemistry-Mol

 view release on metacpan or  search on metacpan

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

    my ($self) = shift;
    if (@_) {
        $self->{charge} = shift;
        $self;
    } else {
        return $self->{charge} if defined $self->{charge};
        my $charge = 0;
        $charge += $_->formal_charge || 0 for $self->atoms;
        $charge;
    }
}

=item $mol->formula_hash

Returns a hash reference describing the molecular formula. For methane it would
return { C => 1, H => 4 }.

=cut

sub formula_hash {
    my ($self) = @_;
    my $formula = {};
    for my $atom ($self->atoms) {
        $formula->{$atom->symbol}++;
        $formula->{H} += $atom->hydrogens if $atom->hydrogens;
    }
    $formula;
}

=item $mol->formula($format)

Returns a string with the formula. The format can be specified as a printf-like
string with the control sequences specified in the L<Chemistry::File::Formula>
documentation.

=cut

sub formula {
    my ($self, $format) = @_;
    require Chemistry::File::Formula;
    $self->print(format => "formula", formula_format => $format);
}

=item my $mol2 = $mol->clone;

Makes a copy of a molecule. Note that this is a B<deep> copy; if your molecule
has a pointer to the rest of the universe, the entire universe will be cloned!

By default, clone() uses L<Storable> to copy the Perl data structure. L<Clone>
can be used instead by setting variable C<$Chemistry::Mol::clone_backend> to
C<Clone> (default is C<Storable>). The documentation of Storable claims L<Clone>
is less memory-intensive.

=cut

sub clone {
    my ($self) = @_;
    my $clone;
    if ($clone_backend eq "Storable") {
        $clone = dclone $self;
        $clone->_weaken if Storable->VERSION < 2.14;
    } elsif ($clone_backend eq "Clone") {
        require Clone;
        $clone = Clone::clone $self;
    } else {
        croak "Unknown clone backend '$clone_backend'";
    }
    $clone;
}

=item my $mol2 = $mol->safe_clone;

Like clone, it makes a deep copy of a molecule. The difference is that the copy
is not "exact" in that new molecule and its atoms and bonds get assigned new
IDs. This makes it safe to combine cloned molecules. For example, this is an
error:

    # XXX don't try this at home!
    my $mol2 = Chemistry::Mol->combine($mol1, $mol1);
    # the atoms in $mol1 will clash

But this is ok:

    # the "safe clone" of $mol1 will have new IDs
    my $mol2 = Chemistry::Mol->combine($mol1, $mol1->safe_clone);

=cut

sub safe_clone {
    my ($mol) = @_;
    my $clone = $mol->clone;
    for ($clone, $clone->atoms, $clone->bonds) {
        $_->id($_->nextID);
    }
    $clone;
} 

sub _weaken {
    my ($self) = @_;
    for ($self->atoms, $self->bonds) {
        $_->_weaken;
    }
    $self;
}

=item ($distance, $atom_here, $atom_there) = $mol->distance($obj)

Returns the minimum distance to $obj, which can be an atom, a molecule, or a
vector. In scalar context it returns only the distance; in list context it
also returns the atoms involved. The current implementation for calculating
the minimum distance between two molecules compares every possible pair of
atoms, so it's not efficient for large molecules.

=cut

sub distance {
    my ($self, $other) = @_;
    if ($other->isa("Chemistry::Mol")) {
        my @atoms = $self->atoms;
        my $atom = shift @atoms or return; # need at least one atom
        my $closest_here = $atom;
        my ($min_length, $closest_there) = $atom->distance($other);
        for $atom (@atoms) {
            my ($d, $o) = $atom->distance($other);
            if ($d < $min_length) {
                ($min_length, $closest_there, $closest_here) = ($d, $o, $atom);
            }
        }
        return wantarray ? 
            ($min_length, $closest_here, $closest_there) : $min_length;
    } elsif ($other->isa("Chemistry::Atom")) {
        return $other->distance($self);
    } elsif ($other->isa("Math::VectorReal")) {
        return Chemistry::Atom->new(coords => $other)->distance($self);
    }
}

=item my $bigmol = Chemistry::Mol->combine($mol1, $mol2, ...)

=item $mol1->combine($mol2, $mol3, ...)

Combines several molecules in one bigger molecule. If called as a class method,
as in the first example, it returns a new combined molecule without altering
any of the parameters. If called as an instance method, as in the second
example, all molecules are combined into $mol1 (but $mol2, $mol3, ...) are not
altered. B<Note>: Make sure you don't combine molecules which contain atoms
with duplicate IDs (for example, if they were cloned).

=cut

# joins several molecules into one
sub combine {
    my ($self, @others) = @_;
    my $mol;
    if (ref $self) {
        $mol = $self;
    } else {
        $mol = $self->new;
    }
    for my $other (@others) {
        my $mol2 = $other->clone;



( run in 1.829 second using v1.01-cache-2.11-cpan-e1769b4cff6 )