File Coverage

blib/lib/HackaMol/Angle.pm
Criterion Covered Total %
statement 48 48 100.0
branch 4 4 100.0
condition 6 6 100.0
subroutine 13 13 100.0
pod 5 5 100.0
total 76 76 100.0


line stmt bran cond sub pod time code
1             package HackaMol::Angle;
2             $HackaMol::Angle::VERSION = '0.051';
3             #ABSTRACT: Angle class for HackaMol
4 12     12   1066 use 5.008;
  12         50  
5 12     12   77 use Moose;
  12         32  
  12         110  
6 12     12   87452 use namespace::autoclean;
  12         35  
  12         153  
7 12     12   1305 use Carp;
  12         31  
  12         1043  
8 12     12   103 use Math::Vector::Real;
  12         42  
  12         670  
9 12     12   95 use MooseX::StrictConstructor;
  12         27  
  12         126  
10             #use MooseX::Storage;
11             #with Storage( 'io' => 'StorableFile' ),
12             with 'HackaMol::Roles::NameRole', 'HackaMol::Roles::AtomGroupRole';
13              
14             has $_ => (
15             is => 'rw',
16             isa => 'Num',
17             default => 0,
18             lazy => 1,
19             clearer => "clear_$_",
20             predicate => "has_$_",
21             ) foreach qw(ang_fc ang_eq);
22              
23             sub ang_normvec {
24 34     34 1 4855 my $self = shift;
25 34         1383 my @atoms = $self->all_atoms;
26 34         82 my $ang = $self->ang_deg;
27 34 100 100     504 return V( 0, 0, 0 ) if ( $ang == 0 or $ang == 180 );
28 14         42 my $vec1 = $atoms[1]->inter_dcoords( $atoms[0] );
29 14         51 my $vec2 = $atoms[1]->inter_dcoords( $atoms[2] );
30 14         45 my $v1xv2 = $vec1 x $vec2;
31 14         110 return ( $v1xv2->versor );
32             }
33              
34             sub bisector {
35             # vector that bisects the angle between two vectors of the angle
36 5     5 1 18 my $self = shift;
37 5         181 my @atoms = $self->all_atoms;
38 5         14 my $ang = $self->ang_deg;
39 5 100 100     87 return V( 0, 0, 0 ) if ( $ang == 0 or $ang == 180 );
40 2         11 my $vec1 = $atoms[1]->inter_dcoords( $atoms[0] );
41 2         10 my $vec2 = $atoms[1]->inter_dcoords( $atoms[2] );
42 2         15 my $bvec = ($vec1->versor+$vec2->versor)->versor;
43 2         40 return $bvec;
44             }
45              
46             sub ang_deg {
47 199     199 1 7703 my $self = shift;
48 199         7032 my @atoms = $self->all_atoms;
49 199         650 return ( $atoms[1]->angle_deg( $atoms[0], $atoms[2] ) );
50             }
51              
52             sub ang_rad {
53 10     10 1 4793 my $self = shift;
54 10         410 my @atoms = $self->all_atoms;
55 10         39 return ( $atoms[1]->angle_rad( $atoms[0], $atoms[2] ) );
56             }
57              
58             has 'angle_efunc' => (
59             is => 'rw',
60             isa => 'CodeRef',
61             builder => "_build_angle_efunc",
62             lazy => 1,
63             );
64              
65             sub _build_angle_efunc {
66              
67             #my $self = shift; #self is passed by moose, but we don't use it here
68             my $subref = sub {
69 2     2   6 my $angle = shift;
70 2         5 my $val = ( $angle->ang_deg - $angle->ang_eq )**2;
71 2         49 return ( $angle->ang_fc * $val );
72 1     1   7 };
73 1         32 return ($subref);
74             }
75              
76             sub angle_energy {
77 3     3 1 27 my $self = shift;
78 3         5 my $energy = &{ $self->angle_efunc }( $self, @_ );
  3         82  
79 3         32 return ($energy);
80             }
81              
82             __PACKAGE__->meta->make_immutable;
83              
84             1;
85              
86             __END__
87              
88             =pod
89              
90             =head1 NAME
91              
92             HackaMol::Angle - Angle class for HackaMol
93              
94             =head1 VERSION
95              
96             version 0.051
97              
98             =head1 SYNOPSIS
99              
100             use HackaMol::Atom;
101             use HackaMol::Angle;
102              
103             my $atom1 = HackaMol::Atom->new(
104             name => 'O1',
105             coords => [ V( 2.05274, 0.01959, -0.07701 ) ],
106             Z => 8,
107             );
108              
109             my $atom2 = HackaMol::Atom->new(
110             name => 'H1',
111             coords => [ V( 1.08388, 0.02164, -0.12303 ) ],
112             Z => 1,
113             );
114            
115             my $atom3 = HackaMol::Atom->new(
116             name => 'H2',
117             coords => [ V( 2.33092, 0.06098, -1.00332 ) ],
118             Z => 1,
119             );
120            
121             my $angle1 = HackaMol::Angle->new(name=>'OH2', atoms=>[$atom1,$atom2,$atom3]);
122             my $angle2 = HackaMol::Angle->new(name=>'OH2', atoms=>[$atom2,$atom1,$atom3]);
123            
124             foreach my $angle ($angle1, $angle2){
125             my $pangle = sprintf(
126             "Angle: %s, angle: %.2f, vector normal to angle plane: %.5 %.5 %.5 \n",
127             $angle->name,
128             $angle->ang,
129             @{$angle->ang_normvec},
130             );
131             print $pangle;
132             }
133            
134             my @COM_ats = map {HackaMol::Atom->new(
135             name => "X".$_->name."X",
136             coords => [ $_->COM ],
137             Z => 1)
138             }($angle1, $angle2);
139            
140             my @ang_w_HH = grep { $_->get_atoms(0)->Z == 1 and
141             $_->get_atoms(1)->Z == 1} ($angle1, $angle2);
142              
143             =head1 DESCRIPTION
144              
145             The HackaMol Angle class provides a set of methods and attributes for working
146             with two connections between three atoms. Like the Bond, the Angle class
147             consumes the AtomGroupRole providing methods to determine the center of mass,
148             total charge, etc (see L<HackaMol::AtomGroupRole>). An Angle containing
149             (atom1,atom2,atom3) produce angles between the atom21 atom23 interatomic vectors.
150              
151             The Angle class also provides attributes and methods to set force_constants and
152             measure energy. The angle_energy method calls on a CodeRef attribute that the
153             user may define. See descriptions below.
154              
155             =head1 METHODS
156              
157             =head2 ang_normvec
158              
159             no arguments. returns Math::Vector::Real (MVR) object from the normalized cross
160             product of the atom21 and atom23 interatomic vectors.
161              
162             =head2 bisector
163              
164             no arguments. returns vector (MVR) that bisects the angle between the two
165             vectors of the angle.
166              
167             =head2 ang_deg
168              
169             no arguments. returns the angle (degrees) between the atom21 and atom23 vectors.
170              
171             =head2 ang_rad
172              
173             no arguments. returns the angle (radians) between the atom21 and atom23 vectors.
174              
175             =head2 angle_energy
176              
177             arguments, as many as you want. Calculates energy using the angle_efunc
178             described below, if the attribute, angle_fc > 0. The angle_energy method calls
179             the angle_efunc as follows:
180              
181             my $energy = &{$self->angle_efunc}($self,@_);
182              
183             which will pass $self and that in @_ array to angle_efunc, which, similar
184             to the Bond class, can be redefined.
185              
186             =head1 ATTRIBUTES
187              
188             =head2 name
189              
190             isa Str that is lazy and rw. useful for labeling, bookkeeping...
191              
192             =head2 angle_fc
193              
194             isa Num that is lazy and rw. default = 0. force constant for harmonic potentials.
195              
196             =head2 ang_eq
197              
198             isa Num that is lazy and rw. default = 0. Equilibrium angle. The ang method
199             returns angle in degrees.
200              
201             =head2 angle_efunc
202              
203             isa CodeRef that is lazy and rw. default uses builder to generate harmonic
204             potential from the angle_fc, ang_eq, and ang. See the _build_angle_efunc,
205             if interested in changing the function form.
206              
207             =head1 SEE ALSO
208              
209             =over 4
210              
211             =item *
212              
213             L<HackaMol::AtomGroupRole>
214              
215             =item *
216              
217             L<HackaMol::Bond>
218              
219             =item *
220              
221             L<HackaMol::Dihedral>
222              
223             =back
224              
225             =head1 EXTENDS
226              
227             =over 4
228              
229             =item * L<Moose::Object>
230              
231             =back
232              
233             =head1 CONSUMES
234              
235             =over 4
236              
237             =item * L<HackaMol::Roles::AtomGroupRole>
238              
239             =item * L<HackaMol::Roles::NameRole>
240              
241             =item * L<HackaMol::Roles::NameRole|HackaMol::Roles::AtomGroupRole>
242              
243             =back
244              
245             =head1 AUTHOR
246              
247             Demian Riccardi <demianriccardi@gmail.com>
248              
249             =head1 COPYRIGHT AND LICENSE
250              
251             This software is copyright (c) 2017 by Demian Riccardi.
252              
253             This is free software; you can redistribute it and/or modify it under
254             the same terms as the Perl 5 programming language system itself.
255              
256             =cut