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 )