Chemistry-Mol
view release on metacpan or search on metacpan
lib/Chemistry/Mol.pm view on Meta::CPAN
=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;
for my $atom ($mol2->atoms) {
$mol->add_atom($atom);
}
for my $bond ($mol2->bonds) {
$mol->add_bond($bond);
}
}
$mol;
}
=item my @mols = $mol->separate
Separates a molecule into "connected fragments". The original object is not
modified; the fragments are clones of the original ones. Example: if you have
ethane (H3CCH3) and you delete the C-C bond, you have two CH3 radicals within
one molecule object ($mol). When you call $mol->separate you get two molecules,
each one with a CH3.
=cut
# splits a molecule into connected fragments
# returns a list of molecules. Does not touch the original copy.
sub separate {
my ($self) = @_;
$self = $self->clone;
my $unseen = set($self->atoms);
my $open = set;
my %colors;
my $color = 0;
while (!$unseen->is_null) {
my ($first) = $unseen->members;
$unseen->remove($first);
$open->insert($first);
while (!$open->is_null) {
my ($atom) = $open->members;
$colors{$atom->id} = $color;
$open->remove($atom);
my $neighbors = set($atom->neighbors);
my $newly_opened_atoms = $unseen * $neighbors;
$unseen -= $newly_opened_atoms;
$open += $newly_opened_atoms;
}
$color++;
}
$color = 0;
my %map;
for my $atom ($self->atoms) {
next if exists $map{$colors{$atom->id}};
$map{$colors{$atom->id}} = $color;
$color++;
}
$colors{$_} = $map{$colors{$_}} for (keys %colors);
my @mols;
push @mols, $self->new for (0 .. $color-1);
for my $atom ($self->atoms) {
$mols[$colors{$atom->id}]->add_atom($atom);
}
for my $bond ($self->bonds) {
my ($atom) = $bond->atoms;
$mols[$colors{$atom->id}]->add_bond($bond);
}
@mols;
}
=item $mol->sprout_hydrogens
Convert all the implicit hydrogen atoms in the molecule to explicit atoms.
It does B<not> generate coordinates for the atoms.
=cut
sub sprout_hydrogens {
my ($self) = @_;
$_->sprout_hydrogens for $self->atoms;
}
=item $mol->collapse_hydrogens
( run in 2.492 seconds using v1.01-cache-2.11-cpan-364913b4093 )