1 | //
|
---|
2 | // molecule.h
|
---|
3 | //
|
---|
4 | // Copyright (C) 1996 Limit Point Systems, Inc.
|
---|
5 | //
|
---|
6 | // Author: Curtis Janssen <cljanss@limitpt.com>
|
---|
7 | // Maintainer: LPS
|
---|
8 | //
|
---|
9 | // This file is part of the SC Toolkit.
|
---|
10 | //
|
---|
11 | // The SC Toolkit is free software; you can redistribute it and/or modify
|
---|
12 | // it under the terms of the GNU Library General Public License as published by
|
---|
13 | // the Free Software Foundation; either version 2, or (at your option)
|
---|
14 | // any later version.
|
---|
15 | //
|
---|
16 | // The SC Toolkit is distributed in the hope that it will be useful,
|
---|
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
19 | // GNU Library General Public License for more details.
|
---|
20 | //
|
---|
21 | // You should have received a copy of the GNU Library General Public License
|
---|
22 | // along with the SC Toolkit; see the file COPYING.LIB. If not, write to
|
---|
23 | // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
24 | //
|
---|
25 | // The U.S. Government is granted a limited license as per AL 91-7.
|
---|
26 | //
|
---|
27 |
|
---|
28 | #ifndef _chemistry_molecule_molecule_h
|
---|
29 | #define _chemistry_molecule_molecule_h
|
---|
30 |
|
---|
31 | #ifdef __GNUC__
|
---|
32 | #pragma interface
|
---|
33 | #endif
|
---|
34 |
|
---|
35 | #include <stdio.h>
|
---|
36 | #include <iostream>
|
---|
37 | #include <util/class/class.h>
|
---|
38 | #include <util/state/state.h>
|
---|
39 | #include <util/keyval/keyval.h>
|
---|
40 | #include <util/misc/units.h>
|
---|
41 | #include <math/symmetry/pointgrp.h>
|
---|
42 | #include <math/scmat/vector3.h>
|
---|
43 | #include <math/scmat/matrix.h>
|
---|
44 | #include <chemistry/molecule/atominfo.h>
|
---|
45 |
|
---|
46 | namespace sc {
|
---|
47 |
|
---|
48 | /**
|
---|
49 | The Molecule class contains information about molecules. It has a
|
---|
50 | KeyVal constructor that can create a new molecule from either a
|
---|
51 | PDB file or from a list of Cartesian coordinates.
|
---|
52 |
|
---|
53 | The following ParsedKeyVal input reads from the PDB
|
---|
54 | file <tt>h2o.pdb</tt>:
|
---|
55 | <pre>
|
---|
56 | molecule<Molecule>: (
|
---|
57 | pdb_file = "h2o.pdb"
|
---|
58 | )
|
---|
59 | </pre>
|
---|
60 |
|
---|
61 | The following input explicitly gives the atom coordinates, using the
|
---|
62 | ParsedKeyVal table notation:
|
---|
63 | <pre>
|
---|
64 | molecule<Molecule>: (
|
---|
65 | unit=angstrom
|
---|
66 | { atom_labels atoms geometry } = {
|
---|
67 | O1 O [ 0.000000000 0 0.369372944 ]
|
---|
68 | H1 H [ 0.783975899 0 -0.184686472 ]
|
---|
69 | H2 H [-0.783975899 0 -0.184686472 ]
|
---|
70 | }
|
---|
71 | )
|
---|
72 | )
|
---|
73 | </pre>
|
---|
74 | The default units are Bohr which can be overridden with
|
---|
75 | <tt>unit=angstrom</tt>. The <tt>atom_labels</tt> array can be
|
---|
76 | omitted. The <tt>atoms</tt> and <tt>geometry</tt> arrays
|
---|
77 | are required.
|
---|
78 |
|
---|
79 | As a special case, an atom can be given with the symbol <tt>Q</tt> or the
|
---|
80 | name <tt>charge</tt>. Such centers are treated as point charges and not
|
---|
81 | given basis functions. The values of the charges must be specified with a
|
---|
82 | <tt>charge</tt> vector in the Molecule input. Since the charge vector
|
---|
83 | assign charges to all centers, including atoms, it is easiest to place all
|
---|
84 | point charge centers first in the geometry, and then give a charge vector
|
---|
85 | with a number of elements equal to the number of point charges. The
|
---|
86 | following example shows a water molecule interacting with a point charge
|
---|
87 | having value 0.1:
|
---|
88 | <pre>
|
---|
89 | molecule<Molecule>: (
|
---|
90 | unit=angstrom
|
---|
91 | charge = [ 0.1 ]
|
---|
92 | { atom_labels atoms geometry } = {
|
---|
93 | Q1 Q [ 0.0 0 10.0 ]
|
---|
94 | O1 O [ 0.000000000 0 0.369372944 ]
|
---|
95 | H1 H [ 0.783975899 0 -0.184686472 ]
|
---|
96 | H2 H [-0.783975899 0 -0.184686472 ]
|
---|
97 | }
|
---|
98 | )
|
---|
99 | )
|
---|
100 | </pre>
|
---|
101 |
|
---|
102 | This feature is designed for doing QM/MM calculations, so, by default,
|
---|
103 | methods will not include interactions between the <tt>Q</tt> centers when
|
---|
104 | computing the energy or the gradient. To include these interactions, set
|
---|
105 | <tt>include_qq=1</tt>.
|
---|
106 |
|
---|
107 | The Molecule class has a PointGroup
|
---|
108 | member object, which also has a KeyVal constructor
|
---|
109 | that is called when a Molecule is made. The
|
---|
110 | following example constructs a molecule with \f$C_{2v}\f$ symmetry:
|
---|
111 | <pre>
|
---|
112 | molecule<Molecule>: (
|
---|
113 | symmetry=c2v
|
---|
114 | unit=angstrom
|
---|
115 | { atoms geometry } = {
|
---|
116 | O [0.000000000 0 0.369372944 ]
|
---|
117 | H [0.783975899 0 -0.184686472 ]
|
---|
118 | }
|
---|
119 | )
|
---|
120 | )
|
---|
121 | </pre>
|
---|
122 | Only the symmetry unique atoms need to be specified. Nonunique
|
---|
123 | atoms can be given too, however, numerical errors in the
|
---|
124 | geometry specification can result in the generation of extra
|
---|
125 | atoms so be careful.
|
---|
126 | */
|
---|
127 | class Molecule: public SavableState
|
---|
128 | {
|
---|
129 | protected:
|
---|
130 | int natoms_;
|
---|
131 | Ref<AtomInfo> atominfo_;
|
---|
132 | Ref<PointGroup> pg_;
|
---|
133 | Ref<Units> geometry_units_;
|
---|
134 | double **r_;
|
---|
135 | int *Z_;
|
---|
136 | double *charges_;
|
---|
137 |
|
---|
138 | // symmetry equiv info
|
---|
139 | int nuniq_;
|
---|
140 | int *nequiv_;
|
---|
141 | int **equiv_;
|
---|
142 | int *atom_to_uniq_;
|
---|
143 | void init_symmetry_info(double tol=0.5);
|
---|
144 | void clear_symmetry_info();
|
---|
145 |
|
---|
146 | // these are optional
|
---|
147 | double *mass_;
|
---|
148 | char **labels_;
|
---|
149 |
|
---|
150 | // The Z that represents a "Q" type atom.
|
---|
151 | int q_Z_;
|
---|
152 |
|
---|
153 | // If true, include the q terms in the charge and efield routines
|
---|
154 | bool include_q_;
|
---|
155 |
|
---|
156 | // If true, include the coupling between q-q pairs when
|
---|
157 | // computing nuclear repulsion energy and gradients.
|
---|
158 | bool include_qq_;
|
---|
159 |
|
---|
160 | // These vectors contain the atom indices of atoms that are not type
|
---|
161 | // "Q" and those that are.
|
---|
162 | std::vector<int> q_atoms_;
|
---|
163 | std::vector<int> non_q_atoms_;
|
---|
164 |
|
---|
165 | void clear();
|
---|
166 |
|
---|
167 | // Throw an exception if an atom is duplicated. The
|
---|
168 | // atoms in the range [begin, natom_) are checked.
|
---|
169 | void throw_if_atom_duplicated(int begin=0, double tol = 1e-3);
|
---|
170 | public:
|
---|
171 | Molecule();
|
---|
172 | Molecule(const Molecule&);
|
---|
173 | Molecule(StateIn&);
|
---|
174 | /** The Molecule KeyVal constructor is used to generate a Molecule
|
---|
175 | object from the input. Several examples are given in the Molecule
|
---|
176 | class overview. The full list of keywords that are accepted is
|
---|
177 | below.
|
---|
178 |
|
---|
179 | <table border="1">
|
---|
180 |
|
---|
181 | <tr><td>Keyword<td>Type<td>Default<td>Description
|
---|
182 |
|
---|
183 | <tr><td><tt>include_q</tt><td>boolean<td>false<td>Some of the
|
---|
184 | atoms can be specified as <tt>Q</tt> and given a customizable
|
---|
185 | charge. Such atoms are a point charge that do not have basis
|
---|
186 | functions. If this option is true, then the <tt>Q</tt> atoms are
|
---|
187 | included when computing the nuclear charge and the electric field
|
---|
188 | due to the nuclear charge.
|
---|
189 |
|
---|
190 | <tr><td><tt>include_qq</tt><td>boolean<td>false<td>Some of the
|
---|
191 | atoms can be specified as <tt>Q</tt> and given a customizable
|
---|
192 | charge. Such atoms are a point charge that do not have basis
|
---|
193 | functions. If this option is true, then the <tt>Q</tt> atoms are
|
---|
194 | included when computing the nuclear repulsion energy and its
|
---|
195 | derivatives.
|
---|
196 |
|
---|
197 | <tr><td><tt>atominfo</tt><td>AtomInfo<td>library values<td>This
|
---|
198 | gives information about each atom, such as the symbol, name, and
|
---|
199 | various atomic radii.
|
---|
200 |
|
---|
201 | <tr><td><tt>symmetry</tt><td>string<td><tt>C1</tt><td>The
|
---|
202 | Schoenflies symbol of the point group. This is case insensitive.
|
---|
203 | It should be a subgroup of D<sub>2h</sub>. If it is <tt>auto</tt>,
|
---|
204 | then the appropriate subgroup of D<sub>2h</sub> will be found.
|
---|
205 |
|
---|
206 | <tr><td><tt>symmetry_tolerance</tt><td>double<td>1.0e-4<td>When
|
---|
207 | a molecule has symmetry, some atoms may be related by symmetry
|
---|
208 | operations. The distance between given atoms and atoms generated
|
---|
209 | by symmetry operations is compared to this threshold to determine
|
---|
210 | if they are the same. If they are the same, then the coordinates
|
---|
211 | are cleaned up to make them exactly symmetry equivalent. If the
|
---|
212 | given molecule was produced by a optimization that started in C1
|
---|
213 | symmetry, but produced a roughly symmetric structure and you would
|
---|
214 | like to begin using symmetry, then this may need to be increased a
|
---|
215 | bit to properly symmetrize the molecule.
|
---|
216 |
|
---|
217 | <tr><td><tt>symmetry_frame</tt><td>double[3][3]<td>[[1 0 0][0 1
|
---|
218 | 0][0 0 1]]<td>The symmetry frame. Ignored for <tt>symmetry =
|
---|
219 | auto</tt>.
|
---|
220 |
|
---|
221 | <tr><td><tt>origin</tt><td>double[3]<td>[0 0 0]<td>The origin of
|
---|
222 | the symmetry frame. Ignored for <tt>symmetry = auto</tt>.
|
---|
223 |
|
---|
224 | <tr><td><tt>redundant_atoms</tt><td>boolean<td>false<td>If true,
|
---|
225 | do not generate symmetry equivalent atoms; they are already given
|
---|
226 | in the input. It should not be necessary to specify this option,
|
---|
227 | since, by default, if a symmetry operation duplicates an atom, the
|
---|
228 | generated atom will not be added to the list of atoms. Ignored for
|
---|
229 | <tt>symmetry = auto</tt>.
|
---|
230 |
|
---|
231 | <tr><td><tt>pdb_file</tt><td>string<td>undefined<td>This gives
|
---|
232 | the name of a PDB file, from which the nuclear coordinates will be
|
---|
233 | read. If this is given, the following options will be ignored.
|
---|
234 |
|
---|
235 | <tr><td><tt>unit</tt><td>string<td>bohr<td>This gives the name
|
---|
236 | of the units used for the geometry. See the Units class for
|
---|
237 | information about the known units. This replaces deprecated
|
---|
238 | keywords that are still recognized: <tt>angstrom</tt> and
|
---|
239 | <tt>angstroms</tt>. This is ignored if <tt>pdb_file</tt> is given.
|
---|
240 |
|
---|
241 | <tr><td><tt>geometry</tt><td>double[][3]<td>none<td>This gives
|
---|
242 | the Cartesian coordinates of the molecule. This is ignored if
|
---|
243 | <tt>pdb_file</tt> is given.
|
---|
244 |
|
---|
245 | <tr><td><tt>atoms</tt><td>string[]<td>none<td>This gives the
|
---|
246 | Cartesian coordinates of the molecule. This is ignored if
|
---|
247 | <tt>pdb_file</tt> is given.
|
---|
248 |
|
---|
249 | <tr><td><tt>ghost</tt><td>boolean[]<td>none<td>If true, the atom
|
---|
250 | will be given zero charge. It will still have basis functions,
|
---|
251 | however. This is used to estimate basis set superposition error.
|
---|
252 | This is ignored if <tt>pdb_file</tt> is given.
|
---|
253 |
|
---|
254 | <tr><td><tt>charge</tt><td>double[]<td>Z for each atom<td>Allows
|
---|
255 | specification of the charge for each atom. This is ignored if
|
---|
256 | <tt>pdb_file</tt> is given.
|
---|
257 |
|
---|
258 | <tr><td><tt>atom_labels</tt><td>string[]<td>none<td>This gives a
|
---|
259 | user defined atom label for each atom. This is ignored if
|
---|
260 | <tt>pdb_file</tt> is given.
|
---|
261 |
|
---|
262 | <tr><td><tt>mass</tt><td>double[]<td>Taken from AtomInfo given by
|
---|
263 | the <tt>atominfo</tt> keyword. <td>This gives a user defined mass
|
---|
264 | for each atom. This is ignored if <tt>pdb_file</tt> is given.
|
---|
265 |
|
---|
266 | </table>
|
---|
267 |
|
---|
268 | */
|
---|
269 | Molecule(const Ref<KeyVal>&input);
|
---|
270 |
|
---|
271 | virtual ~Molecule();
|
---|
272 |
|
---|
273 | Molecule& operator=(const Molecule&);
|
---|
274 |
|
---|
275 | /// Add an AtomicCenter to the Molecule.
|
---|
276 | void add_atom(int Z,double x,double y,double z,
|
---|
277 | const char * = 0, double mass = 0.0,
|
---|
278 | int have_charge = 0, double charge = 0.0);
|
---|
279 |
|
---|
280 | /// Print information about the molecule.
|
---|
281 | virtual void print(std::ostream& =ExEnv::out0()) const;
|
---|
282 | virtual void print_parsedkeyval(std::ostream& =ExEnv::out0(),
|
---|
283 | int print_pg = 1,
|
---|
284 | int print_unit = 1,
|
---|
285 | int number_atoms = 1) const;
|
---|
286 |
|
---|
287 | /// Returns the number of atoms in the molcule.
|
---|
288 | int natom() const { return natoms_; }
|
---|
289 |
|
---|
290 | int Z(int atom) const { return Z_[atom]; }
|
---|
291 | double &r(int atom, int xyz) { return r_[atom][xyz]; }
|
---|
292 | const double &r(int atom, int xyz) const { return r_[atom][xyz]; }
|
---|
293 | double *r(int atom) { return r_[atom]; }
|
---|
294 | const double *r(int atom) const { return r_[atom]; }
|
---|
295 | double mass(int atom) const;
|
---|
296 | /** Returns the label explicitly assigned to atom. If
|
---|
297 | no label has been assigned, then null is returned. */
|
---|
298 | const char *label(int atom) const;
|
---|
299 |
|
---|
300 | /** Takes an (x, y, z) postion and finds an atom within the
|
---|
301 | given tolerance distance. If no atom is found -1 is returned. */
|
---|
302 | int atom_at_position(double *, double tol = 0.05) const;
|
---|
303 |
|
---|
304 | /** Returns the index of the atom with the given label.
|
---|
305 | If the label cannot be found -1 is returned. */
|
---|
306 | int atom_label_to_index(const char *label) const;
|
---|
307 |
|
---|
308 | /** Returns a double* containing the nuclear
|
---|
309 | charges of the atoms. The caller is responsible for
|
---|
310 | freeing the return value. */
|
---|
311 | double *charges() const;
|
---|
312 |
|
---|
313 | /// Return the charge of the atom.
|
---|
314 | double charge(int iatom) const;
|
---|
315 |
|
---|
316 | /// Returns the total nuclear charge.
|
---|
317 | double nuclear_charge() const;
|
---|
318 |
|
---|
319 | /// Sets the PointGroup of the molecule.
|
---|
320 | void set_point_group(const Ref<PointGroup>&, double tol=1.0e-7);
|
---|
321 | /// Returns the PointGroup of the molecule.
|
---|
322 | Ref<PointGroup> point_group() const;
|
---|
323 |
|
---|
324 | /** Find this molecules true point group (limited to abelian groups).
|
---|
325 | If the point group of this molecule is set to the highest point
|
---|
326 | group, then the origin must first be set to the center of mass. */
|
---|
327 | Ref<PointGroup> highest_point_group(double tol = 1.0e-8) const;
|
---|
328 |
|
---|
329 | /** Return 1 if this given axis is a symmetry element for the molecule.
|
---|
330 | The direction vector must be a unit vector. */
|
---|
331 | int is_axis(SCVector3 &origin,
|
---|
332 | SCVector3 &udirection, int order, double tol=1.0e-8) const;
|
---|
333 |
|
---|
334 | /** Return 1 if the given plane is a symmetry element for the molecule.
|
---|
335 | The perpendicular vector must be a unit vector. */
|
---|
336 | int is_plane(SCVector3 &origin, SCVector3 &uperp, double tol=1.0e-8) const;
|
---|
337 |
|
---|
338 | /// Return 1 if the molecule has an inversion center.
|
---|
339 | int has_inversion(SCVector3 &origin, double tol = 1.0e-8) const;
|
---|
340 |
|
---|
341 | /// Returns 1 if the molecule is linear, 0 otherwise.
|
---|
342 | int is_linear(double tolerance = 1.0e-5) const;
|
---|
343 | /// Returns 1 if the molecule is planar, 0 otherwise.
|
---|
344 | int is_planar(double tolerance = 1.0e-5) const;
|
---|
345 | /** Sets linear to 1 if the molecular is linear, 0 otherwise.
|
---|
346 | Sets planar to 1 if the molecular is planar, 0 otherwise. */
|
---|
347 | void is_linear_planar(int&linear,int&planar,double tol = 1.0e-5) const;
|
---|
348 |
|
---|
349 | /** Returns a SCVector3 containing the cartesian coordinates of
|
---|
350 | the center of mass for the molecule. */
|
---|
351 | SCVector3 center_of_mass() const;
|
---|
352 |
|
---|
353 | /// Returns the nuclear repulsion energy for the molecule
|
---|
354 | double nuclear_repulsion_energy();
|
---|
355 |
|
---|
356 | /** Compute the nuclear repulsion energy first derivative with respect
|
---|
357 | to the given center. */
|
---|
358 | void nuclear_repulsion_1der(int center, double xyz[3]);
|
---|
359 |
|
---|
360 | /// Compute the electric field due to the nuclei at the given point.
|
---|
361 | void nuclear_efield(const double *position, double* efield);
|
---|
362 |
|
---|
363 | /** Compute the electric field due to the given charges at the
|
---|
364 | positions of the nuclei at the given point. */
|
---|
365 | void nuclear_charge_efield(const double *charges,
|
---|
366 | const double *position, double* efield);
|
---|
367 |
|
---|
368 | /** If the molecule contains only symmetry unique atoms, this function
|
---|
369 | will generate the other, redundant atoms. The redundant atom
|
---|
370 | will only be generated if there is no other atoms within a distance
|
---|
371 | of tol. If the is another atom and it is not identical, then
|
---|
372 | abort will be called. */
|
---|
373 | void symmetrize(double tol = 0.5);
|
---|
374 |
|
---|
375 | /// Set the point group and then symmetrize.
|
---|
376 | void symmetrize(const Ref<PointGroup> &pg, double tol = 0.5);
|
---|
377 |
|
---|
378 | /** This will try to carefully correct symmetry errors
|
---|
379 | in molecules. If any atom is out of place by more then
|
---|
380 | tol, abort will be called. */
|
---|
381 | void cleanup_molecule(double tol = 0.1);
|
---|
382 |
|
---|
383 | void translate(const double *r);
|
---|
384 | void move_to_com();
|
---|
385 | void transform_to_principal_axes(int trans_frame=1);
|
---|
386 | void transform_to_symmetry_frame();
|
---|
387 | void print_pdb(std::ostream& =ExEnv::out0(), char *title =0) const;
|
---|
388 |
|
---|
389 | void read_pdb(const char *filename);
|
---|
390 |
|
---|
391 | /** Compute the principal moments of inertia and, possibly, the
|
---|
392 | principal axes. */
|
---|
393 | void principal_moments_of_inertia(double *evals, double **evecs=0) const;
|
---|
394 |
|
---|
395 | /// Return information about symmetry unique and equivalent atoms.
|
---|
396 | int nunique() const { return nuniq_; }
|
---|
397 | /// Returns the overall number of the iuniq'th unique atom.
|
---|
398 | int unique(int iuniq) const { return equiv_[iuniq][0]; }
|
---|
399 | /// Returns the number of atoms equivalent to iuniq.
|
---|
400 | int nequivalent(int iuniq) const { return nequiv_[iuniq]; }
|
---|
401 | /// Returns the j'th atom equivalent to iuniq.
|
---|
402 | int equivalent(int iuniq, int j) const { return equiv_[iuniq][j]; }
|
---|
403 | /** Converts an atom number to the number of its generating unique atom.
|
---|
404 | The return value is in [0, nunique). */
|
---|
405 | int atom_to_unique(int iatom) const { return atom_to_uniq_[iatom]; }
|
---|
406 | /** Converts an atom number to the offset of this atom in the list of
|
---|
407 | generated atoms. The unique atom itself is allows offset 0. */
|
---|
408 | int atom_to_unique_offset(int iatom) const;
|
---|
409 |
|
---|
410 | /// Return the number of core electrons.
|
---|
411 | int n_core_electrons();
|
---|
412 |
|
---|
413 | /// Return the maximum atomic number.
|
---|
414 | int max_z();
|
---|
415 |
|
---|
416 | /// Return the molecule's AtomInfo object.
|
---|
417 | Ref<AtomInfo> atominfo() const { return atominfo_; }
|
---|
418 |
|
---|
419 | /// Returns the element name of the atom.
|
---|
420 | std::string atom_name(int iatom) const;
|
---|
421 |
|
---|
422 | /// Returns the element symbol of the atom.
|
---|
423 | std::string atom_symbol(int iatom) const;
|
---|
424 |
|
---|
425 | /** If include_q is true, then include the "Q" atoms in the charge and
|
---|
426 | efield routines. */
|
---|
427 | void set_include_q(bool iq) { include_q_ = iq; }
|
---|
428 | /// Returns include_q. See set_include_q.
|
---|
429 | bool include_q() const { return include_q_; }
|
---|
430 |
|
---|
431 | /** If include_qq is true, include the coupling between pairs of "Q"
|
---|
432 | atoms when computing nuclear repulsion energy and gradients. */
|
---|
433 | void set_include_qq(bool iqq) { include_qq_ = iqq; }
|
---|
434 | /// Returns include_qq. See set_include_qq.
|
---|
435 | bool include_qq() const { return include_qq_; }
|
---|
436 |
|
---|
437 | /// Retrieve the number of "Q" atoms.
|
---|
438 | int n_q_atom() const { return q_atoms_.size(); }
|
---|
439 | /// Retrieve the "Q" atoms.
|
---|
440 | int q_atom(int i) const { return q_atoms_[i]; }
|
---|
441 |
|
---|
442 | /// Retrieve the number of non-"Q" atoms.
|
---|
443 | int n_non_q_atom() const { return non_q_atoms_.size(); }
|
---|
444 | /// Retrieve the of non-"Q" atoms.
|
---|
445 | int non_q_atom(int i) const { return non_q_atoms_[i]; }
|
---|
446 |
|
---|
447 | void save_data_state(StateOut&);
|
---|
448 | };
|
---|
449 |
|
---|
450 | }
|
---|
451 |
|
---|
452 | #endif
|
---|
453 |
|
---|
454 | // Local Variables:
|
---|
455 | // mode: c++
|
---|
456 | // c-file-style: "CLJ"
|
---|
457 | // End:
|
---|