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.053';
2             #ABSTRACT: HackaMol Atom Class
3             use 5.008;
4 19     19   1384493 use Moose;
  19         121  
5 19     19   3218 use namespace::autoclean;
  19         2150441  
  19         144  
6 19     19   99443 use Carp;
  19         51811  
  19         153  
7 19     19   1492 use MooseX::StrictConstructor;
  19         41  
  19         1182  
8 19     19   3199  
  19         138534  
  19         125  
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   105750  
  19         72  
  19         16750  
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   1371 }
55 1173         21053  
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   4529  
69 3853         72007 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   138 my $self = shift;
83 83         1535 return ( _Z_to_vdw_radius( $self->Z ) );
84             }
85              
86             my $self = shift;
87 1     1   3 my $Z = shift or croak "pass argument Z to change_Z method";
88 1         21 $self->_clean_atom;
89             $self->Z($Z);
90             }
91              
92 2     2 1 222 my $self = shift;
93 2 100       14 my $symbol = shift or croak "pass argument symbol to change_Z method";
94 1         7 $self->_clean_atom;
95 1         27 $self->symbol( _fix_symbol($symbol) );
96             }
97              
98             my $self = shift;
99 2     2 1 282 carp "charge> takes no arguments. returns get_charges(t)" if (@_);
100 2 100       39 if ( $self->has_charges ) {
101 1         3 return ( $self->get_charges( $self->t ) );
102 1         4 }
103             else {
104             return 0;
105             }
106 12     12 0 369 }
107 12 100       33  
108 12 100       730 my $self = shift;
109 11         217 foreach my $clearthis ( map { "clear_$_" } @delta_attrs ) {
110             $self->$clearthis;
111             }
112 1         6 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   5  
118 2         7 unless ( $self->has_Z or $self->has_symbol ) {
  10         25  
119 10         269 croak "Either Z or Symbol must be set when calling Atom->new()";
120             }
121 2         34  
122 2         1235 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 10553 return;
127             }
128 6794 100 100     182435  
129 1         16 $self->symbol( _fix_symbol( $self->symbol ) );
130             return;
131             }
132 6793 100       138722  
133             my $self = shift;
134             return ( _symbol_to_mass( $self->symbol ) );
135 1219         26977 }
136 1219         22090  
137             my $symbol = shift;
138             $symbol = ucfirst( lc($symbol) );
139 5574         103290 return $ELEMENTS{$symbol};
140 5574         105028 }
141              
142             my $Z = shift;
143             return $ELEMENTS[$Z];
144 1459     1459   1700 }
145 1459         26587  
146             my $symbol = shift;
147             return $ATOMIC_MASSES{$symbol};
148             }
149 3853     3853   5002  
150 3853         4765 return ucfirst( lc(shift) );
151 3853         70106 }
152              
153             my $Z = shift;
154              
155 1173     1173   1606 # index 1 for single bond length..
156 1173         21771 return $COVALENT_RADII[$Z][1] / 100;
157             }
158              
159             my $Z = shift;
160 1459     1459   1734 return $VDW_RADII[$Z][1] / 100;
161 1459         28908 }
162              
163             __PACKAGE__->meta->make_immutable;
164              
165 5575     5575   108280 1;
166              
167              
168             =pod
169 83     83   113  
170             =head1 NAME
171              
172 83         1690 HackaMol::Atom - HackaMol Atom Class
173              
174             =head1 VERSION
175              
176 1     1   2 version 0.053
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