File Coverage

blib/lib/HackaMol/Atom.pm
Criterion Covered Total %
statement 66 66 100.0
branch 12 12 100.0
condition 3 3 100.0
subroutine 22 22 100.0
pod 2 4 50.0
total 105 107 98.1


line stmt bran cond sub pod time code
1             $HackaMol::Atom::VERSION = '0.052';
2             #ABSTRACT: HackaMol Atom Class
3             use 5.008;
4 19     19   1376923 use Moose;
  19         138  
5 19     19   3245 use namespace::autoclean;
  19         2090901  
  19         161  
6 19     19   102241 use Carp;
  19         51700  
  19         147  
7 19     19   1471 use MooseX::StrictConstructor;
  19         37  
  19         1189  
8 19     19   3100  
  19         138908  
  19         121  
9             #use MooseX::Storage;
10             #with Storage('format' => 'JSON', 'io' => 'File');
11              
12             with 'HackaMol::Roles::NameRole',
13             'HackaMol::Roles::PhysVecMVRRole',
14             'HackaMol::Roles::PdbRole',
15             'HackaMol::Roles::QmAtomRole';
16             use HackaMol::PeriodicTable
17             qw(@ELEMENTS %ELEMENTS %ATOMIC_MASSES @COVALENT_RADII @VDW_RADII %ATOM_MULTIPLICITY);
18 19     19   106719  
  19         86  
  19         17854  
