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 )