File Coverage

blib/lib/Chemistry/File/XYZ.pm
Criterion Covered Total %
statement 47 50 94.0
branch 13 18 72.2
condition 2 5 40.0
subroutine 8 9 88.8
pod 4 4 100.0
total 74 86 86.0


line stmt bran cond sub pod time code
1             package Chemistry::File::XYZ;
2              
3             $VERSION = '0.11';
4             # $Id: XYZ.pm,v 1.2 2004/08/03 00:20:04 itubert Exp $
5              
6 1     1   32662 use base qw(Chemistry::File);
  1         2  
  1         1111  
7 1     1   34427 use Chemistry::Mol;
  1         53835  
  1         52  
8 1     1   11 use Carp;
  1         2  
  1         54  
9 1     1   5 use strict;
  1         2  
  1         31  
10 1     1   5 use warnings;
  1         3  
  1         660  
11              
12             =head1 NAME
13              
14             Chemistry::File::XYZ - XYZ molecule format reader/writer
15              
16             =head1 SYNOPSIS
17              
18             use Chemistry::File::XYZ;
19              
20             # read an XYZ file
21             my $mol = Chemistry::Mol->read("myfile.xyz");
22              
23             # write an XYZ file
24             $mol->write("out.xyz");
25              
26             =cut
27              
28             =head1 DESCRIPTION
29              
30             This module reads XYZ files. It automatically registers the 'xyz' format with
31             Chemistry::Mol, so that XYZ files may be identified and read by
32             Chemistry::Mol->read().
33              
34             The XYZ format is not strictly defined and there are various versions floating
35             around; this module accepts the following:
36              
37             First line: atom count (optional)
38              
39             Second line: molecule name or comment (optional)
40              
41             All other lines: (symbol or atomic number), x, y, and z coordinates separated
42             by spaces, tabs, or commas.
43              
44             If the first line doesn't look like a number, the atom count is deduced from
45             the number of lines in the file. If the second line looks like it defines an
46             atom, it is assumed that there was no name or comment.
47              
48             =head1 OUTPUT OPTIONS
49              
50             On writing, the default format is the following, giving H2 as an example.
51              
52             2
53             Hydrogen molecule
54             H 0.0000 0.0000 0.0000
55             H 0.0000 0.7000 0.0000
56              
57             That is: count line, name line, and atom lines (symbol, x, y, z). These format
58             can be modified by means of certain options:
59              
60             =over
61              
62             =item name
63              
64             Control whether or not to include the name.
65              
66             =item count
67              
68             Control whether or not to include the count line.
69              
70             =item symbol
71              
72             If false, use the atomic numbers instead of the atomic symbols.
73              
74             =back
75              
76             For example,
77              
78             $mol->write("out.xyz", count => 0, name => 0, symbol => 0);
79              
80             gives the following output:
81              
82             1 0.0000 0.0000 0.0000
83             1 0.0000 0.7000 0.0000
84              
85             =cut
86              
87             Chemistry::Mol->register_format(xyz => __PACKAGE__);
88              
89             sub parse_string {
90 1     1 1 512 my ($class, $s, %opts) = @_;
91              
92 1   50     6 my $mol_class = $opts{mol_class} || 'Chemistry::Mol';
93 1   33     14 my $atom_class = $opts{atom_class} || $mol_class->atom_class;
94              
95 1         33 my @lines = split /(?:\n|\r\n?)/, $s;
96 1         4 my $n_atoms;
97 1 50       13 if ($lines[0] =~ /^\s*\d+\s*$/) {
98 1         3 $n_atoms = shift @lines;
99             }
100 1         3 my $name = '';
101 1 50       18 unless ($lines[0] =~ /^\s*([A-Z][a-z]?|\d{1,3})([,\s]+[eE\d.+-]+){3}/) {
102 0         0 $name = shift @lines;
103             }
104 1 50       4 $n_atoms = @lines unless $n_atoms;
105              
106 1         8 my $mol = $mol_class->new(name => $name);
107              
108 1         139 my $i = 0;
109 1         4 for my $line (@lines) {
110 10         940 $i++;
111 10 50       34 last if $i > $n_atoms;
112 10         26 $line =~ s/^\s+//;
113 10         57 my ($elem, $x, $y, $z) = split /[\s,]+/, $line;
114              
115 10 100       60 $mol->new_atom(
116             ($elem =~ /^\d+$/ ? "Z" : "symbol") => $elem,
117             coords => [$x, $y, $z],
118             );
119             }
120 1         85 return $mol;
121             }
122              
123             sub name_is {
124 0     0 1 0 my ($class, $fname) = @_;
125 0         0 $fname =~ /\.xyz$/i;
126             }
127              
128             sub file_is {
129 1     1 1 53 my ($class, $fname) = @_;
130 1         9 $fname =~ /\.xyz$/i;
131             }
132              
133             sub write_string {
134 2     2 1 1317 my ($class, $mol, %opts) = @_;
135              
136 2         14 %opts = (count => 1, name => 1, symbol => 1, %opts);
137              
138             # header
139 2         6 my $ret = '';
140 2 100       12 $ret .= $mol->atoms . "\n" if $opts{count};
141 2 100       16 if ($opts{name}) {
142 1 50       5 my $name = defined $mol->name ? $mol->name : '';
143 1         15 $name =~ s/\n.*//s;
144 1         4 $ret .= "$name\n"
145             }
146              
147             # body
148 2         8 for my $atom ($mol->atoms) {
149 20 100       527 $ret .= sprintf "%-2s %8.4f %8.4f %8.4f\n",
150             $opts{symbol} ? $atom->symbol : $atom->Z,
151             $atom->coords->array;
152             }
153 2         46 $ret;
154             }
155              
156             1;
157              
158             =head1 VERSION
159              
160             0.11
161              
162             =head1 SEE ALSO
163              
164             L, L.
165              
166             =head1 AUTHOR
167              
168             Ivan Tubert-Brohman
169              
170             =cut
171