19             my @delta_attrs = qw(Z symbol mass vdw_radius covalent_radius);
20              
21             has 'is_dirty' => (
22              
23             # when attributes change, the Atom gets dirty. change_symbol, change_Z
24             # generally, classes that have Atom should decide whether to clean Atom
25             is => 'rw',
26             isa => 'Bool',
27             lazy => 1,
28             default => 0, # anytime called, the atom becomes dirty forever!
29             );
30              
31             has 'bond_count' => (
32             traits => ['Counter'],
33             is => 'ro',
34             isa => 'Num',
35             default => 0,
36             handles => {
37             inc_bond_count => 'inc',
38             dec_bond_count => 'dec',
39             reset_bond_count => 'reset',
40             },
41             );
42              
43             has 'symbol' => (
44             is => 'rw',
45             isa => 'Str',
46             predicate => 'has_symbol',
47             clearer => 'clear_symbol',
48             lazy => 1,
49             builder => '_build_symbol',
50             );
51              
52             my $self = shift;
53             return ( _Z_to_symbol( $self->Z ) );
54 1173     1173   1258 }
55 1173         20776  
56             has 'Z' => (
57             is => 'rw',
58             isa => 'Int',
59             predicate => 'has_Z',
60             clearer => 'clear_Z',
61             lazy => 1,
62             builder => '_build_Z',
63             );
64              
65             my $self = shift;
66             return ( _symbol_to_Z( $self->symbol ) );
67             }
68 3853     3853   4380  
69 3853         70290 has $_ => (
70             is => 'rw',
71             isa => 'Num',
72             predicate => "has_$_",
73             clearer => "clear_$_",
74             lazy => 1,
75             builder => "_build_$_",
76             ) foreach (qw(covalent_radius vdw_radius));
77              
78             my $self = shift;
79             return ( _Z_to_covalent_radius( $self->Z ) );
80             }
81              
82 83     83   115 my $self = shift;
83 83         1495 return ( _Z_to_vdw_radius( $self->Z ) );
84             }
85              
86             my $self = shift;
87 1     1   2 my $Z = shift or croak "pass argument Z to change_Z method";
88 1         22 $self->_clean_atom;
89             $self->Z($Z);
90             }
91              
92 2     2 1 228 my $self = shift;
93 2 100       13 my $symbol = shift or croak "pass argument symbol to change_Z method";
94 1         6 $self->_clean_atom;
95 1         21 $self->symbol( _fix_symbol($symbol) );
96             }
97              
98             my $self = shift;
99 2     2 1 198 carp "charge> takes no arguments. returns get_charges(t)" if (@_);
100 2 100       13 if ( $self->has_charges ) {
101 1         4 return ( $self->get_charges( $self->t ) );
102 1         4 }
103             else {
104             return 0;
105             }
106 12     12 0 346 }
107 12 100       32  
108 12 100       724 my $self = shift;
109 11         226 foreach my $clearthis ( map { "clear_$_" } @delta_attrs ) {
110             $self->$clearthis;
111             }
112 1         5 carp "cleaning atom attributes for in place change. setting atom->is_dirty";
113             $self->is_dirty(1);
114             }
115              
116             my $self = shift;
117 2     2   3  
118 2         5 unless ( $self->has_Z or $self->has_symbol ) {
  10         23  
119 10         262 croak "Either Z or Symbol must be set when calling Atom->new()";
120             }
121 2         30  
122 2         1220 if ( $self->has_Z ) {
123              
124             #clear out the symbol if Z is passed. Z is faster and takes precedence
125             $self->clear_symbol;
126 6794     6794 0 8683 return;
127             }
128 6794 100 100     181097  
129 1         13 $self->symbol( _fix_symbol( $self->symbol ) );
130             return;
131             }
132 6793 100       139409  
133             my $self = shift;
134             return ( _symbol_to_mass( $self->symbol ) );
135 1219         26479 }
136 1219         22069  
137             my $symbol = shift;
138             $symbol = ucfirst( lc($symbol) );
139 5574         104028 return $ELEMENTS{$symbol};
140 5574         106529 }
141              
142             my $Z = shift;
143             return $ELEMENTS[$Z];
144 1459     1459   1637 }
145 1459         27553  
146             my $symbol = shift;
147             return $ATOMIC_MASSES{$symbol};
148             }
149 3853     3853   4775  
150 3853         4886 return ucfirst( lc(shift) );
151 3853         68257 }
152              
153             my $Z = shift;
154              
155 1173     1173   1519 # index 1 for single bond length..
156 1173         21456 return $COVALENT_RADII[$Z][1] / 100;
157             }
158              
159             my $Z = shift;
160 1459     1459   1737 return $VDW_RADII[$Z][1] / 100;
161 1459         29856 }
162              
163             __PACKAGE__->meta->make_immutable;
164              
165 5575     5575   109126 1;
166              
167              
168             =pod
169 83     83   109  
170             =head1 NAME
171              
172 83         1666 HackaMol::Atom - HackaMol Atom Class
173              
174             =head1 VERSION
175              
176 1     1   2 version 0.052
177 1         24  
178             =head1 SYNOPSIS
179              
180             use HackaMol::Atom;
181             use Math::Vector::Real;
182            
183            
184             my $atom1 = HackaMol::Atom->new(
185             name => 'Zinc',
186             coords => [ V( 2.05274, 0.01959, -0.07701 ) ],
187             Z => 30,
188             );
189             print $atom->symbol ; #prints "Zn"
190            
191             print "clean " unless $atom->is_dirty; #prints clean
192            
193             $atom->change_symbol("Hg");
194             print $atom->Z ; #prints 80
195            
196             print "dirty " if $atom->is_dirty; #prints dirty
197              
198             =head1 DESCRIPTION
199              
200             Central to HackaMol, the Atom class provides methods and attributes for a
201             given atom. The Atom class consumes L<HackaMol::PhysVecMVRRole>,
202             L<HackaMol::PdbRole>, and L<HackaMol::QmAtomRole>. See the documentation
203             of those roles for details. The Atom class adds attributes (such as I<symbol>,
204             I<Z>,
205             I<covalent_radius>) and methods (such as I<change_symbol>) specific to atoms.
206             Creating an instance of an Atom object requires either the atomic number (I<Z>)
207             or symbol (I<symbol>). The other attributes are lazily built when needed. The
208             Atom class is flexible. The atom type can be changed in place (e.g. convert
209             a zinc atom to a mercury atom, see SYNOPSIS), but changing the type of atom
210             will set the is_dirty flag so that other objects using the atom have the
211             ability to know whether atom-type dependent attributes need to be updated
212             (e.g. forcefield parameters, etc.). Atom data is generated from the PeriodicTable
213             module that borrows data from PerlMol. The PeriodicTable module is for data and
214             will be dumped into a YAML file in the future.
215              
216             =head1 METHODS
217              
218             =head2 change_Z
219              
220             no arguments. Changes the atom type using I<Z>. I<change_Z> calls
221             I<_clean_atom> which clears all attributes and sets calls I<is_dirty(1)>.
222              
223             =head2 change_symbol
224              
225             no arguments. Changes the atom type using symbol and is analogous to
226             I<change_Z>.
227              
228             =head1 ATTRIBUTES
229              
230             =head2 is_dirty
231              
232             isa Bool that is lazy and rw. Default is 0. $self->is_dirty(1) called
233             during the I<change_symbol> and I<change_Z methods>.
234              
235             =head2 symbol
236              
237             isa Str that is lazy and rw. I<_build_symbol> builds the default.
238              
239             Generating an atom instance with I<symbol>, will run C<ucfirst(lc ($symbol))>
240             to make sure the format is correct. Thus, creating an atom object is
241             slightly slower with symbol than with I<Z>. If I<Z> is used to generate the
242             instance of the Atom class (C<my $atom = Atom->new(Z=>1)>), the C<_build_symbol>
243             method generates the symbol from I<Z> only when the symbol attribute is read
244             (I<symbol> attribute is lazy).
245              
246             =head2 Z
247              
248             isa Int that is lazy and rw. I<_build_Z> builds the default
249              
250             I<Z> is the Atomic number.
251              
252             =head2 covalent_radius
253              
254             isa Num that is lazy and rw. I<_build_covalent_radius> builds the default.
255              
256             the covalent radii are taken from those tabulated in:
257              
258             P. Pyykkoe, M. Atsumi (2009).
259             "Molecular Single-Bond Covalent Radii for Elements 1 to 118". Chemistry: A European Journal 15: 186.
260              
261             Covalent radii for double and triple bonds, generated from the same authors, are
262             also tabulated but currently not used.
263              
264             =head2 vdw_radius
265              
266             isa Num that is lazy and rw. _build_vdw_radius builds the default.
267              
268             Atomic Van der Waals radii information will be revisited and revised. Included as
269             reminder for now. See the source of PeriodicTable.pm for more information.
270              
271             =bond_count
272              
273             isa Num that is lazy with a default of 0. The value adjusted with public Counter traits:
274              
275             inc_bond_count adds 1 by default
276             dec_bond_count subtracts 1 by default
277             reset_bond_count sets to zero
278              
279             =head1 SEE ALSO
280              
281             =over 4
282              
283             =item *
284              
285             L<HackaMol::PhysVecMVRRole>
286              
287             =item *
288              
289             L<HackaMol::PdbRole>
290              
291             =item *
292              
293             L<HackaMol::QmAtomRole>
294              
295             =item *
296              
297             L<Chemistry::Atom>
298              
299             =back
300              
301             =head1 EXTENDS
302              
303             =over 4
304              
305             =item * L<Moose::Object>
306              
307             =back
308              
309             =head1 CONSUMES
310              
311             =over 4
312              
313             =item * L<HackaMol::Roles::NameRole>
314              
315             =item * L<HackaMol::Roles::NameRole|HackaMol::Roles::PhysVecMVRRole|HackaMol::Roles::PdbRole|HackaMol::Roles::QmAtomRole>
316              
317             =item * L<HackaMol::Roles::PdbRole>
318              
319             =item * L<HackaMol::Roles::PhysVecMVRRole>
320              
321             =item * L<HackaMol::Roles::QmAtomRole>
322              
323             =back
324              
325             =head1 AUTHOR
326              
327             Demian Riccardi <demianriccardi@gmail.com>
328              
329             =head1 COPYRIGHT AND LICENSE
330              
331             This software is copyright (c) 2017 by Demian Riccardi.
332              
333             This is free software; you can redistribute it and/or modify it under
334             the same terms as the Perl 5 programming language system itself.
335              
336             =cut