$! This is a DCL shar-type archive created by Unix dclshar. $! $CREATE Aaaa_Read.Me $DECK # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Copyright Keith Refson January 1990 All rights reserved Moldy is a general-purpose molecular dynamics simulation program which I wrote initially for my own research into aqueous solutions at mineral surfaces. However it is sufficiently flexible that it ought to be useful for a wide range of simulation calculations of atomic, ionic and molecular systems. Moldy is available by anonymous file transfer from Oxford. Connect to "earth.ox.ac.uk" using "ftp", with an account name of "anonymous" and your email address as password. The relevant files are all in the "/pub" directory and are * moldy-2.8.tar.Z - The Unix distribution (also for MSDOS) * moldy-2.8.com - The VMS distribution * moldy-manual.ps.Z - The Manual in PostScript form. Note that the distribution files already contain the LaTeX source. Please note that moldy is copyrighted and distributed under the GNU public license which is designed to encourage its distribution and modification. This is to ensure that the source code of moldy and any improvements made to it by anybody remains available to anyone who wishes to use it. If you change or improve Moldy, please tell me and if practical and appropriate I will incorporate your modifications into a future release. I hope that as time goes on Moldy will become yet more comprehensiva as a result of your input. I am also keeping a list of email addresses of anyone who uses the program for notification of updates, bugs and so forth. Please notify me if you would like to be added to this list, preferably by email to Keith.Refson@earth.ox.ac.uk. Contents of the distribution: accel.c algorith.c alloc.c aux.c beeman.c These files are the source code for Moldy. convert.c dump.c ewald.c force.c input.c eigens.c kernel.c main.c matrix.c output.c quaterns.c rdf.c restart.c startup.c values.c xdr.c parallel.c defs.h messages.h 'Include' files for above files structs.h xdr.h stddef.h time.h replacement ANSI C include files for non-ANSI systems. stdlib.h string.h dumpanal.c dumpconv.c dumpext.c Source code for 'utility' programs. mdshak.c mextract.c getopt.c Support routine for utility progs. Makefile Make file for Moldy. compile.com Master compile file for VMS. Calls all the others. compile_moldy.com Compile file for "moldy" itself. compile_utils.com Link file for "moldy" itself. link_moldy.com Compile file for utilities. link_utils.com Link file for utilities. defcomm.com Defines comands - execute from your LOGIN.COM moldy.tex LaTeX source for manual moldy.bbl mcy.in methane.in mgclh2o.in Example system specification files tip4p.in tips2.in control.mgclh2o control.tip4p Example control files control.water control.100 UNPACKING --------- A. Unix distribution This distribution of Moldy takes the form of a bourne shell (shar) archive, or a compressed tar archive. To unpack the former, cd to the directory where you wish the files to go and type /bin/sh moldy.shar (or whatever the name of this file is). The tar archive is unpacked with % uncompress moldy.tar % tar xvf moldy.tar B. VMS The VMS version of Moldy comes as a DCL archive, moldy.com. To unpack: $ @moldy This creates all the files needed in the current directory. Alternatively, versions of "uncompress" and "tar" are available for VMS, though they are not standard. If you have them then you can unpack the "moldy.tar.Z" archive (suitably renamed) in the same way. COMPILING --------- A. UNIX Stage 1. You ought to be able to type "make moldy utilities" on just about any flavour of unix and build a working version. However if you want to get the best performance you will have to work a bit harder with compiler options. You may also find that the compile fails for obscure reasons. Don't worry, some compile options will probably sort that out too. Stage 2. Edit "Makefile", choose a suitable set of compiler options for your machine and uncomment them. Moldy has been test compiled on most modern workstations as well as vector super and minisuper-computers, so you only have to select the preset options. N.B. IBM RS6000 This compiler does not supply any "identification" macro so you MUST have -DRS6000 in the c89 command line. Otherwise the XDR stuff won't work. Stage 3. This section describes how to "hand-tune" compiler options. If you get this far you have probably got a different machine or compiler system from any of the tested ones. Moldy recognises a number of C preprocessor macros which adjust its expectations of the compiler and operating system. These are best defined using the "-DMACRO-NAME" option of most unix C compilers. MACRO Purpose ----- ------- The following two macros are used to select the ANSI C "stdarg" mechanism. Default is older "varargs" mechanism. __STDC__ Automatically defined by ANSI compilers in strict mode. ANSI Alternative for ANSI compiler in non-strict mode which does not define __STDC__. ANSI_LIBS Set this if your libraries and header files conform to those expected in the ANSI 89 Standard. Otherwise extra replacement routines and header files to remedy the deficiencies of older systems are included. Set this if at all possible. Only in an ANSI environment can you be sure that all needed headers and library routines will be present. The alternative is a kludge which works most of the time on most machines. This is automatically set in "defs.h" for some machines/compilers vhich are known to have ANSI libraries. USE_XDR Turn on support for the portable binary dump and restart files using the XDR mechanism. This is the only area where Moldy departs substantially from the ANSI C standard so it is optional. Nevertheless it is so massively useful that it is on by default. As this is not part of the standard it may not compile correctly on some systems if the compiler is in "strict ANSI" mode. Use the default or the "relaxed" or "extended" ansi mode often provided. You may well need to add a library to the link using the LDFLAGS variable in the Makefile. For example, solaris 2 on Suns needs the "-lnsl" option and SGI's need the "-lsun" option. You may also need to define some other macro to get the headers correctly included viz: _ALL_SOURCE (IBM RS6000) _HPUX_SOURCE (HPUX) These are needed to enable stuff needed for the XDR routines and headers on IBM and HP machines. N.B. These are actually set automatically in the Moldy header "defs.h" (but see note about need for -DRS6000 on IBM). However other systems may require something similar . SPMD Compile for SPMD (Single Program Multiple Data) parallel execution. You must also specify one of the macros BSP, MPI or TCGMSG to select a message-passing library and have the appropriate include paths and libraries defined in the Makefile. B. VMS (VAX/VMS and OpenVMS/AXP) Just execute the "compile.com" DCL command file which will build Moldy and the utilities. All the required macros are set in "defs.h". It also executes the command file "defcomm.com" which defines the command symbols to execute the programs. It is a good idea to execute this file from your LOGIN.COM to make them available every time you log in. N.B. Depending on how your VMS system is set up you may need to take additional steps to link moldy with the C runtime library. Consult your local documentation or systems staff. If the C library isn't linked by default the command $ assign sys$library:vaxcrtl lnk$library before the executing the compile command file $ @compile may well do the trick. RUNNING ------- Try it out by typing moldy control.water to do a 10 timestep simulation of water. PRINTING THE MANUAL ------------------- The LaTeX source, "moldy.tex" and bibliography file, "moldy.bbl" are supplied. If you have LaTeX, "latex moldy" a couple of times to get the cross-references correct and print the dvi file using dvips or dvi2ps, or whatever dvi output you normally use. There is a "moldy.dvi" target in the make file so just "make moldy.dvi" ought to do the trick. PARALLEL VERSION ---------------- A. Shared memory. ------------- The sources contain separate versions of ewald.c and force.c with the appropriate code and compiler directives for compilation on certain shared-memory parallel machines including Stardent Titan, Convex and Cray architectures. To use, you must REPLACE ewald.c and force.c with the file ewald_parallel.c and force_parallel.c respecively. You must also define the preprocessor symbol PARALLEL during the compilation (eg with the compiler option -DPARALLEL). The code reads the environment to decide how many processors to execute on. The name of the env variable is usually the same one as the manufacturers use for the same purpose NCPUS for the CRAY and THREADS on everything else. Use the SETENV command (for c-chell) or the bourne-shell equivalent to before starting a run. Note. The Stardent Titan version does not work as shipped because the system supplied version of "malloc" can not be safely called from a parallel program. Contact the author for a "thread-safe" version which can. B. Distributed Memory ------------------ To build this version you must have one of the three supported message-passing libraries installed on the target system. These are the Oxford BSP library, MPI (the new standardised message-passing library interface) and TCGMSG (the Theoretical Chamistry message-passing system). Then define the macro PARLIBC in the Makefile to contain the "include" path for the library header files, and the preprocessor symbols SPMD and one of MPI, BSP and TCGMSG. The macro PARLIBL should be defined to link with the appropriate libraries. To find out how to set up a parallel run, consult the documentation for your parallel system, as this varies. The parallel performance increses with system size as the amount of work in the force and ewald sum loops increases as a proportion of the total work and with respect to the communication overhead. A speedup of nearly 7 on an 8-processor IBM SP1 has been demonstrated for the run "control.big", and in general the larger the system the better the parallel performance. The parallel interface is contained within a single file "parallel.c" and versions for other MP libraries should be relatively easy to add with a few hours of programming effort. Alternative Ewald: ------------------ There is an alternative version of Ewald.c which uses W. Smith's RIL paralellization strategy in ewald-RIL.c. This uses far less memory but at the cost of doing parallel communication in the inner loops. This may work reasonably on parallel machines with very short latencies, but on many it serializes the whole code! $EOD $! $CREATE compile.com $DECK $ write sys$output "===========Building Moldy============" $ @compile_moldy $ @link_moldy $ write sys$output "===========Building utilities============" $ @compile_utils $ @link_utils $ @defcomm $ write sys$output "===========Done============" $EOD $! $CREATE accel.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Accel This file contains the 'driver' function for a single timestep - * * "do_step" and other functions which need access to the system * * and species structs, "rescale" and "distant_const". * ****************************************************************************** * Revision Log * $Log: accel.c,v $ * Revision 2.17 1996/11/05 16:47:19 keith * Optimized site and site_force arrays to avoid cache conflicts. * * Revision 2.16 1996/08/23 15:06:01 keith * Fixed bug whereby rot elements of temp_value[] were uninitialized. * This caused a crash on non-ieee machines. * * Revision 2.15 1996/08/14 16:23:24 keith * Fixed error in thermoststat implementation and integration. * * Revision 2.14 1996/03/14 14:42:27 keith * Altered "rescale()" to suntract net velocity in case of * separate-species rescaling, since that doesn't conserve momentum. * * Revision 2.13 1996/01/15 15:14:00 keith * De "lint"-ed the code. * Removed "old" RDF code call. * * Revision 2.12 1995/12/07 17:43:53 keith * Reworked V. Murashov's thermostat code. Created new functions * nhtherm() and gtherm() to calculate alphadot. * Changed to Program units. * * Revision 2.11 1995/12/05 11:24:57 keith * Added new function "poteval" which calls "kernel" to evaluate * potential at single point and modified "distant_const" to * correctly evaluate long-range pressure correction. * * Revision 2.10 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.9 1994/07/12 16:20:26 keith * Fixed bug whereby "dip_mom" left uninitialized for non-coulomb system. * * Revision 2.8 1994/07/07 16:57:01 keith * Updated for parallel execution on SPMD machines. * Interface to MP library routines hidden by par_*() calls. * Compile with -DSPMD to activate * * Revision 2.7 1994/06/08 13:07:39 keith * New version of array allocator which breaks up requests for DOS. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump".Changed size_t to own typedef size_mt == ulong. * * Revision 2.5 94/01/18 13:31:46 keith * Null update for XDR portability release * * Revision 2.4 93/12/16 18:14:11 keith * Fixed divide-by-zero bug when rescaling on atomic systems. * (Only showed up on FPE trapping architectures.) * * Revision 2.3 93/10/28 10:27:32 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:47:36 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.8.1.26 93/03/15 14:39:59 keith * Added GPL copyleft notice to permit release and distribution. * N.B. Previous versions were copyright (C) by author and * only licensed by explicit permission. * * Revision 1.8.1.25 93/03/09 14:15:09 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.8.1.24 92/10/28 14:09:42 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.8.1.23 92/10/01 18:08:09 keith * Added mol_radius(). Function used in force.c for cutoff calculation. * * Revision 1.8.1.22 92/09/22 14:48:19 keith * Tidied up calls to improve "lint" rating. * * Revision 1.8.1.21 92/06/26 17:01:18 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.8.1.20 92/03/19 15:46:28 keith * Removed spurious varlaibe errptr. * * Revision 1.8.1.19 92/03/11 12:56:16 keith * Changed "scale-separately" parameter to "scale options" * * Revision 1.8.1.18 91/11/26 10:22:58 keith * Corrections to calculate framework pressure/stress correctly. * Corrected calculation of distant-stress term (Only 1 1/v necessary). * * Revision 1.8.1.17 91/10/17 14:22:38 keith * Fixed bug in set up pointers in "torque" array. * * Revision 1.8.1.16 91/08/15 18:09:16 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.8.1.15 91/03/12 15:41:07 keith * Tidied up typedefs size_mt and include file * Added explicit function declarations. * * Revision 1.8.1.14 91/02/19 14:50:13 keith * Rewrote loop to work around titan compiler bug * * Revision 1.8.1.13 90/12/19 12:04:56 keith * Added test to protect against infinite looping for velocity non-convergence. * * Revision 1.8.1.12 90/10/25 18:05:55 keith * Modified rescale() to correctly handle separate scaling in case * of framework with no dynamics. Also call thermalise if T=0. * * Revision 1.8.1.11 90/10/23 20:12:09 keith * Added dummy function call to inhibit vectorization. * This allows use of 'ivdep' compiler options and also * works round certain bugs in cray's scc compiler. * * Revision 1.8.1.10 90/10/16 14:47:06 keith * Workaround added to inhibit (incorrect) vectorization of loop * at line 411 under cray scc 1.0 * * Revision 1.8.1.9 90/08/02 15:51:53 keith * Modified to exclude framework-framework interactions. * N.B. Excluded from pe and stress but NOT forces (as they sum to 0). * * Revision 1.8.1.8 90/07/16 15:54:51 keith * Fixed bugs in constant-stress code * * Revision 1.8.1.7 90/05/16 18:38:30 keith * Renamed own freer from cfree to tfree. * * Revision 1.8.1.6 90/05/16 14:18:58 keith * *** empty log message *** * * Revision 1.8.1.5 90/04/16 18:18:58 keith * Changed call of "rahman" by adding "strain-mask" parameter. * * Revision 1.8.1.4 90/01/15 12:23:27 keith * Corrected declaration of arralloc from void* to char* to keep lint happy. * * Revision 1.8.1.3 89/12/22 19:31:56 keith * New version of arralloc() orders memory so that pointers come FIRST. * This means you can simply free() the pointer returned (if l.b. = 0). * * Revision 1.8.1.2 89/12/22 11:14:38 keith * Reversed indices in 'site' and 'site_force' to allow stride of 1 in ewald. * * Revision 1.8.1.1 89/10/06 16:22:51 keith * Make_sites() modified to wrap sites of framework back into MD box. * * Revision 1.8 89/09/04 18:51:43 keith * Made De Leeuw surface dipole term optional (off by default). * This term SHOULD NOT be included for ionic systems. * * Revision 1.7 89/08/10 17:28:05 keith * Fixed if statement so that rdf's started on rather than after 'begin-rdf' * * Revision 1.6 89/07/03 18:17:25 keith * Made code to add dipole energy and force conditional, like Ewald. * * Revision 1.5 89/06/22 15:42:17 keith * Tidied up loops over species to use one pointer as countes * * Revision 1.4 89/06/14 18:18:12 keith * Removed call to SCILIB function VCOPY and equivalents - use memcpy instead. * * Revision 1.3 89/05/22 18:37:04 keith * Added option to scale velocities of each species separately * * Revision 1.2 89/04/20 17:49:08 keith * Added code for surface dipole part of Ewald sum (After De Leeuw et al). * * Revision 1.1 89/04/20 15:58:41 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/accel.c,v 2.17 1996/11/05 16:47:19 keith Exp $"; #endif /*========================== Library include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include #include "string.h" #include "stddef.h" #if defined(DEBUG10) || defined(DEBUG2) #include #endif /*========================== program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void afree(); /* Free allocated array */ void step_1(); /* Step co-ordinates by Beeman algrthm */ void step_2(); /* Step velocities at above */ void beeman_2(); /* As above for individual components */ void make_sites(); /* Construct site coordinate arrays */ void mol_force(); /* Calculare molecular from site force */ void mol_torque(); /* Calculate torques from site forces */ void rotate(); /* Perform rotations given quaternions */ void newton(); /* Calculate accelerations from forces */ void euler(); /* Get quat 2nd derivatives */ void parinello(); /* Get correction to c of m accns */ void rahman(); /* Get h 2nd derivatives */ void energy_dyad(); /* Calculate mvv for stress term */ void force_calc(); /* Calculate direct-space forces */ double dist_pot(); /* Returns integrated potential fn */ void ewald(); /* Get Ewald sum forces */ void dump(); /* Maintain and write dump data files */ void zero_real(); /* Clear area of memory */ void zero_double(); /* Clear area of memory */ void invert(); /* Matrix inverter */ double det(); /* Returns matrix determinant */ void mat_vec_mul(); /* 3 x 3 Matrix by Vector multiplier */ void mean_square(); /* Caluculates mean square of args */ void rdf_calc(); /* Accumulate and bin rdf */ double value(); /* Return thermodynamic average */ double roll_av(); /* Return thermodynamic average */ double vdot(); /* Fast vector dot product */ double sum(); /* Fast vector sum. */ void vscale(); /* Vector by constant multiply */ double vec_dist(); /* normalised vector distance */ void thermalise(); /* Randomize velocities to given temp */ double trans_ke(); /* Compute translational kinetic en. */ double rot_ke(); /* Compute rotational kinetic en. */ void hoover_tr(); /* Corrects forces due to thermostat */ void hoover_rot(); /* Corrects forces due to thermostat */ double gaussiant(); /* Return Force*vel */ double gaussianr1(); /* Return Torque*omega */ double gaussianr2(); /* Return omega*I*omega */ void q_conj_mul(); /* Quat. conjugated x by quat. dot */ void inhibit_vectorization(); /* Self-explanatory dummy */ void kernel(); /* Potential function evaluation */ #ifdef SPMD void par_rsum(); void par_dsum(); #endif #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else gptr *arralloc(); /* Array allocator */ void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ extern int ithread, nthreads; /*========================== Macros ==========================================*/ #define ITER_MAX 10 #define CONVRG 1.0e-7 /* Can't rely on ANSI yet. */ #ifndef DBL_MIN # define DBL_MIN 1.0e-36 #endif /*========================== Cache Parameters=================================*/ /* The default values are for the Cray T3D but are probably good enough * for most other systems too. */ #ifndef NCACHE # define NCACHE (256*sizeof(double)/sizeof(real)) #endif #ifndef NLINE # define NLINE (4*sizeof(double)/sizeof(real)) #endif /*============================================================================*/ /****************************************************************************** * rescale rescale velocities and quaternion derivatives to desired temp.* * Exact behaviour is controlled by flag "control.scale_options". * * This is a bit flag with the following meanings: * * bit 0: scale temperature for each species separately. * * bit 1: scale rotational and translational velocities separately * * bit 2: use rolling averages rather than instantaneous "temperatures" * * bit 3: don't scale at all, but re-initialize from MB distribution. * ******************************************************************************/ void rescale(system, species) system_mp system; spec_mp species; { spec_mp spec; int ispec, imol, i; double *temp_value = dalloc(2*system->nspecies); double min_temp=MIN(value(t_n,0),roll_av(t_n,0)); double rtemp = 0.0, ttemp = 0.0, scale; double total_mass; vec_mt momentum; int tdof=0, rdof=0; /* * First get trans. and rot. "temperatures", either instantaneous * or rolling averages for each species individually. */ for(ispec = 0, spec = species; ispec < system->nspecies; ispec++, spec++) { if( control.scale_options & 0x4 ) { temp_value[2*ispec ] = roll_av(tt_n,ispec); temp_value[2*ispec+1] = roll_av(rt_n,ispec); } else { temp_value[2*ispec ] = value(tt_n,ispec); temp_value[2*ispec+1] = value(rt_n,ispec); } if( ! spec->framework ) { if( temp_value[2*ispec ] < min_temp ) min_temp = temp_value[2*ispec ]; if( spec->rdof > 0 && temp_value[2*ispec+1] < min_temp ) min_temp = temp_value[2*ispec+1]; } } /* * Re initialize from Maxwell-Boltzmann distribution if explicitly * requested, or if any temperature is zero. */ if( min_temp < 1.0e5*DBL_MIN || (control.scale_options & 0x8) ) { thermalise(system, species); return; } /* * Get average of translational and rotational temps (per species) */ if( ! (control.scale_options & 0x2) ) for(ispec = 0, spec = species; ispec < system->nspecies; ispec++, spec++) if( ! spec->framework ) temp_value[2*ispec ] = temp_value[2*ispec+1] = (3*temp_value[2*ispec ] + spec->rdof*temp_value[2*ispec+1]) / (3+spec->rdof); /* * Perform average over species if scaling together. */ if( ! (control.scale_options & 0x1) ) { for(ispec = 0, spec = species; ispec < system->nspecies; ispec++, spec++) if( ! spec->framework ) { ttemp += 3*spec->nmols*temp_value[2*ispec ]; tdof += 3*spec->nmols; rtemp += spec->rdof*spec->nmols*temp_value[2*ispec+1]; rdof += spec->rdof*spec->nmols; } ttemp /= tdof; if( rdof > 0 ) rtemp /= rdof; for(ispec = 0, spec = species; ispec < system->nspecies; ispec++, spec++) if( ! spec->framework ) { temp_value[2*ispec ] = ttemp; temp_value[2*ispec+1] = rtemp; } } /* * Actually do the scaling */ #ifdef DEBUG6 fprintf(stderr,"Trans T\t\tRot T\n"); #endif for(ispec = 0, spec = species; ispec < system->nspecies; ispec++, spec++) { #ifdef DEBUG6 fprintf(stderr,"%8.2f\t%8.2f\n", temp_value[2*ispec],temp_value[2*ispec+1]); #endif if( ! spec->framework ) { scale = sqrt(control.temp / temp_value[2*ispec]); vscale(3 * spec->nmols, scale, spec->vel[0], 1); if( spec->rdof > 0 ) { scale = sqrt(control.temp / temp_value[2*ispec+1]); vscale(4 * spec->nmols, scale, spec->qdot[0], 1); vscale(4 * spec->nmols, scale*scale, spec->qddot[0], 1); vscale(4 * spec->nmols, scale*scale, spec->qddoto[0], 1); } } } /* * Subtract spurious net velocity introduced by scaling species * separately. This will introduce an apparent error into the * instantaneous "temperature". But the error was there anyway * since net linear velocity shouldn't be included in the * calculation. Do nothing for joint rescaling since that does * conserve momentum or for a framework system. */ if( control.scale_options & 0x1 ) { total_mass = 0.0; zero_real(momentum, 3); for (spec = species; spec < species+system->nspecies && ! spec->framework; spec++) { total_mass += spec->mass*spec->nmols; for(i = 0; i < 3; i++) momentum[i] += spec->mass*sum(spec->nmols, spec->vel[0]+i,3); } if(spec == species+system->nspecies)/* Normal loop exit => no framework */ for (spec = species; spec < species+system->nspecies; spec++) for(i = 0; i < 3; i++) for(imol = 0; imol < spec->nmols; imol++) spec->vel[imol][i] -= momentum[i] / total_mass; } tfree((gptr*)temp_value); } /****************************************************************************** * nhtherm Calculate acceleration term for Nose-hoover variable * * Exact behaviour is controlled by flag "control.scale_options". * * This is a bit flag with the following meanings: * * bit 0: scale temperature for each species separately. * * bit 1: scale rotational and translational velocities separately * * bit 2: use rolling averages rather than instantaneous "temperatures" * * bit 3: don't scale at all, but re-initialize from MB distribution. * ******************************************************************************/ void nhtherm(sys, species) system_mp sys; spec_mp species; { int ispec; int nspecies = sys->nspecies; int tdof=0, rdof=0; spec_mt *spec; double *temp_value = dalloc(2*nspecies); double rtemp_mass, ttemp_mass; double ttemp = 0.0, rtemp = 0.0; for(spec=species, ispec = 0; ispec < nspecies; spec++, ispec++) { temp_value[2*ispec ] = trans_ke(sys->h, spec->velp, spec->mass, spec->nmols) /(1.5*spec->nmols*kB); if(spec->rdof > 0) /* Only if polyatomic species */ temp_value[2*ispec+1] = rot_ke(spec->quat, spec->qdotp, spec->inertia, spec->nmols) /(0.5*kB*spec->rdof*spec->nmols); else temp_value[2*ispec+1] = 0.0; } /* * Get average of translational and rotational temps (per species) */ if( ! (control.scale_options & 0x2) ) { for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) { if( ! spec->framework ) temp_value[2*ispec ] = temp_value[2*ispec+1] = (3*temp_value[2*ispec ] + spec->rdof*temp_value[2*ispec+1]) / (3+spec->rdof); } ttemp_mass = rtemp_mass = control.ttmass; } else { ttemp_mass = control.ttmass; rtemp_mass = control.rtmass; /* * ttemp_mass and rtemp_mass are used here to make easier introduction * of different thermal masses for different species later on, provided * such necessity rises */ } /* * Perform average over species if thermostatting together. */ if( ! (control.scale_options & 0x1) ) { for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) if( ! spec->framework ) { ttemp += 3*spec->nmols*temp_value[2*ispec ]; tdof += 3*spec->nmols; rtemp += spec->rdof*spec->nmols*temp_value[2*ispec+1]; rdof += spec->rdof*spec->nmols; } ttemp /= tdof; if( rdof > 0 ) rtemp /= rdof; for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) if( ! spec->framework ) { temp_value[2*ispec ] = ttemp; temp_value[2*ispec+1] = rtemp; } } /* * It might be necessary to zero total momenta of species of each type * if thermostating together */ /* * Find alphadot for Nose-Hoover thermostat */ for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) { if( ! spec->framework ) { sys->tadot[ispec] = 3*spec->nmols*kB / ttemp_mass * (temp_value[2*ispec] - control.temp); sys->radot[ispec] = spec->rdof*spec->nmols*kB / rtemp_mass * (temp_value[2*ispec+1] - control.temp); } } tfree((gptr*)temp_value); } /****************************************************************************** * gtherm Calculate acceleration term for Gaussian thermostat variable * * Exact behaviour is controlled by flag "control.scale_options". * * This is a bit flag with the following meanings: * * bit 0: scale temperature for each species separately. * * bit 1: scale rotational and translational velocities separately * * bit 2: use rolling averages rather than instantaneous "temperatures" * * bit 3: don't scale at all, but re-initialize from MB distribution. * ******************************************************************************/ void gtherm(sys, species, force, torque) system_mp sys; spec_mp species; vec_mp force[]; vec_mp torque[]; { int j, ispec; int nspecies = sys->nspecies; spec_mt *spec; vec_mp vel_tmp = ralloc(sys->nmols); quat_mp qd_tmp; /* Temporary for velocities */ double *temp_value = dalloc(2*nspecies); double ttemp = 0.0, rtemp = 0.0, alphat = 0.0, alphar = 0.0; mat_vec_mul(sys->h, sys->velp, vel_tmp, sys->nmols); for(ispec = 0, spec = species, j = 0; ispec < nspecies; ispec++, spec++) { if( ! spec->framework ) { sys->tap[ispec] = gaussiant(force[ispec], vel_tmp+j, spec->nmols); temp_value[2*ispec] = spec->mass * gaussiant(vel_tmp+j, vel_tmp+j, spec->nmols); if (spec->rdof > 0) { qd_tmp = qalloc(spec->nmols); q_conj_mul(spec->quat, spec->qdotp, qd_tmp, spec->nmols); vscale(4*spec->nmols, 2.0, qd_tmp[0], 1); sys->rap[ispec] = gaussianr1(torque[spec-species], qd_tmp, spec->nmols); temp_value[2*ispec+1] = gaussianr2(qd_tmp, spec->inertia, spec->nmols); xfree(qd_tmp); } else { temp_value[2*ispec+1] = 0.0; sys->rap[ispec] = 0.0; } } j+= spec->nmols; } /* * Get average of translational and rotational alpha's (per species) */ if( ! (control.scale_options & 0x2) ) for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) if( ! spec->framework ) { sys->tap[ispec] = sys->rap[ispec] += sys->tap[ispec]; temp_value[2*ispec] = temp_value[2*ispec+1] += temp_value[2*ispec]; } /* * Perform average over species if thermostatting together. */ if( ! (control.scale_options & 0x1) ) { ttemp = 0.0; rtemp = 0.0; for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) if( ! spec->framework ) { ttemp += temp_value[2*ispec ]; rtemp += temp_value[2*ispec+1]; alphat += sys->tap[ispec]; alphar += sys->rap[ispec]; } for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) { if( ! spec->framework ) { temp_value[2*ispec ] = ttemp; temp_value[2*ispec+1] = rtemp; sys->tap[ispec] = alphat; sys->rap[ispec] = alphar; } } } /* * It might be necessary to zero total momenta of species of each type * if thermostating together */ /* * Finally find alpha = alpha1/alpha2 */ for(ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) if( ! spec->framework ) { if (temp_value[2*ispec] != 0.0) sys->tap[ispec] /= temp_value[2*ispec]; else sys->tap[ispec] = 0.0; if (temp_value[2*ispec+1] != 0.0) sys->rap[ispec] /= temp_value[2*ispec+1]; else sys->rap[ispec] = 0.0; } xfree(vel_tmp); tfree((gptr*)temp_value); } /****************************************************************************** * Poteval Return potential evaluated at a single point. * ******************************************************************************/ static double poteval(potpar, r, ptype) real potpar[]; /* Array of potential parameters */ double r; /* Cutoff distance */ int ptype; /* Potential type selector */ { double pe = 0.0; real f,rr; real *pp[NPOTP]; int i; for(i=0; imax_id); /* Numbers of each site * type */ double c = 0.0; /* Accumulator for result */ /* * Count the sites */ memst(site_count,0,system->max_id*sizeof(int)); for (spec = species; spec < &species[system->nspecies]; spec++) { NOVECTOR for (isite = 0; isite < spec->nsites; isite++) { inhibit_vectorization(); site_count[spec->site_id[isite]] += spec->nmols; } } for (id = 1; id < system->max_id; id++) /* Loops for sum over i,j */ for (jd = 1; jd < system->max_id; jd++) { c -= 2 * PI * site_count[id] * site_count[jd] * dist_pot(potpar[id + system->max_id*jd].p, cutoff, system->ptype); if( iflag ) c += 2.0/3.0 * PI * site_count[id] * site_count[jd] * CUBE(cutoff) * poteval(potpar[id + system->max_id*jd].p, cutoff, system->ptype); } xfree(site_count); return (c); } /****************************************************************************** * Shuffle move down the 'acceleration' co-ordinates * * current->old, old->very old, very old->oblivion to make room for the new * * ones at the next timestep. Only the pointers are actually moved * ******************************************************************************/ static vec_mp v_tmp; static quat_mp q_tmp; static real *atmp; #define shuffle(a, ao, avo, tmp) {tmp = avo; \ avo = ao; \ ao = a; \ a = tmp; } /****************************************************************************** * do_step This routine controls the main part of the calculation for * * each timestep. It performs the following actions: It * * 1) Allocates space for the dynamic arrays for site co-ordinates, * * site forces, molecular forces and torques. * * 2) Builds the array, site, of site co-ordinates from the principal-frame* * co-ordinates, c of m positions and molecular quaternions. * * 3) Steps the co-ordinates using the Beeman algorithm * * 4) Calls the main inter-site force calculating routine, force_calc. * * 5) Calls the Ewald sum routine for charged systems. * * 6) Evaluates the molecular forces and torques from the site forces * * 7) 'shuffles' all the accelerations down to make room for the new ones * * about to be evaluated. * * 8) Applies Newton's equations of motion to calculate accelerations, * * Euler's equations and 2nd order quaternion method to get the * * quaternion accelerations and calculates the h-matrix accelerations * * in the Parinello and Rahman constant-stress method. * * 9) Applies the P & R correction to the c of m accelerations. * * 10) Steps the velocities using the Beeman algorithm, * * and iterates steps 8-10 until convergence. * * 11) Deallocates all the dynamic arrays and returns the space to the heap * ******************************************************************************/ void do_step(sys, species, site_info, potpar, meansq_f_t, pe, dip_mom, stress, restart_header, backup_restart) system_mp sys; /* Pointer to system info (in) */ spec_mt species[]; /* Array of species info (in) */ site_mt site_info[]; /* Array of site info structures (in) */ pot_mt potpar[]; /* Array of potential parameters (in) */ vec_mt meansq_f_t[][2]; /* Mean square force and torque (out) */ double pe[]; /* Potential energy real/Ewald (out) */ vec_mt dip_mom; /* Total system dipole moment (out) */ mat_mt stress; /* Virial part of stress (out) */ restrt_mt *restart_header; /* What the name says. (in) */ int backup_restart; /* Flag signalling backup restart (in)*/ { /* * The following declarations are arrays of pointers to the forces * etc for each species. That is force[i] is a pointer to the force on * molecule 0 of species i */ vec_mp *force = palloc(sys->nspecies), *torque = palloc(sys->nspecies); real ***site_sp = (real***)arralloc((size_mt)sizeof(real*), 2, 0, sys->nspecies-1, 0, 2), ***force_sp = (real***)arralloc((size_mt)sizeof(real*), 2, 0, sys->nspecies-1, 0, 2); /* * The following declarations are pointers to the force etc for the whole * system, and are set equal to (eg) force[0] */ vec_mp force_base = ralloc(sys->nmols), torque_base = sys->nmols_r?ralloc(sys->nmols_r):0; int nsarray = (sys->nsites - 1 | NCACHE - 1) + 1+NLINE; real **site = (real**)arralloc((size_mt)sizeof(real), 2, 0, 2, 0, nsarray-1); real **site_force = (real**)arralloc((size_mt)sizeof(real), 2, 0, 2, 0, nsarray-1); /* * Other local variables */ real *chg = dalloc(sys->nsites), *chg_ptr; vec_mp c_of_m = ralloc(sys->nmols); spec_mp spec, fspec /*Framework species */; int nspecies = sys->nspecies; int ispec, imol, imol_r, isite; int i, j; static boolean init = true; static double dist, distp; double vol = det(sys->h); int iter; mat_mt ke_dyad, hinv; quat_mp qd_tmp; /* Temporary for velocities */ vec_mp acc_tmp, vel_tmp; /* Temporaries for iteration */ int nsitesxf, nmolsxf; /* Count of non-framework sites, mols. */ /* * Initialisation of distant potential constant - executed first time only */ if (init) { dist = distant_const(sys, species, potpar, control.cutoff,0); distp = distant_const(sys, species, potpar, control.cutoff,1); if( ithread == 0 ) note("Distant potential correction = %f, Pressure correction = %f", CONV_E * dist / vol, CONV_P * distp / (vol * vol)); init = false; } /* * The next chunk of code sets up the dynamic arrays for the centre of mass * forces, torques, site vectors and site forces. It is a little complex but * results in great simplicity in all of the called routines. The arrays * themselves are indicated by pointers *_base (*=force etc), and have * dimensions [n][3], n= number of molecules, polyatomics and sites. They are * subdivided into the appropriate segments for each molecular species eg * site_base[nspecies][nsites][3], BUT nsites depends on the species so it is * NOT a 3 dimensional array. Instead the array of pointer 'site' is used. * Site[ispec] is a pointer to the sub-array for species ispec of dimension * [nsites][3]. If any or all of the molecular species are monatomic, then no * space is allocated for the torque array, and all the pointers are NULL. */ /* * Count non-framework sites and molecules. */ fspec = species; nsitesxf = 0; nmolsxf = 0; while (fspec < species+nspecies && ! fspec->framework) { nsitesxf += fspec->nsites * fspec->nmols; nmolsxf += fspec->nmols; fspec++; } /* * Set up arrays of pointers to sites, forces etc for each species */ isite = 0; imol = 0; imol_r = 0; for (ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) { force[ispec] = force_base+imol; if (spec->quat) torque[ispec] = torque_base+imol_r; for( i = 0; i < 3; i++ ) { site_sp[ispec][i] = site[i]+isite; force_sp[ispec][i] = site_force[i]+isite; } imol += spec->nmols; if (spec->quat) imol_r += spec->nmols; isite += spec->nmols * spec->nsites; } /* * Set up array of site charges */ chg_ptr = chg; for (spec = species; spec < species+nspecies; spec++) for (imol = 0; imol < spec->nmols; imol++) for (isite = 0; isite < spec->nsites; isite++) *chg_ptr++ = site_info[spec->site_id[isite]].charge; mat_vec_mul(sys->h, sys->c_of_m, c_of_m, sys->nmols); /* * Set some accumulators to zero */ zero_real(stress[0], 9); /* Initialise stress tensor */ zero_real(meansq_f_t[0][0], 6 * sys->nspecies); zero_real(dip_mom, 3); zero_real(site_force[0], nsarray); zero_real(site_force[1], nsarray); zero_real(site_force[2], nsarray); zero_double(pe, NPE); /* * Initial co-ordinate step of Beeman algorithm. */ step_1(sys); /* * Calculate the site positions at this timestep - loop over species */ for (spec = species; spec < &species[nspecies]; spec++) { make_sites(sys->h, spec->c_of_m, spec->quat, spec->p_f_sites, spec->framework,site_sp[spec-species],spec->nmols,spec->nsites); #ifdef DEBUG1 { int is; printf("%s co-ordinates\n",spec->name); for(is = 0; is < spec->nsites*spec->nmols; is++) printf("%24.15f %24.15f %24.15f\n", site_sp[spec-species][0][is], site_sp[spec-species][1][is], site_sp[spec-species][2][is]); } #endif } /* * Real-space part of force evaluation - no loop over species for efficiency */ force_calc(site, site_force, sys, species, chg, potpar, pe, stress); /* * Reciprocal-space part of Ewald sum */ if (control.alpha > ALPHAMIN) { ewald(site, site_force, sys, species, chg, pe + 1, stress); } /* * Sum Pot, energies, forces and stress from each parallel invocation */ #ifdef SPMD par_dsum(pe, NPE); par_rsum(stress[0], 9); par_rsum(site_force[0], 3*nsarray); #endif if (control.alpha > ALPHAMIN) { /* * Dipole moment contribution to forces and potential (De Leeuw, Perram * and Smith Proc Roy Soc A373, 27-56 (1980) */ for (i = 0; i < 3; i++) dip_mom[i] = vdot(sys->nsites, site[i], 1, chg, 1); if( control.surface_dipole ) { for (i = 0; i < 3; i++) for ( isite = 0; isite < sys->nsites; isite++ ) site_force[i][isite] -= 4.0*PI/(3.0*vol)*dip_mom[i] * chg[isite]; pe[1] += 2.0*PI/(3.0*vol) * SUMSQ(dip_mom); } } /* * Calculate the centre of mass forces and torques from the site forces */ for (spec = species; spec < &species[nspecies]; spec++) { ispec = spec-species; mol_force(force_sp[ispec], force[ispec], spec->nsites, spec->nmols); if (spec->rdof > 0) mol_torque(force_sp[ispec], spec->p_f_sites, torque[ispec], spec->quat, spec->nsites, spec->nmols); } /* * Add correction term to convert from site to molecular virial */ for (i = 0; i < 3; i++) { for (j = i + 1; j < 3; j++) stress[j][i] = stress[i][j]; for (j = 0; j < 3; j++) { /* * Non-framework sites sum f.s = sum f.r - sum F.R */ stress[i][j] -= vdot(nsitesxf, site_force[i], 1, site[j], 1) - vdot(nmolsxf, force_base[0] + i, 3, c_of_m[0] + j, 3); /* * Framework sites -- can't use "site" array as sites have been * relocated by pbc's back into md cell. */ if( fspec < species+nspecies ) for(imol=0; imol < fspec->nmols; imol++) stress[i][j] -= vdot(fspec->nsites, site_force[i]+nsitesxf+imol*fspec->nsites,1, fspec->p_f_sites[0]+j,3); } } /* * Calculate distant stress and potential terms and add */ pe[0] += dist / vol; for (i = 0; i < 3; i++) stress[i][i] += distp / vol; /* * Shuffle the accelerations (acc -> acco, acco-> accvo, accvo -> acc) Don't * actually move the data - just the pointers */ shuffle(sys->acc, sys->acco, sys->accvo, v_tmp); shuffle(sys->qddot, sys->qddoto, sys->qddotvo, q_tmp); if (control.const_pressure) shuffle(sys->hddot, sys->hddoto, sys->hddotvo, v_tmp); if (control.const_temp == 1) { shuffle(sys->tadot, sys->tadoto, sys->tadotvo, atmp); shuffle(sys->radot, sys->radoto, sys->radotvo, atmp); } for (spec = species; spec < &species[nspecies]; spec++) { inhibit_vectorization(); /* Inhibits (incorrect) vectorization */ shuffle(spec->acc, spec->acco, spec->accvo, v_tmp); if (spec->rdof > 0) shuffle(spec->qddot, spec->qddoto, spec->qddotvo, q_tmp); } /* * Now apply the Newton/Euler equations to find the accelerations and * quaternion second derivatives. */ for (spec = species; spec < &species[nspecies]; spec++) newton(force[spec-species], spec->acc, spec->mass, spec->nmols); /* * Correction to centre of mass accelerations for constant pressure algorithm * First get scaled accelerations by multiplying by the inverse h matrix and * add P&R term. Then calculate the 'accelerations' of the unit cell matrix * and use the velocity predictor to step the cell "velocities". */ invert(sys->h, hinv); mat_vec_mul(hinv, sys->acc, sys->acc, sys->nmols); if (control.const_pressure) { zero_real(ke_dyad[0], 9); for (spec = species; spec < &species[nspecies]; spec++) energy_dyad(ke_dyad, sys->h, spec->velp, spec->mass, spec->nmols); rahman(stress, sys->h, sys->hddot, ke_dyad, control.pressure, control.pmass, control.strain_mask); beeman_2(sys->hdot[0], sys->hdotp[0], sys->hddot[0], sys->hddoto[0], sys->hddotvo[0], 9); } /* * Iterate linear velocity dependant parts with beeman step 2 until convergence */ if (control.const_pressure || control.const_temp) { iter = 0; acc_tmp = ralloc(sys->nmols); vel_tmp = ralloc(sys->nmols); do { iter++; if(iter > ITER_MAX) message(NULLI, NULLP, FATAL, NCNVRG, iter, vec_dist(vel_tmp[0], sys->velp[0], 3 * sys->nmols)); if (control.const_pressure) parinello(sys->h, sys->hdotp, sys->velp, sys->acc, acc_tmp, sys->nmols); else memcp(acc_tmp[0], sys->acc[0], 3 * sys->nmols * sizeof(real)); /* * Nose-Hoover thermostat added by VVMurashov , started on 20.10.95 * * Gaussian thermostat added by VVM , started on 3/11/95 * General formular alpha = alpha1/alpha2, where alpha1 = SUM force*vel * and alpha2 = SUM mass * vel ^ 2. Sys->tap(rap) is used to store * alpha1's and temp_value is used to store alpha2's temporarily. */ if (control.const_temp == 1) { nhtherm(sys, species); beeman_2(sys->ta, sys->tap, sys->tadot, sys->tadoto, sys->tadotvo, nspecies); #ifdef DEBUG3 printf("ta %8.4f tap %8.4f tadot %8.4f tadoto %8.4f\n", sys->ta[0], sys->tap[0], sys->tadot[0], sys->tadoto[0]); #endif } if (control.const_temp == 2) gtherm(sys, species, force, torque); if (control.const_temp) { for (ispec = 0, j = 0, spec = species; ispec < nspecies; ispec++, spec++) { if( ! spec->framework ) { hoover_tr(sys->tap[ispec], acc_tmp+j, acc_tmp+j, sys->velp+j, spec->nmols); } j+=spec->nmols; } } memcp(vel_tmp[0], sys->velp[0], 3 * sys->nmols * sizeof(real)); beeman_2(sys->vel[0], sys->velp[0], acc_tmp[0], sys->acco[0], sys->accvo[0], 3 * sys->nmols); } while (vec_dist(vel_tmp[0], sys->velp[0], 3 * sys->nmols) > CONVRG); #ifdef DEBUG printf("Velocities converged in %d iterations \n", iter); #endif memcp(sys->acc, acc_tmp, 3*sys->nmols * sizeof(real)); xfree(acc_tmp); xfree(vel_tmp); } /* * Iterate angular velocity dependant parts with beeman step 2 until convergence */ if (sys->nmols_r > 0) { iter = 0; qd_tmp = qalloc(sys->nmols_r); acc_tmp = ralloc(sys->nmols_r); do { iter++; if(iter > ITER_MAX) message(NULLI, NULLP, FATAL, NCNVRG, iter, vec_dist(qd_tmp[0], sys->qdotp[0], 4 * sys->nmols_r)); if (control.const_temp == 1) { nhtherm(sys, species); beeman_2(sys->ra, sys->rap, sys->radot, sys->radoto, sys->radotvo, nspecies); } if (control.const_temp == 2) gtherm(sys, species, force, torque); #ifdef DEBUG3 printf("ra %8.4f rap %8.4f radot %8.4f radoto %8.4f\n", sys->ra[0], sys->rap[0], sys->radot[0], sys->radoto[0]); #endif for (ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) if (spec->rdof > 0) { if (control.const_temp) { /**************************************************************** * VVM uses qd_tmp as a temp array to store angular velocities * ****************************************************************/ q_conj_mul(spec->quat, spec->qdotp, qd_tmp, spec->nmols); vscale(4*spec->nmols, 2.0, qd_tmp[0], 1); hoover_rot(sys->rap[ispec], spec->inertia, torque[spec-species], acc_tmp, qd_tmp, spec->nmols); } else memcp(acc_tmp[0], torque[spec-species], 3 * spec->nmols * sizeof(real)); euler(acc_tmp, spec->quat, spec->qdotp, spec->qddot, spec->inertia, spec->nmols); } memcp(qd_tmp[0], sys->qdotp[0], 4 * sys->nmols_r * sizeof(real)); beeman_2(sys->qdot[0], sys->qdotp[0], sys->qddot[0], sys->qddoto[0], sys->qddotvo[0], 4 * sys->nmols_r); } while (vec_dist(qd_tmp[0], sys->qdotp[0], 4 * sys->nmols_r) > CONVRG); #ifdef DEBUG printf("Quaternion derivatives converged in %d iterations \n", iter); #endif xfree(qd_tmp); xfree(acc_tmp); } /* * Apply constraint to any framework molecules. */ for (spec = species; spec < &species[nspecies]; spec++) if( spec->framework ) { zero_real(spec->acc[0], 3*spec->nmols); zero_real(spec->vel[0], 3*spec->nmols); } /* * Final MD update step */ step_2(sys); /* * Calculate mean-square forces and torques */ for (ispec = 0, spec = species; ispec < nspecies; ispec++, spec++) { mean_square(force[ispec], meansq_f_t[ispec][0], spec->nmols); if (spec->rdof > 0) mean_square(torque[ispec], meansq_f_t[ispec][1], spec->nmols); } if( ithread == 0 ) { #ifdef OLDRDF /* * Accumulate radial distribution functions */ if (control.rdf_interval > 0 && control.istep >= control.begin_rdf && control.istep % control.rdf_interval == 0) rdf_calc(site, sys, species); #endif /* * Perform periodic dump of dynamic data */ if (control.dump_interval > 0 && control.dump_level != 0 && control.istep >= control.begin_dump && (control.istep - control.begin_dump) % control.dump_interval == 0) dump(sys, force_base, torque_base, stress, pe[0] + pe[1], restart_header, backup_restart); } /* * Deallocate the dynamic storage before exiting */ xfree(force); xfree(torque); afree((gptr*)site); afree((gptr*)site_force); xfree(force_base); if (torque_base != NULL) xfree(torque_base); afree((gptr*)site_sp); afree((gptr*)force_sp); xfree(chg); xfree(c_of_m); } /******************************************************************************* * Mol_radius. Determine and return the greatest molecular radius of any * * species in the system. That is, the largest c-of-mass - site distance. * *******************************************************************************/ double mol_radius(species, nspecies) spec_mt species[]; int nspecies; { spec_mp spec; static double radius = -1.0; double r; int isite; if( radius >= 0.0 ) return radius; radius = 0.0; for(spec = species; spec < species+nspecies; spec++) if( !spec->framework ) { for( isite = 0; isite < spec->nsites; isite++ ) { r = SUMSQ(spec->p_f_sites[isite]); radius = MAX(radius, r); } } return radius; } $EOD $! $CREATE algorith.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Algorith This file contains functions to implement the simulation algor - * * ithms and other functions which do not need access to the system * * and species structs. Contents: * * rotate() Perform co-ordinate transformation from quaternions * * Vec_dist() Return 'distance' between 2 long vectors * * mol_force() Calculate molecular centre of mass forces * * mol_torque() Calculate molecular torques * * make_sites() Generate atomic site co-ordinates from c-of-m etc * * newton() Calculate accelerations from forces * * euler() Calculate quaternion accelerations from torques * * parinello() Calculate P&R c-of-m acceleration term * * rahman() Calculate unit cell matrix accelerations from stress * * trans_ke() Return translational kinetic energy. * * rot_ke() Return rotational kinetic energy * * energy_dyad() Calculate kinetic energy part of stress tensor * * gaussiant() Return alpha in Gaussian thermostat(trans) * * gaussianr1() Return alpha1 in Gaussian thermostat(rot) * * gaussianr2() Return alpha2 in Gaussian thermostat(rot) * * hoover_tr() Calculate correction to the forces(accelerations) * * hoover_rot() due to thermostat * ****************************************************************************** * Revision Log * $Log: algorith.c,v $ * Revision 2.9 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.8 1994/07/07 16:52:14 keith * Performance optimization to mol_force. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump".Changed size_t to own typedef size_mt == ulong. * * Revision 2.5 1994/01/18 13:32:05 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:27:35 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:48:51 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.1.1.12 93/03/15 14:41:28 keith * Added GPL copyleft notice to permit release and distribution. * N.B. Previous versions were copyright (C) by author and * only licensed by explicit permission. * * Revision 1.1.1.11 93/03/09 15:58:12 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.1.1.10 91/08/15 18:11:39 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.1.1.9 91/03/12 15:42:03 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.1.1.8 90/10/22 16:41:43 keith * Make vec_dist() robust in case of all-zero vectors. * * Revision 1.1.1.7 90/09/28 13:28:09 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.1.1.6 90/07/16 15:55:25 keith * Fixed bugs in constant-stress code * * Revision 1.1.1.5 90/05/16 18:39:06 keith * *** empty log message *** * * Revision 1.1.1.4 90/04/16 18:19:29 keith * Modified rahman() to arbitrarily constrain h matrix by new parameter "mask". * * Revision 1.1.1.3 89/12/21 16:29:43 keith * Reversed indices in 'site' and 'site_force' to allow stride of 1 in ewald. * * Revision 1.1.1.2 89/10/24 17:17:25 keith * Modified pbc algorithm to use floor() library function. * Now works with non-orthorhombic cell. * * Revision 1.1.1.1 89/10/06 16:23:57 keith * Make_sites() modified to wrap sites of framework back into MD box. * * Revision 1.1 89/04/20 16:00:19 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/algorith.c,v 2.9 1995/12/04 11:45:49 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" #include "messages.h" /*========================== Library include files ===========================*/ #include #include "string.h" #include "stddef.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void mat_vec_mul(); /* 3 x 3 Matrix by Vector multiplier */ void mat_mul(); /* 3 x 3 matrix multiplier */ void mat_add(); /* Add 2 3x3 matrices */ void mat_sca_mul(); /* Multiply 3x3 matrix by scalar */ void transpose(); /* transpose a 3x3 matrix */ void invert(); /* invert a 3x3 matrix */ double det(); /* Determinant of 3x3 matrix */ void q_to_rot(); /* Make rotation matrix from quat'n */ void q_mul(); void q_conj_mul(); double vdot(); /* Vector dot product */ double sum(); /* Vector sum */ void vscale(); #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== Macros ==========================================*/ #define MATMUL(i, m, r, o) (m[i][0]*r[0][o] + m[i][1]*r[1][o] + m[i][2]*r[2][o]) /*============================================================================*/ /****************************************************************************** * rotate Perform the rotation described by the quaternions in the * * second parameter on each of the co-ordinates in the first, putting the * * result in the third. (Pawley, Mol. Phys. 43, 1321-1330 (1981)) * * NB this is different to Evans' formulation. * * Apply each rotation to nvec/nquat vectors. * ******************************************************************************/ static void rotate(r_in, r_out, nvec, quat, nquat, inv_mat) vec_mp r_in, /* Co-ordinates to be rotated [n][3] (in) */ r_out; /* Resulting co-ordinates [n][3] (out) */ quat_mp quat; /* Quaternions for the rotation. (in) */ int nvec, /* Number of co-ordinates. (in) */ nquat; /* Number of quaternions (in) */ invrot inv_mat; /* Flag to do inverse rotations (in) */ { mat_mt rot; int iquat; if(nvec % nquat != 0) message(NULLI, NULLP, FATAL, ROTLEN, nvec, nquat); for(iquat = 0; iquat < nquat; iquat++) { q_to_rot(quat[iquat], rot); if(inv_mat == inv) transpose(rot, rot); mat_vec_mul(rot, r_in, r_out, nvec / nquat); r_in += nvec/nquat; r_out += nvec/nquat; } } /****************************************************************************** * mean_square Calculate the mean square of list of vectors for each cmpnt * ******************************************************************************/ void mean_square(x, meansq, nmols) vec_mt x[]; vec_mt meansq; int nmols; { int i; for(i = 0; i < 3; i++) meansq[i] = vdot(nmols, x[0]+i, 3, x[0]+i, 3) / nmols; } /****************************************************************************** * vec_dist Return the normalised distance between 2 vectors * ******************************************************************************/ double vec_dist(v1, v2, n) real *v1, *v2; /* Input vectors */ int n; /* Length ie v1[n], v2[n] */ { register double s=0, s1=0,s2=0; /* Accumulators for sums */ while(n-- > 0) { s += (*v1 - *v2) * (*v1 - *v2); s1 += *v1 * *v1; s2 += *v2 * *v2; v1++; v2++; } s1 = MAX(s1,s2); if( s1 == 0.0 ) return s1; else return(sqrt(s / s1)); } /****************************************************************************** * molecule_force Calculate the centre of mass forces on a number of * * molecules given the site forces and the site co-ordinates. * ******************************************************************************/ void mol_force(site_force, force, nsites, nmols) real **site_force; /* Site forces [nsites*nmols][3] (in) */ vec_mp force; /* Centre of mass forces [nmols][3] (out) */ int nsites, /* Number of sites on one molecule (in) */ nmols; /* Number of molecules (in) */ { int i, imol, isite; double f; for(imol = 0; imol < nmols; imol++) for(i = 0; i < 3; i++) { f = 0; for(isite=0; isite < nsites; isite++) f += site_force[i][isite+imol*nsites]; force[imol][i] = f; } } /****************************************************************************** * molecule_torque Calculate the torque on a number of identical * * molecules given the space frame site forces and co-ordinates. * ******************************************************************************/ void mol_torque(site_force, site, torque, quat, nsites, nmols) real **site_force; /* Principal frame site forces (in) */ vec_mp site, /* Principal frame site co-ordinates (in) */ torque; /* Molecular torques [nmols][3] (out) */ quat_mp quat; /* Molecular quaternions [nmols][4] (in) */ int nsites, /* Number of sites on one molecule (in) */ nmols; /* Number of molecules (in) */ { vec_mp princ_force = ralloc(nsites); int i, j, k, imol, isite; register double torq; for(imol = 0; imol < nmols; imol++) { for(i = 0; i < 3; i++) { VECTORIZE for(isite = 0; isite < nsites; isite++) princ_force[isite][i] = site_force[i][isite+imol*nsites]; } rotate(princ_force, princ_force, nsites, quat+imol, 1, inv); for(i = 0, j = 1, k = 2; i < 3; i++, j=(j+1)%3, k=(k+1)%3) { torq = 0.0; VECTORIZE for(isite = 0; isite < nsites; isite++) torq += site[isite][j]*princ_force[isite][k] -site[isite][k]*princ_force[isite][j]; torque[imol][i] = torq; } } xfree(princ_force); } /****************************************************************************** * make_sites Calculate the atomic site co-ordinates for nmols identical * * molecules from the principal-frame sites, the quaternions and the centre * * of mass co-ordinates. Called once for each molecular species. * ******************************************************************************/ void make_sites(h, c_of_m_s , quat, p_f_sites, framework, site, nmols, nsites) mat_mt h; /* Unit cell matrix h (in) */ vec_mp c_of_m_s, /* Centre of mass co-ords [nmols][3] (in) */ p_f_sites; /* Principal-frame sites [nsites][3] (in) */ real **site; /* Sites [nmols*nsites][3] (out) */ int framework; /* Flag to signal framework structure (in) */ quat_mp quat; /* Quaternions [nmols][4] (in) */ int nmols, /* Number of molecules */ nsites; /* Number of sites on each molecule */ { int imol, isite, i; /* Counters */ vec_mt c_of_m; /* Unscaled centre of mass co-ordinates */ vec_mt *ssite = ralloc(nsites); register double t; mat_mt hinv; double lx = h[0][0], lxy = h[0][1], ly = h[1][1], lxz = h[0][2], lz = h[2][2], lyz = h[1][2]; invert(h,hinv); for(imol = 0; imol < nmols; imol++) { mat_vec_mul(h,c_of_m_s+imol,(vec_mp)c_of_m, 1);/* Get real c-of-m co-ords*/ if(quat) { rotate(p_f_sites,ssite,nsites,quat+imol,1,noinv); for(i = 0; i < 3; i++) for(isite = 0; isite < nsites; isite++) site[i][imol*nsites+isite] = ssite[isite][i] + c_of_m[i]; } else { for(i = 0; i < 3; i++) for(isite = 0; isite < nsites; isite++) site[i][imol*nsites+isite] = p_f_sites[isite][i] + c_of_m[i]; } } if( framework ) /* Apply pbc's to put sites into cell */ for( isite = 0; isite < nmols*nsites; isite++ ) { site[0][isite] -= lx * floor(MATMUL(0,hinv,site,isite) + 0.5); site[0][isite] -= lxy * (t = floor(MATMUL(1,hinv,site,isite) + 0.5)); site[1][isite] -= ly * t; site[0][isite] -= lxz * (t = floor(MATMUL(2,hinv,site,isite) + 0.5)); site[1][isite] -= lyz * t; site[2][isite] -= lz * t; } xfree(ssite); } /****************************************************************************** * newton Apply newton's equation to calculate the acceleration of a * * number of molecules given the force. * ******************************************************************************/ void newton(force, acc, mass, nmols) vec_mp force, /* Centre of mass forces [nmols][3] (in) */ acc; /* Accelerations [nmols][3] (out) */ double mass; /* Molecular mass (in) */ int nmols; /* Number of molecules (in) */ { int imol, i; double rmass = 1.0/mass; for(i=0; i < 3; i++) for(imol = 0; imol < nmols; imol++) { acc[imol][i] = force[imol][i] * rmass; #ifdef DEBUG2 printf("Newton accelerations for %4i mol %4i orient %8.4f \n",imol, i, acc[imol][i]); #endif } } /****************************************************************************** * euler Use the Euler equations and the second-order quaternion method to * * calculate the second derivatives of the molecular quaternions from the * * torques etc. Test for zero moments of inertia is to handle case of linear * * molecule. * ******************************************************************************/ void euler(torque, quat, qdot, qddot, inertia, nmols) vec_mp torque; /* Space frame torques [nmols][3] (in) */ quat_mp quat, qdot, /* Quaternions for this species and d/dt (in) */ qddot; /* Quaternion second derivatives (out) */ vec_mt inertia; /* Principal moments of inertia (in) */ int nmols; /* Number of molecules (in) */ { /* The following two quantities, though vectors, are stored in the last 3 * * components of a quaternion array to allow easy application of the * * quaternion multiplication in the equations of motion. */ quat_mp omega, /* Principal frame angular velocities */ ang_acc=qalloc(nmols); /* Principal frame ang accelerations */ real *qp; register int imol; int i, j, k; register double Iir, Ijk; /* Temporaries for moments of inertia */ if(quat == NULL) return; /* Molecule is point atom or ion - no action */ omega = qddot; /* Use the qddot array as workspace for angular vels */ q_conj_mul(quat, qdot, omega, nmols); vscale(4 * nmols, 2.0, omega[0], 1); for(imol = 0; imol < nmols; imol++) { qp = qdot[imol]; ang_acc[imol][0] = -2.0 * (qp[0]*qp[0] + qp[1]*qp[1] + qp[2]*qp[2] + qp[3]*qp[3]); } for(i=1, j=2, k=3; i<4; i++, j=i%3+1, k=j%3+1) if(inertia[i-1] != 0.0) { Iir = 1.0/inertia[i-1]; Ijk = inertia[j-1] - inertia[k-1]; for(imol = 0; imol < nmols; imol++) ang_acc[imol][i] = Iir * (torque[imol][i-1] + Ijk * omega[imol][j]*omega[imol][k]); } else for(imol = 0; imol < nmols; imol++) ang_acc[imol][i] = 0.0; omega = NULL; /* Omega not needed any more - re use as qddot*/ q_mul(quat, ang_acc, qddot, nmols); vscale(4 * nmols, 0.5, qddot[0], 1); xfree(ang_acc); } /****************************************************************************** * Parinello Calculate the correction to the scaled centre of mass * * accelerations in the Parinello and Rahman zero-stress method. * * Parinello M. and Rahman A. J. Appl. Phys. 52(12), 7182-7190 (1981) * ******************************************************************************/ void parinello(h, h_dot, vel, acc, acc_out, nmols) mat_mt h, /* P and R's unit cell matrix (in) */ h_dot; /* Derivative of h matrix (in) */ vec_mp vel, /* Centre of mass scaled velocities (in) */ acc, acc_out; /* C of M accelerations (in/out) */ int nmols; /* Size of vel and acc/ number molecules (in) */ { mat_mt h_tr, /* Transpose of h */ h_tr_dot, /* Transpose of h_dot */ h_tmp_1, /* Store for intermediate terms */ h_tmp_2, /* Store for intermediate terms */ G, /* h_tr * h (metric tensor) */ G_inv, /* Inverse of G */ G_dot, /* Derivative of G */ G_i_d; /* G_inv * G_dot */ vec_mp acc_corr=ralloc(nmols); /* Correction term to accelerations */ int i, imol; /* Counters */ transpose(h,h_tr); mat_mul(h_tr,h,G); /* We now have the G matrix */ invert(G, G_inv); /* G (-1) done */ transpose(h_dot, h_tr_dot); mat_mul(h_tr_dot, h, h_tmp_1); mat_mul(h_tr, h_dot, h_tmp_2); mat_add(h_tmp_1, h_tmp_2, G_dot); /* G dot now complete */ mat_mul(G_inv, G_dot, G_i_d); /* G_inv * G_dot */ mat_vec_mul(G_i_d, vel, acc_corr, nmols); /* Calculate correction term */ for(i = 0; i < 3; i++) /* Add correction term */ for(imol = 0; imol < nmols; imol++) /* to accelerations */ acc_out[imol][i] = acc[imol][i] - acc_corr[imol][i]; xfree(acc_corr); } /****************************************************************************** * Trans_ke calculate and return the translational kinetic energy * ******************************************************************************/ double trans_ke(h, vel_s, mass, nmols) mat_mt h; /* Unit cell matrix (in) */ vec_mt vel_s[]; /* Scaled c of m velocities (in) */ double mass; /* Mass of a molecule of this species (in) */ int nmols; /* Number of molecules (in) */ { double ke; vec_mp vel = ralloc(nmols); /* Unscaled (real) velocities */ mat_vec_mul(h, vel_s, vel, nmols); /* Calculate unscaled velocities */ ke = vdot(3*nmols, vel[0], 1, vel[0], 1); xfree(vel); return(0.5 * mass * ke); } /****************************************************************************** * rot_ke calculate and return the rotational kinetic energy * ******************************************************************************/ double rot_ke(quat, qdot, inertia, nmols) quat_mt quat[], /* Molecular quaternions (in) */ qdot[]; /* Quaternion derivatives (in) */ vec_mt inertia; /* Principal moments of inertia (in) */ int nmols; /* Number of molecules (in) */ { double ke = 0.0; quat_mp omega_p = qalloc(nmols); /* Principal angular velocities */ int i; q_conj_mul(quat, qdot, omega_p, nmols); /* Calculate angular velocities */ vscale(4 * nmols, 2.0, omega_p[0], 1); /* omega = 2*q~*qdot */ for(i = 0; i < 3; i++) ke += inertia[i] * vdot(nmols, omega_p[0]+i+1, 4, omega_p[0]+i+1, 4); xfree(omega_p); return(0.5 * ke); } /****************************************************************************** * energy_dyad. Calculate the dyadic sum m V V (dyad over V) for zero stress * ******************************************************************************/ void energy_dyad(ke_dyad, h, vels, mass, nmols) mat_mt ke_dyad, /* Dyad is accumulated here (in/out) */ h; /* Unit cell matrix (in) */ vec_mp vels; /* Scaled velocities (in) */ double mass; /* Mass of particles (in) */ int nmols; /* Number of molecules (in) */ { int i, j; /* Counters */ vec_mp vel = ralloc(nmols); /* Real velocities */ mat_vec_mul(h, vels, vel, nmols); /* Calculate unscaled velocities */ for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) { ke_dyad[i][j] += mass * vdot(nmols, vel[0]+i, 3, vel[0]+j, 3); } xfree(vel); } /****************************************************************************** * Rahman Calculate the unit cell matrix accelerations * ******************************************************************************/ void rahman(stress_vir, h, hddot, ke_dyad, press, W, mask) mat_mt stress_vir, /* Stress virial */ h, /* Unit cell matrix */ hddot, /* Unit cell accelerations */ ke_dyad; /* Translational kinetic energy dyad */ double press, /* Externally applied pressure */ W; /* Piston mass parameter */ int mask; /* Mask constrained el's of h matrix */ { double vol = det(h); /* Unit cell volume */ mat_mt stress, /* Stress tensor */ h_tr, /* Transpose of h */ h_tr_inv, /* Inverse of transpose of h */ sigma; /* P & R sigma matrix */ int i, j; /* Counters */ for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) stress[i][j] = (ke_dyad[i][j] + stress_vir[i][j]) / vol; for(i = 0; i < 3; i++) stress[i][i] -= press; /* Subtract applied pressure from diagonal */ transpose(h, h_tr); /* Calculate sigma = vol*h transpose inverse */ invert(h_tr, h_tr_inv); mat_sca_mul(vol, h_tr_inv, sigma); mat_mul(stress, sigma, hddot); /* Calculate unit cell accelerations */ mat_sca_mul(1.0/W, hddot, hddot); /* * Zero unwanted degrees of freedom. Refson PhD Thesis (1986) */ for(i = 0; i < 9; i++) { if( mask & 1 ) hddot[0][i] = 0.0; /* Access as [9] rather than [3][3] */ mask >>= 1; } } /****************************************************************************** * Hoover_tr() function corrects forces to realize thermostat * * main formula: mass * accel = force - alpha * mass * vel * * Function is added by VVMurashov on 22/10/95 * ******************************************************************************/ void hoover_tr(alpha, accel_in, accel_out, vel, nmols) double alpha; /* Thermostat multiplier */ vec_mp vel, /* Centre of mass scaled velocities (in) */ accel_in, /* Array of forces (in/out) */ accel_out; int nmols; /* Size of vel and force/number molecules(in) */ { int i, j; /* Counters */ for(i = 0; i < 3; i++) /* Add correction term */ for(j = 0; j < nmols; j++) /* to accelerations */ accel_out[j][i] = accel_in[j][i] - alpha*vel[j][i]; } /****************************************************************************** * Hoover_rot() function corrects forces to realize thermostat * * main formula: inertia * accel = torque - alpha * inertia * omega * * Function is added by VVMurashov on 22/10/95 * ******************************************************************************/ void hoover_rot(alpha, inertia, force_in, force_out, omega, nmols) double alpha; /* Nose-Hoover multiplier */ vec_mt inertia; /* Inertia vector */ quat_mp omega; /* Angular velocities (in) */ vec_mp force_in, /* Array of forces (in/out) */ force_out; int nmols; /* Size of vel and force/number molecules(in) */ { int i, imols; /* Counters */ for(i = 0; i < 3; i++) /* Add correction term */ for(imols = 0; imols < nmols; imols++) /* to accelerations */ force_out[imols][i] = force_in[imols][i] - alpha*inertia[i]* omega[imols][i+1]; } /***************************************************************************** * Gaussiant() function calculates alpha1 or alpha2 for the Gaussian * * thermostat. Principle formula: alpha = alpha1 / alpha2 * * alpha1 = (SUM force * vel), and alpha2 = (SUM mass * vel^2) * * Function is added by VVMurashov on 3/11/95 * *****************************************************************************/ double gaussiant(vec1, vec2, nmols) vec_mp vec1, /* First array (in) */ vec2; /* Second array (in) */ int nmols; /* Size of arrays [nmols][n] (in) */ { double alpha = 0.0; /* Sum of products (out) */ int i; /* Counters */ for(i = 0; i < 3; i++) alpha += vdot(nmols, vec1[0]+i, 3, vec2[0]+i, 3); return(alpha); } /***************************************************************************** * Gaussianr1() function is the same as above, but allows for dealing with * * quaternion array. Function is added by VVMurashov on 3/11/95 * *****************************************************************************/ double gaussianr1(vec1, vec2, nmols) vec_mp vec1; /* First array (in) */ quat_mp vec2; /* Second array (in) */ int nmols; /* Size of arrays [nmols][n] (in) */ { double alpha = 0.0; /* Sum of products (out) */ int i; /* Counters */ for(i = 0; i < 3; i++) alpha += vdot(nmols, vec1[0]+i, 3, vec2[0]+i+1, 4); return(alpha); } /***************************************************************************** * Gaussianr2() function calculates alpha2 for the Gaussian thermostat * * Principle formula: alpha = alpha1/alpha2 * * where alpha1 = (SUM torque * omega), and alpha2 = (SUM inertia * omega^2) * * Function is added by VVMurashov on 3/11/95 * *****************************************************************************/ double gaussianr2(omega, inertia, nmols) vec_mt inertia; /* Inertia vector */ quat_mp omega; /* Angular velocities (in) */ int nmols; /* Size of vel and force/number molecules(in) */ { double alpha = 0.0; /* Gaussian multiplier (out) */ int i; /* Counters */ for(i = 0; i < 3; i++) alpha += inertia[i] * vdot(nmols, omega[0]+i+1, 4, omega[0]+i+1, 4); return(alpha); } $EOD $! $CREATE alloc.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Alloc Interface functions to dynamic store allocators. * * talloc() Allocate storage and test for success or failure * * arralloc() Allocate rectangular dope-vector (ie using pointers) array * * * * N.B. Portability. * * These functions make some assumptions which are not guaranteed by the * * ANSI standard. * * 1) Various other modules rely on talloc() setting the store to floating- * * point zero. This may not be the same as binary zero. In that case * * the macros "ralloc" etc in "defs.h" will have to be converted into * * functions here which do type-dependant initialisation to zero. * * 2) arralloc() relies on a common format for pointers to different data * * types, and assumes that the representation of a "data" pointer is the * * same as of an integer pointer. (N.B. it can not be used to allocate * * character data). It will not work (and cannot be made to work) on * * machines for which this is false. * ****************************************************************************** * Revision Log * $Log: alloc.c,v $ * Revision 2.8 1994/06/08 13:08:08 keith * New version of array allocator which breaks up requests for DOS. * Now must use specific "afree()" paired with arralloc(). * * Revision 2.6 1994/02/21 16:55:58 keith * Significant restructuring for better portability and * data modularity. * * Added sanity test for 16-bit architectures. * * Revision 2.5 1994/01/18 13:32:09 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:27:37 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:48:54 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.22 93/03/15 14:41:32 keith * Added GPL copyleft notice to permit release and distribution. * N.B. Previous versions were copyright (C) by author and * only licensed by explicit permission. * * Revision 1.21 93/03/12 20:11:49 keith * Fixed mistake of typing word_mt to double -- must be int. * Documented it better. * * Revision 1.20 93/03/09 15:58:16 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.19 93/03/05 15:00:30 keith * Added generic type "word_t" for portability. * Moved include line for security in non-ansi gcc environments * * Revision 1.18 92/06/26 17:02:42 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.17 92/06/05 13:37:02 keith * Conditionally undefed va_dcl for ANSI, stdarg.h case -- * just prevents warning from gcc. * * Revision 1.16 91/10/17 14:22:21 keith * Added debugging code * * Revision 1.15 91/08/19 16:44:11 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * * Revision 1.14 91/03/12 15:42:10 keith * Tidied up typedefs size_mt and include file * Added explicit function declarations. * * Revision 1.13 91/03/07 17:52:32 keith * Macros in support of parallel version for titan added. * * Revision 1.12 90/10/23 20:13:14 keith * Added dummy function call to inhibit vectorization. * This allows use of 'ivdep' compiler options and also * works round certain bugs in cray's scc compiler. * * Revision 1.11 90/08/29 18:21:09 keith * Replaced calloc() call with malloc() and memset(). * On the CRAY XMP calloc() is very inefficient. * * * Revision 1.10 90/08/23 12:46:39 keith * Re-implemented arralloc() using more elegant recursive algorithm. * * Revision 1.9 90/05/16 18:39:36 keith * Renamed own freer from cfree to tfree. * * Revision 1.8 90/05/16 14:19:23 keith * *** empty log message *** * * Revision 1.7 90/05/02 17:51:09 keith * Include of stddef.h added to get size_mt (removed from defs.h) * * Revision 1.6 90/04/25 14:20:16 keith * Modified to allow for machines with word ptr != char ptr. * * Revision 1.5 90/03/26 16:54:46 keith * Added portability warning to header comments. * * Revision 1.4 90/01/15 17:22:25 keith * New version of arralloc() orders memory so that pointers come FIRST. * This means you can simply free() the pointer returned (if l.b. = 0). * * Revision 1.3 89/09/21 14:56:01 keith * Modified talloc() to return null rather than exit if 0 bytes requested. * * Revision 1.2 89/05/24 13:54:26 keith * Changed ifdef's to select on defined(__STDC__) macro * * Revision 1.1 89/04/27 16:52:17 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/alloc.c,v 2.8 1994/06/08 13:08:08 keith stab $"; #endif /*========================== program include files ===========================*/ #include "defs.h" #include "messages.h" /*========================== Library include files ===========================*/ #if defined(ANSI) || defined(__STDC__) # include #else # include #endif #include "stdlib.h" #include "stddef.h" #include "string.h" #ifdef DEBUGX #include #endif #ifdef PARALLEL # ifdef ardent # include # define THREADED # endif #endif #ifndef THREADED # define THREAD_SYS(S) S; #endif #ifdef DBMALLOC typedef size_mt size_t; #include #endif /*========================== External function declarations ==================*/ void inhibit_vectorization(); /* Self-explanatory dummy */ #ifdef DEBUG int malloc_verify(); int malloc_debug(); #endif #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*============================================================================*/ /****************************************************************************** * word_mt * * This is the core of the non-ANSI conformance of "arralloc" and *must* be * * right for portability. Word_mt must be typed to the *smallest* size of * * object to be allocated. On a word-addressed machine it ought to be the * * smallest addressible object. Char is only safe for byte-addressible * * architectures (with the exception of the Cray, which works). Moldy doesn't* * call it for anything smaller than an int, which being the "naturally" sized* * object is the optimum. If pointer representations of any actually required* * object (ie NOT char) do differ then these functions will have to be * * rewritten. * * * * Wide_mt is the widest type for alignment purposes. Try double. * ******************************************************************************/ typedef int word_mt; typedef double wide_mt; /****************************************************************************** * talloc() Call Calloc to allocate memory, test result and stop if failed* ******************************************************************************/ gptr *talloc(n, size, line, file) int n; size_mt size; int line; char *file; { gptr *p; #ifdef ANSI_LIBS /* * Test for malloc arg which would overflow. Since size_mt is long * and size_t may be int this could happen on 16 bit machines. * We can only rely on size_t as parameter to malloc if libs are * ANSI conformant. */ if( (size_mt)(size_t)(n*size) != n*size ) message(NULLI, NULLP, FATAL, NOMEM, line, file, (int)n, (unsigned long)size); #endif THREAD_SYS(p = malloc(n*size)) #ifdef DEBUGX fprintf(stderr,"Alloc: %16s line %3d: %d x %lu bytes (%p to %p)\n", file, line, n, size, p, p+n*size); #endif if(p == NULL && (n*size != 0)) THREAD_SYS(message(NULLI, NULLP, FATAL, NOMEM, line, file, (int)n, (unsigned long)size)) #ifdef DEBUGZ (void)memset((gptr*)p,0x10,n*size); #endif return(p); } /****************************************************************************** * Cfree - synonym to free() * ******************************************************************************/ void tfree(p) gptr *p; { #ifdef DEBUG if( ! malloc_verify() ) message(NULLI, NULLP, FATAL, "Internal Error: Heap corrupt"); #endif THREAD_SYS(free((gptr*)p)) } #ifdef __MSDOS__ union u {struct {int ndim, noffset, len;} b; word_mt * p; wide_mt w;}; #define bsize (sizeof(union u)/sizeof(word_mt*)) #define bwsize (sizeof(union u)/sizeof(word_mt)) void afree(pp) gptr *pp; { word_mt **p = (word_mt**)pp; int i; union u *up = (union u *)(p-bsize); if( up->b.ndim > 1 ) { for( i=0; i < up->b.len; i++) afree((gptr*)(p[i] + up->b.noffset)); } tfree((gptr*)(p-bsize)); } #else void afree(p) gptr *p; { tfree(p); } #endif /****************************************************************************** * arralloc. Allocate a psuedo array of any dimensionality and type with * * specified lower and upper bounds for each dimension. Each dimension is * * an array of pointers, and the actual data is laid out in standard 'c' * * fashion ie last index varies most rapidly. All storage is got in one * * block, and so can be freed in one go. * * array = (double*) arralloc(sizeof(double), 3, 0, 10, -10, 10, 0, 5); * * xfree(array); * * (N.B. if lower bound of 1st dimension != 0 then free array+l.b. * ******************************************************************************/ #ifdef __MSDOS__ word_mt **subarray(size, ndim, len, ap) size_mt size; int ndim, len; va_list ap; { word_mt **p; word_mt *d; union u *up; int blen, i, lb = va_arg(ap, int), ub = va_arg(ap,int); if( ndim > 1 ) { #ifdef DEBUGY fprintf(stderr,"[%d...%d]", lb, ub); #endif blen = len+bsize; p = (word_mt**)talloc(blen, (size_mt)sizeof(word_mt *), __LINE__, __FILE__); up = (union u *)p; p += bsize; up->b.ndim = ndim; up->b.len = len; up->b.noffset = lb*(ndim>2?sizeof(word_mt*):size)/sizeof(word_mt); for( i=0; ib.noffset; return p; } else { blen = len*(size/sizeof(word_mt))+bwsize; d = (word_mt*)talloc(blen, (size_mt)sizeof(word_mt), __LINE__, __FILE__); up = (union u *)d; d += bwsize; up->b.ndim = ndim; return (word_mt **)d; } } #if defined(ANSI) || defined(__STDC__) # undef va_alist # define va_alist size_mt size, int ndim, ... # ifdef va_dcl # undef va_dcl # endif # define va_dcl /* */ #endif /*VARARGS*/ gptr *arralloc(va_alist) va_dcl { va_list ap; word_mt *p; int lb, ub; #if defined(ANSI) || defined(__STDC__) va_start(ap, ndim); #else size_mt size; /* size of array element */ int ndim; /* Number of dimensions */ va_start(ap); size = va_arg(ap, size_mt); ndim = va_arg(ap, int); #endif #ifdef DEBUGY fprintf(stderr,"%dD array of %lu byte elements:", ndim, size); #endif if( size % sizeof(word_mt) != 0 ) /* Code only works for 'word' objects */ message(NULLI, NULLP, FATAL, WDPTR, size); lb = va_arg(ap, int); ub = va_arg(ap, int); #ifdef DEBUGY fprintf(stderr,"[%d...%d]", lb, ub); #endif p=(word_mt*)subarray(size, ndim, ub-lb+1, ap) - lb*(ndim>1?sizeof(word_mt*):size)/sizeof(word_mt); #ifdef DEBUGY putc('\n',stderr); #endif va_end(ap); return (gptr*)p; } #else #define CSA(a) ((char*)(a)) #define ALIGN(a,base,b) ((word_mt*)(CSA(base)+((CSA(a)-CSA(base))+(b)-1)/(b)*(b) )) static void subarray(size, ndim, prdim, pp, qq, base, ap) size_mt size; int ndim; long prdim; word_mt ***pp, **qq, *base; va_list ap; { word_mt *dd = ALIGN(qq,base,size), **dpp = (word_mt**)pp; int i, lb = va_arg(ap, int), dim = va_arg(ap, int) - lb + 1; if(ndim > 0) /* General case - set up pointers to pointers */ { for( i = 0; i < prdim; i++) { inhibit_vectorization(); /* Circumvent bug in cray compiler v4.1 */ pp[i] = qq + i*dim - lb; } subarray(size, ndim-1, prdim*dim, (word_mt***)qq, qq+prdim*dim, base, ap); } else /* Last recursion - set up pointers to data */ for( i = 0; i < prdim; i++) dpp[i] = dd + (i*dim - lb)*size/sizeof(word_mt); } #if defined(ANSI) || defined(__STDC__) # undef va_alist # define va_alist size_mt size, int ndim, ... # ifdef va_dcl # undef va_dcl # endif # define va_dcl /* */ #endif /*VARARGS*/ gptr *arralloc(va_alist) va_dcl { va_list ap, ap2; word_mt **p, **start; int lb, ub, idim; long n_ptr = 0, n_data = 1; #if defined(ANSI) || defined(__STDC__) va_start(ap, ndim); #else size_mt size; /* size of array element */ int ndim; /* Number of dimensions */ va_start(ap); size = va_arg(ap, size_mt); ndim = va_arg(ap, int); #endif #ifdef DEBUGY fprintf(stderr,"%dD array of %lu byte elements:", ndim, size); #endif if( size % sizeof(word_mt) != 0 ) /* Code only works for 'word' objects */ message(NULLI, NULLP, FATAL, WDPTR, size); /* * Cycle over dims, checking bounds and accumulate # pointers & data items. */ ap2 = ap; /* Save ap for later use by subarray() */ for(idim = 0; idim < ndim; idim++) { lb = va_arg(ap, int); ub = va_arg(ap,int); #ifdef DEBUGY fprintf(stderr,"[%d...%d]", lb, ub); #endif if(ub < lb) message(NULLI, NULLP, FATAL, INSIDE, lb, ub); n_data *= ub - lb + 1; if( idim < ndim-1 ) n_ptr += n_data; } #ifdef DEBUGY putc('\n',stderr); #endif /* * Allocate space for pointers and data. */ #ifdef DEBUGY { size_mt mallen=(n_data+1)*size+n_ptr*sizeof(word_mt**); fprintf(stderr,"Calling talloc(%lu)....\n", mallen); } #endif start = (word_mt**)talloc(1, (size_mt)((n_data+1)*size+n_ptr*sizeof(word_mt**)), __LINE__, __FILE__); /* * Set up pointers to form dope-vector array. */ subarray(size, ndim-1, 1L, &p, start, (word_mt*)start, ap2); va_end(ap); return (gptr*)p; } #endif $EOD $! $CREATE ansi.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993, 1995 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Ansi This file contains implementations of some ANSI C library * * functions for machines which don't have them. * ******************************************************************************/ /*========================== program include files ===========================*/ #include "defs.h" #ifndef _POSIX_SOURCE # define _POSIX_SOURCE #endif /*========================== Library include files ===========================*/ #if defined(ANSI) || defined(__STDC__) #include #else #include #endif #include "string.h" #include "stddef.h" #include "stdlib.h" #include #ifndef ANSI_LIBS /****************************************************************************** * strerror for pre-ANSI unix machines * ******************************************************************************/ #if defined(unix) || defined(__unix__) char *strerror(i) int i; { extern int sys_nerr; extern char *sys_errlist[]; if( i >= 0 && i < sys_nerr ) return sys_errlist[i]; else return "invalid error code"; } #endif /****************************************************************************** * raise for pre-ANSI unix machines * ******************************************************************************/ #if defined(unix) || defined(__unix__) int raise(sig) int sig; { extern int getpid(); extern int kill(); return(kill(getpid(), sig)); } #endif /****************************************************************************** * strstr replacement for pre-ANSI machines which don't have it. * ******************************************************************************/ char *strstr(cs, ct) CONST char *cs, *ct; { int i, sl = strlen(cs)-strlen(ct); for(i = 0; i <= sl; i++) if( !strcmp(cs+i,ct) ) return (char*)cs+i; return 0; } /****************************************************************************** * mem{cpy,set} and strchr replacement for BSD machines which don't have them.* ******************************************************************************/ #ifdef BSD char *strchr(s, c) CONST char *s; int c; { extern char *index(); return index(s,c); } gptr *memcpy(s1, s2, n) gptr *s1, *s2; int n; { int bcopy(); (void)bcopy((char *)s2, (char *)s1, n); return(s1); } gptr *memset(s, c, n) gptr *s; int c, n; { void bzero(); char *sp; if( c == 0 ) (void)bzero(s, n); else { for( sp=s; sp < (char*)s+n; sp++) *sp = c; } return(s); } #endif /****************************************************************************** * remove. delete (unlink) a file. (ANSI replacement) * ******************************************************************************/ #if defined(unix) || defined(__unix__) int remove(file) CONST char *file; { int unlink(); return (unlink(file)); } #endif /****************************************************************************** * raise for VMS. Earlier VAX/VMS libs don't it have it. Assume that any vsn* * late enough to have __DECC is OK. Don't believe ANSI_LIBS -- kludge. * ******************************************************************************/ #if defined(vms) && ! defined(__DECC) int raise(sig) int sig; { extern int getpid(); extern int kill(); return(kill(getpid(), sig)); } #endif /****************************************************************************** * vprintf for those machines which don't have it * ******************************************************************************/ #ifndef HAVE_VPRINTF #ifdef HAVE_DOPRNT int vprintf (fmt, args) char *fmt; va_list args; { return(_doprnt(fmt, args, stdout)); } #else /* No _doprnt or equivalent */ #include int vprintf (format, ap) CONST char *format; va_list ap; { int pos, charsout, fpos, error, modflag; char fmt[1024], temps[1024]; char ch; pos = charsout = error = 0; while (format[pos] != 0) { modflag = 0; if (format[pos] != '%') { putchar (format[pos++]); } else { fmt[0] = '%'; pos++; fpos = 1; while (format[pos] != 0 && !islower (format[pos]) && format[pos] != '%') fmt[fpos++] = format[pos++]; if( format[pos] == 'l' || format[pos] == 'L' || format[pos] == 'h') { modflag = format[pos]; fmt[fpos++] = format[pos++]; } if (format[pos] == 0) { /* error in format string */ error++; } ch = fmt[fpos++] = format[pos++]; fmt[fpos] = 0; #ifdef DEBUG printf ("Format is \"%s\"\n", fmt); #endif /* Now fmt contains the format for this part of the output and ch contains the conversion code. */ temps[0] = 0; switch (ch) { case 'n': *va_arg (ap, int *) = charsout; break; case 's': sprintf (temps, fmt, va_arg (ap, char *)); break; case 'p': sprintf (temps, fmt, va_arg (ap, void *)); break; case 'c': case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': if( modflag == 'l') sprintf (temps, fmt, va_arg (ap, long)); else sprintf (temps, fmt, va_arg (ap, int)); break; case 'e': case 'E': case 'f': case 'g': case 'G': sprintf (temps, fmt, va_arg (ap, double)); break; default: (void)strcpy (temps, fmt); error++; } #ifdef DEBUG printf ("temps is \"%s\"\n", temps); #endif fputs (temps, stdout); charsout += strlen (temps); #ifdef DEBUG printf ("still to interpret \"%s\"\n", (char *) &format[pos]); #endif } } if (error) return (-1); return (charsout); } #endif /* HAVE_DOPRNT */ #endif /* Vprintf needed */ #endif $EOD $! $CREATE auxil.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Aux This file contains auxilliary service functions and (almost) * * all machine-dependant stuff. The ANSI standard interface is * * used as much as possible for library functions; if a machine * * is missing something an ANSI interface routine is supplied. * ****************************************************************************** * Revision Log * $Log: auxil.c,v $ * Revision 2.10 1996/11/18 15:58:48 keith * Revised Cray macro tests to use _CRAY1 to select vector architecture. * Use "scalar" versions rather than SCILIB functions on Cray T3D * to avoid parallel divergence bug. SCILIB can return different * results on different processors which is unacceptable. * Added optimised "sum()". * Removed "gatheri()" and "wheneq()" as they are no longer needed. * * Revision 2.9 1996/03/06 15:24:46 keith * Modified CRAY defs to pick up SCILIB stuff on MPP archs. * * Protected "precision()" against very clever optimisers keeping * eps in register - caused failure on Intels w/ long fp regs. * * Revision 2.8 1995/12/05 20:55:10 keith * Separated ANSI replacement routines from Auxil.c into Ansi.c * Removed all COS functionality. * * Revision 2.7 1994/06/08 13:09:00 keith * Added "zero_dbls()" function. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Moved declaration of "match" structure from input.c * Moved a few sanity tests & modifications of "control" * members to here from other modules. * * Changed size_t to own typedef size_mt == ulong. * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Renamed Aux.c to Auxil.c for DOS (ugh). * Revamped cpu time interface to use POSIX "times()" whenever * available - including for BSD systems - and got rid of * "getrusage()" version entirely. * Thus eliminating various marginally portable header * kludges. * * Added memset() emulation for *really* old BSD systems. * * Revision 2.5 94/01/29 11:09:53 keith * Fixed bug in "strstr()" replacement for non-ANSI libraries * * Revision 2.4 94/01/18 13:23:04 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.3 93/10/28 10:27:38 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.2 93/09/06 14:43:28 keith * Fixed portability problems/bugs in XDR code. * * Revision 2.0 93/03/15 14:48:56 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.7.1.32 93/03/15 14:41:33 keith * Added GPL copyleft notice to permit release and distribution. * N.B. Previous versions were copyright (C) by author and * only licensed by explicit permission. * * Revision 1.7.1.31 93/03/12 12:19:22 keith * Reorganized defines to recognise all ANSI (__type__) forms. * Moved spxpy() from aux.c to force.c and force_parallel.c * * Revision 1.7.1.30 93/03/09 15:58:18 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.7.1.29 93/03/05 15:02:58 keith * Now is POSIX - safe wrt declaration of times(). * * Revision 1.7.1.28 92/09/22 14:48:22 keith * Tidied up calls to improve "lint" rating. * * Revision 1.7.1.27 92/06/26 17:02:46 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.7.1.26 92/06/19 17:28:40 keith * Added faster version of "search_lt" for Titan. * * Revision 1.7.1.25 92/06/12 12:55:41 keith * Mods to make it work on VMS again. Ugh. * * Revision 1.7.1.24 92/06/11 20:31:04 keith * Added file locking against multiple runs using same dump or backup files. * * Revision 1.7.1.23 91/11/26 10:24:31 keith * Modified timing routines to work under POSIX. * Replaced saxpy() with sxpy() -- UNVECTORIZED as indices may be repeated. * * Revision 1.7.1.22 91/08/17 16:24:15 keith * Added strerror() for pre-ANSI unix systems * Updated #defines with __unix__ symbol and protection of sys/time.h for convex. * * Revision 1.7.1.21 91/08/15 18:11:44 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.7.1.20 91/05/29 10:58:00 keith * Modified wheneq to generate better code on Stardent TITAN * Added #ifdefe'd "const" qualifier in "remove" for ANSI compilers * without ANSI libraries. * * Revision 1.7.1.19 91/03/12 15:42:12 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.7.1.18 91/02/07 16:48:36 keith * Modified BLAS functions to vectorise better undar Stardent Titan compiler. * * Revision 1.7.1.17 90/10/23 20:10:47 keith * Added inhibit_vectorization() dummy function. * * Revision 1.7.1.16 90/10/18 17:24:26 keith * Added extra arg to gather() for (conditional) bounds check. * C.f. force.c 1.8.1.17. * * Revision 1.7.1.15 90/09/28 13:29:08 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.7.1.14 90/08/30 16:00:21 keith * Replaced malloc() calls with calls to own allocator 'aalloc()' * Ifdefed out 'remove' and 'memset/memcpy' if ANSI_LIBS is set. * * Revision 1.7.1.13 90/05/16 18:39:46 keith * Renamed own freer from cfree to tfree. * * Revision 1.7.1.12 90/05/15 19:00:16 keith * Incorporate new ANSI CLOCKDS_PER_SEC instead of CLK_TCK. * * Revision 1.7.1.11 90/05/02 18:15:12 keith * Tidied up include files, added "time.h". * * Revision 1.7.1.10 90/04/16 13:04:08 keith * Improved sysV version of rt_clock() by using result of times(). * Coded zero-real explicitly for ANSI compliance. * Added strchr() for BSD systems (calls index()). * * Revision 1.7.1.9 90/03/27 17:34:46 keith * Moved selection of own `vprintf into defs.h - * Define symbol HAVE_VPRINTF if not needed. (Also HAVE_DOPRNT). * * Revision 1.7.1.8 90/03/09 17:32:35 keith * Modified preprocessor conditionals to handle unicos. * * Revision 1.7.1.7 90/01/02 19:01:03 keith * Rewrote loops to go from zero to n again - substantially faster on Stellar * * Revision 1.7.1.6 89/12/18 17:50:23 keith * Sum() tests for special case of stride=1 for efficiency. * Rt_clock() added (returns time in seconds). * * Revision 1.7.1.5 89/11/21 15:51:10 keith * Added purge() for cray and fixed replace() for standard case. * * Revision 1.7.1.4 89/10/25 10:05:24 keith * Added spaxpy() in support of change in force.c. * * Revision 1.7.1.3 89/09/20 17:08:26 keith * Added wheneq() and gatheri() to veclib calls for convex. * Modified search_lt() for cray to return zero if called with n=0. * * Revision 1.7.1.2 89/09/18 17:39:37 keith * Fixed error in vprintf which used puts() instead of fputs() giving extra \n. * Made 'eps' static in precision() to give correct answer on subsequent calls. * * Revision 1.7.1.1 89/08/25 15:21:36 keith * Mods to add framework structures to simulation model * * Revision 1.7 89/08/15 18:29:58 keith * Fixed bug which assumed clock tick for Sys V machines = 1/60s * * Revision 1.6 89/08/10 17:29:42 keith * Fixed search_lt() to return correct result for non-unit stride. * * Revision 1.5 89/06/14 14:14:44 keith * Fixed ifdef's for CRAY to handle case of unicos. * Fixed mistake in #define's for typedef clash in sysV CPU(). * * Revision 1.4 89/06/09 17:01:53 keith * Made zero_real() call memset/bzero * Fixed vprintf() for machines which use _doprnt() * Added alliant vector functions * Modified cpu() to avoid typedef clash on Stellar GS 1000 * Rewrote 'scalar' versions of vector functions to allow vectorisation. * * Revision 1.3 89/06/01 21:23:04 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.2 89/06/01 18:00:42 keith * Moved `vadd()' from aux.c to force.c for ease of vectorisation. * Now no need to compile aux.c with vectorisation. * * Revision 1.1 89/04/27 15:01:14 keith * Initial revision * * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/auxil.c,v 2.10 1996/11/18 15:58:48 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" #ifndef _POSIX_SOURCE # define _POSIX_SOURCE #endif /*========================== Library include files ===========================*/ #if defined(ANSI) || defined(__STDC__) #include #else #include #endif #include #include #include "string.h" #include "stddef.h" #include "stdlib.h" #include "time.h" #include /*================= System Library include files - unix only ================*/ #if defined(unix) || defined(__unix__) /* * We must protect the inclusion of . */ #ifndef SYS_TYPES_INCLUDED #define SYS_TYPES_INCLUDED # include #endif #include #include #ifndef CLK_TCK # include # ifdef HZ # define CLK_TCK HZ # else # define CLK_TCK 60 /* Really old unices defined 60. May be wrong.*/ # endif #endif #endif /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ /*============================================================================*/ /****************************************************************************** * Vector routines - special cases for cray and convex to call vectorised * * library versions. Other machines do it the hard way. * * CRAY versions. * ******************************************************************************/ #if defined(_CRAY1) #define VECTS_DEFINED double vdot(n,x,ix,y,iy) int n; real *x, *y; int ix, iy; { double SDOT(); return(SDOT(&n, x, &ix, y, &iy)); } double sum(n,x,ix) int n; real *x; int ix; { double SSUM(); return(SSUM(&n, x, &ix)); } void vscale(n,s,x,ix) int n; double s; real *x; int ix; { void SSCAL(); SSCAL(&n, &s, x, &ix); } int search_lt(n, x, ix, s) int n; real x[]; int ix; double s; { int ISRCHFLT(); if( n <= 0 ) return(0); return( ISRCHFLT(&n, x, &ix, &s) - 1); } void gather(n, a, b, ix, lim) int n; real a[], b[]; int ix[]; { void GATHER(); GATHER(&n, a, b+1, ix); } #endif /****************************************************************************** * Vector routines - CONVEX versions. The calls are to VECLIB functions. * ******************************************************************************/ #if defined(__convexc__) #define VECTS_DEFINED #define SINGLE (sizeof(real) == sizeof(float)) double vdot(n,x,ix,y,iy) int n; real *x, *y; int ix, iy; { double ddot_(); float sdot_(); if(SINGLE) return(sdot_(&n, x, &ix, y, &iy)); else return(ddot_(&n, x, &ix, y, &iy)); } double sum(n,x,ix) int n; real *x; int ix; { double dsum_(); float ssum_(); if(SINGLE) return(ssum_(&n, x, &ix)); else return(dsum_(&n, x, &ix)); } void vscale(n,s,x,ix) int n; double s; real *x; int ix; { float s2 = s; void dscal_(), sscal_(); if(SINGLE) sscal_(&n, &s2, x, &ix); else dscal_(&n, &s, x, &ix); } int search_lt(n, x, ix, s) int n; real x[]; int ix; double s; { float s2 = s; int i, idsvlt_(), issvlt_(); if(SINGLE) return( (i = issvlt_(&n, x, &ix, &s2)) ? i - 1 : n); else return( (i = idsvlt_(&n, x, &ix, &s)) ? i - 1 : n); } /*ARGSUSED*/ void gather(n, a, b, ix, lim) int n; real a[], b[]; int ix[]; { void dgthr_(), sgthr_(); if(SINGLE) sgthr_(&n, b+1, a, ix); else dgthr_(&n, b+1, a, ix); } #endif /****************************************************************************** * alliant versions - with cray librarries * ******************************************************************************/ #if defined(alliant) #define VECTS_DEFINED double vdot(n,x,ix,y,iy) int n; real *x, *y; int ix, iy; { double sdot_(); return(sdot_(&n, x, &ix, y, &iy)); } double sum(n,x,ix) int n; real *x; int ix; { double ssum_(); return(ssum_(&n, x, &ix)); } void vscale(n,s,x,ix) int n; double s; real *x; int ix; { void sscal_(); sscal_(&n, &s, x, &ix); } int search_lt(n, x, ix, s) int n; real x[]; int ix; double s; { int isrchflt_(); return( isrchflt_(&n, x, &ix, &s) - 1); } /*ARGSUSED*/ void gather(n, a, b, ix, lim) int n; real a[], b[]; int ix[]; { void gather_(); gather_(&n, a, b+1, ix); } #endif /****************************************************************************** * Vector handling functions - C versions. * ******************************************************************************/ #ifndef VECTS_DEFINED double vdot(n,x,ix,y,iy) int n; real x[], y[]; int ix, iy; { register double dot=0.0; register int i, j; if( ix == iy && ix == 1) { VECTORIZE for(i = 0; i < n; i++) dot += x[i] * y[i]; } else { VECTORIZE for(i = j = 0; i != n*ix; i += ix) { dot += x[i] * y[j]; j += iy; } } return(dot); } double sum(n,x,ix) register int n; register double x[]; register int ix; { register double sa=0.0,sb=0.0,sc=0.0,sd=0.0,s1=0.0,s2=0.0,s3=0.0,s4=0.0; int i; if( ix == 1 ) { for( i = 0; i < n-3; i+=4) { s1 += sa; sa = x[i]; s2 += sb; sb = x[i+1]; s3 += sc; sc = x[i+2]; s4 += sd; sd = x[i+3]; } s1 += sa; s2 += sb; s3 += sc; s4 += sd; for( ; i < n; i++) s1 += x[i]; } else { for(i = 0; i != n*ix; i += ix) s1 += x[i]; } return(s1+s2+s3+s4); } void vscale(n,s,x,ix) register int n; register double s; register real x[]; register int ix; { int i; VECTORIZE for(i = 0; i != n*ix; i += ix) x[i] *= s; } /* * Two alternatives for search_lt. The first can vectorize using an * IDFMIN type function, the second using an isrchtl. They don't * do QUITE the same thing; the first returns the index of the * smallest value,, the second that of the first one less than s. */ #ifdef ardent int search_lt(n, x, ix, s) int n; real x[]; int ix; double s; { int i, im=n*ix; double min = x[0]; VECTORIZE for( i = 0; i != n*ix; i += ix ) if( x[i] < min ) { im = i; min = x[i]; } if ( min < s ) return(im/ix); else return n; } #else int search_lt(n, x, ix, s) int n; real x[]; int ix; double s; { int i, im=n*ix; VECTORIZE for( i = (n-1)*ix; i >= 0; i -= ix ) if( x[i] < s ) im = i; return(im/ix); } #endif /*ARGSUSED*/ void gather(n, a, b, ix, lim) int n, lim; real a[], b[]; int ix[]; { int i; VECTORIZE for( i = 0; i < n; i++) { #ifdef DEBUG if(ix[i] < 0 || ix[i] >= lim ) message(0,0,2, "Gather index out of bounds %d %d\n", i, ix[i]); #endif a[i] = b[ix[i]]; } } #endif /****************************************************************************** * random number generators. Note they assume 'unsigned' of at least 32 bits * ******************************************************************************/ #define im 1771875L #define ia 2416L #define ic 374441L static unsigned long jran = 1; void smdrand(seed) unsigned long seed; { jran = seed; } double mdrand() { jran = (jran*ia + ic) % im; return (double)jran/(double)im; } /****************************************************************************** * Precision. Return smallest eps s.t. 1.0+eps > 1 * ******************************************************************************/ double precision() { static int first=1; static double eps = 0.5; double VOLATILE eps2, *eps1 = &eps2; /* Use pointer to force store */ double VOLATILE junk, *ptr = &junk; if(first) { first = 0; do { eps = eps * 0.5; *eps1 = 1.0 + eps; *ptr = 1.0; /* This prevents optimization of *eps1 */ } while(*eps1 > 1.0); eps *= 2.0; } return(eps); } /****************************************************************************** * cpu. Return (double) the current cpu time in seconds. * * rt_clock(). Return elapsed time in s. * ******************************************************************************/ #if defined(unix) || defined(__unix__) double cpu() { struct tms buf; (void)times(&buf); return (buf.tms_utime + buf.tms_stime)/(double)CLK_TCK; } /* * The BSD version way to get the rt clock is via gettimeofday. But * some systems , noticably Ultrix, DON'T include the * necessary struct definitions if _POSIX_SOURCE is defined!. Aargh. * However in that case we can rely on POSIX behaviour of times - * (ie it's return value) - so the alternative rt_clock ought to * work. The test is for the macro associated with the "timezone" * struct definition. */ #if defined(BSD) && defined(DST_NONE) double rt_clock() { int gettimeofday(); struct timeval tp; (void)gettimeofday(&tp,(struct timezone *)0); return(tp.tv_sec + tp.tv_usec*0.000001); } #else /* System V or POSIX. */ double rt_clock() { struct tms buf; return times(&buf)/(double)CLK_TCK; } #endif /* USG or BSG */ #else /* Not Unix */ #if !defined(CLOCKS_PER_SEC) && defined(CLK_TCK) # define CLOCKS_PER_SEC CLK_TCK #endif double cpu() { return((double)clock() / CLOCKS_PER_SEC); } double rt_clock() { return time((time_t *)0); } #endif /****************************************************************************** * cctime() Return ctime() but without the newline * ******************************************************************************/ char *cctime(timeloc) time_mt *timeloc; { time_t loc = *timeloc; char *p = ctime(&loc); *strchr(p, '\n') = '\0'; return(p); } /****************************************************************************** * atime. Return a pointer to the time and date string * ******************************************************************************/ char *atime() { time_mt t = time((time_t*)0); return(cctime(&t)); } /****************************************************************************** * Zero real. Set array to floating-point zero. * ******************************************************************************/ void zero_real(r,n) real r[]; int n; { int i; VECTORIZE for(i = 0; i < n; i++) r[i] = 0.0; } void zero_double(r,n) double r[]; int n; { int i; VECTORIZE for(i = 0; i < n; i++) r[i] = 0.0; } void zero_dbls(r,n) double r[]; size_mt n; { long i; VECTORIZE for(i = 0; i < n; i++) r[i] = 0.0; } /****************************************************************************** * replace - replace file1 by file2, renaming or overwriting * ******************************************************************************/ #if defined(unix) || defined(__unix__) int replace(file1, file2) char *file1, *file2; { int f; char *backup = aalloc(strlen(file2)+2, char); (void)strcat(strcpy(backup, file2), "%"); f = rename(file2, backup); /* Backup old version - ignore failure*/ f = rename(file1, file2); /* Rename old version to new */ xfree(backup); return(f); } # else int replace(file1, file2) char *file1, *file2; { int f; int rename(); f = rename(file1, file2); if(f != 0 && remove(file2) == 0) /* If already exists try remove target*/ f = rename(file1, file2); return(f); } #endif /****************************************************************************** * Purge Remove 1 old version of a file. (Do nothing if O/S has no versions)* ******************************************************************************/ #ifdef vms void purge(file) char *file; { char *name = aalloc(strlen(file)+4,char); strcpy(name, file); if( strchr(name, ';') == NULL) (void)remove(strcat(name,";-1")); tfree(name); } #else /* VMS */ # if defined(unix) || defined(__unix__) void purge(file) char *file; { int unlink(); char *name = aalloc(strlen(file)+2,char); (void)strcat(strcpy(name, file), "%"); (void)unlink(name); xfree(name); } # else /*ARGSUSED*/ void purge(file) char *file; { } # endif #endif /* VMS */ /****************************************************************************** * err_fn error function. See Abramowitz & Stegun p299. * ******************************************************************************/ #define E1 0.254829592 #define E2 -0.284496736 #define E3 1.421413741 #define E4 -1.453152027 #define E5 1.061405429 #define PP 0.3275911 #define POLY5(t) ((t)*(E1 + (t)*(E2 + (t)*(E3 + (t)*(E4 + (t)*E5))))) double err_fn(x) double x; { double t = 1.0/(1.0 + PP * x); if ( x >= 0.0 ) return( 1.0 - POLY5(t) * exp(-x*x) ); else return( -err_fn(-x) ); } /****************************************************************************** * inhibit_vectorization(). Self explanatory dummy function * ******************************************************************************/ void inhibit_vectorization() { } $EOD $! $CREATE beeman.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Beeman - Routines to implement the modified Beeman algorithm for * * stepping the co-ordinates in a MD simulation including rigid * * molecules * * Original algorithm - D. Beeman J. Comp. Phys 20, 131-139 (1976) * * Modified with velocity predictor to handle velocity-dependant forces * * - K. Refson Physica 131B 256-266 (1985) * * * * External routines: step_1(system), step_2(system), beeman_2() * * External references: none * * External data: none * * External data references: control * * * * Note: The routines beeman_1, beeman_2 and predict treat their arguments * * as one dimensional arrays for simplicity. Thus the 'number' * * argument is 3 (for c_of_m) or 4 (for quaternions) times the number* * of particles. This may cause 'consistency' messages from lint. * ****************************************************************************** * Revision Log * $Log: beeman.c,v $ * Revision 2.9 1996/08/14 16:23:24 keith * Fixed error in thermoststat implementation and integration. * * Revision 2.8 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.7 1994/06/08 13:09:29 keith * Protected against possible bus error for systems with no * rotational freedom by making all references to "quat" etc conditional * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Revision 2.5 1994/01/18 13:32:13 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:27:45 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:48:58 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.5 93/03/15 14:41:37 keith * Added GPL copyleft notice to permit release and distribution. * N.B. Previous versions were copyright (C) by author and * only licensed by explicit permission. * * Revision 1.4 93/03/09 15:58:21 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.3 91/08/15 18:11:47 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.2 89/10/24 17:18:37 keith * Modified pbc algorithm to use floor() library function. * Now works with non-orthorhombic cell. * * Revision 1.1 89/04/20 16:00:35 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/beeman.c,v 2.9 1996/08/14 16:23:24 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ /*========================== Macros ==========================================*/ #define TOLERANCE 1.0e-4 /*============================================================================*/ /****************************************************************************** * Normalise the new quaternions * ******************************************************************************/ static void normalise(quat,n) int n; /* Number of quaternions (in) */ quat_mp quat; /* Quaternions (update) */ { register int i, j; register double norm; for(i=0; i TOLERANCE) message(NULLI, NULLP, FATAL, QNORM2, i, quat[i][0],quat[i][1],quat[i][2],quat[i][3]); for(j=0; j<4; j++) quat[i][j] /= norm; } } /****************************************************************************** * Constrain the quaternion derivatives * ******************************************************************************/ void constrain(quat, qdot ,n) int n; /* Number of quaternions (in) */ quat_mp quat; /* Quaternions (in) */ quat_mp qdot; /* Quaternion derivatives (update) */ { register int i, j; register double delta; for(i=0; i TOLERANCE) message(NULLI, NULLP, FATAL, QCONST, i, delta); for(j=0; j<4; j++) qdot[i][j] -= delta * quat[i][j]; } } /****************************************************************************** * Apply periodic boundary conditions to put particles back in MD box * ******************************************************************************/ static void escape(c_of_m, nmols) int nmols; /* First dimension of c-of-m */ vec_mp c_of_m; /* Centre of mass co-ordinates (updat) */ { int imol; /* Molecule counter */ for(imol = 0; imol < nmols; imol++) { c_of_m[imol][0] -= floor(c_of_m[imol][0] + 0.5); c_of_m[imol][1] -= floor(c_of_m[imol][1] + 0.5); c_of_m[imol][2] -= floor(c_of_m[imol][2] + 0.5); } } /****************************************************************************** * Step co-ordinates as first (P(r)) stage of Beeman algorithm * ******************************************************************************/ static void beeman_1(x, xdot, xddot, xddoto, n) int n; /* Length of vectors (in) */ real x[], /* Co-ordinate array (update) */ xdot[], /* First derivatives (in) */ xddot[], /* Accelerations (in) */ xddoto[]; /* Old accelerations (in) */ { register int i; register real step = control.step, step_sq = step * step / 6.0; for(i=0; ic_of_m[0],sys->vel[0],sys->acc[0],sys->acco[0], 3*sys->nmols); escape(sys->c_of_m, sys->nmols); if( sys->nmols_r > 0 ) { beeman_1(sys->quat[0],sys->qdot[0],sys->qddot[0],sys->qddoto[0], 4*sys->nmols_r); normalise(sys->quat, sys->nmols_r); } if(control.const_pressure) beeman_1(sys->h[0], sys->hdot[0], sys->hddot[0], sys->hddoto[0], 9); predict(sys->vel[0], sys->velp[0], sys->acc[0], sys->acco[0], sys->accvo[0], 3*sys->nmols); if( sys->nmols_r > 0 ) { predict(sys->qdot[0], sys->qdotp[0], sys->qddot[0], sys->qddoto[0], sys->qddotvo[0], 4*sys->nmols_r); constrain(sys->quat, sys->qdotp, sys->nmols_r); if (control.const_temp) predict(sys->ra, sys->rap, sys->radot, sys->radoto, sys->radotvo, sys->nspecies); } if(control.const_pressure) predict(sys->h[0], sys->hdotp[0], sys->hdot[0], sys->hddoto[0], sys->hddotvo[0], 9); if (control.const_temp) predict(sys->ta, sys->tap, sys->tadot, sys->tadoto, sys->tadotvo, sys->nspecies); #ifdef DEBUG3 printf("Step1\n"); #endif } /****************************************************************************** * Apply second stage of modified beeman algorithm to the whole system * * Step the centre of mass velocities, and the derivatives of the * * quaternions and Parinello & Rahman h matrix (if const pressure * * simulation), and predict the corresponding velocities. * ******************************************************************************/ void step_2(sys) system_mp sys; /* pointer to whole-system record */ { beeman_2(sys->vel[0], sys->vel[0], sys->acc[0], sys->acco[0],sys->accvo[0], 3*sys->nmols); if( sys->nmols_r > 0 ) { beeman_2(sys->qdot[0], sys->qdot[0], sys->qddot[0], sys->qddoto[0], sys->qddotvo[0], 4*sys->nmols_r); constrain(sys->quat, sys->qdot, sys->nmols_r); if (control.const_temp == 1) beeman_2(sys->ra, sys->ra, sys->radot, sys->radoto, sys->radotvo, sys->nspecies); } if(control.const_pressure) beeman_2(sys->hdot[0], sys->hdot[0], sys->hddot[0], sys->hddoto[0], sys->hddotvo[0], 9); if (control.const_temp == 1) beeman_2(sys->ta, sys->ta, sys->tadot, sys->tadoto, sys->tadotvo, sys->nspecies); #ifdef DEBUG3 printf("Step2\n"); #endif } $EOD $! $CREATE convert.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Convert Functions for conversion of units of input parameters. * ****************************************************************************** * Revision Log * $Log: convert.c,v $ * Revision 2.8 1995/12/07 17:47:59 keith * Reworked V. Murashov's thermostat code. * Convert mass params from kJ/mol ps^2 to prog units. Defaults=1. * * Revision 2.8 1995/12/06 17:49:03 keith * Updated conversion table for thermostat parameters. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Revision 2.5 94/01/18 13:32:14 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:27:46 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:00 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.5 93/03/09 15:58:24 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.4 92/10/28 14:10:01 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.3 91/08/15 18:11:49 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.2 90/05/21 15:29:28 keith * Moved definition of struct pot_dim[][] from convert.c to kernel.c. * * Revision 1.1 89/04/20 16:00:36 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/convert.c,v 2.8 1995/12/07 17:47:59 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ extern CONST dim_mt pot_dim[][NPOTP]; /* Pot'l dimension specification */ /*========================== External function declarations ==================*/ #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== Structs local to module =========================*/ /* This struct array contains all details for conversions in 'control' struct */ typedef struct { double *d; /* Pointer to item to be converted */ dim_mt dim; /* Dimensions of quantity (eg MLT(-2))*/ unit_mt unit; /* Units (in MKS) for conversion from */ } conv_mt, *conv_mp; /*========================== Global variables ================================*/ #define TMUNIT (MUNIT/CONV_TM) static CONST conv_mt conv[] = { {&control.step, {0,0,1,0}, {1,1,TUNIT,1}}, {&control.pressure, {1,-1,-2,0}, {1e6,1,1,1}}, {&control.pmass, {1,0,0,0}, {MUNIT,1,1,1}}, {&control.ttmass, {1,2,0,0}, {TMUNIT,LUNIT,1,1}}, {&control.rtmass, {1,2,0,0}, {TMUNIT,LUNIT,1,1}}, {&control.cutoff, {0,1,0,0}, {1,LUNIT,1,1}}, {&control.density, {1,-3,0,0}, {.001,.01,1,1}}, {&control.alpha, {0,-1,0,0}, {1,LUNIT,1,1}}, {&control.limit, {0,-1,0,0}, {1,LUNIT,1,1}}}; #define NCONV (sizeof conv / sizeof(conv_mt)) /*============================================================================*/ /****************************************************************************** * unit_scale Takes the dimensions of a quantity (dim), the units it is in * * (unit_from) and returns the scale by which it must be multiplied to * * convert it to new units (unit_to). Uses logarithms to avoid overflow. * ******************************************************************************/ #define MAX_SCALE 80 /* 1e35 - safe for any machine*/ static double unit_scale(dim, unit_from, unit_to) CONST dim_mp dim; /* Dimensions */ unit_mp unit_from, unit_to; /* Units to convert from/to */ { double lnscale = dim->m*(log(unit_from->m) - log(unit_to->m)) + dim->l*(log(unit_from->l) - log(unit_to->l)) + dim->t*(log(unit_from->t) - log(unit_to->t)) + dim->q*(log(unit_from->q) - log(unit_to->q)); if(lnscale < -MAX_SCALE || lnscale > MAX_SCALE) message(NULLI,NULLP,FATAL,BADUNI,lnscale); return(exp(lnscale)); } /****************************************************************************** * Convert_potentials Scale potential parameters, site masses and charges * * from input units to program units. * ******************************************************************************/ void conv_potentials(unit_from, unit_to, potpar, npotpar, ptype, site_info, max_id) CONST unit_mp unit_from, unit_to; /* Values of units for conversion */ pot_mt potpar[]; /* Array of potpar records[max_id**2] */ int npotpar; /* Number of 'active' parameters */ int ptype; /* Potential type */ site_mt site_info[]; /* Site specification array[max_id] */ int max_id; /* How many site id's */ { int idi, idj, ip; /* Counters for id's and potpar */ static dim_mt mass_dim = {1,0,0,0}, /* Dimensions of mass */ charge_dim = {0,0,0,1}; /* Dimensions of charge */ double mscale = unit_scale(&mass_dim, unit_from, unit_to), qscale = unit_scale(&charge_dim, unit_from, unit_to); /* Scale factors for mass and charge */ double potscale[NPOTP]; /* Scale factors for pot'l parameters */ for(ip = 0; ip < npotpar;ip++) /* Work out scale factors for pot'l */ potscale[ip] = unit_scale(&pot_dim[ptype][ip],unit_from, unit_to); for(idi = 0; idi < max_id; idi++) { site_info[idi].mass *= mscale; /* Scale mass of each site */ site_info[idi].charge *= qscale; /* Scale charge of each site */ for(idj = 0; idj < max_id; idj++) for(ip = 0; ip < npotpar; ip++) /* Scale potential parameters */ potpar[idi + max_id*idj].p[ip] *= potscale[ip]; } } /****************************************************************************** * convert_control Convert various quantities in the control record between* * input and program units. Which to convert are indicated by the array * * 'conv' which contains a pointer to the data and a dimension struct. * ******************************************************************************/ void conv_control(unit, direction) CONST unit_mp unit; /* Units conversion is to/from */ boolean direction; /* True=from input, false=to input */ { int ic; /* Counter */ for(ic = 0; ic < NCONV; ic++) if(direction) *conv[ic].d *= unit_scale(&conv[ic].dim, &conv[ic].unit, unit); else *conv[ic].d *= unit_scale(&conv[ic].dim, unit, &conv[ic].unit); } $EOD $! $CREATE dump.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * dump Does a periodic dump of simulation data to a file. In fact most * * of this function is concerned with the bookkeeping associated with * * maintaining a sequentially numbered set of contiguous dump files, * * ensuring contiguity and dealing with errors. The actual writing is done * * by 'write_dump_record'. * * * The user must supply a prototype filename (control.dump_file, read in * * by keyword "dump-name". This should contain a numeric conversion code * * in 'printf' format (eg %3.3d ) which will be replaced by a sequential file* * number. (If it is absent the file number is added to the end). * * Each dump file consists of a header record which is a struct (type dump_t)* * followed by up to control.ndumps dump records. A file may be incomplete- * * the ndumps field of the header struct records the actual number. It is * * not necessary to write one file per run - records are added to the end * * of an existing file and a new one is started only when it is full. The * * contents of the record are determined by the "dump-level" parameter and * * consist of binary data. Each header struct contains a unique timestamp - * * "dump_init" which is the same for all files in a sequence of dumps. (Note * * that the previous dump file MUST be accessible in order to read and * * propagate this number - so when archiving dumps, always leave the very * * last one.) * ****************************************************************************** * Revision Log * $Log: dump.c,v $ * Revision 2.9 1996/03/06 18:20:04 keith * Added cast in xdr_vector() call to supress spurious warning message. * * Revision 2.8 1994/10/17 10:57:11 keith * Fixed bug in sequence code to check timesteps. * * Revision 2.7 1994/06/08 13:11:43 keith * Protected against possible bus error for systems with no * rotational freedom by making all references to "quat" etc conditional * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Revision 2.5 1994/02/01 14:33:45 keith * Revised consistency checks to safeguard existing files: * Now checks timestep in dump header. * Reverted behaviour on dump-level change to start new run * - acidentally botched in 2.4. * Changed behaviour on restart-file consistency check failure * to start new run too. * Improved messages. * * Revision 2.4 1994/01/24 18:32:32 keith * Don't rename dump run if restarting from backup file and * dump file exists and matches. * * Revision 2.3 93/10/28 10:27:47 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/08/18 20:52:08 keith * Added support for dumps in XDR format. * * Revision 2.0 93/03/15 14:49:01 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.19 93/03/09 15:58:26 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.18 92/06/02 10:37:52 keith * Added check of ferror() as well as return from fwrite(). Talk * about belt and braces. * * Revision 1.17 92/04/21 17:49:16 keith * Corrected error message * * Revision 1.16 92/03/02 15:28:32 keith * Fixed bug which caused dump/restart consistency check to erroneously * report an error on the second dump write. * Relaxed check to allow dump run to abort and restart from beginning. * * Revision 1.15 91/08/16 15:23:57 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.14 91/08/15 18:11:51 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.13 91/03/12 15:42:24 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.12 91/02/19 14:51:05 keith * Minor changes to get rid of misleading compiler warnings. * * Revision 1.11 90/05/16 18:40:01 keith * Renamed own freer from cfree to tfree. * * Revision 1.10 90/05/16 14:10:18 keith * Modified so that mutates always apply to rest of run. * * Revision 1.9 90/05/02 15:28:52 keith * Removed references to size_t and time_t typedefs, no longer in "defs.h" * * Revision 1.8 90/04/25 17:09:23 keith * Corrected test for mutation failure. * * Revision 1.7 90/04/17 10:49:47 keith * Corrected test for dump and restart consistency. * * Revision 1.6 90/04/09 14:49:33 keith * Now tests for failure of mutate() and gives up rather than lloping. * * Revision 1.5 89/10/16 15:47:37 keith * Fixed DUMP_SIZE macro to be correct! * * Revision 1.4 89/07/05 18:42:06 keith * Eliminated 'dump-offset' - renumbering starts at 1 for new dump run. * * Revision 1.3 89/05/15 17:54:12 keith * Added members 'vsn' and 'dump_size' to header (cf structs.h r1.3) * Fixed bugs in call of write and ftell to write data correctly. * * Revision 1.2 89/05/11 13:56:05 keith * Tidied up code using flags rather than GOTO's * Fixed bug in 'dump_convert' which wrote outside array bounds * Put PE in dump-level 1 rather than 8 * * Revision 1.1 89/04/27 15:13:56 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/dump.c,v 2.9 1996/03/06 18:20:04 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include #include "string.h" #include "stddef.h" #include "time.h" #include /*========================== program include files ===========================*/ #include "structs.h" #include "messages.h" #include "xdr.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ static char *mutate(); double mdrand(); void mat_vec_mul(); static void dump_convert(); static void real_to_float(); #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ #ifdef USE_XDR static XDR xdrs; #endif /*========================== Macros ==========================================*/ #define DUMP_SIZE(level) (( (level & 1) + (level>>1 & 1) + (level>>2 & 1) ) * \ (3*system->nmols + 4*system->nmols_r + 9)+ \ (level>>3 & 1) * \ (3*system->nmols + 3*system->nmols_r + 9) +\ (level & 1)) /*============================================================================*/ static int read_dump_hdr(fname, dumpf, hdr_p, xdr_write) char *fname; FILE **dumpf; dump_mt *hdr_p; boolean *xdr_write; { int errflg = true; /* Provisionally !! */ *xdr_write = false; if( (*dumpf = fopen(fname, "r+b")) == NULL) /* Open dump file */ message(NULLI, NULLP, WARNING, DOERRR, fname, strerror(errno)); else { #ifdef USE_XDR /* * Attempt to read dump header in XDR format */ xdrstdio_create(&xdrs, *dumpf, XDR_DECODE); if( xdr_dump(&xdrs, hdr_p) ) { hdr_p->vsn[sizeof hdr_p->vsn - 1] = '\0'; if( strstr(hdr_p->vsn,"(XDR)") ) { errflg = false; *xdr_write = true; } } #endif /* * If we failed, try to read header as native struct image. */ if( ! *xdr_write ) { if( fseek(*dumpf, 0L, 0) ) message(NULLI, NULLP, WARNING, SEFAIL, fname, strerror(errno)); else if( fread((gptr*)&*hdr_p, sizeof(dump_mt), 1, *dumpf) == 0 ) message(NULLI, NULLP, WARNING, DRERR, fname, strerror(errno)); else errflg = false; } } return errflg; } /*============================================================================*/ void dump(system, force, torque, stress, pe, restart_header, backup_restart) restrt_mt *restart_header; int backup_restart; system_mp system; vec_mt force[], torque[]; mat_mt stress; double pe; { FILE *dumpf=NULL; /* File pointer to dump files */ dump_mt dump_header, /* Header record proforma */ hdr_tmp; char cur_file[L_name], /* Names of current and previous */ prev_file[L_name], /* dump files. */ *fname; /* Pointer to one of above filenames */ int filenum=(control.istep-control.begin_dump) / (control.dump_interval * control.maxdumps), ndumps =(control.istep-control.begin_dump) / control.dump_interval % control.maxdumps; int istep_hdr; /* Timestep for dump header */ unsigned dump_size = DUMP_SIZE(control.dump_level); /* Size in floats of each dump record */ float *dump_buf=aalloc(dump_size,float); /* For converted data */ long file_pos=0, /* Offset within file of current rec. */ file_len; /* Length of file */ boolean errflg = false; #define NMUTATES 10 /* Max number of mutation attempts. */ int nmutates = 0; /* Number of mutation attempts. */ int junk; boolean xdr_write = false; /* Is current dump in XDR format? */ static int firsttime = 1; if( ! strchr(control.dump_file, '%') ) (void)strcat(control.dump_file, "%d"); (void)sprintf(cur_file, control.dump_file, filenum); (void)sprintf(prev_file, control.dump_file, filenum-1); if( control.istep > control.begin_dump ) /* Continue existing dump run */ { /* Get last dump's header */ if( ndumps == 0 ) fname = prev_file; else fname = cur_file; istep_hdr = control.istep - ndumps*control.dump_interval; if( ndumps == 0 ) istep_hdr -= control.maxdumps*control.dump_interval; errflg = true; /* * Attempt to read header and perform consistency checks which, * if failed, are "fatal" to dump run and initiate a *NEW* run * by setting errflg. */ if( read_dump_hdr(fname, &dumpf, &dump_header, &xdr_write) /* fails */ ) errflg = true; /* message already printed */ else if( control.dump_level != dump_header.dump_level ) /* Level */ message(NULLI, NULLP, WARNING, DMPALT); else if( istep_hdr != dump_header.istep ) /* Timeslice */ message(NULLI, NULLP, WARNING, DUMPTS, fname, istep_hdr,dump_header.istep); else if( firsttime && /* Matches Restart */ dump_header.timestamp < restart_header->timestamp && dump_header.restart_timestamp != restart_header->prev_timestamp && dump_header.restart_timestamp != restart_header->timestamp ) message(NULLI, NULLP, WARNING, CONTIG, fname); else errflg = false; /* * At this point we think we have a matching dump header. * Check to see if amount of data in file matches and whether * length of file is consistent with header. Any errors now are * too serious to just start another dump sequence and so abort * the run. */ if( !errflg ) { if( dump_header.ndumps < (ndumps ? ndumps : control.maxdumps ) ) message(NULLI,NULLP,FATAL, SHTDMP, fname, dump_header.ndumps, ndumps); else if( dump_header.ndumps > (ndumps ? ndumps : control.maxdumps) ) message(NULLI,NULLP,WARNING,LNGDMP, fname, dump_header.ndumps, ndumps); dump_header.ndumps = ndumps; if( fseek(dumpf, 0L, SEEK_END) ) message(NULLI, NULLP, FATAL, SEFAIL, fname, strerror(errno)); file_len = ftell(dumpf); /* Get length of file */ #ifdef USE_XDR if( xdr_write ) file_pos = XDR_DUMP_SIZE + ndumps*dump_size*XDR_FLOAT_SIZE; /* Expected length */ else #endif file_pos = sizeof(dump_mt) + ndumps*dump_size*sizeof(float); /* Expected length */ if( file_len < file_pos ) message(NULLI, NULLP, FATAL, CORUPT, fname, file_pos, file_len); } else { if( dumpf ) { #ifdef USE_XDR if( xdr_write ) xdr_destroy(&xdrs); #endif (void)fclose(dumpf); } if( ndumps != 0 ) { ndumps = 0; filenum = 0; control.begin_dump = control.istep; (void)sprintf(cur_file, control.dump_file, filenum); } message(NULLI,NULLP,WARNING,DRESET); } } if( errflg || control.istep == control.begin_dump ) { (void)strcpy(dump_header.title, control.title); (void)strncpy(dump_header.vsn, "$Revision: 2.9 $"+11, sizeof dump_header.vsn-1); #ifdef USE_XDR if( control.xdr_write ) { (void)strncat(dump_header.vsn, " (XDR)", sizeof dump_header.vsn-1); xdr_write = true; } #endif dump_header.dump_interval = control.dump_interval; dump_header.dump_level = control.dump_level; dump_header.maxdumps = control.maxdumps; dump_header.dump_size = dump_size; dump_header.dump_init = time((time_t *)0); note(DUMPST, cur_file, control.istep); } if( ndumps == 0) /* Start of new dump file */ { if( dumpf ) /* Finished with old file */ { #ifdef USE_XDR if( xdr_write ) xdr_destroy(&xdrs); #endif (void)fclose(dumpf); } while( (dumpf = fopen(cur_file, "r")) != 0 ) /* File of that name */ { /* already exists */ (void)fclose(dumpf); /* * Test whether existing file belongs to current dump * sequence in case of run restarted from backup. In that * case, OVERWRITE it. */ if( backup_restart ) { errflg = read_dump_hdr(cur_file, &dumpf, &hdr_tmp, &junk); if( errflg == false && (hdr_tmp.dump_init == dump_header.dump_init) ) { (void)fclose(dumpf); break; } } if( nmutates++ >= NMUTATES || mutate(control.dump_file) == NULL) message(NULLI, NULLP, FATAL, MUFAIL, control.dump_file, nmutates); message(NULLI, NULLP, WARNING, DMPEXS, cur_file, control.dump_file); (void)sprintf(cur_file, control.dump_file, filenum); } dump_header.ndumps = 0; dump_header.istep = control.istep; dump_header.timestamp = time((time_t *)0); dump_header.restart_timestamp = 0; if( (dumpf = fopen(cur_file, "w+b")) == 0) message(NULLI, NULLP, FATAL, DOERRW, cur_file, strerror(errno)); #ifdef USE_XDR if( xdr_write ) { xdrstdio_create(&xdrs, dumpf, XDR_ENCODE); if( ! xdr_dump(&xdrs, &dump_header) ) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); if( (file_pos = xdr_getpos(&xdrs)) == -1) message(NULLI, NULLP, FATAL, GPFAIL, cur_file, strerror(errno)); } else #endif { if( fwrite((gptr*)&dump_header, sizeof(dump_mt), 1, dumpf) == 0) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); if( (file_pos = ftell(dumpf)) == -1) message(NULLI, NULLP, FATAL, GPFAIL, cur_file, strerror(errno)); } } #ifdef USE_XDR else { if( xdr_write ) { xdr_destroy(&xdrs); xdrstdio_create(&xdrs, dumpf, XDR_ENCODE); } } #endif dump_convert(dump_buf, system, force, torque, stress, pe); dump_header.ndumps++; dump_header.restart_timestamp = restart_header->timestamp; #ifdef USE_XDR if( xdr_write ) { if( ! xdr_setpos(&xdrs, file_pos) ) /* Write data at end */ message(NULLI, NULLP, FATAL, SEFAIL, cur_file, strerror(errno)); if( ! xdr_vector(&xdrs, (gptr*)dump_buf, dump_size, sizeof(float), (xdrproc_t)xdr_float) ) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); } else #endif { if( fseek(dumpf, file_pos, SEEK_SET) ) /* Write data at end */ message(NULLI, NULLP, FATAL, SEFAIL, cur_file, strerror(errno)); if( fwrite((gptr*)dump_buf, sizeof(float), dump_size, dumpf) < dump_size ) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); } #ifdef USE_XDR if( xdr_write ) { (void)xdr_setpos(&xdrs, 0); if( ! xdr_dump(&xdrs, &dump_header) ) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); xdr_destroy(&xdrs); } else #endif { (void)fseek(dumpf, 0L, SEEK_SET); /* Write header */ if( fwrite((gptr*)&dump_header, sizeof(dump_mt), 1, dumpf) == 0) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); } if( ferror(dumpf) || fclose(dumpf) ) message(NULLI, NULLP, FATAL, DWERR, cur_file, strerror(errno)); firsttime = 0; xfree(dump_buf); } /****************************************************************************** * mutate Take a string defining a file name and randomly alter characters * * to generate another, hopefully valid file name. Assumes that a printf * * conversion code is present and only alters contiguously alphabetic chars * * before the percent. * ******************************************************************************/ #define N_MUTATE 3 /* Max number of mutated chars*/ static char *mutate(name) char *name; { char *pc_pos = strchr(name,'%'), *begin = pc_pos; static char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZZ"; while( begin > name && (pc_pos - begin) < N_MUTATE && isalnum(*(begin-1)) ) begin--; if(begin >= pc_pos) /* No characters to mutate */ return NULL; while( begin < pc_pos ) *begin++ = alpha[(int)(mdrand() * 26.0)]; return name; } /****************************************************************************** * dump_convert format data and place in buffer for dumping to file * * Quantities dumped depend on bits set in 'control.dump_level' as follows: * * bit 0: centre of mass co-ords, quaternions, unit cell matrix. * * bit 1: derivatives of above. *. * bit 2: second derivatives of above. * * bit 3: forces, torques, stress and potential energy. * * All quantities are converted to floats (from real, whatever that is) and * * c_of_m and its derivatives are converted to unscaled co-ordinates. * ******************************************************************************/ static void dump_convert(buf, system, force, torque, stress, pe) float *buf; system_mp system; vec_mt force[], torque[]; mat_mt stress; double pe; { int nmols = system->nmols, nmols_r = system->nmols_r; vec_mt *scale_buf = ralloc(nmols); real ppe = pe; if( control.dump_level & 1) { mat_vec_mul(system->h, system->c_of_m, scale_buf, nmols); real_to_float(scale_buf[0], buf, 3*nmols); buf += 3*nmols; if( system->nmols_r > 0 ) { real_to_float(system->quat[0], buf, 4*nmols_r); buf += 4*nmols_r; } real_to_float(system->h[0], buf, 9); buf += 9; real_to_float(&ppe, buf, 1); buf += 1; } if( control.dump_level & 2) { mat_vec_mul(system->h, system->vel, scale_buf, nmols); real_to_float(scale_buf[0], buf, 3*nmols); buf += 3*nmols; if( system->nmols_r > 0 ) { real_to_float(system->qdot[0], buf, 4*nmols_r); buf += 4*nmols_r; } real_to_float(system->hdot[0], buf, 9); buf += 9; } if( control.dump_level & 4) { mat_vec_mul(system->h, system->acc, scale_buf, nmols); real_to_float(scale_buf[0], buf, 3*nmols); buf += 3*nmols; if( system->nmols_r > 0 ) { real_to_float(system->qddot[0], buf, 4*nmols_r); buf += 4*nmols_r; } real_to_float(system->hddot[0], buf, 9); buf += 9; } if( control.dump_level & 8) { real_to_float(force[0], buf, 3*nmols); buf += 3*nmols; if( system->nmols_r > 0 ) { real_to_float(torque[0], buf, 3*nmols_r); buf += 3*nmols_r; } real_to_float(stress[0], buf, 9); buf += 9; } xfree(scale_buf); } /****************************************************************************** * real_to_float Copy data from one array to another, converting from * * typedef real to type float in the interests of space. (may be null op'n) * ******************************************************************************/ static void real_to_float(b, a, n) float a[]; real b[]; int n; { int i; for( i=0; i for stellar * * Revision 1.5 89/11/01 17:29:10 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * 'Uniform charge sheet' term added in case of electrically charged system. * * Revision 1.5 89/10/26 11:29:26 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * 'Uniform charge sheet' term added in case of electrically charged layer. * * Revision 1.5 89/10/26 11:27:31 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * * Revision 1.4 89/10/02 11:39:14 keith * Fixed error in *star macros which assumed rlv's were cols of h(-1) r.t. rows. * * Revision 1.3 89/06/09 13:38:17 keith * Older code for computation of q cos/sin k.r restored conditionally by * use of macro OLDEWALD. This is for more primitive vectorising compilers. * * Revision 1.2 89/06/08 10:42:51 keith * Modified to circumvent compiler bug in VMS/VAXC 2.4-026 * * Revision 1.1 89/04/20 16:00:39 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/ewald.c,v 2.13 1996/11/05 16:45:49 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar # include #else #ifdef titan # include #else # include #endif #endif #include "stddef.h" #include "stdlib.h" #include "string.h" /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void afree(); /* Free allocated array */ double err_fn(); /* Error function */ double det(); /* Determinant of 3x3 matrix */ void invert(); /* Inverts a 3x3 matrix */ void mat_vec_mul(); /* Multiplies a 3x3 matrix by 3xN vect*/ void mat_sca_mul(); /* Multiplies a 3x3 matrix by scalar */ void transpose(); /* Transposes a 3x3 matrix */ void zero_real(); /* Initialiser */ void zero_double(); /* Initialiser */ double sum(); /* Sum of elements of 'real' vector */ #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ void note(char *,...); /* Write a message to the output file */ void message(int *,...); /* Write a warning or error message */ #else gptr *arralloc(); /* Array allocator */ void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control record */ extern int ithread, nthreads; /*========================== Macros ==========================================*/ #define astar hinvp[0] #define bstar hinvp[1] #define cstar hinvp[2] #define moda(hmat) (hmat[0][0]) #define modb(hmat) sqrt(SQR(hmat[0][1]) + SQR(hmat[1][1])) #define modc(hmat) sqrt(SQR(hmat[0][2]) + SQR(hmat[1][2]) + SQR(hmat[2][2])) /*========================== Cache Parameters=================================*/ /* The default values are for the Cray T3D but are probably good enough * for most other systems too. */ #ifndef NCACHE # define NCACHE (256*sizeof(double)/sizeof(real)) #endif #ifndef NLINE # define NLINE (4*sizeof(double)/sizeof(real)) #endif /*============================================================================*/ struct s_hkl {double kx, ky, kz; int h,k,l;}; /***************************************************************************** * qsincos(). Evaluate q sin(k.r) and q cos(k.r). This is in a separate * * function because some compilers (notably Stellar's) generate MUCH better * * vector code this way. * *****************************************************************************/ static void qsincos(coshx,sinhx,cosky,sinky,coslz,sinlz,chg, qcoskr,qsinkr,k,l,nsites) real coshx[], sinhx[], cosky[], sinky[], coslz[], sinlz[], chg[], qcoskr[], qsinkr[]; int k,l,nsites; { int is; real qckr; if( k >= 0 ) if( l >= 0 ) { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*coslz[is] - (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*coslz[is] + (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*coslz[is] + (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*coslz[is] - (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else if( l >= 0 ) { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*coslz[is] - (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*coslz[is] + (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*coslz[is] + (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*coslz[is] - (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } } /****************************************************************************** * Calculate cos and sin of astar*x, bstar*y & cstar*z for each charged site * * Use addition formulae to get sin(h*astar*x)=sin(Kx*x) etc for each site * ******************************************************************************/ static void trig_recur(chx,shx,sin1x,cos1x,site0,site1,site2,kstar,hmax,ns0,ns1) real **chx, **shx, sin1x[],cos1x[], *site0, *site1, *site2, *kstar; int ns0, ns1, hmax; { int h, is; real *coshx, *sinhx, *cm1, *sm1, coss, kr; real ksx = kstar[0], ksy = kstar[1], ksz = kstar[2]; sinhx = shx[0]; coshx = chx[0]; VECTORIZE for(is = ns0; is < ns1; is++) { coshx[is] = 1.0; sinhx[is] = 0.0; } if( hmax >= 1 ) { coshx = chx[1]; sinhx = shx[1]; VECTORIZE for(is = ns0; is < ns1; is++) { kr = ksx*site0[is]+ksy*site1[is]+ksz*site2[is]; coshx[is] = cos(kr); sinhx[is] = sin(kr); } memcp(cos1x+ns0, coshx+ns0, (ns1-ns0)*sizeof(real)); memcp(sin1x+ns0, sinhx+ns0, (ns1-ns0)*sizeof(real)); for(h = 2; h <= hmax; h++) { coshx = chx[h]; sinhx = shx[h]; cm1 = chx[h-1]; sm1 = shx[h-1]; VECTORIZE for(is = ns0; is < ns1; is++) { coss = cm1[is]*cos1x[is] - sm1[is]*sin1x[is]; sinhx[is] = sm1[is]*cos1x[is] + cm1[is]*sin1x[is]; coshx[is] = coss; } } } } /****************************************************************************** * allocate_arrays(). Memory allocation for Ewald's arrays. We malloc one * * large block and divide it out so as to precisely control the relative * * offsets of the arrays. This is to avoid cache conflicts. * * Revert to bog-standard method for MSDOS * ******************************************************************************/ static real* allocate_arrays(nsarray, hmax, kmax, lmax, chx, cky, clz, shx, sky, slz, chg, cos1x, cos1y, cos1z, sin1x, sin1y, sin1z, qcoskr, qsinkr) int nsarray, hmax, kmax, lmax; real ***chx, ***cky, ***clz, ***shx, ***sky, ***slz; real **cos1x, **cos1y, **cos1z, **sin1x, **sin1y, **sin1z; real **chg, **qcoskr, **qsinkr; { int h, k,l; real *csp, *base; #ifndef __MSDOS__ /* * Attempt to cache-align these arrays for optimum performance. * This requires NON-ANSI pointer conversion and arithmetic. * It should work with any UNIX address space, so make it conditional. */ base = dalloc((2*(hmax+kmax+lmax)+15)*nsarray+10*NLINE+NCACHE); #if defined(unix) && !defined(__BOUNDS_CHECKING_ON) csp = (real*)0 + (((base - (real*)0) - 1 | NCACHE-1) + 1); #else csp = base; #endif *chx = (real**)arralloc(sizeof(real*),1,0,hmax); *cky = (real**)arralloc(sizeof(real*),1,0,kmax); *clz = (real**)arralloc(sizeof(real*),1,0,lmax); *shx = (real**)arralloc(sizeof(real*),1,0,hmax); *sky = (real**)arralloc(sizeof(real*),1,0,kmax); *slz = (real**)arralloc(sizeof(real*),1,0,lmax); *qcoskr = csp; csp += nsarray + NLINE; *qsinkr = csp; csp += nsarray + NLINE; *chg = csp; csp += nsarray + NLINE; for(h = 0; h <= hmax; h++, csp += nsarray) (*chx)[h] = csp; csp += NLINE; for(h = 0; h <= hmax; h++, csp += nsarray) (*shx)[h] = csp; csp += NLINE; for(k = 0; k <= kmax; k++, csp += nsarray) (*cky)[k] = csp; csp += NLINE; for(k = 0; k <= kmax; k++, csp += nsarray) (*sky)[k] = csp; csp += NLINE; for(l = 0; l <= lmax; l++, csp += nsarray) (*clz)[l] = csp; csp += NLINE; for(l = 0; l <= lmax; l++, csp += nsarray) (*slz)[l] = csp; csp += NLINE; *cos1x = csp; csp += nsarray; *cos1y = csp; csp += nsarray; *cos1z = csp; csp += nsarray + NLINE; *sin1x = csp; csp += nsarray; *sin1y = csp; csp += nsarray; *sin1z = csp; csp += nsarray; #else *chx = (real**)arralloc((size_mt)sizeof(real),2, 0, hmax, 0, nsarray-1); *cky = (real**)arralloc((size_mt)sizeof(real),2, 0, kmax, 0, nsarray-1); *clz = (real**)arralloc((size_mt)sizeof(real),2, 0, lmax, 0, nsarray-1); *shx = (real**)arralloc((size_mt)sizeof(real),2, 0, hmax, 0, nsarray-1); *sky = (real**)arralloc((size_mt)sizeof(real),2, 0, kmax, 0, nsarray-1); *slz = (real**)arralloc((size_mt)sizeof(real),2, 0, lmax, 0, nsarray-1); *cos1x = (*chx)[1]; *cos1y = (*cky)[1]; *cos1z = (*clz)[1]; *sin1x = (*shx)[1]; *sin1y = (*sky)[1]; *sin1z = (*slz)[1]; csp = base = dalloc(3*nsarray); *chg = csp; csp += nsarray; *qcoskr = csp; csp += nsarray; *qsinkr = csp; csp += nsarray; #endif return base; } /****************************************************************************** * Ewald Calculate reciprocal-space part of coulombic forces * ******************************************************************************/ void ewald(site,site_force,system,species,chgx,pe,stress) real **site, /* Site co-ordinate arrays (in) */ **site_force; /* Site force arrays (out) */ system_mp system; /* System record (in) */ spec_mt species[]; /* Array of species records (in) */ real chgx[]; /* Array of site charges (in) */ double *pe; /* Potential energy (out) */ mat_mt stress; /* Stress virial (out) */ { mat_mt hinvp; /* Matrix of reciprocal lattice vects*/ int h, k, l; /* Recip. lattice vector indices */ int i, j, is, ssite; /* Counters. */ spec_mp spec; /* species[ispec] */ int nsites = system->nsites; double pe_k, /* Pot'l energy for current K vector */ coeff, coeff2; /* 2/(e0V) * A(K) & similar */ double r_4_alpha = -1.0/(4.0 * control.alpha * control.alpha); double sqcoskr,sqsinkr, /* Sum q(i) sin/cos(K.r(i)) */ sqcoskrn, sqsinkrn, sqcoskrf, sqsinkrf; double ksq, /* Squared magnitude of K vector */ kcsq = SQR(control.k_cutoff); double kx,ky,kz,kzt; vec_mt kv; /* (Kx,Ky,Kz) */ real force_comp, kv0, kv1, kv2, sfx, sfy; struct s_hkl *hkl, *phkl; int nhkl = 0; /* * Maximum values of h, k, l s.t. |k| < k_cutoff */ int hmax = floor(control.k_cutoff/(2*PI)*moda(system->h)), kmax = floor(control.k_cutoff/(2*PI)*modb(system->h)), lmax = floor(control.k_cutoff/(2*PI)*modc(system->h)); /* * lower and upper limits for parallel loops. */ #if defined(SPMD) && defined(MPPMANY) int nsnode = (nsites+nthreads-1)/nthreads; int nsarr0 = nsnode * nthreads; int ns0 = MIN(nsites, nsnode * ithread), ns1 = MIN(nsites, nsnode * (ithread+1)); #else int ns0 = 0, ns1 = nsites; int nsarr0 = nsites; #endif /* * Round up size of arrays to cache sub-multiple size. */ #if 1 int nsarray = (nsarr0 - 1 | NCACHE - 1) + 1; #else int nsarray = nsarr0; #endif /* * Arrays for cos & sin (h x(i)), (k y(i)) and (l z(i)) eg chx[h][isite] * and pointers to a particular h,k or l eg coshx[is] = chh[2][is] */ real **chx, **cky, **clz, **shx, **sky, **slz; real *cshkl; real *coshx, *cosky, *coslz, *sinhx, *sinky, *sinlz; real *cos1x, *cos1y, *cos1z, *sin1x, *sin1y, *sin1z; real *chg; real *site_fx = site_force[0], *site_fy = site_force[1], *site_fz = site_force[2]; real *qcoskr, /* q(i) cos(K.R(i)) */ *qsinkr; /* q(i) sin(K.R(i)) */ double vol = det(system->h); /* Volume of MD cell */ static double self_energy, /* Constant self energy term */ sheet_energy; /* Correction for non-neutral system. */ static boolean init = true; /* Flag for the first call of function*/ static int nsitesxf; /* Number of non-framework sites. */ /* * Trig array set-up. The precise storage layout is to avoid cache conflicts. */ cshkl = allocate_arrays(nsarray, hmax, kmax, lmax, &chx, &cky, &clz, &shx, &sky, &slz, &chg, &cos1x, &cos1y, &cos1z, &sin1x, &sin1y, &sin1z, &qcoskr, &qsinkr); memcp(chg, chgx, nsites*lsizeof(real)); /* * First call only - evaluate self energy term and store for subsequent calls * Self energy includes terms for non-framework sites only. */ if(init) { double sqsq = 0, sq = 0, sqxf, intra, r; int js, frame_flag; self_energy = sheet_energy = 0; ssite = 0; spec = species; while( spec < species+system->nspecies && ! spec->framework) { intra = 0.0; for(is = 0; is < spec->nsites; is++) for(js = is+1; js < spec->nsites; js++) { r = DISTANCE(spec->p_f_sites[is], spec->p_f_sites[js]); intra += chg[ssite+is] * chg[ssite+js] *err_fn(control.alpha * r) / r; } self_energy += spec->nmols * intra; ssite += spec->nsites*spec->nmols; spec++; } nsitesxf = ssite; frame_flag = (spec != species+system->nspecies); for(is = 0; is < nsitesxf; is++) { sq += chg[is]; sqsq += SQR(chg[is]); } self_energy += control.alpha / sqrt(PI) * sqsq; /* * Sqxf is total non-framework charge. Calculate grand total in sq. */ sqxf = sq; for(; is < nsites; is++) sq += chg[is]; /* * Charged-system/uniform sheet correction terms (really in direct * space term but included here for convenience). * 1) For charged framework only. */ if( frame_flag ) { sheet_energy = PI*SQR(sq-sqxf) / (2.0*SQR(control.alpha)); message(NULLI, NULLP, INFO, FRACHG, (sq-sqxf)*CONV_Q, sheet_energy/vol*CONV_E); } /* * 2) Case of entire system non-neutral. */ if( fabs(sq)*CONV_Q > 1.0e-5) { sheet_energy -= intra = PI*SQR(sq) / (2.0*SQR(control.alpha)); message(NULLI, NULLP, WARNING, SYSCHG, sq*CONV_Q, intra/vol*CONV_E); } note("Ewald self-energy = %f Kj/mol",self_energy*CONV_E); } if( ithread == 0 ) { *pe -= self_energy; /* Subtract self energy term */ *pe += sheet_energy/vol; /* Uniform charge correction */ for(i=0; i<3; i++) stress[i][i] += sheet_energy/vol; } invert(system->h, hinvp); /* Inverse of h is matrix of r.l.v.'s */ mat_sca_mul(2*PI, hinvp, hinvp); /* * Build array hkl[] of k vectors within cutoff. * N. B. This code presupposes upper-triangular H matrix. */ hkl = aalloc(4*(hmax+1)*(kmax+1)*(lmax+1), struct s_hkl); for(h = 0; h <= hmax; h++) for(k = (h==0 ? 0 : -kmax); k <= kmax; k++) { kx = h*astar[0] + k*bstar[0]; ky = h*astar[1] + k*bstar[1]; kzt = h*astar[2] + k*bstar[2]; ksq = SQR(kx) + SQR(ky); for(l = (h==0 && k==0 ? 1 : -lmax); l <= lmax; l++) { kz = kzt + l*cstar[2]; if( SQR(kz)+ksq < kcsq ) { hkl[nhkl].h = h; hkl[nhkl].k = k; hkl[nhkl].l = l; hkl[nhkl].kx = kx; hkl[nhkl].ky = ky; hkl[nhkl].kz = kz; nhkl++; } } } if( init ) note("%d K-vectors included in reciprocal-space sum",nhkl); init = false; /* * Calculate cos and sin of astar*x, bstar*y & cstar*z for each charged site * Use addition formulae to get sin(h*astar*x)=sin(Kx*x) etc for each site */ trig_recur(chx,shx,sin1x,cos1x,site[0],site[1],site[2],astar,hmax,ns0,ns1); trig_recur(cky,sky,sin1y,cos1y,site[0],site[1],site[2],bstar,kmax,ns0,ns1); trig_recur(clz,slz,sin1z,cos1z,site[0],site[1],site[2],cstar,lmax,ns0,ns1); #if defined(SPMD) && defined(MPPMANY) par_collect_all(chx[0]+ns0, chx[0], nsnode, nsarray, hmax+1); par_collect_all(shx[0]+ns0, shx[0], nsnode, nsarray, hmax+1); par_collect_all(cky[0]+ns0, cky[0], nsnode, nsarray, kmax+1); par_collect_all(sky[0]+ns0, sky[0], nsnode, nsarray, kmax+1); par_collect_all(clz[0]+ns0, clz[0], nsnode, nsarray, lmax+1); par_collect_all(slz[0]+ns0, slz[0], nsnode, nsarray, lmax+1); #endif /* * Start of main loops over K vector indices h, k, l between -*max, *max etc. * To avoid calculating K and -K, only half of the K-space box is covered. * Points on the axes are included once and only once. (0,0,0) is omitted. */ for(phkl = hkl+ithread; phkl < hkl+nhkl; phkl += nthreads) { /* * Calculate actual K vector and its squared magnitude. */ h = phkl->h; k = phkl->k; l = phkl->l; kv0 = kv[0] = phkl->kx; kv1 = kv[1] = phkl->ky; kv2 = kv[2] = phkl->kz; ksq = SUMSQ(kv); /* * Calculate pre-factors A(K) etc */ coeff = 2.0 / (EPS0 * vol) * exp(ksq * r_4_alpha) / ksq; coeff2 = 2.0 * (1.0 - ksq * r_4_alpha) / ksq; /* * Set pointers to array of cos (h*astar*x) (for efficiency & vectorisation) */ coshx = chx[h]; cosky = cky[abs(k)]; coslz = clz[abs(l)]; sinhx = shx[h]; sinky = sky[abs(k)]; sinlz = slz[abs(l)]; /* * Calculate q(i)*cos/sin(K.R(i)) by addition formulae. Note handling of * negative k and l by using sin(-x) = -sin(x), cos(-x) = cos(x). For * efficiency & vectorisation there is a loop for each case. */ qsincos(coshx,sinhx,cosky,sinky,coslz,sinlz,chg, qcoskr,qsinkr,k,l,nsites); sqcoskrn = sum(nsitesxf, qcoskr, 1); sqsinkrn = sum(nsitesxf, qsinkr, 1); sqcoskrf = sum(nsites-nsitesxf, qcoskr+nsitesxf, 1); sqsinkrf = sum(nsites-nsitesxf, qsinkr+nsitesxf, 1); sqcoskr = sqcoskrn + sqcoskrf; sqsinkr = sqsinkrn + sqsinkrf; /* * Evaluate potential energy contribution for this K and add to total. * Exclude frame-frame interaction terms. */ pe_k = 0.5 * coeff * (sqcoskrn*(sqcoskrn+sqcoskrf+sqcoskrf) + sqsinkrn*(sqsinkrn+sqsinkrf+sqsinkrf)); *pe += pe_k; sqsinkr *= coeff; sqcoskr *= coeff; sqsinkrn *= coeff; sqcoskrn *= coeff; /* * Calculate long-range coulombic contribution to stress tensor */ NOVECTOR for(i = 0; i < 3; i++) { stress[i][i] += pe_k; NOVECTOR for(j = i; j < 3; j++) stress[i][j] -= pe_k * coeff2 * kv[i] * kv[j]; } /* * Evaluation of site forces. Non-framework sites interact with all others */ VECTORIZE for(is = 0; is < nsitesxf; is++) { force_comp = qsinkr[is]*sqcoskr - qcoskr[is]*sqsinkr; sfx = site_fx[is] + kv0 * force_comp; sfy = site_fy[is] + kv1 * force_comp; site_fz[is] += kv2 * force_comp; site_fx[is] = sfx; site_fy[is] = sfy; } /* * Framework sites -- only interact with non-framework sites */ VECTORIZE for(is = nsitesxf; is < nsites; is++) { force_comp = qsinkr[is]*sqcoskrn - qcoskr[is]*sqsinkrn; sfx = site_fx[is] + kv0 * force_comp; sfy = site_fy[is] + kv1 * force_comp; site_fz[is] += kv2 * force_comp; site_fx[is] = sfx; site_fy[is] = sfy; } /* * End of loop over K vectors. */ } afree((gptr*)chx); afree((gptr*)cky); afree((gptr*)clz); afree((gptr*)shx); afree((gptr*)sky); afree((gptr*)slz); xfree(cshkl); xfree(hkl); } $EOD $! $CREATE force.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Force This module contains functions to implement the 'link cell' * * interatomic force calculation (Hockney, R.W. & Eastwood J.W. * * "Computer Simulation Using Particles" McGraw-Hill (1981), 277)* * It is vectorised and optimised for a CRAY XMP and Convex C1, * * but should run well on any vector machine with reasonably * * efficient scatter/gather. (And of course on scalar machines!) * * The actual calculation of the potential is in a different * * module (kernel.c) for ease of modification. * ****************************************************************************** * $Log: force.c,v $ * Revision 2.14 1996/11/04 17:34:30 keith * Moderate rewriting and code re-organization. * 1. Simplified PBC relocation calculation, got rid of large * arrays reloc[] etc, saving 32 MB for 8192 waters on T3D. * There is now NO LIMIT to cutoff or RDF limit and macro * parameter NSH is removed. * 2. Rewrote site_neighbour_list to be more transparent and got * rid of silly vector sort calls. There are now separate versions for * scalar and vector machines. Code is now optimized for usual non- * framework case, but it's faster than 2.10 even for frameworks. * 3. Corrected misleading comments, reorganized code in force_calc() * to be more transparent. Commented local variables MUCH better. * 4. It's also a bit faster. * * Revision 2.13 1996/08/14 16:46:04 keith * Workaround for T3D Cray compiler bug real*int/int ==> int division. * Got rid of unnccessary par_abort() calls - rplaced with exit(). * (message on thread 0 calls par_abort()). * * Revision 2.12 1996/05/03 16:14:20 keith * Fixed bug whereby reloc could overflow in strict cutoff mode by * tightening up test condition. Also fixed the calculation of * n_nab_sites to reflect the increased cutoff in strict mode. * * Revision 2.11 1996/01/17 17:12:47 keith * Incorporated rdf accumulation into forces and parallelized. * New functions rdf_inner(), calls rdf_accum() from rdf.c * * Revision 1.8.1.8 89/11/01 17:34:15 keith * Modified to use SPAXPY vectorised scattered add. * * Revision 1.8.1.6 89/10/12 16:28:39 keith * Added conditional code to produce histogram of interaction distances * and calculate 'minimum image' energy. * Added preprocessor constant NSH to fix size of relocation arrays. * Fixed mistake in metric G in neighbour_list() (G=h'h not hh'). * * Revision 1.8.1.5 89/10/02 17:12:59 keith * New version of neighbour_list() which works for arbitrary cutoff radii. * site_neighbour_list checks for overflow. * Main loop limits modified, (in conjunction with mods in site_neighbour_list) * to correctly include all molecule-framework interactions. * * Revision 1.8.1.4 89/09/12 16:14:41 keith * Fixed bug in fill_cells() which didn't increment spec properly in imol loop * * Revision 1.8.1.3 89/08/31 11:58:04 keith * Fixed bug in 'BIN' macro to correctly handle case of rc<0. * * Revision 1.8.1.2 89/08/30 17:00:33 keith * Fixed memory overlap bug in site_neighbour_list * * Revision 1.8.1.1 89/08/25 15:24:43 keith * Mods to add framework structures to simulation model * * Revision 1.7 89/08/22 14:48:39 keith * Created new variable 'n_nab_sites' for max size of vector arrays. * * Revision 1.6 89/07/04 18:43:14 keith * Fixed error in kernel and force which led to sites being allocated the * wrong potential parameters. Needed extra parameter to kernel. * * Revision 1.5 89/06/22 15:44:23 keith * Tidied up loops over species to use one pointer as counter. * * Revision 1.4 89/06/14 14:18:49 keith * Fixed #ifdef s for CRAY to handle case of UNICOS * Fix mistake in VCALLS conditional code. * * Revision 1.3 89/06/01 18:01:46 keith * Moved `vadd()' from aux.c to force.c for ease of vectorisation. * Now no need to compile aux.c with vectorisation. * * Revision 1.2 89/05/17 13:53:49 keith * Reorganised neighbour list construction in preparation for framework. * (Also goes slighty faster) * * Revision 1.1 89/04/20 16:00:40 keith * Initial revision * * Revision 1.3 90/03/29 15:44:51 keith * Merged force.c revisions 1.8.1.11-1.8.1.13 * * Revision 1.2 90/03/09 17:30:29 keith * Modified FKERNEL ifdefs for UNICOS. * * Revision 1.1 90/01/31 13:19:28 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/force.c,v 2.14 1996/11/04 17:34:30 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar #include #else #include #endif #include "stddef.h" #include "string.h" #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void afree(); /* Free allocated array */ int search_lt(); /* Search a vector for el. < scalar */ void gather(); /* Interface to CRAY gather routine */ void mat_mul(); /* Matrix multiplier */ double det(); /* Determinant of 3x3 matrix */ void invert(); /* 3x3 matrix inverter */ void mat_vec_mul(); /* Matrix by vector multiplier */ void transpose(); /* Generate 3x3 matrix transpose */ void zero_real(); /* Initialiser */ void force_inner(); /* Inner loop forward reference */ void rdf_inner(); /* RDF calc forward reference */ double precision(); /* Floating pt precision. */ void kernel(); /* Force kernel routine */ double mol_radius(); /* Radius of largest molecule. */ void rdf_accum(); /* Bin distances for rdf evaluation. */ #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else gptr *arralloc(); /* Array allocator */ void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ extern int ithread, nthreads; /*========================== Structs local to module =========================*/ typedef struct cell_s /* Prototype element of linked list of*/ { /* molecules within interaction range */ int isite, num, frame_type; struct cell_s *next; } cell_mt; typedef struct /* Prototype of neighbour cell list */ { /* element. */ int i, j, k; } ivec_mt; typedef struct /* Prototype of neighbour cell list */ { /* element. */ real i, j, k; } rvec_mt; typedef struct /* Prototype of neighbour cell list */ { /* element. */ real x, y, z; int i, j, k; } irvec_mt; /*========================== Global variables ================================*/ static irvec_mt *ifloor; /*Lookup tables for int "floor()" */ /*========================== Macros ==========================================*/ /* * Multiplication factor for size of neighbour list arrays. If you need * to increase this from 1, your system must be *highly* inhomogeneous * and may not make sense! */ #define NMULT 3.0 #define TOO_CLOSE 0.25 /* Error signalled if r**2 < this */ #define NCELL(ix,iy,iz) ((iz)+(nz)*((iy)+(ny)*(ix))) #define LOCATE(r,eps) NCELL(cellbin(r[0], nx, eps), \ cellbin(r[1], ny, eps), \ cellbin(r[2], nz, eps)) #define BIGINT 32768 #define IFLOOR(i,n) ((i+BIGINT*n)/n-BIGINT) #define moda(hmat) sqrt(SQR(hmat[0][0]) + SQR(hmat[1][0]) + SQR(hmat[2][0])) #define modb(hmat) sqrt(SQR(hmat[0][1]) + SQR(hmat[1][1]) + SQR(hmat[2][1])) #define modc(hmat) sqrt(SQR(hmat[0][2]) + SQR(hmat[1][2]) + SQR(hmat[2][2])) #ifdef __BOUNDS_CHECKING_ON /* The declaration of "array" potp has a lower */ # define P0 0 /* bound of 1. This is a violation of strict */ #else /* ANSI, so turn it off when bounds checking. */ # define P0 1 #endif /*============================================================================*/ /****************************************************************************** * spxpy Sparse add for force.c. N.B. MUST NOT BE VECTORIZED as ix may * * contain duplicate entries. This occurs if a site interacts with * * more than one periodic copy of another site. * ******************************************************************************/ static void spxpy(n, sx, sy, ix) int n, ix[]; real sx[], sy[]; { int i; NOVECTOR #ifdef __STDC__ #pragma novector #endif for( i = 0; i < n; i++) { sy[ix[i]] += sx[i]; } } /****************************************************************************** * cellbin. Safe binning function for putting molecules/sites into cells. * * Any error at the boundaries is disasterous and hard to detect. * * Results may depend on machine-dependant rounding etc. * ******************************************************************************/ int cellbin(rc, nc, eps) double rc, eps; int nc; { int ibin; if(rc < -0.5+eps || rc >= 0.5-eps) { if(rc < -0.5+eps && rc >= -0.5-eps) rc = -0.5; else if(rc >= 0.5-eps && rc <= 0.5+eps) rc = 0.5-eps; else message(NULLI, NULLP, ERROR, "Co-ordinate out of range in BIN (fill_cells) %.17g\n",rc); } if( (ibin = ((rc+0.5)*nc)) >= nc || ibin < 0) message(NULLI, NULLP, ERROR, "Rounding problem in BIN (fill_cells) %.17g\n",rc); return ibin; } /****************************************************************************** ******************************************************************************/ #ifdef DEBUG2 #define NBINS 200 static int bins[NBINS]; hist(jmin, jmax, rr) int jmin, jmax; real rr[]; { double rbin = 10.0; int j; for(j = jmin; j < jmax; j++) if(rr[j] < SQR(NBINS/rbin)) bins[(int)(rbin*sqrt(rr[j]))]++; } void histout() { int j; for(j = 0; j < NBINS; j++) { printf("%d%c",bins[j],(j+1)%10?' ':'\n'); bins[j] = 0; } } #endif /****************************************************************************** * Neighbour_list. Build the list of cells within cutoff radius of cell 0 * ******************************************************************************/ static ivec_mt *neighbour_list(nnabor, h, cutoff, nx, ny, nz, icheck) int *nnabor; mat_mt h; double cutoff; int nx, ny, nz; int icheck; { double dist; int i, j, ix, iy, iz, mx, my, mz, inabor = 0, nnab; static int onabor=0; ivec_mt *nabor; vec_mt s; mat_mt G, htr, htrinv; transpose(h, htr); mat_mul(htr, h, G); invert(htr, htrinv); mx = ceil(cutoff*nx*moda(htrinv)); my = ceil(cutoff*ny*modb(htrinv)); mz = ceil(cutoff*nz*modc(htrinv)); nnab = 4*mx*my*mz; nabor = aalloc(nnab, ivec_mt); #ifdef DEBUG1 printf(" Distance ix iy iz sx sy sz\n"); #endif for(ix = 0; ix < mx; ix++) for(iy = (ix == 0 ? 0 : -my); iy < my; iy++) for(iz = (ix == 0 && iy == 0 ? 0 : -mz); iz < mz; iz++) { s[0] = (double)ix/nx; s[1] = (double)iy/ny; s[2] = (double)iz/nz; dist = 0.0; for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) dist += s[i]*G[i][j]*s[j]; if(dist < SQR(cutoff)) { if( inabor >= nnab ) message(NULLI, NULLP, FATAL, "Internal error in neighbour_list()"); nabor[inabor].i = ix; nabor[inabor].j = iy; nabor[inabor].k = iz; inabor++; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", dist,ix,iy,iz,s[0],s[1],s[2]); #endif } } if( icheck ) { if( inabor != onabor ) note(NABORS,2 * inabor); onabor = inabor; } *nnabor = inabor; return(nabor); } /****************************************************************************** * Strict_Neighbour_list. Build the list of cells within cutoff radius * * This is the strict version and includes every cell which has an interior * * point at a distance less than the cutoff from any interior point of the * * reference cell. In fact the distance criterion is cutoff+2*(maximum mol- * * ecular radius). This ensures that all *sites* which might be closer to- * * gether than the cutoff are included. * * The method used is based on the fact that the closest interior points * * of a pair of parallelopiped cells are either at corners of both cells or * * at the ends of a line perpendicular to the faces of both parallelopipeds. * * The face-face distance is always the shortest, if the perpendicular * * projection of the faces onto a common plane intersect with each other * * The goal is therefore to build a list containing all cells which have a * * corner-corner or face-face distance to the reference cell which is less * * than the cutoff. * * Cells may be admitted to the list by multiple corner-corner or face-face * * contact criteria but must only be recorded in the final list once. The * * easiest way to do this is to use a "map" of all the cells potentially * * within the cutoff radius and to flag occupancy. * * It is easier to loop over all grid vectors within the cutoff and assign * * cells which have that vector as some corner-corner vector with the * * reference cell, rather than to loop over cells and calculate all corner * * pair distances. This method calculates each distance only once instead * * of 27 times (the number of distinct corner-corner vectors between 2 * * cells). * * To exploit Newton's third law the list should contain only the positive * * hemisphere (in the x direction). * * * * The algorithm is as follows. * * 1) Set up an empty "map" * * 2) Loop over all points on a grid with points at the link-cell corners * * choose only points which are closer to the origin than the cutoff. * * Set the occupancy flag for all cells which have that as a corner-pair * * vector to the reference cell. This is a 3x3x3 block of cells centred * * on the cell whose index is the same as the gridpoint being considered. * * Because we only want the "positive x" cells 2x3x3 will suffice. * * 3) Add cells which have a perpendicular face-face separation within the * * cutoff. Only the outermost cells need be considered since inner ones * * are already admitted by corner-pair distance. Thus * * 3a) project the facing corner points of the reference cell onto the * * plane just within the cutoff. * * 3b) add the cells with faces which overlap the projection. Zero, two * * or four cells are added depending on whether the projected points * * coincide with the corner points, the edges or none of the faces. * * 4) The final list is built by scanning the map. * ******************************************************************************/ static ivec_mt *strict_neighbour_list(nnabor, h, cutoff, nx, ny, nz, icheck) int *nnabor; mat_mt h; double cutoff; int nx, ny, nz; int icheck; { double dist; int i, j, k, ix, iy, iz, mx, my, mz, inabor = 0, nnab; static int onabor=0; int ***cellmap; ivec_mt *nabor; vec_mt s; mat_mt G, htr, htrinv; int face_cells[4][3],mxyz[3], nxyz[3], ixyz, jxyz, kxyz; double proj[3], modabc; transpose(h, htr); mat_mul(htr, h, G); invert(htr, htrinv); mx = ceil(cutoff*nx*moda(htrinv)); my = ceil(cutoff*ny*modb(htrinv)); mz = ceil(cutoff*nz*modc(htrinv)); /* * Allocate and clear array for map of cells */ nnab = 4*(mx+1)*(my+1)*(mz+1); cellmap = (int***)arralloc((size_mt)sizeof ***cellmap, 3, 0, mx, -my-1, my, -mz-1, mz); memst(cellmap[0][-my-1]-mz-1,0, nnab*sizeof ***cellmap); /* * Add cells with corner-pair distances < cutoff */ #ifdef DEBUG1 printf(" Distance ix iy iz sx sy sz\n"); #endif for(ix = 0; ix < mx; ix++) for(iy = (ix == 0 ? 0 : -my); iy < my; iy++) for(iz = (ix == 0 && iy == 0 ? 0 : -mz); iz < mz; iz++) { s[0] = (double)ix/nx; s[1] = (double)iy/ny; s[2] = (double)iz/nz; dist = 0.0; for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) dist += s[i]*G[i][j]*s[j]; if(dist < SQR(cutoff)) { for(i=0; i<=1; i++) for(j = -1; j <= 1; j++) for(k = -1; k <= 1; k++) cellmap[ix+i][iy+j][iz+k] = 1; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", dist,ix,iy,iz,s[0],s[1],s[2]); #endif } } /* * Add cells with face-face distance < cutoff. Cells along x,y,z axes * are added in +/- directions, but only +ve ix indices added to map. */ nxyz[0] = nx; nxyz[1] = ny; nxyz[2] = nz; mxyz[0] = mx; mxyz[1] = my; mxyz[2] = mz; for( ixyz=0; ixyz < 3; ixyz++) /* Loop over directions */ { jxyz = (ixyz+1) % 3; kxyz = (jxyz+1) % 3; proj[0] = proj[1] = proj[2] = 0.0; modabc = 0.0; for( i=0; i<3; i++ ) { modabc += htrinv[i][ixyz]; proj[i] += htrinv[i][ixyz]*htrinv[i][(ixyz+i) % 3]; } for( i=0; i<3; i++ ) proj[i] *= (mxyz[ixyz]-1)*nxyz[i]/(nxyz[ixyz] * modabc); /* * proj now contains projection vector. Construct 4 candidate * cells. */ for( i=0; i<3; i++ ) face_cells[0][i] = face_cells[1][i] = face_cells[2][i] = face_cells[3][i] = floor(proj[i]); face_cells[0][ixyz] = face_cells[1][ixyz] = face_cells[2][ixyz] = face_cells[3][ixyz] = mxyz[ixyz]; face_cells[1][jxyz] = face_cells[3][jxyz] = ceil(proj[jxyz]); face_cells[2][kxyz] = face_cells[3][kxyz] = ceil(proj[kxyz]); /* * Now make sure we add only cells with +ve x index. Add the * inverse cell if ix<0. */ for( i=0; i < 4; i++) if( face_cells[i][0] < 0 ) for( j=0; j<3; j++ ) face_cells[i][j] = -face_cells[i][j]; /* * Now add the cells to the map. */ for( i=0; i < 4; i++ ) { cellmap[face_cells[i][0]][face_cells[i][1]][face_cells[i][2]] = 1; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", 0.5,face_cells[i][0],face_cells[i][1],face_cells[i][2], 0.0,0.0,0.0); #endif } } /* * Scan map and build list. N.B. Loop indices are 1 greater than when * list built since we added cells outside original loop limits. */ nabor = aalloc(nnab, ivec_mt); for(ix = 0; ix <= mx; ix++) for(iy = (ix == 0 ? 0 : -my-1); iy <= my; iy++) for(iz = (ix == 0 && iy == 0 ? 0 : -mz-1); iz <= mz; iz++) { if( cellmap[ix][iy][iz] ) { if( inabor >= nnab ) message(NULLI, NULLP, FATAL, "Internal error in neighbour_list()"); nabor[inabor].i = ix; nabor[inabor].j = iy; nabor[inabor].k = iz; inabor++; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", 1.0,ix,iy,iz,0.0,0.0,0.0); #endif } } if( icheck ) { if( inabor != onabor ) note(NABORS,2 * inabor); onabor = inabor; } *nnabor = inabor; afree((gptr*)cellmap); return(nabor); } /****************************************************************************** * Fill_cells. Allocate all the sites to cells depending on their centre of * * mass co-ordinate by binning. * ******************************************************************************/ static void fill_cells(c_of_m, nmols, site, species, h, nx, ny, nz, lst, cell, frame_type) vec_mt c_of_m[]; /* Centre of mass co-ords (in) */ int nmols; /* Number of molecules (in) */ real **site; /* Atomic site co-ordinates (in) */ spec_mp species; /* Pointer to species array (in) */ mat_mt h; /* Unit cell matrix (in) */ int nx, ny, nz; cell_mt *lst; /* Pile of cell structs (in) */ cell_mt *cell[]; /* Array of cells (assume zeroed)(out)*/ int *frame_type; /* Framework type counter (out)*/ { int icell, imol, im=0, is, isite = 0; double eps = 8.0*precision(); spec_mp spec = species; cell_mt *list = lst; vec_mt ssite; mat_mt hinv; *frame_type=1; invert(h, hinv); for(imol = 0, im = 0; imol < nmols; imol++, im++) { if(im == spec->nmols) { im = 0; spec++; } if( spec->framework ) { for( is = 0; is < spec->nsites; is++) { ssite[0] = site[0][isite]; ssite[1] = site[1][isite]; ssite[2] = site[2][isite]; mat_vec_mul(hinv, (vec_mt*)ssite, (vec_mt*)ssite, 1); icell = LOCATE(ssite, eps); list->isite = isite++; list->num = 1; list->frame_type = *frame_type; list->next = cell[icell]; cell[icell] = list++; list->next = NULL; } (*frame_type)++; } else { icell = LOCATE(c_of_m[imol], eps); list->isite = isite; list->num = spec->nsites; list->frame_type = 0; list->next = cell[icell]; cell[icell] = list++; list->next = NULL; isite += spec->nsites; } } } /****************************************************************************** * site_neightbour list. Build the list of sites withing interaction radius * * from the lists of sites in cells. * ******************************************************************************/ int site_neighbour_list(nab, reloc, n_nab_sites, nfnab, n_frame_types, n_nabors, ix, iy, iz, nx, ny, nz, nabor, cell) int *nab; /* Array of sites in list (out) */ rvec_mt reloc[]; /* Relocation indices for list (out) */ int n_nab_sites; /* Size of above arrays (in) */ int nfnab[]; /* N frame sites index by type (out) */ int n_frame_types; /* Number of distinct frameworks(in) */ int n_nabors; /* Number of neighbour cells (in) */ int ix, iy, iz, nx, ny, nz; /* Labels of current cell (in) */ ivec_mt *nabor; /* List of neighbour cells (in) */ cell_mt **cell; /* Head of cell list (in) */ { int jx, jy, jz; /* Labels of cell in neighbour list */ int j0, jnab, jsite; /* Counters for cells etc */ int nnab = 0; /* Counter for size of nab */ int ftype; cell_mt *cmol; /* Pointer to current cell element */ #ifndef VECTOR /* * Usual version for scalar machines. */ irvec_mt *ifl = ifloor; real ri, rj, rk; int jcell; nnab = 0; for(ftype = 0; ftype < n_frame_types; ftype++) /* Do Framework types first */ { j0 = (ftype == 0) ? 0: 1; for(jnab = j0; jnab < n_nabors; jnab++) /* Loop over neighbour cells */ { jx = ix + nabor[jnab].i; /* jx-jz are indices of neighbour cell*/ jy = iy + nabor[jnab].j; jz = iz + nabor[jnab].k; ri = ifl[jx].x; /* Compute PBC relocation vector - */ jx -= ifl[jx].i; /* Actually we use a lookup table for speed. */ rj = ifl[jy].y; /* Ifl[] contains integer and real versions */ jy -= ifl[jy].j; /* of value since conversions are expensive. */ rk = ifl[jz].z; /* Float value is floor(jx/nx). */ jz -= ifl[jz].k; /* Int value is nx*floor(jx/nx). */ jcell = NCELL(jx,jy,jz); #ifdef DEBUG1 if(jx<0 || jx>=nx || jy<0 || jy>=ny || jz<0 || jz>=nz) message(NULLI,NULLP,FATAL,"Bounds error on reloc (%d,%d,%d)",jx,jy,jz); #endif /* Loop over molecules in this cell, filling 'nab' with its sites */ for(cmol = cell[jcell]; cmol != 0; cmol = cmol->next) { if( cmol->frame_type == ftype ) { for(jsite = 0; jsite < cmol->num; jsite++) { nab[nnab] = cmol->isite + jsite; reloc[nnab].i = ri; reloc[nnab].j = rj; reloc[nnab].k = rk; nnab++; } } if(nnab > n_nab_sites) message(NULLI,NULLP,FATAL,TONAB,nnab,n_nab_sites); } } nfnab[ftype] = nnab; } #else /* * Version optimized for vector machines, particularly Cray PVP */ int ti,tj,tk; static int nnarray = 0; static real *ri, *rj, *rk; static int *jcell; if( n_nabors > nnarray ) { /* * Malloc workspace arrays. Keep them around and only deallocate if * required size changes. */ if (ri) { xfree(ri); xfree(jcell); } ri = dalloc(3*n_nabors); rj = ri + n_nabors; rk = rj + n_nabors; jcell = ialloc(n_nabors); nnarray = n_nabors; } nnab = 0; for(jnab = 0; jnab < n_nabors; jnab++) /* Loop over neighbour cells */ { jx = ix + nabor[jnab].i; /* jx-jz are indices of neighbour cell*/ jy = iy + nabor[jnab].j; jz = iz + nabor[jnab].k; ri[jnab] = ti = IFLOOR(jx,nx); rj[jnab] = tj = IFLOOR(jy,ny); rk[jnab] = tk = IFLOOR(jz,nz); jcell[jnab] = NCELL(jx-ti*nx,jy-tj*ny,jz-tk*nz); #ifdef DEBUG1 if(jx<0 || jx>=nx || jy<0 || jy>=ny || jz<0 || jz>=nz) message(NULLI,NULLP,FATAL,"Bounds error on reloc (%d,%d,%d)",jx,jy,jz); #endif } for(ftype = 0; ftype < n_frame_types; ftype++) /* Do Framework types first */ { j0 = (ftype == 0) ? 0: 1; for(jnab = j0 ; jnab < n_nabors; jnab++) /* Loop over neighbour cells */ { /* Loop over molecules in this cell, filling 'nab' with its sites */ for(cmol = cell[jcell[jnab]]; cmol != 0; cmol = cmol->next) { if( cmol->frame_type == ftype) { for(jsite = 0; jsite < cmol->num; jsite++) { nab[nnab] = cmol->isite + jsite; reloc[nnab].i = ri[jnab]; reloc[nnab].j = rj[jnab]; reloc[nnab].k = rk[jnab]; nnab++; } } } } if(nnab > n_nab_sites) message(NULLI,NULLP,FATAL,TONAB,nnab,n_nab_sites); nfnab[ftype] = nnab; } #endif return nnab; } /****************************************************************************** * Force_calc. This is the main intermolecular site force calculation * * routine * ******************************************************************************/ void force_calc(site, site_force, system, species, chg, potpar, pe, stress) real **site, /* Site co-ordinate arrays (in) */ **site_force; /* Site force arrays (out) */ system_mt *system; /* System struct (in) */ spec_mt species[]; /* Array of species records (in) */ real chg[]; /* Array of site charges (in) */ pot_mt potpar[]; /* Array of potential parameters (in) */ double *pe; /* Potential energy (out) */ mat_mt stress; /* Stress virial (out) */ { int isite, imol, i, /* Site counter i,j */ i_id, ipot; /* Miscellaneous */ int n_frame_types; /* ==1 for no fw, 2 if fw present. */ int nsites = system->nsites,/* Local copy to keep optimiser happy */ n_potpar = system->n_potpar, max_id = system->max_id; double mol_diam = 2.0*mol_radius(species, system->nspecies), cutoff = control.cutoff + (control.strict_cutoff?mol_diam:0); double reloc_lim = MAX(cutoff, control.limit+mol_diam); double subcell = control.subcell; /* Local copy. May change it. */ int *id = ialloc(nsites), /* Array of site_id[nsites] */ *id_ptr; /* Pointer to 'id' array */ int n_nab_sites = nsites* /* Dimension of site n'bor list arrays*/ #ifdef DEBUG2 MAX(1.0,NMULT*4.19*CUBE(cutoff)/det(system->h)); #else NMULT*4.19*CUBE(cutoff)/det(system->h); #endif ivec_mt *nabor, *rdf_nabor; /* Lists of neighbour cells */ int n_nabors, n_rdf_nabors; /* Number of elements in lists. */ int icell, ncells; /* Subcell counter and total = nxnynz */ int n_cell_list; /* Size of link-cells "heap" */ int nx, ny, nz, nmax; /* Number of subcells in MD cell */ static int onx=0, ony=0, onz=0; /* Saved values of nx, ny, nz. */ static int mmax; /* Saved offset of ifloor for free(). */ int mx, my, mz; /* Limits for ifloor array. */ real ***potp /* Expanded potential parameter array */ = (real***)arralloc((size_mt)sizeof(real), 3, P0,max_id-1, 0, n_potpar-1, 0, nsites-1); cell_mt *c_ptr; /* Heap of link cell entries for list */ cell_mt **cell; /* Array of list heads for subcells */ spec_mt *spec; /* Temp. loop pointer to species. */ mat_mt htr, htrinv; /* Transpos and inverse of h matrix */ #ifdef DEBUG2 double ppe, rr[3], ss[3]; int im, is, i; mat_mp h = system->h; mat_mt hinv; #endif /* * Choose a partition into subcells if none specified. */ if(subcell <= 0.0) subcell = control.cutoff/5.0; nx = system->h[0][0]/subcell+0.5; ny = system->h[1][1]/subcell+0.5; nz = system->h[2][2]/subcell+0.5; ncells = nx*ny*nz; if( nx != onx || ny != ony || nz != onz ) { note("MD cell divided into %d subcells (%dx%dx%d)",ncells,nx,ny,nz); onx = nx; ony = ny; onz = nz; /* * Allocate and fill lookup tables for floor(jx/nx) etc. */ if( ifloor ) xfree(ifloor-mmax); transpose(system->h, htr); invert(htr, htrinv); mx = (int)ceil(reloc_lim*nx*moda(htrinv))+1; my = (int)ceil(reloc_lim*ny*modb(htrinv))+1; mz = (int)ceil(reloc_lim*nz*modc(htrinv))+1; mmax = MAX3(mx, my, mz); nmax = MAX3(nx, ny, nz); ifloor = aalloc(2*mmax+nmax, irvec_mt)+mmax; for(i = -mmax; i < mmax+nmax; i++) { ifloor[i].x = IFLOOR(i,nx); ifloor[i].y = IFLOOR(i,ny); ifloor[i].z = IFLOOR(i,nz); ifloor[i].i = nx*IFLOOR(i,nx); ifloor[i].j = ny*IFLOOR(i,ny); ifloor[i].k = nz*IFLOOR(i,nz); } } /* * Construct and fill expanded site-identifier array, id */ id_ptr = id; for (spec = species; spec < species+system->nspecies; spec++) for(imol = 0; imol < spec->nmols; imol++) { memcp(id_ptr, spec->site_id, spec->nsites*sizeof(int)); id_ptr += spec->nsites; } /* * Build arrays of pot. pars [max_id][nsites] for access in vector loops */ for(ipot = 0; ipot < n_potpar; ipot++) for(i_id = 1; i_id < max_id; i_id++) { #ifdef titan NOVECTOR #endif for(isite = 0; isite < nsites; isite++) potp[i_id][ipot][isite] = potpar[i_id*max_id+id[isite]].p[ipot]; } /* * Allocate "heap" of list entries to build linked lists from. */ n_cell_list = 1; for(spec = species; spec < species+system->nspecies; spec++) if( spec->framework ) n_cell_list += spec->nmols*spec->nsites; else n_cell_list += spec->nmols; c_ptr = aalloc(n_cell_list, cell_mt); /* * Build a linked list of molecules/sites for each subcell. * "cell" is the array of list heads NX x NY x NZ. */ cell = aalloc(ncells, cell_mt *); for( icell=0; icell < ncells; icell++) cell[icell] = NULL; fill_cells(system->c_of_m, system->nmols, site, species, system->h, nx, ny, nz, c_ptr, cell, &n_frame_types); if( n_frame_types > 2 ) message(NULLI, NULLP, FATAL, "Multiple framework molecules are not supported"); /* * Build lists of cells within cutoff of reference cell. */ if( control.strict_cutoff ) nabor = strict_neighbour_list(&n_nabors, system->h, cutoff, nx, ny, nz, 1); else nabor = neighbour_list(&n_nabors, system->h, cutoff, nx, ny, nz, 1); #ifdef DEBUG2 ppe = 0; spec = species; isite = 0; invert(h, hinv); for(imol = 0, im = 0; imol < system->nmols; imol++, im++) { if(im == spec->nmols) { im = 0; spec++; } for(is = isite; is < isite+spec->nsites; is++) { for(jsite = 0; jsite < isite; jsite++) { for( i=0; i<3; i++) rr[i] = site[i][jsite] - site[i][is]; mat_vec_mul(hinv, rr, ss, 1); for( i=0; i<3; i++) ss[i] -= floor(ss[i]+0.5); mat_vec_mul(h, ss, rr, 1); r_sqr[jsite] = SUMSQ(rr); if( control.strict_cutoff && r_sqr[jsite] > cutoffsq ) r_sqr[jsite] = cutoff100sq; } hist(0,isite,r_sqr); kernel(0,isite,forceij,&ppe,r_sqr,chg,chg[is], norm,control.alpha,system->ptype,potp[id[is]]); } isite += spec->nsites; } histout(); note("Direct pot. energy = %g",ppe*CONV_E); #endif force_inner(ithread, nthreads, site, chg, potp, id, n_nab_sites, n_nabors, nabor, nx, ny, nz, cell, n_frame_types, system, stress, pe, site_force); /* * Accumulate radial distribution functions */ if (control.rdf_interval > 0 && control.istep >= control.begin_rdf && control.istep % control.rdf_interval == 0) { n_nab_sites = nsites* NMULT*4.19*CUBE(control.limit+mol_diam)/det(system->h); rdf_nabor = strict_neighbour_list(&n_rdf_nabors, system->h, control.limit+mol_diam, nx, ny, nz, 0); rdf_inner(ithread, nthreads, site, id, n_nab_sites, n_rdf_nabors, rdf_nabor, nx, ny, nz, cell, n_frame_types, system); xfree(rdf_nabor); } #ifdef DEBUG2 histout(); #endif afree((gptr*)(potp+P0)); xfree(c_ptr); xfree(cell); xfree(id); xfree(nabor); } /****************************************************************************** * Force_inner() Paralellised inner loops of force_calc. Loops over cells * * in MD cell with stride = nomber of processors available. Should be * * called once for each parallel thread. * ******************************************************************************/ void force_inner(ithread, nthreads, site, chg, potp, id, n_nab_sites, n_nabors, nabor, nx, ny, nz, cell, n_frame_types, system, stress, pe, site_force) int ithread, nthreads; /* Parallel node variables. (in) */ real **site; /* Site co-ordinate arrays (in) */ real chg[]; /* Array of site charges (in) */ real ***potp; /* Expanded potential parameter array */ int id[]; /* Array of site_id[nsites] (in) */ int n_nab_sites; /* Dimension of site n'bor list arrays*/ int n_nabors; /* Number of elements in lists. (in)*/ ivec_mt *nabor; /* Lists of neighbour cells (in)*/ int nx, ny, nz; /* Number of subcells in MD cell (in)*/ cell_mt **cell; /* Array of list heads of subcells(in)*/ int n_frame_types; /* ==1 for no fw, 2 if fw present (in)*/ system_mt *system; /* System struct (in) */ mat_mt stress; /* Stress virial (out) */ double *pe; /* Potential energy (out) */ real **site_force; /* Site force arrays (out) */ { /* * The following arrays are for 'neighbour site list' * quantities and should be dimensioned to the max value of * 'nnab'. A rough approx is the ratio of the volume of * the "cutoff sphere" to that of the MD cell times nsites. * This may be too small for inhomogeneous systems, but at * least it scales with the cutoff radius. */ int *nab = ialloc(n_nab_sites); /* Neigbour site gather vector*/ rvec_mt *reloc = aalloc(n_nab_sites, rvec_mt); /* Site PBC shifts */ real *nab_sx = dalloc(n_nab_sites), /* 'Gathered' list of */ *nab_sy = dalloc(n_nab_sites), /* neighbour site co-ords */ *nab_sz = dalloc(n_nab_sites), /* - x,y,z components. */ *forcejx = dalloc(n_nab_sites), /* List of neighbour site */ *forcejy = dalloc(n_nab_sites), /* forces in gathered form */ *forcejz = dalloc(n_nab_sites), /* - xyz components. */ *rx = dalloc(n_nab_sites), /* Reference to neigbour site */ *ry = dalloc(n_nab_sites), /* - site vector adjusted for */ *rz = dalloc(n_nab_sites), /* periodic boundaries. xyz. */ *r_sqr = dalloc(n_nab_sites), /* Squared site-site distance */ *nab_chg = dalloc(n_nab_sites), /* Gathered neig. site charges*/ *forceij = dalloc(n_nab_sites); /* -V'(r) / r */ real **nab_pot /* Gathered pot par array */ = (real**)arralloc((size_mt)sizeof(real), 2, 0, system->n_potpar-1, 0, n_nab_sites-1); real **pp, **ppp; /* Loop pointer variables for potp. */ real force_cpt, site0, site1, site2, s00, s01, s02, s11, s12, s22; /* Accumulators for forces and stresses. */ real rrx, rry, rrz; /* Scalar loop temporaries */ real h00, h01, h02, h11, h12, h22; /* Temp copies of system->h */ double norm = 2.0*control.alpha/sqrt(PI); /* Coulombic prefactor*/ double cutoffsq = SQR(control.cutoff), /* Temporary copy for optim'n */ cutoff100sq = 10000.0*cutoffsq; int ix, iy, iz; /* 3-d cell indices for ref and neig. */ int icell, /* Index for cells of molecule pair */ nnab, jbeg, jmin, jmax, /* Number of sites in neighbour list */ isite, jsite, ipot, lim;/* Counters. */ int nsites = system -> nsites; /* Temporary copy for optim'n */ int nfnab[2]; /* Number of non-fw and fw neighbours */ cell_mt *cmol; /* Loop counter for link cells. */ s00 = s01 = s02 = s11 = s12 = s22 = 0.0; /* Accumulators for stress */ /****************************************************************************** * Start of main loop over all subcells. * * First build "site neighbour list" containing all sites belonging to * * molecules in this subcell and all others in the cell neighbour list. * * Use "gather" to construct corresponding arrays of co-ordinates, charges * * and potential parameters. * * Then loop over all sites in THIS cell and calculate pair distances, * * potential forces and stress. * ******************************************************************************/ for( icell = ithread; icell < nx*ny*nz; icell += nthreads) { if(cell[icell] == NULL) continue; /* Empty cell - go on to next */ ix = icell/ (ny*nz); iy = icell/nz - ny*ix; iz = icell - nz*(iy + ny*ix); nnab = 0; #ifdef DEBUG1 printf("Working on cell %4d (%d,%d,%d) (sites %4d to %4d)\n", icell, ix,iy,iz,cell[icell]->isite,cell[icell]->isite+cell[icell]->num-1); printf("\n jcell\tjx jy jz\tNsites\n"); #endif /* * Build site neighbour list 'nab' from cell list. */ nnab = site_neighbour_list(nab, reloc, n_nab_sites, nfnab, n_frame_types, n_nabors, ix, iy, iz, nx, ny, nz, nabor, cell); #ifdef DEBUG4 for(jsite=0; jsiteh[0][0]; h01 = system->h[0][1]; h02 = system->h[0][2]; h11 = system->h[1][1]; h12 = system->h[1][2]; h22 = system->h[2][2]; VECTORIZE for(jsite=0; jsitenext) { if( cmol->frame_type ) { jmin = 0; jmax = nfnab[0]; } else { jmin = jbeg += cmol->num; jmax = nnab; } lim = cmol->isite + cmol->num; for(isite = cmol->isite; isite < lim; isite++) { /* Loop over sites in molecule */ /* * Construct pot'l param arrays corresponding to neighbour sites. */ pp = potp[id[isite]]; ppp = nab_pot; for(ipot = 0; ipot < system->n_potpar; ipot++) { gather(jmax, *ppp++, *pp++, nab, nsites); } #ifdef DEBUG1 if(isite == 100) #endif #if defined(DEBUG1) || defined(DEBUG5) { int jnab; for(jnab = jmin; jnab < jmax; jnab++) printf("%4d %4d\n", jnab,nab[jnab]); } #endif site0=site[0][isite]; site1=site[1][isite]; site2=site[2][isite]; VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { rrx = nab_sx[jsite] - site0; rry = nab_sy[jsite] - site1; rrz = nab_sz[jsite] - site2; r_sqr[jsite] = rrx*rrx+rry*rry+rrz*rrz; rx[jsite] = rrx; ry[jsite] = rry; rz[jsite] = rrz; } if( (jsite = jmin+search_lt(jmax-jmin, r_sqr+jmin, 1, TOO_CLOSE)) < jmax ) message(NULLI, NULLP, WARNING, TOOCLS, isite, nab[jsite], sqrt(TOO_CLOSE)); if( control.strict_cutoff ) for(jsite = jmin; jsite < jmax; jsite++) if( r_sqr[jsite] > cutoffsq ) r_sqr[jsite] = cutoff100sq; #ifdef DEBUG2 hist(jmin, jmax, r_sqr); #endif /* Call the potential function kernel */ kernel(jmin, jmax, forceij, pe, r_sqr, nab_chg, chg[isite], norm, control.alpha, system->ptype, nab_pot); site0 = site1 = site2 = 0.0; VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { force_cpt = forceij[jsite]*rx[jsite]; s00 += force_cpt * rx[jsite]; s02 += force_cpt * rz[jsite]; s01 += force_cpt * ry[jsite]; site0 -= force_cpt; forcejx[jsite] += force_cpt; } VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { force_cpt = forceij[jsite]*ry[jsite]; s11 += force_cpt * ry[jsite]; s12 += force_cpt * rz[jsite]; site1 -= force_cpt; forcejy[jsite] += force_cpt; } VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { force_cpt = forceij[jsite]*rz[jsite]; s22 += force_cpt * rz[jsite]; site2 -= force_cpt; forcejz[jsite] += force_cpt; } site_force[0][isite] += site0; site_force[1][isite] += site1; site_force[2][isite] += site2; #ifdef DEBUG3 printf("PE = %f\n",pe[0]); #endif } } spxpy(nnab, forcejx, site_force[0], nab); spxpy(nnab, forcejy, site_force[1], nab); spxpy(nnab, forcejz, site_force[2], nab); } stress[0][0] += s00; stress[0][1] += s01; stress[0][2] += s02; stress[1][1] += s11; stress[1][2] += s12; stress[2][2] += s22; afree((gptr*)nab_pot); xfree(nab); xfree(reloc); xfree(nab_chg); xfree(r_sqr); xfree(forceij); xfree(rx); xfree(ry); xfree(rz); xfree(forcejx); xfree(forcejy); xfree(forcejz); xfree(nab_sx); xfree(nab_sy); xfree(nab_sz); } /****************************************************************************** * Rdf_inner() Paralellised inner loops of force_calc. Based on force_inner * * but only calls rdf_accum(). * ******************************************************************************/ void rdf_inner(ithread, nthreads, site, id, n_nab_sites, n_nabors, nabor, nx, ny, nz, cell, n_frame_types, system) int ithread, nthreads; /* Parallel node variables. (in) */ real **site; /* Site co-ordinate arrays (in) */ int id[]; /* Array of site_id[nsites] (in) */ int n_nab_sites; /* Dimension of site n'bor list arrays*/ int n_nabors; /* Number of elements in lists. (in)*/ ivec_mt *nabor; /* Lists of neighbour cells (in)*/ int nx, ny, nz; /* Number of subcells in MD cell (in)*/ cell_mt **cell; /* Array of list heads of subcells(in)*/ int n_frame_types; /* ==1 for no fw, 2 if fw present (in)*/ system_mt *system; /* System struct (in)*/ { int *nab = ialloc(n_nab_sites); /* Neigbour site gather vector*/ rvec_mt *reloc = aalloc(n_nab_sites, rvec_mt); /* Site PBC shifts */ real *nab_sx = dalloc(n_nab_sites), /* 'Gathered' list of */ *nab_sy = dalloc(n_nab_sites), /* neighbour site co-ords */ *nab_sz = dalloc(n_nab_sites), /* - x,y,z components. */ *r_sqr = dalloc(n_nab_sites); /* Squared site-site distance */ real site0, site1, site2; real rrx, rry, rrz; /* Scalar loop temporaries */ real h00, h01, h02, h11, h12, h22; /* Temp copies of system-> h */ int ix, iy, iz; /* 3-d cell indices for ref and neig. */ int icell, /* Index for cells of molecule pair */ nnab, jbeg, jmin, jmax, /* Number of sites in neighbour list */ isite, jsite, lim; /* Counters. */ int nsites = system -> nsites; /* Temporary copy for optim'n */ int nfnab[2]; /* Number of non-fw and fw neighbours */ cell_mt *cmol; /* Loop counter for link cells. */ /****************************************************************************** * Start of main loop over subcells. * ******************************************************************************/ for( icell = ithread; icell < nx*ny*nz; icell += nthreads) { if(cell[icell] == NULL) continue; /* Empty cell - go on to next */ ix = icell/ (ny*nz); iy = icell/nz - ny*ix; iz = icell - nz*(iy + ny*ix); /* * Build site neighbour list 'nab' from cell list. */ nnab = site_neighbour_list(nab, reloc, n_nab_sites, nfnab, n_frame_types, n_nabors, ix, iy, iz, nx, ny, nz, nabor, cell); gather(nnab, nab_sx, site[0], nab, nsites); /* Construct list of site */ gather(nnab, nab_sy, site[1], nab, nsites); /* co-ordinates from nabo */ gather(nnab, nab_sz, site[2], nab, nsites); /* list. */ /* * Apply periodic boundary conditions to neighbour site co-ords. * Assume h matrix is upper triangular. */ h00 = system->h[0][0]; h01 = system->h[0][1]; h02 = system->h[0][2]; h11 = system->h[1][1]; h12 = system->h[1][2]; h22 = system->h[2][2]; VECTORIZE for(jsite=0; jsitenext) { if( cmol->frame_type ) { jmin = 0; jmax = nfnab[0]; } else { jmin = jbeg += cmol->num; jmax = nnab; } lim = cmol->isite + cmol->num; for(isite = cmol->isite; isite < lim; isite++) { /* Loop over sites in molecule */ site0=site[0][isite]; site1=site[1][isite]; site2=site[2][isite]; VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { rrx = nab_sx[jsite] - site0; rry = nab_sy[jsite] - site1; rrz = nab_sz[jsite] - site2; r_sqr[jsite] = rrx*rrx+rry*rry+rrz*rrz; } /* * Accumulate radial distribution functions */ rdf_accum(jmin, jmax, r_sqr, id[isite], id, nab); } } } xfree(nab); xfree(reloc); xfree(r_sqr); xfree(nab_sx); xfree(nab_sy); xfree(nab_sz); } $EOD $! $CREATE input.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Input Functions for reading and verifying the input files (except * * the restart file). Contents: * * Strlower(); Convert a string to lowercase (Internal use only) * * Get_line(); Read next input line. (Internal use only) * * Read_sysdef() Read the system specification file * * Lattice_start() Read initial crystal structure and set it up * * Read_control() Read control file * ****************************************************************************** * Revision Log * $Log: input.c,v $ * Revision 2.9 1996/11/04 17:32:28 keith * Fixed non-ANSI compliance in get_line() which decremented pointer to * 1 element below start of array and compared with beginning. I doubt * this could ever cause a failure in reality but standards are standards. * * Revision 2.8 1995/10/25 11:59:00 keith * Fixed input parser bug which didn't notice missing "=" and silently * used incorrect value. * * Revision 2.7.1.2 1995/10/25 11:49:49 keith * Fixed input parser bug which didn't notice missing "=" and silently * used incorrect value. * * Revision 2.7.1.1 1994/12/16 12:02:34 keith * Experimental version with partial Ewald sum evaluated at rlv's only. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * * moved "match" to startup.c and passed as param. * Added check for end-of-file in 2 cases where I missed before. * * Revision 2.5 94/01/25 10:57:11 keith * Null update for XDR portability release * * Revision 2.4 94/01/25 10:56:58 keith * Changed default for "xdr" parameter to "on". * * Revision 2.3 93/10/28 10:27:52 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/07/19 13:27:53 keith * Added XDR capability for backup and dump files. * * Revision 2.0 93/03/15 14:49:08 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.8.1.21 93/03/12 12:14:14 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.8.1.21 93/03/09 15:58:36 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.8.1.20 92/10/28 14:09:48 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.8.1.19 92/09/22 14:48:15 keith * Tidied up calls to improve "lint" rating. * * Revision 1.8.1.18 92/06/26 17:03:10 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.8.1.17 92/03/11 12:56:21 keith * Changed "scale-separately" parameter to "scale options" * * Revision 1.8.1.16 91/08/19 16:46:39 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * * Revision 1.8.1.15 91/08/16 15:25:30 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.8.1.13 91/03/12 15:42:49 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.8.1.12 90/10/22 17:47:25 keith * Corrected conversion of unit cell angles and lengths to vectors * in lattice_start(). * * Revision 1.8.1.11 90/08/20 17:25:45 keith * Modified to order species so that frameworks are last. * * Revision 1.8.1.10 90/05/03 16:41:24 keith * Fixed sys-spec parsing to cope with GEC and other broken scanf's which * return too many items matched. * * Revision 1.8.1.9 90/04/16 18:18:16 keith * Added "strain-mask" field to input parse table. * * Revision 1.8.1.8 90/04/12 16:27:09 keith * Added include of which was removed from "structs.h" * * Revision 1.8.1.7 90/03/26 18:05:50 keith * Moved system-dependant backup and temp file names to "defs.h" * * Revision 1.8.1.6 89/11/22 14:34:44 keith * Changed default values of begin-rdf and average-interval. * * Revision 1.8.1.5 89/11/21 16:32:30 keith * Removed member out_file from control and all uses. (Now command parameter). * * Revision 1.8.1.4 89/11/20 18:06:23 keith * Modified form of match[] to include default values. * * Revision 1.8.1.3 89/11/20 13:30:00 keith * Replaced separate arrays "types" and "npotp" with array of structs "potspec" * * Revision 1.8.1.2 89/09/04 18:56:08 keith * Added 'surface-dipole' keyword to control file. * * Revision 1.8.1.1 89/08/30 12:55:44 keith * Mods to add framework structures to simulation model * * Revision 1.8 89/08/30 12:51:41 keith * Fixed read_sysdef() to keep original input line when reading potentials * to make error message informative. * Modified lattice_start() to fix bug which only considered rotations * of one species. In conjunction with change in startup. * * Revision 1.7 89/07/07 10:49:56 keith * Fixed lattice_start() so as not to test quaternion normalisation for * monatomic sopecies. * * Revision 1.6 89/06/26 13:55:34 keith * Tidied up loops over species to use one pointer as counter. * Incorrect code to print control params removed from read_control() * * Revision 1.5 89/06/21 13:36:42 keith * Moved pot. par. defs arrays types[], npotp[] and npott to kernel.c * Moved print_sysdef() to output.c * Made match[] external and its dimension nmatch into an external int * * Revision 1.4 89/06/16 16:56:08 keith * Corrected bug in lattice_start() which crashed for point atoms/ions * Added message for successful lattice start * * Revision 1.3 89/06/01 21:24:24 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.2 89/05/22 14:05:38 keith * Added rescale-separately option, changed 'contr_t' format. * * Revision 1.1 89/04/20 16:00:42 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/input.c,v 2.9 1996/11/04 17:32:28 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include #include #include "string.h" #include "stddef.h" #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void q_mul_1(); void zero_real(); /* Initialiser */ #if defined(ANSI) || defined(__STDC__) void message(int *, ...); /* Write a warning or error message */ #else void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control record */ extern CONST pots_mt potspec[]; /* Potential type specification */ /*========================== Macros ==========================================*/ #define LLEN 132 /* Flags to indicate status of potpar and site_info records */ #define S_USED 0x01 #define S_MASS 0x02 #define S_CHARGE 0x04 #define S_NAME 0x08 /*============================================================================= | Start of functions | =============================================================================*/ /****************************************************************************** * get_line read an input line skipping blank and comment lines * ******************************************************************************/ static char *get_line(line, len, file) char *line; int len; FILE *file; { char *s, *t; int i; do { s = fgets(line, len, file); /* Read one line of input */ if(s == NULL) break; /* exit if end of file */ i = strlen(s) - 1; while(i >= 0 && (s[i] == ' ' || s[i] == '\t' || s[i] == '\n')) s[i--] = '\0'; /* Strip trailing white space */ } while(*s == '\0' || *s == '#'); /* Repeat if blank or comment */ if(s == NULL) *line = '\0'; /* Return null at eof */ return(line); } /****************************************************************************** * strlower convert a string to lowercase anr return a pointer to it * ******************************************************************************/ char *strlower(s) char *s; { char *t; for(t = s; *t != '\0'; t++) *t = isupper(*t) ? tolower(*t) : *t; return(s); } /****************************************************************************** * Sort array of species structs so frameworks are at end. * ******************************************************************************/ static void sort_species(species, nspecies) spec_mt *species; int nspecies; { spec_mt tmp, *lo=species, *hi=species+nspecies-1; while( lo < hi ) { while( lo < hi && ! lo->framework) lo++; while( lo < hi && hi->framework) hi--; if( lo >= hi ) break; tmp = *hi; *hi = *lo; *lo = tmp; lo++; hi--; } } /****************************************************************************** * read_sysdef Read the system specification file which must be open and * * pointed to by parameter 'file'. Set up the structures system and species * * and arrays site_info and potpar (allocating space) and read in and check * * the supplied values. The reading is done in two passes. Pass 1 simply * * counts the number of species, number of sites on each species and the * * largest site identifier index in order to allocate the dynamic arrays. * * Pass 2 does the actual reading and checking. * ******************************************************************************/ void read_sysdef(file, system, spec_pp, site_info, pot_ptr) FILE *file; /* File pointer to read info from */ system_mp system; /* Pointer to system array (in main) */ spec_mp *spec_pp; /* Pointer to be set to species array */ site_mp *site_info; /* To be pointed at site_info array */ pot_mp *pot_ptr; /* To be pointed at potpar array */ { int nspecies = 0, /* Number of distinct species */ max_id = 0, /* Largest site identifier index */ id, idi, idj, /* Temp. site identifier index */ isite, /* species and site counters */ sflag, /* Temporary flag */ i, /* Counter */ n_potpar, /* Number of parameters for this pot'l*/ n_items; /* How many items scanf found in input*/ struct list_mt {int n; struct list_mt *p;};/* Template for linked list nsites*/ struct list_mt nsites_base, /* Head of list (contains no datum) */ *nsites, /* List entry for current species */ *last = &nsites_base; /* List entry for previous species */ int nerrs = 0; /* Accumulated error count */ int flag; /* Used to test 'fseek' result */ long start_pos = ftell(file);/* Rewind marker for second pass */ char name[LLEN], /* Species name temporary */ keywd[LLEN], /* Species attribute keywords */ line[LLEN], /* Store for input line from file */ pline[LLEN]; /* Used in pot'l paramater parsing */ double mass, charge, p_tmp; /* Local temporaries */ double p_f_sites[3]; /* Local temporary */ pot_mp pp1; /* Used for acces to potpar ij and ji */ spec_mp species, spec; /* Local pointer to species array */ site_mp s_ptr; /* Local pointer to site info array */ static pot_mt pot = {S_USED}; /* Local storage for potentials */ message(&nerrs,NULLP,INFO,SYSRD); /* First pass - read system definition and count nspecies, nsites, max_id */ (void)get_line(line,LLEN,file); /* Read first line. */ while(sscanf(line, "%s", name) > 0 && strcmp(strlower(name), "end") != 0) { /* Loop, parsing 'line' for */ nspecies++; /* name of new species. */ nsites = aalloc(1, struct list_mt); /* Make new list element */ last->p = nsites; /* Link it in */ last = nsites; /* Backwards pointer for link */ nsites->p=NULL; nsites->n=0; while(sscanf(get_line(line,LLEN,file), "%d", &id) > 0) { /* Loop, reading and parsing */ nsites->n++; /* for integer ie new site id.*/ max_id = MAX(max_id, id); /* Count nsites, greatest id. */ } /* Leave 'line' if parse fails*/ } if(nspecies == 0) /* Empty file?? */ message(&nerrs,NULLP,FATAL,NOSPEC); /* Allocate arrays of species and site info records */ max_id++; system->max_id = max_id; *spec_pp = aalloc(nspecies, spec_mt ); *site_info = aalloc(max_id, site_mt ); memst(*site_info, 0, max_id*sizeof(site_mt)); *pot_ptr = aalloc(SQR(max_id), pot_mt ); for( i = 0; i < SQR(max_id); i++) { (*pot_ptr)[i].flag = 0; zero_real((*pot_ptr)[i].p,NPOTP); } species = *spec_pp; /* Local pointer for neatness.*/ system->nspecies = nspecies; flag = fseek(file, start_pos, 0); /* Prepare to reread input. */ if(flag) message(NULLI, NULLP, FATAL, SEFAIL, "control file", strerror(errno)); nsites = &nsites_base; /* Pass 2. read system definition and set up species and site_info arrays */ for (spec = species; spec < species+system->nspecies; spec++) { /* Loop over all species. */ n_items = sscanf(get_line(line,LLEN,file),"%s %d %s", name, &spec->nmols, keywd); name[sizeof spec->name-1] = '\0'; /* Truncate before copying */ (void)strcpy(spec->name, name); /* to avoid overflow. */ nsites = nsites->p; /* Find next element of list */ spec->nsites = nsites->n; /* which contains nsites. */ switch(n_items) { /* Relies on fall-through: do not re-order */ case 3: if(! strcmp(strlower(keywd), "framework")) spec->framework = true; else if(*keywd != '\0') /* Kludge for broken scanf's. */ message(&nerrs, NULLP, ERROR, UNKEY, keywd); break; case 2: spec->framework = false; break; /* Normal exit from switch */ default: message(&nerrs,line, ERROR, NONUM, name); } if(spec->nmols <= 0) /* Can't have <=0 molecules */ message(&nerrs,line,ERROR, NOMOLS, spec->nmols, name); if(spec->nsites <=0) /* or ghost molecules! */ message(&nerrs,NULLP,ERROR,NOSITE,spec->nsites,name); spec->p_f_sites = ralloc(spec->nsites); /* Allocate space and set */ spec->site_id = ialloc(spec->nsites+1); /* pointers for each species. */ for(isite = 0; isite < spec->nsites; isite++) { /* Loop over sites on molecule*/ n_items =sscanf(get_line(line,LLEN,file), "%d %lf %lf %lf %lf %lf %s", &id, /* Get and parse line of input*/ p_f_sites, p_f_sites + 1, p_f_sites + 2, &mass, &charge, name); if(id <= 0) /* Test for valid site index. */ { message(&nerrs,line, ERROR, INVSID, id); id = 0; } spec->site_id[isite] = id; /* Put id into rightful place.*/ name[sizeof s_ptr->name - 1] = '\0'; /* Truncate site name. */ s_ptr = *site_info + id; /* Reference (*site_info)[id].*/ s_ptr->flag |= S_USED; switch (n_items) /* Handle input items in */ { /* reverse order. */ case 7: /* Site name supplied. */ if(s_ptr->flag & S_NAME && strcmp(name, s_ptr->name) != 0) message(&nerrs,line,ERROR,NCONF,id,s_ptr->name); else (void)strcpy(s_ptr->name, name); s_ptr->flag |= S_NAME; case 6: /* Site charge supplied. */ if(s_ptr->flag & S_CHARGE && charge != s_ptr->charge) message(&nerrs,line,ERROR,CCONF,id, s_ptr->charge); else s_ptr->charge = charge; s_ptr->flag |= S_CHARGE; case 5: /* Site mass supplied. */ if(s_ptr->flag & S_MASS && mass != s_ptr->mass) message(&nerrs,line,ERROR,MCONF,id, s_ptr->mass); else if(mass < 0.0) message(&nerrs,NULLP,ERROR,INVMAS,id,mass); else s_ptr->mass = mass; s_ptr->flag |= S_MASS; case 4: /* All site co-ordinates */ for( i = 0; i < 3; i++ ) spec->p_f_sites[isite][i] = p_f_sites[i]; break; /* Normal exit from switch */ case 3: /* One or more site */ case 2: /* co-ordinates are missing. */ case 1: message(&nerrs,line,ERROR,MISSCO,n_items-1,id); break; default: /* Should never occur. */ message(&nerrs,NULLP, FATAL, BROKEN, n_items); } } } /* * Order species structs with frameworks last */ sort_species(species, nspecies); /* * Check that all sites have been fully defined, and for gaps in ordering. */ for(id = 1; id < max_id; id++) { sflag = (*site_info)[id].flag; if(sflag & S_USED) { if(! (sflag & S_MASS)) message(&nerrs,NULLP,ERROR,NOMASS,id); if(! (sflag & S_CHARGE)) message(&nerrs,NULLP,ERROR,NOCGRG,id); if(! (sflag & S_NAME)) message(&nerrs,NULLP,ERROR,NONAME,id); } else message(&nerrs,NULLP, WARNING, NOTUSD,id); } (void)get_line(line,LLEN,file); /* read "end" -left by pass 1 */ /* Next line is keyword indicating type of potentials to be used */ n_items = sscanf(get_line(line,LLEN,file), "%s", name); if( n_items <= 0 ) message(NULLI,NULLP,FATAL,SYSEOF,"potential type specification"); for(i = 0; potspec[i].name; i++) /* Is 'name' a known type? */ if(strcmp(strlower(name), potspec[i].name) == 0) break; if(! potspec[i].name) /* Did the loop find 'name'? */ message(&nerrs,line,FATAL,UNKPOT,name); /* no */ system->ptype = i; /* yes */ n_potpar = system->n_potpar = potspec[system->ptype].npar; /* Now read in parameters */ while(sscanf(get_line(line,LLEN,file),"%s",name) > 0 && strcmp(strlower(name), "end") != 0) { n_items = 0; if(sscanf(line,"%d %d %[^#]",&idi,&idj,pline) <= 2)/* Not enough values */ message(&nerrs,line,ERROR,NOPAIR); else { /* Parse potential parameters */ (void)strcat(pline, "$"); /* Add marker to end */ while(n_items < NPOTP && sscanf(pline,"%lf %[^#]", &p_tmp, pline) > 1 ) pot.p[n_items++] = p_tmp; } if (n_items < n_potpar) message(&nerrs,line,ERROR,NOPOTP,n_potpar); else /* Test id pair and if OK store values*/ { if(idi < 1 || idi >= max_id) message(&nerrs,line,ERROR,IDOUTR,idi); if(idj < 1 || idj >= max_id) message(&nerrs,line,ERROR,IDOUTR,idj); if(!( (*site_info)[idi].flag & S_USED &&(*site_info)[idj].flag & S_USED)) message(&nerrs,line,WARNING,EXTPOT); pp1 = (*pot_ptr) + (idi + idj * system->max_id); if(pp1->flag & S_USED) /* pot'l for this id pair already set?*/ message(&nerrs,line,ERROR,DUPPOT); else /* Put values into pp1 and pp2 */ { (*pot_ptr)[idi + idj * system->max_id] = pot; (*pot_ptr)[idj + idi * system->max_id] = pot; } } } /* Check whether potentials have been defined for all 'used' site id's */ for(idi = 0; idi < max_id; idi++) for(idj = idi; idj < max_id; idj++) if( ( (*site_info)[idi].flag & S_USED /* True if sites idi, idj */ && (*site_info)[idj].flag & S_USED) /* both used but pot'l not*/ && !((*pot_ptr)[idi + max_id * idj].flag & S_USED)) message(&nerrs,NULLP,WARNING,NOPOT,idi,idj); if(nerrs > 0) /* if any errors have been detected */ message(&nerrs,NULLP,FATAL,ERRS,nerrs); else message(&nerrs,NULLP,INFO,SUCCES); } /****************************************************************************** * lattice_start Initialse the simulation co-ordinates on a lattice. Read * * from the end of the system specification file. The format is one line * * specifying the unit cell (6 x floating point + 3 x int # cells) * * a b c alpha beta gamma nx ny nz * * followed by one line for each molecule in the unit cell: * * species x y z q0 q1 q2 q3 * * 'species' is the name, x, y, z are FRACTIONAL co-ords and 4 quaternions. * ******************************************************************************/ void lattice_start(file, system, species, qpf) FILE *file; /* File to read info from */ system_mp system; /* System info struct */ spec_mp species; /* Array of species info structs */ quat_mt qpf[]; /* Princ frame rotation quaternion */ { typedef struct init_s {int species; struct init_s *next; double r[3], q[4];} init_mt; /* For linked list of coords */ init_mt *cur, *init = NULL; /* Current and header of list */ double a, b, c, calpha, cbeta, cgamma; /* Unit cell lengths, angles */ int ix, iy, iz, nx, ny, nz; /* Number of unit cells in MDC*/ spec_mp spec; char line[LLEN], name[LLEN]; int n_items, nerrs = 0, ispec, imol, i; int *nmols = ialloc(system->nspecies); real ca, cb, cg, sg; quat_mt q; memst(nmols,0,system->nspecies*sizeof(int)); n_items = sscanf(get_line(line,LLEN,file),"%lf%lf%lf%lf%lf%lf%d%d%d", &a, &b, &c, &calpha, &cbeta, &cgamma, &nx, &ny, &nz); if(n_items <= 0 ) message(NULLI, NULLP, FATAL, SYSEOF, "lattice start file"); if(n_items < 9) message(&nerrs, line, ERROR, NOCELL); if( ! (a > 0 && b > 0 && c > 0 && nx > 0 && ny > 0 && nz > 0 && calpha > 0 && calpha < 180.0 && cbeta > 0 && cbeta < 180.0 && cgamma > 0 && cgamma < 180.0)) message(&nerrs, line, ERROR, INVCEL); ca = cos(calpha*DTOR); cb = cos(cbeta*DTOR); cg = cos(cgamma*DTOR); sg = sin(cgamma*DTOR); system->h[0][0] = nx*a; /* Set up MD cell matrix */ system->h[0][1] = ny*b * cg; /* from lengths and angles. */ system->h[1][1] = ny*b * sg; system->h[0][2] = nz*c * cb; system->h[1][2] = nz*c / sg * (ca - cb*cg); system->h[2][2] = nz*c / sg * sqrt(1 - ca*ca - cb*cb - cg*cg + 2*ca*cb*cg); while(sscanf(get_line(line,LLEN,file), "%s", name) > 0 && strcmp(strlower(name), "end") != 0) /* Cycle over lines in file */ { cur =aalloc(1, init_mt ); /* Get struct for new molecule*/ cur->next = init; init = cur; /* Link it into list */ n_items = sscanf(line, "%s%lf%lf%lf%lf%lf%lf%lf", name, &cur->r[0], &cur->r[1], &cur->r[2], &cur->q[0], &cur->q[1], &cur->q[2], &cur->q[3]); if(n_items > 1) /* Have name of molecule */ { for (spec = species; spec < species+system->nspecies; spec++) if(strcmp(strlower(name),strlower(spec->name)) == 0) break; if(spec >= species+system->nspecies) /* Didn't find it */ message(&nerrs,NULLP,ERROR,UNKSPE,name); else /* Found it - check values */ { cur->species = spec-species; if(n_items < 4) message(&nerrs, line, ERROR, FEWCOO, name); if(cur->r[0] < 0 || cur->r[0] >= 1 || cur->r[1] < 0 || cur->r[1] >= 1 || cur->r[2] < 0 || cur->r[2] >= 1) message(&nerrs,NULLP,ERROR,FRACCO,cur->r[0],cur->r[1],cur->r[2]); if(species[cur->species].rdof != 0) { if( n_items < 8 ) message(&nerrs, line, ERROR, FEWQUA, name); if(fabs(1.0 - SQR(cur->q[0]) - SQR(cur->q[1]) - SQR(cur->q[2]) - SQR(cur->q[3])) > 1e-4) message(&nerrs,NULLP,ERROR,QNORM, cur->q[0],cur->q[1],cur->q[2],cur->q[3]); } nmols[cur->species] += nx*ny*nz; } } } for (spec = species; spec < species+system->nspecies; spec++) { ispec = spec-species; if(nmols[ispec] != spec->nmols) message(&nerrs,NULLP,ERROR,NIMOLS,spec->name, nmols[ispec],spec->nmols); nmols[ispec] = 0; } if(nerrs > 0) /* Is file all correct? */ message(NULLI, NULLP, FATAL, INITER, nerrs); for(cur = init; cur != NULL; cur = cur->next) { spec = species + cur->species; for(ix = 0; ix < nx; ix++) for(iy = 0; iy < ny; iy++) for(iz = 0; iz < nz; iz++) { imol = nmols[cur->species]; spec->c_of_m[imol][0] = (cur->r[0]+ix)/nx - 0.5; spec->c_of_m[imol][1] = (cur->r[1]+iy)/ny - 0.5; spec->c_of_m[imol][2] = (cur->r[2]+iz)/nz - 0.5; if(spec->rdof > 0 ) { for( i = 0; i < 4; i++ ) q[i] = cur->q[i]; /* Convert type to 'real' */ q_mul_1(q, qpf[cur->species], spec->quat[imol]); } nmols[cur->species]++; } } message(NULLI, NULLP, INFO, LATTIC); } /******************************************************************************* * assign() Convert string value by format and assign to pointer location. * ******************************************************************************/ static int assign(strval, fmt, ptr) char *strval, *fmt; gptr *ptr; { int len = strlen(fmt); int code = fmt[MAX(0,len-1)]; if( len > 2 && fmt[len-2] == 'l' ) code = toupper(code); switch(code) { case 's': case ']': return sscanf(strval, fmt, (char*)ptr); case 'd': return sscanf(strval, fmt, (int*)ptr); case 'D': return sscanf(strval, fmt, (long*)ptr); case 'f': return sscanf(strval, fmt, (float*)ptr); case 'F': return sscanf(strval, fmt, (double*)ptr); default: message(NULLI, NULLP, FATAL, "Scanf code \"%s\" not catered for", fmt); } return -1; /* This statement is never reached */ } /****************************************************************************** * read_control. Read the control parameters from the standard input. * * Input lines are of the form " key = value ", one per line. The struct * * 'match' is searched for a matching key, and if found converts the value * * according to the format string and stores it at the value of the pointer * * in 'match'. "name=" with no value means assign a null string. * ******************************************************************************/ void read_control(file,match) FILE *file; CONST match_mt *match; { char line[LLEN], name[LLEN], value[LLEN]; int n_items; int nerrs = 0; CONST match_mt *match_p; while( *get_line(line,LLEN,file) != '\0' ) { n_items = sscanf(line, " %[^= ] = %127[^#]",name, value); if(!strcmp(strlower(name),"end")) break; if( n_items < 1 ) message(&nerrs,line,ERROR,NOKEY); else { for( match_p = match; match_p->key; match_p++ ) if(! strcmp(strlower(name), match_p->key)) break; if( ! match_p->key ) /* Reached end without success*/ message(&nerrs,line,ERROR,NOTFND,name); else /* Found it, so convert value */ { if( n_items == 1 ) { if(strcmp(match_p->format,SFORM) == 0 ) *(char*)match_p->ptr = '\0'; /* name= - assign null */ else message(&nerrs,line,ERROR,NOVAL,name); } else { n_items = assign(value, match_p->format, match_p->ptr); if( n_items < 1 ) message(&nerrs,NULLP,ERROR,BADVAL,value,name); } } } } if( nerrs > 0 ) message(&nerrs,NULLP,FATAL,ERRCON,nerrs,(nerrs>1)?'s':' '); else message(&nerrs,NULLP,INFO,SUCCON); } $EOD $! $CREATE eigens.c $DECK #include #include "defs.h" /* eigens.c * * Eigenvalues and eigenvectors of a real symmetric matrix * * * * SYNOPSIS: * * int n; * double A[n*(n+1)/2], EV[n*n], E[n]; * void eigens( A, EV, E, n ); * * * * DESCRIPTION: * * The algorithm is due to J. vonNeumann. * - - * A[] is a symmetric matrix stored in lower triangular form. * That is, A[ row, column ] = A[ (row*row+row)/2 + column ] * or equivalently with row and column interchanged. The * indices row and column run from 0 through n-1. * * EV[] is the output matrix of eigenvectors stored columnwise. * That is, the elements of each eigenvector appear in sequential * memory order. The jth element of the ith eigenvector is * EV[ n*i+j ] = EV[i][j]. * * E[] is the output matrix of eigenvalues. The ith element * of E corresponds to the ith eigenvector (the ith row of EV). * * On output, the matrix A will have been diagonalized and its * orginal contents are destroyed. * * ACCURACY: * * The error is controlled by an internal parameter called RANGE * which is set to 1e-10. After diagonalization, the * off-diagonal elements of A will have been reduced by * this factor. * * ERROR MESSAGES: * * None. * */ /* Copyright 1973, 1991 by Stephen L. Moshier Copyleft version. */ void eigens( A, RR, E, N ) real A[], RR[], E[]; int N; { int IND, L, LL, LM, M, MM, MQ, I, J, K, IA, LQ; int IQ, IM, IL, NLI, NMI; real ANORM, ANORMX, AIA, THR, ALM, QI, ALL, AMM, X, Y; real SINX, SINX2, COSX, COSX2, SINCS, AIL, AIM; real RLI, RMI, Q, V; static real RANGE;/*1.0e-10; /*3.0517578e-5;*/ double precision(); RANGE=precision(); /* Initialize identity matrix in RR[] */ for( J=0; J ANORMX ) { THR=THR/N; do { /* while IND != 0 */ IND = 0; for( L=0; L M) IM=M+IQ; else IM=I+MQ; if(I >= L) IL=L+IQ; else IL=I+LQ; AIL=A[IL]; AIM=A[IM]; X=AIL*COSX-AIM*SINX; A[IM]=AIL*SINX+AIM*COSX; A[IL]=X; } NLI = N*L + I; NMI = N*M + I; RLI = RR[ NLI ]; RMI = RR[ NMI ]; RR[NLI]=RLI*COSX-RMI*SINX; RR[NMI]=RLI*SINX+RMI*COSX; } X=2.0*ALM*SINCS; A[LL]=ALL*COSX2+AMM*SINX2-X; A[MM]=ALL*SINX2+AMM*COSX2+X; A[LM]=(ALL-AMM)*SINCS+ALM*(COSX2-SINX2); } /* for M=L+1 to N-1 */ } /* for L=0 to N-2 */ } while( IND != 0 ); } /* while THR > ANORMX */ done: ; /* Extract eigenvalues from the reduced matrix */ L=0; for( J=1; J<=N; J++ ) { L=L+J; E[J-1]=A[L-1]; } } $EOD $! $CREATE kernel.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * kernel Functions to calculate the forces, potential and distant pot'l* * correction for various potentials. ALL POTENTIAL-DEPENDANT * * CODE is in this module. * * dist_pot() Return distant-potential correction * * kernel() Calculate pe and forces * * types[] Array of names of potential function types. * * npotp[] Array containing number of parameters for each type. * * npott size of above two arrays. * * Since CRAY CC 4.0 won't vectorise library function calls, a * * FORTRAN equivalent to kernel() is provided in kernel.f. To * * use it, compile force.c with macro FKERNEL defined and link * * with it AND THIS MODULE. * ****************************************************************************** * Revision Log * $Log: kernel.c,v $ * Revision 2.8 1996/10/04 17:27:24 keith * Rescheduled line order to overlap divide/computation on DEC Alpha/T3D. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/18 13:32:38 keith * Null update for XDR portability release * * Revision 2.4 94/01/13 12:46:53 keith * Aedded distant porential correction for GENPOT potential (NTS 13/1/94. * * * Revision 2.3 93/10/28 10:27:57 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:11 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.17 93/03/12 12:24:46 keith * Got rid of unneccesary convex special case. * * Revision 1.16 93/03/09 15:58:41 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.15 92/09/22 14:45:20 keith * A few efficiency improvements for the Titan * * Revision 1.14 92/06/10 15:53:16 keith * Added new potential type "generic" for Neal. * * Revision 1.13 91/08/16 15:25:35 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.12 91/08/15 18:12:03 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.11 91/02/19 14:51:26 keith * Minor changes to get rid of misleading compiler warnings. * * Revision 1.10 90/09/28 13:29:39 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.9 90/05/21 15:29:00 keith * Moved definition of struct pot_dim[][] from convert.c to kernel.c. * * Revision 1.8 90/05/02 13:04:52 keith * Tidied up and restructured code to improve readability. * Reduced number of scalar temporaries in vector loops - this is * necessary to vectorize under CRAY CC 5.0. * * Revision 1.7 89/12/22 19:33:44 keith * Added p0-p3 - temporaries for pot[0..3] pointers within loops. * Some machines (eg stellar) generate better code this way. * * Revision 1.6 89/12/15 12:56:53 keith * Added conditional ionclusion of for stellar * * Revision 1.5 89/11/20 13:29:26 keith * Replaced separate arrays "types" and "npotp" with array of structs "potspec" * * Revision 1.4 89/10/12 16:42:37 keith * Eleminated a few inefficiencies in non-coulombic LJ and MCY loops. * * Revision 1.3 89/07/04 18:42:07 keith * Fixed error in kernel and force which led to sites being allocated the * wrong potential parameters. Needed extra parameter to kernel. * * Revision 1.2 89/06/20 18:22:31 keith * Moved pot. par defs arrays 'types', 'npotp' and npott from input.c to kernel.c * * Revision 1.1 89/04/20 16:00:45 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/kernel.c,v 2.8 1996/10/04 17:27:24 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar # include #else #ifdef ardent # include #else # include #endif #endif /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ #if defined(ANSI) || defined(__STDC__) void message(int *,...); /* Write a warning or error message */ #else void message(); /* Write a warning or error message */ #endif /*========================== Potential type specification ====================*/ CONST pots_mt potspec[] = {{"lennard-jones",2}, /* Name, index & # parms */ {"buckingham",3}, {"mcy",4}, {"generic",6}, {0,0}}; /* MUST be null-terminated*/ /* * Array of dimensions of pot'l parameters. Powers of {m,l,t} per parameter. */ CONST dim_mt pot_dim[][NPOTP]= {{{1,2,-2},{0,1,0}}, {{1,8,-2},{1,2,-2},{0,-1,0}}, {{1,2,-2},{0,-1,0},{1,2,-2},{0,-1,0}}, {{1,2,-2},{0,-1,0},{1,14,-2}, {1,6,-2},{1,8,-2},{1,10,-2}}}; /*========================== Macros ==========================================*/ #define E1 0.254829592 /* Polynomial Constants used in */ #define E2 -0.284496736 /* Evaluation of the complementary */ #define E3 1.421413741 /* Error function. */ #define E4 -1.453152027 /* Approximation used is that of */ #define E5 1.061405429 /* Abramowitz & Stegun p299. */ #define PP 0.3275911 #define POLY5(t) ((t)*(E1 + (t)*(E2 + (t)*(E3 + (t)*(E4 + (t)*E5))))) #define LJPOT 0 #define E6POT 1 #define MCYPOT 2 #define GENPOT 3 /*============================================================================*/ /****************************************************************************** * dist_pot return attractive part of potential integrated from cutoff to * * infinity for distant pressure calculation. * ******************************************************************************/ double dist_pot(potpar, cutoff, ptype) real potpar[]; /* Array of potential parameters */ double cutoff; /* Cutoff distance */ int ptype; /* Potential type selector */ { switch(ptype) { default: message(NULLI, NULLP, FATAL, UNKPTY, ptype); case LJPOT: return(potpar[0]*CUBE(SQR(potpar[1])/cutoff) / 3.0); case E6POT: return(potpar[0] / ( 3.0*CUBE(cutoff))); case MCYPOT: if( potpar[3] != 0.0 ) return( potpar[2] * (SQR(cutoff)/potpar[3] + 2*cutoff/SQR(potpar[3]) + 2.0 / CUBE(potpar[3])) * exp(-potpar[3]*cutoff)); else return( 0.0 ); case GENPOT: return ( potpar[4] / ( 3.0*CUBE(cutoff)) + potpar[3] / cutoff); } } /****************************************************************************** * kernel Innermost loop of force calculation. Takes a vector of squared * * atomic distances (r_sqr), charges (chg) , pot'l parameters (pot[which]), * * and returns a vector of forces (forceij) and the potential energy (pe) * ******************************************************************************/ void kernel(jmin, nnab, forceij, pe, r_sqr, nab_chg, chg, norm, alpha, ptype, pot) int jmin, nnab; /* Lower and upper limits for vectors. (in) */ int ptype; /* Index of potential type in potspec[]. (in) */ double *pe; /* Potential energy accumulator. (in/out) */ double alpha, norm; /* Ewald parameter and 2*alpha/sqrt(pi). (in) */ double chg; /* Electric charge of reference site. (in) */ real forceij[]; /* Vector of dU(r)/dr for each in r_sqr.(out) */ real r_sqr[]; /* Vector of site-site distances (**2). (in) */ real nab_chg[]; /* Vector of charges of neighbour sites. (in) */ real *pot[]; /* Vectors of potential parameters. (in) */ { register real t, ar; /* Argument of erfc() polynomial. */ register real r; /* Site-site distance. */ register real r_r, r_6_r, r_sqr_r, r_12_r, /* Reciprocal powers of r. */ r_4_r, r_8_r; register real erfc_term; /* Intermediates in erfc calculation. */ real ppe = 0.0; /* Local accumulator of pot. energy. */ real exp_f1, exp_f2; /* Temporary for b*exp(-cr) etc */ register int jsite; /* Loop counter for vectors. */ real *p0 = pot[0], *p1 = pot[1], /* Local bases for arrays of pot'l */ *p2 = pot[2], *p3 = pot[3], /* parameters. */ *p4 = pot[4], *p5 = pot[5]; if(alpha > 0.0) switch(ptype) { default: message(NULLI, NULLP, FATAL, UNKPTY, ptype); case LJPOT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { /* * Calculate r and coulombic part */ r = sqrt(r_sqr[jsite]); ar = alpha*r; t = 1.0/(1.0+PP*ar); erfc_term = nab_chg[jsite]* chg * exp(-SQR(ar)); r_r = 1.0 / r; t = POLY5(t) * erfc_term * r_r; erfc_term = t + norm * erfc_term; r_sqr_r = SQR(r_r); /* * Non-coulombic ie potential-specific part */ r_6_r = SQR(p1[jsite])* r_sqr_r; r_6_r = CUBE(r_6_r); r_12_r = SQR(r_6_r); ppe += t + p0[jsite]*(r_12_r - r_6_r); forceij[jsite] = r_sqr_r*(6.0*p0[jsite]*(2*r_12_r - r_6_r) + erfc_term); } break; case E6POT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { /* * Calculate r and coulombic part */ r = sqrt(r_sqr[jsite]); ar = alpha*r; t = 1.0/(1.0+PP*ar); erfc_term = nab_chg[jsite]* chg * exp(-SQR(ar)); r_r = 1.0 / r; t = POLY5(t) * erfc_term * r_r; erfc_term = t + norm * erfc_term; r_sqr_r = SQR(r_r); /* * Non-coulombic ie potential-specific part */ exp_f1 = p1[jsite] * exp(-p2[jsite] * r); r_6_r = p0[jsite] * CUBE(r_sqr_r); ppe += t - r_6_r + exp_f1; forceij[jsite] = r_sqr_r*(-6.0* r_6_r+ erfc_term) + p2[jsite]*exp_f1 * r_r; } break; case MCYPOT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { /* * Calculate r and coulombic part */ r = sqrt(r_sqr[jsite]); ar = alpha*r; t = 1.0/(1.0+PP*ar); erfc_term = nab_chg[jsite]* chg * exp(-SQR(ar)); r_r = 1.0 / r; t = POLY5(t) * erfc_term * r_r; erfc_term = t + norm * erfc_term; r_sqr_r = SQR(r_r); /* * Non-coulombic ie potential-specific part */ exp_f1 = p0[jsite] * exp(-p1[jsite]*r); exp_f2 = -p2[jsite] * exp(-p3[jsite]*r); ppe +=t + exp_f1 + exp_f2; forceij[jsite] = (p1[jsite]*exp_f1 + p3[jsite]*exp_f2) * r_r + erfc_term * r_sqr_r; } break; case GENPOT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { /* * Calculate r and coulombic part */ r = sqrt(r_sqr[jsite]); ar = alpha*r; t = 1.0/(1.0+PP*ar); erfc_term = nab_chg[jsite]* chg * exp(-SQR(ar)); r_r = 1.0 / r; t = POLY5(t) * erfc_term * r_r; erfc_term = t + norm * erfc_term; r_sqr_r = SQR(r_r); /* * Non-coulombic ie potential-specific part */ exp_f1 = p0[jsite] * exp(-p1[jsite]*r); r_4_r = SQR(r_sqr_r); r_6_r = r_sqr_r * r_4_r; r_8_r = p5[jsite] * SQR(r_4_r); r_12_r = p2[jsite] * SQR(r_6_r); r_4_r *= p3[jsite]; r_6_r *= p4[jsite]; ppe += t + exp_f1 + r_12_r -r_4_r - r_6_r - r_8_r; forceij[jsite] = r_sqr_r*( 12.0*r_12_r - 4.0*r_4_r - 6.0*r_6_r - 8.0*r_8_r + erfc_term) + p1[jsite]*exp_f1 * r_r; } break; } else switch(ptype) { default: message(NULLI, NULLP, FATAL, UNKPTY, ptype); case LJPOT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { r_sqr_r = 1.0 / r_sqr[jsite]; r_6_r = SQR(p1[jsite])* r_sqr_r; r_6_r = CUBE(r_6_r); r_12_r = SQR(r_6_r); ppe += p0[jsite]*(r_12_r - r_6_r); forceij[jsite] = r_sqr_r*6.0*p0[jsite]*(2*r_12_r - r_6_r); } break; case E6POT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { r = sqrt(r_sqr[jsite]); r_r = 1.0 / r; exp_f1 = p1[jsite] * exp(-p2[jsite] * r); r_sqr_r = SQR(r_r); r_6_r = p0[jsite] * r_sqr_r * r_sqr_r * r_sqr_r; ppe += - r_6_r + exp_f1; forceij[jsite] = -r_sqr_r * 6.0 * r_6_r + p2[jsite]*exp_f1 * r_r; } break; case MCYPOT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { r = sqrt(r_sqr[jsite]); r_r = 1.0 / r; exp_f1 = p0[jsite] * exp(-p1[jsite]*r); exp_f2 = -p2[jsite] * exp(-p3[jsite]*r); ppe += exp_f1 + exp_f2; forceij[jsite] = (p1[jsite]*exp_f1 + p3[jsite]*exp_f2) *r_r; } break; case GENPOT: VECTORIZE for(jsite=jmin; jsite < nnab; jsite++) { r = sqrt(r_sqr[jsite]); r_r = 1.0 / r; exp_f1 = p0[jsite] * exp(-p1[jsite]*r); r_sqr_r = SQR(r_r); r_4_r = SQR(r_sqr_r); r_6_r = r_sqr_r * r_4_r; r_8_r = p5[jsite] * SQR(r_4_r); r_12_r = p2[jsite] * SQR(r_6_r); r_4_r *= p3[jsite]; r_6_r *= p4[jsite]; ppe += exp_f1 + r_12_r -r_4_r - r_6_r - r_8_r; forceij[jsite] = r_sqr_r*( 12.0*r_12_r - 4.0*r_4_r - 6.0*r_6_r - 8.0*r_8_r) + p1[jsite]*exp_f1 * r_r; } break; } *pe += ppe; } $EOD $! $CREATE main.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * MAIN Driver program for MOLDY. Calls startup to read input and * * control parameters and set up the simulation variables and * * executes the main cycle over timesteps. It also contains * * the definition of the 'control' struct with the default * * values of the simulation control parameters. * ****************************************************************************** * Revision Log * $Log: main.c,v $ * Revision 2.12 1996/09/03 15:01:12 keith * Added test for divergent parallel trajectories. * * Revision 2.11 1996/03/19 15:48:56 keith * Timing message now printed on thread zero only. * * Revision 2.11 1996/03/19 15:48:22 keith * *** empty log message *** * * Revision 2.10 1996/01/15 16:54:43 keith * De lint-ed code, added prototypes etc. * * Made averages calculation output on thread zero only. * Added code for parallel RDF calculation, summing data from each thread * * Revision 2.9 1995/10/25 11:59:45 keith * Added test to avoid attemted open of backup file with null name. * * Revision 2.8 1994/07/07 16:57:01 keith * Updated for parallel execution on SPMD machines. * Interface to MP library routines hidden by par_*() calls. * Compile with -DSPMD to activate * * Revision 2.7 1994/06/08 13:14:37 keith * Changed all timestep-related parameters to type "long". This means * that 16-bit DOS compilers can do more than 32767 timesteps. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/18 13:32:42 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:27:59 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:13 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.20 93/03/09 15:58:58 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.19 92/10/28 14:09:30 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.18 92/06/12 12:55:58 keith * Mods to make it work on VMS again. Ugh. * * Revision 1.17 92/06/11 20:31:49 keith * Added file locking against multiple runs using same dump or backup files. * * Revision 1.16 91/08/15 18:12:06 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.15 91/03/12 15:43:04 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.14 91/02/21 15:27:19 keith * Mods for parallel version for titan added * * Revision 1.13 90/05/16 14:20:04 keith * *** empty log message *** * * Revision 1.12 90/04/14 17:53:41 keith * Added signal handler to catch CPU exceeded and TERM signal. * * Revision 1.11 89/12/15 12:57:00 keith * Now prints elapsed as well as cpu time. * * Revision 1.10 89/11/20 18:04:15 keith * Moved initialisation of control and units to 'input.c' * Added 2nd command line arg to specify output file. * * Revision 1.9 89/11/20 12:02:09 keith * Changed interface to print_rdf. cf rdf.c 1.6 * Modified write of restart and backup files - added 'purge' call. * * Revision 1.8 89/09/04 18:48:31 keith * Chhanged initialisation of 'control' commensurate with structs 1.6.1.2 * * Revision 1.7 89/08/10 17:30:54 keith * Fixed if statement so that rdf's started on rather than after 'begin-rdf' * * Revision 1.6 89/07/05 18:19:37 keith * Code to support the portable text mode save configuration added. * Calculation of when to output averages and rdf data fixed to print * when (istep-start+1) % interval == 0. * * Revision 1.5 89/06/01 21:24:38 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.4 89/05/24 11:08:19 keith * Fixed bug which called 'averages()' before and at begin-average. * Velocities are now rescaled up to and including scale_end. * Put better defaults for 'control' parameters. * * Revision 1.3 89/05/22 14:05:34 keith * Added rescale-separately option, changed 'contr_t' format. * * Revision 1.2 89/04/21 10:48:38 keith * Corrected bug which left step counter 1 too high at end of run * * Revision 1.1 89/04/20 16:00:48 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/main.c,v 2.12 1996/09/03 15:01:12 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== System include files ============================*/ #include #ifdef SIGCPULIM /* Alternative name to SIGXCPU. */ #define SIGXCPU SIGCPULIM #endif /* Unicos uses SIGCPULIM not SIGXCPU. */ #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ void start_up(); void do_step(); void values(); double value(); void averages(); void output(); void rescale(); void dump(); void print_rdf(); void print_config(); double cpu(); void write_restart(); void purge(); double rt_clock(); gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ #ifdef SPMD void par_begin(); void par_sigintreset(); void par_finish(); void par_isum(); void par_imax(); void par_broadcast(); void replicate(); #endif #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif void rmlockfiles(); /* Delete all lock files. */ gptr *rdf_ptr(); /* Return ptr to start of rdf data */ /*========================== External data definition ========================*/ contr_mt control; /* Main simulation control parms. */ int ithread=0, nthreads=1; /*============================================================================*/ /****************************************************************************** * Signal handler. Just set flag and return. * ******************************************************************************/ static int sig_flag = 0; static void shutdown(sig) int sig; { sig_flag = sig; } static void siglock(sig) int sig; { rmlockfiles(); #ifdef SPMD if( sig == SIGINT ) par_sigintreset(); else #endif signal(sig, SIG_DFL); raise(sig); } /****************************************************************************** * Main program. * ******************************************************************************/ int main(argc, argv) int argc; char *argv[]; { system_mt system; spec_mt *species; site_mt *site_info; pot_mt *potpar; restrt_mt restart_header; int backup_restart; static mat_mt stress_vir; static double pe[NPE]; double t0, t00; double delta_cpu = 0.0, cpu_base = cpu(); double rt = rt_clock(); vec_mt (*meansq_f_t)[2]; vec_mt dip_mom; int *rdf_base; int rdf_size; #ifdef SPMD par_begin(&argc, &argv, &ithread, &nthreads); #endif #ifdef PARALLEL # ifdef ardent int nthreads = nprocessors(); int stacksize = 65536; # endif #endif #if defined(SPMD) && !defined(READALL) if( ithread == 0 ) #endif start_up((argc>1)?argv[1]:"", (argc>2)?argv[2]:"", &system, &species, &site_info, &potpar, &restart_header, &backup_restart); #if defined(SPMD) && !defined(READALL) replicate(&control, &system, &species, &site_info, &potpar, &restart_header); #endif rdf_base = (int*)rdf_ptr(&rdf_size); meansq_f_t = (vec_mt (*)[2])ralloc(2*system.nspecies); /* * Set signal handlers -- attempt clean shutdown */ (void)signal(SIGTERM, shutdown); #ifdef SIGXCPU (void)signal(SIGXCPU, shutdown); #endif /* * Set signal handlers -- remove lock files and exit * Check that the signal is actually defined if it is non-ansi */ #ifdef SIGHUP (void)signal(SIGHUP, siglock); #endif (void)signal(SIGINT, siglock); #ifdef SIGQUIT (void)signal(SIGQUIT, siglock); #endif #ifdef SIGABRT (void)signal(SIGABRT, siglock); #endif #ifdef PARALLEL # ifdef ardent MT_SET_THREAD_NUMBER(&nthreads); MT_INIT(&stacksize); # endif #endif /* * Main MD timestep loop */ while( control.istep < control.nsteps && sig_flag == 0) { control.istep++; do_step(&system, species, site_info, potpar, meansq_f_t, pe, dip_mom, stress_vir, &restart_header, backup_restart); values(&system, species, meansq_f_t, pe, dip_mom, stress_vir); if( ithread == 0 && control.istep % control.print_interval == 0) output(); if(control.scale_interval > 0) { if(control.istep <= control.scale_end && control.istep % control.scale_interval == 0) rescale(&system, species); if( ithread == 0 && control.istep == control.scale_end) note("Temperature scaling turned off after step %ld", control.istep); } if(control.average_interval > 0 && control.istep >= control.begin_average && ithread == 0) { if( control.istep == control.begin_average ) { note("started accumulating thermodynamic averages on timestep %ld", control.istep); } else if ( (control.istep-control.begin_average + 1) % control.average_interval == 0) averages(); } if(control.rdf_interval > 0 && control.istep >= control.begin_rdf && (control.istep-control.begin_rdf+1) % control.rdf_out == 0) { #if defined(SPMD) && ! defined OLDRDF par_isum(rdf_base, rdf_size); if( ithread == 0 ) print_rdf(&system, species, site_info); memst((gptr*)rdf_base, 0, rdf_size*sizeof(int)); #else if( ithread == 0 ) print_rdf(&system, species, site_info); #endif } if(control.backup_interval > 0 && control.backup_file[0] && control.istep % control.backup_interval == 0) { #if defined(SPMD) && ! defined OLDRDF par_isum(rdf_base, rdf_size); if( ithread != 0 ) memst((gptr*)rdf_base, 0, rdf_size*sizeof(int)); #endif if( ithread == 0 ) { write_restart(control.backup_file, &restart_header, &system, species, site_info, potpar); purge(control.backup_file); } } if(delta_cpu == 0.0) delta_cpu = cpu() - cpu_base;/* Time for a timestep*/ if( cpu()-cpu_base+delta_cpu >= control.cpu_limit ) sig_flag++; /* Cheat */ #ifdef SPMD /* * Better make sure every process wants to stop at the same time! */ par_imax(&sig_flag); /* * Vital consistency check that all threads are absolutely in sync. * Use Temperature as it's a function of all KEs & therefore trajs. */ if( control.istep%10 == 0) { t0 = t00 = value(t_n,0); par_broadcast(&t0, 1, sizeof(double), 0); if( t0 != t00) message(NULLI, NULLP, FATAL, DESYNC, ithread, t0, t00); } #endif } /* End of main MD timestep loop */ #if defined(SPMD) && ! defined OLDRDF par_isum(rdf_base, rdf_size); #endif if( ithread == 0 ) { if(control.istep < control.nsteps) /* Run ended prematurely */ { if(sig_flag == SIGTERM) note("Run ended after step %ld - SIGTERM received", control.istep); else note("Run ended after step %ld - cpu limit exceeded", control.istep); write_restart(control.backup_file, &restart_header, &system, species, site_info, potpar); } else if(control.save_file[0] != '\0') { if( control.print_sysdef ) print_config(control.save_file, &system, species, site_info, potpar); else write_restart(control.save_file, &restart_header, &system, species, site_info, potpar); (void)remove(control.backup_file); /* Get rid of backup */ } else (void)remove(control.backup_file); /* Get rid of backup */ rmlockfiles(); printf(" *I* Run used %.2fs of CPU time and %.2fs elapsed\n", cpu()-cpu_base, rt_clock()-rt); } #ifdef SPMD par_finish(); #endif return(0); } $EOD $! $CREATE matrix.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * matrix Functions for manipulating 3x3 matrices * * Contents: * * mat_vec_mul() Multiply matrix by array of vectors * * mat_mul() Multiply two 3x3 matrices * * mat_sca_mul() Multiply 3x3 matrix by scalar * * mat_add() Add two 3x3 matrices * * transpose() Transpose a 3x3 matrix * * det() Return determinant of 3x3 matrix * * invert() Invert a 3x3 matrix * ****************************************************************************** * Revision Log * $Log: matrix.c,v $ * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Eliminated non-ANSI (and not portable to DOS) pointer * comparison. * * Revision 2.5 1994/01/18 13:32:44 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:28:00 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/08/18 20:54:18 keith * Tidied up clashes over ABS, MIN, MAX macros. * * Revision 2.0 93/03/15 14:49:14 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.7 93/03/09 15:59:01 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.6 91/08/15 18:12:08 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.5 90/09/28 13:29:43 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.4 89/12/18 17:54:23 keith * Rewrote transpose() to compile correctly under -va option (for Stellar). * * Revision 1.3 89/10/26 11:26:55 keith * Mat_vec_mul() vectorised. * * Revision 1.2 89/10/24 17:16:21 keith * Modified transpose() so as not to vectorise under '-va' option on convex. * * Revision 1.1 89/04/20 16:00:50 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/matrix.c,v 2.7 1994/06/08 13:22:31 keith stab $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" #include "messages.h" /*========================== Library include files ===========================*/ #include "string.h" /*========================== External function declarations ==================*/ #if defined(ANSI) || defined(__STDC__) void message(int *, ...); /* Write a warning or error message */ #else void message(); /* Write a warning or error message */ #endif /*============================================================================*/ #define ABS(x) ((x) > 0 ? (x) : -(x)) /****************************************************************************** * 3 x 3 Matrix - vector multiply (of multiple vectors) * * The input and output vectors need not necessarily be distinct * ******************************************************************************/ void mat_vec_mul(m, in_vec, out_vec, number) int number; /* Number of vectors to be multiplied */ mat_mt m; /* Matrix */ vec_mp in_vec, /* Input vector, [number][3] (in/out)*/ out_vec; /* Output vector. CAN BE SAME AS INPUT (out)*/ { int i; register real a0, a1, a2; /* * There are two blocks of code depending on whether the input and output * * arrays are distinct. If they are not, in_vec is explicitly assigned * * otherwise there could be problems with optimising compilers. Also, * * temporary storage is required to avoid writing over the input vector * * and trying to re-use the 'old' values. */ if(in_vec == out_vec) /* ie parameters point to the same array */ { VECTORIZE for(i = 0; i < number; i++) { a0 = in_vec[i][0]; a1 = in_vec[i][1]; a2 = in_vec[i][2]; in_vec[i][0] = m[0][0]*a0 + m[0][1]*a1 + m[0][2]*a2; in_vec[i][1] = m[1][0]*a0 + m[1][1]*a1 + m[1][2]*a2; in_vec[i][2] = m[2][0]*a0 + m[2][1]*a1 + m[2][2]*a2; } } else /* parameters are distinct arrays */ { VECTORIZE for(i = 0; i < number; i++) { a0 = in_vec[i][0]; a1 = in_vec[i][1]; a2 = in_vec[i][2]; out_vec[i][0] = m[0][0]*a0 + m[0][1]*a1 + m[0][2]*a2; out_vec[i][1] = m[1][0]*a0 + m[1][1]*a1 + m[1][2]*a2; out_vec[i][2] = m[2][0]*a0 + m[2][1]*a1 + m[2][2]*a2; } } #if 0 /* Can not test for overlap portably in ANSI C. */ else /* in_vec and out_vec overlap, but are not identical */ message(NULLI, NULLP, FATAL, OVRLP1, in_vec, out_vec, number); #endif } /****************************************************************************** * mat_mul Multiply two 3 x 3 matrices. Result can NOT overwrite input. * ******************************************************************************/ void mat_mul(a, b, c) mat_mt a, /* Input matrix 1 (in) */ b, /* Input matrix 2 (in) */ c; /* Result matrix (out) */ { register int i, j; /* Counters */ if(c == a || c == b) message(NULLI, NULLP, FATAL, OVRLAP, "mat_mul"); for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) c[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]; } /****************************************************************************** * mat_sca_mul. Multiply a 3x3 matrix by a scalar * ******************************************************************************/ void mat_sca_mul(s, a, b) register real s; /* Scalar (in) */ mat_mt a, /* Input matrix (in) */ b; /* Result matrix (out) */ { register int i, j; for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) b[i][j] = s * a[i][j]; } /****************************************************************************** * mat_add Add two 3 x 3 matrices. * ******************************************************************************/ void mat_add(a, b, c) mat_mt a, /* Input matrix 1 (in) */ b, /* Input matrix 2 (in) */ c; /* Result matrix (out) */ { register int i, j; /* Counters */ for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) c[i][j] = a[i][j] + b[i][j]; } /****************************************************************************** * Transpose Transpose a 3 x 3 matrix. Will handle case of a = b * ******************************************************************************/ void transpose(a, b) mat_mt a, /* Input matrix (in) */ b; /* Transposed matrix (out) */ { mat_mt tmp; memcp(tmp, a, sizeof tmp); b[0][0] = tmp[0][0]; b[1][1] = tmp[1][1]; b[2][2] = tmp[2][2]; b[0][1] = tmp[1][0]; b[1][0] = tmp[0][1]; b[0][2] = tmp[2][0]; b[2][0] = tmp[0][2]; b[1][2] = tmp[2][1]; b[2][1] = tmp[1][2]; } /****************************************************************************** * Det. Determinant of a 3 x 3 matrix * ******************************************************************************/ double det(a) mat_mt a; /* Matrix (in) */ { int i, j, k; /* Counters */ register double deter = 0.0; for(i = 0, j = 1, k = 2; i < 3; i++, j=(j+1)%3, k=(k+1)%3) deter += a[0][i] * (a[1][j]*a[2][k] - a[1][k]*a[2][j]); return(deter); } /****************************************************************************** * invert. Calculate the inverse of a 3x3 matrix. Adjoint method. * ******************************************************************************/ void invert(a, b) mat_mt a, /* Input matrix (in) */ b; /* Inverse matrix (out) */ { int i, j, k, l, m, n; /* Counters */ register real deter; /* Reciprocal of determinant */ if(a == b) message(NULLI, NULLP, FATAL, OVRLAP, "invert"); if((deter = det(a)) == 0.0) message(NULLI, NULLP, FATAL, SNGMAT, "invert"); deter = 1.0 / deter; for(i = 0, j = 1, k = 2; i < 3; i++, j=(j+1)%3, k=(k+1)%3) for(l = 0, m = 1, n = 2; l < 3; l++, m=(m+1)%3, n=(n+1)%3) b[l][i] = deter*(a[j][m]*a[k][n] - a[j][n]*a[k][m]); } $EOD $! $CREATE output.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * output Contains various output and error handling functions, except * * for 'print_frame' and 'output' which, because of their * * intimate connection with the averages/values database are * * located in "values.c". Contents: * * new_line() Write new line & manage page length * * new_page() Start new output page * * put_line() Write a line of symbols * * note() Write a message to the output file * * message() Write an error or warning message, possibly exiting * * print_array() \ * * format_int() \ Internal (static) procedures for use by * * format_dbl() / banner_page() * * format_vec() / * * banner_page() Write main startup banner and simulation parameters * * print_sysdef() Print system specification readable by read_sysdef() * ****************************************************************************** * Revision Log * $Log: output.c,v $ * Revision 2.11 1996/03/05 18:48:00 keith * Removed a couplt of CONST declarations because IBL xlc compiler * complained about them. * * Revision 2.10 1995/12/07 17:54:06 keith * Reworked V. Murashov's thermostat code. * Convert mass params from kJ/mol ps^2 to prog units. Defaults=100. * * Revision 2.9 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.8 1994/07/07 17:04:29 keith * Updated for parallel execution on SPMD machines. * Interface to MP library routines hidden by par_*() calls. * Compile with -DSPMD to activate. * * Revision 2.7 1994/06/08 13:15:58 keith * Changed all timestep-related parameters to type "long". This means * that 16-bit DOS compilers can do more than 32767 timesteps. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/21 12:21:22 keith * Corrected trivial and latent bug in print_config() * * Revision 2.3 93/10/28 10:28:01 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:16 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.8.1.15 93/03/12 12:14:23 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.8.1.15 93/03/09 15:59:03 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.8.1.14 93/03/05 15:03:25 keith * Moved include of stdlib above stdio for non-ANSI gcc environments. * * Revision 1.8.1.13 92/10/28 14:10:02 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.8.1.12 92/06/11 20:31:52 keith * Added file locking against multiple runs using same dump or backup files. * * Revision 1.8.1.11 92/06/05 13:37:44 keith * Conditionally undefed va_dcl for ANSI, stdarg.h case -- * just prevents warning from gcc. * * Revision 1.8.1.10 92/03/11 12:56:18 keith * Changed "scale-separately" parameter to "scale options" * * Revision 1.8.1.9 91/08/19 16:47:37 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * * Revision 1.8.1.8 91/08/16 15:25:59 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.8.1.6 90/05/16 18:40:32 keith * Renamed own freer from cfree to tfree. * * Revision 1.8.1.5 90/05/16 14:20:17 keith * *** empty log message *** * * Revision 1.8.1.4 90/05/15 19:00:54 keith * Fixed error line 497 which wrapped on unsigned "strlen" * * Revision 1.8.1.3 89/11/21 15:52:52 keith * Fixed format of "special" in accordance with altered struct type match_t. * * Revision 1.8.1.1 89/11/20 13:30:06 keith * Replaced separate arrays "types" and "npotp" with array of structs "potspec" * * Revision 1.7.1.2 89/09/04 17:56:35 keith * Added charge and dipole info to per-species output in banner_page() * * Revision 1.8 89/09/04 17:53:43 keith * Added charge and dipole info to per-species output in banner_page() * * Revision 1.7 89/08/11 10:53:38 keith * Tidied up loops over species to use pointer as counter * Fixed print_config() to convert control parameters to correct units * before outputting them. * Explicitly included stdio.h before varargs to get round VMS C problem. * * Revision 1.6 89/07/04 18:46:01 keith * Print_config() added. Prints control, sys-spec and configurational info * which can be reread as a lattice start, for portable restart. * * Revision 1.4 89/06/20 18:30:36 keith * moved print_sysdef() from input.c to output.c * made definitions of 'types[]' and 'npotp[]' external (in kernel). * Updated banner_page() to provide more info * * Revision 1.3 89/06/01 21:25:07 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.2 89/05/24 13:55:03 keith * Changed ifdef's to select on __STDC__ macro * Message() now prints to user specified output file after initial set up * * Revision 1.1 89/04/27 16:52:19 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/output.c,v 2.11 1996/03/05 18:48:00 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #if defined(ANSI) || defined(__STDC__) #include #else #include #endif #include #include "stdlib.h" #include "stddef.h" #include "string.h" #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ void conv_control(); /* Unit conversion for 'control' */ char *atime(); /* Current date and time in ASCII */ char *cctime(); /* Convert long time to ASCII. */ void rmlockfiles(); /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ extern CONST match_mt match[]; /* Control file keyword table. */ extern CONST pots_mt potspec[]; /* Potential type specification */ extern int ithread, nthreads; /*========================== External data definitions ======================*/ static int out_page = 1; /* Which page of output we are on */ static int out_line = 999999; /* Which line of output */ /*========================== Macros ==========================================*/ #define S_USED 0x01 /*========================== Special Control output cases ====================*/ static int one=1; extern unit_mt prog_unit; static CONST match_mt special[] = { {"lattice-start", "%d", "", (gptr*)&one}, {"restart-file", "%s", "", (gptr*)""}, {"sys-spec-file", "%s", "", (gptr*)""}, {"mass-unit", "%lf", "", (gptr*)&prog_unit.m}, {"length-unit", "%lf", "", (gptr*)&prog_unit.l}, {"time-unit", "%lf", "", (gptr*)&prog_unit.t}, {"charge-unit", "%lf", "", (gptr*)&prog_unit.q} }; static CONST int nspecial = sizeof(special) / sizeof(match_mt); /****************************************************************************** * lines_left(). How many lines are left on page? * ******************************************************************************/ int lines_left() { if( control.page_length > 0) return MAX(0,control.page_length - out_line); else return 999999; } /****************************************************************************** * new_line. print a newline and update line counter * ******************************************************************************/ void new_line() { void new_page(); (void)putchar('\n'); out_line++; if(out_line > control.page_length && control.page_length > 0) new_page(); } void new_lins(n) int n; { while(n-- > 0) new_line(); } /****************************************************************************** * new_page Take a new page on the output and print a header * ******************************************************************************/ void new_page() { (void)putchar('\f'); /* Take new page */ out_line = 0; /* Print page header */ (void)printf("\t%s\t%s\tPage %d", atime(), control.title, out_page++); new_line(); } /****************************************************************************** * Banner line. * ******************************************************************************/ void put_line(c) int c; { int n = control.page_width; while(n-- > 0) (void)putchar(c); new_line(); } /****************************************************************************** * message. Deliver error message to possibly exiting. It can be called * * BEFORE output file is opened, in which case outt to stderr. * ******************************************************************************/ #if defined(ANSI) || defined(__STDC__) # undef va_alist # define va_alist int *nerrs, ... # ifdef va_dcl # undef va_dcl # endif # define va_dcl /* */ #endif /*VARARGS*/ void message(va_alist) va_dcl { va_list ap; char *buff; int sev; char *format; static char *sev_txt[] = {" *I* "," *W* "," *E* "," *F* "}; #if defined(ANSI) || defined(__STDC__) va_start(ap, nerrs); #else int *nerrs; va_start(ap); nerrs = va_arg(ap, int *); #endif buff = va_arg(ap, char *); sev = va_arg(ap, int); format= va_arg(ap, char *); if( ithread == 0 || abs(sev) == FATAL) { (void)printf(sev_txt[abs(sev)]); (void)vprintf(format, ap); new_line(); /* To maintain pagination */ if(buff != NULL) /* null ptr means don't print buffer */ { (void)printf(" buffer contents=\"%s\"",buff); new_line(); } } va_end(ap); if(sev >= ERROR && nerrs != NULL) (*nerrs)++; if(sev == FATAL) rmlockfiles(); if(abs(sev) == FATAL) { #ifdef SPMD par_abort(3); #endif exit(3); } } /****************************************************************************** * note write a message to the output file * ******************************************************************************/ #if defined(ANSI) || defined(__STDC__) #undef va_alist #define va_alist char *text, ... #define va_dcl /* */ #endif /*VARARGS*/ void note(va_alist) va_dcl { va_list ap; #if defined(ANSI) || defined(__STDC__) va_start(ap, text); #else char *text; va_start(ap); text = va_arg(ap, char *); #endif if( ithread > 0 ) return; (void)printf(" *I* "); (void)vprintf( text, ap); new_line(); va_end(ap); } /****************************************************************************** * Print_array Print out an array of strings in a common format * ******************************************************************************/ static void print_array(text, n) char *text[]; size_mt n; { int i; for(i=0; ih; char version[132], *vsn=version; new_page(); new_lins(2); print_array( banner, lsizeof banner / sizeof(char*)); (void)sprintf(version, "Version %.*s (%.*s) %.*s", (int)strlen(Revision+11)-1, Revision+11, (int)strlen(Revision_State+8)-1, Revision_State+8, (int)strlen(Revision_Date+7)-1, Revision_Date+7); print_array( &vsn, (size_mt)1); print_array( name_addr, lsizeof name_addr / sizeof(char*)); print_array( copy_notice, lsizeof copy_notice / sizeof(char*)); if(control.restart_file[0] != '\0') if(control.new_sysdef) (void)printf( " New system specification read in from file %s", control.sysdef); else (void)printf( " System specification read in from restart file %s", control.restart_file); else (void)printf( " System specification read in from file %s", control.sysdef); new_line(); for(spec = species; spec < &species[system->nspecies]; spec++) { (void)printf(" %s", spec->name); new_line(); format_int("Number of molecules",spec->nmols); format_int("Number of sites",spec->nsites); format_dbl("Mass",spec->mass,MUNIT_N); format_dbl("Electric Charge", spec->charge*CONV_Q,CONV_Q_N); if(spec->nsites > 1 ) format_dbl("Dipole moment",spec->dipole*CONV_D,CONV_D_N); if(spec->rdof == 0) { (void)printf( "\t%s molecule has no rotational degrees of freedom", spec->name); new_line(); } else { if(spec->rdof == 2) { (void)printf("\t%s molecule is linear",spec->name); new_line(); } format_vec("Moments of inertia", spec->inertia[0],spec->inertia[1],spec->inertia[2],IUNIT_N); } } new_line(); (void)printf(" MD cell vectors"); new_line(); format_vec("a",h[0][0],h[1][0],h[2][0],LUNIT_N); format_vec("b",h[0][1],h[1][1],h[2][1],LUNIT_N); format_vec("c",h[0][2],h[1][2],h[2][2],LUNIT_N); (void)printf(" Run parameters"); new_line(); if(control.istep > 0) format_long("Initial step",control.istep); format_long("Final step",control.nsteps); format_dbl("Size of step",control.step,TUNIT_N); format_dbl("CPU limit",control.cpu_limit,"s"); if(control.scale_interval > 0) { if( control.scale_options & 0x8 ) { (void)printf(" Velocities to be periodically RESET from MB distribution"); new_line(); } else { (void)printf(" Temperature will be scaled using %s kinetic energy", control.scale_options & 0x4 ? "rolling average" : "instantaneous"); new_line(); if( control.scale_options & 0x3) { (void)printf(" (for "); if( control.scale_options & 0x2 ) { (void)printf("transl. and rotl."); if( control.scale_options & 0x1 ) (void)printf(" and "); } if( control.scale_options & 0x1 ) (void)printf("each species"); (void)printf(" individually)"); new_line(); } } format_long("No. steps between scalings",control.scale_interval); format_long("End scaling at step",control.scale_end); } if((control.scale_interval > 0) || (control.const_temp == 1)) format_dbl("Applied Temperature",control.temp,"K"); if(control.const_temp) { (void)printf(" %s thermostat will be used", control.const_temp == 1 ? "Nose-Hoover" : "Gaussian"); new_line(); if( control.scale_options & 0x3) { (void)printf(" (for "); if( control.scale_options & 0x2 ) { (void)printf("transl. and rotl."); if( control.scale_options & 0x1 ) (void)printf(" and "); } if( control.scale_options & 0x1 ) (void)printf("each species"); (void)printf(" individually)"); new_line(); } if(control.const_temp == 1) { format_dbl("Translational temperature mass parameter ", control.ttmass*CONV_TM, CONV_TM_N); format_dbl("Rotational temperature mass parameter ", control.rtmass*CONV_TM, CONV_TM_N); } } if(control.const_pressure) { (void)printf(" Constant stress ensemble will be used"); new_line(); format_dbl("Applied pressure", CONV_P*control.pressure,CONV_P_N); format_dbl("Mass parameter W",control.pmass,MUNIT_N); if(control.const_temp == 2) message(NULLI, NULLP, WARNING, GANDP); } format_dbl("Interaction cut-off",control.cutoff,LUNIT_N); if(control.alpha != 0.0) { format_dbl("Alpha parameter for Ewald sum",control.alpha,RLUNIT_N); format_dbl("Reciprocal space cut-off",control.k_cutoff,RLUNIT_N); } if( control.rdf_interval > 0 ) { (void)printf(" Radial distribution functions will be calculated"); new_line(); format_long("Starting at timestep", control.begin_rdf); format_long("No. steps between binnings", control.rdf_interval); format_long("Calculate and print after", control.rdf_out); } if( control.dump_level > 0 && control.dump_interval > 0 ) { (void)printf(" Configurational data will be dumped to file(s) %s", control.dump_file); new_line(); format_long("Starting at timestep", control.begin_dump); format_long("No. steps between dumps", control.dump_interval); format_int("Dump level", control.dump_level); } if(control.restart_file[0] == '\0') { (void)printf( " New run entitled \"%s\" started %s", restart_header->title, restart_header->init_date); new_line(); } else { (void)printf( " Run initialised from restart file %s written %s", control.restart_file, cctime(&restart_header->timestamp)); new_line(); (void)printf( " This is restart No %d of run \"%s\" started %s", restart_header->seq, restart_header->title, restart_header->init_date); new_line(); } (void)fflush(stdout); } /****************************************************************************** * print sysdef Print out the definition of the system, in the format that * * read_sysdef can interpret. * ******************************************************************************/ static void print_sysdef(file, system, species, site_info, potpar) FILE *file; system_mp system; /* Pointer to system array (in main) */ spec_mt species[]; /* Pointer to species array */ site_mp site_info; /* pointer to site_info array */ pot_mt potpar[]; /* Potential parameter array */ { spec_mp spec; int isite, idi, idj, idij, ip; int n_potpar = potspec[system->ptype].npar; for(spec = species; spec < &species[system->nspecies]; spec++) { (void)fprintf(file, " %-16s %d %s\n", spec->name, spec->nmols, spec->framework ? "framework" : ""); for(isite=0; isite < spec->nsites; isite++) (void)fprintf(file, " %6d %9g %9g %9g %9g %9g %s\n", spec->site_id[isite], spec->p_f_sites[isite][0], spec->p_f_sites[isite][1], spec->p_f_sites[isite][2], site_info[spec->site_id[isite]].mass, site_info[spec->site_id[isite]].charge, site_info[spec->site_id[isite]].name); } (void)fprintf(file, " end\n"); (void)fprintf(file," %s potential parameters\n",potspec[system->ptype].name); for(idi = 1; idi < system->max_id; idi++) for(idj = idi; idj < system->max_id; idj++) { idij = idj + idi * system->max_id; if(potpar[idij].flag & S_USED) { (void)fprintf(file, " %6d %6d", idi, idj); for(ip = 0; ip < n_potpar; ip++) (void)fprintf(file, " %9g",potpar[idij].p[ip]); (void)fputc('\n',file); } } (void)fprintf(file, " end\n"); } /****************************************************************************** * Print_config() Print out the configuration of the system in a text * * format. Control parameters system definition and 'lattice start' are * * output allowing a portable restart. * ******************************************************************************/ void print_config(save_name, system, species, site_info, potpar) char *save_name; /* Name of save file to be written */ system_mp system; /* Pointer to system array (in main) */ spec_mp species; /* Pointer to be set to species array */ site_mp site_info; /* To be pointed at site_info array */ pot_mp potpar; /* To be pointed at potpar array */ { FILE *out; CONST match_mt *match_p, *cur, *special_p; spec_mp spec; int imol, code, i, j, k; double cell_length[3], cell_angle[3]; mat_mp h = system->h; /* * Convert 'control' to input units for correct rereading. * Save current values and restore afterwards. */ conv_control(&prog_unit, false); if( (out = fopen(save_name, "w")) == NULL ) message(NULLI, NULLP, FATAL, OSFAIL, save_name); for( match_p = match; match_p->key; match_p++) { for( special_p = special; special_p < &special[nspecial]; special_p++) if( ! strcmp(match_p->key, special_p->key) ) break; if( special_p < &special[nspecial] ) cur = special_p; else cur = match_p; code = cur->format[MAX(0, (long)strlen(cur->format)-1)]; switch(code) { case 's': case ']': (void)fprintf(out, "%s = %s\n", cur->key, (char*)cur->ptr); break; case 'd': (void)fprintf(out, "%s = %d\n", cur->key, *(int*)cur->ptr); break; case 'f': (void)fprintf(out, "%s = %.7g\n", cur->key, *(double*)cur->ptr); break; default: message(NULLI, NULLP, FATAL, "Printf code \"%s\" not catered for", cur->format); } } (void)fprintf(out, "end\n"); for( i = 0; i < 3; i++) cell_length[i] = sqrt(SQR(h[0][i]) + SQR(h[1][i]) + SQR(h[2][i])); for( i=0, j=1, k=2; i < 3; i++, j=(i+1)%3, k=(j+1)%3) cell_angle[i] = acos( (h[0][j]*h[0][k] + h[1][j]*h[1][k] + h[2][j]*h[2][k])/ (cell_length[j]*cell_length[k])) / DTOR; print_sysdef(out, system, species, site_info, potpar); (void)fprintf(out, "%g %g %g %g %g %g 1 1 1\n", cell_length[0], cell_length[1], cell_length[2], cell_angle[0], cell_angle[1], cell_angle[2]); for( spec = species; spec < &species[system->nspecies]; spec++ ) for( imol = 0; imol < spec->nmols; imol++ ) { (void)fprintf(out, "%s %g %g %g", spec->name, spec->c_of_m[imol][0]+0.5, spec->c_of_m[imol][1]+0.5, spec->c_of_m[imol][2]+0.5); if( spec->rdof > 0 ) (void)fprintf(out, " %g %g %g %g\n", spec->quat[imol][0], spec->quat[imol][1], spec->quat[imol][2], spec->quat[imol][3]); else (void)fputc('\n', out); } (void)fprintf(out, "end\n"); if( ferror(out) || fclose(out) ) message(NULLI,NULLP,FATAL,REWRT,strerror(errno)); conv_control(&prog_unit, true); } $EOD $! $CREATE quaterns.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * quaterns Functions for manipulating quaternions * ****************************************************************************** * Revision Log * $Log: quaterns.c,v $ * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.5 1994/01/18 13:32:54 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:28:05 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:18 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.2 93/03/09 15:59:06 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.1 89/04/20 16:00:52 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/quaterns.c,v 2.7 1994/06/08 13:22:31 keith stab $"; #endif /*========================== Library include files ===========================*/ #include /*========================== Program include files ===========================*/ #include "defs.h" /*========================== External function declarations ==================*/ double precision(); /*============================================================================*/ /****************************************************************************** * Quaternion multiplier. Multiplies arrays of quaternions p by q to give r * * Can be called with r the same as p or q. * ******************************************************************************/ void q_mul(p, q, r, n) quat_mp p, /* First Quaternion array [n][4] (in) */ q, /* Second quaternion array [n][4] (in) */ r; /* Resultant quaternions [n][4] (out) */ int n; /* Number of quaternions in the arrays (in) */ { register int i; register real p0, p1, p2, p3; register real q0, q1, q2, q3; for(i = 0; i < n; i++) { p0 = p[i][0]; p1 = p[i][1]; p2 = p[i][2]; p3 = p[i][3]; q0 = q[i][0]; q1 = q[i][1]; q2 = q[i][2]; q3 = q[i][3]; r[i][0] = p0*q0 - p1*q1 - p2*q2 - p3*q3; r[i][1] = p1*q0 + p0*q1 - p3*q2 + p2*q3; r[i][2] = p2*q0 + p3*q1 + p0*q2 - p1*q3; r[i][3] = p3*q0 - p2*q1 + p1*q2 + p0*q3; } } /****************************************************************************** * Quaternion multiplier. Multiplies quaternions p by q to give r * * Can be called with r the same as p or q. * ******************************************************************************/ void q_mul_1(p, q, r) quat_mt p, /* First Quaternion array [n][4] (in) */ q, /* Second quaternion array [n][4] (in) */ r; /* Resultant quaternions [n][4] (out) */ { register real p0, p1, p2, p3; register real q0, q1, q2, q3; p0 = p[0]; p1 = p[1]; p2 = p[2]; p3 = p[3]; q0 = q[0]; q1 = q[1]; q2 = q[2]; q3 = q[3]; r[0] = p0*q0 - p1*q1 - p2*q2 - p3*q3; r[1] = p1*q0 + p0*q1 - p3*q2 + p2*q3; r[2] = p2*q0 + p3*q1 + p0*q2 - p1*q3; r[3] = p3*q0 - p2*q1 + p1*q2 + p0*q3; } /****************************************************************************** * Quaternion multiplier. Multiplies arrays of quaternions p(-1) by q to * * give r. Can be called with r the same as p or q. * ******************************************************************************/ void q_conj_mul(p, q, r, n) quat_mp p, /* First Quaternion array [n][4] (in) */ q, /* Second quaternion array [n][4] (in) */ r; /* Resultant quaternions [n][4] (out) */ int n; /* Number of quaternions in the arrays (in) */ { register int i; register real p0, p1, p2, p3; register real q0, q1, q2, q3; for(i = 0; i < n; i++) { p0 = p[i][0]; p1 = -p[i][1]; p2 = -p[i][2]; p3 = -p[i][3]; q0 = q[i][0]; q1 = q[i][1]; q2 = q[i][2]; q3 = q[i][3]; r[i][0] = p0*q0 - p1*q1 - p2*q2 - p3*q3; r[i][1] = p1*q0 + p0*q1 - p3*q2 + p2*q3; r[i][2] = p2*q0 + p3*q1 + p0*q2 - p1*q3; r[i][3] = p3*q0 - p2*q1 + p1*q2 + p0*q3; } } /****************************************************************************** * q_to_mat Make the rotation matrix corresponding to quaternion q * ******************************************************************************/ void q_to_rot(quat, rot) quat_mt quat; /* Input quaternion (in) */ mat_mt rot; /* Rotation matrix (out) */ { register real q0, q1, q2, q3; register real a01, a02, a03, a12, a13, a23; q0 = quat[0]; q1 = quat[1]; q2 = quat[2]; q3 = quat[3]; a01 = 2.0*q0*q1; a02 = 2.0*q0*q2; a03 = 2.0*q0*q3; a12 = 2.0*q1*q2; a13 = 2.0*q1*q3; a23 = 2.0*q2*q3; rot[0][1] = a12 - a03; rot[0][2] = a13 + a02; rot[1][0] = a12 + a03; rot[1][2] = a23 - a01; rot[2][0] = a13 - a02; rot[2][1] = a23 + a01; q0 = q0*q0; q1 = q1*q1; q2 = q2*q2; q3 = q3*q3; rot[0][0] = q0 + q1 - q2 - q3; rot[1][1] = q0 - q1 + q2 - q3; rot[2][2] = q0 - q1 - q2 + q3; } /****************************************************************************** * rot_to_q. Inverse of above. Will fall over badly If rot is not orthogonal.* ******************************************************************************/ void rot_to_q(rot, quat) mat_mt rot; /* Rotation matrix (in) */ quat_mt quat; /* Input quaternion (out) */ { int i, j, k; real sign; double eps = 100*precision(); /* Safety margin for square roots */ quat[0] = 0.5 * sqrt(1.0 + eps + rot[0][0] + rot[1][1] + rot[2][2]); for( i = 0, j = 1, k = 2; i < 3; i++, j=(i+1)%3, k=(j+1)%3 ) { if( quat[0] > 0 ) sign = (rot[j][k] - rot[k][j]) >= 0.0 ? 1.0 : -1.0; else sign = (rot[i][j] + rot[j][i] >= 0) ^ (rot[i][k] + rot[k][i] >= 0) ? -1.0 : 1.0; quat[i+1] = sign*0.5*sqrt(1.0+eps + rot[i][i] - rot[j][j] - rot[k][k]); } } $EOD $! $CREATE rdf.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * rdf Functions to accumulate and calculate radial distribution * * functions. Contents: * * init_rdf() Prepare to collect rdf's. Must be called first * * rdf_calc() (NOT USED)Bin site-site distances and accumulate RDF's * * rdf_accum() Bin site-site distances and accumulate RDF's * * print_rdf() Calculate RDF from binned data and output it. * * rdf[idi][idj][ibin] RDF database (also accessed by 'restart') * ****************************************************************************** * Revision Log * $Log: rdf.c,v $ * Revision 2.8 1996/01/15 15:19:12 keith * New function rdf_accum for parallel accululation or RDF data. * rdf_ptr() now takes one param, *size, which returns # items. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/18 13:32:55 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:28:08 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/07/29 17:37:11 keith * Changed evaluation of rdf to be in exact accordance with * manual. That is, replaced (nsites-1) with nsites and * 3(b+1/2)^2 with [(b+1)^3 - b^3]. Should make negligible * difference to results. * * Revision 2.0 93/03/15 14:49:19 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.19 93/03/12 12:25:17 keith * Got rid of unneccesary convex special case. * * Revision 1.18 93/03/09 15:59:09 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.17 92/11/02 17:31:17 keith * Fixed bug where counter array "nfrac" was not initialised. * * Revision 1.16 92/10/28 14:09:52 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.15 92/09/22 14:48:13 keith * Tidied up calls to improve "lint" rating. * * Revision 1.14 92/06/26 17:03:25 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.13 91/08/15 18:12:12 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.12 91/03/12 15:43:14 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.11 90/10/23 20:13:18 keith * Added dummy function call to inhibit vectorization. * This allows use of 'ivdep' compiler options and also * works round certain bugs in cray's scc compiler. * * Revision 1.10 90/05/16 18:40:38 keith * Renamed own freer from cfree to tfree. * * Revision 1.9 90/05/01 12:51:19 keith * Corrected line-breaking algorithm in print_rdf() to never exceed line length. * * Revision 1.8 90/02/02 15:30:19 keith * Split inner loop in rdf_calc() into one large, vectorisable loop and * one smaller, unvectorisable binning loop. * Replaced library function floor() by (vectorisable) macro. * * Revision 1.7 89/12/21 16:30:02 keith * Reversed indices in 'site' and 'site_force' to allow stride of 1 in ewald. * * Revision 1.6 89/11/20 11:59:19 keith * Corrected normalisation in calculation of rdf. Changed interface (cf main). * * Revision 1.5 89/10/24 17:18:33 keith * Modified pbc algorithm to use floor() library function. * Now works with non-orthorhombic cell. * * Revision 1.4 89/07/07 10:37:02 keith * Added check for uniformly zero RDF which otherwise gave divide by zero. * * Revision 1.3 89/06/22 15:45:10 keith * Tidied up loops over species to use one pointer as counter. * * Revision 1.2 89/06/01 21:25:16 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.1 89/04/20 16:00:53 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/rdf.c,v 2.8 1996/01/15 15:19:12 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar #include #else #include #endif #include "string.h" #include /*========================== Program include files ===========================*/ #include "structs.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ double det(); void invert(); void new_line(); void put_line(); double precision(); void inhibit_vectorization(); /* Self-explanatory dummy */ /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ /*====================================data definitions ======================*/ static int ***rdf; /* The RDF 'array' */ static int *rdf_base; /* base of data area */ static int rdf_size; gptr *rdf_ptr(size) int *size; { *size = rdf_size; return (gptr*)rdf_base; } /*========================== Macros ==========================================*/ #define MATMUL(i, m, r) (m[i][0]*r[0] + m[i][1]*r[1] + m[i][2]*r[2]) #define floor(x) (double)((int)((x) + 10) - 10) /* Vectorisable macro floor()*/ /*============================================================================*/ /****************************************************************************** * rdf_init. Prepare to bin rdf's. Allocate memory and pointers * ******************************************************************************/ void init_rdf(system) system_mp system; /* System info struct */ { int max_id = system->max_id; int idi, idj; int *base; rdf = aalloc(max_id, int ** ); rdf_size = control.nbins * max_id * (max_id - 1) / 2; base = rdf_base = ialloc(rdf_size); memst(base, 0, rdf_size*sizeof(int)); for(idi = 1; idi < max_id; idi++) rdf[idi] = aalloc(max_id, int * ); for(idi = 1; idi < max_id; idi++) for(idj = idi; idj < max_id; idj++) { rdf[idi][idj] = rdf[idj][idi] = base; base += control.nbins; } } /****************************************************************************** * rdf_calc. Calculate site pair distances and bin for RDF. * ******************************************************************************/ void rdf_calc(site, system, species) real **site; /* Site co-ordinate array */ system_mp system; /* System info struct */ spec_mt species[]; /* Species info struct array */ { spec_mp spec; register double t; double r; real *site0 = site[0], *site1 = site[1], *site2 = site[2]; vec_mt rij; double rbin; /* 1.0/bin width */ int imol, isite, jsite, nsites = system->nsites; int *id = ialloc(system->nsites), *bind = ialloc(system->nsites); int *id_ptr; mat_mt hinv; double lx = system->h[0][0], lxy = system->h[0][1], ly = system->h[1][1], lxz = system->h[0][2], lz = system->h[2][2], lyz = system->h[1][2]; invert(system->h,hinv); rbin = control.nbins / control.limit; /* Construct and fill expanded site-identifier array, id */ id_ptr = id; for (spec = species; spec < &species[system->nspecies]; spec++) for(imol = 0; imol < spec->nmols; imol++) { memcp(id_ptr, spec->site_id, spec->nsites*sizeof(int)); id_ptr += spec->nsites; } for(isite = 0; isite < nsites; isite++) { VECTORIZE for(jsite = isite+1; jsite < nsites; jsite++) { rij[0] = site0[jsite] - site0[isite]; rij[1] = site1[jsite] - site1[isite]; rij[2] = site2[jsite] - site2[isite]; rij[0] -= lx * floor(MATMUL(0,hinv,rij) + 0.5); rij[0] -= lxy * (t = floor(MATMUL(1,hinv,rij) + 0.5)); rij[1] -= ly * t; rij[0] -= lxz * (t = floor(MATMUL(2,hinv,rij) + 0.5)); rij[1] -= lyz * t; rij[2] -= lz * t; r = sqrt(rij[0]*rij[0] + rij[1]*rij[1] + rij[2]*rij[2]); bind[jsite] = rbin*r; } for(jsite = isite+1; jsite < nsites; jsite++) { inhibit_vectorization(); if( bind[jsite] < control.nbins ) rdf[id[isite]][id[jsite]][bind[jsite]]++; } } xfree(id); xfree(bind); } /****************************************************************************** * rdf_accum. Calculate site pair distances and bin for RDF. * ******************************************************************************/ void rdf_accum(lo, hi, rsq, iid, id, nab) int lo, hi; real rsq[]; int iid; int id[]; int nab[]; { int j, bin; int *nj = nab + lo; int **rdfi = rdf[iid]; double rbin = control.nbins / control.limit; for(j=lo; jmax_id); /* Per site count of system*/ spec_mt *spec; double bin = control.limit/control.nbins, bincb = bin*bin*bin, rho = system->nsites/det(system->h); double norm; char buf[32]; memst(nfrac,0,system->max_id*sizeof(*nfrac)); for(spec = species; spec < species+system->nspecies; spec++) for(is = 0; is < spec->nsites; is++) nfrac[spec->site_id[is]] += spec->nmols; put_line('_'); (void)printf("\tRadial Distribution Functions\tBin width=%g", bin); new_line(); for(idi = 1; idi < system->max_id; idi++) for(idj = idi; idj < system->max_id; idj++) { (void)printf("\t%s-%s RDF", site_info[idi].name, site_info[idj].name); new_line(); col = 0; norm = 3.0*system->nsites*control.rdf_interval / (4.0*PI*bincb*rho*nfrac[idi]*nfrac[idj]*control.rdf_out); if( idi == idj ) norm += norm; for(ibin = 0; ibin < control.nbins; ibin++) { sprintf(buf, " %7f",rdf[idi][idj][ibin]*norm/ ( 3*(SQR(ibin) + ibin) + 1)); col += strlen(buf); if(col > control.page_width) { col = strlen(buf); new_line(); } fputs(buf, stdout); rdf[idi][idj][ibin] = 0; /* Reset */ } new_line(); } put_line('_'); xfree(nfrac); } $EOD $! $CREATE restart.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * restart functions for writing program configurations to a data file * * and rereading them. Because of the way they are used, the * * writing function is unitary, but the reading part is split * * between three routines. Contents: * * cread() Read data record from file, check length * * cwrite() Write length and data as record to file * * re_re_header() Read the restart header and control structs * * re_re_sysdef() Read system definition records from restart file * * read_restart() Read simulation dynamic variables, averages & rdf's * ****************************************************************************** * Revision Log * $Log: restart.c,v $ * Revision 2.10 1996/10/24 13:06:49 keith * Fixed restart structure correctly - broken in prev version. * Thermostat parameters may not be properly read. * * Revision 2.9 1996/01/12 15:45:52 keith * Reworked V. Murashov's thermostat code. * Convert mass params from kJ/mol ps^2 to prog units. Defaults=1. * Restored defaults of zero for Ewald sum params. * Modified Alpha/cutoff initialization to handle uncharged case correctly. * * Changed to macros from defs.h for input units. * * Revision 2.8 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/18 13:32:56 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:28:11 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.2 1993/10/22 12:44:23 keith * Fixed initialization bug which caused XDR write to fail on 64-bit Alphas. * * Revision 2.1 93/07/19 13:28:11 keith * Added XDR capability for backup and dump files. * * Revision 2.0 93/03/15 14:49:20 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.19 93/03/09 15:59:12 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.18 92/10/29 15:20:35 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.17 92/06/10 15:52:40 keith * Added capability to read restart files where NPOTP has changed. * * Revision 1.16 92/06/02 10:38:27 keith * Added check of ferror() as well as return from fwrite(). Talk * about belt and braces. * * Revision 1.15 92/03/24 12:41:07 keith * Moved reset-averages code to values.c and did it properly. * * Revision 1.14 92/03/19 15:14:12 keith * Added support for dynamic allocation of rolling average arrays, * conversion of existing restart files is done on fly. * * Revision 1.13 91/08/23 14:12:46 keith * Fixed declaration of av_ptr to agree with definition in values.c * * Revision 1.12 91/08/16 15:59:48 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.11 91/08/15 18:12:14 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.10 91/03/12 15:43:16 keith * Tidied up typedefs size_mt and include file * Added explicit function declarations. * * Revision 1.9 91/02/19 14:51:31 keith * Minor changes to get rid of misleading compiler warnings. * * Revision 1.8 90/08/24 17:47:26 keith * Made 'reset-averages' parameter actually do something. * * Revision 1.7 90/05/02 15:28:55 keith * Removed references to size_mt and time_t typedefs, no longer in "defs.h" * * Revision 1.6 89/11/01 17:40:36 keith * Read_restart modified to allow skip of read of averages data - * specified by asize=0. * * Revision 1.4 89/06/22 15:45:14 keith * Tidied up loops over species to use one pointer as counter. * * Revision 1.3 89/05/22 14:05:43 keith * Added rescale-separately option, changed 'contr_t' format. * * Revision 1.2 89/05/22 13:53:20 keith * Fixed to put correct RCS Revision into restart file header * * Revision 1.1 89/04/27 15:16:09 keith * Initial revision * * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/restart.c,v 2.10 1996/10/24 13:06:49 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include "string.h" #include "stddef.h" #include "time.h" #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" #include "xdr.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ int replace(); gptr *av_ptr(); char *atime(); char *cctime(); gptr *rdf_ptr(); #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ /*============================================================================*/ typedef struct {FILE *fp; XDR *xp;} xfp_mt; static size_mt stored_size = 0; static boolean xdr_read; static int size_flg = 0; /****************************************************************************** * creset() reset and rewind input stream. * ******************************************************************************/ static void creset(fp) FILE *fp; { size_flg = 0; if( fseek(fp,0L,0) ) message(NULLI,NULLP,FATAL,SEFAIL,"",strerror(errno)); } /****************************************************************************** * cnext. Read the size of the next 'record' stored in the file. * * Leave file pointer unchanged. ie do lookahead. * ******************************************************************************/ static size_mt cnext(xfp) xfp_mt xfp; { (void)fread((gptr*)&stored_size, sizeof stored_size, 1, xfp.fp); if(ferror(xfp.fp)) message(NULLI,NULLP,FATAL,REREAD,ftell(xfp.fp),strerror(errno)); else if(feof(xfp.fp)) message(NULLI,NULLP,FATAL,REEOF); size_flg++; return stored_size; } #ifdef USE_XDR static size_mt xdr_cnext(xfp) xfp_mt xfp; { if( xdr_read ) { if(!xdr_u_long(xfp.xp,&stored_size)) message(NULLI,NULLP,FATAL,REREAD,xdr_getpos(xfp.xp),strerror(errno)); size_flg++; return stored_size; } else return cnext(xfp); } #endif /****************************************************************************** * cread. read a word from the binary restart file. This should be the * * size of the next 'record' stored in the file. Check it against the * * expected value. Finally call fread to read in this data and check for * * error and end of file * ******************************************************************************/ static void cread(xfp, ptr, size, nitems, proc) xfp_mt xfp; gptr *ptr; size_mt size; int nitems; xdrproc_t proc; { int status; if( size_flg ) size_flg = 0; else { status = fread((gptr*)&stored_size, sizeof stored_size, 1, xfp.fp); if(ferror(xfp.fp)) message(NULLI,NULLP,FATAL,REREAD,ftell(xfp.fp),strerror(errno)); else if(feof(xfp.fp)) message(NULLI,NULLP,FATAL,REEOF); else if( status == 0 ) message(NULLI,NULLP,FATAL,"Unknown read error: %s",strerror(errno)); } if(stored_size != (unsigned long)size * nitems) message(NULLI,NULLP,FATAL,REFORM, ftell(xfp.fp), stored_size, size * nitems); status = fread(ptr, size, nitems, xfp.fp); if(ferror(xfp.fp)) message(NULLI,NULLP,FATAL,REREAD,ftell(xfp.fp),strerror(errno)); else if(feof(xfp.fp)) message(NULLI,NULLP,FATAL,REEOF); else if ( status < nitems ) message(NULLI,NULLP,FATAL,"Unknown write error"); } #ifdef USE_XDR static void xdr_cread(xfp, ptr, size, nitems, proc) xfp_mt xfp; gptr *ptr; size_mt size; int nitems; xdrproc_t proc; { unsigned int begin_data, end_data; if( xdr_read ) { if( size_flg ) size_flg = 0; else { if( xdr_u_long(xfp.xp,&stored_size) == 0 ) message(NULLI,NULLP,FATAL,REREAD,xdr_getpos(xfp.xp),strerror(errno)); } #if 0 if(stored_size != (unsigned long)size * nitems) message(NULLI,NULLP,FATAL,REFORM, ftell(xfp.fp), stored_size, size * nitems); #endif begin_data = xdr_getpos(xfp.xp); while(nitems > 0) { if (! (*proc)(xfp.xp,ptr) ) break; ptr = (gptr*) ((char*)ptr+size); nitems--; } end_data = xdr_getpos(xfp.xp); if ( nitems > 0 ) if(feof(xfp.fp)) message(NULLI,NULLP,FATAL,REEOF); else message(NULLI,NULLP,FATAL,"Unknown read error"); if(stored_size != end_data-begin_data) message(NULLI,NULLP,FATAL,REFORM, xdr_getpos(xfp.xp), stored_size, end_data-begin_data); } else cread(xfp, ptr, size, nitems, proc); } #endif /****************************************************************************** * cwrite. opposite of cread. write the length followed by the data * ******************************************************************************/ static void cwrite(xfp, ptr, size, nitems, proc) xfp_mt xfp; gptr *ptr; size_mt size; int nitems; xdrproc_t proc; { unsigned long length = (unsigned long)size*nitems; if( fwrite((gptr*)&length, sizeof length, 1, xfp.fp) == 0 ) message(NULLI,NULLP,FATAL,REWRT,strerror(errno)); if( fwrite(ptr, size, nitems, xfp.fp) < nitems ) message(NULLI,NULLP,FATAL,REWRT,strerror(errno)); } #ifdef USE_XDR static void xdr_cwrite(xfp, ptr, size, nitems, proc) xfp_mt xfp; gptr *ptr; size_mt size; int nitems; xdrproc_t proc; { unsigned long length=0; unsigned int begin_length, begin_data, end_data; if( control.xdr_write ) { /* * We can't calculate length in advance. Instead we post-calculate * it from "getpos" and backspace in order to write it. */ begin_length = xdr_getpos(xfp.xp); if( xdr_u_long(xfp.xp,&length) == 0) message(NULLI,NULLP,FATAL,REWRT,strerror(errno)); begin_data = xdr_getpos(xfp.xp); while(nitems > 0) { if( !(*proc)(xfp.xp,ptr) ) break; ptr = (gptr*) ((char*)ptr+size); nitems--; } if( nitems > 0 ) message(NULLI,NULLP,FATAL,REWRT,strerror(errno)); end_data = xdr_getpos(xfp.xp); length = end_data-begin_data; if( ! xdr_setpos(xfp.xp, begin_length) || ! xdr_u_long(xfp.xp,&length) || ! xdr_setpos(xfp.xp, end_data) ) message(NULLI,NULLP,FATAL,REWRT,strerror(errno)); } else cwrite(xfp, ptr, size, nitems, proc); } #endif #ifdef USE_XDR #define cread xdr_cread #define cwrite xdr_cwrite #define cnext xdr_cnext #endif /****************************************************************************** * re_re_header Read from the (already opened) restart file, the * * restart header and control structs. * ******************************************************************************/ static XDR xdrs; void re_re_header(restart, header, contr) FILE *restart; restrt_mt *header; contr_mt *contr; { int vmajor,vminor; xfp_mt xfp; xfp.xp = &xdrs; #ifdef USE_XDR xdr_read = TRUE; xdrstdio_create(xfp.xp, restart, XDR_DECODE); if( cnext(xfp) == XDR_RESTRT_SIZE ) { cread(xfp, (gptr*)header, lsizeof(restrt_mt), 1, xdr_restrt); header->vsn[15] = '\0'; /* Add terminator in case vsn is garbage*/ if( ! strstr(header->vsn,"(XDR)") ) xdr_read = FALSE; } else xdr_read=FALSE; if( ! xdr_read ) /* Didn't find XDR flag */ creset(restart); #endif xfp.fp=restart; if( ! xdr_read ) cread(xfp, (gptr*)header, lsizeof(restrt_mt), 1, xdr_restrt); cread(xfp, (gptr*)contr, lsizeof(contr_mt), 1, xdr_contr); /* * Parse header version */ if( sscanf(header->vsn, "%d.%d", &vmajor, &vminor) < 2 ) message(NULLI, NULLP, FATAL, INRVSN, header->vsn); /* * Bodge up botched control struct in restart files written by * Moldy 2.10 ir restart.c 2.9 */ if( vmajor == 2 && vminor == 9 ) { contr->ttmass = contr->rtmass = 10000.0; contr->const_temp = 0; message(NULLI,NULLP,WARNING,BODGUP,contr->ttmass); } } /****************************************************************************** * conv_potsize Convert potential parameters array if NPOTP has changed * ******************************************************************************/ static void conv_potsize(pot, old_pot_size, old_npotp, npotpar, npotrecs) pot_mt *pot; size_mt old_pot_size; int old_npotp, npotpar, npotrecs; { int i; char *tmp_pot; if( old_npotp == NPOTP ) return; else if ( npotpar <= NPOTP ) { note("Old potential parameter array size = %d, new = %d",old_npotp,NPOTP); tmp_pot = aalloc( old_pot_size*npotrecs, char); memcp(tmp_pot, pot, old_pot_size*npotrecs); for( i=0; i < npotrecs; i++) memcp(pot+i, tmp_pot+old_pot_size*i, MIN(old_pot_size,sizeof(pot_mt))); xfree(tmp_pot); } else message(NULLI, NULLP, FATAL, CPOTFL, NPOTP, npotpar); } /****************************************************************************** * re_re_sysdef Read the system specification from the restart file * * which must be open and pointed to by parameter 'file'. Set up the * * structures system and species and arrays site_info and potpar (allocating * * space) and read in the supplied values. * ******************************************************************************/ void re_re_sysdef(restart, vsn, system, spec_ptr, site_info, pot_ptr) FILE *restart; /* File pointer to read info from */ char *vsn; /* Version string file written with */ system_mp system; /* Pointer to system array (in main) */ spec_mp *spec_ptr; /* Pointer to be set to species array */ site_mp *site_info; /* To be pointed at site_info array */ pot_mp *pot_ptr; /* To be pointed at potpar array */ { spec_mp spec; size_mt old_pot_size; int old_npotp, n_pot_recs; int vmajor,vminor; xfp_mt xfp; xfp.xp = &xdrs; xfp.fp = restart; /* * Parse header version */ if( sscanf(vsn, "%d.%d", &vmajor, &vminor) < 2 ) message(NULLI, NULLP, FATAL, INRVSN, vsn); /* * Read in system structure. * Size changed in 2.11, read old files (XDR only). */ if( vmajor > 2 || (vmajor == 2 && vminor > 9) ) cread(xfp, (gptr*)system, lsizeof(system_mt), 1, xdr_system); else cread(xfp, (gptr*)system, lsizeof(system_mt)-10*lsizeof(real*), 1, xdr_system_2); /* Allocate space for species, site_info and potpar arrays and set pointers*/ *spec_ptr = aalloc(system->nspecies, spec_mt ); *site_info = aalloc(system->max_id, site_mt ); *pot_ptr = aalloc(system->max_id * system->max_id, pot_mt ); /* read species array into allocated space */ cread(xfp, (gptr*)*spec_ptr, lsizeof(spec_mt), system->nspecies, xdr_species); for (spec = *spec_ptr; spec < &(*spec_ptr)[system->nspecies]; spec++) { spec->p_f_sites = ralloc(spec->nsites); /* Allocate the species - */ spec->site_id = ialloc(spec->nsites); /* specific arrays */ cread(xfp,(gptr*)spec->p_f_sites, lsizeof(real), 3*spec->nsites, xdr_real); cread(xfp,(gptr*)spec->site_id, lsizeof(int), spec->nsites, xdr_int); } cread(xfp, (gptr*)*site_info, lsizeof(site_mt), system->max_id, xdr_site); /* * Potential Parameters -- complicated by need to convert if NPOTP changed. */ n_pot_recs = SQR(system->max_id); #ifdef USE_XDR if( xdr_read ) old_npotp = (cnext(xfp)/ n_pot_recs - 2*XDR_INT_SIZE)/XDR_REAL_SIZE; else #endif old_npotp = ((long)cnext(xfp)/ n_pot_recs - (long)sizeof(pot_mt))/ (long)sizeof(real) + NPOTP; old_pot_size = sizeof(pot_mt) + (old_npotp - NPOTP) * sizeof(real); *pot_ptr = (pot_mt*)aalloc(n_pot_recs*MAX(sizeof(pot_mt),old_pot_size), char); xdr_set_npotpar(old_npotp); /* Pass npotpar to xdr_pot. Ugh! */ cread(xfp, (gptr*)*pot_ptr, old_pot_size, n_pot_recs, xdr_pot); conv_potsize(*pot_ptr, old_pot_size, old_npotp, system->n_potpar, n_pot_recs); } /****************************************************************************** * read_restart. read the dynamic simulation variables from restart file. * ******************************************************************************/ void read_restart(restart, vsn, system, av_convert) FILE *restart; char *vsn; /* Version string file written with */ system_mp system; int av_convert; { gptr *ap; /* Pointer to averages database */ size_mt asize; /* Size of averages database */ boolean rdf_flag; /* Indicates whether file contains rdf*/ int rdf_size; gptr *rdf_base; int vmajor,vminor; xfp_mt xfp; /* * Parse header version */ if( sscanf(vsn, "%d.%d", &vmajor, &vminor) < 2 ) message(NULLI, NULLP, FATAL, INRVSN, vsn); xfp.xp= &xdrs; xfp.fp=restart; cread(xfp, (gptr*)system->c_of_m, lsizeof(real), 3*system->nmols, xdr_real); cread(xfp, (gptr*)system->vel, lsizeof(real), 3*system->nmols, xdr_real); cread(xfp, (gptr*)system->velp, lsizeof(real), 3*system->nmols, xdr_real); cread(xfp, (gptr*)system->acc, lsizeof(real), 3*system->nmols, xdr_real); cread(xfp, (gptr*)system->acco, lsizeof(real), 3*system->nmols, xdr_real); cread(xfp, (gptr*)system->accvo, lsizeof(real), 3*system->nmols, xdr_real); if(system->nmols_r > 0) { cread(xfp, (gptr*)system->quat, lsizeof(real), 4*system->nmols_r, xdr_real); cread(xfp, (gptr*)system->qdot, lsizeof(real), 4*system->nmols_r, xdr_real); cread(xfp, (gptr*)system->qdotp, lsizeof(real), 4*system->nmols_r, xdr_real); cread(xfp, (gptr*)system->qddot, lsizeof(real), 4*system->nmols_r, xdr_real); cread(xfp, (gptr*)system->qddoto, lsizeof(real), 4*system->nmols_r, xdr_real); cread(xfp, (gptr*)system->qddotvo, lsizeof(real), 4*system->nmols_r, xdr_real); } cread(xfp, (gptr*)system->h, lsizeof(real), 9, xdr_real); cread(xfp, (gptr*)system->hdot, lsizeof(real), 9, xdr_real); cread(xfp, (gptr*)system->hdotp, lsizeof(real), 9, xdr_real); cread(xfp, (gptr*)system->hddot, lsizeof(real), 9, xdr_real); cread(xfp, (gptr*)system->hddoto, lsizeof(real), 9, xdr_real); cread(xfp, (gptr*)system->hddotvo, lsizeof(real), 9, xdr_real); if( vmajor > 2 || (vmajor == 2 && vminor > 7) ) { cread(xfp, (gptr*)system->ta, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->tap, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->tadot, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->tadoto, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->tadotvo, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->ra, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->rap, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->radot, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->radoto, lsizeof(real), system->nspecies, xdr_real); cread(xfp, (gptr*)system->radotvo, lsizeof(real), system->nspecies, xdr_real); } ap = av_ptr(&asize,av_convert); /* get addr, size of database */ xdr_set_av_size_conv(asize,av_convert); /* Pass to xdr_averages. Ugh! */ cread(xfp, ap, asize, 1, xdr_averages); cread(xfp, (gptr*)&rdf_flag, lsizeof rdf_flag, 1, xdr_bool); /* Read flag signalling stored RDF data. */ if(rdf_flag && control.rdf_interval>0)/* Only read if data there and needed*/ { rdf_base = rdf_ptr(&rdf_size); cread(xfp, rdf_base, lsizeof(int), rdf_size, xdr_int); } #ifdef USE_XDR if( xdr_read ) xdr_destroy(xfp.xp); #endif } /****************************************************************************** * write_restart. Write the restart file. Included (in order) are * * the 'restart_header' and 'control' structs, the system-specification * * (system species, site_info and potpar data) and the dynamic variables. * ******************************************************************************/ void write_restart(save_name, header, system, species, site_info, potpar) char *save_name; /* Name of save file to be written */ restrt_mt *header; /* Restart header struct. */ system_mp system; /* Pointer to system array (in main) */ spec_mp species; /* Pointer to be set to species array */ site_mp site_info; /* To be pointed at site_info array */ pot_mp potpar; /* To be pointed at potpar array */ { spec_mp spec; gptr *ap; /* Pointer to averages database */ size_mt asize; /* Size of averages database */ int rdf_size; gptr *rdf_base; int zero = 0, one = 1; restrt_mt save_header; FILE *save; XDR xdrsw; xfp_mt xfp; char *vsn = "$Revision: 2.10 $"+11; save = fopen(control.temp_file, "wb"); if(save == NULL) { message(NULLI, NULLP, ERROR, OSFAIL, control.temp_file); return; } xfp.xp = &xdrsw; xfp.fp = save; #ifdef USE_XDR if( control.xdr_write ) xdrstdio_create(xfp.xp, save, XDR_ENCODE); #endif save_header = *header; (void)strncpy(save_header.vsn, vsn, sizeof save_header.vsn-1); save_header.vsn[strlen(save_header.vsn)-2] = '\0'; /* Strip trailing $ */ if( control.xdr_write ) (void)strncat(save_header.vsn," (XDR)",16); save_header.prev_timestamp = header->timestamp; save_header.timestamp = time((time_t*)0); /* Update header */ save_header.seq++; cwrite(xfp, (gptr*)&save_header, lsizeof save_header, 1, xdr_restrt); cwrite(xfp, (gptr*)&control, lsizeof control, 1, xdr_contr); cwrite(xfp, (gptr*)system, lsizeof(system_mt), 1, xdr_system); cwrite(xfp, (gptr*)species, lsizeof(spec_mt), system->nspecies, xdr_species); for (spec = species; spec < &species[system->nspecies]; spec++) { cwrite(xfp,(gptr*)spec->p_f_sites,lsizeof(real), 3*spec->nsites, xdr_real); cwrite(xfp,(gptr*)spec->site_id, lsizeof(int), spec->nsites, xdr_int); } cwrite(xfp, (gptr*)site_info, lsizeof(site_mt), system->max_id, xdr_site); xdr_set_npotpar(NPOTP); /* Pass npotpar to xdr_pot. Ugh! */ cwrite(xfp, (gptr*)potpar, lsizeof(pot_mt), SQR(system->max_id), xdr_pot); cwrite(xfp, (gptr*)system->c_of_m, lsizeof(real), 3*system->nmols, xdr_real); cwrite(xfp, (gptr*)system->vel, lsizeof(real), 3*system->nmols, xdr_real); cwrite(xfp, (gptr*)system->velp, lsizeof(real), 3*system->nmols, xdr_real); cwrite(xfp, (gptr*)system->acc, lsizeof(real), 3*system->nmols, xdr_real); cwrite(xfp, (gptr*)system->acco, lsizeof(real), 3*system->nmols, xdr_real); cwrite(xfp, (gptr*)system->accvo, lsizeof(real), 3*system->nmols, xdr_real); if(system->nmols_r > 0) { cwrite(xfp, (gptr*)system->quat, lsizeof(real), 4*system->nmols_r, xdr_real); cwrite(xfp, (gptr*)system->qdot, lsizeof(real), 4*system->nmols_r, xdr_real); cwrite(xfp, (gptr*)system->qdotp, lsizeof(real), 4*system->nmols_r, xdr_real); cwrite(xfp, (gptr*)system->qddot, lsizeof(real), 4*system->nmols_r, xdr_real); cwrite(xfp, (gptr*)system->qddoto, lsizeof(real), 4*system->nmols_r, xdr_real); cwrite(xfp, (gptr*)system->qddotvo, lsizeof(real), 4*system->nmols_r, xdr_real); } cwrite(xfp, (gptr*)system->h, lsizeof(real), 9, xdr_real); cwrite(xfp, (gptr*)system->hdot, lsizeof(real), 9, xdr_real); cwrite(xfp, (gptr*)system->hdotp, lsizeof(real), 9, xdr_real); cwrite(xfp, (gptr*)system->hddot, lsizeof(real), 9, xdr_real); cwrite(xfp, (gptr*)system->hddoto, lsizeof(real), 9, xdr_real); cwrite(xfp, (gptr*)system->hddotvo, lsizeof(real), 9, xdr_real); cwrite(xfp, (gptr*)system->ta, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->tap, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->tadot, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->tadoto, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->tadotvo, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->ra, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->rap, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->radot, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->radoto, lsizeof(real), system->nspecies, xdr_real); cwrite(xfp, (gptr*)system->radotvo, lsizeof(real), system->nspecies, xdr_real); ap = av_ptr(&asize,0); /* get addr, size of database */ xdr_set_av_size_conv(asize,0); /* Pass asize to xdr_averages. Ugh! */ cwrite(xfp, ap, asize, 1, xdr_averages); if(control.rdf_interval > 0) /* If we have rdf data */ { cwrite(xfp, (gptr*)&one, lsizeof(int), 1, xdr_bool);/* Flag rdf data */ rdf_base = rdf_ptr(&rdf_size); cwrite(xfp, rdf_base, lsizeof(int), rdf_size, xdr_int);/* write data */ } else cwrite(xfp, (gptr*)&zero, lsizeof(int), 1, xdr_bool);/*flag no rdf data*/ #ifdef USE_XDR if( control.xdr_write ) xdr_destroy(xfp.xp); #endif if( ferror(save) || fclose(save) ) /* Delayed write error? */ message(NULLI, NULLP, FATAL, REWRT, strerror(errno)); if(replace(control.temp_file, save_name) == 0)/* Rename temp file to output*/ { /* Don't signal backup write */ if(strcmp(save_name, control.backup_file)) note("Configuration written to save file \"%s\" at %s, Seq no %d", save_name, cctime(&save_header.timestamp), save_header.seq); } else message(NULLI, NULLP, ERROR, RNFAIL, save_name, control.temp_file, strerror(errno)); } $EOD $! $CREATE startup.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * startup Functions to perform operations to set up and initialise the * * simulation and control the reading of control parameters, * * system specification and restart files. Contents: * * start_up() Master start-up control function * * allocate_dynamics() Set up dynamic variable arrays by memory allocation * * initialise_sysdef() Calculate 'whole-system' quantities and more * * check_sysdef() Check new system specification is consistent with old * * interp() Scale derivatives when changing timestep * * skew_start() Set up skew-cyclic initial configuration * * random_start() Set up random initial configuration (not used) * * (N.B) lattice_start in "input.c" * * thermalise() Set up Maxwell-Boltzmann velocity distribution * * select_spec() Randomly choose a species * * random_quat() Generate quaternion for uniform random rotation * * gauss_rand() Return random sample from univariant gaussian * ****************************************************************************** * Revision Log * $Log: startup.c,v $ * Revision 2.12 1996/08/15 14:35:39 keith * Fixed restart structure correctly - broken in prev version. * Thermostat parameters may not be properly read. * * Revision 2.11 1996/01/15 15:23:30 keith * Changed input to new units * Reset defaults for cutoff, alpha to zero for "auto" select. * (Murashov's code missed this) * Added safety checks to auto-ewald routine. * * Revision 2.10 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.9 1995/01/03 13:56:39 keith * Added auto-generation of Ewald Sum parameters using Fincham's formulae. * * Revision 2.8 1994/07/07 16:57:01 keith * Updated for parallel execution on SPMD machines. * Interface to MP library routines hidden by par_*() calls. * Compile with -DSPMD to activate * * Revision 2.7 1994/06/08 13:16:34 keith * Changed all timestep-related parameters to type "long". This means * that 16-bit DOS compilers can do more than 32767 timesteps. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * * Moved declaration of "match" structure from input.c * Moved a few sanity tests & modifications of "control" * members to here from other modules. * * Revision 2.5 94/01/24 18:20:11 keith * Null checkin for release compatibility. * * Revision 2.4 94/01/24 18:18:35 keith * Deleted commented-out code for NR jacobi() function. Eigens() is * now well-tested. Eliminated compiler warnings. * * Added external "backup_restart" to flag that run started from a * backup file. For dump(). * * * Revision 2.3 93/10/28 10:28:13 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:22 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.6.1.27 93/03/13 01:45:58 keith * Replaced NR "jacobi.c" with "eigens.c" for public release. * * Revision 1.6.1.26 93/03/12 12:14:28 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.6.1.26 93/03/09 15:59:15 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.6.1.25 92/10/28 14:09:53 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.6.1.24 92/09/22 14:48:08 keith * Tidied up calls to improve "lint" rating. * * Revision 1.6.1.23 92/06/26 17:03:28 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.6.1.22 92/06/16 12:42:49 keith * Zeroed unit cell velocities/accns if constraint changed. * * Revision 1.6.1.21 92/06/11 21:39:58 keith * Fixed bug which meant you couldn't change backup file name in restart if backup existed. * Added file locking against multiple runs using same dump or backup files. * * Revision 1.6.1.20 92/04/21 17:50:08 keith * Fixed bug which compared char to NULL instead of 0. * * Revision 1.6.1.19 92/03/19 15:45:54 keith * Added support for dynamic allocation of rolling average arrays, * conversion of existing restart files is done on fly. * * Revision 1.6.1.18 92/03/11 12:56:11 keith * Changed "scale-separately" parameter to "scale options" * * Revision 1.6.1.17 91/08/16 15:26:09 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.6.1.16 91/08/15 18:12:16 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.6.1.15 91/03/12 15:43:19 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.6.1.14 91/02/04 18:20:08 keith * Call to inhibit vectorization() added on line 509 for titan. * Alloas use of vector_c option which otherwise caused crash. * * Revision 1.6.1.13 90/10/25 19:00:26 keith * Made interpolate_derivatives() robust against interpolation from zero. * * Revision 1.6.1.12 90/10/23 20:13:20 keith * Added dummy function call to inhibit vectorization. * This allows use of 'ivdep' compiler options and also * works round certain bugs in cray's scc compiler. * * Revision 1.6.1.11 90/08/24 17:46:42 keith * Made 'reset-averages' parameter actually do something. * * Revision 1.6.1.10 90/05/16 18:40:46 keith * Renamed own freer from cfree to tfree. * * Revision 1.6.1.9 90/05/16 14:20:28 keith * *** empty log message *** * * Revision 1.6.1.8 90/02/22 18:03:40 keith * Modified backup-restart code so as not to copy whole backup header into * restart header. This erroneously wrote a timestamp to dumps after restrart. * * Revision 1.6.1.7 89/11/21 16:32:38 keith * Removed member out_file from control and all uses. (Now command parameter). * Added new argument to specify output file. * Added default_control() to initialise control struct. * Fixed bug in start_up which tried to free unallocated var qpf. * * Revision 1.6.1.6 89/11/01 17:06:24 keith * Made allocate_dynamics() externally visible to allow link with 'mdshak'. * * Revision 1.6.1.5 89/10/05 18:18:02 keith * Modified initialise_sysdef() to stop rotation to princ frame of framework. * * Revision 1.6.1.4 89/09/21 15:02:57 keith * Test for old timestep of zero when altering timestep, in which case do nothing. * * Revision 1.6.1.3 89/09/19 14:50:15 keith * Fixed bug in check_sysdef which didn't increment species pointer. * * Revision 1.6.1.2 89/09/05 10:28:10 keith * Fixed bug in code to disable Ewald sum for uncharged system (init.._sysdef() * Added calculation of species total charge. * * Revision 1.6.1.1 89/08/31 10:14:40 keith * Mods to simulate framework structure * * Revision 1.6 89/08/30 12:36:26 keith * Modified start_up to fix bug which only considered rotations * of one species. In conjunction with change in lattice_start(). * * Revision 1.5 89/07/06 16:23:56 keith * Eliminated 'dump-offset' - renumbering starts at 1 for new dump run. * * Revision 1.4 89/06/23 15:35:10 keith * print-control option deleted. * * Revision 1.3 89/06/22 15:45:19 keith * Tidied up loops over species to use one pointer as counter. * * Revision 1.2 89/06/14 17:57:48 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.1 89/04/27 15:16:41 keith * Initial revision * * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/startup.c,v 2.12 1996/08/15 14:35:39 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #include #include "string.h" #include "stddef.h" #include "stdlib.h" #include /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void read_control(); void read_sysdef(); void lattice_start(); void conv_control(); void conv_potentials(); void init_averages(); void convert_averages(); void init_rdf(); void re_re_header(); void re_re_sysdef(); void read_restart(); void banner_page(); void zero_real(); void eigens(); void transpose(); void mat_vec_mul(); double det(); void q_mul(); void rot_to_q(); void print_sysdef(); char *atime(); double mdrand(); double precision(); void smdrand(); void inhibit_vectorization(); /* Self-explanatory dummy */ #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ extern int ithread, nthreads; /*========================== GLOBAL variables ================================*/ CONST unit_mt prog_unit = {MUNIT, LUNIT, TUNIT, QUNIT}; static unit_mt input_unit; /* Unit specification (see Convert.c) */ static char backup_lockname[L_name]; static char dump_lockname[L_name]; #ifdef DEBUG static char afmt[] = " %8s = %8X %8s = %8X %8s = %8X %8s = %8X\ %8s = %8X %8s = %8X\n"; #endif /* * Default backup and temporary file names if not set in "defs.h" */ #ifndef BACKUP_FILE #define BACKUP_FILE "MDBACKUP" #endif #ifndef TEMP_FILE #define TEMP_FILE "MDTEMPX" #endif /*========================== Control file keyword template ===================*/ /* * format SFORM is defined as %NAMLENs in structs.h, to avoid overflow. */ CONST match_mt match[] = { {"title", SFORM, "Test Simulation",(gptr*) control.title}, {"nsteps", "%ld", "0", (gptr*)&control.nsteps}, {"step", "%lf", "0.005", (gptr*)&control.step}, {"text-mode-save", "%d", "0", (gptr*)&control.print_sysdef}, {"new-sys-spec", "%d", "0", (gptr*)&control.new_sysdef}, {"scale-options" , "%d", "0", (gptr*)&control.scale_options}, {"therm-options" , "%d", "0", (gptr*)&control.scale_options}, {"surface-dipole", "%d", "0", (gptr*)&control.surface_dipole}, {"lattice-start", "%d", "0", (gptr*)&control.lattice_start}, {"sys-spec-file", SFORM, "", (gptr*)control.sysdef}, {"restart-file", SFORM, "", (gptr*)control.restart_file}, {"save-file", SFORM, "", (gptr*)control.save_file}, {"dump-file", SFORM, "", (gptr*)control.dump_file}, {"backup-file", SFORM, BACKUP_FILE, (gptr*)control.backup_file}, {"temp-file", SFORM, TEMP_FILE, (gptr*)control.temp_file}, {"strict-cutoff", "%d", "0", (gptr*)&control.strict_cutoff}, {"xdr", "%d", "1", (gptr*)&control.xdr_write}, {"strain-mask", "%d", "200", (gptr*)&control.strain_mask}, {"nbins", "%d", "100", (gptr*)&control.nbins}, {"seed", "%ld", "1234567", (gptr*)&control.seed}, {"page-width", "%d", "132", (gptr*)&control.page_width}, {"page-length", "%d", "44", (gptr*)&control.page_length}, {"scale-interval", "%ld", "10", (gptr*)&control.scale_interval}, {"const-pressure", "%d", "0", (gptr*)&control.const_pressure}, {"const-temp", "%d", "0", (gptr*)&control.const_temp}, {"reset-averages", "%d", "0", (gptr*)&control.reset_averages}, {"scale-end", "%ld", "1000000", (gptr*)&control.scale_end}, {"begin-average", "%ld", "1001", (gptr*)&control.begin_average}, {"average-interval", "%ld", "5000", (gptr*)&control.average_interval}, {"begin-dump", "%ld", "1", (gptr*)&control.begin_dump}, {"dump-interval", "%ld", "20", (gptr*)&control.dump_interval}, {"dump-level", "%d", "0", (gptr*)&control.dump_level}, {"ndumps", "%d", "250", (gptr*)&control.maxdumps}, {"backup-interval", "%ld", "500", (gptr*)&control.backup_interval}, {"roll-interval", "%ld", "10", (gptr*)&control.roll_interval}, {"print-interval", "%ld", "10", (gptr*)&control.print_interval}, {"begin-rdf", "%ld", "1000000", (gptr*)&control.begin_rdf}, {"rdf-interval", "%ld", "20", (gptr*)&control.rdf_interval}, {"rdf-out", "%ld", "5000", (gptr*)&control.rdf_out}, {"temperature", "%lf", "0.0", (gptr*)&control.temp}, {"pressure", "%lf", "0.0", (gptr*)&control.pressure}, {"w", "%lf", "100.0", (gptr*)&control.pmass}, {"rtmass", "%lf", "100.0", (gptr*)&control.rtmass}, {"ttmass", "%lf", "100.0", (gptr*)&control.ttmass}, {"cutoff", "%lf", "0.0", (gptr*)&control.cutoff}, {"subcell", "%lf", "0.0", (gptr*)&control.subcell}, {"density", "%lf", "1.0", (gptr*)&control.density}, {"alpha", "%lf", "0.0", (gptr*)&control.alpha}, {"k-cutoff", "%lf", "0.0", (gptr*)&control.k_cutoff}, {"rdf-limit", "%lf", "10.0", (gptr*)&control.limit}, {"cpu-limit", "%lf", "1.0e20", (gptr*)&control.cpu_limit}, {"mass-unit", "%lf", AMUSTR, (gptr*)&input_unit.m}, {"length-unit", "%lf", "1.0e-10", (gptr*)&input_unit.l}, {"time-unit", "%lf", "1.0e-13", (gptr*)&input_unit.t}, {"charge-unit", "%lf", ECSTR, (gptr*)&input_unit.q}, {0,0,0,0} }; /* Null termination essential. */ /*============================================================================* * Functions for external access to globals. * *============================================================================*/ void rmlockfiles() { if( backup_lockname[0] ) (void)remove(backup_lockname); if( dump_lockname[0] ) (void)remove(dump_lockname); } /*============================================================================*/ /****************************************************************************** * default_control. Initialise 'control' with default values from 'match' * ******************************************************************************/ static void default_control() { CONST match_mt *match_p; char tmp[64]; for( match_p = match; match_p->key; match_p++) (void)sscanf(strncpy(tmp,match_p->defalt, sizeof tmp), match_p->format, match_p->ptr); } /****************************************************************************** * gauss_rand. Return a random variable from a gaussian distribution with uni * * variance. After Press, Plannery, Teulkolsk & Vetterling p202. * ******************************************************************************/ static double gauss_rand() { static int set = 1; static double gset; double v1, v2, r, fac; if(set) { do { v1 = 2.0*mdrand()-1.0; v2 = 2.0*mdrand() - 1.0; r = v1*v1 + v2*v2; } while(r > 1.0); fac = sqrt(-2.0 * log(r) / r); gset = v1 * fac; set = 0; return(v2*fac); } else { set = 1; return(gset); } } /****************************************************************************** * random_quat. Generate quaternions to represent uniform random rotations. * * If q=(cos(psi/2), l sin(psi/2)) , l is a unit vector, uniformity requires * * that q(0) be distributed linearly ie p(q(0)) = q(0). L is a random unit * * vector, generated from spherical co-ordinates theta and phi with * * distribution p(theta) = sin(theta) * ******************************************************************************/ static void random_quat(q, n) quat_mp q; /* First quaternion (out) */ int n; /* Number to be generated. (in) */ { double phi, cos_theta, sin_theta, st2; while(n-- > 0) { phi = 2.0*PI*mdrand(); /* Phi is uniform on [0, 2pi) */ cos_theta = 1.0 - 2.0*mdrand(); /* 0 <= theta < pi, p(theta)=sin() */ sin_theta = sqrt(1.0 - SQR(cos_theta)); (*q)[0] = sqrt(mdrand()); st2 = sqrt(1.0 - SQR((*q)[0])); (*q)[1] = st2*sin_theta*sin(phi); (*q)[2] = st2*sin_theta*cos(phi); (*q)[3] = st2*cos_theta; q++; } } /****************************************************************************** * select_spec Choose a species at random, weighted by proportion of whole * ******************************************************************************/ static spec_mp select_spec(system, species) system_mp system; spec_mt species[]; { int sel = mdrand() * system->nmols; spec_mp spec; for (spec = species; spec < species+system->nspecies; spec++) { if(sel < spec->nmols) return(spec); sel -= spec->nmols; } return((spec_mp)-1); } /****************************************************************************** * skew_start. Make a starting configuration with all molecules arranged at * * regular intervals on a line passing at an angle through the MD cell. This* * permits a reasonable spacing between molecules without restricting the * * number allowed as in a lattice start. * ******************************************************************************/ static void skew_start(system, species) system_mp system; spec_mt species[]; { int ispec, imol; /* Counters for species, molecules etc*/ spec_mp spec; double mass = 0.0; /* Whole system mass */ double n_third = pow((double)system->nmols,1.0/3.0); int nz = 1, ny = (int)(n_third+0.5), nx = (int)(SQR(n_third)+0.5); int *nmols = ialloc(system->nspecies), nm; double delta_x = (double)nx / system->nmols, delta_y = (double)ny / system->nmols, delta_z = (double)nz / system->nmols; for (spec = species; spec < species+system->nspecies; spec++) { inhibit_vectorization(); /* Circumvent cray scc bug */ mass += spec->mass * spec->nmols; } system->h[0][0] = system->h[1][1] = system->h[2][2] = pow(mass/control.density, 1.0/3.0); /* L = cube root of mass/density */ memst(nmols, 0, system->nspecies*sizeof(int)); for(imol = 0; imol < system->nmols; imol++) { do { spec = select_spec(system, species); /* Choose species */ ispec = spec-species; } while(nmols[ispec] >= spec->nmols); /* Repeat if all set */ nm = nmols[ispec]; spec->c_of_m[nm][0] = imol*delta_x; spec->c_of_m[nm][1] = imol*delta_y; spec->c_of_m[nm][2] = imol*delta_z; nmols[ispec]++; } random_quat(system->quat, system->nmols_r); xfree(nmols); } /****************************************************************************** * random_start. This function generates a completely random starting * * configuration. Molecules are placed at random locations and orientations * * in md box, whose size is chosed to give the required density. * ******************************************************************************/ #ifdef NOT_FOR_NOW void random_start(system, species) system_mp system; spec_mt species[]; { int imol, i; /* Counters for species, molecules etc*/ double mass = 0.0; /* Whole system mass */ for (spec = species; spec < species+system->nspecies; spec++) mass += spec->mass * spec->nmols; system->h[0][0] = system->h[1][1] = system->h[2][2] = pow(mass/control.density, 1.0/3.0); /* L = cube root of mass/density */ for(imol = 0; imol < system->nmols; imol++) for(i = 0; i < 3; i++) /* Centre of mass co-ords -1 < x < 1 */ system->c_of_m[imol][i] = mdrand() - 1.0; random_quat(system->quat, system->nmols_r); } #endif /****************************************************************************** * thermalise set velocities and quaternion derivatives to values sampled * * at random from the Boltzmann distribution for the required temperature. * ******************************************************************************/ void thermalise(system, species) system_mp system; spec_mt species[]; { int imol, i; /* Counters for species, molecules etc*/ spec_mp spec; /* Pointer to species[ispec] */ double omega_sq; /* |omega|squared / 4 */ double root_ktm, root_kti[3]; /* Gaussian widths of MB distribution */ double total_mass = 0; vec_mt momentum; /* Whole system momentum */ zero_real(momentum, 3); /* * Set accelerations to zero. */ zero_real(system->vel[0], 3*system->nmols); zero_real(system->acc[0], 3*system->nmols); zero_real(system->acco[0], 3*system->nmols); zero_real(system->accvo[0], 3*system->nmols); zero_real(system->ta, system->nspecies); zero_real(system->tap, system->nspecies); zero_real(system->tadot, system->nspecies); zero_real(system->tadoto, system->nspecies); zero_real(system->tadotvo, system->nspecies); zero_real(system->ra, system->nspecies); zero_real(system->rap, system->nspecies); zero_real(system->radot, system->nspecies); zero_real(system->radoto, system->nspecies); zero_real(system->radotvo, system->nspecies); for (spec = species; spec < species+system->nspecies; spec++) { if( !spec->framework) { root_ktm = sqrt(kB * control.temp / spec->mass) / system->h[0][0]; total_mass += spec->mass*spec->nmols; for(imol = 0; imol < spec->nmols; imol++) for(i = 0; i < 3; i++) /* Centre of mass co-ords -1 < x < 1 */ { spec->vel[imol][i] = root_ktm * gauss_rand(); momentum[i] += spec->mass*spec->vel[imol][i]; } if(spec->rdof > 0) { for(i = 0; i < 3; i++) if(spec->inertia[i] != 0.0) root_kti[i] = 0.5*sqrt(kB * control.temp / spec->inertia[i]); else root_kti[i] = 0.0; for(imol = 0; imol < spec->nmols; imol++) { spec->qdot[imol][0] = 0.0; for(i = 0; i < 3; i++) /* Centre of mass co-ords -1 < x < 1 */ spec->qdot[imol][i+1] = root_kti[i] * gauss_rand(); omega_sq = -SUMSQ2(spec->qdot[imol]); for(i = 0; i < 4; i++) spec->qddotvo[imol][i] = spec->qddoto[imol][i] = spec->qddot[imol][i] = omega_sq*spec->quat[imol][i]; } } } } q_mul(system->quat, system->qdot, system->qdot, system->nmols_r); for (spec = species; spec < species+system->nspecies; spec++) if( !spec->framework) { for(i = 0; i < 3; i++) for(imol = 0; imol < spec->nmols; imol++) spec->vel[imol][i] -= momentum[i] / total_mass; } } /****************************************************************************** * initialise_sysdef Computes various quanities and completes the set-up * * of the system once it has been read in. Quantities computed are :- * * Total numbers of molecules, sites, degrees of freedom in whole system, * * mass and inertia tensor for each species. The molecular site co- * * ordinates are re-expressed wrt the molecular centre of mass, the inertia * * tensor is diagonalised and the site co-ordinates rotated to the principal * * frame. * ******************************************************************************/ #define LTR(i,j) (((i)*(i)+(i))/2+(j)) void initialise_sysdef(system, species, site_info, qpf) system_mp system; spec_mt species[]; site_mt site_info[]; quat_mt qpf[]; /* Quaternion rotation to princ.frame*/ { vec_mt c_of_m; /* Co-ordinates of centre of mass */ vec_mt dipole; /* Molecular dipole moment */ real inertia[6]; /* Inertia tensor */ mat_mt v; /* Transformation matrix to prin. fr.*/ spec_mp spec; /* Used for looping over species */ double mass; /* Temporary for site mass */ int nz; /* Count of zero moments of inertia */ int i, j, isite, id; /* Various loop counters */ boolean flag; /* Used to test for charges */ double imax; /* Largest moment of inertia */ double eps = 10.0*precision(); /* Criterion for "zero" moment. */ system->nsites = 0; system->nmols = 0; system->nmols_r = 0; system->d_of_f = 0; for (spec = species; spec < species+system->nspecies; spec++) { /* Loop over molecular species */ system->nmols += spec->nmols; system->nsites += spec->nmols * spec->nsites; if( !spec->framework ) system->d_of_f += spec->nmols * 3; zero_real(c_of_m,3); /* Initialise C_of_M for this species*/ zero_real(dipole,3); /* And dipole moment */ spec->mass = 0.0; /* Mass */ spec->charge = 0.0; /* And total charge */ for(isite=0; isite < spec->nsites; isite++) /* Calculate (sum m*r) and */ { /* molecular mass. */ for(i=0; i<3; i++) c_of_m[i] += spec->p_f_sites[isite][i] * site_info[spec->site_id[isite]].mass; spec->mass += site_info[spec->site_id[isite]].mass; spec->charge += site_info[spec->site_id[isite]].charge; } if(spec->mass < 1.0) /* Lighter than 1 amu ? */ message(NULLI,NULLP,FATAL,ZMASS,spec->name,spec->mass); for(i=0; i < 3; i++) /* Finish calculation of c. of mass. */ c_of_m[i] /= spec->mass; for(isite=0; isite < spec->nsites; isite++) for(i=0; i < 3; i++) /* Subtract c_of_m from co-ordinates */ spec->p_f_sites[isite][i] -= c_of_m[i]; if(spec->nsites > 1) /* If molecule is polyatomic */ { zero_real(inertia,6); /* Initialise inertia tensor */ for(isite=0; isite < spec->nsites; isite++) { mass = site_info[spec->site_id[isite]].mass; for(i=0; i < 3; i++) /* Calculate inertia tensor */ { inertia[LTR(i,i)] += mass * SUMSQ(spec->p_f_sites[isite]); for(j=0; j <= i; j++) inertia[LTR(i,j)] -= mass * spec->p_f_sites[isite][i] * spec->p_f_sites[isite][j]; } } #ifdef DEBUG printf(" *D* Molecule type %d, mass = %g, C of M = (%g,%g,%g)\n", spec-species, spec->mass, c_of_m[0], c_of_m[1], c_of_m[2]); print_mat(inertia, " *D* Inertia Tensor"); #endif eigens(inertia,v[0],spec->inertia,3); rot_to_q(v, qpf[spec-species]); /* make equivalent quaternion*/ #ifdef DEBUG print_mat(v," *D* Rotation Mat."); #endif imax = MAX3(spec->inertia[0],spec->inertia[1],spec->inertia[2]); nz = 0; for( i=0; i<3; i++) /* Count zero moments. */ if( spec->inertia[i] < eps*imax ) { nz++; spec->inertia[i] = 0.0; } spec->rdof = 3-nz; /* Rotational deg. of freedom*/ if( spec->framework ) /* Frameworks can't rotate */ { spec->rdof = 0; spec->quat = 0; } if(spec->rdof > 0) /* Count molecules with */ { system->nmols_r += spec->nmols; /* rotational freedom. */ mat_vec_mul(v,spec->p_f_sites, spec->p_f_sites, spec->nsites); } system->d_of_f += spec->rdof * spec->nmols;/* Count total d of f */ for(i = 0; i < 3; i++) /* Calculate molecular dipole*/ for(isite = 0; isite < spec->nsites; isite++) dipole[i] += spec->p_f_sites[isite][i] * site_info[spec->site_id[isite]].charge; spec->dipole = sqrt(SUMSQ(dipole)); } else { spec->dipole = 0; spec->rdof = 0; zero_real(spec->inertia,3); spec->quat = 0; } } #ifdef DEBUG printf(" *D* Totals: nsites = %d, nmols = %d, nmols_r = %d, dof = %d\n", system->nsites, system->nmols, system->nmols_r, system->d_of_f); #endif flag = false; /* Test to see if any charges present */ for(id = 1; id < system->max_id; id++) flag |= (site_info[id].charge != 0.0); if(!flag) control.alpha = -1.0; /* Don't call Ewald sum if not */ } /****************************************************************************** * allocate_dynamics Allocate memory for the dynamic MD variables * ******************************************************************************/ void allocate_dynamics(system, species) system_mp system; spec_mt species[]; { spec_mp spec; /* Alias for species[ispec] */ int nmol_cum = 0, /* Cumulative number of molecules */ nmolr_cum = 0; /* As above excluding point atoms */ system->c_of_m = ralloc(system->nmols); system->vel = ralloc(system->nmols); system->velp = ralloc(system->nmols); system->acc = ralloc(system->nmols); system->acco = ralloc(system->nmols); system->accvo = ralloc(system->nmols); #ifdef DEBUG printf(" *D* System Dynamic variables (all %d x 3 reals)\n",system->nmols); printf(afmt,"c_of_m",system->c_of_m,"vel",system->vel,"velp",system->velp, "acc",system->acc,"acco",system->acco,"accvo",system->accvo); #endif system->ta = dalloc(system->nspecies); system->tap = dalloc(system->nspecies); system->tadot = dalloc(system->nspecies); system->tadoto = dalloc(system->nspecies); system->tadotvo = dalloc(system->nspecies); system->ra = dalloc(system->nspecies); system->rap = dalloc(system->nspecies); system->radot = dalloc(system->nspecies); system->radoto = dalloc(system->nspecies); system->radotvo = dalloc(system->nspecies); if(system->nmols_r > 0) { system->quat = qalloc(system->nmols_r); system->qdot = qalloc(system->nmols_r); system->qdotp = qalloc(system->nmols_r); system->qddot = qalloc(system->nmols_r); system->qddoto = qalloc(system->nmols_r); system->qddotvo= qalloc(system->nmols_r); } else system->quat = system->qdot = system->qdotp = system->qddot = system->qddoto = system->qddotvo= 0; system->h = ralloc(3); system->hdot = ralloc(3); system->hdotp = ralloc(3); system->hddot = ralloc(3); system->hddoto = ralloc(3); system->hddotvo = ralloc(3); zero_real(system->h[0], 9); zero_real(system->hdot[0], 9); zero_real(system->hddot[0], 9); zero_real(system->hddoto[0], 9); zero_real(system->hddotvo[0], 9); #ifdef DEBUG printf(" *D* System Dynamic variables (all 9 reals)\n"); printf(afmt,"h",system->h, "hdot",system->hdot, "hdotp",system->hdotp, "hddot",system->hddot,"hddoto",system->hddoto,"hddotvo",system->hddotvo); #endif for (spec = species; spec < species+system->nspecies; spec++) { inhibit_vectorization(); spec->c_of_m = system->c_of_m + nmol_cum; spec->vel = system->vel + nmol_cum; spec->velp = system->velp + nmol_cum; spec->acc = system->acc + nmol_cum; spec->acco = system->acco + nmol_cum; spec->accvo = system->accvo + nmol_cum; #ifdef DEBUG printf(" *D* Species %d Dynamic variables (all %d x 3 reals)\n", spec-species, spec->nmols); printf(afmt,"c_of_m",spec->c_of_m,"vel",spec->vel,"velp",spec->velp, "acc",spec->acc,"acco",spec->acco,"accvo",spec->accvo); #endif if(spec->rdof > 0) { spec->quat = system->quat + nmolr_cum; spec->qdot = system->qdot + nmolr_cum; spec->qdotp = system->qdotp + nmolr_cum; spec->qddot = system->qddot + nmolr_cum; spec->qddoto = system->qddoto + nmolr_cum; spec->qddotvo = system->qddotvo + nmolr_cum; nmolr_cum += spec->nmols; #ifdef DEBUG printf(" *D* Species %d Dynamic variables (all %d x 4 reals)\n", spec-species, spec->nmols); printf(afmt,"quat",spec->quat, "qdot",spec->qdot, "qdotp",spec->qdotp, "qddot",spec->qddot,"qddoto",spec->qddoto,"qddotvo",spec->qddotvo); #endif } else spec->quat = spec->qdot = spec->qdotp = spec->qddot = spec->qddoto = spec->qddotvo= 0; nmol_cum += spec->nmols; } /* * These may not be initialised if reading an old restart file, * so zero them here for safety. */ zero_real(system->ta, system->nspecies); zero_real(system->tap, system->nspecies); zero_real(system->tadot, system->nspecies); zero_real(system->tadoto, system->nspecies); zero_real(system->tadotvo, system->nspecies); zero_real(system->ra, system->nspecies); zero_real(system->rap, system->nspecies); zero_real(system->radot, system->nspecies); zero_real(system->radoto, system->nspecies); zero_real(system->radotvo, system->nspecies); } /****************************************************************************** * Interpolate_derivatives & interp. Interp is a quadratic interpolation * * routine for scaling derivatives for a new timestep. * * Interpolate_derivatives calls it for all the dynamic variables. * ******************************************************************************/ static void interp(ratio, x, xo, xvo, n) double ratio; /* Between old and new timesteps */ real *x, *xo, *xvo; /* Pointers to 1st dynamic variable */ int n; /* Size of arrays x, xo, xvo */ { double c1 = 1.0 - 1.5*ratio + 0.5*SQR(ratio), c2 = 2.0*ratio - SQR(ratio), c3 = -0.5*ratio + 0.5*SQR(ratio), c4 = 1.0 - 3.0*ratio + 2.0*SQR(ratio), c5 = 4.0*ratio - 4.0*SQR(ratio), c6 = -1.0*ratio + 2.0*SQR(ratio); double tmp; while(n-- > 0) { tmp = *xo; *xo = c1 * *x + c2 * *xo + c3 * *xvo; *xvo = c4 * *x + c5 * tmp + c6 * *xvo; x++; xo++; xvo++; } } static void interpolate_derivatives(sys, step, step1) system_mp sys; double step, step1; { double ratio; if( step == 0.0 ) { message(NULLI, NULLP, WARNING, ZEROTS, step1); return; } ratio = step1/step; message(NULLI, NULLP, INFO, NEWTS, step, step1); interp(ratio, sys->acc[0], sys->acco[0], sys->accvo[0], 3*sys->nmols); if( sys->nmols_r > 0 ) interp(ratio, sys->qddot[0], sys->qddoto[0],sys->qddotvo[0], 4*sys->nmols_r); interp(ratio, sys->hddot[0], sys->hddoto[0],sys->hddotvo[0], 9); interp(ratio, sys->tadot, sys->tadoto, sys->tadotvo, sys->nspecies); interp(ratio, sys->radot, sys->radoto, sys->radotvo, sys->nspecies); } /****************************************************************************** * check_sysdef. Read in system specification from the restart * * file and check its consistency with the previously defined spec. This is * * for use when replacing the system spec in the middle of a run. The system* * spec from restart is discarded. Only the minimum checks are applied for * * the dynamic variables stored in the restart file to make sense with the * * new system spec. Checked are a) Number of species, b) Number of molecules* * of each species and c) that the molecules have the same rotational degrees* * of freedom. The number of sites can change subject to c). * ******************************************************************************/ static void check_sysdef(restart, vsn, system, species) FILE *restart; /* Restart file pointer */ char *vsn; /* restart file version. */ system_mp system; /* NEW 'system' struct */ spec_mt species[]; /* NEW 'species' struct array */ { system_mt sys_tmp; /* Local temporaries of system, */ spec_mp spec_tmp, spec; /* species, site_info and potpar */ site_mp site_tmp; /* used when overwriting restart */ pot_mp pot_tmp; /* sysdef. */ re_re_sysdef(restart, vsn, &sys_tmp, &spec_tmp, &site_tmp, &pot_tmp); if(system->nspecies != sys_tmp.nspecies) message(NULLI, NULLP, FATAL, NSPCON, system->nspecies, sys_tmp.nspecies); for (spec = species; spec < species+system->nspecies; spec++, spec_tmp++) { if(spec->nmols != spec_tmp->nmols) message(NULLI, NULLP, FATAL, NMLCON, spec_tmp->name, spec->nmols, spec_tmp->nmols); if(spec->rdof != spec_tmp->rdof) message(NULLI, NULLP, FATAL, NDFCON, spec_tmp->name, spec->rdof, spec_tmp->rdof); xfree(spec_tmp->p_f_sites); xfree(spec_tmp->site_id); } xfree((spec_tmp-system->nspecies)); xfree(site_tmp); xfree(pot_tmp); } /****************************************************************************** * Init_cutoffs. Set the initial values of the alpha parameter and cutoffs * * for the Ewald Sum according to the formulae in Fincham, (1993) CCP5 38, p17* * alpha = (nsites*pi^3/V^2 tr/tf)^1/6 is the optmum value * * r_c = p^1/2 / alpha and k_c = 2 * alpha / p^1/2 * * are the cutoffs which giva an accuracy of exp(-p). Here use 10^-5. * * Any value explicity specified in the control file is left alone. * ******************************************************************************/ #define LOGACC 11.5 /* p =11.5 <=> acc = 10^-5 */ #define TRoverTF 5.5 /* Ratio of indiv. interaction times - approx */ void init_cutoffs(alpha, cutoff, k_cutoff, h, nsites) double *alpha, *cutoff, *k_cutoff; mat_mt h; int nsites; { double max_cutoff = MIN3(h[0][0], h[1][1], h[2][2]); double vol = det(h); if( *alpha == 0.0 ) *alpha = pow(nsites*CUBE(PI)/SQR(vol)*TRoverTF, 1.0/6.0); if( *alpha > 0.0 ) { if( *cutoff == 0.0 ) { *cutoff = sqrt(LOGACC)/ *alpha; if( *cutoff > max_cutoff ) { message( NULLI, NULLP, WARNING, MAXCUT, *cutoff, max_cutoff); *cutoff = max_cutoff; } } if( *k_cutoff == 0.0 ) *k_cutoff = 2.0* (*alpha) * sqrt(LOGACC); } else if ( *cutoff <= 0.0 ) message(NULLI, NULLP, FATAL, NOCUT, *cutoff); } /****************************************************************************** * startup This function sets up everything that is needed to start a * * run. It controls the reading in of the control, system specification and * * restart files, conversions to program units, calculation of molecular * * mass & moments of inertia and evaluation of 'whole system' quantities eg * * number of molecules. * ******************************************************************************/ void start_up(contr_name, out_name, system, species, site_info, potpar, restart_header, backup_restart) char *contr_name, /* Name of control file "" for stdin */ *out_name; /* Name of output file "" for stdout */ system_mp system; /* Pointer to system struct */ spec_mp *species; /* Pointer to species array */ site_mp *site_info; /* Pointer to site_info array */ pot_mp *potpar; /* Pointer to pot'l parameter array */ restrt_mt *restart_header; /* Pointer to restart hdr info (out) */ int *backup_restart; /* (ptr to) flag said purpose (out) */ { FILE *contr_file, /* File pointer for control read */ *sysdef, /* File pointer for sysdef file read */ *backup = NULL, /* File pointer for backup file read */ *restart = NULL, /* File pointer for restart file read */ *lock; /* File pointer for lockfile */ double old_step; /* Timestep read from restart file */ long old_dump_interval; /* To check if altered on restart */ int old_max_dumps; /* To check if altered on restart */ long old_roll_interval; /* To check if altered on restart */ boolean flag; /* Used to test 'fseek' */ long pos; /* Where control info starts on input */ restrt_mt backup_header; /* To read backup file header into */ contr_mt backup_control; /* Control struct from backup file */ quat_mt *qpf=0; /* Quat of rotation to princ. frame */ int av_convert; /* Flag for old-fmt averages in restrt*/ int i; *backup_restart = 0; (void)memst(restart_header,0,sizeof(*restart_header)); if(contr_name[0] == '\0') /* Null name - read control from */ contr_file = stdin; /* standard input. */ else /* Open named file for reading control*/ { contr_file = fopen(contr_name,"r"); if(contr_file == NULL) message(NULLI, NULLP, FATAL, OCFAIL, contr_name, strerror(errno)); } pos = ftell(contr_file); /* Current file pos needed for cray */ default_control(); /* Set up default values of params */ read_control(contr_file, match); /* Do keyword read of control params */ conv_control(&prog_unit,true); /* Convert to program units */ if(control.restart_file[0] != '\0') /* Open restart file, get backup name */ { if((restart = fopen(control.restart_file,"rb")) == NULL) message(NULLI, NULLP, FATAL, ORFAIL, control.restart_file, strerror(errno)); re_re_header(restart, restart_header, &control); /* * Now reread control file to override restart file defaults. * Need to do this here in case backup file name changed. */ old_step = control.step; /* Needed for scaling */ old_roll_interval = control.roll_interval; /* In case it changed */ old_dump_interval = control.dump_interval; /* Check if these par */ old_max_dumps = control.maxdumps; /* -amaters altered. */ conv_control(&prog_unit, false); control.scale_end -= control.istep; /* These parameters */ control.begin_average -= control.istep; /* are respecified */ control.begin_rdf -= control.istep; /* RELATIVE to current*/ control.begin_dump -= control.istep; /* time step. */ control.nsteps -= control.istep; flag = fseek(contr_file,pos,0); /* Rewind control file*/ if( flag ) message(NULLI,NULLP,FATAL,SEFAIL,contr_name[0]?contr_name:"stdin", strerror(errno)); read_control(contr_file, match); /* Reread control file*/ conv_control(&prog_unit,true); /* Back to prog units */ } /* * At this point we have read the control file, read the control * parameters from the restart file (if specified). Now we * know the name of the backup file (Whew!). Now we have * all the parameter values we can set up and test the lockfiles. */ if( ithread == 0 && control.backup_file[0] ) (void)strcat(strncpy(backup_lockname,control.backup_file,L_name-5), LOCKEX); if( ithread == 0 && control.dump_file[0] ) { (void)sprintf(dump_lockname, control.dump_file, 0); (void)strncat(dump_lockname, LOCKEX, L_name-1); } if( backup_lockname[0] ) { if( fopen(backup_lockname,"r") ) message(NULLI, NULLP, -FATAL, LOCKED, "backup", backup_lockname); if( (lock=fopen(backup_lockname,"w")) != 0 ) (void)fclose(lock); else message(NULLI, NULLP, WARNING, LOCKFL, backup_lockname); } if( dump_lockname[0] ) { if( fopen(dump_lockname,"r") ) { if( backup_lockname[0] ) remove(backup_lockname); message(NULLI, NULLP, -FATAL, LOCKED, "dump", dump_lockname); } if( (lock=fopen(dump_lockname,"w")) != 0 ) (void)fclose(lock); else message(NULLI, NULLP, WARNING, LOCKFL, dump_lockname); } /* * Check for the existance of a backup file and restart from it. */ if( control.backup_file[0] != '\0' && ( backup = fopen(control.backup_file,"rb")) != NULL ) /* Backup exists */ { re_re_header(backup, &backup_header, &backup_control); if(restart && (backup_header.timestamp < restart_header->timestamp)) backup = NULL; /* Backup older than restart-don't use*/ } if( backup ) /* We are restarting from backup file. File is already open and header and * * control struct have been read into backup_header and backup_control resp* * 1) Set number of steps to number yet to do. * * 2) Copy backup header and control into the correct structs. * * 3) Read rest of backup file as for ordinary restart, omitting reread of * * control and scaling since nothing can have changed. */ { control = backup_control; (void)strcpy(restart_header->init_date, backup_header.init_date); (void)strcpy(restart_header->title,backup_header.title); re_re_sysdef(backup,backup_header.vsn,system,species,site_info,potpar); allocate_dynamics(system, *species);/* Memory for dynamic variables */ init_averages(system->nspecies, backup_header.vsn, control.roll_interval, control.roll_interval,&av_convert); if(control.rdf_interval > 0) init_rdf(system); /* Prepare to calculate rdf */ read_restart(backup, backup_header.vsn, system, av_convert); /* Saved dynamic vars etc */ convert_averages(control.roll_interval, control.roll_interval,av_convert); (void)fclose(backup); (*backup_restart)++; message(NULLI, NULLP, INFO, BACKUP, control.backup_file); } else if( !restart ) /* Initiate a new run from scratch, ie not restart * * 1) Read the system specification. This is either in a file of its own * * or follows the control info. * * 2) Convert potential parameters, site masses and charges to prog. units.* * 3) Calculate molecular masses, moments of inertia and nmols etc. * * 4) Allocate memory for the MD dynamic variables. * * 5) Call the dynamic var initialisation routine. * * 6) Set up averages data structures. */ { if( control.sysdef[0] == '\0' || strcmp(control.sysdef,contr_name) == 0 ) sysdef = contr_file; /* Sys def'n is tacked onto control */ else /* Sys def'n is in separate file */ { /* Open system specification file */ sysdef = fopen(control.sysdef,"r"); if(sysdef == NULL) message(NULLI, NULLP, FATAL, ODFAIL,control.sysdef,strerror(errno)); } /* Read system specification file */ read_sysdef(sysdef, system, species, site_info, potpar); conv_potentials(&input_unit, &prog_unit, *potpar, system->n_potpar, system->ptype, *site_info, system->max_id); qpf = qalloc(system->nspecies); initialise_sysdef(system, *species, *site_info, qpf); allocate_dynamics(system, *species); /* Allocate dynamic arrays */ smdrand(control.seed); /* Seed random number generato*/ if( control.lattice_start ) /* Choose startup method */ lattice_start(sysdef, system, *species, qpf); /* Lattice - from file */ else skew_start(system, *species); /* Start from skew lattice */ thermalise(system, *species); /* Initialise velocities */ init_averages(system->nspecies, (char*)0, control.roll_interval, control.roll_interval ,&av_convert); if( control.rdf_interval > 0 ) init_rdf(system); /* Prepare to calculate rdf */ if(control.limit <= 0.0) /* Choose RDF limit */ control.limit = 0.5*MIN3(system->h[0][0],system->h[1][1], system->h[2][2]); init_cutoffs(&control.alpha, &control.cutoff, &control.k_cutoff, system->h, system->nsites); (void)strcpy(restart_header->init_date, atime()); (void)strcpy(restart_header->title,control.title); if(sysdef != contr_file) (void)fclose(sysdef); /* Finished with sys spec file*/ } else /* Continue from a restart file. The restart file contains a header, the * * saved 'control' struct, system specification, dynamic variables and * * averages. The old 'control' values act as defaults for this run. To do * * this they are read into 'control', and the control file is rewound and * * reread. To keep the units consistent, the old control is converted to * * the NEW input units before rereading, and then back to program units. * * Also the scale_end and begin_average parameters are incremented by the * * initial timestep only if they are explicitly specified. * * By the time we get here, this has all been done. * * * * The next thing to be read is the system spec. Normally this is just * * taken from the restart file, but a facility is provided to allow its * * replacement with a setup from a new system spec 'source' file. Its * * consistency with the old sys-spec is only checked in so far as the size * * and shape of the dynamic variable arrays are identical. Beware. * * Memory is allocated for the dynamic variables and averages which are * * read from the input file. Finally if the timestep has been altered the * * accelerations at previous timesteps are adjusted to the new step. */ { control.scale_end += control.istep; control.begin_average += control.istep; control.begin_rdf += control.istep; control.begin_dump += control.istep; control.nsteps += control.istep; if( control.maxdumps != old_max_dumps || /* Need to restart */ control.dump_interval != old_dump_interval ) /* dump seq if changed*/ { control.begin_dump = control.istep + 1; /* Set new beginning */ } if( !control.new_sysdef ) /* Usual case, get sysdef from restart*/ re_re_sysdef(restart, restart_header->vsn, system, species, site_info, potpar); else /* Get sysdef from new sys-spec file */ { if( control.sysdef[0]=='\0' || strcmp(control.sysdef,contr_name) == 0 ) sysdef = contr_file; /* Sys def'n is tacked onto control */ else /* Sys def'n is in separate file */ { /* Open system specification file */ sysdef = fopen(control.sysdef,"r"); if( sysdef == NULL ) message(NULLI,NULLP,FATAL,OSFAIL,control.sysdef,strerror(errno)); } /* Read in and set up new system spec (just as in case of new run) */ read_sysdef(sysdef, system, species, site_info, potpar); conv_potentials(&input_unit, &prog_unit, *potpar, system->n_potpar, system->ptype, *site_info, system->max_id); #ifdef DEBUG printf(" *D* Read and converted new system specification\n"); #endif qpf = qalloc(system->nspecies); initialise_sysdef(system, *species, *site_info, qpf); /* Consistent with saved one?*/ check_sysdef(restart, restart_header->vsn, system, *species); if(sysdef != contr_file) (void)fclose(sysdef); control.reset_averages = 1; /* Averages invalid if sysdef changed */ } allocate_dynamics(system, *species);/* Memory for dynamic variables */ init_averages(system->nspecies, restart_header->vsn, control.roll_interval, old_roll_interval, &av_convert); if(control.rdf_interval > 0) init_rdf(system); /* Prepare to calculate rdf */ read_restart(restart, restart_header->vsn, system, av_convert); /* Saved dynamic vars etc */ convert_averages(control.roll_interval, old_roll_interval, av_convert); control.reset_averages = 0; /* This flag never propagated.*/ if(control.step != old_step) interpolate_derivatives(system, old_step, control.step); for(i = 0; i < 9; i++) /* Zap cell velocities if constrained */ if( (control.strain_mask >> i) & 1 ) system->hddot[0][i] = system->hddoto[0][i] = system->hdot[0][i] = 0; (void)fclose(restart); message(NULLI, NULLP, INFO, RESUCC, control.restart_file); } (void)fclose(contr_file); if( out_name[0] != '\0' ) /* Open output file (or use stdout) */ { (void)fflush(stdout); /* Purge buffer before opening file */ if( freopen(out_name, "a", stdout) == NULL ) message(NULLI, NULLP, FATAL, OOFAIL, out_name, strerror(errno)); } if( ithread == 0 ) banner_page(system, *species, restart_header); if( qpf != NULL ) xfree(qpf); } $EOD $! $CREATE values.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * values. Calculate various thermodynamic quantities and their averages * * ant print periodic output. Contents: * * init_averages() Allocate and set up averages database * * av_ptr() Return pointer and size of database * * add_average() Update an average with a new datum * * value() Return current value of specified quantity * * roll_av() Return rolling averagee of specified quantity * * roll_sd() Return standard deviation of rolling average * * values() Calculate all values and update database * * print_frame() Print periodic output in formatted form * * output() Call print_frame for values, rolling averages & sd's * * averages() Calculate and print averages() * ****************************************************************************** * Revision Log * $Log: values.c,v $ * Revision 2.7 1994/06/08 13:17:00 keith * Made database size a size_mt (unsigned long) for 16 bit machines. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/18 13:33:05 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:28:15 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/07/19 13:28:25 keith * Added XDR capability for backup and dump files. * * Revision 2.0 93/03/15 14:49:24 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.15 93/03/09 15:59:19 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.14 92/09/22 14:47:36 keith * Tidied up calls to improve "lint" rating. * * Revision 1.13 92/06/26 17:03:38 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.12 92/03/24 12:41:31 keith * Fixed bug introduced in last revision which calculated * averages wrongly. * Added code to zero averages database if reset-averages * is set OR if the info in restart averages database is * out of date. (ie ig begin-averages is within current run). * * Revision 1.11 92/03/19 15:45:42 keith * Added support for dynamic allocation of rolling average arrays, * conversion of existing restart files is done on fly. * * Revision 1.10 91/08/19 16:48:51 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * * Revision 1.9 91/03/12 15:43:29 keith * Tidied up typedefs size_mt and include file * Added explicit function declarations. * * Revision 1.8 90/05/16 18:40:53 keith * Renamed own freer from cfree to tfree. * * Revision 1.7 90/05/16 14:20:40 keith * *** empty log message *** * * Revision 1.6 90/05/08 17:19:09 keith * Fixed bug which got indexing of av_info[] wrong in test for -ve variance. * * Revision 1.5 90/04/16 18:17:19 keith * Rearranged expression as workaround for CRAY CC4.1 bug. * * Revision 1.4 89/06/22 15:45:29 keith * Tidied up loops over species to use one pointer as counter. * * Revision 1.3 89/06/01 21:25:40 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.2 89/05/19 10:35:28 keith * Fixed bug which printed to stdout rather than control.out. * * Revision 1.1 89/04/20 16:00:58 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/values.c,v 2.7 1994/06/08 13:17:00 keith stab $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" #include "structs.h" #include "messages.h" /*========================== Library include files ===========================*/ #include #include "string.h" #include "stddef.h" #include /*========================== External function declarations ==================*/ void mat_vec_mul(); void q_conj_mul(); /* Quaternion multiply conjugated */ double det(); /* Determinant of 3x3 matrix */ double vdot(); /* Vector dot product */ double sum(); /* Vector sum */ void zero_real(); void zero_double(); void zero_dbls(); void energy_dyad(); double trans_ke(); double rot_ke(); double precision(); /* Machine precision constant */ char *atime(); void new_line(); void new_lins(); void new_page(); gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ int lines_left(); /* on current page of output */ #if defined(ANSI) || defined(__STDC__) void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ /*========================== Structs local to module =========================*/ typedef struct { double value, sum, sum_sq, mean, sd, roll[1]; } av_mt; typedef struct { av_n id; char *name, *unit; int field_width; char *format; int mult; av_mt **p; } av_info_t; /*========================== Global variables ================================*/ static av_info_t av_info[] = { {tke_n, "Trans KE", CONV_E_N, 11, "%11.5g",-1, NULL}, {rke_n, "Rot KE", CONV_E_N, 11, "%11.5g",-1, NULL}, {pe_n, "Pot Energy", CONV_E_N, 11, "%11.5g",NPE,NULL}, {e_n, "Tot Energy", CONV_E_N, 11, "%11.5g", 1, NULL}, {tt_n, "TTemp", CONV_T_N, 6, "%6.1f", -1, NULL}, {rt_n, "RTemp", CONV_T_N, 6, "%6.1f", -1, NULL}, {t_n, "Temp", CONV_T_N, 6, "%6.1f", 1, NULL}, {h0_n, "h(1,*)", LUNIT_N, 6, "%6.2f", 3, NULL}, {h1_n, "h(2,*)", LUNIT_N, 6, "%6.2f", 3, NULL}, {h2_n, "h(3,*)", LUNIT_N, 6, "%6.2f", 3, NULL}, {stress0_n,"Stress", CONV_P_N, 10, "%10.3g",3, NULL}, {stress1_n,"Stress", CONV_P_N, 10, "%10.3g",3, NULL}, {stress2_n,"Stress", CONV_P_N, 10, "%10.3g",3, NULL}, {press_n,"Pressure", CONV_P_N, 10, "%10.3g",1, NULL}, {vir_n, "Virial", CONV_E_N, 11, "%11.5g",1, NULL}, {msqf_n,"", CONV_F_N, 10, "%10.5g",-3, NULL}, {msqt_n,"", CONV_N_N, 10, "%10.5g",-3, NULL}, {dip_n, "Dip Mom", CONV_D_N, 8, "%8.2g", 3, NULL}}; static size_mt av_size; /* Size of averages database */ static size_mt av_mt_size; /* Size of entry inaverages database */ static av_head_mt *av_head; static av_mt *av; /* Dynamic array of averages structs */ static int navs = 0; /* Size of array av */ static int max_row = 0; /* Largest number of components */ static int max_col = (int)press_n; /* Number to print across page */ static size_mt av_tmp_size; static gptr *av_tmp; /*========================== Macros ==========================================*/ #define NAVT (int)end #define INC(av_mp) (av_mp = (av_mt*)((char*)av_mp + av_mt_size)) /*============================================================================*/ /****************************************************************************** * init_averages Allocate space for and initialise the averages database. * * The first word is the 'count' of numbers summed to date, (Pointed at by * * global av_cnt) which is followed by an array of av_t structs of dimension * * navs. * * Struct array av_info is set up with .av_p pointing to the appropriate * * entry in av. The multiplicity (number of components) is also set by the * * following rule - a positive entry is the true multiplicity and a negative * * one is multiplied by the number of species for the true multiplicity. * ******************************************************************************/ void init_averages(nspecies, vsn, roll_interval, old_roll_interval,av_convert) int nspecies; char *vsn; long roll_interval, old_roll_interval; int *av_convert; { av_mt *av_mp; int i, imult; int major, minor, cmajor=1, cminor=13; for(i = 0; i < (int)end; i++) /* cycle over enum types av_n */ { if(av_info[i].mult < 0) /* Set true multiplicity of each type */ av_info[i].mult = -nspecies * av_info[i].mult; navs += av_info[i].mult; /* Count total */ if(i < max_col && av_info[i].mult > max_row) max_row = av_info[i].mult; } /* Determine size of database, Allocate space and set pointers */ av_mt_size = sizeof(av_mt)+(roll_interval-1)*sizeof(double); av_size = sizeof(av_head_mt) + navs*av_mt_size; av_head = (av_head_mt*)balloc(1, av_size); av_head->nav = av_head->nroll = av_head->iroll = 0; av = (av_mt*)(av_head+1); zero_dbls((double*)av, navs*av_mt_size/sizeof(double)); av_mp = av; for(i = 0; i < (int)end; i++) /* Set up pointers to area of array */ { /* reserved for each type, size=mult. */ av_info[i].p = aalloc(av_info[i].mult, av_mt*); for(imult = 0; imult < av_info[i].mult; imult++) { av_info[i].p[imult] = av_mp; INC(av_mp); } } /* * Do we have to do any conversion on averages read from restart file? * We just allocate buffers and set flags here. */ *av_convert = 0; if( vsn ) { /* * First check whether restart was written by 1.13 or earlier. */ if( sscanf(vsn, "%d.%d", &major, &minor) < 2 ) message(NULLI, NULLP, FATAL, INRVSN, vsn); if( major < cmajor || (major==cmajor && minor <= cminor ) ) { av_tmp_size = (navs+1)*sizeof(old_av_u_mt); av_tmp = balloc(1,av_tmp_size); *av_convert = 1; } /* * Has size of rolling average store changed? */ else if (roll_interval != old_roll_interval ) { av_tmp_size = sizeof(av_head_mt) + navs*(sizeof(av_mt)+(old_roll_interval-1)*sizeof(double)); av_tmp = balloc(1, av_tmp_size); *av_convert = 2; } } } /****************************************************************************** * convert_averages. Update averages database if roll_interval changed or * * if restart file written using old "static" scheme. * * Also a convenient place to implement reset_averages. * ******************************************************************************/ void convert_averages(roll_interval, old_roll_interval, av_convert) long roll_interval, old_roll_interval; int av_convert; { int iav, old_nroll, old_iroll, rbl; size_mt prev_av_mt_size; old_av_u_mt *old_av_mp=(old_av_u_mt *)av_tmp; av_head_mt *prev_av_head = (av_head_mt *)av_tmp; av_mt *av_mp, *prev_av_mp; switch(av_convert) { case 0: /* No conversion needed */ break; case 1: /* Convert from static scheme */ old_nroll = old_av_mp[0].cnt.roll; old_iroll = control.istep % old_roll_interval; av_head->nroll = MIN(old_nroll,roll_interval); av_head->iroll = av_head->nroll % roll_interval; av_head->nav = old_av_mp[0].cnt.av; rbl = MIN(old_iroll, av_head->nroll); old_av_mp++; av_mp = av_info[0].p[0]; for(iav = 0; iav < navs; iav++) { av_mp->value = old_av_mp->av.value; av_mp->sum = old_av_mp->av.sum; av_mp->sum_sq = old_av_mp->av.sum_sq; av_mp->mean = old_av_mp->av.mean; av_mp->sd = old_av_mp->av.sd; memcp(av_mp->roll+av_head->nroll-rbl, old_av_mp->av.roll+old_iroll-rbl, rbl*sizeof(double)); memcp(av_mp->roll, old_av_mp->av.roll+old_nroll-av_head->nroll+rbl, (av_head->nroll-rbl)*sizeof(double)); INC(av_mp); old_av_mp++; } break; case 2: /* Change roll_interval */ prev_av_mt_size = sizeof(av_mt)+(old_roll_interval-1)*sizeof(double); old_nroll = prev_av_head->nroll; old_iroll = prev_av_head->iroll; av_head->nroll = MIN(old_nroll,roll_interval); av_head->iroll = av_head->nroll % roll_interval; av_head->nav = prev_av_head->nav; rbl = MIN(old_iroll, av_head->nroll); prev_av_mp = (av_mt *)(prev_av_head+1); av_mp = av_info[0].p[0]; for(iav = 0; iav < navs; iav++) { /* * Can do a struct copy -- will only pick up 1st roll entry */ *av_mp = *prev_av_mp; memcp(av_mp->roll+av_head->nroll-rbl, prev_av_mp->roll+old_iroll-rbl, rbl*sizeof(double)); memcp(av_mp->roll, prev_av_mp->roll+old_nroll-av_head->nroll+rbl, (av_head->nroll-rbl)*sizeof(double)); INC(av_mp); prev_av_mp = (av_mt*)((char*)prev_av_mp + prev_av_mt_size); } break; } /* * Reset averages and counters to zero if a) requested * or b) we have not yet reached begin_average. (The latter * avoids the situation of non-contiguous averages). * Yes I know we just set them up, but this way is clearest. */ if( control.reset_averages || control.istep+1 <= control.begin_average ) { av_mp = av_info[0].p[0]; for(iav = 0; iav < navs; iav++) { av_mp->sum = av_mp->sum_sq = av_mp->mean = av_mp->sd = 0.0; INC(av_mp); } av_head->nav = 0; } } /****************************************************************************** * av_ptr Return a pointer to averages database and its size (for restart) * ******************************************************************************/ gptr *av_ptr(size, av_convert) size_mt *size; int av_convert; { switch(av_convert) { case 0: *size = av_size; if(av_head != NULL) return((gptr*)av_head); break; case 1: case 2: *size = av_tmp_size; if(av_tmp != NULL) return(av_tmp); } message(NULLI, NULLP, FATAL, AVNOC, "av_ptr"); return(NULL); /* To satisfy lint */ } /****************************************************************************** * add_average update the averages database with new datum * ******************************************************************************/ static void add_average(datum, type, offset) double datum; /* Datum to store and accumulate sums */ av_n type; /* What kind (ie where to store) */ int offset; /* Sub-type or which component */ { av_mt *av_mp; if(offset < 0 || offset > av_info[(int)type].mult - 1) message(NULLI, NULLP, FATAL, AVBNDS, offset, av_info[(int)type].name); av_mp = av_info[(int)type].p[offset]; av_mp->value = datum; if(control.istep >= control.begin_average) { av_mp->sum += datum; av_mp->sum_sq += datum * datum; } av_mp->roll[av_head->iroll] = datum; } /****************************************************************************** * values Calculate the values of the thermodynamic quantities, maintain and* * if necessary print them, their averages and rolling averages. * ******************************************************************************/ void values(system, species, meansq_f_t, pe, dipole, stress_vir) system_mp system; /* record of system info */ spec_mt species[]; /* Records of info for each species */ vec_mt meansq_f_t[][2];/* mean square forces and torques */ double pe[]; /* potential energy real/reciprocal space */ vec_mt dipole; /* dipole moment of whole system */ mat_mt stress_vir; /* 'Potential' part of stress, or virial */ { spec_mp spec; int ispec, ipe; double e, tot_ke = 0.0, tot_pe = 0.0; int i, j, k; mat_mt ke_dyad, stress; double vol = det(system->h); for(ipe = 0; ipe < NPE; ipe++) { add_average(CONV_E * pe[ipe], pe_n, ipe); tot_pe += pe[ipe]; } for (spec = species; spec < &species[system->nspecies]; spec++) { ispec = spec-species; e = trans_ke(system->h, spec->vel, spec->mass, spec->nmols); add_average(CONV_E * e, tke_n, ispec); /* c of m kinetic energy */ tot_ke += e; add_average(e/(1.5*spec->nmols*kB), tt_n, ispec); /* c of mass temp. */ if(spec->rdof > 0) /* Only if polyatomic species */ { e = rot_ke(spec->quat, spec->qdot, spec->inertia, spec->nmols); add_average(CONV_E * e, rke_n, ispec); /* Rotational kinetic energy */ tot_ke += e; add_average(e/(0.5*kB*spec->rdof*spec->nmols), rt_n, ispec); } /* and temperature */ } /* Overall temperature */ add_average(CONV_E*(tot_ke+tot_pe), e_n, 0); /* Total energy */ add_average(tot_ke/(0.5*kB*system->d_of_f), t_n, 0); for(i = 0; i < 3; i++) /* Non-zero (upper triangle) */ { add_average(system->h[i][0], h0_n, i); add_average(system->h[i][1], h1_n, i); add_average(system->h[i][2], h2_n, i); } zero_real(ke_dyad[0],9); for (spec = species; spec < &species[system->nspecies]; spec++) energy_dyad(ke_dyad, system->h, spec->vel, spec->mass, spec->nmols); k = 0; for(i = 0; i < 3; i++) { for(j = i; j < 3; j++) { stress[j][i] = stress[i][j] = CONV_P * 0.5/vol * (ke_dyad[i][j] + ke_dyad[j][i] + stress_vir[i][j] + stress_vir[j][i]); } add_average(stress[i][0], stress0_n, i); add_average(stress[i][1], stress1_n, i); add_average(stress[i][2], stress2_n, i); } add_average((stress[0][0] + stress[1][1] + stress[2][2])/3.0, press_n, 0); add_average((stress_vir[0][0] + stress_vir[1][1] + stress_vir[2][2]) *CONV_V/3.0, vir_n, 0); k = 0; for(ispec = 0; ispec < system->nspecies; ispec++) for(i = 0; i < 3; i++) { add_average(CONV_F*CONV_F*meansq_f_t[ispec][0][i], msqf_n, k); add_average(CONV_N*CONV_N*meansq_f_t[ispec][1][i], msqt_n, k++); } for(i = 0; i < 3; i++) add_average(CONV_D * dipole[i], dip_n, i); /* * Update counters. */ if(control.istep >= control.begin_average) (av_head->nav)++; if(av_head->nroll < control.roll_interval) (av_head->nroll)++; av_head->iroll = (av_head->iroll+1) % control.roll_interval; } /****************************************************************************** * value, roll_av, roll_sd. Functions returning the value, rolling * * average, or s.d for rolling average indicated by pointer p. * ******************************************************************************/ double value(type, comp) av_n type; int comp; { return(av_info[(int)type].p[comp]->value); } double roll_av(type, comp) av_n type; int comp; { int i; double mean = 0.0; for(i = 0; i < av_head->nroll; i++) mean += av_info[(int)type].p[comp]->roll[i]; return(mean/ av_head->nroll); } static double roll_sd(type, comp) av_n type; int comp; { int i; double *roll, ssq = 0.0, mean = roll_av(type, comp), var, bottom = -32.0*sqrt((double)control.roll_interval)*precision(); roll = av_info[(int)type].p[comp]->roll; for(i = 0; i < av_head->nroll; i++) ssq += roll[i] * roll[i]; var = ssq/ av_head->nroll - mean*mean; if( var * av_head->nroll < ssq * bottom) message(NULLI, NULLP, WARNING, NEGVAR, "roll_sd", var, av_info[(int)type].name); return(var > 0.0 ? sqrt(var): 0.0); } /****************************************************************************** * Print frame. Print the values from the structs pointed at by * * av_info[i].p in a reasonable format. Function parameter allows various * * info from struct to be printed in the same format. av_info contains * * the field width and format to use for each data type. * ******************************************************************************/ static void print_frame(header_sym, header_text, f) int header_sym; char *header_text; double (*f)(); { int row, col, icol; static int out_width = 1; static boolean initial = true; if(initial) { for(icol = 0; icol < max_col; icol++) /* Count total width */ out_width += av_info[icol].field_width + 1; } if( initial || lines_left() < max_row + 1 ) /* If near end of page*/ { new_page(); for(icol = 0; icol < max_col; icol++) /* Print column titles*/ (void)printf(" %*s", av_info[icol].field_width, av_info[icol].name); new_line(); initial = false; } col = 0; /* Print row of 'header_sym' */ while(col++ < 8) /* with 'header_text' in the */ (void)putchar(header_sym); /* middle. */ col += printf(" %s ", header_text); while(col++ < out_width) (void)putchar(header_sym); new_line(); for(row = 0; row < max_row; row++) /* Print 'max_col' fields */ { /* across page, up to max_row */ for(icol = 0; icol < max_col; icol++) /* down. Print value returned*/ { /* by (*f) in field or fill */ (void)putchar(' '); /* with spaces */ if(row < av_info[icol].mult) (void)printf( av_info[icol].format, (*f)((av_n)icol, row)); else for(col = 0; col < av_info[icol].field_width; col++) (void)putchar(' '); } new_line(); } } /****************************************************************************** * output Main output routine to be called periodically. * * Calls print_frame which does most of the real work. * ******************************************************************************/ void output() { char s[64]; (void)sprintf(s, "Timestep %ld Current values", control.istep); print_frame('=', s, value); (void)sprintf(s,"Rolling averages over last %d timesteps", av_head->nroll); print_frame('-', s, roll_av); print_frame('-', "Standard deviations", roll_sd); (void)fflush(stdout); } /****************************************************************************** * averages calculate and print averages, reset counter. * ******************************************************************************/ void averages() { int i, iav, col; double variance, bottom = -32.0*sqrt((double)av_head->nav)*precision(); av_mt *av_mp; if(av_head == NULL) message(NULLI, NULLP, FATAL, AVNOC, "averages"); if(av_head->nav == 0) { note("no sums accumulated for averages"); return; } if(lines_left() < NAVT + 4 ) /* If near end of page*/ new_page(); else new_lins(2); (void)printf( " Averages over last %d timesteps",av_head->nav); new_line(); av_mp = av; for(iav = 0; iav < NAVT; iav++) { for(i = 0; i < av_info[iav].mult; i++) { av_mp = av_info[iav].p[i]; av_mp->mean = av_mp->sum / av_head->nav; variance = av_mp->sum_sq/ av_head->nav - av_mp->mean * av_mp->mean; if(variance * av_head->nav < av_mp->sum_sq * bottom) message(NULLI, NULLP, WARNING, NEGVAR, "averages", variance, av_info[(int)iav].name); av_mp->sd = variance > 0.0 ? sqrt(variance) : 0.0; av_mp->sum = 0.0; av_mp->sum_sq = 0.0; } } av_head->nav = 0; for(iav = 0; iav < NAVT; iav++) { col = 0; col += printf( " %-16s= ",av_info[iav].name); for(i = 0; i < av_info[iav].mult; i++) { if(col + 2 * av_info[iav].field_width + 6 > control.page_width) { new_line(); col = printf(" "); } col += printf( av_info[iav].format, av_info[iav].p[i]->mean); col += printf(" +/- "); col += printf(av_info[iav].format, av_info[iav].p[i]->sd); if(i < av_info[iav].mult - 1) col += printf(","); } if(col + 10 > control.page_width) new_line(); col += printf(" %s", av_info[iav].unit); new_line(); } (void)fflush(stdout); } $EOD $! $CREATE xdr.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * xdr Moldy-specific xdr routines for storing binary data in machine- * * independent format. For compatibility with existing binary * * formats, strings are stored as fixed-length opaque data. * ****************************************************************************** * Revision Log * $Log: xdr.c,v $ * Revision 2.11 1996/10/23 13:06:51 keith * Fixed restart structure correctly - broken in prev version. * Thermostat parameters may not be properly read. * * Revision 2.10 1996/03/06 18:20:45 keith * Added cast in xdr_vector() call to supress spurious warning message. * * Revision 2.9 1994/10/17 10:54:06 keith * Got rid of dummy xdr_array which really screwed things up! * * Revision 2.8 1994/07/07 17:03:39 keith * Fixed up missing xdr_vector to be compiled in only if NEED_XDR_VECTOR defined. * * Revision 2.7 1994/06/08 13:17:38 keith * Changed all timestep-related parameters to type "long". This means * that 16-bit DOS compilers can do more than 32767 timesteps. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 94/01/18 13:33:07 keith * Null update for XDR portability release * * Revision 2.4 94/01/18 13:15:18 keith * Put casts in function calls to satisfy picky-picky-picky SGI compiler. * Added return values to dummy xdr functions to get rid of VMS warnings. * * Revision 2.4 93/12/20 16:42:04 keith * Put casts in function calls to satisfy picky-picky-picky SGI compiler. * * Revision 2.3 93/10/28 10:28:17 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.2 93/09/06 14:42:46 keith * Fixed portability problems/bugs in XDR code. * * Revision 2.1 93/07/19 13:29:08 keith * Support for XDR backup/dump routines. * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/xdr.c,v 2.11 1996/10/23 13:06:51 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "structs.h" /*========================== Library include files ===========================*/ #include "stddef.h" #include "xdr.h" /*============================================================================*/ #ifdef USE_XDR bool_t xdr_real(xdrs, rp) XDR *xdrs; real *rp; { if( sizeof(real) == sizeof(double) ) return xdr_double(xdrs, (double*)rp); else if( sizeof(real) == sizeof(float) ) return xdr_float(xdrs, (float*)rp); else return FALSE; } bool_t xdr_contr(xdrs, cp) XDR *xdrs; contr_mt *cp; { return xdr_opaque(xdrs, cp->title, L_name) && xdr_long(xdrs, &cp->istep) && xdr_long(xdrs, &cp->nsteps) && xdr_double(xdrs, &cp->step) && xdr_vector(xdrs, (gptr*)&cp->print_sysdef, 7, sizeof(boolean), (xdrproc_t)xdr_bool) && xdr_opaque(xdrs, cp->sysdef, 6*L_name) && xdr_vector(xdrs, (gptr*)cp->spare, 23, sizeof(int), (xdrproc_t)xdr_int) && xdr_double(xdrs, &cp->ttmass) && xdr_double(xdrs, &cp->rtmass) && xdr_int(xdrs, &cp->pad) && xdr_int(xdrs, &cp->const_temp) && xdr_bool(xdrs, &cp->xdr_write) && xdr_bool(xdrs, &cp->strict_cutoff) && xdr_int(xdrs, &cp->strain_mask) && xdr_int(xdrs, &cp->nbins) && xdr_u_long(xdrs, &cp->seed) && xdr_vector(xdrs, (gptr*)&cp->page_width, 2, sizeof(int), (xdrproc_t)xdr_int) && xdr_vector(xdrs, (gptr*)&cp->scale_interval, 7, sizeof(long), (xdrproc_t)xdr_long) && xdr_vector(xdrs, (gptr*)&cp->dump_level, 2, sizeof(int), (xdrproc_t)xdr_int) && xdr_vector(xdrs, (gptr*)&cp->backup_interval, 6, sizeof(long), (xdrproc_t)xdr_long) && xdr_vector(xdrs, (gptr*)&cp->temp, 10, sizeof(double), (xdrproc_t)xdr_double); } bool_t xdr_system(xdrs, sp) XDR *xdrs; system_mt *sp; { return xdr_vector(xdrs, (gptr*)&sp->nsites, 8, sizeof(int), (xdrproc_t)xdr_int) && /* * This is an awful hack. There are 28 real[3]* pointers * next. Their stored values are NEVER re-used so we just * output a placeholder. For compatibility of XDR/non-XDR * files on 4 byte big-endian ieee architectures we emit * 4 bytes each. DON'T use sizeof as that would make XDR * file M/C dependent. */ xdr_opaque(xdrs, (gptr*)&sp->c_of_m, 28*XDR_4PTR_SIZE); } /* * This version for reading restart files written by 2.10 or before. */ bool_t xdr_system_2(xdrs, sp) XDR *xdrs; system_mt *sp; { return xdr_vector(xdrs, (gptr*)&sp->nsites, 8, sizeof(int), (xdrproc_t)xdr_int) && xdr_opaque(xdrs, (gptr*)&sp->c_of_m, 18*XDR_4PTR_SIZE); } bool_t xdr_species(xdrs, sp) XDR *xdrs; spec_mt *sp; { return xdr_vector(xdrs, (gptr*)sp->inertia, 6, sizeof(real), (xdrproc_t)xdr_real) && xdr_vector(xdrs, (gptr*)&sp->nsites, 4, sizeof(int), (xdrproc_t)xdr_int) && xdr_opaque(xdrs, sp->name, 32) && /* * This is an awful hack. There are 14 real[3]* pointers * next. Their stored values are NEVER re-used so we just * output a placeholder. For compatibility of XDR/non-XDR * files on 4 byte big-endian ieee architectures we emit * 4 bytes each. DON'T use sizeof as that would make XDR * file M/C dependent. */ xdr_opaque(xdrs, (gptr*)&sp->site_id, 14*XDR_4PTR_SIZE) && xdr_int(xdrs,(int*)&sp->pad[0]) && xdr_int(xdrs,(int*)&sp->pad[1]); } bool_t xdr_site(xdrs, sp) XDR *xdrs; site_mt *sp; { return xdr_double(xdrs, &sp->mass) && xdr_double(xdrs, &sp->charge) && xdr_opaque(xdrs, sp->name, 8) && xdr_int(xdrs, &sp->flag) && xdr_int(xdrs, &sp->pad); } static unsigned int xdr_npotpar; void xdr_set_npotpar(npotpar) int npotpar; { xdr_npotpar = npotpar; } bool_t xdr_pot(xdrs, sp) XDR *xdrs; pot_mt *sp; { return xdr_int(xdrs, &sp->flag) && xdr_int(xdrs, &sp->pad) && xdr_vector(xdrs, (gptr*)sp->p, xdr_npotpar, sizeof(real), (xdrproc_t)xdr_real); } bool_t xdr_restrt(xdrs, sp) XDR *xdrs; restrt_mt *sp; { return xdr_u_long(xdrs, &sp->timestamp) && xdr_u_long(xdrs, &sp->prev_timestamp) && xdr_opaque(xdrs, sp->init_date, DLEN+L_name+16) && xdr_int(xdrs, &sp->seq); } bool_t xdr_dump(xdrs, sp) XDR *xdrs; dump_mt *sp; { return xdr_opaque(xdrs, sp->title, L_name+16) && xdr_vector(xdrs, (gptr*)&sp->istep, 2, sizeof(long), (xdrproc_t)xdr_long) && xdr_vector(xdrs, (gptr*)&sp->dump_level, 4, sizeof(int), (xdrproc_t)xdr_int) && xdr_vector(xdrs, (gptr*)&sp->timestamp, 3, sizeof(unsigned long), (xdrproc_t)xdr_u_long); } static bool_t xdr_av_head_t(xdrs,ap) XDR *xdrs; av_head_mt *ap; { return xdr_vector(xdrs, (gptr*)&ap->nav, 4, sizeof(int), (xdrproc_t)xdr_int) && xdr_double(xdrs, &ap->align); } static bool_t xdr_old_av_u_t(xdrs,ap) XDR *xdrs; old_av_u_mt *ap; { return xdr_vector(xdrs, (gptr*)&ap->cnt.av, 2, sizeof(int), (xdrproc_t)xdr_int) && xdr_opaque(xdrs, (gptr*)(&ap->cnt.av+2*sizeof(int)), (7+MAX_ROLL_INTERVAL)*XDR_DOUBLE_SIZE-2*XDR_INT_SIZE); } static size_mt xdr_av_size; static int av_convert; void xdr_set_av_size_conv(size, av_conv) size_mt size; int av_conv; { xdr_av_size = size; av_convert = av_conv; } bool_t xdr_averages(xdrs, ap) XDR *xdrs; gptr *ap; { /* * The global flag av_convert requires explanation. It is * set by init_averages() which is always called before * this function. av_convert=1 if we are reading data in * the old (fixed length = MAX_ROLL_INTERVAL) format and * 0 or 2 otherwise. */ unsigned navst; /* Total # of average data items */ old_av_u_mt *apo = (old_av_u_mt *)ap; av_head_mt *aph = (av_head_mt *)ap; if( xdrs->x_op == XDR_DECODE && av_convert == 1 ) { navst = (xdr_av_size-sizeof(old_av_u_mt)) / sizeof(double); return xdr_old_av_u_t(xdrs,apo) && xdr_vector(xdrs, (gptr*)(apo+1), navst, sizeof(double), (xdrproc_t)xdr_double); } else { navst = (xdr_av_size-sizeof(av_head_mt)) / sizeof(double); return xdr_av_head_t(xdrs,aph) && xdr_vector(xdrs, (gptr*)(aph+1), navst, sizeof(double), (xdrproc_t)xdr_double); } } #ifdef NEED_XDR_VECTOR #define LASTUNSIGNED ((u_int)0-1) /* * xdr_vector(): * * XDR a fixed length array. Unlike variable-length arrays, * the storage of fixed length arrays is static and unfreeable. * > basep: base of the array * > size: size of the array * > elemsize: size of each element * > xdr_elem: routine to XDR each element */ bool_t xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) register XDR *xdrs; register char *basep; register u_int nelem; register u_int elemsize; register xdrproc_t xdr_elem; { register u_int i; register char *elptr; elptr = basep; for (i = 0; i < nelem; i++) { if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) { return(FALSE); } elptr += elemsize; } return(TRUE); } #endif #else void xdr_set_npotpar (npotpar) int npotpar; {} void xdr_set_av_size_conv (size, av_conv) size_mt size; int av_conv; {} bool_t xdr_site () {return 0;} bool_t xdr_restrt () {return 0;} bool_t xdr_averages () {return 0;} bool_t xdr_real () {return 0;} bool_t xdr_contr () {return 0;} bool_t xdr_system () {return 0;} bool_t xdr_system_2 () {return 0;} bool_t xdr_species () {return 0;} bool_t xdr_pot () {return 0;} bool_t xdr_int () {return 0;} bool_t xdr_bool () {return 0;} #endif $EOD $! $CREATE parallel.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Parallel - support and interface routines to parallel MP libraries. * ****************************************************************************** * $Log: parallel.c,v $ * Revision 2.19 1996/10/15 13:50:45 keith * Corrections to Cray SHMEM library interface. * * Revision 2.18 1996/09/03 15:04:51 keith * Added optional code for MPI global sums to guarantee identical * results on all processors. Compile with -DUNSYMM to activate. * * Revision 2.17 1996/03/19 12:33:50 keith * Optimised T3D par_collect_all. Now does not call barrier() * within loop, but uses pt-to-pt synchronization. * (b) Works "in-place" in memory rather than in static buffers. * This may well not be robust because of sbreak() call which * may break malloc(). * * Revision 2.14 1996/01/17 17:08:42 keith * Added "par_isum()" for rdf calculation. * Added security "exit()" call to par_abort(). * Corrected bug where par_dsum called vradd. * Added "init_rdf" call for all threads. * * Revision 2.13 1995/12/22 11:42:04 keith * Modified buffer handling for BSP interface. It used to complain and * stop if buffer was too small. Now it divides data into chunks smaller * than the buffer and transfers them one at a time. * * Revision 2.12 1995/12/06 10:44:50 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * * Revision 2.11 1994/11/24 14:48:17 keith * Fixed problem with arg lists for TCGMSG * * Revision 2.10 1994/10/17 10:49:41 keith * Changed arg list of bspstart to match changed library version. * * Revision 2.9 1994/07/11 11:15:30 keith * Tidied up startup routine with par_broadcast() function. * Documented parallel routine interface calls for porting. * * Revision 2.8 1994/07/07 17:00:26 keith * Interface to BSP, TCGMSG and MPI message-passing libraries. * * Revision 1.1 1994/07/07 16:59:44 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/parallel.c,v 2.19 1996/10/15 13:50:45 keith Exp $"; #endif /*========================== program include files ===========================*/ #include "defs.h" #include "structs.h" #include "messages.h" /*========================== system include files ===========================*/ #include #include "string.h" #ifdef DEBUG #include #endif #ifdef TCGMSG #include #endif #ifdef MPI #include #endif #ifdef SHMEM #include #include #include #endif /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ gptr *av_ptr(); gptr *rdf_ptr(); void init_averages(); void allocate_dynamics(); extern int ithread, nthreads; /*====================== Utilities for interface functions ===================*/ #ifdef TCGMSG static long lval; #define ADDR(expr) (lval=(expr),&lval) #endif #ifdef BSP /* * BSP currently doesn't handle auto & heap vars. This interface * copies to static storage. A 1MB buffer is large enough to * handle up to 44000 atomic sites in one go, and data for larger * systems is parcelled up appropriately and sent in chunks. */ #define NBUFMXW 131072 #define NBUFMAX (NBUFMXW*sizeof(double)) static double tmpbuf[NBUFMXW]; #endif #ifdef SHMEM /* * SHMEM doesn't handle auto & heap vars either. Handle as for BSP. * Make sure buffer is a good power-of 2 words and cache aligned. */ #pragma _CRI cache_align tmpbuf, pWrk, pSync, pSyncb #define NBUFMXW 131072 #define NBUFMAX (NBUFMXW*sizeof(double)) static double tmpbuf[NBUFMXW]; /* * SHMEM synchronization and work arrays. pWrk must be bigger than * _SHMEM_REDUCE_MIN_WRKDATA_SIZE. Since we have no compile-time MAX * function we declare pSync inelegantly as the sum of the sizes. */ static double pWrk[2][NBUFMXW/2+1]; static long pSync[2][_SHMEM_REDUCE_SYNC_SIZE]; static long pSyncb[_SHMEM_BCAST_SYNC_SIZE]; static int psi = 0; #endif #ifdef MPI #define M_REAL (sizeof(real)==sizeof(double)?MPI_DOUBLE:MPI_FLOAT) #endif /*====================== Parallel lib interface functions ====================* * The following set of functions define the interface between moldy and * * a message-passing parallel library. To port to a new library it suffices * * to implement these in terms of the library primitives. Thus all of the * * implementation-dependent parallel code is confined to this file. * * * * The functions required are: * * par_sigintreset() : Moldy sets a handler for SIGINT. This fn is called* * from the signal handler to restore the default. * * par_begin(int *argc, char ***argv, int *ithread, int *nthreads) * * : Initialize the library and return the number of * * processes and the ID of this process. * * par_finish() : Terminate the parallel run normally. * * par_abort(int code) : Terminate the run abnormally. Return code if poss.* * par_broadcast(void *buf, int n, size_mt size, int ifrom) * * : Broadcast the specified buffer from ifrom to all. * * par_{r,d}sum(void *buf, int n) : Perform a global parallel sum reduction * * on the buffer containing n {reals,doubles}. * * par_imax(int *idat) : Perform a global "maximum" reduction on the single * * int argument. * * * * Note that there is no provision for heterogeneous execution by way of * * type identification. Though some MP libraries (eg MPI) do provide the * * hooks it is too hard to implement for the control and other structs. * * It's also hard to see why this might ever be useful for a MD run. * *============================================================================*/ /****************************************************************************** * par_sigintreset(). Reset signal handler to parallel lib default upon trap * * of SIGINT. * ******************************************************************************/ #ifdef TCGMSG extern void SigintHandler(); void par_sigintreset() { signal(SIGINT, SigintHandler); } #endif #ifdef BSP void par_sigintreset() { signal(SIGINT, SIG_DFL); } #endif #ifdef SHMEM void par_sigintreset() { signal(SIGINT, SIG_DFL); } #endif #ifdef MPI void par_sigintreset() { signal(SIGINT, SIG_DFL); } #endif /****************************************************************************** * par_imax(). Calculate global maximum over all processors. * ******************************************************************************/ #ifdef TCGMSG void par_imax(idat) int *idat; { IGOP_(ADDR(10+MSGINT), idat, ADDR(1), "max"); } #endif #ifdef BSP static void imax(i1, i2, i3, size) int *i1, *i2, *i3; int size; { *i1 = MAX(*i2,*i3); } void par_imax(idat) int *idat; { bspreduce(imax, idat, idat, sizeof(int)); } #endif #ifdef SHMEM void par_imax(idat) int *idat; { shmem_int_max_to_all(idat, idat, 1, 0, 0, nthreads, (int*)pWrk[psi], pSync[psi]); psi = ! psi; #ifdef SHMEM_BARRIER barrier(); #endif } #endif #ifdef MPI void par_imax(idat) int *idat; { int result; MPI_Allreduce(idat, &result, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); *idat = result; } #endif /****************************************************************************** * par_isum(). Calculate sum of int array over all processors. * ******************************************************************************/ #ifdef TCGMSG void par_isum(buf, n) int *buf; int n; { IGOP_(ADDR(MSGINT), buf, &n, "+"); } #endif #ifdef BSP static void viadd(res, x, y, nb) int res[], x[], y[]; int nb; { int i, n=nb/sizeof(int); for(i = 0; i < n; i++) res[i] = x[i] + y[i]; } void par_isum(buf, n) int *buf; int n; { int m; /* * BSP only allows operations on statically allocated buffers. *sigh* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(int)); memcp(tmpbuf, buf, m*sizeof(int)); bspreduce(viadd, tmpbuf, tmpbuf, m*sizeof(int)); memcp(buf, tmpbuf, m*sizeof(int)); buf += m; n -= m; } } #endif #ifdef SHMEM void par_isum(buf, n) int *buf; int n; { int m; /* * BSP only allows operations on statically allocated buffers. *sigh* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(int)); memcp(tmpbuf, buf, m*sizeof(int)); shmem_int_sum_to_all((int*)tmpbuf, (int*)tmpbuf, m, 0, 0, nthreads, (int*)pWrk[psi], pSync[psi]); memcp(buf, tmpbuf, m*sizeof(int)); psi = ! psi; buf += m; n -= m; #ifdef SHMEM_BARRIER barrier(); #endif } } #endif #ifdef MPI /* * MPI demands seperate send and receive buffers. Malloc one and keep * it around. Extend if necessary. */ void par_isum(buf, n) int *buf; int n; { static int *tmpbuf = 0; static int tmpsize = 0; if( n <= 0 ) return; if(n > tmpsize) { if( tmpbuf ) free(tmpbuf); tmpbuf = aalloc(n, int); tmpsize = n; } MPI_Allreduce(buf, tmpbuf, n, MPI_INT, MPI_SUM, MPI_COMM_WORLD); memcp(buf, tmpbuf, n*sizeof(int)); } #endif /****************************************************************************** * par_rsum()/dsum. Calculate sum of "reals"/doubles over all processors. * ******************************************************************************/ #ifdef TCGMSG void par_rsum(buf, n) real *buf; int n; { DGOP_(ADDR(MSGDBL), buf, &n, "+"); } void par_dsum(buf, n) real *buf; int n; { DGOP_(ADDR(MSGDBL), buf, &n, "+"); } #endif #ifdef BSP static void vradd(res, x, y, nb) real res[], x[], y[]; int nb; { int i, n=nb/sizeof(real); for(i = 0; i < n; i++) res[i] = x[i] + y[i]; } static void vdadd(res, x, y, nb) double res[], x[], y[]; int nb; { int i, n=nb/sizeof(double); for(i = 0; i < n; i++) res[i] = x[i] + y[i]; } void par_rsum(buf, n) real *buf; int n; { int m; /* * BSP only allows operations on statically allocated buffers. *sigh* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(real)); memcp(tmpbuf, buf, m*sizeof(real)); bspreduce(vradd, tmpbuf, tmpbuf, m*sizeof(real)); memcp(buf, tmpbuf, m*sizeof(real)); buf += m; n -= m; } } void par_dsum(buf, n) double *buf; int n; { int m; /* * BSP only allows operations on statically allocated buffers. *sigh* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(double)); memcp(tmpbuf, buf, m*sizeof(double)); bspreduce(vdadd, tmpbuf, tmpbuf, m*sizeof(double)); memcp(buf, tmpbuf, m*sizeof(double)); buf += m; n -= m; } } #endif #ifdef SHMEM void par_rsum(buf, n) real *buf; int n; { int m; if( sizeof(real) == sizeof(float)) { /* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(real)); memcp(tmpbuf, buf, m*sizeof(real)); shmem_float_sum_to_all((float*)tmpbuf, (float*)tmpbuf, m,0,0, nthreads, (float*)pWrk[psi], pSync[psi]); memcp(buf, tmpbuf, m*sizeof(real)); psi = ! psi; buf += m; n -= m; #ifdef SHMEM_BARRIER barrier(); #endif } } else if ( sizeof(real) == sizeof(double)) { while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(real)); memcp(tmpbuf, buf, m*sizeof(real)); shmem_double_sum_to_all((double*)tmpbuf, (double*)tmpbuf, m,0,0, nthreads, (double*)pWrk[psi], pSync[psi]); memcp(buf, tmpbuf, m*sizeof(real)); psi = ! psi; buf += m; n -= m; #ifdef SHMEM_BARRIER barrier(); #endif } } } void par_dsum(buf, n) double *buf; int n; { int m; /* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( n > 0 ) { m = MIN(n, NBUFMAX/sizeof(double)); memcp(tmpbuf, buf, m*sizeof(double)); shmem_double_sum_to_all((double*)tmpbuf, (double*)tmpbuf, m, 0, 0, nthreads, (double*)pWrk[psi], pSync[psi]); memcp(buf, tmpbuf, m*sizeof(double)); psi = ! psi; buf += m; n -= m; #ifdef SHMEM_BARRIER barrier(); #endif } } #endif #ifdef MPI /* * MPI demands seperate send and receive buffers. Malloc one and keep * it around. Extend if necessary. * * The MPI standard recommends but does not guarantee that the results * of an Allreduce operation are identical on all threads. For * efficiency we assume that it is here, but provide conditional code * in case it isn't. The test on accel.c will trap if results differ, * in which case recompile with -DUNSYMM. */ void par_rsum(buf, n) real *buf; int n; { static real *tmpbuf = 0; static int tmpsize = 0; if(n > tmpsize) { if( tmpbuf ) free(tmpbuf); tmpbuf = dalloc(n); tmpsize = n; } #ifdef UNSYMM MPI_Reduce(buf, tmpbuf, n, M_REAL, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Bcast(tmpbuf, n, M_REAL, 0, MPI_COMM_WORLD); #else MPI_Allreduce(buf, tmpbuf, n, M_REAL, MPI_SUM, MPI_COMM_WORLD); #endif memcp(buf, tmpbuf, n*sizeof(real)); } void par_dsum(buf, n) double *buf; int n; { static double *tmpbuf = 0; static int tmpsize = 0; if(n > tmpsize) { if( tmpbuf ) free(tmpbuf); tmpbuf = aalloc(n, double); tmpsize = n; } #ifdef UNSYMM MPI_Reduce(buf, tmpbuf, n, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Bcast(tmpbuf, n, MPI_DOUBLE, 0, MPI_COMM_WORLD); #else MPI_Allreduce(buf, tmpbuf, n, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #endif memcp(buf, tmpbuf, n*sizeof(double)); } #endif /****************************************************************************** * par_broadcast(). Broadcast data to all processors. * ******************************************************************************/ #ifdef TCGMSG void par_broadcast(buf, n, size, ifrom) gptr *buf; int n; size_mt size; int ifrom; { long type = 0; long lenbuf = n*size; long ifrm = ifrom; BRDCST_(&type, buf, &lenbuf, &ifrm); } #endif #ifdef BSP void par_broadcast(buf, n, size, ifrom) gptr *buf; int n; size_mt size; int ifrom; { int m; long nbyt = n*size; /* Must have a signed type for loop test */ /* * BSP only allows operations on statically allocated buffers. *sigh* * Use loop to perform general operation copying in and out of a * fixed-size, static buffer. */ while( nbyt > 0 ) { m = MIN(nbyt, NBUFMAX); memcp(tmpbuf, buf, m); bspbroadcast(ifrom, tmpbuf, tmpbuf, m); memcp(buf, tmpbuf, m); buf = (char*)buf + m; nbyt -= m; } } #endif #ifdef SHMEM void par_broadcast(buf, n, size, ifrom) gptr *buf; int n; size_mt size; int ifrom; { int m; long nbyt = n*size; /* Must have a signed type for loop test */ /* * Usual comments about fixed-size buffers apply. The shmem * broadcast routine works in 8 byte word units, but that's OK * since we copy the exact length in and out of the real arrays. */ while( nbyt > 0 ) { m = MIN(nbyt, NBUFMAX); if( ithread == ifrom ) memcp(tmpbuf, buf, m); shmem_broadcast((long*)tmpbuf, (long*)tmpbuf, (m+sizeof(long)-1)/sizeof(long), ifrom, 0, 0, nthreads, pSyncb); if( ithread != ifrom ) memcp(buf, tmpbuf, m); buf = (char*)buf + m; nbyt -= m; barrier(); } } #endif #ifdef MPI void par_broadcast(buf, n, size, ifrom) gptr *buf; int n; size_mt size; int ifrom; { MPI_Bcast(buf, n*size, MPI_BYTE, ifrom, MPI_COMM_WORLD); } #endif /****************************************************************************** * par_collect_all(). Global gather to all. * ******************************************************************************/ #ifdef BSP void par_collect_all(send, recv, n, stride, nblk) real *send, *recv; int n, nblk, stride; { int i, right, left, iblk, ibeg; real *recvbuf = (real*)tmpbuf; int nbuf = NBUFMAX/sizeof(real); if(nblk*stride > nbuf) message(NULLI, NULLP, FATAL, "Par_Collect_All: Buffer too small %d,%d\n", nblk*stride,nbuf); for(iblk = 0; iblk < nblk; iblk++) memcp(recvbuf+ithread*n+iblk*stride, send+iblk*stride, n*sizeof(real)); for (i=1; i= 0 ) for(iblk = 0; iblk < nblk; iblk++) bspstore(right, recvbuf+ibeg*n+iblk*stride, recvbuf+ibeg*n+iblk*stride, i*n*sizeof(real)); else for(iblk = 0; iblk < nblk; iblk++) { bspstore(right, recvbuf+(ibeg+nthreads)*n+iblk*stride, recvbuf+(ibeg+nthreads)*n+iblk*stride, -ibeg*n*sizeof(real)); bspstore(right, recvbuf+iblk*stride, recvbuf+iblk*stride, (ithread+1)*n*sizeof(real)); } bspsstep_end(111); } memcp(recv, recvbuf, nblk*stride*sizeof(real)); } #endif #ifdef SHMEM #define NSYNC 16 void par_collect_all(send, recv, n, stride, nblk) real *send, *recv; int n, nblk, stride; { int i, right, left, iblk, ibeg, iSync; static long *recvs; long *recvbuf; static volatile long SyncB[NSYNC]; long Sync0 = ithread; long *cur_break; for(iSync=0; iSync < NSYNC; iSync++) SyncB[iSync] = _SHMEM_SYNC_VALUE; iSync = 0; recvs = (long*)recv; /* * Copy send data to proper place in receive buffer unless it is * already there. */ if( recv+ithread*n != send ) { for(iblk = 0; iblk < nblk; iblk++) memcp(recv+ithread*n+iblk*stride, send+iblk*stride, n*sizeof(real)); } barrier(); /* Ensure all PEs ready to receive data */ shmem_set_cache_inv(); /* * This version lives dangerously and works "in-place" with * the existing receive buffers. */ for (i=1; i cur_break ) { if( sbreak(recvbuf+nblk*stride - cur_break) == 0) message(NULLI, NULLP, FATAL, "Par_collect_all (%d): sbreak() failed\n"); } if( ibeg >= 0 ) for(iblk = 0; iblk < nblk; iblk++) shmem_put(recvbuf+ibeg*n+iblk*stride, recvs+ibeg*n+iblk*stride, i*n, right); else for(iblk = 0; iblk < nblk; iblk++) { shmem_put(recvbuf+(ibeg+nthreads)*n+iblk*stride, recvs+(ibeg+nthreads)*n+iblk*stride, -ibeg*n, right); shmem_put(recvbuf+iblk*stride, recvs+iblk*stride, (ithread+1)*n, right); } shmem_quiet(); /* Wait for puts to complete */ shmem_put((long*)&SyncB[iSync], &Sync0, 1, right); /* Signal to "right" its done */ while( SyncB[iSync] == _SHMEM_SYNC_VALUE ) ; /* Spin wait until data has arrived here */ #ifdef DEBUG if( SyncB[iSync] != left ) message(NULLI, NULLP, FATAL, "Par Collect: (%d) Sync out of order. Expected %d, got %d\n", ithread, left, SyncB[iSync]); #endif SyncB[iSync] = _SHMEM_SYNC_VALUE; iSync++; } shmem_clear_cache_inv(); } #endif #ifdef MPI void par_collect_all(send, recv, n, stride, nblk) real *send, *recv; int n, nblk, stride; { int i; int blens[2]; MPI_Datatype vtype, block, types[2]; MPI_Aint displs[2]; /* * Use the defined datatypes of MPI to collect the whole array from * distributed slices across processors. The "vtype" vector defines * the actual data, "nblk" blocks of "n" elements with a stride of "stride". * "block" is a struct with identical data to "vtype" BUT with a upper * bound of exactly 1 block. This fools MPI_Allgather into assembling * the scattered data into an interleaved array. */ MPI_Type_vector(nblk, n, stride, M_REAL, &vtype); blens[0] = 1; blens[1] = 1; types[0] = vtype; types[1] = MPI_UB; displs[0] = 0; displs[1] = n*sizeof(real); MPI_Type_struct(2, blens, displs, types, &block); MPI_Type_commit(&block); MPI_Allgather(send, 1, block, recv, 1, block, MPI_COMM_WORLD); MPI_Type_free(&vtype); MPI_Type_free(&block); } #endif /****************************************************************************** * par_begin(). Initialize parallel libs. * ******************************************************************************/ #ifdef TCGMSG void par_begin(argc, argv, ithread, nthreads) int *argc; char ***argv; int *ithread; int *nthreads; { int i; PBEGIN_(*argc, *argv); *nthreads = NNODES_(); *ithread = NODEID_(); for(i = 1; i < *argc; i++ ) if( !strcmp((*argv)[i],"-master")) { *argc = i-1; (*argv)++; break; } } #endif #ifdef BSP void par_begin(argc, argv, ithread, nthreads) int *argc; char ***argv; int *ithread; int *nthreads; { bspstart(*argc, *argv, 0, nthreads, ithread); } #endif #ifdef SHMEM void par_begin(argc, argv, ithread, nthreads) int *argc; char ***argv; int *ithread; int *nthreads; { int i; *nthreads = _num_pes(); *ithread = _my_pe(); for(i=0; i < _SHMEM_BCAST_SYNC_SIZE; i++) pSyncb[i] = _SHMEM_SYNC_VALUE; for(i=0; i < _SHMEM_REDUCE_SYNC_SIZE; i++) pSync[0][i] = pSync[1][i] = _SHMEM_SYNC_VALUE; barrier(); } #endif #ifdef MPI void par_begin(argc, argv, ithread, nthreads) int *argc; char ***argv; int *ithread; int *nthreads; { MPI_Init(argc, argv); MPI_Comm_size(MPI_COMM_WORLD, nthreads); MPI_Comm_rank(MPI_COMM_WORLD, ithread); } #endif /****************************************************************************** * par_finish(). Parallel lib wind-up function. * ******************************************************************************/ #ifdef TCGMSG void par_finish() { PEND_(); } #endif #ifdef BSP void par_finish() { bspfinish(); } #endif #ifdef SHMEM void par_finish() { barrier(); } #endif #ifdef MPI void par_finish() { MPI_Finalize(); } #endif /****************************************************************************** * par_abort(). Parallel lib abort function. * ******************************************************************************/ #ifdef TCGMSG void par_abort(code) int code; { Error("",code); exit(code); } #endif #ifdef BSP void par_abort(code) int code; { #ifdef NOTYET bspabort(code); #endif bspfinish(); exit(code); } #endif #ifdef SHMEM void par_abort(code) int code; { globalexit(code); } #endif #ifdef MPI void par_abort(code) int code; { MPI_Abort(MPI_COMM_WORLD, code); exit(code); } #endif /****************************************************************************** * copy_sysdef * ******************************************************************************/ void copy_sysdef(system, spec_ptr, site_info, pot_ptr) system_mp system; /* Pointer to system array (in main) */ spec_mp *spec_ptr; /* Pointer to be set to species array */ site_mp *site_info; /* To be pointed at site_info array */ pot_mp *pot_ptr; /* To be pointed at potpar array */ { spec_mp spec; int n_pot_recs; #ifdef SPMD /* * Fetch "system" struct */ par_broadcast((gptr*)system, 1, lsizeof(system_mt), 0); /* Allocate space for species, site_info and potpar arrays and set pointers*/ if( ithread > 0 ) { *spec_ptr = aalloc(system->nspecies, spec_mt ); *site_info = aalloc(system->max_id, site_mt ); *pot_ptr = aalloc(system->max_id * system->max_id, pot_mt ); } /* read species array into allocated space */ par_broadcast((gptr*)*spec_ptr, system->nspecies, lsizeof(spec_mt),0); /* Fill p_f_sites and site_id arrays for each species */ for (spec = *spec_ptr; spec < &(*spec_ptr)[system->nspecies]; spec++) { if( ithread > 0 ) { spec->p_f_sites = ralloc(spec->nsites); /* Allocate the species - */ spec->site_id = ialloc(spec->nsites); /* specific arrays */ } par_broadcast((gptr*)spec->p_f_sites, 3*spec->nsites, sizeof(real), 0); par_broadcast((gptr*)spec->site_id, spec->nsites, sizeof(int), 0); } /* Fill site_info array */ par_broadcast((gptr*)*site_info, system->max_id, sizeof(site_mt), 0); /* * Potential Parameters. */ n_pot_recs = SQR(system->max_id); if( ithread > 0 ) *pot_ptr = (pot_mt*)aalloc(n_pot_recs*sizeof(pot_mt), char); par_broadcast((gptr*)*pot_ptr, n_pot_recs, sizeof(pot_mt), 0); #endif } /****************************************************************************** * copy_dynamics() * ******************************************************************************/ void copy_dynamics(system) system_mp system; { gptr *ap; /* Pointer to averages database */ size_mt asize; /* Size of averages database */ #ifdef SPMD par_broadcast((gptr*)system->c_of_m,3*system->nmols, sizeof(real), 0); par_broadcast((gptr*)system->vel, 3*system->nmols, sizeof(real), 0); par_broadcast((gptr*)system->velp, 3*system->nmols, sizeof(real), 0); par_broadcast((gptr*)system->acc, 3*system->nmols, sizeof(real), 0); par_broadcast((gptr*)system->acco, 3*system->nmols, sizeof(real), 0); par_broadcast((gptr*)system->accvo, 3*system->nmols, sizeof(real), 0); if(system->nmols_r > 0) { par_broadcast((gptr*)system->quat, 4*system->nmols_r, sizeof(real), 0); par_broadcast((gptr*)system->qdot, 4*system->nmols_r, sizeof(real), 0); par_broadcast((gptr*)system->qdotp, 4*system->nmols_r, sizeof(real), 0); par_broadcast((gptr*)system->qddot, 4*system->nmols_r, sizeof(real), 0); par_broadcast((gptr*)system->qddoto, 4*system->nmols_r, sizeof(real), 0); par_broadcast((gptr*)system->qddotvo, 4*system->nmols_r, sizeof(real), 0); } par_broadcast((gptr*)system->h, 9, sizeof(real), 0); par_broadcast((gptr*)system->hdot, 9, sizeof(real), 0); par_broadcast((gptr*)system->hdotp, 9, sizeof(real), 0); par_broadcast((gptr*)system->hddot, 9, sizeof(real), 0); par_broadcast((gptr*)system->hddoto, 9, sizeof(real), 0); par_broadcast((gptr*)system->hddotvo, 9, sizeof(real), 0); par_broadcast((gptr*)system->ta, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->tap, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->tadot, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->tadoto, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->tadotvo, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->ra, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->rap, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->radot, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->radoto, system->nspecies, sizeof(real), 0); par_broadcast((gptr*)system->radotvo, system->nspecies, sizeof(real), 0); ap = av_ptr(&asize,0); /* get addr, size of database */ par_broadcast(ap, 1, asize,0); /* * N.B. We do NOT broadcast the accumulated RDF info. That would * be incorrect since it is later summed. Leave on thread zero and * zeros on other threads. WHen globally summed it will be correct. */ #endif } /****************************************************************************** * replicate(). Make a copy of all Moldy's constant and dynamic data. * * This is for parallel implementations and allows "start_up" * * to be called on one processor. This version calls the * * Oxford BSP library. * ******************************************************************************/ void replicate(control, system, spec_ptr, site_info, pot_ptr, restart_header) contr_mt *control; system_mt *system; spec_mt **spec_ptr; site_mt **site_info; pot_mt **pot_ptr; restrt_mt *restart_header; { int av_convert; /* * Fetch the top-level structs */ #ifdef SPMD par_broadcast((gptr*)control, 1, sizeof *control, 0); par_broadcast((gptr*)restart_header, 1, sizeof *restart_header, 0); /* * Now get "species" struct array and internal dynamic arrays */ copy_sysdef(system, spec_ptr, site_info, pot_ptr); if( ithread > 0 ) { /* * Now we have all the information to create the dynamic variables */ allocate_dynamics(system, *spec_ptr); /* * Initialise averages database. */ init_averages(system->nspecies, (char*)0, control->roll_interval, control->roll_interval,&av_convert); /* * Initialise radial distribution function database. */ if(control->rdf_interval > 0) init_rdf(system); } /* * Copy the dynamic vars from the other processes. */ copy_dynamics(system); #endif } $EOD $! $CREATE structs.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /* * $Header: /home/eeyore_data/keith/md/moldy/RCS/structs.h,v 2.9 1996/10/19 11:55:24 keith Exp $ * * $Log: structs.h,v $ * Revision 2.9 1996/10/19 11:55:24 keith * Corrected bug in control struct and xdr write of thermostat vars. * * Revision 2.8 1996/01/15 15:25:28 keith * Corrected definition of thermostat dynamic vars. * * Revision 2.7 1995/12/04 11:45:49 keith * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * Thanks to V. Murashov. * * Revision 2.6 1994/06/08 13:16:34 keith * Changed all timestep-related parameters to type "long". This means * that 16-bit DOS compilers can do more than 32767 timesteps. * * Revision 2.5 1994/01/18 13:33:02 keith * Null update for XDR portability release * * Revision 2.5 1994/01/18 13:33:02 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:28:19 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/07/19 13:28:21 keith * Added XDR capability for backup and dump files. * * Revision 2.0 93/03/15 14:49:26 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.6.1.15 93/03/12 12:14:34 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.6.1.15 93/03/09 15:59:22 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.6.1.14 92/10/28 14:09:40 keith * Changed "site_[tp]" typedefs to avoid name clash on HP. * * Revision 1.6.1.13 92/09/22 14:55:12 keith * Added support for "strict cutoff" mode. * * Revision 1.6.1.12 92/03/11 12:56:24 keith * Changed "scale-separately" parameter to "scale options" * * Revision 1.6.1.11 91/08/23 11:34:49 keith * Added extra padding to struct spec_t to round size up to 8 byte * boundary. This promotes portability of restart files. Rounded * up rather than down for compatibility of existing restart files. * * Revision 1.6.1.10 91/08/15 18:12:21 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.6.1.9 90/05/02 15:44:36 keith * Got rid of typedefs time_t and size_t. * * Revision 1.6.1.8 90/04/16 18:20:40 keith * Added new field "strain-mask" to control. * * Revision 1.6.1.7 90/04/12 16:29:10 keith * removed unneccessary include of * * Revision 1.6.1.6 90/04/06 11:09:49 keith * Moved definition of NPOTP to defs.h * * Revision 1.6.1.5 89/11/21 16:31:32 keith * Removed member out_file from control and all uses. (Now command parameter). * * Revision 1.6.1.4 89/11/20 18:10:41 keith * Added "defalt" field to match_t. * * Revision 1.6.1.3 89/11/20 13:30:14 keith * Replaced separate arrays "types" and "npotp" with array of structs "potspec" * * Revision 1.6.1.2 89/09/04 18:40:19 keith * Added 'surface_dipole' to control_t (& removed pad), moved 'scale_separately' * Added field 'charge' to spec_t. * * Revision 1.6.1.1 89/08/25 15:24:21 keith * Mods to add framework structures to simulation model * * Revision 1.6 89/06/20 18:25:36 keith * Moved definition of match_t to structs.h * * Revision 1.5 89/06/01 21:25:33 keith * Control.out eliminated, use printf and freopen instead to direct output. * * Revision 1.4 89/05/22 14:05:48 keith * Added rescale-separately option, changed 'contr_t' format. * * Revision 1.3 89/05/15 16:12:04 keith * Added new members, 'vsn' and 'dump_size' to dump_t. * * Must use with r1.3 or later of 'dump.c'. * * Revision 1.2 89/05/11 13:50:32 keith * Modified restrt_t to allow commensurate sun3/sun4 padding * * Revision 1.1 89/04/27 14:44:58 keith * Initial revision * * */ #ifndef STRUCT_ALREADY #define STRUCT_ALREADY #include "defs.h" #define SFORM "%127[^#]" /* Format for scanf to read strings safely */ typedef struct /* Control parameters for simulation */ { char title[L_name]; /* Job title */ long istep, /* Current timestep - used as loop counter */ nsteps; /* Number of timesteps to execute */ double step; /* Value of timestep in program units */ boolean print_sysdef, /* Flag to print out system specification file*/ new_sysdef, /* Read new sysdef instead of restart file one*/ const_pressure, /* Flag to turn on P&R CP method */ reset_averages, /* Flag to set average counters to zero */ scale_options, /* Scale each species separately */ surface_dipole, /* Flag surface dipole term in Ewald sum */ lattice_start; /* Flag to read starting state from sysdef */ char sysdef[L_name], /* Name of system specification file */ restart_file[L_name], /* Name of restart configuration file */ save_file[L_name], /* Name of file to write restart conf */ dump_file[L_name], /* Name of file 'dump' writes to */ backup_file[L_name], /* Name of backup save file */ temp_file[L_name]; /* Temporary file for writing restart */ int spare[23]; /* Extra space for expansion (should be ODD) */ double ttmass, /* Nose-Hoover trans temp mass parameter */ rtmass; /* Nose-Hoover rotat temp mass parameter */ int pad; /* To keep alignment of struct. */ int const_temp; /* Flag to turn on N&H CT method */ boolean xdr_write, /* Write restart, dump files in portable way. */ strict_cutoff; /* Perform real-space cutoff rigorously */ int strain_mask; /* Mask of constrained elements of h matrix */ int nbins; /* Number of bins for rdf calculation */ unsigned long seed; /* Seed for random number generator */ int page_width, /* Line width for output file */ page_length; /* Length of page on output file */ long scale_interval, /* Number of timesteps between scales */ scale_end, /* Stop scaling after n timesteps */ begin_average, /* Number of 'equilibration' steps */ average_interval,/* Frequency of averages calculation */ begin_dump, /* When to start storing dumps for analysis */ dump_offset, /* Used in for dump file names - internal only*/ dump_interval; /* Frequency of configuration dumps */ int dump_level, /* What to dump to file */ maxdumps; /* How many dump records in a dump file */ long backup_interval,/* Frequency to save state to backup file */ roll_interval, /* Number of timesteps for rolling avgs */ print_interval, /* Number of timesteps between printouts */ begin_rdf, /* When to start RDF calculation */ rdf_interval, /* Frequency to accumulate rdf data */ rdf_out; /* Frequency to calculate and output rdf */ double temp, /* Required temperature */ pressure, /* Required pressure */ pmass, /* Parinello and Rahman W parameter */ cutoff, /* Cut off radius */ subcell, /* Size of side of interaction cells */ density, /* Initial density on set-up */ alpha, /* Convergence factor for Ewald sum */ k_cutoff, /* Cutoff in k space for ewald sum */ limit, /* Limiting distance for rdf calculation */ cpu_limit; /* Maximum CPU allowed before run is stopped */ } contr_mt, *contr_mp; typedef struct /* Whole system information */ { int nsites, /* Total number of sites */ nmols, /* Total number of molecules/atoms */ nmols_r, /* Total number of polyatomics */ nspecies, /* Number of different molecule types */ max_id, /* Last dimension of potpar array */ d_of_f; /* Degrees of freedom of whole system */ int ptype, /* 0 = LJ, 1= buckingham, 2= MCY */ n_potpar; /* # parameters for this potential */ /* Dynamic variable arrays for whole system */ /* Dimensions for C of M quantities are [nmols][3] */ /* and for quaternions and derivatives, [nmols_r][4] */ vec_mp c_of_m, /* Centre of mass positions */ vel, /* " " " velocities */ velp, /* Predicted C of M velocities */ acc, /* C of M accelerations */ acco, /* " " at previous timestep */ accvo; /* " " two timesteps before */ quat_mp quat, /* Quaternions for this component */ qdot, /* Quaternion derivatives */ qdotp, /* Predicted quaternion derivatives */ qddot, /* Quaternion second derivatives */ qddoto, /* Old quaternion second derivatives */ qddotvo; /* Second derivatives two timesteps before */ mat_mp h, /* Unit cell for zero-stress simulation */ hdot, /* Unit cell derivatives */ hdotp, /* Predicted unit cell derivatives */ hddot, /* Unit cell second derivatives */ hddoto, /* Old unit cell second derivatives */ hddotvo; /* Very old unit cell second derivatives */ /* * Following variables ta..., ra.. have been introduced * by VVM and have dimensions of [nspecies] */ real *ta, /* N-H alpha for trans temp */ *tap, /* Predicted N-H alpha for trans temp */ *tadot, /* Derivative of trans alpha */ *tadoto, /* Old derivative of trans alpha */ *tadotvo; /* Very old derivative of trans alpha */ real *ra, /* N-H alpha for trans temp */ *rap, /* Predicted N-H alpha for trans temp */ *radot, /* Derivative of trans alpha */ *radoto, /* Old derivative of trans alpha */ *radotvo; /* Very old derivative of trans alpha */ } system_mt, *system_mp; typedef struct /* Information for one species */ { real inertia[3], /* Principal moments of inertia */ mass, /* Mass of whole molecule */ dipole, /* Dipole Moment */ charge; /* Total charge */ int nsites, /* Number of sites on this species */ nmols; /* Number of molecules of this species */ int rdof, /* Rotational degrees of freedom (2=linear) */ framework; /* Flag to signal this is a framework species */ char name[32]; /* Name of this species */ int *site_id; /* site identifier array */ vec_mp p_f_sites; /* Site co-ordinates in principal frame */ /* Dynamic variable arrays for this species */ /* These point to a subset of the whole-system arrays */ /* Dimensions for C of M quantities are [nmols][3] */ /* and for quaternions and derivatives, [nmols][4] */ /* If species is monatomic, quaternion pointers are null */ vec_mp c_of_m, /* Centre of mass positions */ vel, /* " " " velocities */ velp, /* Predicted C of M velocities */ acc, /* C of M accelerations */ acco, /* " " at previous timestep */ accvo; /* " " two timesteps before */ quat_mp quat, /* Quaternions for this species */ qdot, /* Quaternion derivatives */ qdotp, /* Predicted quaternion derivatives */ qddot, /* Quaternion second derivatives */ qddoto, /* Old quaternion second derivatives */ qddotvo; /* Second derivatives two timesteps before */ int pad[2]; /* Needed for compatibility of binary restart */ /* files due to historical cock-up. */ } spec_mt, *spec_mp; typedef struct /* site info template. */ { double mass, charge; char name[8]; int flag; int pad; } site_mt, *site_mp; typedef struct /* Holds potential parameter information */ { int flag; int pad; real p[NPOTP]; } pot_mt, *pot_mp; typedef struct { char *name; int npar; } pots_mt; typedef struct /* Units used for program input */ { double m, /* mass */ l, /* length */ t, /* time */ q; /* charge */ } unit_mt, *unit_mp; typedef struct /* Record of dimensions of physical quantity */ { int m, /* Number of powers of mass in unit */ l, t, q; } dim_mt, *dim_mp; typedef struct /* Struct template for keyword */ { /* in read_control. */ char *key, *format, *defalt; gptr *ptr; } match_mt; #define DLEN 28 /* Length of date/time string */ typedef struct /* Restart file header format */ { time_mt timestamp, /* Date and time restart file was written */ prev_timestamp; /* Timestamp of preceding restart file */ char init_date[DLEN],/* Date run was initiated (propagated through)*/ title[L_name], /* Title when run was initiated */ vsn[16]; /* Version SID of program that wrote restart */ int seq; /* Sequence NO. eg 5th restart in run */ } restrt_mt; typedef struct /* Dump file header format */ { char title[L_name], /* Run title at beginning of dump run */ vsn[16]; /* RCS Revision number */ long istep, /* Timestep at beginning of this file */ dump_interval; /* How many steps between dumps */ int dump_level, /* Parameter determining contents of record */ maxdumps, /* Maximum number of dump records in file */ ndumps, /* How many dump records in file */ dump_size; /* Size of a dump record */ time_mt timestamp, /* Time file was written */ dump_init, /* Time dump run was started (ie first file) */ restart_timestamp;/* Time corresponding restart file written */ } dump_mt; #define MAX_ROLL_INTERVAL 100 typedef struct { double value, sum, sum_sq, mean, sd, roll[MAX_ROLL_INTERVAL], roll_mean, roll_sd; } old_av_mt; typedef union { old_av_mt av; struct { int av, roll; } cnt; } old_av_u_mt; typedef struct { int nav, nroll, iroll, pad; double align; } av_head_mt; #endif $EOD $! $CREATE defs.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /* * $Header: /home/eeyore_data/keith/md/moldy/RCS/defs.h,v 2.11 1996/11/05 16:50:29 keith Exp $ * * $Log: defs.h,v $ * Revision 2.11 1996/11/05 16:50:29 keith * Release for 2.11. * Added ANSI_LIBS for Sun Solaris2 * Defs modified for Convex/HP SPP. * Vector selection macro VECTOR added for site_neighbour_list() and * cray PVP tested for by _CRAY1 macro. * Added cache-tuning parameters NLINE and NCACHE. * * Revision 2.10 1996/03/06 18:16:21 keith * Minor mods assuming ANSI behaviour on MS_DOS * Removed all COS functionality. * Updated IBM AIX macro selection * Added ANSI_LIBS functionality for Linux, OSF and SGI * * Added conditional defn of VOLATILE for the precision() bugfix * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * * Updated constants from CODATA 1986. Compile with -DOLDCONSTS for * compatibility. * * Revision 2.10 1995/12/22 14:00:52 keith * Minor mods assuming ANSI behaviour on MS_DOS * Removed all COS functionality. * * Nose-Hoover and Gaussian (Hoover constrained) thermostats added. * * Updated constants from CODATA 1986. Compile with -DOLDCONSTS for * compatibility * * Revision 2.9 1995/01/05 09:56:35 keith * Null update to increment version number * * Revision 2.8 1994/07/07 17:03:39 keith * Fixed up missing xdr_vector to be compiled in only if NEED_XDR_VECTOR defined. * * Revision 2.8 1994/07/07 17:03:39 keith * Fixed up missing xdr_vector to be compiled in only if NEED_XDR_VECTOR defined. * * Revision 2.7 1994/06/08 13:10:43 keith * New macro "balloc(n,size)" for cases when type isn't explicit. * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * * Now recognises _UNICOS macro and defines "unix". * Specific MSDOS file names added on __MSDOS__ macro. * Evaluates CONST macro to const or nil depending on * ANSI/KR environment. * Added size_mt typedef (ulong) for interfacing with lib fns. * * Revision 2.5 94/01/25 16:49:41 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.4 94/01/18 13:13:42 keith * Workaround for bugs and defined symbol _HPUX_SOURCE needed to compile xdr. * * Revision 2.3.1.1 93/12/21 19:02:17 keith * Mods to allow HP's ANSI compiler to work. I think it's broken. * Not tested on other architectures yet so don't incorporate * into main line. * NB Added _POSIX_SOURCE and _XOPEN_SOURCE symbols for *all* architectures. * This might or might no avoid problems. * * Revision 2.3 93/10/28 17:41:01 keith * Added __unix to the list of recognised macros * * Revision 2.3 93/10/28 10:28:29 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.2 93/10/14 18:17:56 keith * Fixed prortability problems to IBM RS6000 * * Revision 2.1 93/08/18 20:54:03 keith * Tidied up clashes over ABS, MIN, MAX macros. * * Revision 2.1 93/07/19 13:27:15 keith * Added XDR capability for backup and dump files. * * Revision 2.0 93/03/15 14:49:28 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.24 93/03/12 12:26:12 keith * Reorganized defines to recognise all ANSI (__type__) forms. * Fixed up Cray by defining old symbol. * * Revision 1.23 93/03/09 15:59:24 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.22 92/06/15 16:52:00 keith * Put parens round arg on xfree macro to make it safe with expr. * * Revision 1.21 92/06/12 12:55:56 keith * Mods to make it work on VMS again. Ugh. * * Revision 1.20 92/06/11 21:40:41 keith * Added LOCKEX macro for system-dependent lock extension. * * Revision 1.19 92/06/10 15:53:33 keith * Added new potential type "generic" for Neal. * * Revision 1.18 92/02/26 14:29:04 keith * Updated vectorization directive substitution for Convex C vsn 4.3 * * Revision 1.17 91/08/19 16:49:34 keith * Moved #if so that errno.h is included for system V. * * Revision 1.16 91/08/17 13:58:59 keith * Added "__unix__" symbol for ANSI unix compilers. * * Revision 1.15 91/08/15 18:12:22 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.14 91/03/12 15:43:31 keith * Tidied up typedefs size_mt and include file * Added explicit function declarations. * * Revision 1.13 90/09/28 13:29:45 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.12 90/09/05 10:30:57 keith * Support for cray scc added - directives and ANSI_LIBS macro set. * * Revision 1.11 90/08/22 10:58:42 keith * Changed ANSI libraries conditional compilation to rely on own * symbol ANSI_LIBS rather than __STDC__. * Corrected test for cray scc compiler in vectorization directives. * * Revision 1.10 90/05/02 15:43:52 keith * Got rid of typedefs time_t and size_mt. * * Revision 1.9 90/04/12 16:23:44 keith * Used to check for Berkeley unix and define symbol BSD * * Revision 1.8 90/04/06 11:09:22 keith * Aquired definition of NPOTP from structs. * * Revision 1.7 90/03/27 17:36:12 keith * Moved O/S dependent conditionals to here, esp VPRINTF. * Reorganised configuration conditionals into one block. * * Revision 1.6 90/03/26 18:04:33 keith * Tidied up system dependant includes. * Added system-dependant backup and temp file names (for input.c). * * Revision 1.5 90/03/09 17:34:45 keith * Added preprocessor directives to define USG (ie system V) for unicos. * * Revision 1.4 89/09/04 18:41:49 keith * Added conversion constants for charges. * * Revision 1.3 89/06/14 14:16:35 keith * Added vectorisation for stellar and recognised sysV & SysV macros * * Revision 1.2 89/05/22 14:05:51 keith * Added rescale-separately option, changed 'contr_t' format. * * Revision 1.1 89/05/02 10:51:58 keith * Initial revision * * */ #ifndef DEFS_ALREADY #define DEFS_ALREADY /* * Version ID strings */ #define REVISION "$Revision: 2.11 $" #define REVISION_DATE "$Date: 1996/11/05 16:50:29 $" #define REVISION_STATE "$State: Exp $" /****************************************************************************** * Configurational information. Edit this to tailor to your machine * ******************************************************************************/ /* * See if we can detect IBM RS6000. * _ALL_SOURCE is necessary to make XDR stuff work. */ #ifdef _AIX # define __unix__ # define ANSI_LIBS # ifndef _ALL_SOURCE # define _ALL_SOURCE # endif #endif /* * To allow XDR stuff to work on HP. Surely there's a more general * way of doing this? I think that HPs header files are broken. */ #if defined(__hpux) && ! defined(__convex_spp) #define _HPUX_SOURCE #endif #if (defined(__unix__) || defined(__unix) || defined(_unix_) || defined(_unix) || defined(_UNICOS)) && !defined(unix) # define unix #endif #ifdef __vms # ifndef vms # define vms # endif # ifndef VMS # define VMS # endif #endif #ifdef ardent # define ARDENT # define NEED_XDR_VECTOR #endif /* * Define operating-system dependant default filenames */ #if defined(__MSDOS__) || defined(__WATCOMC__) # define BACKUP_FILE "MDBCK" # define TEMP_FILE "MDTEMPX" # define LOCKEX "$LK" #endif #ifdef vms # define BACKUP_FILE "MDBACKUP.DAT" # define TEMP_FILE "MDTEMPXXXX.DAT" # define LOCKEX "$LCK" #endif #ifdef CMS # define BACKUP_FILE "MDBACKUP MOLDY A1" # define TEMP_FILE "MDTEMP XXXXXXXX A1" #endif #ifdef unix # define LOCKEX ".lck" #endif #ifndef LOCKEX # define LOCKEX "LK" #endif /* * Set ANSI_LIBS only if you have the standard ANSI headers and libraries */ #ifdef _CRAY #ifndef CRAY # define CRAY #endif #endif #if defined(CRAY) /* scc compiler comes with libraries*/ # define ANSI_LIBS #endif #ifdef __linux__ # define ANSI_LIBS #endif #ifdef __osf__ # define ANSI_LIBS #endif #ifdef __sgi__ # define ANSI_LIBS #endif #if defined(__sun) && defined(__SVR4) /* Solaris 2 libraries are ANSI */ # define ANSI_LIBS #endif /* * New convex compiler is ANSI, but doesn't define __STDC__ or convexvc. * It has a silly macro __stdc__ which we will use instead. convexvc * may not be necessary as is no longer required. But there * is still veclib. */ #if defined(__convexc__) # if defined(__stdc__) /* Anything but "-pcc" mode */ # define ANSI # define ANSI_LIBS # endif #endif #if defined(vms) # define ANSI # define ANSI_LIBS #endif #if defined(__MSDOS__) || defined(__WATCOMC__) # define ANSI # define ANSI_LIBS #endif /* * Set HAVE_VPRINTF if this function is in target machine's library. */ #ifdef ANSI_LIBS /* ANSI has it */ #define HAVE_VPRINTF #endif #if defined(sun) || defined(stellar) || defined(titan) /* So do these */ #define HAVE_VPRINTF #endif #if defined(cray) && (defined(unix) || defined(__unix__)) /* ie UNICOS */ #define HAVE_VPRINTF #endif /* * Otherwise does machine have _doprnt? */ #if defined(convex) || defined(sequent) #define HAVE_DOPRNT #endif /* * Get rid of "const" keyword for non-ANSI compilers. */ #if defined(__STDC__) || defined(ANSI) # define CONST const # define VOLATILE volatile #else # define CONST /* */ # define VOLATILE /* */ #endif /* * Hardware configuration. Specify cache-tuning params NCACHE and NLINE * NCACHE is minimum size of "sites" arrays and should be a sub-multiple * of the cache length in WORDS (sizeof(real)). It MUST be a power * of two since the alignment algorithm relies on this. * NLINE is padding (in words) between arrays to avoid cache conflicts. * Theoretically NCACHE should equal the size of the cache and NLINE * the size of the cache line. But too large an NCACHE wastes memory * (arrays are padded to a multiple of this) and is actually slower * for small systems presumably because it causes TLB misses. 512 * works well for HP/PA and IBM RISC/POWER. * NLINE ought really to be a multiple of the cache line size but it * doesn't seem to matter as long as it's not zero. * 512/4 works well on HP/PA/IBM RISC/POWER/SPARC/ALPHA/MIPS so use as * default. Hardware-specific values could be set here conditionally. */ #define NCACHE 256 #define NLINE 4 /* * Vectorisation directive translation. N.B. Most preprocessors munge * directives so the #define must substitute the preprocessor OUTPUT. */ #if defined(_CRAY1) /* This seems to be defined for all CRI PVP systems */ # ifdef __STDC__ # define VECTORIZE # define NOVECTOR # else # define VECTORIZE ## ivdep # define NOVECTOR ## novector # endif # define VECTOR /* To choose vector vsn of site_neighbour_list */ #else #if defined(__convexc__) && ! defined(__convex_spp) # define VECTORIZE ;/* $dir no_recurrence */; # define NOVECTOR ;/* $dir scalar */; # define VECTOR /* To choose vector vsn of site_neighbour_list */ #else #ifdef stellar # define VECTORIZE __dir NO_RECURRENCE : # define NOVECTOR __dir SCALAR : # define VECTOR /* To choose vector vsn of site_neighbour_list */ #else #ifdef ardent # define VECTORIZE # pragma ivdep # define NOVECTOR # pragma novector # define VECTOR /* To choose vector vsn of site_neighbour_list */ #else # define VECTORIZE /* Canny vectorise on this machine!*/ # define NOVECTOR /* */ #endif #endif #endif #endif /* * Set symbol USG to identify system V variant of unix, BSD for Berkeley. */ #include /* * Berkeley error numbers appear to be very regular, so the following is * pretty likely to get it right. If it doesn't, do the define by hand. * BSD is used to signal use of getrusage() rather than times() (unix only) * and absence of mem*() and strchr() functions from library. */ #if defined(unix) && !defined(USG) #if EWOULDBLOCK==35 && EINPROGRESS==36 && EALREADY==37 # define BSD #else # define USG #endif #endif /****************************************************************************** * End of machine/OS configuration. * ******************************************************************************/ #define NPOTP 7 /* Must be number of doubles in pot_mt */ #ifndef SEEK_END #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #define L_name 128 /* Max Length of file names */ #define NPE 2 /* real & Ewald PE's */ #undef MAX #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MAX3(x,y,z) MAX(x, MAX(y,z)) #undef MIN #define MIN(x,y) ((x) < (y) ? (x) : (y)) #define MIN3(x,y,z) MIN(((x) < (y) ? (x) : (y)),z) #define SUMSQ(x) (x[0]*x[0] + x[1]*x[1] +x[2]*x[2]) #define SUMSQ2(x) (x[1]*x[1] + x[2]*x[2] +x[3]*x[3]) #define SQR(x) ((x) * (x)) #define CUBE(x) ((x) * (x) * (x)) #define DISTANCE(x,y) sqrt(SQR(x[0]-y[0])+SQR(x[1]-y[1])+SQR(x[2]-y[2])) #define SIGN(x, y) ((y) > 0 ? fabs(x) : -fabs(x)) #define ALPHAMIN 1e-7 /* Fundamental constants '_' denotes MKS units. SHOULD NEVER BE ALTERED */ #define PI 3.14159265358979323846 #define DTOR (PI/180.0) #ifdef OLDCONSTS #define _kB 1.380662e-23 #define _kcal 4184.0 #define _EPS0 8.85418782e-12 #define _ELCHG 1.6021892e-19 #define ECSTR "1.6021892e-19" #define _ROOT_4_PI_EPS 1.0548222865e-5 #define AVOGAD 6.022045e23 #define AMU 1.6605655e-27 #define AMUSTR "1.6605655e-27" #define RTAMU 4.0745e-14 /*sqrt(amu) */ #else /* Values from CODATA 1986 */ #define _kB 1.380658e-23 #define _kcal 4184.0 #define _EPS0 8.854187817e-12 #define _ELCHG 1.60217733e-19 #define ECSTR "1.60217733e-19" #define _ROOT_4_PI_EPS 1.05482230112e-05 #define AVOGAD 6.0221367e23 #define AMU 1.6605402e-27 #define AMUSTR "1.6605402e-27" #define RTAMU 4.07497263794495e-14 /*sqrt(amu) */ #endif #define RGAS (AVOGAD*_kB) /* Program units relative to MKS units ONLY M, L, T, Q UNIT SHOULD BE CHANGED */ #define MUNIT AMU /* atomic mass units */ #define LUNIT 1.0e-10 /* Angstrom */ #define TUNIT 1.0e-12 /* Picosecond */ #define EUNIT (MUNIT * (LUNIT/TUNIT) * (LUNIT/TUNIT)) #define QUNIT /*sqrt(EUNIT*LUNIT)*/ (RTAMU*1.e-3*_ROOT_4_PI_EPS) #define MUNIT_N "amu" #define LUNIT_N "A" #define RLUNIT_N "A(-1)" #define TUNIT_N "ps" #define IUNIT_N "amuA**2" #define DIPUNIT_N "Prog units" /* Constants in program units */ #define kB (_kB / EUNIT) #define EPS0 (0.25 / PI) /* Output conversion units */ #define CONV_E (0.001*AVOGAD*EUNIT) /* kJ/mol */ #define CONV_T (kB / CONV_E) /* kB / E unit*/ #define CONV_P (MUNIT/(LUNIT*TUNIT*TUNIT)/1.0e6) /* MPa */ #define CONV_V CONV_E #define CONV_F (MUNIT*LUNIT/(TUNIT*TUNIT)*sqrt(AVOGAD))/* N/mol */ #define CONV_N (CONV_F*LUNIT) /* Nm/mol */ #define CONV_D (QUNIT*LUNIT*4.8e10/_ELCHG) #define CONV_Q (QUNIT/_ELCHG) #define CONV_TM 0.01 #define CONV_E_N "kJ/mol" #define CONV_T_N "K" #define CONV_P_N "Mpa" #define CONV_F_N "N**2/mol" #define CONV_N_N "(Nm)**2/mol" #define CONV_D_N "D" #define CONV_Q_N "Qe" #define CONV_TM_N "kJ/mol*ps**2" #define false 0 #define true 1 typedef unsigned long int time_mt;/* Larger than any possible time_t */ typedef unsigned long size_mt; /* Wide type for passing sizeof */ #if (defined(ANSI) || defined(__STDC__)) && !defined(VMS) typedef void gptr; #else typedef char gptr; #endif typedef double real; typedef int boolean; typedef enum {inv, noinv} invrot; typedef enum {tke_n, rke_n, pe_n, e_n, tt_n, rt_n, t_n, h0_n, h1_n, h2_n, stress0_n, stress1_n, stress2_n, press_n, vir_n, msqf_n, msqt_n, dip_n, end} av_n; typedef real vec_mt[3]; typedef vec_mt *vec_mp; typedef real quat_mt[4]; typedef quat_mt *quat_mp; typedef real mat_mt[3][3]; typedef vec_mt *mat_mp; #define balloc(n,size) talloc((int)(n),(size_mt)(size), __LINE__, __FILE__) #define aalloc(n, type) (type *)balloc((n), sizeof(type)) #define ialloc(n) aalloc(n, int) #define dalloc(n) aalloc(n, real) #define ralloc(n) aalloc(n, vec_mt) #define palloc(n) aalloc(n, vec_mt *) #define qalloc(n) aalloc(n, quat_mt) #define xfree( ptr ) tfree( (gptr *) (ptr) ) #define lsizeof (size_mt)sizeof #ifdef ANSI_LIBS # define memcp(s1,s2,n) (void)memcpy( (gptr*)(s1), (gptr*)(s2), (size_mt)(n)) # define memst(s,c,n) (void)memset( (gptr*)(s), (c), (size_mt)(n)) #else # define memcp(s1,s2,n) (void)memcpy( (gptr*)(s1), (gptr*)(s2), (int)(n)) # define memst(s,c,n) (void)memset( (gptr*)(s), (c), (int)(n)) #endif #endif $EOD $! $CREATE string.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /* * $Header: /home/eeyore_data/keith/md/moldy/RCS/string.h,v 2.8 1996/03/06 16:02:13 keith Exp $ * * $Log: string.h,v $ * Revision 2.8 1996/03/06 16:02:13 keith * Moved tests/#defines of m/c include macros into non-ansi case only. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Added RS6000 macro for inclusion protection. * * Revision 2.5 94/01/18 13:33:00 keith * Null update for XDR portability release * * Revision 2.4 94/01/18 13:23:17 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.3 93/10/28 10:28:31 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/07/19 13:28:19 keith * Added XDR capability for backup and dump files. * * Revision 2.0 93/03/15 14:49:29 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.10 93/03/09 15:59:26 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.9 91/08/16 15:26:17 keith * Checked error returns from fread, fwrite, fseek and fclose more * rigourously. Called strerror() to report errors. * * Revision 1.8 91/08/15 18:12:24 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_t and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.7 91/03/12 15:43:40 keith * Tidied up typedefs size_t and include file * Added explicit function declarations. * * Revision 1.6 90/04/14 16:02:06 keith * Replaced calls to system headers with own definitions for portability. * * */ #ifdef ANSI_LIBS # include #else #ifndef __string_h #ifndef _STRING_H #ifndef _STRING_H_ #ifndef __STRING_H #ifndef _H_STRING #ifndef __STRING_H__ #ifndef _STRING_INCLUDED #include "stddef.h" extern char *strcat(), *strncat(), *strcpy(), *strncpy(), *strchr(), *strtok(), *strdup(), *strstr(), *strerror(); extern int strcmp(); #ifdef __GNUC__ extern unsigned long #else extern int #endif strlen(); extern gptr *memcpy(), *memset(); #define __string_h #define _STRING_H #define _STRING_H_ #define __STRING_H #define __STRING_H__ #define _H_STRING #define _STRING_INCLUDED #endif #endif #endif #endif #endif #endif #endif #endif $EOD $! $CREATE time.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /* * Time.h replacement for ANSI one */ #ifdef ANSI_LIBS #include #else #ifndef __time_h #ifndef _TIME_H #ifndef _TIME_H_ #ifndef __TIME_H #ifndef _H_TIME #ifndef __TIME_H__ #ifndef _TIME_INCLUDED #include # if defined(unix) || defined(__unix__) /* * We must protect the inclusion of . */ # ifndef SYS_TYPES_INCLUDED # define SYS_TYPES_INCLUDED # include # endif extern time_t time(); extern char * ctime(); # endif #define __time_h #define _TIME_H #define _TIME_H_ #define __TIME_H #define _H_TIME #define __TIME_H__ #define _TIME_INCLUDED #endif #endif #endif #endif #endif #endif #endif #endif $EOD $! $CREATE stddef.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #ifdef ANSI_LIBS # include #else #ifndef __stddef_h #ifndef _STDDEF_H #ifndef _STDDEF_H_ #ifndef __STDDEF_H #ifndef __STDDEF_H__ #ifndef _STDDEF_INCLUDED # ifndef NULL # define NULL 0 # endif #endif #endif #endif #endif #endif #endif #endif $EOD $! $CREATE stdlib.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #ifdef ANSI_LIBS # include #else #ifndef __stdlib_h #ifndef _STDLIB_H #ifndef _STDLIB_H_ #ifndef __STDLIB_H #ifndef __STDLIB_H__ #ifndef _H_STDLIB #ifndef _STDLIB_INCLUDED # include "stddef.h" extern char * calloc(); extern char * malloc(); extern char * realloc(); extern void free (); extern void exit (); extern int abs (); extern int atoi (); extern long strtol(); #define __stdlib_h #define __STDLIB_H__ #define __STDLIB_H #define _STDLIB_H_ #define _STDLIB_H #define _H_STDLIB #define _STDLIB_INCLUDED #endif /* __STDLIB_H__ */ #endif /* __STDLIB_H__ */ #endif /* _STDLIB_H_ */ #endif /* _STDLIB_H_ */ #endif /* _STDLIB_H_ */ #endif /* _STDLIB_H_ */ #endif /* _STDLIB_H_ */ #endif $EOD $! $CREATE messages.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /* * $Header: /home/eeyore_data/keith/md/moldy/RCS/messages.h,v 2.14 1996/09/02 21:45:42 keith Exp $ */ #ifndef SYSRD /* Skip if already defined */ /* Severities to be passed to 'message'. */ #define INFO 0 #define WARNING 1 #define ERROR 2 #define FATAL 3 #define NULLP (char*)0 #define NULLI (int*)0 #define BACKUP "Simulation restarted from backup file %s" #define RNFAIL "Rename to \"%s\" failed -- file left in \"%s\"\n - %s" #define SYSRD "reading system specification file" #define TOMANY "Too many species in system specification file" #define NOSPEC "failed to read any molecular species info" #define NONUM "number of molecules of %s not specified" #define NOMOLS "invalid number (%d) of molecules of %s" #define NOSITE "invalid number (%d) of sites on molecule %s" #define INVSID "invalid site id %d" #define NCONF "site %d - name conflicts with previously set value %s" #define CCONF "site %d - charge conflicts with previously set value %f" #define MCONF "site %d - mass conflicts with previously set value %f" #define INVMAS "site %d - negative value (%g) supplied for mass" #define MISSCO "only %d site co-ordinates specified for site %d" #define BROKEN "internal error - sscanf returned %d items" #define NOMASS "no mass specified for site id %d" #define NOCGRG "no charge specified for site id %d" #define NONAME "no name specified for site id %d" #define NOTUSD "unused site identifier %d" #define UNKPOT "unknown type of potential %s (lennard-jones, buckingham, mcy)" #define NOPAIR "site id pair is required" #define NOPOTP "insufficient potential parameters supplied (%d needed)" #define IDOUTR "site id %d out of range" #define EXTPOT "potentials specified for unused sites - ignored" #define DUPPOT "potentials already set for this site pair" #define NOPOT "no potential parameters given between sites %d and %d" #define ERRS "system specification file contains %d errors" #define SUCCES "system specification file successfully read in" #define LATTIC "system successfully initialised from lattice start" #define REFORM "wrong length record in restart file at byte %ld\ - found %lu, expected %lu" #define REREAD "read error on restart file at byte %ld\n - %s" #define REEOF "unexpected end of file reading restart file" #define REWRT "write error on restart file\n - %s" #define NOVAL "no value associated with name \"%s\"" #define NOTFND "keyword \"%s\" not found" #define BADVAL "value \"%s\" is wrong type for keyword \"%s\"" #define ERRCON "control file contains %d error%c" #define SUCCON "control file read in successfully" #define BADUNI "Overflow during conversion of units - ln(scale) = %f" #define ZMASS "Mass of %s molecule (%f) is less than 1 amu" #define OCFAIL "Failed to open file \"%s\" for reading control info" #define ODFAIL "Failed to open file \"%s\" for reading system specification\n - %s" #define ORFAIL "Failed to open file \"%s\" for reading restart configuration\n - %s" #define OSFAIL "Failed to open file \"%s\" for writing restart configuration\n - %s" #define OOFAIL "Failed to open file \"%s\" as main output file\n - %s" #define SEFAIL "Rewind or seek failed on file \"%s\"\n - %s" #define RESUCC "restart file \"%s\" successfully read in" #define NEWTS "Interpolating accelerations from old timestep %g to new %g" #define ZEROTS "Cannot interpolate from old timestep of 0 (to new of %gps)" #define NSPCON "Number of species in sysdef file (%d) and restart file (%d)\ must be the same" #define NMLCON "Number of molecules of %s in sysdef and restart files must\ be the same (%d vs %d)" #define NDFCON "Molecules of %s in sysdef and restart files must have same \ rotational degrees of freedom (%d vs %d)" #define CROWDED "Cells too large - multiple occupation (mol=%d, cell=%d)" #define NABORS "Neighbour list contains %d cells" #define TONAB "Too many sites (%d) for neighbour list arrays (%d slots) \n\ - Increase NMULT in \"force.c\"" #define CUTOFF "Cutoff radius > %d * cell dimension.\n\ - Increase NSH in \"force.c\"" #define CUTRDF "RDF limit > %d * cell dimension.\n\ - Increase NSH in \"force.c\"" #define TOOCLS "Sites %d and %d closer than %fA." #define TOODIM "Arralloc request for %d dimensions - max %d" #define INSIDE "Array bounds [%d...%d] inside out (from ARRALLOC)" #define UNKPTY "KERNEL called with unkown potential type %d" #define NOCELL "Not enough values to specify unit cell\n\ expected 3 lengths, 3 angles and number of unit cells in MD cell." #define INVCEL "Invalid unit cell parameters - must be +ve and angles < 180" #define UNKSPE "\"%s\" is not recognised as a molecular species" #define FEWCOO "Too few co-ordinates for species \"%s\" - 3 needed" #define FEWQUA "Too few quaternions for species \"%s\" - 4 needed" #define FRACCO "Fractional co-ordinates must be in range [0,1) - (%f,%f,%f)" #define QNORM "Quaternion (%f,%f,%f,%f) is not normalised" #define QNORM2 "Quaternion %d (%f,%f,%f,%f) - normalisation error in beeman" #define QCONST "Quaternion %d - constraint error (%g)" #define NIMOLS "Wrong number of molecules of %s - given %d, expected %d" #define INITER "Initialisation file contains %d errors" #define ROTLEN "Length (%d) not a multiple of quaternion number (%d) in \ \"rotate\"" #define OVRLAP "%s - Result matrix overlaps input" #define OVRLP1 "mat_vec_mul - Input and output vectors overlap\ (in=%x, out=%x, len=%x)" #define SNGMAT "%s - matrix is singular" #define AVNOC "%s - init_averages has not been called" #define AVBNDS "add_average - offset (%d) out of bounds for type %s" #define NEGVAR "%s - variance < 0 (%f) for type %s" #define NOMEM "Memory allocation fails at line %d in \"%s\"\ (%d items of %lu bytes)" #define DUMPST "Started dumping data to file \"%s\" at timestep %ld" #define CONTIG "Dump file \"%s\" and restart file do not match" #define DUMPTS "Dump file(\"%s\")'s timestep (%ld) does not match current timestep (%ld)." #define DRESET "Problems prevent continuing existing dump. Starting new sequence." #define SHTDMP "Records missing from dump file \"%s\" - found %d, expected %d" #define LNGDMP "Extra records in dump file \"%s\" - found %d, expected %d" #define CORUPT "Dump file \"%s\" corrupt - expected %d bytes, found %d" #define DOERRR "Failed to open dump file \"%s\"\n - %s" #define DRERR "Read from dump file \"%s\" failed\n - %s" #define DMPALT "Dump-level altered, new dump run started" #define DMPEXS "File \"%s\" exists - Dumps will be written to \"%s\"" #define DOERRW "Failed to open dump file \"%s\" for writing\n - %s" #define DWERR "Write to dump file \"%s\" failed\n - %s" #define MUFAIL "Unable to mutate dump file name \"%s\" (in %d attempts)\n" #define UNKEY "Unknown keyword \"%s\"" #define SYSCHG "System has net electric charge of %.2g - \ correction of %g kJmol(-1) added to self energy" #define FRACHG "Framework has net electric charge of %.2g - \ correction of %g kJmol(-1) added to self energy" #define WDPTR "Arralloc called for object with size (%ul) not an integral\ number of words" #define NCNVRG "Do_step: velocities failed to converge after %d iterations \ - dist = %f" #define INRVSN "Values.c:init_averages: Invalid RCS version \"%s\"\n" #define CPOTFL "Not enough space to store potential parameters from restart\ file. Increase NPOTP in \"defs.h\" from %d to at least %d and recompile" #define LOCKED "Another instance of MOLDY is accessing the same %s files.\n\ Delete lockfile \"%s\" if the previous run crashed." #define LOCKFL "Failed to create lockfile \"%s\"" #define XDRFL "XDR call failed" #define GPFAIL "Get file position failed on file \"%s\"\n - %s" #endif #define SYSEOF "Unexpected end of file encountered while reading %s" #define MAXCUT "Optimum cutoff of %2.2f A is larger than allowed maximum \ of %2.2f.\n Maximum will be used but accuracy of Ewald sum is compromised." #define GANDP "Application of Parinello-Rahman algorithm along with \ Gaussian thermostat would interfere with each other." #define NOKEY "no keyword found on line" #define NOCUT "No real-space cutoff specified or cutoff invalid" #define BODGUP "Reading bad 2.10 restart file - thermostat parameters invalid.\ \n Setting ttmass and rtmass to %f and const-temp=0" #define DESYNC "Trajectories on parallel threads are diverging.\n Thread %d: %20.17g != %20.17g" $EOD $! $CREATE xdr.h $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * xdr Moldy-specific xdr routines for storing binary data in machine- * * independent format. For compatibility with existing binary * * formats, strings are stored as fixed-length opaque data. * ****************************************************************************** * Revision Log * $Log: xdr.h,v $ * Revision 2.9 1996/09/25 16:29:12 keith * Fixed restart structure correctly - broken in prev version. * Thermostat parameters may not be properly read. * * Revision 2.8 1996/03/07 15:01:57 keith * Made "malloc in types.h" macro protection conditional on "ANSI_LIBS" * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Revision 2.5.1.1 1994/02/03 18:36:12 keith * Tidied up and got rid of most of the global data items. * * Revision 2.5 94/01/18 17:35:45 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.5 94/01/18 13:33:08 keith * Null update for XDR portability release * * Revision 2.4 94/01/18 13:23:19 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.3 93/10/14 18:18:16 keith * Fixed prortability problems to IBM RS6000 * * Revision 2.2 93/09/06 14:42:47 keith * Fixed portability problems/bugs in XDR code. * * Revision 2.1 93/07/19 13:29:47 keith * Support for XDR backup/dump routines. * */ #ifndef lint static char *RCSidh = "$Header: /home/eeyore_data/keith/md/moldy/RCS/xdr.h,v 2.9 1996/09/25 16:29:12 keith Exp $"; #endif /*========================== Library include files ===========================*/ #ifdef USE_XDR /* * Some descended from Sun's original include a declaration * of "malloc" in an unprotected fashion. Try to define it out of the * way -- include "stdlib.h" if necessary to put it back. * In case an implementation (eg SGI) does it right by including * ensure that any Moldy module includes "stdlib.h" *before* "xdr.h". */ #ifndef ANSI_LIBS #define free xxfree #define exit xxexit #define malloc xxmalloc #define calloc xxcalloc #define realloc xxrealloc #endif #ifdef vms #include "rpc_types.h" #include "rpc_xdr.h" #else #include "time.h" #include #include #endif #ifndef ANSI_LIBS #undef free #undef exit #undef malloc #undef calloc #undef realloc #endif #else typedef char XDR; typedef int bool_t; typedef bool_t (*xdrproc_t)(); #endif /*============================================================================*/ bool_t xdr_real(); bool_t xdr_contr(); bool_t xdr_system(); bool_t xdr_system_2(); bool_t xdr_species(); bool_t xdr_site(); void xdr_set_npotpar(); bool_t xdr_pot(); bool_t xdr_restrt(); bool_t xdr_dump(); void xdr_set_av_size_conv(); bool_t xdr_averages(); #ifndef USE_XDR bool_t xdr_int(); bool_t xdr_bool(); #endif #define XDR_INT_SIZE 4 #define XDR_4PTR_SIZE 4 #define XDR_ULONG_SIZE 4 #define XDR_FLOAT_SIZE 4 #define XDR_DOUBLE_SIZE 8 #define XDR_REAL_SIZE ( (sizeof(real)==sizeof(double))?XDR_DOUBLE_SIZE:XDR_FLOAT_SIZE) #define XDR_RESTRT_SIZE (2*XDR_ULONG_SIZE+(DLEN)+(L_name)+16+XDR_INT_SIZE) #define XDR_DUMP_SIZE ((L_name)+16+6*XDR_INT_SIZE+3*XDR_ULONG_SIZE) $EOD $! $CREATE control.water $DECK # # N.B. This file conians an error but is left for backward compatibility # The tips2.in potentials are in units of kcal/mol so this file should # set time-unit=4.8888213e-14 #Kcal mol-1 amu A # title=Water_test surface-dipole=1 #out-file=out.water.list temperature=300 subcell=2.5 density=1 scale-interval=10 scale-end=500 backup-interval=100 average-interval=1000 sys-spec-file=tips2.in page-length=44 step=0.0005 nsteps=10 print-interval=10 begin-rdf=1000 rdf-interval=0 rdf-out=4000 rdf-limit=10 cutoff=6.25 k-cutoff = 3 alpha = 0.45 dump-file = dump-level=0 ndumps=3 dump-interval=0 begin-dump=10000 restart-file = save-file= rdf-limit=9 end $EOD $! $CREATE control.tip4p $DECK title=Example TIP4P Simulation surface-dipole=1 temperature=300 subcell=2.5 density=1 scale-interval=10 scale-end=500 average-interval=1000 sys-spec-file=tip4p.in page-length=44 step=0.0005 nsteps=10 print-interval=10 dump-level=0 save-file= time-unit=4.8888213e-14 #Kcal mol-1 amu A end $EOD $! $CREATE control.mgclh2o $DECK title=Magnesium Chloride Solution sys-spec-file=mgclh2o.in step=0 nsteps=1 print-interval=1 density=1 cutoff=6.25 k-cutoff = 3 alpha = 0.45 text-mode-save=1 save-file=mdsave.mgclh2o #restart-file=mdsave.water.1 time-unit=4.8888213e-14 end $EOD $! $CREATE control.clay $DECK title = 4 Mg 64 H2O Otay-montmorillonite run 1 nsteps = 01 step = 0.0 text-mode-save = 0 new-sys-spec = 0 surface-dipole = 0 lattice-start = 1 sys-spec-file = restart-file = save-file = strain-mask = 200 const-pressure = 0 reset-averages = 0 scale-end = 10000 begin-average = 10001 average-interval = 20000 begin-dump = 10001 dump-interval = 20 dump-level = 0 ndumps = 250 backup-interval = 500 roll-interval = 100 print-interval = 1 begin-rdf = 40000 rdf-interval = 20 rdf-out = 30000 temperature = 300 pressure = 0 w = 100 cutoff = 12.6 strict-cutoff=0 subcell = 1.8 density = 1 alpha = 0.35 k-cutoff = 2 rdf-limit = 10 cpu-limit = 1e+20 mass-unit = 1.660565e-27 length-unit = 1e-10 time-unit = 1e-12 charge-unit = 4.298401e-22 end water 64 1 0.75695 0 -0.520325 1.0079 267.435 H 1 -0.75695 0 -0.520325 1.0079 267.435 H 2 0 0 0.0655569 15.9994 0 O 3 0 0 -0.202143 0 -534.871 Charge cation 4 4 0 0 0 24.31 745.481 Ni clay 1 framework 5 -7.16606 -9.14 3.28 15.9994 -298.22 O 5 -8.48606 -6.86 3.28 15.9994 -298.22 O 5 -5.84606 -6.86 3.28 15.9994 -298.22 O 6 -9.80606 -9.14 1.06 15.9994 -267.44 O 7 -9.80606 -9.14 2.0176 1.0079 267.44 H 8 -7.16606 -7.62 2.73 28.086 447.33 Si 8 -9.80606 -6.09 2.73 28.086 447.33 Si 9 -8.04606 -9.14 0 0 -372.74 Vacancy 5 -9.80606 -4.57 3.28 15.9994 -298.22 O 5 -5.84606 -2.29 3.28 15.9994 -298.22 O 5 -8.48606 -2.29 3.28 15.9994 -298.22 O 6 -7.16606 -4.57 1.06 15.9994 -267.44 O 7 -7.16606 -4.57 2.0176 1.0079 267.44 H 8 -9.80606 -3.05 2.73 28.086 447.33 Si 8 -7.16606 -1.52 2.73 28.086 447.33 Si 10 -5.40606 -4.57 0 24.305 0 Mg 5 -8.92606 8.88178e-15 -3.28 15.9994 -298.22 O 5 -7.60606 -2.28 -3.28 15.9994 -298.22 O 5 -10.2461 -2.28 -3.28 15.9994 -298.22 O 6 -6.28606 8.88178e-15 -1.06 15.9994 -267.44 O 7 -6.28606 8.88178e-15 -2.0176 1.0079 267.44 H 8 -8.92606 -1.52 -2.73 28.086 447.33 Si 8 -6.28606 -3.05 -2.73 28.086 447.33 Si 5 -6.28606 -4.57 -3.28 15.9994 -298.22 O 5 -10.2461 -6.85 -3.28 15.9994 -298.22 O 5 -7.60606 -6.85 -3.28 15.9994 -298.22 O 6 -8.92606 -4.57 -1.06 15.9994 -267.44 O 7 -8.92606 -4.57 -2.0176 1.0079 267.44 H 8 -6.28606 -6.09 -2.73 28.086 447.33 Si 8 -8.92606 -7.62 -2.73 28.086 447.33 Si 5 -7.16606 8.88178e-15 3.28 15.9994 -298.22 O 5 -8.48606 2.28 3.28 15.9994 -298.22 O 5 -5.84606 2.28 3.28 15.9994 -298.22 O 6 -9.80606 8.88178e-15 1.06 15.9994 -267.44 O 7 -9.80606 8.88178e-15 2.0176 1.0079 267.44 H 8 -7.16606 1.52 2.73 28.086 447.33 Si 8 -9.80606 3.05 2.73 28.086 447.33 Si 9 -8.04606 8.88178e-15 0 0 -372.74 Vacancy 5 -9.80606 4.57 3.28 15.9994 -298.22 O 5 -5.84606 6.85 3.28 15.9994 -298.22 O 5 -8.48606 6.85 3.28 15.9994 -298.22 O 6 -7.16606 4.57 1.06 15.9994 -267.44 O 7 -7.16606 4.57 2.0176 1.0079 267.44 H 8 -9.80606 6.09 2.73 28.086 447.33 Si 8 -7.16606 7.62 2.73 28.086 447.33 Si 10 -5.40606 4.57 0 24.305 0 Mg 5 -8.92606 9.14 -3.28 15.9994 -298.22 O 5 -7.60606 6.86 -3.28 15.9994 -298.22 O 5 -10.2461 6.86 -3.28 15.9994 -298.22 O 6 -6.28606 9.14 -1.06 15.9994 -267.44 O 7 -6.28606 9.14 -2.0176 1.0079 267.44 H 8 -8.92606 7.62 -2.73 28.086 447.33 Si 8 -6.28606 6.09 -2.73 28.086 447.33 Si 5 -6.28606 4.57 -3.28 15.9994 -298.22 O 5 -10.2461 2.29 -3.28 15.9994 -298.22 O 5 -7.60606 2.29 -3.28 15.9994 -298.22 O 6 -8.92606 4.57 -1.06 15.9994 -267.44 O 7 -8.92606 4.57 -2.0176 1.0079 267.44 H 8 -6.28606 3.05 -2.73 28.086 447.33 Si 8 -8.92606 1.52 -2.73 28.086 447.33 Si 5 -1.88606 -9.14 3.28 15.9994 -298.22 O 5 -3.20606 -6.86 3.28 15.9994 -298.22 O 5 -0.566058 -6.86 3.28 15.9994 -298.22 O 6 -4.52606 -9.14 1.06 15.9994 -267.44 O 7 -4.52606 -9.14 2.0176 1.0079 267.44 H 8 -1.88606 -7.62 2.73 28.086 447.33 Si 8 -4.52606 -6.09 2.73 28.086 447.33 Si 9 -2.76606 -9.14 0 0 -372.74 Vacancy 5 -4.52606 -4.57 3.28 15.9994 -298.22 O 5 -0.566058 -2.29 3.28 15.9994 -298.22 O 5 -3.20606 -2.29 3.28 15.9994 -298.22 O 6 -1.88606 -4.57 1.06 15.9994 -267.44 O 7 -1.88606 -4.57 2.0176 1.0079 267.44 H 8 -4.52606 -3.05 2.73 28.086 447.33 Si 8 -1.88606 -1.52 2.73 28.086 447.33 Si 10 -0.126058 -4.57 0 24.305 0 Mg 5 -3.64606 8.88178e-15 -3.28 15.9994 -298.22 O 5 -2.32606 -2.28 -3.28 15.9994 -298.22 O 5 -4.96606 -2.28 -3.28 15.9994 -298.22 O 6 -1.00606 8.88178e-15 -1.06 15.9994 -267.44 O 7 -1.00606 8.88178e-15 -2.0176 1.0079 267.44 H 8 -3.64606 -1.52 -2.73 28.086 447.33 Si 8 -1.00606 -3.05 -2.73 28.086 447.33 Si 5 -1.00606 -4.57 -3.28 15.9994 -298.22 O 5 -4.96606 -6.85 -3.28 15.9994 -298.22 O 5 -2.32606 -6.85 -3.28 15.9994 -298.22 O 6 -3.64606 -4.57 -1.06 15.9994 -267.44 O 7 -3.64606 -4.57 -2.0176 1.0079 267.44 H 8 -1.00606 -6.09 -2.73 28.086 447.33 Si 8 -3.64606 -7.62 -2.73 28.086 447.33 Si 5 -1.88606 8.88178e-15 3.28 15.9994 -298.22 O 5 -3.20606 2.28 3.28 15.9994 -298.22 O 5 -0.566058 2.28 3.28 15.9994 -298.22 O 6 -4.52606 8.88178e-15 1.06 15.9994 -267.44 O 7 -4.52606 8.88178e-15 2.0176 1.0079 267.44 H 8 -1.88606 1.52 2.73 28.086 447.33 Si 8 -4.52606 3.05 2.73 28.086 447.33 Si 9 -2.76606 8.88178e-15 0 0 -372.74 Vacancy 5 -4.52606 4.57 3.28 15.9994 -298.22 O 5 -0.566058 6.85 3.28 15.9994 -298.22 O 5 -3.20606 6.85 3.28 15.9994 -298.22 O 6 -1.88606 4.57 1.06 15.9994 -267.44 O 7 -1.88606 4.57 2.0176 1.0079 267.44 H 8 -4.52606 6.09 2.73 28.086 447.33 Si 8 -1.88606 7.62 2.73 28.086 447.33 Si 10 -0.126058 4.57 0 24.305 0 Mg 5 -3.64606 9.14 -3.28 15.9994 -298.22 O 5 -2.32606 6.86 -3.28 15.9994 -298.22 O 5 -4.96606 6.86 -3.28 15.9994 -298.22 O 6 -1.00606 9.14 -1.06 15.9994 -267.44 O 7 -1.00606 9.14 -2.0176 1.0079 267.44 H 8 -3.64606 7.62 -2.73 28.086 447.33 Si 8 -1.00606 6.09 -2.73 28.086 447.33 Si 5 -1.00606 4.57 -3.28 15.9994 -298.22 O 5 -4.96606 2.29 -3.28 15.9994 -298.22 O 5 -2.32606 2.29 -3.28 15.9994 -298.22 O 6 -3.64606 4.57 -1.06 15.9994 -267.44 O 7 -3.64606 4.57 -2.0176 1.0079 267.44 H 8 -1.00606 3.05 -2.73 28.086 447.33 Si 8 -3.64606 1.52 -2.73 28.086 447.33 Si 5 3.39394 -9.14 3.28 15.9994 -298.22 O 5 2.07394 -6.86 3.28 15.9994 -298.22 O 5 4.71394 -6.86 3.28 15.9994 -298.22 O 6 0.753942 -9.14 1.06 15.9994 -267.44 O 7 0.753942 -9.14 2.0176 1.0079 267.44 H 8 3.39394 -7.62 2.73 28.086 447.33 Si 8 0.753942 -6.09 2.73 28.086 447.33 Si 9 2.51394 -9.14 0 0 -372.74 Vacancy 5 0.753942 -4.57 3.28 15.9994 -298.22 O 5 4.71394 -2.29 3.28 15.9994 -298.22 O 5 2.07394 -2.29 3.28 15.9994 -298.22 O 6 3.39394 -4.57 1.06 15.9994 -267.44 O 7 3.39394 -4.57 2.0176 1.0079 267.44 H 8 0.753942 -3.05 2.73 28.086 447.33 Si 8 3.39394 -1.52 2.73 28.086 447.33 Si 10 5.15394 -4.57 0 24.305 0 Mg 5 1.63394 8.88178e-15 -3.28 15.9994 -298.22 O 5 2.95394 -2.28 -3.28 15.9994 -298.22 O 5 0.313942 -2.28 -3.28 15.9994 -298.22 O 6 4.27394 8.88178e-15 -1.06 15.9994 -267.44 O 7 4.27394 8.88178e-15 -2.0176 1.0079 267.44 H 8 1.63394 -1.52 -2.73 28.086 447.33 Si 8 4.27394 -3.05 -2.73 28.086 447.33 Si 5 4.27394 -4.57 -3.28 15.9994 -298.22 O 5 0.313942 -6.85 -3.28 15.9994 -298.22 O 5 2.95394 -6.85 -3.28 15.9994 -298.22 O 6 1.63394 -4.57 -1.06 15.9994 -267.44 O 7 1.63394 -4.57 -2.0176 1.0079 267.44 H 8 4.27394 -6.09 -2.73 28.086 447.33 Si 8 1.63394 -7.62 -2.73 28.086 447.33 Si 5 3.39394 8.88178e-15 3.28 15.9994 -298.22 O 5 2.07394 2.28 3.28 15.9994 -298.22 O 5 4.71394 2.28 3.28 15.9994 -298.22 O 6 0.753942 8.88178e-15 1.06 15.9994 -267.44 O 7 0.753942 8.88178e-15 2.0176 1.0079 267.44 H 8 3.39394 1.52 2.73 28.086 447.33 Si 8 0.753942 3.05 2.73 28.086 447.33 Si 9 2.51394 8.88178e-15 0 0 -372.74 Vacancy 5 0.753942 4.57 3.28 15.9994 -298.22 O 5 4.71394 6.85 3.28 15.9994 -298.22 O 5 2.07394 6.85 3.28 15.9994 -298.22 O 6 3.39394 4.57 1.06 15.9994 -267.44 O 7 3.39394 4.57 2.0176 1.0079 267.44 H 8 0.753942 6.09 2.73 28.086 447.33 Si 8 3.39394 7.62 2.73 28.086 447.33 Si 10 5.15394 4.57 0 24.305 0 Mg 5 1.63394 9.14 -3.28 15.9994 -298.22 O 5 2.95394 6.86 -3.28 15.9994 -298.22 O 5 0.313942 6.86 -3.28 15.9994 -298.22 O 6 4.27394 9.14 -1.06 15.9994 -267.44 O 7 4.27394 9.14 -2.0176 1.0079 267.44 H 8 1.63394 7.62 -2.73 28.086 447.33 Si 8 4.27394 6.09 -2.73 28.086 447.33 Si 5 4.27394 4.57 -3.28 15.9994 -298.22 O 5 0.313942 2.29 -3.28 15.9994 -298.22 O 5 2.95394 2.29 -3.28 15.9994 -298.22 O 6 1.63394 4.57 -1.06 15.9994 -267.44 O 7 1.63394 4.57 -2.0176 1.0079 267.44 H 8 4.27394 3.05 -2.73 28.086 447.33 Si 8 1.63394 1.52 -2.73 28.086 447.33 Si 5 8.67394 -9.14 3.28 15.9994 -298.22 O 5 7.35394 -6.86 3.28 15.9994 -298.22 O 5 9.99394 -6.86 3.28 15.9994 -298.22 O 6 6.03394 -9.14 1.06 15.9994 -267.44 O 7 6.03394 -9.14 2.0176 1.0079 267.44 H 8 8.67394 -7.62 2.73 28.086 447.33 Si 8 6.03394 -6.09 2.73 28.086 447.33 Si 9 7.79394 -9.14 0 0 -372.74 Vacancy 5 6.03394 -4.57 3.28 15.9994 -298.22 O 5 9.99394 -2.29 3.28 15.9994 -298.22 O 5 7.35394 -2.29 3.28 15.9994 -298.22 O 6 8.67394 -4.57 1.06 15.9994 -267.44 O 7 8.67394 -4.57 2.0176 1.0079 267.44 H 8 6.03394 -3.05 2.73 28.086 447.33 Si 8 8.67394 -1.52 2.73 28.086 447.33 Si 10 10.4339 -4.57 0 24.305 0 Mg 5 6.91394 8.88178e-15 -3.28 15.9994 -298.22 O 5 8.23394 -2.28 -3.28 15.9994 -298.22 O 5 5.59394 -2.28 -3.28 15.9994 -298.22 O 6 9.55394 8.88178e-15 -1.06 15.9994 -267.44 O 7 9.55394 8.88178e-15 -2.0176 1.0079 267.44 H 8 6.91394 -1.52 -2.73 28.086 447.33 Si 8 9.55394 -3.05 -2.73 28.086 447.33 Si 5 9.55394 -4.57 -3.28 15.9994 -298.22 O 5 5.59394 -6.85 -3.28 15.9994 -298.22 O 5 8.23394 -6.85 -3.28 15.9994 -298.22 O 6 6.91394 -4.57 -1.06 15.9994 -267.44 O 7 6.91394 -4.57 -2.0176 1.0079 267.44 H 8 9.55394 -6.09 -2.73 28.086 447.33 Si 8 6.91394 -7.62 -2.73 28.086 447.33 Si 5 8.67394 8.88178e-15 3.28 15.9994 -298.22 O 5 7.35394 2.28 3.28 15.9994 -298.22 O 5 9.99394 2.28 3.28 15.9994 -298.22 O 6 6.03394 8.88178e-15 1.06 15.9994 -267.44 O 7 6.03394 8.88178e-15 2.0176 1.0079 267.44 H 8 8.67394 1.52 2.73 28.086 447.33 Si 8 6.03394 3.05 2.73 28.086 447.33 Si 9 7.79394 8.88178e-15 0 0 -372.74 Vacancy 5 6.03394 4.57 3.28 15.9994 -298.22 O 5 9.99394 6.85 3.28 15.9994 -298.22 O 5 7.35394 6.85 3.28 15.9994 -298.22 O 6 8.67394 4.57 1.06 15.9994 -267.44 O 7 8.67394 4.57 2.0176 1.0079 267.44 H 8 6.03394 6.09 2.73 28.086 447.33 Si 8 8.67394 7.62 2.73 28.086 447.33 Si 10 10.4339 4.57 0 24.305 0 Mg 5 6.91394 9.14 -3.28 15.9994 -298.22 O 5 8.23394 6.86 -3.28 15.9994 -298.22 O 5 5.59394 6.86 -3.28 15.9994 -298.22 O 6 9.55394 9.14 -1.06 15.9994 -267.44 O 7 9.55394 9.14 -2.0176 1.0079 267.44 H 8 6.91394 7.62 -2.73 28.086 447.33 Si 8 9.55394 6.09 -2.73 28.086 447.33 Si 5 9.55394 4.57 -3.28 15.9994 -298.22 O 5 5.59394 2.29 -3.28 15.9994 -298.22 O 5 8.23394 2.29 -3.28 15.9994 -298.22 O 6 6.91394 4.57 -1.06 15.9994 -267.44 O 7 6.91394 4.57 -2.0176 1.0079 267.44 H 8 9.55394 3.05 -2.73 28.086 447.33 Si 8 6.91394 1.52 -2.73 28.086 447.33 Si end mcy potential parameters 1 1 278795 2.76084 0 0 1 2 608950 2.9619 114472 2.23326 1 3 0 0 0 0 1 4 310472 1.6807 0 2 1 5 608950 2.9619 114472 2.23326 1 6 608950 2.9619 114472 2.23326 1 7 278795 2.76084 0 0 1 8 241513 2.15646 894.111 1.21767 1 9 0 0 0 0 1 10 0 0 0 0 2 2 4.55308e+08 5.15271 0 0 2 3 0 0 0 0 2 4 4.92339e+06 2.39325 2.84573e+06 2.10376 2 5 4.55308e+08 5.15271 0 0 2 6 4.55308e+08 5.15271 0 0 2 7 608950 2.9619 114472 2.23326 2 8 5.465e+06 3.20367 563073 2.26705 2 9 0 0 0 0 2 10 0 0 0 0 3 3 0 0 0 0 3 4 0 0 0 0 3 5 0 0 0 0 3 6 0 0 0 0 3 7 0 0 0 0 3 8 0 0 0 0 3 9 0 0 0 0 3 10 0 0 0 0 4 4 0 0 0 0 4 5 4.92339e+06 2.39325 2.84573e+06 2.10376 4 6 4.92339e+06 2.39325 2.84573e+06 2.10376 4 7 310472 1.6807 0 2 4 8 2.90316e+06 2.00923 7.80092e+07 4.8272 4 9 0 0 0 0 4 10 0 0 0 0 5 5 4.55308e+08 5.15271 0 0 5 6 4.55308e+08 5.15271 0 0 5 7 608950 2.9619 114472 2.23326 5 8 5.465e+06 3.20367 563073 2.26705 5 9 0 0 0 0 5 10 0 0 0 0 6 6 4.55308e+08 5.15271 0 0 6 7 608950 2.9619 114472 2.23326 6 8 5.465e+06 3.20367 563073 2.26705 6 9 0 0 0 0 6 10 0 0 0 0 7 7 278795 2.76084 0 0 7 8 241513 2.15646 894.111 1.21767 7 9 0 0 0 0 7 10 0 0 0 0 8 8 0 0 0 0 8 9 0 0 0 0 8 10 0 0 0 0 9 9 0 0 0 0 9 10 0 0 0 0 10 10 0 0 0 0 end 21.12 18.28 14.6846 90 90 90 1 1 1 water 0.759832 0.322085 0.579316 0.553836 -0.245817 -0.695562 -0.38605 water 0.223053 0.4935 0.404179 0.0254173 0.28349 0.232883 -0.929921 water 0.889842 0.86648 0.581554 -0.388827 0.490987 0.754408 0.196502 water 0.745392 0.561496 0.436654 -0.796572 -0.335381 0.349554 -0.361668 water 0.319489 0.758783 0.418008 0.546379 -0.380393 0.25875 0.699871 water 0.624505 0.542736 0.390583 0.330871 0.32724 0.123698 0.876435 water 0.105252 0.216243 0.499404 0.403523 -0.205568 -0.602575 -0.657126 water 0.849922 0.0198829 0.407292 0.67912 0.0729964 -0.479315 0.551113 water 0.844278 0.25793 0.414067 -0.898672 -0.257052 0.0919572 -0.343302 water 0.34612 0.494503 0.418877 -0.750894 0.00243009 0.431425 -0.500024 water 0.488573 0.444088 0.427095 0.644461 -0.177315 -0.149875 0.728537 water 0.988289 0.710787 0.610797 -0.197612 0.847297 -0.477572 -0.12232 water 0.260721 0.111984 0.586134 0.0641008 0.919175 -0.180528 -0.344119 water 0.460344 0.13135 0.42775 -0.802078 -0.253715 -0.539999 -0.0264657 water 0.796052 0.97418 0.583112 0.111393 0.768994 -0.22146 -0.589233 water 0.738605 0.483402 0.612498 -0.126574 -0.631955 0.614351 0.455176 water 0.101785 0.431662 0.409435 0.803029 -0.0827806 0.267762 -0.525924 water 0.388823 0.0879565 0.582199 0.0173793 -0.68974 0.574983 0.439717 water 0.202808 0.939093 0.460056 -0.835197 -0.161335 0.496707 0.172334 water 0.57187 0.248668 0.754676 -0.409311 -0.13072 0.253034 0.866805 water 0.958542 0.466028 0.578196 -0.433213 0.587305 -0.668432 0.143523 water 0.683699 0.416439 0.442454 0.156154 -0.0157807 -0.504856 -0.848815 water 0.156825 0.0157323 0.602513 0.321394 0.23251 -0.858882 0.323987 water 0.107467 0.0319565 0.403613 -0.902008 -0.280924 0.189709 -0.267345 water 0.648611 0.620677 0.55868 0.424098 0.679881 0.528197 -0.280909 water 0.979669 0.764235 0.440702 -0.419644 0.510726 -0.498646 -0.560723 water 0.575486 0.0717962 0.395312 -0.102159 -0.315145 0.33499 -0.882059 water 0.454516 0.620378 0.578225 0.168697 0.601681 -0.779169 0.0491688 water 0.447083 0.976982 0.45556 -0.456518 0.356597 -0.03401 0.814416 water 0.55227 0.0263455 0.567041 -0.0847129 0.833366 0.437724 0.326683 water 0.127496 0.508683 0.594628 -0.0662231 -0.595624 0.60085 -0.528985 water 0.604049 0.480899 0.585807 -0.482056 0.112756 -0.860665 -0.119009 water 0.195631 0.770207 0.451215 -0.941964 -0.0405309 0.32119 0.0888647 water 0.250478 0.435973 0.589574 0.0530178 -0.894343 0.0310409 0.443143 water 0.687891 0.190913 0.402201 0.401279 0.133607 -0.316638 0.849038 water 0.587425 0.330902 0.406204 -0.260244 0.518073 0.349927 0.735816 water 0.668211 0.951081 0.59193 0.160572 -0.967481 -0.124172 0.150927 water 0.213446 0.624263 0.571595 0.391166 0.684839 -0.443336 0.425955 water 0.677464 0.762682 0.440927 0.0390529 0.495236 0.0862708 -0.863582 water 0.338145 0.892386 0.523161 0.346735 -0.611359 0.632383 0.325741 water 0.518301 0.254972 0.550605 -0.0138953 0.640156 0.514757 0.570116 water 0.509235 0.602066 0.406765 -0.62137 -0.158615 -0.765676 0.0498089 water 0.0211412 0.979153 0.543686 0.392641 -0.39296 0.555751 -0.618511 water 0.9645 0.339662 0.452773 -0.72078 -0.126765 0.546836 0.406666 water 0.665761 0.096088 0.5486 -0.511585 -0.550495 0.608281 -0.255403 water 0.0832491 0.877086 0.406179 -0.814705 0.00298576 -0.397789 -0.421913 water 0.210736 0.121134 0.409758 0.201056 0.613347 0.0048254 -0.763779 water 0.33091 0.631779 0.50305 0.0944773 -0.132146 0.986161 0.0331458 water 0.704021 0.998381 0.404576 -0.0615754 -0.377837 0.273204 0.882501 water 0.020632 0.127384 0.571868 -0.55586 -0.210702 -0.802132 0.0566425 water 0.327792 0.252616 0.515905 0.0620516 -0.870431 -0.461407 0.160007 water 0.923759 0.148728 0.445765 -0.28803 -0.292352 0.282701 -0.866977 water 0.134534 0.349143 0.581143 0.406134 -0.605335 0.673065 0.124932 water 0.38132 0.388073 0.564208 0.037677 0.748064 0.317653 -0.581444 water 0.832489 0.241757 0.719359 0.768678 -0.395081 -0.193884 0.464171 water 0.980405 0.546512 0.420296 0.645924 -0.155894 0.648178 0.371947 water 0.851108 0.638525 0.501449 -0.425952 0.244066 0.856044 -0.161818 water 0.497237 0.772974 0.408313 -0.348851 0.062697 0.150953 -0.922814 water 0.0945238 0.633043 0.456066 0.215811 -0.0922409 0.165256 -0.957918 water 0.606612 0.901825 0.427113 0.760682 -0.405813 -0.256159 -0.437106 water 0.772279 0.764202 0.590733 -0.131805 -0.432765 0.779731 -0.432852 water 0.115709 0.843612 0.576826 0.446792 -0.499523 -0.622361 -0.404378 water 0.53523 0.87816 0.602627 0.16992 -0.635633 -0.512522 -0.551742 water 0.232435 0.335546 0.447805 0.352898 -0.586391 0.120519 0.719086 cation 0.679092 0.515941 0.509385 cation 0.629674 0.00628125 0.484204 cation 0.175441 0.433911 0.510471 cation 0.111913 0.946498 0.521342 clay 0.5 0.5 0. 1 0 0 0 end $EOD $! $CREATE control.argon $DECK # # This sets up conditions at the triple point # sys-spec-file=argon.in density=1.428 temperature=84 scale-interval=5 scale-end=2500 nsteps=5000 print-interval=500 roll-interval=500 begin-average=2501 average-interval=2500 step=0.01 subcell=2 strict-cutoff=1 cutoff=8.5125 #2.5 * sigma begin-rdf=2501 rdf-interval=50 rdf-out=2500 $EOD $! $CREATE control.tips2 $DECK title=Example TIPS2 Simulation surface-dipole=1 temperature=300 subcell=2.5 density=1 scale-interval=10 scale-end=500 average-interval=1000 sys-spec-file=tips2.in page-length=44 step=0.0005 nsteps=10 print-interval=10 dump-level=0 save-file= time-unit=4.8888213e-14 #Kcal mol-1 amu A rdf-limit=6 end $EOD $! $CREATE control.quartz $DECK sys-spec-file=quartz-vbst.in time-unit=1.0181e-14 nsteps=10 step=0.001 print-interval=10 scale-interval=1 temperature=300 lattice-start=1 cutoff=8.48 subcell=3 end $EOD $! $CREATE tips2.in $DECK # Modified TIPS2 water Water 64 1 0 0 0 16 0 O 2 0.7569503 0 -0.5858822 1 0.535 H 2 -0.7569503 0 -0.5858822 3 0 0 -0.15 0 -1.07 M end lennard-jones 1 1 0.51799 3.2407 end $EOD $! $CREATE tip4p.in $DECK # TIP4P water in KCal Mol-1 Water 256 1 0 0 0 16 0 O 2 0.7569503 0 -0.5858822 1 0.52 H 2 -0.7569503 0 -0.5858822 3 0 0 -0.15 0 -1.04 M end lennard-jones 1 1 0.6201667 3.1536 end $EOD $! $CREATE mgclh2o.in $DECK # MCY Water/ Mg2+ / Cl - solution Water 200 1 0 0 0 16 0 O 2 0.7569503 0 -0.5858822 1 0.717484 H 2 -0.7569503 0 -0.5858822 3 0 0 -0.2677 0 -1.434968 M Magnesium 4 4 0 0 0 24.31 2 Mg2+ Chloride 8 5 0 0 0 35.45 -1 Cl- end MCY 1 1 1088213.2 5.152712 0 0 1 2 1455.427 2.961895 273.5954 2.233264 2 2 666.3373 2.760844 0 0 1 4 47750.0 3.836 546.3 1.253 # New values of Mg potl 2 4 111.0 1.06 0 1.0 1 5 198855.0 3.910 0 0 2 5 1857.0 2.408 77.94 1.369 4 5 28325.5 2.65 0 0 end $EOD $! $CREATE argon.in $DECK # LJ Argon - about as simple as you can get # Parameters from Allen and Tildesley Table 1.1 Argon 108 1 0 0 0 39.948 0 Ar end Lennard-Jones 1 1 3.984 3.41 $EOD $! $CREATE quartz-vbst.in $DECK # Quartz parameters from Van Beest, Kramer and Van Santen # Physical Review Letters 64,(16) p1955 (1990) # Units are eV, A, el chg. so time-unit=1.0181e-14 Oxygen 384 1 0 0 0 16 -1.2 O Silicon 192 2 0 0 0 28.0855 2.4 Si end buckingham 1 1 175.0000 1388.7730 2.76000 1 2 133.5381 18003.7572 4.87318 2 2 0.0 0.0 0.0 end 4.903 4.903 5.393 90 90 120 4 4 4 Oxygen 0.415000 0.272000 0.120000 Oxygen 0.857000 0.5850000 0.453300 Oxygen 0.728000 0.143000 0.453300 Oxygen 0.143000 0.728000 0.880000 Oxygen 0.272000 0.415000 0.546700 Oxygen 0.5850000 0.857000 0.213300 Silicon 0.465000 0 0 Silicon 0.535000 0.535000 0.333300 Silicon 0 0.465000 0.666700 end $EOD $! $CREATE methane.in $DECK # Deutero-Methane test case Methane 100 1 0 0 0 12 0.0 C 2 0.88181631 0 -0.62353829 2 0.0 H 2 -0.88181631 0 -0.62353829 2 0 0.88181631 0.62353829 2 0 -0.88181631 0.62353829 end buckingham 1 1 2376.5 349908.0 3.60 # William's parameters for carbon 1 2 523.0 36677.0 3.67 2 2 114.2 11104.0 3.74 end $EOD $! $CREATE mcy.in $DECK # MCY Water Water 64 1 0 0 0 16 0 O 2 0.7569503 0 -0.5858822 1 0.717484 H 2 -0.7569503 0 -0.5858822 3 0 0 -0.2677 0 -1.434968 M end MCY 1 1 1088213.2 5.152712 0 1.0 1 2 1455.427 2.961895 273.5954 2.233264 2 2 666.3373 2.760844 0 1.0 end $EOD $! $CREATE water-example.out $DECK *I* control file read in successfully Tue Mar 19 15:15:10 1996 Water_test Page 1 *I* reading system specification file *W* no potential parameters given between sites 1 and 2 *W* no potential parameters given between sites 1 and 3 *W* no potential parameters given between sites 2 and 2 *W* no potential parameters given between sites 2 and 3 *W* no potential parameters given between sites 3 and 3 *I* system specification file successfully read in Tue Mar 19 15:15:10 1996 Water_test Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file tips2.in Water Number of molecules = 64 Number of sites = 4 Mass = 18 amu Electric Charge = 0 Qe Dipole moment = 2.23869 D Moments of inertia = 0.610236 1.75618 1.14595 amuA**2 MD cell vectors a = 12.4137 0 0 A b = 0 12.4137 0 A c = 0 0 12.4137 A Run parameters Final step = 10 Size of step = 0.0005 ps CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 10 End scaling at step = 500 Applied Temperature = 300 K Tue Mar 19 15:15:10 1996 Water_test Page 3 Interaction cut-off = 6.25 A Alpha parameter for Ewald sum = 0.45 A(-1) Reciprocal space cut-off = 3 A(-1) New run entitled "Water_test" started Tue Mar 19 15:15:10 1996 *I* Distant potential correction = -11.021253, Pressure correction = -18.948198 *I* MD cell divided into 125 subcells (5x5x5) *I* Neighbour list contains 82 cells *I* Ewald self-energy = 794.119798 Kj/mol *I* 447 K-vectors included in reciprocal-space sum Tue Mar 19 15:15:11 1996 Water_test Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 10 Current values ================================================================================== 241.85 446.66 -47.024 393.4 303.0 559.6 431.3 12.41 0.00 0.00 -15.9 254 -172 -248.09 0.00 12.41 0.00 254 107 -84.6 0.00 0.00 12.41 -172 -84.6 -33.9 -------- Rolling averages over last 10 timesteps -------------------------------------------------------------------------- 238.28 323.42 35.98 393.33 298.5 405.2 351.9 12.41 0.00 0.00 177 322 -97.7 -204.35 0.00 12.41 0.00 322 305 -41.8 0.00 0.00 12.41 -97.7 -41.8 152 -------- Standard deviations ---------------------------------------------------------------------------------------------- 1.78 64.953 42.932 0.099594 2.2 81.4 41.8 0.00 0.00 0.00 256 124 186 23.783 0.00 0.00 0.00 124 173 70.6 0.00 0.00 0.00 186 70.6 208 *I* Run used 1.08s of CPU time and 1.39s elapsed $EOD $! $CREATE tip4p-example.out $DECK *I* control file read in successfully Tue Mar 19 15:15:39 1996 Example TIP4P Simulation Page 1 *I* reading system specification file *W* no potential parameters given between sites 1 and 2 *W* no potential parameters given between sites 1 and 3 *W* no potential parameters given between sites 2 and 2 *W* no potential parameters given between sites 2 and 3 *W* no potential parameters given between sites 3 and 3 *I* system specification file successfully read in Tue Mar 19 15:15:39 1996 Example TIP4P Simulation Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file tip4p.in Water Number of molecules = 256 Number of sites = 4 Mass = 18 amu Electric Charge = 0 Qe Dipole moment = 2.17592 D Moments of inertia = 0.610236 1.75618 1.14595 amuA**2 MD cell vectors a = 19.7055 0 0 A b = 0 19.7055 0 A c = 0 0 19.7055 A Run parameters Final step = 10 Size of step = 0.0005 ps CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 10 End scaling at step = 500 Applied Temperature = 300 K Tue Mar 19 15:15:39 1996 Example TIP4P Simulation Page 3 Interaction cut-off = 8.93822 A Alpha parameter for Ewald sum = 0.379401 A(-1) Reciprocal space cut-off = 2.57322 A(-1) Radial distribution functions will be calculated Starting at timestep = 1000000 No. steps between binnings = 20 Calculate and print after = 5000 New run entitled "Example TIP4P Simulation" started Tue Mar 19 15:15:39 1996 *I* Distant potential correction = -64.115635, Pressure correction = -27.801126 *I* MD cell divided into 512 subcells (8x8x8) *I* Neighbour list contains 204 cells *I* Ewald self-energy = 1722.888659 Kj/mol *I* 1102 K-vectors included in reciprocal-space sum Tue Mar 19 15:16:01 1996 Example TIP4P Simulation Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 10 Current values ================================================================================== 922.49 1589.3 -1410.9 1079.1 288.9 497.8 393.4 19.71 0.00 0.00 881 -485 -16.1 -21.87 0.00 19.71 0.00 -485 903 110 0.00 0.00 19.71 -16.1 110 -452 -------- Rolling averages over last 10 timesteps -------------------------------------------------------------------------- 913.44 1187.8 -1088.8 1078.8 286.1 372.0 329.1 19.71 0.00 0.00 492 -221 441 66.438 0.00 19.71 0.00 -221 1.18e+03 236 0.00 0.00 19.71 441 236 -364 -------- Standard deviations ---------------------------------------------------------------------------------------------- 4.6929 213.58 171.89 0.60279 1.5 66.9 34.2 0.00 0.00 0.00 1.61e+03 820 1.39e+03 46.168 0.00 0.00 0.00 820 455 317 0.00 0.00 0.00 1.39e+03 317 114 *I* Run used 10.88s of CPU time and 22.93s elapsed $EOD $! $CREATE mgclh2o-example.out $DECK *I* control file read in successfully Tue Mar 19 15:16:27 1996 Magnesium Chloride Solution Page 1 *I* reading system specification file *W* no potential parameters given between sites 1 and 3 *W* no potential parameters given between sites 2 and 3 *W* no potential parameters given between sites 3 and 3 *W* no potential parameters given between sites 3 and 4 *W* no potential parameters given between sites 3 and 5 *W* no potential parameters given between sites 4 and 4 *W* no potential parameters given between sites 5 and 5 *I* system specification file successfully read in Tue Mar 19 15:16:27 1996 Magnesium Chloride Solution Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file mgclh2o.in Water Number of molecules = 200 Number of sites = 4 Mass = 18 amu Electric Charge = 0 Qe Dipole moment = 2.19159 D Moments of inertia = 0.610236 1.75618 1.14595 amuA**2 Magnesium Number of molecules = 4 Number of sites = 1 Mass = 24.31 amu Electric Charge = 2 Qe Magnesium molecule has no rotational degrees of freedom Chloride Number of molecules = 8 Number of sites = 1 Mass = 35.45 amu Electric Charge = -1 Qe Chloride molecule has no rotational degrees of freedom Tue Mar 19 15:16:27 1996 Magnesium Chloride Solution Page 3 MD cell vectors a = 18.7676 0 0 A b = 0 18.7676 0 A c = 0 0 18.7676 A Run parameters Final step = 1 Size of step = 0 ps CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 10 End scaling at step = 1000000 Applied Temperature = 0 K Interaction cut-off = 6.25 A Alpha parameter for Ewald sum = 0.45 A(-1) Reciprocal space cut-off = 3 A(-1) Radial distribution functions will be calculated Starting at timestep = 1000000 No. steps between binnings = 20 Calculate and print after = 5000 New run entitled "Magnesium Chloride Solution" started Tue Mar 19 15:16:27 1996 *I* Distant potential correction = -72.207003, Pressure correction = -18.188941 *I* MD cell divided into 3375 subcells (15x15x15) *I* Neighbour list contains 486 cells *I* Ewald self-energy = 11332.778403 Kj/mol *I* 1484 K-vectors included in reciprocal-space sum Tue Mar 19 15:16:28 1996 Magnesium Chloride Solution Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 1 Current values =================================================================================== 0 0 3209.1 2423.7 0.0 0.0 0.0 18.77 0.00 0.00 3.36e+04 1.68e+04 7.49e+03 0 0 -785.41 0.0 0.0 0.00 18.77 0.00 1.68e+04 5.84e+03 1.19e+03 0 0 0.0 0.0 0.00 0.00 18.77 7.49e+03 1.19e+03 3.65e+03 -------- Rolling averages over last 1 timesteps --------------------------------------------------------------------------- 0 0 3209.1 2423.7 0.0 0.0 0.0 18.77 0.00 0.00 3.36e+04 1.68e+04 7.49e+03 0 0 -785.41 0.0 0.0 0.00 18.77 0.00 1.68e+04 5.84e+03 1.19e+03 0 0 0.0 0.0 0.00 0.00 18.77 7.49e+03 1.19e+03 3.65e+03 -------- Standard deviations ---------------------------------------------------------------------------------------------- 0 0 0 0 0.0 0.0 0.0 0.00 0.00 0.00 0 0 0 0 0 0 0.0 0.0 0.00 0.00 0.00 0 0 0 0 0 0.0 0.0 0.00 0.00 0.00 0 0 0 *I* Run used 0.85s of CPU time and 1.21s elapsed $EOD $! $CREATE clay-example.out $DECK *I* control file read in successfully Tue Mar 19 15:16:43 1996 4 Mg 64 H2O Otay-montmorillonite run 1 Page 1 *I* reading system specification file *I* system specification file successfully read in *I* system successfully initialised from lattice start Tue Mar 19 15:16:43 1996 4 Mg 64 H2O Otay-montmorillonite run 1 Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file water Number of molecules = 64 Number of sites = 4 Mass = 18.0155 amu Electric Charge = -2.68285e-06 Qe Dipole moment = 2.1916 D Moments of inertia = 0.614524 1.76954 1.15502 amuA**2 cation Number of molecules = 4 Number of sites = 1 Mass = 24.3104 amu Electric Charge = 2.00001 Qe cation molecule has no rotational degrees of freedom clay Number of molecules = 1 Number of sites = 240 Mass = 4072.18 amu Electric Charge = -8.00004 Qe Dipole moment = 175.556 D clay molecule has no rotational degrees of freedom Tue Mar 19 15:16:43 1996 4 Mg 64 H2O Otay-montmorillonite run 1 Page 3 MD cell vectors a = 21.12 0 0 A b = 1.11933e-15 18.28 0 A c = 8.99172e-16 8.99172e-16 14.6846 A Run parameters Final step = 1 Size of step = 0 ps CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 10 End scaling at step = 10000 Applied Temperature = 300 K Interaction cut-off = 12.6 A Alpha parameter for Ewald sum = 0.35 A(-1) Reciprocal space cut-off = 2 A(-1) Radial distribution functions will be calculated Starting at timestep = 40000 No. steps between binnings = 20 Calculate and print after = 30000 New run entitled "4 Mg 64 H2O Otay-montmorillonite run 1" started Tue Mar 19 15:16:43 1996 *I* Distant potential correction = -0.006564, Pressure correction = -0.009982 *I* MD cell divided into 960 subcells (12x10x8) *I* Neighbour list contains 1400 cells *I* Framework has net electric charge of -8 - correction of 201.117 kJmol(-1) added to self energy *W* System has net electric charge of -0.00016 - correction of 8.14254e-08 kJmol(-1) added to self energy *I* Ewald self-energy = 4773.730122 Kj/mol *I* 381 K-vectors included in reciprocal-space sum Tue Mar 19 15:16:44 1996 4 Mg 64 H2O Otay-montmorillonite run 1 Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 1 Current values =================================================================================== 162.66 238.47 -5068.5 -9171.2 203.8 298.8 246.5 21.12 0.00 0.00 -11.5 3.53 -895 4.6092 0 -4508.4 92.4 0.0 0.00 18.28 0.00 3.53 39.8 528 0 0 0.0 0.0 0.00 0.00 14.68 -895 528 -38.1 -------- Rolling averages over last 1 timesteps --------------------------------------------------------------------------- 162.66 238.47 -5068.5 -9171.2 203.8 298.8 246.5 21.12 0.00 0.00 -11.5 3.53 -895 4.6092 0 -4508.4 92.4 0.0 0.00 18.28 0.00 3.53 39.8 528 0 0 0.0 0.0 0.00 0.00 14.68 -895 528 -38.1 -------- Standard deviations ---------------------------------------------------------------------------------------------- 0 0 0 0 0.0 0.0 0.0 0.00 0.00 0.00 0 0 0 0 0 0 0.0 0.0 0.00 0.00 0.00 0 0 0 0 0 0.0 0.0 0.00 0.00 0.00 0 0 0 *I* Run used 0.90s of CPU time and 1.70s elapsed $EOD $! $CREATE argon-example.out $DECK *I* control file read in successfully Tue Mar 19 15:26:32 1996 Test Simulation Page 1 *I* reading system specification file *I* system specification file successfully read in Tue Mar 19 15:26:32 1996 Test Simulation Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file argon.in Argon Number of molecules = 108 Number of sites = 1 Mass = 39.948 amu Electric Charge = 0 Qe Argon molecule has no rotational degrees of freedom MD cell vectors a = 17.1191 0 0 A b = 0 17.1191 0 A c = 0 0 17.1191 A Run parameters Final step = 5000 Size of step = 0.01 ps CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 5 End scaling at step = 2500 Applied Temperature = 84 K Interaction cut-off = 8.5125 A Tue Mar 19 15:26:32 1996 Test Simulation Page 3 Alpha parameter for Ewald sum = -1 A(-1) Reciprocal space cut-off = 0 A(-1) Radial distribution functions will be calculated Starting at timestep = 2501 No. steps between binnings = 50 Calculate and print after = 2500 New run entitled "Test Simulation" started Tue Mar 19 15:26:32 1996 *I* Distant potential correction = -49.447049, Pressure correction = -32.664916 *I* MD cell divided into 729 subcells (9x9x9) *I* Neighbour list contains 912 cells Tue Mar 19 15:26:54 1996 Test Simulation Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 500 Current values ================================================================================= 114.61 0 -661.46 -546.85 85.1 0.0 85.1 17.12 0.00 0.00 -11.7 4.62 0.187 0 0.00 17.12 0.00 4.62 6.83 0.59 0.00 0.00 17.12 0.187 0.59 45.5 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 112.62 0 -668.07 -555.46 83.6 0.0 83.6 17.12 0.00 0.00 2.22 -13.6 1.75 0 0.00 17.12 0.00 -13.6 -1.64 -23.1 0.00 0.00 17.12 1.75 -23.1 -10.7 -------- Standard deviations ---------------------------------------------------------------------------------------------- 3.6427 0 11.857 13.496 2.7 0.0 2.7 0.00 0.00 0.00 25.7 14.2 19.1 0 0.00 0.00 0.00 14.2 41.4 22.3 0.00 0.00 0.00 19.1 22.3 34.8 ======== Timestep 1000 Current values ================================================================================ 118.41 0 -665.58 -547.17 87.9 0.0 87.9 17.12 0.00 0.00 12.8 18.8 -8.52 0 0.00 17.12 0.00 18.8 -7.15 0.142 0.00 0.00 17.12 -8.52 0.142 -16 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 113.16 0 -665.22 -552.07 84.0 0.0 84.0 17.12 0.00 0.00 -1.06 1.14 -4.48 0 0.00 17.12 0.00 1.14 7.94 -1.6 0.00 0.00 17.12 -4.48 -1.6 -3.3 -------- Standard deviations ---------------------------------------------------------------------------------------------- 3.1419 0 5.9929 6.0009 2.3 0.0 2.3 0.00 0.00 0.00 21.8 17.2 13.2 0 0.00 0.00 0.00 17.2 19.8 14.6 0.00 0.00 0.00 13.2 14.6 22.2 ======== Timestep 1500 Current values ================================================================================ 113.87 0 -666.44 -552.56 84.5 0.0 84.5 17.12 0.00 0.00 3.59 -9.6 17.7 0 0.00 17.12 0.00 -9.6 -4.45 -27.1 0.00 0.00 17.12 17.7 -27.1 11 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 113.15 0 -668.95 -555.81 84.0 0.0 84.0 17.12 0.00 0.00 4.7 5.03 -3.66 0 0.00 17.12 0.00 5.03 -3.09 5.91 0.00 0.00 17.12 -3.66 5.91 -9.98 -------- Standard deviations ---------------------------------------------------------------------------------------------- 2.5191 0 7.0706 7.0682 1.9 0.0 1.9 0.00 0.00 0.00 26.8 13.3 15.1 0 0.00 0.00 0.00 13.3 20.9 18.7 0.00 0.00 0.00 15.1 18.7 21.9 ======== Timestep 2000 Current values ================================================================================ 118.64 0 -674.94 -556.3 88.1 0.0 88.1 17.12 0.00 0.00 8.68 6.92 4.34 0 0.00 17.12 0.00 6.92 -27.9 -9.61 0.00 0.00 17.12 4.34 -9.61 -9.36 Tue Mar 19 15:28:14 1996 Test Simulation Page 5 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 113.18 0 -665.26 -552.08 84.0 0.0 84.0 17.12 0.00 0.00 2.83 0.862 7.4 0 0.00 17.12 0.00 0.862 8.63 -2.94 0.00 0.00 17.12 7.4 -2.94 0.988 -------- Standard deviations ---------------------------------------------------------------------------------------------- 2.7947 0 7.3998 7.3711 2.1 0.0 2.1 0.00 0.00 0.00 27.9 13.2 13.8 0 0.00 0.00 0.00 13.2 19 10.3 0.00 0.00 0.00 13.8 10.3 21.1 ======== Timestep 2500 Current values ================================================================================ 113.58 0 -663.33 -549.74 84.3 0.0 84.3 17.12 0.00 0.00 18.5 -9.17 2.88 0 0.00 17.12 0.00 -9.17 -14 18.4 0.00 0.00 17.12 2.88 18.4 19.6 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 113.07 0 -665.48 -552.41 83.9 0.0 83.9 17.12 0.00 0.00 2.04 11.1 4.86 0 0.00 17.12 0.00 11.1 -5.15 -7.27 0.00 0.00 17.12 4.86 -7.27 6.31 -------- Standard deviations ---------------------------------------------------------------------------------------------- 2.6673 0 6.8769 6.9119 2.0 0.0 2.0 0.00 0.00 0.00 21.3 12.7 13.4 0 0.00 0.00 0.00 12.7 23.1 14.7 0.00 0.00 0.00 13.4 14.7 21.1 *I* Temperature scaling turned off after step 2500 *I* started accumulating thermodynamic averages on timestep 2501 ======== Timestep 3000 Current values ================================================================================ 121.78 0 -672.13 -550.35 90.4 0.0 90.4 17.12 0.00 0.00 -38.8 8.94 29.9 0 0.00 17.12 0.00 8.94 5.59 -21 0.00 0.00 17.12 29.9 -21 -4.84 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 112.54 0 -662.69 -550.15 83.6 0.0 83.6 17.12 0.00 0.00 14.5 7.33 0.889 0 0.00 17.12 0.00 7.33 0.51 -5.23 0.00 0.00 17.12 0.889 -5.23 2.7 -------- Standard deviations ---------------------------------------------------------------------------------------------- 5.9692 0 5.9969 0.21025 4.4 0.0 4.4 0.00 0.00 0.00 19.9 16.1 14.5 0 0.00 0.00 0.00 16.1 24.1 13.5 0.00 0.00 0.00 14.5 13.5 21 ======== Timestep 3500 Current values ================================================================================ 119.43 0 -668.94 -549.51 88.7 0.0 88.7 17.12 0.00 0.00 10.9 -15.1 -4.8 0 0.00 17.12 0.00 -15.1 8.06 -8.65 0.00 0.00 17.12 -4.8 -8.65 -32.5 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 114.77 0 -664.72 -549.95 85.2 0.0 85.2 17.12 0.00 0.00 0.694 1.24 6.96 0 0.00 17.12 0.00 1.24 5 -3.06 0.00 0.00 17.12 6.96 -3.06 6.35 Tue Mar 19 15:29:29 1996 Test Simulation Page 6 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress -------- Standard deviations ---------------------------------------------------------------------------------------------- 6.464 0 6.547 0.2507 4.8 0.0 4.8 0.00 0.00 0.00 21.7 13.9 15.9 0 0.00 0.00 0.00 13.9 23.5 12.6 0.00 0.00 0.00 15.9 12.6 18.3 ======== Timestep 4000 Current values ================================================================================ 114.04 0 -663.9 -549.86 84.7 0.0 84.7 17.12 0.00 0.00 -10.3 21.2 -3.94 0 0.00 17.12 0.00 21.2 6.79 6.49 0.00 0.00 17.12 -3.94 6.49 13.9 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 114.06 0 -664.2 -550.13 84.7 0.0 84.7 17.12 0.00 0.00 1.02 -9.18 5.13 0 0.00 17.12 0.00 -9.18 7.94 1.31 0.00 0.00 17.12 5.13 1.31 1.2 -------- Standard deviations ---------------------------------------------------------------------------------------------- 5.5247 0 5.5451 0.20845 4.1 0.0 4.1 0.00 0.00 0.00 18.9 13.2 12.3 0 0.00 0.00 0.00 13.2 19.8 15.1 0.00 0.00 0.00 12.3 15.1 20.1 ======== Timestep 4500 Current values ================================================================================ 107.92 0 -657.56 -549.63 80.1 0.0 80.1 17.12 0.00 0.00 27.1 4.43 -8.28 0 0.00 17.12 0.00 4.43 23.1 -10.2 0.00 0.00 17.12 -8.28 -10.2 12.1 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 115.03 0 -665.12 -550.09 85.4 0.0 85.4 17.12 0.00 0.00 7.29 0.831 1.87 0 0.00 17.12 0.00 0.831 -3.7 1.42 0.00 0.00 17.12 1.87 1.42 4.77 -------- Standard deviations ---------------------------------------------------------------------------------------------- 6.0505 0 6.0715 0.26149 4.5 0.0 4.5 0.00 0.00 0.00 17 18.4 14 0 0.00 0.00 0.00 18.4 21.7 13.7 0.00 0.00 0.00 14 13.7 23.1 ======== Timestep 5000 Current values ================================================================================ 123.96 0 -674.22 -550.26 92.0 0.0 92.0 17.12 0.00 0.00 -30.3 10 -31.2 0 0.00 17.12 0.00 10 1.83 -14.1 0.00 0.00 17.12 -31.2 -14.1 -23.5 -------- Rolling averages over last 500 timesteps ------------------------------------------------------------------------- 114.61 0 -664.5 -549.89 85.1 0.0 85.1 17.12 0.00 0.00 16 -3.71 2.72 0 0.00 17.12 0.00 -3.71 -0.173 1.82 0.00 0.00 17.12 2.72 1.82 3.64 -------- Standard deviations ---------------------------------------------------------------------------------------------- 6.1853 0 6.2186 0.28451 4.6 0.0 4.6 0.00 0.00 0.00 20.8 15.5 13.7 0 0.00 0.00 0.00 15.5 23.6 20.6 0.00 0.00 0.00 13.7 20.6 16 Tue Mar 19 15:30:44 1996 Test Simulation Page 7 Averages over last 2500 timesteps Trans KE = 114.2 +/- 6.1113 kJ/mol Rot KE = 0 +/- 0 kJ/mol Pot Energy = -664.25 +/- 6.1411, 0 +/- 0 kJ/mol Tot Energy = -550.04 +/- 0.26601 kJ/mol TTemp = 84.8 +/- 4.5 K RTemp = 0.0 +/- 0.0 K Temp = 84.8 +/- 4.5 K h(1,*) = 17.12 +/- 0.00, 0.00 +/- 0.00, 0.00 +/- 0.00 A h(2,*) = 0.00 +/- 0.00, 17.12 +/- 0.00, 0.00 +/- 0.00 A h(3,*) = 0.00 +/- 0.00, 0.00 +/- 0.00, 17.12 +/- 0.00 A Stress = 7.91 +/- 20.8, -0.698 +/- 16.5, 3.51 +/- 14.3 Mpa Stress = -0.698 +/- 16.5, 1.92 +/- 22.9, -0.748 +/- 15.6 Mpa Stress = 3.51 +/- 14.3, -0.748 +/- 15.6, 3.73 +/- 19.9 Mpa Pressure = 4.52 +/- 11.8 Mpa Virial = -62.481 +/- 39.258 kJ/mol = 2790.5 +/- 672.46, 2707.9 +/- 631.47, 2839.5 +/- 642.43 N**2/mol = 0 +/- 0, 0 +/- 0, 0 +/- 0 (Nm)**2/mol Dip Mom = 0 +/- 0, 0 +/- 0, 0 +/- 0 D ____________________________________________________________________________________________________________________________________ Radial Distribution Functions Bin width=0.1 Ar-Ar RDF 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.008278 0.147756 0.731934 1.679294 2.500705 2.940002 2.935227 2.725624 2.326135 1.956447 1.669340 1.402221 1.194516 1.029435 0.894747 0.791462 0.707519 0.660602 0.602891 0.614683 0.561621 0.578181 0.600775 0.556807 0.596482 0.622303 0.678695 0.729301 0.760295 0.854689 0.872368 0.984521 1.030832 1.104755 1.176589 1.136206 1.212770 1.271280 1.273792 1.294933 1.283603 1.297667 1.270707 1.257051 1.151918 1.100711 1.059952 1.016456 0.996895 0.926224 0.865295 0.848670 0.828072 0.815875 0.811136 0.835673 0.839571 0.832592 0.870152 0.857046 0.880279 0.914954 0.947011 0.998518 1.006689 1.036509 1.066917 1.068506 1.085858 ____________________________________________________________________________________________________________________________________ *I* Run used 175.40s of CPU time and 253.43s elapsed $EOD $! $CREATE tips2-example.out $DECK *I* control file read in successfully Tue Mar 19 15:24:49 1996 Example TIPS2 Simulation Page 1 *I* reading system specification file *W* no potential parameters given between sites 1 and 2 *W* no potential parameters given between sites 1 and 3 *W* no potential parameters given between sites 2 and 2 *W* no potential parameters given between sites 2 and 3 *W* no potential parameters given between sites 3 and 3 *I* system specification file successfully read in Tue Mar 19 15:24:49 1996 Example TIPS2 Simulation Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file tips2.in Water Number of molecules = 64 Number of sites = 4 Mass = 18 amu Electric Charge = 0 Qe Dipole moment = 2.23869 D Moments of inertia = 0.610236 1.75618 1.14595 amuA**2 MD cell vectors a = 12.4137 0 0 A b = 0 12.4137 0 A c = 0 0 12.4137 A Run parameters Final step = 10 Size of step = 0.0005 ps CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 10 End scaling at step = 500 Applied Temperature = 300 K Tue Mar 19 15:24:49 1996 Example TIPS2 Simulation Page 3 Interaction cut-off = 7.09427 A Alpha parameter for Ewald sum = 0.478015 A(-1) Reciprocal space cut-off = 3.24205 A(-1) Radial distribution functions will be calculated Starting at timestep = 1000000 No. steps between binnings = 20 Calculate and print after = 5000 New run entitled "Example TIPS2 Simulation" started Tue Mar 19 15:24:49 1996 *I* Distant potential correction = -31.531180, Pressure correction = -54.492931 *I* MD cell divided into 125 subcells (5x5x5) *I* Neighbour list contains 94 cells *I* Ewald self-energy = 968.356089 Kj/mol *I* 570 K-vectors included in reciprocal-space sum Tue Mar 19 15:24:51 1996 Example TIPS2 Simulation Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 10 Current values ================================================================================== 240.18 447.32 -65.41 325.56 300.9 560.4 430.7 12.41 0.00 0.00 455 437 -144 -296.54 0.00 12.41 0.00 437 654 116 0.00 0.00 12.41 -144 116 1.03e+03 -------- Rolling averages over last 10 timesteps -------------------------------------------------------------------------- 237.63 323.63 11.435 325.49 297.7 405.5 351.6 12.41 0.00 0.00 651 532 -13.7 -247.21 0.00 12.41 0.00 532 864 178 0.00 0.00 12.41 -13.7 178 1.21e+03 -------- Standard deviations ---------------------------------------------------------------------------------------------- 1.2436 65.177 39.65 0.098793 1.6 81.7 41.6 0.00 0.00 0.00 271 202 350 26.75 0.00 0.00 0.00 202 208 125 0.00 0.00 0.00 350 125 214 *I* Run used 1.30s of CPU time and 1.50s elapsed $EOD $! $CREATE quartz-example.out $DECK *I* control file read in successfully Tue Mar 19 15:25:39 1996 Test Simulation Page 1 *I* reading system specification file *I* system specification file successfully read in *I* system successfully initialised from lattice start Tue Mar 19 15:25:39 1996 Test Simulation Page 2 # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Version 2.10 (Exp ) 1996/03/06 18:16:21 Keith Refson Department of Earth Sciences Parks Road, Oxford OX1 3PR keith@earth.ox.ac.uk Moldy Copyright (C) Keith Refson 1988, 1992, 1993 Moldy comes with ABSOLUTELY NO WARRANTY: This is free software and you are welcome to redistribute it under certain conditions. For details see file COPYING included with source. System specification read in from file quartz-vbst.in oxygen Number of molecules = 384 Number of sites = 1 Mass = 16 amu Electric Charge = -1.2 Qe oxygen molecule has no rotational degrees of freedom silicon Number of molecules = 192 Number of sites = 1 Mass = 28.0855 amu Electric Charge = 2.4 Qe silicon molecule has no rotational degrees of freedom MD cell vectors a = 19.612 0 0 A b = -9.806 16.9845 0 A c = 1.3209e-15 2.28787e-15 21.572 A Run parameters Final step = 10 Size of step = 0.001 ps Tue Mar 19 15:25:39 1996 Test Simulation Page 3 CPU limit = 1e+20 s Temperature will be scaled using instantaneous kinetic energy No. steps between scalings = 1 End scaling at step = 1000000 Applied Temperature = 300 K Interaction cut-off = 8.48 A Alpha parameter for Ewald sum = 0.352007 A(-1) Reciprocal space cut-off = 2.38743 A(-1) Radial distribution functions will be calculated Starting at timestep = 1000000 No. steps between binnings = 20 Calculate and print after = 5000 New run entitled "Test Simulation" started Tue Mar 19 15:25:39 1996 *I* Distant potential correction = -2097.957193, Pressure correction = -969.585951 *I* MD cell divided into 1560 subcells (12x10x13) *I* Neighbour list contains 552 cells *I* Ewald self-energy = 457724.399972 Kj/mol *I* 833 K-vectors included in reciprocal-space sum Tue Mar 19 15:25:51 1996 Test Simulation Page 4 Trans KE Rot KE Pot Energy Tot Energy TTemp RTemp Temp h(1,*) h(2,*) h(3,*) Stress Stress Stress ======== Timestep 10 Current values ================================================================================== 4420.6 0 -5.4959e+05 -1.0005e+06 923.0 0.0 733.4 19.61 -9.81 0.00 1.36e+03 -4.15e+03 114 848.2 0 -4.5614e+05 354.2 0.0 0.00 16.98 0.00 -4.15e+03 1.45e+04 -176 0.00 0.00 21.57 114 -176 -7.07e+03 -------- Rolling averages over last 10 timesteps -------------------------------------------------------------------------- 4401.2 0 -5.3414e+05 -9.844e+05 919.0 0.0 749.1 19.61 -9.81 0.00 -480 -2.62e+03 1.95e+03 980.16 0 -4.5565e+05 409.3 0.0 0.00 16.98 0.00 -2.62e+03 1.8e+04 1.27e+03 0.00 0.00 21.57 1.95e+03 1.27e+03 -9.95e+03 -------- Standard deviations ---------------------------------------------------------------------------------------------- 1053.4 0 10253 10141 220.0 0.0 153.2 0.00 0.00 0.00 2.49e+03 2.11e+03 8.08e+03 125.59 0 325.13 52.4 0.0 0.00 0.00 0.00 2.11e+03 2.91e+03 2.76e+03 0.00 0.00 0.00 8.08e+03 2.76e+03 1.08e+04 *I* Run used 5.47s of CPU time and 12.35s elapsed $EOD $! $CREATE moldyext.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #include "defs.h" #include "string.h" #if defined(ANSI) || defined(__STDC__) #include #else #include #endif #include "stdlib.h" #include "stddef.h" #include int getopt(); #define NSIGNAL 8 #define buf_inc 128 #if defined(ANSI) || defined(__STDC__) #undef va_alist #define va_alist char *format, ... #ifdef va_dcl # undef va_dcl #endif #define va_dcl /* */ #endif /*VARARGS*/ void error(va_alist) va_dcl { va_list p; #if defined(ANSI) || defined(__STDC__) va_start(p, format); #else char *format; va_start(p); format = va_arg(p, char *); #endif vfprintf(stderr,format,p); fputc('\n',stderr); va_end(p); exit(3); } static char * mystrdup(s) char *s; { char * t=malloc(strlen(s)+1); return t?strcpy(t,s):0; } /****************************************************************************** * Tokenise(). Parse the string of fields to be returned and return a mask * * in a char array. Format is 1,3,6-9,3 . . . ie comma-separated with cont- * * iguous range specified with hyphen. Numbering starts at 1. * ******************************************************************************/ int tokenise(fields, mask, len) char *fields, *mask; int len; { char *s; int lo, hi, i, n; for(i = 0; i < len; i++) mask[i] = 0; while( ( s = strtok(fields,",") ) != NULL ) { n = sscanf(s, "%d-%d", &lo, &hi); if( n == 0 ) return 0; if( n == 1 ) hi = lo; if( lo < 1 || hi < lo || hi > len) return 0; for( i = lo-1; i < hi; i++) mask[i] = 1; fields = NULL; } return 1; } /****************************************************************************** * read_record(). Read one 'record' of Moldy output into buffer. A record * * starts on the line following 8 '=' characters and enbtd either at the first* * line containing 8 '-' chars or a linefeed. It takes a char* pointer to a * * malloc'ed buffer area, and realloc's this if it needs more space. * *****************************************************************************/ char *read_record() { static char *buf = NULL; static int buf_len = 132; int c, nsymb, buf_cnt; if( buf == 0) { if( ( buf = malloc(buf_len) ) == 0) error("Memory allocation fails: %d bytes requested", buf_len); } nsymb = 0; /* * Read input, discarding up to and including next 8 contiguous '=' */ while( nsymb < NSIGNAL && ( c = getchar()) != EOF) { if( c == '=' ) nsymb++; else nsymb = 0; } /* * Read up to and including next newline */ while( (c = getchar()) != EOF && c != '\n' ) ; /* Empty loop body */ /* * Now read input into buffer, extending it if necessary. * Read up to (and including) next 8 '-' or formfeed */ buf_cnt = 0; nsymb = 0; while( nsymb < NSIGNAL && (c = getchar()) != EOF && c != '\f' ) { if( buf_cnt >= buf_len ) /* Buffer too small */ { buf_len += buf_inc; /* Make it bigger */ if( ( buf = realloc(buf, buf_len) ) == 0) error("Memory allocation fails: %d bytes requested", buf_len); } buf[buf_cnt++] = c; if( c == '-' ) nsymb++; else nsymb = 0; } buf_cnt -= nsymb; /* Don't return trailing '-' */ buf[buf_cnt] = '\0'; /* Terminate string */ return( buf ); } /****************************************************************************** * main program * ******************************************************************************/ #define MAX_FIELDS 256 int main(argc, argv) int argc; char *argv[]; { char *buf, *fields; char mask[MAX_FIELDS]; char sfield[64]; int field, cnt, end, inc; extern char *optarg; extern int optind; if( getopt(argc, argv, "f:") == -1) fields = "1-256"; else fields = optarg; if( tokenise(mystrdup(fields), mask, MAX_FIELDS) == 0 ) error("Invalid field specification \"%s\": usage eg 1,3,5-9,4",fields); #ifdef DEBUG { int i; for(i = 0; i < MAX_FIELDS; i++) if(mask[i]) putchar('1'); else putchar('0'); putchar('\n'); } #endif while(optind < argc) { if(strcmp(argv[optind],"-") && freopen(argv[optind], "r", stdin) == NULL) error("Failed to open file \"%s\" for reading\n", argv[optind]); optind++; while( ! feof( stdin) ) { buf = read_record(); end = strlen(buf); cnt = 0; field = 0; while( cnt < end ) { if(sscanf(buf+cnt, "%63s%n", sfield, &inc) != EOF) { if(mask[field]) { putchar('\t'); fputs(sfield,stdout); } cnt += inc; field++; } else cnt = end; /* Flag exit from inner loop */ } if( field > 0 ) putchar('\n'); } } return 0; } $EOD $! $CREATE dumpanal.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/dumpanal.c,v 2.7 1994/06/08 13:12:11 keith stab $"; #endif /* * $Log: dumpanal.c,v $ * Revision 2.7 1994/06/08 13:12:11 keith * Declared xdr_dump(). * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Revision 2.5 94/01/26 11:55:39 keith * Tidied up lint/gcc warnings. * Fixed def'n of main to "int" coz it failed on broken (?) VMS compiler. * * Revision 2.4 94/01/18 13:23:12 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.3 93/10/14 18:18:36 keith * Fixed prortability problems to IBM RS6000 * * Revision 2.2 93/09/06 14:42:41 keith * Fixed portability problems/bugs in XDR code. * * Revision 2.1 93/08/18 20:52:07 keith * Added support for dumps in XDR format. * * Revision 2.0 93/03/15 14:49:43 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.3 93/03/09 15:59:49 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.2 89/05/15 16:51:27 keith * Modified to work with structs.h 1.3 or later * * Revision 1.1 89/04/11 15:04:51 keith * Initial revision * */ #include "defs.h" #include #include "string.h" #include "structs.h" #include "time.h" #ifdef USE_XDR #include "xdr.h" #endif #ifdef USE_XDR bool_t xdr_dump(); #endif /****************************************************************************** * strstr replacement for pre-ANSI machines which don't have it. * ******************************************************************************/ #ifndef ANSI_LIBS char *strstr(cs, ct) char *cs, *ct; { char *end = cs+strlen(cs)-strlen(ct); for(; cs <= end; cs++) if( !strcmp(cs,ct) ) return cs; return 0; } #endif char *ctime(); void analyze(); void print_header(); int main(argc, argv) int argc; char *argv[]; { int i; for(i = 1; i < argc; i++) analyze(argv[i]); return 0; } void analyze(file) char *file; { FILE *f; dump_mt header; int errflg = 0, xdr = 0; #ifdef USE_XDR XDR xdrs; #endif if( (f = fopen(file,"rb")) != NULL ) { printf("\n***** %s *****\n",file); #ifdef USE_XDR /* * Attempt to read dump header in XDR format */ xdrstdio_create(&xdrs, f, XDR_DECODE); if( xdr_dump(&xdrs, &header) ) { header.vsn[sizeof header.vsn - 1] = '\0'; if( strstr(header.vsn,"(XDR)") ) { errflg = 0; xdr = 1; } } else errflg = 1; #endif /* * If we failed, try to read header as native struct image. */ if( ! xdr ) { if( fseek(f, 0L, 0) == 0 && fread((char*)&header, sizeof(dump_mt), 1, f) == 1) errflg = 0; } if( errflg == 0) print_header(&header); else printf("Failed to read anything from %s",file); #ifdef USE_XDR if( xdr ) xdr_destroy(&xdrs); #endif (void)fclose(f); } } void print_header(header) dump_mt *header; { printf("Title\t\t\t= \"%s\"\n",header->title); printf("RCS Revision\t\t= %.*s\n", (int)strlen(header->vsn)-1, header->vsn); printf("Istep\t\t\t= %d\n",header->istep); printf("Dump_interval\t\t= %d\n", header->dump_interval); printf("Dump_level\t\t= %d\n", header->dump_level); printf("Max dumps\t\t= %d\n", header->maxdumps); printf("Dump Size\t\t= %d\n", header->dump_size); printf("Number of dumps\t\t= %d\n", header->ndumps); printf("Timestamp\t\t= %s", ctime((time_t*)&header->timestamp)); printf("Restart Timestamp\t= %s", ctime((time_t*)&header->restart_timestamp)); printf("Dump Start\t\t= %s", ctime((time_t*)&header->dump_init)); } $EOD $! $CREATE dumpconv.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/dumpconv.c,v 2.8 1995/12/05 20:55:10 keith Exp $"; #endif /* * $Log: dumpconv.c,v $ * Revision 2.8 1995/12/05 20:55:10 keith * Separated ANSI replacement routines from Auxil.c into Ansi.c * Removed all COS functionality. * * Revision 2.7 1994/06/08 13:12:34 keith * Changed "%g" scan format to "%f" - should be identical but * some systems, particularly VAX/VMS didn't grok "%g". * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Revision 2.5 94/01/21 12:51:04 keith * Corrected declaration of main() * * Revision 2.4 94/01/21 12:35:03 keith * Incorporated all portability experience to multiple platforms since 2.2. * Rewrote varargs functions to use stdargs conditionally on __STDC__ * * Revision 2.5 1994/01/18 16:26:29 keith * Incorporated all portability experience to multiple platforms since 2.2. * Rewrote varargs functions to use stdargs conditionally on __STDC__ * * Revision 2.5 94/01/18 13:13:09 keith * Incorporated all portability experience to multiple platforms since 2.2. * Rewrote varargs functions to use stdargs conditionally on __STDC__ * * Revision 2.4 93/12/21 18:49:40 keith * Portability improvements: * 1. Moved malloc etc declarations into header files * 2. Rewrote varargs functions to use stdargs conditionally on __STDC__ * * Revision 2.3 93/10/28 10:28:50 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.2 93/09/06 14:42:43 keith * Fixed portability problems/bugs in XDR code. * * Revision 2.1 93/08/18 20:52:05 keith * Added support for dumps in XDR format. * * Revision 2.0 93/03/15 14:49:44 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.5 93/03/09 15:59:51 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.4 91/08/15 18:13:10 keith * * * Revision 1.3 90/09/28 10:51:27 keith * Amended #idfefs for unicos * * Revision 1.2 89/09/07 18:15:54 keith * checked in with -k by keith at 89.09.08.15.48.37. * * Revision 1.2 89/09/07 18:15:54 keith * Rationalised command-line parameters. Now takes option '-d', + two * file names for input and output. A file name of '-' means use stdin/out * as does an absent name. * This should work better on non-unix machines. * * Revision 1.1 89/06/27 12:10:34 keith * Initial revision * */ #include "defs.h" #include "stdlib.h" #include "stddef.h" #include "structs.h" #include "string.h" #if defined(ANSI) || defined(__STDC__) #include #else #include #endif #include #ifdef USE_XDR #include "xdr.h" XDR xdrsr; XDR xdrsw; bool_t xdr_dump(); #endif /****************************************************************************** * strstr replacement for pre-ANSI machines which don't have it. * ******************************************************************************/ #ifndef ANSI_LIBS char *strstr(cs, ct) char *cs, *ct; { char *end = cs+strlen(cs)-strlen(ct); for(; cs <= end; cs++) if( !strcmp(cs,ct) ) return cs; return 0; } #endif #if defined(ANSI) || defined(__STDC__) #undef va_alist #define va_alist char *format, ... #define va_dcl /* */ #endif /*VARARGS*/ void error(va_alist) va_dcl { va_list p; #if defined(ANSI) || defined(__STDC__) va_start(p, format); #else char *format; va_start(p); format = va_arg(p, char *); #endif vfprintf(stderr,format,p); fputc('\n',stderr); va_end(p); exit(3); } void read_text(buf,buflen) float *buf; int buflen; { int i; for( i = 0; i < buflen; i++ ) scanf("%f", &buf[i]); if( ferror(stdin) ) error("Read error on input file (Error code %d).",ferror(stdin)); } void write_text(buf,buflen) float *buf; int buflen; { int i; for( i = 0; i < buflen; i++ ) printf("%.7g%c",buf[i],(i+1) % 5 ? ' ' : '\n'); if( i % 5 ) fputc('\n', stdout); if( ferror(stdout) ) error("Write error on output file (Error code %d).",ferror(stdout)); } void read_binary(buf,buflen,xdr) float *buf; int buflen, xdr; { #ifdef USE_XDR if( xdr ) { xdr_vector(&xdrsr, (char*)buf, buflen, XDR_FLOAT_SIZE, xdr_float); } else #endif { fread(buf , sizeof(float), buflen, stdin); } if( ferror(stdin) ) error("Read error on input file (Error code %d).",ferror(stdin)); } void write_native(buf, buflen) float *buf; int buflen; { fwrite(buf , sizeof(float), buflen, stdout); if( ferror(stdout) ) error("Write error on output file (Error code %d).",ferror(stdout)); } #ifdef USE_XDR void write_xdr(buf, buflen) float *buf; int buflen; { xdr_vector(&xdrsw, (char*)buf, buflen, XDR_FLOAT_SIZE, xdr_float); if( ferror(stdout) ) error("Write error on output file (Error code %d).",ferror(stdout)); } #endif void read_bin_hdr(header, xdrw) dump_mt *header; int *xdrw; { int xdr = 0, errflg = 0; #ifdef USE_XDR /* * Attempt to read dump header in XDR format */ xdrstdio_create(&xdrsr, stdin, XDR_DECODE); if( xdr_dump(&xdrsr, header) ) { header->vsn[sizeof header->vsn - 1] = '\0'; if( strstr(header->vsn,"(XDR)") ) { errflg = 0; xdr = 1; } } else errflg = 1; #endif /* * If we failed, try to read header as native struct image. */ if( ! xdr ) { if( fseek(stdin, 0L, 0) == 0 && fread((char*)header, sizeof(dump_mt), 1, stdin) == 1) errflg = 0; } if( errflg || ferror(stdin) || feof(stdin) ) { error("Failed to read header record (Error code %d).",ferror(stdin)); exit(2); } *xdrw = xdr; } int read_header(header) dump_mt *header; { int num; char *c; fgets(header->title, sizeof header->title, stdin); if((c = strchr(header->title, '\n'))) *c = '\0'; fgets(header->vsn, sizeof header->vsn, stdin); if((c = strchr(header->vsn, '\n'))) *c = '\0'; num = 2; num += scanf("%d %d %d %d %d", &header->istep, &header->dump_interval, &header->dump_level, &header->maxdumps, &header->ndumps); num += scanf("%ld %ld %ld %d",&header->timestamp, &header->restart_timestamp, &header->dump_init, &header->dump_size); if( num == 11 ) return 0; else return -1; } void write_native_hdr(header) dump_mt *header; { char *s; if( (s = strstr(header->vsn,"(XDR)") ) != 0 ) *s = 0; if( ! fwrite((char*)header, sizeof(dump_mt), 1, stdout) ) error("Write error on output file (Error code %d).",ferror(stdout)); } #ifdef USE_XDR void write_xdr_hdr(header) dump_mt *header; { strncat(header->vsn,"(XDR)",sizeof header->vsn); xdrstdio_create(&xdrsw, stdout, XDR_ENCODE); if( ! xdr_dump(&xdrsw, header) ) error("Write error on output file (Error code %d).",ferror(stdout)); } #endif void print_header(header) dump_mt *header; { char *s; if( (s = strstr(header->vsn,"(XDR)") ) != 0 ) *s = 0; printf("%s\n%s\n",header->title, header->vsn); printf("%d %d %d %d %d\n", header->istep, header->dump_interval, header->dump_level, header->maxdumps, header->ndumps); printf("%ld %ld %ld %d\n",header->timestamp, header->restart_timestamp, header->dump_init, header->dump_size); } int main(argc, argv) int argc; char *argv[]; { static char *ity[2] = {"rb","r"}, *oty[2] = {"w","wb"}; dump_mt header; float *buf; int idump; int textin = 0, xdrin, xdrout = 0; while( argc > 0 && argv[1][0] == '-' ) { switch( argv[1][1] ) { case 'd': textin++; break; case 'x': xdrout++; break; default: fprintf(stderr,"Usage: dumpconvert [-d] [-x] infile outfile\n"); exit(2); } argc--; argv++; } if( argc > 0 ) { if( strcmp(argv[1],"-") && freopen(argv[1], ity[textin], stdin) == NULL ) error("Failed to open file \"%s\" for input", argv[1]); } if( argc > 1 ) { if( strcmp(argv[2],"-") && freopen(argv[2], oty[textin], stdout) == NULL ) error("Failed to open file \"%s\" for writing", argv[2]); } if( textin ) { read_header(&header); #ifdef USE_XDR if( xdrout ) write_xdr_hdr(&header); else #endif write_native_hdr(&header); } else { read_bin_hdr(&header, &xdrin); #ifdef USE_XDR if( xdrout ) write_xdr_hdr(&header); else #endif print_header(&header); } if( ! (buf = (float *)calloc(header.dump_size, sizeof(float)))) error("Failed to allocate memory (%d words requested)\n", header.dump_size); for( idump = 0; idump < header.ndumps; idump++) { if( textin ) { read_text(buf, header.dump_size); #ifdef USE_XDR if( xdrout ) write_xdr(buf, header.dump_size); else #endif write_native(buf, header.dump_size); } else { read_binary(buf, header.dump_size, xdrin); #ifdef USE_XDR if( xdrout ) write_xdr(buf, header.dump_size); else #endif write_text(buf, header.dump_size); } } return 0; } $EOD $! $CREATE dumpext.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #include "defs.h" #include "stdlib.h" #include "stddef.h" #include "string.h" #include #include "structs.h" #ifdef USE_XDR # include "xdr.h" #endif int getopt(); static char * mystrdup(s) char *s; { char * t=malloc(strlen(s)+1); return t?strcpy(t,s):0; } /****************************************************************************** * strstr replacement for pre-ANSI machines which don't have it. * ******************************************************************************/ #ifndef ANSI_LIBS char *strstr(cs, ct) char *cs, *ct; { char *end = cs+strlen(cs)-strlen(ct); for(; cs <= end; cs++) if( !strcmp(cs,ct) ) return cs; return 0; } #endif int av_convert; #undef MIN #define MIN(x,y) ( (x) > (y) ? (y) : (x)) /*========================== Macros ==========================================*/ #define DUMP_SIZE(level, n, n_r) \ (( (level & 1) + (level>>1 & 1) + (level>>2 & 1) ) * \ (3*n + 4*n_r + 9)+ \ (level>>3 & 1) * \ (3*n + 3*n_r + 9) +\ (level & 1)) /*============================================================================*/ typedef struct list_mt { struct list_mt *next; int i; char *p; int num; } list_mt; typedef struct cpt_mt { int ncpt, offset, size, mols; char name[32]; } cpt_mt; /****************************************************************************** * get_int(). Read an integer from stdin, issuing a prompt and checking * * validity and range. Loop until satisfied, returning EOF if appropriate. * ******************************************************************************/ int get_int(prompt, lo, hi) char *prompt; int lo, hi; { char ans_str[80]; int ans_i, ans_flag; ans_flag = 0; while( ! feof(stdin) && ! ans_flag ) { fputs(prompt, stderr); fflush(stderr); fgets(ans_str, sizeof ans_str, stdin); if( sscanf(ans_str, "%d", &ans_i) == 1 && ans_i >= lo && ans_i <= hi) ans_flag++; } if( feof(stdin) ) { fprintf(stderr,"\nExit requested\n"); exit(3); } if( ans_flag ) return(ans_i); else return(EOF); } /****************************************************************************** * List manipulation procedures * ******************************************************************************/ void insert(entry, head) list_mt *entry, *head; { while( head->next != NULL && entry->i > head->next->i) head = head->next; entry->next = head->next; head->next = entry; } void print_list(head) list_mt *head; { if(head == NULL) return; fprintf(stderr,"%-8d%s\n",head->i, head->p); print_list(head->next); } /****************************************************************************** * forstr. Parse string str of format s-f:n (final 2 parts optional), * * returning integer values of s,f,n. f defaults to s and n to 1 * ******************************************************************************/ int forstr(str, start, finish, inc) char *str; int *start, *finish, *inc; { char *p, *pp; if( (p = strchr(str,':')) != NULL) { *inc = strtol(p+1, &pp, 0); if( pp == p+1 ) goto limerr; *p = 0; } else *inc = 1; if( (p = strchr(str,'-')) != NULL) { *p = 0; *start = strtol(str, &pp, 0); if( pp == str ) goto limerr; *finish = strtol(p+1, &pp, 0); if( pp == p+1 ) goto limerr; } else { *start = *finish = strtol(str, &pp, 0); if( pp == str ) goto limerr; } return 0; limerr: return -1; } /****************************************************************************** * Put. Write data in text or binary form. * ******************************************************************************/ void put(buf, n, bflg) float *buf; int n; int bflg; { #ifdef DEBUG2 fprintf(stderr,"Put: %d at %8x (%s)\n", n, buf, bflg? "binary":"text"); #endif if( bflg ) fwrite((char*)buf, sizeof(float), n, stdout); else while(n-- > 0) fprintf(stdout,"%7g ",*buf++); } /****************************************************************************** * Extract. Process one dump file, extracting and outputting data. * ******************************************************************************/ void extract(dump_name, cpt_mask, molecules, cpt, ncpt, tslice, num, inc, bflg, nmols, xdr) char *dump_name; int cpt_mask; list_mt *molecules; cpt_mt cpt[]; int ncpt, tslice, num, inc; int bflg, nmols, xdr; { FILE *dump_file; dump_mt header; float *buf = (float*)calloc(4*nmols,sizeof(float));/* nmols > nmols_r */ long dump_base; int icpt, start, nitems; list_mt *mol; int errflg = 0; #ifdef USE_XDR XDR xdrs; #endif if( (dump_file = fopen(dump_name, "rb")) == NULL) { fprintf(stderr, "Failed to open dump file \"%s\"\n", dump_name); exit(2); } #ifdef DEBUG fprintf(stderr,"Working on file \"%s\" (%d-%d)\n", dump_name, tslice, num); #endif #ifdef USE_XDR /* * Attempt to read dump header in XDR format */ if( xdr ) { xdrstdio_create(&xdrs, dump_file, XDR_DECODE); errflg = ! xdr_dump(&xdrs, &header); } else #endif { if( fread((char*)&header, sizeof(dump_mt), 1, dump_file) == 0 ) errflg = false; } if( errflg || ferror(dump_file) || feof(dump_file) ) { fprintf(stderr, "Failed to read dump header \"%s\"\n", dump_name); exit(2); } #ifdef USE_XDR if( xdr ) dump_base = XDR_DUMP_SIZE+tslice*header.dump_size*XDR_FLOAT_SIZE; else #endif dump_base = sizeof(dump_mt)+tslice*header.dump_size*sizeof(float); while(tslice < num && tslice < header.ndumps) { #ifdef DEBUG fprintf(stderr,"Timeslice %d of %d\n", tslice, num); #endif for( icpt = 0; icpt < ncpt; icpt++) { if( cpt_mask & (1 << icpt) ) { #ifdef USE_XDR if( xdr ) { xdr_setpos(&xdrs, dump_base+cpt[icpt].offset*XDR_FLOAT_SIZE); xdr_vector(&xdrs, (char*)buf, (u_int)cpt[icpt].size, XDR_FLOAT_SIZE, xdr_float); } else #endif { fseek(dump_file, dump_base+cpt[icpt].offset*sizeof(float), 0); fread((char*)buf, sizeof(float), cpt[icpt].size, dump_file); } if( cpt[icpt].mols ) for(mol = molecules; mol != 0; mol = mol->next) { start = mol->i * cpt[icpt].ncpt; nitems = mol->num * cpt[icpt].ncpt; if( start+nitems > cpt[icpt].size ) nitems = cpt[icpt].size - start; put(buf+start, nitems, bflg); } else put(buf, cpt[icpt].size, bflg); } } if( ! bflg ) putchar('\n'); tslice += inc; #ifdef USE_XDR if( xdr ) dump_base += inc*XDR_FLOAT_SIZE * header.dump_size; else #endif dump_base += inc*sizeof(float) * header.dump_size; } #ifdef USE_XDR if( xdr ) xdr_destroy(&xdrs); #endif (void)fclose(dump_file); (void)free((char*)buf); } int main(argc, argv) int argc; char *argv[]; { int c; extern int optind; extern char *optarg; int errflg = 0, genflg = 0, tsflg = 0, bflg = 0; int nmols=0, nmols_r=0; int xcpt= -1; char *dump_name=0, *dump_base=0, *out_name=0; char cur_dump[256]; char *tsrange; FILE *dump_file; int nfiles = 0; int start,finish,inc; int tslice, numslice, maxslice; int offset, icpt; int idump0; int xdr = 0; #ifdef USE_XDR XDR xdrs; #endif static cpt_mt cpt[] = {{3, 0, 3, 1, "C of M positions"}, {4, 0, 4, 1, "quaternions"}, {9, 0, 1, 0, "unit cell matrix"}, {1, 0, 1, 0, "potential energy"}, {3, 0, 3, 1, "C of M velocities"}, {4, 0, 4, 1, "quaternion derivatives"}, {9, 0, 1, 0, "unit cell velocities"}, {3, 0, 3, 1, "C of M accelerations"}, {4, 0, 4, 1, "quaternion accelerations"}, {9, 0, 1, 0, "unit cell accelerations"}, {3, 0, 3, 1, "C of M forces"}, {3, 0, 3, 1, "torques"}, {9, 0, 1, 0, "stress tensor"} }; #define NCPT (sizeof(cpt)/sizeof(cpt_mt)) static int level_mask[16] = { 0x0000,0x000f,0x0070,0x007f, 0x0380,0x038f,0x03f0,0x03ff, 0x1c00,0x1c0f,0x1c70,0x1c7f, 0x1f80,0x1f8f,0x1ff0,0x1fff}; dump_mt proto_header, header; list_mt f_head; list_mt mol_head; list_mt *cur; mol_head.next = NULL; f_head.next = NULL; while( (c = getopt(argc, argv, "c:br:R:q:Q:t:m:o:") ) != EOF ) switch(c) { case 'c': xcpt = strtol(optarg,(char**)0,0); break; case 'b': bflg++; break; case 'r': case 'R': nmols = strtol(optarg,(char**)0,0); break; case 'q': case 'Q': nmols_r = strtol(optarg,(char**)0,0); break; case 'o': out_name = optarg; break; case 't': if( tsflg++ == 0) tsrange = optarg; else errflg++; break; case 'm': if( forstr(optarg, &start, &finish, &inc) ) errflg++; else { cur = (list_mt *)calloc(1, sizeof(list_mt)); cur->i = start; cur->num=finish-start+1; insert(cur, &mol_head); } break; case '?': case 'h': errflg++; } if(optind >= argc) { fprintf(stderr,"%s: no dump files given\n",argv[0]); errflg++; } if( errflg ) { fprintf(stderr, "Usage: dumpext [-Rn] [-Qn] [-b] [-c cpt]\ [-t timeslices] [-m molecules] [-o output-file] dumpfiles\n"); exit(2); } /* * Interactive input of parameters not supplied as argument */ if( ! nmols ) nmols = get_int("Number of molecules? ",1,1000000); if( ! nmols_r ) nmols_r = get_int("Number of polyatomic molecules? ",0,1000000); if( xcpt < 0 ) { fprintf(stderr,"Which quantity do you require?\n"); fprintf(stderr,"\t%-32s %d\n","All data components",0); for(icpt = 0; icpt < NCPT; icpt++) fprintf(stderr,"\t%-32s %d\n",cpt[icpt].name,icpt+1); xcpt=get_int("Quantity index (0-13)? ",0,NCPT); } /* * Molecule mask */ if(mol_head.next == 0) { cur = (list_mt*)calloc(1,sizeof(list_mt)); cur->i = 0; cur->num = nmols; mol_head.next = cur; } /* * Generate list of dump files if required */ if( strchr(argv[optind],'%') ) { genflg++; #define MAXTRY 500 dump_base = argv[optind]; idump0 = -1; do /* Search for a dump file matching pattern */ sprintf(cur_dump, dump_base, ++idump0); while( (dump_file = fopen(cur_dump, "rb")) == NULL && idump0 < MAXTRY); if( dump_file == NULL ) /* If we didn't find one . . */ { fprintf(stderr,"I can't find any dump files to match \"%s\".\n",dump_base); exit(2); } (void)fclose(dump_file); } else idump0 = optind; /* * Check all dump files for correctness and build ordered list */ while(1) { if( genflg ) { sprintf(cur_dump, dump_base, idump0++); dump_name = cur_dump; } else { dump_name = argv[idump0++]; if( dump_name == 0 ) break; } if( (dump_file = fopen(dump_name, "rb")) == NULL) { if( genflg ) break; /* Exit loop if at end of sequence */ fprintf(stderr, "Failed to open dump file \"%s\"\n", dump_name); exit(2); } #ifdef USE_XDR /* * Attempt to read dump header in XDR format */ xdrstdio_create(&xdrs, dump_file, XDR_DECODE); if( xdr_dump(&xdrs, &header) ) { header.vsn[sizeof header.vsn - 1] = '\0'; if( strstr(header.vsn,"(XDR)") ) { errflg = 0; xdr = 1; } } else errflg = 1; #endif /* * If we failed, try to read header as native struct image. */ if( ! xdr ) { if( fseek(dump_file, 0L, 0) == 0 && fread((char*)&header, sizeof(dump_mt), 1, dump_file) == 1) errflg = 0; } if( errflg || ferror(dump_file) || feof(dump_file) ) { fprintf(stderr, "Failed to read dump header \"%s\"\n", dump_name); exit(2); } if( nfiles++ == 0 ) proto_header = header; else if( strncmp(header.title, proto_header.title, L_name) || strncmp(header.vsn, proto_header.vsn, sizeof header.vsn) || header.dump_interval != proto_header.dump_interval || header.dump_level != proto_header.dump_level || header.dump_size != proto_header.dump_size || header.dump_init != proto_header.dump_init ) { fprintf(stderr,"Dump headers don't match: file\"%s\"\n", dump_name); exit(2); }; #ifdef USE_XDR if( xdr ) xdr_destroy(&xdrs); #endif (void)fclose(dump_file); cur = (list_mt *)calloc(1, sizeof(list_mt)); cur->p = mystrdup(dump_name); cur->i = header.istep/header.dump_interval; cur->num = header.ndumps; insert(cur, &f_head); #ifdef DEBUG fprintf(stderr,"File \"%s\" \nslice %5d length %5d\n", dump_name, cur->i, cur->num); #endif } if( xcpt > 0 && ! (1 << (xcpt-1) & level_mask[proto_header.dump_level]) ) { fprintf(stderr,"Sorry the component requested (%s)",cpt[xcpt-1].name); fprintf(stderr," is not contained in a dump of level %d\n", header.dump_level); exit(2); } tslice = start = f_head.next->i; for(cur = f_head.next; cur; cur = cur->next) { if( cur->i != tslice ) { fprintf(stderr,"Dump file \"%s\" out of sequence at slice %d\n", cur->p, tslice); exit(2); } cur->i -= start; tslice += cur->num; #ifdef DEBUG fprintf(stderr,"File \"%s\" \nslice %5d length %5d\n", cur->p, cur->i, cur->num); #endif } maxslice = tslice - start; if(DUMP_SIZE(header.dump_level, nmols,nmols_r) != proto_header.dump_size) { fprintf(stderr, "Number of molecules (%d/%d) ",nmols,nmols_r); fprintf(stderr, "incompatible with dump size (%d) and level(%d)\n", proto_header.dump_size, proto_header.dump_level); exit(2); } /* * Set up timestep mask */ if( ! tsflg ) { numslice = maxslice; tslice = 0; inc = 1; } else if( forstr(tsrange, &tslice, &numslice, &inc) ) { fprintf(stderr,"Incorrect time slice selection \"%s\"\n", tsrange); exit(2); } else { numslice += 1; if(tslice < 0 || numslice > maxslice) { fprintf(stderr, "Error in dump sequence - step %d not found\n", numslice); exit(2); } } /* * Set up component size and offsets */ #ifdef DEBUG fprintf(stderr,"Size Offset\n"); #endif offset=0; cpt[0].size = cpt[4].size = cpt[7].size = cpt[10].size = nmols; cpt[1].size = cpt[5].size = cpt[8].size = cpt[11].size = nmols_r; for(icpt = 0; icpt < NCPT; icpt++) { cpt[icpt].size *= cpt[icpt].ncpt; cpt[icpt].offset = offset; if( (1<next) { if( cur->i <= tslice && tslice < MIN(cur->i + cur->num, numslice) ) { extract(cur->p, xcpt?1<<(xcpt-1):~0, mol_head.next, cpt, NCPT, tslice-cur->i, MIN(cur->num,numslice-cur->i), inc, bflg, nmols, xdr); tslice += (cur->i + cur->num - tslice - 1) / inc * inc + inc; } } return 0; } $EOD $! $CREATE manalyze.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/manalyze.c,v 2.8 1996/11/05 09:53:50 keith Exp $"; #endif /* * $Log: manalyze.c,v $ * Revision 2.8 1996/11/05 09:53:50 keith * Fixed bug which reported last record twice. * Now prints offsets too for ease of debugging. * * Revision 2.7 1994/06/08 13:22:31 keith * Null update for version compatibility * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Revision 2.5 1994/01/26 11:57:07 keith * Tidied up lint/gcc warnings. * Fixed def'n of main to "int" coz it failed on broken (?) VMS compiler. * Rewrote varargs functions to use stdargs conditionally on __STDC__ * * Revision 2.5 1994/01/21 12:46:01 keith * Lint/gcc -Wall tidying * * Revision 2.4 94/01/18 13:23:14 keith * Incorporated all portability experience to multiple platforms since 2.2. * Including ports to VAX/VMS and Open VMS on Alpha AXP and Solaris. * * Revision 2.3 93/10/28 10:28:54 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.0 93/03/15 14:49:46 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.5 93/03/09 15:59:54 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.4 91/08/15 18:13:13 keith * * * Revision 1.3 91/03/07 18:10:59 keith * Changed message * * Revision 1.2 90/04/25 14:47:28 keith * Declared malloc(). * * Revision 1.1 90/02/22 17:46:11 keith * Initial revision * */ #include "defs.h" #include "stddef.h" #include "structs.h" #include "stdlib.h" #include char *ctime(); int main(argc, argv) int argc; char *argv[]; { FILE *f = stdin; restrt_mt restart_header; unsigned size, offset; char *ptr; int n, rec = 1; if(argc > 1) { f = fopen(argv[1],"r"); if(f == NULL) { fprintf(stderr,"Couldn't open restart file \"%s\"\n",argv[1]); exit(1); } } (void)fread((gptr*)&size, sizeof size, 1, f); if(size != sizeof restart_header) { fprintf(stderr,"This isn't a Moldy restart file\n"); exit(1); } fread(&restart_header, size, 1,f); offset = sizeof size; printf("Restart file was written at %s", ctime(&restart_header.timestamp)); printf("This is restart No %d of run \"%s\" started %s\n", restart_header.seq, restart_header.title, restart_header.init_date); printf("It was written by version %s of write_restart\n",restart_header.vsn); printf("\n\tHeader record\t%d\tbytes %9X %9X\n",size, offset, size); offset += sizeof restart_header + sizeof size; do { n = fread((gptr*)&size, sizeof size, 1, f); if( n < 1 ) break; printf("\tRecord %d \t%d\tbytes %9X %9X\n",rec++,size, offset, size); offset += size + sizeof size; ptr = malloc(size); fread(ptr,size,1,f); free(ptr); } while(!feof(f)); return 0; } $EOD $! $CREATE mdshak.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/mdshak.c,v 2.10 1996/09/26 14:39:36 keith Exp $"; #endif #include "defs.h" #if defined(ANSI) || defined(__STDC__) #include #else #include #endif #include #include #include "stdlib.h" #include "stddef.h" #include "string.h" #include #include "structs.h" #include "messages.h" #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ #else gptr *arralloc(); /* Array allocator */ #endif void invert(); void mat_vec_mul(); void make_sites(); char *strlower(); void read_sysdef(); void initialise_sysdef(); void re_re_header(); void re_re_sysdef(); void allocate_dynamics(); void lattice_start(); void read_restart(); void init_averages(); int getopt(); gptr *talloc(); FILE *popen(); /*======================== Global vars =======================================*/ int ithread=0, nthreads=1; static char *comm; contr_mt control; #define OUTBIN 2 #define SHAK 0 #define XYZ 1 /****************************************************************************** * Dummies of 'moldy' routines so that mdshak may be linked with moldy library* ******************************************************************************/ void init_rdf() {} gptr *rdf_ptr() {return 0;} void new_lins() {} int lines_left() {return 0;} void new_page() {} void new_line() { (void)putchar('\n'); } void banner_page() {} void note() {} void conv_potentials() {} void conv_control() {} /****************************************************************************** * message. Deliver error message to possibly exiting. It can be called * * BEFORE output file is opened, in which case outt to stderr. * ******************************************************************************/ #if defined(ANSI) || defined(__STDC__) # undef va_alist # define va_alist int *nerrs, ... # ifdef va_dcl # undef va_dcl # endif # define va_dcl /* */ #endif /*VARARGS*/ void message(va_alist) va_dcl { va_list ap; char *buff; int sev; char *format; static char *sev_txt[] = {" *I* "," *W* "," *E* "," *F* "}; #if defined(ANSI) || defined(__STDC__) va_start(ap, nerrs); #else int *nerrs; va_start(ap); nerrs = va_arg(ap, int *); #endif buff = va_arg(ap, char *); sev = va_arg(ap, int); format= va_arg(ap, char *); (void)fprintf(stderr, "%s: ",comm); (void)vfprintf(stderr, format, ap); va_end(ap); fputc('\n',stderr); if(buff != NULL) /* null ptr means don't print buffer */ { (void)fprintf(stderr," buffer contents=\"%s\"",buff); fputc('\n',stderr); } if(sev >= ERROR && nerrs != NULL) (*nerrs)++; if(sev == FATAL) exit(3); } /****************************************************************************** * message. Deliver error message to possibly exiting. * ******************************************************************************/ #if defined(ANSI) || defined(__STDC__) #undef va_alist #define va_alist char *format, ... #ifdef va_dcl # undef va_dcl #endif #define va_dcl /* */ #endif /*VARARGS*/ void error(va_alist) va_dcl { va_list ap; #if defined(ANSI) || defined(__STDC__) va_start(ap, format); #else char *format; va_start(ap); format= va_arg(ap, char *); #endif (void)fprintf(stderr, "%s: ",comm); (void)vfprintf(stderr, format, ap); fputc('\n',stderr); va_end(ap); exit(3); } static char * mystrdup(s) char *s; { char * t=malloc(strlen(s)+1); return t?strcpy(t,s):0; } /****************************************************************************** * get_int(). Read an integer from stdin, issuing a prompt and checking * * validity and range. Loop until satisfied, returning EOF if appropriate. * ******************************************************************************/ int get_int(prompt, lo, hi) char *prompt; int lo, hi; { char ans_str[80]; int ans_i, ans_flag; ans_flag = 0; while( ! feof(stdin) && ! ans_flag ) { fputs(prompt, stderr); fflush(stderr); fgets(ans_str, sizeof ans_str, stdin); if( sscanf(ans_str, "%d", &ans_i) == 1 && ans_i >= lo && ans_i <= hi) ans_flag++; } if( ans_flag ) return(ans_i); else return(EOF); } /****************************************************************************** * get_sym(). Read a character from stdin and match to suplied set * ******************************************************************************/ int get_sym(prompt, cset) char *prompt; char *cset; { char ans_c, ans_str[80]; int ans_flag; ans_flag = 0; while( ! feof(stdin) && ! ans_flag ) { fputs(prompt, stderr); fflush(stderr); fgets(ans_str, sizeof ans_str, stdin); if( sscanf(ans_str, " %c", &ans_c) == 1 && strchr(cset, ans_c)) ans_flag++; } if( ans_flag ) return(ans_c); else return(EOF); } /****************************************************************************** * get_str(). Read an string from stdin, issuing a prompt. * ******************************************************************************/ char *get_str(prompt) char *prompt; { char ans_str[80]; char *str = malloc(80); int ans_flag; ans_flag = 0; while( ! feof(stdin) && ! ans_flag ) { fputs(prompt, stderr); fflush(stderr); fgets(ans_str, sizeof ans_str, stdin); if( sscanf(ans_str, "%s", str) == 1) ans_flag++; } if( ans_flag ) return(str); else return(NULL); } /****************************************************************************** ******************************************************************************/ /****************************************************************************** * forstr. Parse string str of format s-f:n (final 2 parts optional), * * returning integer values of s,f,n. f defaults to s and n to 1 * ******************************************************************************/ int forstr(instr, start, finish, inc) char *instr; int *start, *finish, *inc; { char *p, *pp, *str = mystrdup(instr); long strtol(); if( (p = strchr(str,':')) != NULL) { *inc = strtol(p+1, &pp, 0); if( pp == p+1 ) goto limerr; *p = 0; } else *inc = 1; if( (p = strchr(str,'-')) != NULL) { *p = 0; *start = strtol(str, &pp, 0); if( pp == str ) goto limerr; *finish = strtol(p+1, &pp, 0); if( pp == p+1 ) goto limerr; } else { *start = *finish = strtol(str, &pp, 0); if( pp == str ) goto limerr; } return 0; limerr: return -1; } /****************************************************************************** * dump_to_moldy. Fill the 'system' arrays with the dump data in 'buf' (see * * dump.c for format), expanding floats to doubles if necessary. * ******************************************************************************/ #define DUMP_SIZE(level) (( (level & 1) + (level>>1 & 1) + (level>>2 & 1) ) * \ (3*sys.nmols + 4*sys.nmols_r + 9)+ \ (level>>3 & 1) * \ (3*sys.nmols + 3*sys.nmols_r + 9) +\ (level & 1)) void dump_to_moldy(buf, system) float *buf; system_mt *system; { int i; float *c_of_m = buf; float *quat = buf+3*system->nmols; float *h = buf+3*system->nmols + 4*system->nmols_r; mat_mt hinv; /* $dir no_recurrence */ for(i = 0; i < system->nmols; i++) { system->c_of_m[i][0] = c_of_m[3*i]; system->c_of_m[i][1] = c_of_m[3*i+1]; system->c_of_m[i][2] = c_of_m[3*i+2]; } /* $dir no_recurrence */ for(i = 0; i < system->nmols_r; i++) { system->quat[i][0] = quat[4*i]; system->quat[i][1] = quat[4*i+1]; system->quat[i][2] = quat[4*i+2]; system->quat[i][3] = quat[4*i+3]; } /* $dir no_recurrence */ for(i = 0; i < 3; i++) { system->h[i][0] = h[3*i]; system->h[i][1] = h[3*i+1]; system->h[i][2] = h[3*i+2]; } invert(system->h, hinv); mat_vec_mul(hinv, system->c_of_m, system->c_of_m, system->nmols); } /****************************************************************************** ******************************************************************************/ void mat_vec_mul3(m, vec, number) int number; /* Number of vectors to be multiplied */ real m[3][3]; /* Matrix */ real **vec; /* Output vector. CAN BE SAME AS INPUT (out)*/ { int i; register double a0, a1, a2; for(i = 0; i < number; i++) { a0 = vec[0][i]; a1 = vec[1][i]; a2 = vec[2][i]; vec[0][i] = m[0][0]*a0 + m[0][1]*a1 + m[0][2]*a2; vec[1][i] = m[1][0]*a0 + m[1][1]*a1 + m[1][2]*a2; vec[2][i] = m[2][0]*a0 + m[2][1]*a1 + m[2][2]*a2; } } /****************************************************************************** * shakal_out(). Write a system configuration to stdout in the form of an * * input data file for the graphics program SCHAKAL88. * ******************************************************************************/ void schakal_out(n, system, species, site_info, insert) int n; system_mt *system; spec_mt species[]; site_mt site_info[]; char *insert; { double **site = (double**)arralloc(sizeof(double),2, 0,2,0,system->nsites-1); spec_mt *spec; double a, b, c, alpha, beta, gamma; mat_mp h = system->h; mat_mt hinv; int imol, isite, is; invert(h,hinv); a = sqrt(SQR(h[0][0]) + SQR(h[1][0]) + SQR(h[2][0])); b = sqrt(SQR(h[0][1]) + SQR(h[1][1]) + SQR(h[2][1])); c = sqrt(SQR(h[0][2]) + SQR(h[1][2]) + SQR(h[2][2])); alpha = 180/PI*acos((h[0][1]*h[0][2]+h[1][1]*h[1][2]+h[2][1]*h[2][2])/b/c); beta = 180/PI*acos((h[0][0]*h[0][2]+h[1][0]*h[1][2]+h[2][0]*h[2][2])/a/c); gamma = 180/PI*acos((h[0][0]*h[0][1]+h[1][0]*h[1][1]+h[2][0]*h[2][1])/a/b); printf("CELL %f %f %f %f %f %f\n", a, b, c, alpha, beta, gamma); for(spec = species; spec < species+system->nspecies; spec++) { make_sites(system->h, spec->c_of_m, spec->quat, spec->p_f_sites, spec->framework, site, spec->nmols, spec->nsites); mat_vec_mul3(hinv, site, spec->nsites*spec->nmols); isite = 0; for(imol = 0; imol < spec->nmols; imol++) { puts("MOL"); for(is = 0; is < spec->nsites; is++) { if(fabs(site_info[spec->site_id[is]].mass) != 0) (void)printf("ATOM %-8s %7.4f %7.4f %7.4f\n", site_info[spec->site_id[is]].name, site[0][isite], site[1][isite], site[2][isite]); isite++; } } } if( insert != NULL) (void)printf("%s\n", insert); (void)printf("END %d\n", n); if( ferror(stdout) ) error("Error writing output - \n%s\n", strerror(errno)); } /****************************************************************************** * xyz_out(). Write a system configuration to stdout in the form of an * * input data file for the graphics program XYZ (rasmol -xyz file) * ******************************************************************************/ void xyz_out(n, system, species, site_info, insert) int n; system_mt *system; spec_mt species[]; site_mt site_info[]; char *insert; { double **site = (double**)arralloc(sizeof(double),2, 0,2,0,system->nsites-1); spec_mt *spec; double a, b, c, alpha, beta, gamma; mat_mp h = system->h; mat_mt hinv; int imol, isite, is; /* We count the number of atoms */ isite=0; for(spec = species; spec < species+system->nspecies; spec++) { for(imol = 0; imol < spec->nmols; imol++) { for(is = 0; is < spec->nsites; is++) { if(fabs(site_info[spec->site_id[is]].mass) != 0) isite++; } } } /* Now we write the Xyz header */ (void)printf("%d\n",isite); /* It would be nice to have here the real title */ (void)printf("%s\n",control.title); for(spec = species; spec < species+system->nspecies; spec++) { make_sites(system->h, spec->c_of_m, spec->quat, spec->p_f_sites, spec->framework, site, spec->nmols, spec->nsites); isite = 0; for(imol = 0; imol < spec->nmols; imol++) { for(is = 0; is < spec->nsites; is++) { if(fabs(site_info[spec->site_id[is]].mass) != 0) (void)printf("%-8s %7.4f %7.4f %7.4f\n", site_info[spec->site_id[is]].name, site[0][isite], site[1][isite], site[2][isite]); isite++; } } } if( insert != NULL) (void)printf("%s\n", insert); if( ferror(stdout) ) error("Error writing output - \n%s\n", strerror(errno)); } /****************************************************************************** * atoms_out(). Write a system configuration to stdout in the form of an * * binary atomic co-ordinates. * ******************************************************************************/ void atoms_out(n, system, species, site_info, atom_sel) int n; system_mt *system; spec_mt species[]; site_mt site_info[]; char *atom_sel; { double **site = (double**)arralloc(sizeof(double),2, 0,2,0,system->nsites-1); spec_mt *spec; float fsite[3]; mat_mp h = system->h; mat_mt hinv; int imol, isite, is,i; invert(h,hinv); for(spec = species; spec < species+system->nspecies; spec++) { make_sites(system->h, spec->c_of_m, spec->quat, spec->p_f_sites, spec->framework, site, spec->nmols, spec->nsites); mat_vec_mul3(hinv, site, spec->nsites*spec->nmols); isite = 0; for(imol = 0; imol < spec->nmols; imol++) { for(is = 0; is < spec->nsites; is++) { for(i=0; i<3; i++) fsite[i]=site[i][isite]; fwrite((char*)fsite, sizeof fsite, 1, stdout); isite++; } } } if( ferror(stdout) ) error("Error writing output - \n%s\n", strerror(errno)); } /****************************************************************************** * Centre_mass. Shift system centre of mass to origin (in discrete steps), * ******************************************************************************/ void centre_mass(species, nspecies, c_of_m) spec_mt species[]; int nspecies; vec_mt c_of_m; { double mass; spec_mt *spec; int imol; vec_mt *s_c_of_m; mass = c_of_m[0] = c_of_m[1] = c_of_m[2] = 0.0; for(spec = species; spec < species + nspecies; spec++ ) { s_c_of_m = spec->c_of_m; for(imol = 0; imol < spec->nmols; imol++) { c_of_m[0] += spec->mass*s_c_of_m[imol][0]; c_of_m[1] += spec->mass*s_c_of_m[imol][1]; c_of_m[2] += spec->mass*s_c_of_m[imol][2]; } mass += spec->nmols*spec->mass; } c_of_m[0] /= mass; c_of_m[1] /= mass; c_of_m[2] /= mass; c_of_m[0] = floor(c_of_m[0]+0.5); c_of_m[1] = floor(c_of_m[1]+0.5); c_of_m[2] = floor(c_of_m[2]+0.5); } /****************************************************************************** * Shift. Translate all co-ordinates. * ******************************************************************************/ void shift(r, nmols, s) vec_mt r[]; int nmols; vec_mt s; { int imol; for(imol = 0; imol < nmols; imol++) { r[imol][0] -= s[0]; r[imol][1] -= s[1]; r[imol][2] -= s[2]; } } /****************************************************************************** * moldy_out. Select output routine and handle file open/close * * Translate system relative to either centre of mass of posn of framework. * ******************************************************************************/ void moldy_out(n, system, species, site_info, atom_sel, outsw, insert) int n; system_mt *system; spec_mt species[]; site_mt site_info[]; char *atom_sel; int outsw; char *insert; { spec_mp spec, frame_spec = NULL; vec_mt c_of_m; for(spec = species; spec < species+system->nspecies; spec++) if( spec->framework ) frame_spec = spec; if( frame_spec != NULL ) shift(system->c_of_m, system->nmols, frame_spec->c_of_m[0]); else { centre_mass(species, system->nspecies, c_of_m); shift(system->c_of_m, system->nmols, c_of_m); } switch (outsw) { case SHAK: schakal_out(n, system, species, site_info, insert); break; case XYZ: xyz_out(n, system, species, site_info, insert); break; case OUTBIN: atoms_out(n, system, species, site_info, atom_sel); break; } } /****************************************************************************** * main(). Driver program for generating SCHAKAL input files from MOLDY * * files. Acceptable inputs are sys-spec files, or restart files. Actual * * configrational info can be read from dump files, lattice-start files or * * restart files. Call: mdshak [-s sys-spec-file] [-r restart-file]. If * * neither specified on command line, user is interrogated. * ******************************************************************************/ int main(argc, argv) int argc; char *argv[]; { int c, cflg = 0, ans_i, sym, data_source = 0; char line[80]; extern char *optarg; int errflg = 0; int intyp = 0; int start, finish, inc; int rflag; int irec; int iout = 0; int outsw=0; char *filename = NULL, *dump_name = NULL; char *dumplims = NULL, *atom_sel = NULL; char *insert = NULL; char *tempname; char dumpcommand[256]; int dump_size; float *dump_buf; FILE *Fp, *Dp; restrt_mt restart_header; system_mt sys; spec_mt *species; site_mt *site_info; pot_mt *potpar; quat_mt *qpf; int av_convert; #define MAXTRY 100 control.page_length=1000000; comm = argv[0]; if( strstr(comm, "mdshak") ) outsw = SHAK; else if (strstr(comm, "mdxyz") ) outsw = XYZ; else outsw = OUTBIN; while( (c = getopt(argc, argv, "a:bo:cr:s:d:t:i:xh") ) != EOF ) switch(c) { case 'a': atom_sel = optarg; break; case 'b': outsw=OUTBIN; break; case 'o': if( freopen(optarg, "w", stdout) == NULL ) error("failed to open file \"%s\" for output", optarg); break; case 'c': cflg++; break; case 'r': case 's': if( intyp ) errflg++; intyp = data_source = c; filename = optarg; break; case 'd': dump_name = optarg; break; case 't': dumplims = optarg; break; case 'i': insert = optarg; break; case 'x': outsw = XYZ; break; case 'h': outsw = SHAK; break; default: case '?': errflg++; } if( errflg ) { fprintf(stderr, "Usage: %s [-x] [-h] [-c] [-s sys-spec-file] [-r restart-file] ", comm); fputs("[-d dump-files] [-t s[-f[:n]]] [-o output-file]\n", stderr); exit(2); } if( dump_name ) data_source = 'd'; if(intyp == 0) { fputs("How do you want to specify the simulated system?\n", stderr); fputs("Do you want to use a system specification file (1)", stderr); fputs(" or a restart file (2)\n", stderr); if( (ans_i = get_int("? ", 1, 2)) == EOF ) exit(2); intyp = ans_i-1 ? 'r': 's'; if( intyp == 's' ) { fputs( "Do you need to skip 'control' information?\n", stderr); if( (sym = get_sym("y or n? ","yYnN")) == 'y' || sym == 'Y') cflg++; } if( (filename = get_str("File name? ")) == NULL ) exit(2); } switch(intyp) { case 's': if( (Fp = fopen(filename,"r")) == NULL) error("Couldn't open sys-spec file \"%s\" for reading", filename); if( cflg ) { do { fscanf(Fp, "%s",line); (void)strlower(line); } while(! feof(stdin) && strcmp(line,"end")); } read_sysdef(Fp, &sys, &species, &site_info, &potpar); qpf = qalloc(sys.nspecies); initialise_sysdef(&sys, species, site_info, qpf); break; case 'r': if( (Fp = fopen(filename,"rb")) == NULL) error("Couldn't open restart file \"%s\" for reading -\n%s\n", filename, strerror(errno)); re_re_header(Fp, &restart_header, &control); control.rdf_interval = 0; /* Don't attempt to read RDF data */ re_re_sysdef(Fp, restart_header.vsn, &sys, &species, &site_info, &potpar); break; default: error("Internal error - invalid input type", ""); } allocate_dynamics(&sys, species); if( data_source == 0 ) /* If called interactively */ { fputs( "Where is the configurational information kept?\n", stderr); if( intyp == 's' ) { fputs( "In a lattice start file(1) or a dump dataset(2)?\n", stderr); if( (ans_i = get_int("? ", 1, 2)) == EOF) exit(2); data_source = ans_i-1 ? 'd' : 's'; } else if( intyp == 'r' ) { fputs( "In a restart file(1) or a dump dataset(2)?\n", stderr); if( (ans_i = get_int("? ", 1, 2)) == EOF) exit(2); data_source = ans_i-1 ? 'd' : 'r'; } } switch(data_source) /* To read configurational data */ { case 's': /* Lattice_start file */ lattice_start(Fp, &sys, species, qpf); moldy_out(1, &sys, species, site_info, atom_sel, outsw, insert); break; case 'r': /* Restart file */ init_averages(sys.nspecies, restart_header.vsn, control.roll_interval, control.roll_interval, &av_convert); read_restart(Fp, restart_header.vsn, &sys, av_convert); moldy_out(1, &sys, species, site_info, atom_sel, outsw, insert); break; case 'd': /* Dump dataset */ if( dump_name == 0 ) { fputs("Enter canonical name of dump files (as in control)\n",stderr); if( (dump_name = get_str("Dumps? ")) == NULL) exit(2); } /* * Ensure that the dump limits start, finish, inc are set up, * either on command line or by user interaction. */ do { rflag = 0; if( dumplims == NULL ) { fputs("Please specify range of dump records in form", stderr); fputs(" in form start-finish:increment\n", stderr); dumplims = get_str("s-f:n? "); } if( forstr(dumplims, &start, &finish, &inc) ) { rflag++; fputs("Invalid range for dump records \"", stderr); fputs(dumplims, stderr); fputs("\"\n", stderr); } if( start > finish || start < 0 || inc <= 0 ) { rflag++; fputs("Dump record limits must satisfy", stderr); fputs(" finish >= start, start >= 0 and increment > 0\n", stderr); } if( rflag) { (void)free(dumplims); dumplims = NULL; } } while(rflag); /* * Allocate buffer for data */ dump_size = DUMP_SIZE(~0)*sizeof(float); if( (dump_buf = (float*)malloc(dump_size)) == 0) error("malloc failed to allocate dump record buffer (%d bytes)", dump_size); /* * Loop over dump records, ascertaining which file they are in * and opening it if necessary. Call output routine. */ #if defined (unix) || defined (__unix__) sprintf(dumpcommand,"dumpext -R%d -Q%d -b -c 0 -t %s %s", sys.nmols,sys.nmols_r, dumplims, dump_name); if( (Dp = popen(dumpcommand,"r")) == 0) error("Failed to execute \'dumpext\" command - \n%s", strerror(errno)); #else tempname = tmpnam((char*)0); sprintf(dumpcommand,"dumpext -R%d -Q%d -b -c 0 -t %s -o %s %s", sys.nmols,sys.nmols_r, dumplims, tempname, dump_name); system(dumpcommand); if( (Dp = fopen(tempname,"rb")) == 0) error("Failed to open \"%s\"",tempname); #endif for(irec = start; irec <= finish; irec+=inc) { if( fread(dump_buf, dump_size, 1, Dp) < 1 || ferror(Dp) ) error("Error reading record %d in dump file - \n%s\n", irec, strerror(errno)); dump_to_moldy(dump_buf, &sys); moldy_out(iout++, &sys, species, site_info, atom_sel, outsw, insert); #ifdef DEBUG fprintf(stderr,"Sucessfully read dump record %d from file \"%s\"\n", irec%header.maxdumps, dump_name); #endif } #if defined (unix) || defined (__unix__) pclose(Dp); #else fclose(Dp); remove(tempname); #endif break; default: break; } return 0; } $EOD $! $CREATE ewald_parallel.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Ewald The reciprocal-space part of the standard Ewald sum technique * ****************************************************************************** * Revision Log * $Log: ewald_parallel.c,v $ * Revision 2.9 1994/12/30 11:58:42 keith * Fixed bug hwhich caused core dump for small k-cutoff (hmax=0) * * Revision 2.8 1994/06/22 09:59:05 keith * Rearranged procedures * Minor optimization to "trig rules" loops. * * Revision 2.7 1994/06/08 13:13:59 keith * New version of array allocator which breaks up requests for DOS. * Now must use specific "afree()" paired with arralloc(). * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Added CONST qualifier to (re-)declarations of ANSI library * emulation routines to give reliable compilation even * without ANSI_LIBS macro. (#define's away for K&R * compilers) * * Revision 2.5 1994/01/26 16:34:36 keith * Fixed non-ansi #endif. * * Revision 2.3 93/10/28 10:28:59 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/09/02 12:34:44 keith * Optimized qsincos() -- should give up to 25% speed improvement on * compilers without assert no aliasing options. * * Revision 2.0 93/03/15 14:49:49 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.22 93/03/12 12:23:05 keith * Reorganized defines to recognise all ANSI (__type__) forms. * Moved spxpy() from aux.c to force.c and force_parallel.c * * * Revision 1.21 93/03/09 15:59:58 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.20 93/03/05 15:01:53 keith * Added CRAY parallelising directives * * Revision 1.19 92/08/13 17:56:58 keith * Modified nprocessors to limit execution to 1 proc * unless env var THREADS explicitly set. * * Revision 1.18 92/06/26 17:03:02 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.17 92/02/26 14:33:48 keith * Got rid of pstrip pragmas for convex -- they just broke things * * Revision 1.16 91/11/27 15:15:56 keith * Corrected calculation of sheet energy term for charged framework. * Split force loop so as to omit frame-frame force (and stress) terms. * Added spaces so that Stellix compiler doesn't choke on "=*" * Replaced main loop variable with pointer to work round Stellix 2.3 bug * * Revision 1.16 91/11/26 12:48:43 keith * Put #ifdefs around machine-specific pragmas for portability. Now * supports Stardent 1000,2000 & 3000 (titan) series and convex. * * Revision 1.13 91/08/24 16:55:18 keith * Added pragmas for convex C240 parallelization * * Revision 1.12 91/08/15 18:13:17 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.11 91/05/29 17:02:00 keith * Modified for minor speed improvement on Stardent titan * * Revision 1.10 91/03/12 16:30:08 keith * Stardent Titan (ST3000) version. * * Revision 1.9 90/09/28 13:29:19 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.8 90/08/29 11:00:49 keith * Speeded up loop at 231 to improve parallel efficiency. * * Revision 1.7 90/08/01 19:11:40 keith * Modified to exclude framework-framework interactions. * N.B. Excluded from pe and stress but NOT forces (as they sum to 0). * * Revision 1.6 90/05/16 18:40:57 keith * Renamed own freer from cfree to tfree. * * Revision 1.5 90/05/16 14:20:47 keith * *** empty log message *** * * Revision 1.4 90/05/02 15:37:31 keith * Removed references to size_mt and time_t typedefs, no longer in "defs.h" * * Revision 1.3 90/04/26 15:29:48 keith * Changed declaration of arralloc back to char* * * Revision 1.2 90/04/25 10:37:06 keith * Fixed bug which led to ihkl[] accessing outside bounds of chx[] etc arrays * when in const-pressure mode and MD cell expanded between steps. * * Revision 1.1 90/01/31 13:18:59 keith * Initial revision * * Revision 1.6 89/12/15 12:56:26 keith * Added conditional ionclusion of for stellar * * Revision 1.5 89/11/01 17:29:10 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * 'Uniform charge sheet' term added in case of electrically charged system. * * Revision 1.5 89/10/26 11:29:26 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * 'Uniform charge sheet' term added in case of electrically charged layer. * * Revision 1.5 89/10/26 11:27:31 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * * Revision 1.4 89/10/02 11:39:14 keith * Fixed error in *star macros which assumed rlv's were cols of h(-1) r.t. rows. * * Revision 1.3 89/06/09 13:38:17 keith * Older code for computation of q cos/sin k.r restored conditionally by * use of macro OLDEWALD. This is for more primitive vectorising compilers. * * Revision 1.2 89/06/08 10:42:51 keith * Modified to circumvent compiler bug in VMS/VAXC 2.4-026 * * Revision 1.1 89/04/20 16:00:39 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/ewald_parallel.c,v 2.9 1994/12/30 11:58:42 keith stab $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar # include #else #ifdef titan # include #else # include #endif #endif #include "stddef.h" #include "stdlib.h" /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void afree(); /* Free allocated array */ double err_fn(); /* Error function */ double det(); /* Determinant of 3x3 matrix */ void invert(); /* Inverts a 3x3 matrix */ void mat_vec_mul(); /* Multiplies a 3x3 matrix by 3xN vect*/ void mat_sca_mul(); /* Multiplies a 3x3 matrix by scalar */ void transpose(); /* Transposes a 3x3 matrix */ void zero_real(); /* Initialiser */ void zero_double(); /* Initialiser */ double sum(); /* Sum of elements of 'real' vector */ void ewald_inner(); /* Inner loop forward reference */ int nprocessors(); /* Return no. of procs to execute on. */ #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else gptr *arralloc(); /* Array allocator */ void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control record */ /*========================== Macros ==========================================*/ #define astar hinvp[0] #define bstar hinvp[1] #define cstar hinvp[2] #define moda(hmat) (hmat[0][0]) #define modb(hmat) sqrt(SQR(hmat[0][1]) + SQR(hmat[1][1])) #define modc(hmat) sqrt(SQR(hmat[0][2]) + SQR(hmat[1][2]) + SQR(hmat[2][2])) /*============================================================================*/ struct _hkl {double kx, ky, kz; int h,k,l;}; /***************************************************************************** * qsincos(). Evaluate q sin(k.r) and q cos(k.r). This is in a separate * * function because some compilers (notably Stellar's) generate MUCH better * * vector code this way. * *****************************************************************************/ static void qsincos(coshx,sinhx,cosky,sinky,coslz,sinlz,chg, qcoskr,qsinkr,k,l,nsites) real coshx[], sinhx[], cosky[], sinky[], coslz[], sinlz[], chg[], qcoskr[], qsinkr[]; int k,l,nsites; { int is; real qckr; if( k >= 0 ) if( l >= 0 ) { #ifdef __convexc__ #pragma _CNX no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*coslz[is] - (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*coslz[is] + (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else { #ifdef __convexc__ #pragma _CNX no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*coslz[is] + (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*coslz[is] - (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else if( l >= 0 ) { #ifdef __convexc__ #pragma _CNX no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*coslz[is] - (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*coslz[is] + (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else { #ifdef __convexc__ #pragma _CNX no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*coslz[is] + (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*coslz[is] - (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } } /****************************************************************************** * Ewald Calculate reciprocal-space part of coulombic forces * ******************************************************************************/ #ifdef titan #ifdef PARALLEL #pragma opt_level 3 #pragma pproc ewald_inner #endif #endif void ewald(site,site_force,system,species,chg,pe,stress) real **site, /* Site co-ordinate arrays (in) */ **site_force; /* Site force arrays (out) */ system_mp system; /* System record (in) */ spec_mt species[]; /* Array of species records (in) */ real chg[]; /* Array of site charges (in) */ double *pe; /* Potential energy (out) */ mat_mt stress; /* Stress virial (out) */ { mat_mt hinvp; /* Matrix of reciprocal lattice vects*/ register int h, k, l; /* Recip. lattice vector indices */ int i, j, is, ssite;/* Counters. */ spec_mp spec; /* species[ispec] */ register int nsites = system->nsites; double kx,ky,kz; vec_mt kv; /* (Kx,Ky,Kz) */ struct _hkl *hkl; int nhkl = 0; register real coss; /* * Maximum values of h, k, l s.t. |k| < k_cutoff */ int hmax = floor(control.k_cutoff/(2*PI)*moda(system->h)), kmax = floor(control.k_cutoff/(2*PI)*modb(system->h)), lmax = floor(control.k_cutoff/(2*PI)*modc(system->h)); /* * Arrays for cos & sin (h x(i)), (k y(i)) and (l z(i)) eg chx[h][isite] * and pointers to a particular h,k or l eg coshx[is] = chh[2][is] */ real **chx = (real**)arralloc((size_mt)sizeof(real),2, 0, hmax, 0, nsites-1), **cky = (real**)arralloc((size_mt)sizeof(real),2, 0, kmax, 0, nsites-1), **clz = (real**)arralloc((size_mt)sizeof(real),2, 0, lmax, 0, nsites-1), **shx = (real**)arralloc((size_mt)sizeof(real),2, 0, hmax, 0, nsites-1), **sky = (real**)arralloc((size_mt)sizeof(real),2, 0, kmax, 0, nsites-1), **slz = (real**)arralloc((size_mt)sizeof(real),2, 0, lmax, 0, nsites-1); real *coshx, *cosky, *coslz, *sinhx, *sinky, *sinlz; real *c1, *s1, *cm1, *sm1; real *sf0, *sf1, *sf2, *ssf0, *ssf1, *ssf2; real *site0, *site1, *site2; int nthreads = nprocessors(), ithread; double *pe_n = aalloc(nthreads, double); mat_mt *stress_n = aalloc(nthreads, mat_mt); real ***s_f_n; double r_4_alpha = -1.0/(4.0 * control.alpha * control.alpha); double vol = det(system->h); /* Volume of MD cell */ static double self_energy, /* Constant self energy term */ sheet_energy; /* Correction for non-neutral system. */ static boolean init = true; /* Flag for the first call of function*/ static int nsitesxf; /* Number of non-framework sites. */ invert(system->h, hinvp); /* Inverse of h is matrix of r.l.v.'s */ mat_sca_mul(2*PI, hinvp, hinvp); s_f_n = aalloc(nthreads, real**); s_f_n[0] = site_force; for(ithread = 1; ithread < nthreads; ithread++) { s_f_n[ithread] = (real**)arralloc((size_mt)sizeof(real), 2, 0, 2, 0, nsites-1); zero_real(s_f_n[ithread][0],3*nsites); } zero_real(stress_n,9*nthreads); zero_double(pe_n, nthreads); /* * First call only - evaluate self energy term and store for subsequent calls * Self energy includes terms for non-framework sites only. */ if(init) { double sqsq = 0, sq = 0, sqxf, intra, r; int js, frame_flag; self_energy = sheet_energy = 0; ssite = 0; spec = species; while( spec < species+system->nspecies && ! spec->framework) { intra = 0.0; for(is = 0; is < spec->nsites; is++) for(js = is+1; js < spec->nsites; js++) { r = DISTANCE(spec->p_f_sites[is], spec->p_f_sites[js]); intra += chg[ssite+is] * chg[ssite+js] *err_fn(control.alpha * r) / r; } self_energy += spec->nmols * intra; ssite += spec->nsites*spec->nmols; spec++; } nsitesxf = ssite; frame_flag = (spec != species+system->nspecies); #ifdef titan #pragma no_parallel #endif for(is = 0; is < nsitesxf; is++) { sq += chg[is]; sqsq += SQR(chg[is]); } self_energy += control.alpha / sqrt(PI) * sqsq; /* * Sqxf is total non-framework charge. Calculate grand total in sq. */ sqxf = sq; #ifdef titan #pragma no_parallel #endif for(; is < nsites; is++) sq += chg[is]; /* * Charged-system/uniform sheet correction terms (really in direct * space term but included here for convenience). * 1) For charged framework only. */ if( frame_flag ) { sheet_energy = PI*SQR(sq-sqxf) / (2.0*SQR(control.alpha)); message(NULLI, NULLP, INFO, FRACHG, (sq-sqxf)*CONV_Q, sheet_energy/vol*CONV_E); } /* * 2) Case of entire system non-neutral. */ if( fabs(sq)*CONV_Q > 1.0e-5) { sheet_energy -= intra = PI*SQR(sq) / (2.0*SQR(control.alpha)); message(NULLI, NULLP, WARNING, SYSCHG, sq*CONV_Q, intra/vol*CONV_E); } note("Ewald self-energy = %f Kj/mol",self_energy*CONV_E); init = false; } /* * Build array hkl[] of k vectors within cutoff */ hkl = aalloc(4*(hmax+1)*(kmax+1)*(lmax+1), struct _hkl); for(h = 0; h <= hmax; h++) for(k = (h==0 ? 0 : -kmax); k <= kmax; k++) { kv[0] = h*astar[0] + k*bstar[0]; kv[1] = h*astar[1] + k*bstar[1]; kz = h*astar[2] + k*bstar[2]; for(l = (h==0 && k==0 ? 1 : -lmax); l <= lmax; l++) { /* kv[0] = kx + l*cstar[0]; kv[1] = ky + l*cstar[1]; */ kv[2] = kz + l*cstar[2]; if( SUMSQ(kv) < SQR(control.k_cutoff) ) { hkl[nhkl].h = h; hkl[nhkl].k = k; hkl[nhkl].l = l; hkl[nhkl].kx = kv[0]; hkl[nhkl].ky = kv[1]; hkl[nhkl].kz = kv[2]; nhkl++; } } } *pe -= self_energy; /* Subtract self energy term */ *pe += sheet_energy/vol; /* Uniform charge correction */ for(i=0; i<3; i++) stress[i][i] += sheet_energy/vol; /* * Calculate cos and sin of astar*x, bstar*y & cstar*z for each charged site */ coshx = chx[0]; cosky = cky[0]; coslz = clz[0]; sinhx = shx[0]; sinky = sky[0]; sinlz = slz[0]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { coshx[is] = cosky[is] = coslz[is] = 1.0; sinhx[is] = sinky[is] = sinlz[is] = 0.0; } site0 = site[0]; site1 = site[1]; site2 = site[2]; if( hmax >= 1 ) { coshx = chx[1]; sinhx = shx[1]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { kx = astar[0]*site0[is]+astar[1]*site1[is]+astar[2]*site2[is]; coshx[is] = cos(kx); sinhx[is] = sin(kx); } } if( kmax >= 1 ) { cosky = cky[1]; sinky = sky[1]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { ky = bstar[0]*site0[is]+bstar[1]*site1[is]+bstar[2]*site2[is]; cosky[is] = cos(ky); sinky[is] = sin(ky); } } if( lmax >= 1 ) { coslz = clz[1]; sinlz = slz[1]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { kz = cstar[0]*site0[is]+cstar[1]*site1[is]+cstar[2]*site2[is]; coslz[is] = cos(kz); sinlz[is] = sin(kz); } } /* * Use addition formulae to get sin(h*astar*x)=sin(Kx*x) etc for each site */ for(h = 2; h <= hmax; h++) { coshx = chx[h]; sinhx = shx[h]; cm1 = chx[h-1]; sm1 = shx[h-1]; c1 = chx[1]; s1 = shx[1]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { coss = cm1[is]*c1[is] - sm1[is]*s1[is]; sinhx[is] = sm1[is]*c1[is] + cm1[is]*s1[is]; coshx[is] = coss; } } for(k = 2; k <= kmax; k++) { cosky = cky[k]; sinky = sky[k]; cm1 = cky[k-1]; sm1 = sky[k-1]; c1 = cky[1]; s1 = sky[1]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { coss = cm1[is]*c1[is] - sm1[is]*s1[is]; sinky[is] = sm1[is]*c1[is] + cm1[is]*s1[is]; cosky[is] = coss; } } for(l = 2; l <= lmax; l++) { coslz = clz[l]; sinlz = slz[l]; cm1 = clz[l-1]; sm1 = slz[l-1]; c1 = clz[1]; s1 = slz[1]; #ifdef titan #pragma no_parallel #endif VECTORIZE for(is = 0; is < nsites; is++) { coss = cm1[is]*c1[is] - sm1[is]*s1[is]; sinlz[is] = sm1[is]*c1[is] + cm1[is]*s1[is]; coslz[is] = coss; } } /* * Start of main loops over K vector indices h, k, l between -*max, *max etc. * To avoid calculating K and -K, only half of the K-space box is covered. * Points on the axes are included once and only once. (0,0,0) is omitted. */ #ifdef PARALLEL #ifdef stellar /*$dir parallel*/ #endif /* stellar */ #ifdef titan #pragma ipdep #pragma pproc ewald_inner #endif /* titan */ #ifdef __convexc__ #pragma _CNX force_parallel #endif /* __convexc__ */ #ifdef CRAY #pragma _CRI taskloop private(ithread) shared(nthreads, nhkl, hkl, nsites, \ nsitesxf, chx, cky, clz, shx, sky, slz, chg, vol, r_4_alpha, \ stress_n, pe_n, s_f_n) #endif /* CRAY */ #endif /*PARALLEL */ for(ithread = 0; ithread < nthreads; ithread++) ewald_inner(ithread, nthreads, nhkl, hkl, nsites, nsitesxf, chx, cky, clz, shx, sky, slz, chg, &vol, &r_4_alpha, stress_n[ithread], pe_n+ithread, s_f_n[ithread]); /* * Sum Pot, energies, forces and stress from each parallel invocation */ for(ithread = 0; ithread < nthreads; ithread++) { *pe += pe_n[ithread]; #ifdef titan #pragma asis #endif for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) stress[i][j] += stress_n[ithread][i][j]; } sf0 = site_force[0]; sf1 = site_force[1]; sf2 = site_force[2]; for(ithread = 1; ithread < nthreads; ithread++) { ssf0 = s_f_n[ithread][0]; ssf1 = s_f_n[ithread][1]; ssf2 = s_f_n[ithread][2]; #ifdef titan #pragma ipdep #endif #ifdef __convexc__ #pragma _CNX vstrip (64) #pragma _CNX force_vector #pragma _CNX force_parallel_ext #endif #ifdef CRAY #pragma _CRI ivdep #endif for(is = 0; is < nsites; is++) { sf0[is] += ssf0[is]; sf1[is] += ssf1[is]; sf2[is] += ssf2[is]; } } afree((gptr*)chx); afree((gptr*)cky); afree((gptr*)clz); afree((gptr*)shx); afree((gptr*)sky); afree((gptr*)slz); xfree(pe_n); xfree(stress_n); xfree(hkl); for( ithread = 1; ithread < nthreads; ithread++) afree(s_f_n[ithread]); xfree(s_f_n); } #ifdef titan #ifdef PARALLEL #pragma opt_level 2 #endif #endif /***************************************************************************** * Ewald_inner(). Part of Ewald sum to run in parallel on multi-stream or * * multi-processor computers. It splits up the loop over k-vectors by using* * a stride of the number of threads in use. The loop starts from a value * * unique to the thread. Summable quantities, pe, stress, site_force are * * accumulated where specified by the arguments so it is the callers * * responsibility to provide a separte area and accumulate the grand totals * *****************************************************************************/ void ewald_inner(ithread, nthreads, nhkl, hkl, nsites, nsitesxf, chx, cky, clz, shx, sky, slz, chg, volp, r_4_alphap, stress, pe, site_force) int ithread, nthreads, nhkl; struct _hkl hkl[]; int nsites; int nsitesxf; /* N sites excluding framework sites. */ real **chx, **cky, **clz, **shx, **sky, **slz; double *volp, *r_4_alphap; mat_mt stress; double *pe; real chg[]; real **site_force; { vec_mt kv; double ksq, coeff, coeff2, pe_k; double sqcoskr, sqsinkr, sqcoskrn, sqsinkrn, sqcoskrf, sqsinkrf; real *coshx, *cosky, *coslz, *sinhx, *sinky, *sinlz; int is, i, j, h, k, l; struct _hkl *phkl; double vol = *volp, r_4_alpha = *r_4_alphap; real force_comp, kv0, kv1, kv2; real *qcoskr = dalloc(nsites), *qsinkr = dalloc(nsites); real *site_fx = site_force[0], *site_fy = site_force[1], *site_fz = site_force[2]; for(phkl = hkl+ithread; phkl < hkl+nhkl; phkl += nthreads) { h = phkl->h; k = phkl->k; l = phkl->l; kv0 = kv[0] = phkl->kx; kv1 = kv[1] = phkl->ky; kv2 = kv[2] = phkl->kz; /* * Calculate pre-factors A(K) etc */ ksq = SUMSQ(kv); coeff = 2.0 / (EPS0 * vol) * exp(ksq * r_4_alpha) / ksq; coeff2 = 2.0 * (1.0 - ksq * r_4_alpha) / ksq; /* * Set pointers to array of cos (h*astar*x) (for efficiency & vectorisation) */ coshx = chx[h]; cosky = cky[abs(k)]; coslz = clz[abs(l)]; sinhx = shx[h]; sinky = sky[abs(k)]; sinlz = slz[abs(l)]; /* * Calculate q(i)*cos/sin(K.R(i)) by addition formulae. Note handling of * negative k and l by using sin(-x) = -sin(x), cos(-x) = cos(x). For * efficiency & vectorisation there is a loop for each case. */ qsincos(coshx,sinhx,cosky,sinky,coslz,sinlz,chg, qcoskr,qsinkr,k,l,nsites); sqcoskrn = sum(nsitesxf, qcoskr, 1); sqsinkrn = sum(nsitesxf, qsinkr, 1); sqcoskrf = sum(nsites-nsitesxf, qcoskr+nsitesxf, 1); sqsinkrf = sum(nsites-nsitesxf, qsinkr+nsitesxf, 1); sqcoskr = sqcoskrn + sqcoskrf; sqsinkr = sqsinkrn + sqsinkrf; /* * Evaluate potential energy contribution for this K and add to total. * Exclude frame-frame interaction terms. */ pe_k = 0.5 * coeff * (sqcoskrn*(sqcoskrn+sqcoskrf+sqcoskrf) + sqsinkrn*(sqsinkrn+sqsinkrf+sqsinkrf)); *pe += pe_k; sqsinkr *= coeff; sqcoskr *= coeff; sqsinkrn *= coeff; sqcoskrn *= coeff; /* * Calculate long-range coulombic contribution to stress tensor */ NOVECTOR for(i = 0; i < 3; i++) { stress[i][i] += pe_k; NOVECTOR for(j = i; j < 3; j++) stress[i][j] -= pe_k * coeff2 * kv[i] * kv[j]; } /* * Evaluation of site forces. Non-framework sites interact with all others */ VECTORIZE for(is = 0; is < nsitesxf; is++) { force_comp = qsinkr[is]*sqcoskr - qcoskr[is]*sqsinkr; site_fx[is] += kv0 * force_comp; site_fy[is] += kv1 * force_comp; site_fz[is] += kv2 * force_comp; } #if 1 /* * Framework sites -- only interact with non-framework sites */ VECTORIZE for(is = nsitesxf; is < nsites; is++) { force_comp = qsinkr[is]*sqcoskrn - qcoskr[is]*sqsinkrn; site_fx[is] += kv0 * force_comp; site_fy[is] += kv1 * force_comp; site_fz[is] += kv2 * force_comp; } #endif /* * End of loop over K vectors. */ } xfree(qcoskr); xfree(qsinkr); } char *getenv(); #ifdef titan int nprocessors() { char *env; static int n=0; int nphys; if( n <= 0 ) { nphys = MT_NUMBER_OF_PROCS(); if( ( env = getenv("THREADS") ) == NULL ) n = 1; else { n = atoi(env); if ( n <= 0 || n > nphys) n = nphys; } } return n; } #else #ifdef CRAY int nprocessors() { char *env; static int n = 0; int nphys = 8; if( n <= 0 ) { if( ( env = getenv("NCPUS") ) == NULL ) n = 1; else { n = atoi(env); if ( n <= 0 || n > nphys) n = nphys; } } return n; } #else /* GS1000/2000 but should compile on any unix */ int nprocessors() { char *env; static int n = 0; int nphys = 4; if( n <= 0 ) { if( ( env = getenv("THREADS") ) == NULL ) n = 1; else { n = atoi(env); if ( n <= 0 || n > nphys) n = nphys; } } return n; } #endif #endif $EOD $! $CREATE force_parallel.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Force This module contains functions to implement the 'link cell' * * interatomic force calculation (Hockney, R.W. & Eastwood J.W. * * "Computer Simulation Using Particles" McGraw-Hill (1981), 277)* * It is vectorised and optimised for a CRAY XMP and Convex C1, * * but should run well on any vector machine with reasonably * * efficient scatter/gather. (And of course on scalar machines!) * * The actual calculation of the potential is in a different * * module (kernel.c) for ease of modification. * ****************************************************************************** * Revision Log * Revision 1.3 90/03/29 15:44:51 keith * Merged force.c revisions 1.8.1.11-1.8.1.13 * * Revision 1.2 90/03/09 17:30:29 keith * Modified FKERNEL ifdefs for UNICOS. * * Revision 1.1 90/01/31 13:19:28 keith * Initial revision * * Revision 1.8.1.8 89/11/01 17:34:15 keith * Modified to use SPAXPY vectorised scattered add. * * Revision 1.8.1.6 89/10/12 16:28:39 keith * Added conditional code to produce histogram of interaction distances * and calculate 'minimum image' energy. * Added preprocessor constant NSH to fix size of relocation arrays. * Fixed mistake in metric G in neighbour_list() (G=h'h not hh'). * * Revision 1.8.1.5 89/10/02 17:12:59 keith * New version of neighbour_list() which works for arbitrary cutoff radii. * site_neighbour_list checks for overflow. * Main loop limits modified, (in conjunction with mods in site_neighbour_list) * to correctly include all molecule-framework interactions. * * Revision 1.8.1.4 89/09/12 16:14:41 keith * Fixed bug in fill_cells() which didn't increment spec properly in imol loop * * Revision 1.8.1.3 89/08/31 11:58:04 keith * Fixed bug in 'BIN' macro to correctly handle case of rc<0. * * Revision 1.8.1.2 89/08/30 17:00:33 keith * Fixed memory overlap bug in site_neighbour_list * * Revision 1.8.1.1 89/08/25 15:24:43 keith * Mods to add framework structures to simulation model * * Revision 1.7 89/08/22 14:48:39 keith * Created new variable 'n_nab_sites' for max size of vector arrays. * * Revision 1.6 89/07/04 18:43:14 keith * Fixed error in kernel and force which led to sites being allocated the * wrong potential parameters. Needed extra parameter to kernel. * * Revision 1.5 89/06/22 15:44:23 keith * Tidied up loops over species to use one pointer as counter. * * Revision 1.4 89/06/14 14:18:49 keith * Fixed #ifdef s for CRAY to handle case of UNICOS * Fix mistake in VCALLS conditional code. * * Revision 1.3 89/06/01 18:01:46 keith * Moved `vadd()' from aux.c to force.c for ease of vectorisation. * Now no need to compile aux.c with vectorisation. * * Revision 1.2 89/05/17 13:53:49 keith * Reorganised neighbour list construction in preparation for framework. * (Also goes slighty faster) * * Revision 1.1 89/04/20 16:00:40 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/force_parallel.c,v 2.8 1994/12/16 11:58:54 keith stab $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar #include #else #include #endif #include "stddef.h" #include "string.h" /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void afree(); /* Free allocated array */ int search_lt(); /* Search a vector for el. < scalar */ double vdot(); /* Vector dot product */ double sum(); /* Sum a vector */ void gather(); /* Interface to CRAY gather routine */ void gatheri(); /* Integer gather */ int wheneq(); /* Array indexer */ void mat_mul(); /* Matrix multiplier */ double det(); /* Determinant of 3x3 matrix */ void invert(); /* 3x3 matrix inverter */ void mat_vec_mul(); /* Matrix by vector multiplier */ void transpose(); /* Generate 3x3 matrix transpose */ void zero_real(); /* Initialiser */ void zero_double(); /* Initialiser */ void force_inner(); /* Inner loop forward reference */ int nprocessors(); /* Return no. of procs to execute on. */ double precision(); /* Floating pt precision. */ void kernel(); /* Force kernel routine */ double mol_radius(); /* Radius of largest molecule. */ #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ void note(char *, ...); /* Write a message to the output file */ void message(int *, ...); /* Write a warning or error message */ #else gptr *arralloc(); /* Array allocator */ void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control parms. */ /*========================== Structs local to module =========================*/ typedef struct cell_s /* Prototype element of linked list of*/ { /* molecules within interaction range */ int isite, num, frame_type; struct cell_s *next; } cell_mt; typedef struct /* Prototype of neighbour cell list */ { /* element. */ int i, j, k; } ivec_mt; typedef struct /* Prototype for a 3Nx x 3Ny x 3Nz */ { /* pbc relocation array. */ int ncell, rel; } reloc_mt; /*========================== Global variables ================================*/ static int nx = 0, ny = 0, nz = 0, onx = 0, ony = 0, onz = 0; /*========================== Macros ==========================================*/ #define NCELL(ix,iy,iz) ((iz)+nz*((iy)+ny*(ix))) /* * Maximum cutoff radius relative to MD cell dimension. */ #define NSH 1 /* * Multiplication factor for size of neighbour list arrays. If you need * to increase this from 1, your system must be *highly* inhomogeneous * and may not make sense! */ #define NMULT 4.0 #define NSHELL (2*NSH+1) #define NREL(ix,iy,iz) ((iz)+NSH+NSHELL*((iy)+NSH+NSHELL*((ix)+NSH))) #define CELLMAX 5 #define TOO_CLOSE 0.25 /* Error signalled if r**2 < this */ #define LOCATE(r,eps) NCELL(cellbin(r[0], nx, eps), \ cellbin(r[1], ny, eps), \ cellbin(r[2], nz, eps)) #define moda(hmat) sqrt(SQR(hmat[0][0]) + SQR(hmat[1][0]) + SQR(hmat[2][0])) #define modb(hmat) sqrt(SQR(hmat[0][1]) + SQR(hmat[1][1]) + SQR(hmat[2][1])) #define modc(hmat) sqrt(SQR(hmat[0][2]) + SQR(hmat[1][2]) + SQR(hmat[2][2])) /*============================================================================*/ /****************************************************************************** * spxpy Sparse add for force.c. N.B. MUST NOT BE VECTORIZED as ix may * * contain duplicate entries. This occurs if a site interacts with * * more than one periodic copy of another site. * ******************************************************************************/ static void spxpy(n, sx, sy, ix) int n, ix[]; real sx[], sy[]; { int i; NOVECTOR #ifdef __STDC__ #pragma novector #endif for( i = 0; i < n; i++) { sy[ix[i]] += sx[i]; } } /****************************************************************************** * cellbin. Safe binning function for putting molecules/sites into cells. * * Any error at the boundaries is disasterous and hard to detect. * * Results may depend on machine-dependant rounding etc. * ******************************************************************************/ int cellbin(rc, nc, eps) double rc, eps; int nc; { int ibin; if(rc < -0.5+eps || rc >= 0.5-eps) { if(rc < -0.5+eps && rc >= -0.5-eps) rc = -0.5; else if(rc >= 0.5-eps && rc <= 0.5+eps) rc = 0.5-eps; else message(NULLI, NULLP, ERROR, "Co-ordinate out of range in BIN (fill_cells) %.17g\n",rc); } if( (ibin = ((rc+0.5)*nc)) >= nc || ibin < 0) message(NULLI, NULLP, ERROR, "Rounding problem in BIN (fill_cells) %.17g\n",rc); return ibin; } /****************************************************************************** ******************************************************************************/ #ifdef DEBUG2 #define NBINS 200 static int bins[NBINS]; hist(jmin, jmax, rr) int jmin, jmax; real rr[]; { double rbin = 10.0; int j; for(j = jmin; j < jmax; j++) if(rr[j] < SQR(NBINS/rbin)) bins[(int)(rbin*sqrt(rr[j]))]++; } void histout() { int j; for(j = 0; j < NBINS; j++) { printf("%d%c",bins[j],(j+1)%10?' ':'\n'); bins[j] = 0; } } #endif /****************************************************************************** * Neighbour_list. Build the list of cells within cutoff radius of cell 0 * ******************************************************************************/ static ivec_mt *neighbour_list(nnabor, h, cutoff) int *nnabor; mat_mt h; double cutoff; { double dist; int i, j, ix, iy, iz, mx, my, mz, inabor = 0, nnab; static int onabor=0; ivec_mt *nabor; vec_mt s; mat_mt G, htr, htrinv; transpose(h, htr); mat_mul(htr, h, G); invert(htr, htrinv); mx = ceil(cutoff*nx*moda(htrinv)); my = ceil(cutoff*ny*modb(htrinv)); mz = ceil(cutoff*nz*modc(htrinv)); nnab = 4*mx*my*mz; nabor = aalloc(nnab, ivec_mt); #ifdef DEBUG1 printf(" Distance ix iy iz sx sy sz\n"); #endif for(ix = 0; ix < mx; ix++) for(iy = (ix == 0 ? 0 : -my); iy < my; iy++) for(iz = (ix == 0 && iy == 0 ? 0 : -mz); iz < mz; iz++) { s[0] = (double)ix/nx; s[1] = (double)iy/ny; s[2] = (double)iz/nz; dist = 0.0; for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) dist += s[i]*G[i][j]*s[j]; if(dist < SQR(cutoff)) { if( inabor >= nnab ) message(NULLI, NULLP, FATAL, "Internal error in neighbour_list()"); nabor[inabor].i = ix; nabor[inabor].j = iy; nabor[inabor].k = iz; inabor++; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", dist,ix,iy,iz,s[0],s[1],s[2]); #endif } } if( inabor != onabor ) note(NABORS,2 * inabor); onabor = inabor; *nnabor = inabor; return(nabor); } /****************************************************************************** * Strict_Neighbour_list. Build the list of cells within cutoff radius * * This is the strict version and includes every cell which has an interior * * point at a distance less than the cutoff from any interior point of the * * reference cell. In fact the distance criterion is cutoff+2*(maximum mol- * * ecular radius). This ensures that all *sites* which might be closer to- * * gether than the cutoff are included. * * The method used is based on the fact that the closest interior points * * of a pair of parallelopiped cells are either at corners of both cells or * * at the ends of a line perpendicular to the faces of both parallelopipeds. * * The face-face distance is always the shortest, if the perpendicular * * projection of the faces onto a common plane intersect with each other * * The goal is therefore to build a list containing all cells which have a * * corner-corner or face-face distance to the reference cell which is less * * than the cutoff. * * Cells may be admitted to the list by multiple corner-corner or face-face * * contact criteria but must only be recorded in the final list once. The * * easiest way to do this is to use a "map" of all the cells potentially * * within the cutoff radius and to flag occupancy. * * It is easier to loop over all grid vectors within the cutoff and assign * * cells which have that vector as some corner-corner vector with the * * reference cell, rather than to loop over cells and calculate all corner * * pair distances. This method calculates each distance only once instead * * of 27 times (the number of distinct corner-corner vectors between 2 * * cells). * * To exploit Newton's third law the list should contain only the positive * * hemisphere (in the x direction). * * * * The algorithm is as follows. * * 1) Set up an empty "map" * * 2) Loop over all points on a grid with points at the link-cell corners * * choose only points which are closer to the origin than the cutoff. * * Set the occupancy flag for all cells which have that as a corner-pair * * vector to the reference cell. This is a 3x3x3 block of cells centred * * on the cell whose index is the same as the gridpoint being considered. * * Because we only want the "positive x" cells 2x3x3 will suffice. * * 3) Add cells which have a perpendicular face-face separation within the * * cutoff. Only the outermost cells need be considered since inner ones * * are already admitted by corner-pair distance. Thus * * 3a) project the facing corner points of the reference cell onto the * * plane just within the cutoff. * * 3b) add the cells with faces which overlap the projection. Zero, two * * or four cells are added depending on whether the projected points * * coincide with the corner points, the edges or none of the faces. * * 4) The final list is built by scanning the map. * ******************************************************************************/ static ivec_mt *strict_neighbour_list(nnabor, h, cutoff) int *nnabor; mat_mt h; double cutoff; { double dist; int i, j, k, ix, iy, iz, mx, my, mz, inabor = 0, nnab; static int onabor=0; int ***cellmap; ivec_mt *nabor; vec_mt s; mat_mt G, htr, htrinv; int face_cells[4][3],mxyz[3], nxyz[3], ixyz, jxyz, kxyz; double proj[3], modabc; transpose(h, htr); mat_mul(htr, h, G); invert(htr, htrinv); mx = ceil(cutoff*nx*moda(htrinv)); my = ceil(cutoff*ny*modb(htrinv)); mz = ceil(cutoff*nz*modc(htrinv)); /* * Allocate and clear array for map of cells */ nnab = 4*(mx+1)*(my+1)*(mz+1); cellmap = (int***)arralloc((size_mt)sizeof ***cellmap, 3, 0, mx, -my-1, my, -mz-1, mz); memst(cellmap[0][-my-1]-mz-1,0, nnab*sizeof ***cellmap); /* * Add cells with corner-pair distances < cutoff */ #ifdef DEBUG1 printf(" Distance ix iy iz sx sy sz\n"); #endif for(ix = 0; ix < mx; ix++) for(iy = (ix == 0 ? 0 : -my); iy < my; iy++) for(iz = (ix == 0 && iy == 0 ? 0 : -mz); iz < mz; iz++) { s[0] = (double)ix/nx; s[1] = (double)iy/ny; s[2] = (double)iz/nz; dist = 0.0; for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) dist += s[i]*G[i][j]*s[j]; if(dist < SQR(cutoff)) { for(i=0; i<=1; i++) for(j = -1; j <= 1; j++) for(k = -1; k <= 1; k++) cellmap[ix+i][iy+j][iz+k] = 1; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", dist,ix,iy,iz,s[0],s[1],s[2]); #endif } } /* * Add cells with face-face distance < cutoff. Cells along x,y,z axes * are added in +/- directions, but only +ve ix indices added to map. */ nxyz[0] = nx; nxyz[1] = ny; nxyz[2] = nz; mxyz[0] = mx; mxyz[1] = my; mxyz[2] = mz; for( ixyz=0; ixyz < 3; ixyz++) /* Loop over directions */ { jxyz = (ixyz+1) % 3; kxyz = (jxyz+1) % 3; proj[0] = proj[1] = proj[2] = 0.0; modabc = 0.0; for( i=0; i<3; i++ ) { modabc += htrinv[i][ixyz]; proj[i] += htrinv[i][ixyz]*htrinv[i][(ixyz+i) % 3]; } for( i=0; i<3; i++ ) proj[i] *= (mxyz[ixyz]-1)*nxyz[i]/(nxyz[ixyz] * modabc); /* * proj now contains projection vector. Construct 4 candidate * cells. */ for( i=0; i<3; i++ ) face_cells[0][i] = face_cells[1][i] = face_cells[2][i] = face_cells[3][i] = floor(proj[i]); face_cells[0][ixyz] = face_cells[1][ixyz] = face_cells[2][ixyz] = face_cells[3][ixyz] = mxyz[ixyz]; face_cells[1][jxyz] = face_cells[3][jxyz] = ceil(proj[jxyz]); face_cells[2][kxyz] = face_cells[3][kxyz] = ceil(proj[kxyz]); /* * Now make sure we add only cells with +ve x index. Add the * inverse cell if ix<0. */ for( i=0; i < 4; i++) if( face_cells[i][0] < 0 ) for( j=0; j<3; j++ ) face_cells[i][j] = -face_cells[i][j]; /* * Now add the cells to the map. */ for( i=0; i < 4; i++ ) { cellmap[face_cells[i][0]][face_cells[i][1]][face_cells[i][2]] = 1; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", 0.5,face_cells[i][0],face_cells[i][1],face_cells[i][2], 0.0,0.0,0.0); #endif } } /* * Scan map and build list. N.B. Loop indices are 1 greater than when * list built since we added cells outside original loop limits. */ nabor = aalloc(nnab, ivec_mt); for(ix = 0; ix <= mx; ix++) for(iy = (ix == 0 ? 0 : -my-1); iy <= my; iy++) for(iz = (ix == 0 && iy == 0 ? 0 : -mz-1); iz <= mz; iz++) { if( cellmap[ix][iy][iz] ) { if( inabor >= nnab ) message(NULLI, NULLP, FATAL, "Internal error in neighbour_list()"); nabor[inabor].i = ix; nabor[inabor].j = iy; nabor[inabor].k = iz; inabor++; #ifdef DEBUG1 printf("%12f %4d %4d %4d %12f %12f %12f\n", 1.0,ix,iy,iz,0.0,0.0,0.0); #endif } } if( inabor != onabor ) note(NABORS,2 * inabor); onabor = inabor; *nnabor = inabor; afree((gptr*)cellmap); return(nabor); } /****************************************************************************** * Fill_cells. Allocate all the sites to cells depending on their centre of * * mass co-ordinate by binning. * ******************************************************************************/ static void fill_cells(c_of_m, nmols, site, species, h, lst, cell, frame_type) vec_mt c_of_m[]; /* Centre of mass co-ords (in) */ int nmols; /* Number of molecules (in) */ real **site; /* Atomic site co-ordinates (in) */ spec_mp species; /* Pointer to species array (in) */ mat_mt h; /* Unit cell matrix (in) */ cell_mt *lst; /* Pile of cell structs (in) */ cell_mt *cell[]; /* Array of cells (assume zeroed)(out)*/ int *frame_type; /* Framework type counter (out)*/ { int icell, imol, im=0, is, isite = 0; double eps = 8.0*precision(); spec_mp spec = species; cell_mt *list = lst; vec_mt ssite; mat_mt hinv; *frame_type=1; invert(h, hinv); for(imol = 0, im = 0; imol < nmols; imol++, im++) { if(im == spec->nmols) { im = 0; spec++; } if( spec->framework ) { for( is = 0; is < spec->nsites; is++) { ssite[0] = site[0][isite]; ssite[1] = site[1][isite]; ssite[2] = site[2][isite]; mat_vec_mul(hinv, (vec_mt*)ssite, (vec_mt*)ssite, 1); icell = LOCATE(ssite, eps); list->isite = isite++; list->num = 1; list->frame_type = *frame_type; list->next = cell[icell]; cell[icell] = list++; list->next = NULL; } (*frame_type)++; } else { icell = LOCATE(c_of_m[imol], eps); list->isite = isite; list->num = spec->nsites; list->frame_type = 0; list->next = cell[icell]; cell[icell] = list++; list->next = NULL; isite += spec->nsites; } } } /****************************************************************************** * site_neightbour list. Build the list of sites withing interaction radius * * from the lists of sites in cells. * ******************************************************************************/ int site_neighbour_list(nab, reloc_i, n_nab_sites, nfnab, n_frame_types, n_nabors, ix, iy, iz, nabor, cell, reloc, work ) int *nab; /* Array of sites in list (out) */ int *reloc_i; /* Relocation indices for list (out) */ int n_nab_sites; /* Size of above arrays (in) */ int nfnab[]; /* N frame sites index by type (out) */ int n_frame_types; /* Number of distinct frameworks(in) */ int n_nabors; /* Number of neighbour cells (in) */ int ix, iy, iz; /* Labels of current cell (in) */ ivec_mt *nabor; /* List of neighbour cells (in) */ cell_mt **cell; /* Head of cell list (in) */ reloc_mt ***reloc; /* Relocation index array (in) */ int *work; /* Workspace */ { int jx, jy, jz; /* Labels of cell in neighbour list */ int jcell, jnab, jsite, rl; /* Counters for cells etc */ int nnab = 0; /* Counter for size of nab */ int ftype, c, nnabf = 0; cell_mt *cmol; /* Pointer to current cell element */ int *reloc_if = work, *frame_key = reloc_if + n_nab_sites, *nabf = frame_key + n_nab_sites, *idx = nabf + n_nab_sites; for(jnab = 0; jnab < n_nabors; jnab++) /* Loop over neighbour cells */ { jx = ix + nabor[jnab].i; jy = iy + nabor[jnab].j; jz = iz + nabor[jnab].k; #ifdef DEBUG1 if(jx<-nx || jx>=2*nx || jy<-ny || jy>=2*ny || jz<-nz || jz>=2*nz) message(NULLI,NULLP,FATAL,"Bounds error on reloc (%d,%d,%d)",jx,jy,jz); #endif jcell = reloc[jx][jy][jz].ncell; rl = reloc[jx][jy][jz].rel; /* Loop over molecules in this cell, filling 'nab' with its sites */ for(cmol = cell[jcell]; cmol != NULL; cmol = cmol->next) { if( jnab > 0 || cmol->frame_type == 0 ) for(jsite = 0; jsite < cmol->num; jsite++) { nabf[nnabf] = cmol->isite + jsite; reloc_if[nnabf] = rl; frame_key[nnabf] = cmol->frame_type; nnabf++; } if(nnabf > n_nab_sites) message(NULLI,NULLP,FATAL,TONAB,nnabf,n_nab_sites); } } nnab = 0; for( ftype = 0; ftype < n_frame_types; ftype++ ) { c = wheneq(nnabf, frame_key, 1, ftype, idx); gatheri(c, nab+nnab, nabf, idx); gatheri(c, reloc_i+nnab, reloc_if, idx); nfnab[ftype] = nnab += c; } return nnab; } /****************************************************************************** * reloc_alloc. Allocate and fill relocation array * ******************************************************************************/ static void reloc_alloc(h, reloc) mat_mt h; real reloc[][CUBE(NSHELL)]; { int tx, ty, tz; for(tx = -NSH; tx <= NSH; tx++) for(ty = -NSH; ty <= NSH; ty++) for(tz = -NSH; tz <= NSH; tz++) { reloc[0][NREL(tx,ty,tz)] = tx*h[0][0] + ty*h[0][1] + tz*h[0][2]; reloc[1][NREL(tx,ty,tz)] = ty*h[1][1] + tz*h[1][2]; reloc[2][NREL(tx,ty,tz)] = tz*h[2][2]; } } #ifdef titan #ifdef PARALLEL #pragma opt_level 3 #pragma pproc force_inner #endif #endif /****************************************************************************** * Force_calc. This is the main intermolecular site force calculation * * routine * ******************************************************************************/ void force_calc(site, site_force, system, species, chg, potpar, pe, stress) real **site, /* Site co-ordinate arrays (in) */ **site_force; /* Site force arrays (out) */ system_mp system; /* System struct (in) */ spec_mt species[]; /* Array of species records (in) */ real chg[]; /* Array of site charges (in) */ pot_mt potpar[]; /* Array of potential parameters (in) */ double *pe; /* Potential energy (out) */ mat_mt stress; /* Stress virial (out) */ { int isite, imol, /* Site counter i,j */ i_id, ipot, i, j; /* Miscellaneous */ int n_frame_types; int nsites = system->nsites,/* Local copy to keep optimiser happy */ n_potpar = system->n_potpar, max_id = system->max_id; int icell, ncells; /* Total number of cells */ int tx, ty, tz; /* Temporaries for # unit cell shifts */ int ix, iy, iz; int *id = ialloc(nsites), /* Array of site_id[nsites] */ *id_ptr; /* Pointer to 'id' array */ real ***potp /* Expanded pot'l parameters */ = (real***)arralloc((size_mt)sizeof(real), 3, 1, max_id-1, 0, n_potpar-1, 0, nsites-1); /* * The following arrays are for 'neighbour site list' * quantities and should be dimensioned to the max value of * 'nnab'. A rough approx is the ratio of the volume of * the "cutoff sphere" to that of the MD cell times nsites. * This may be too small for inhomogeneous systems, but at * least it scales with the cutoff radius. */ int n_nab_sites = nsites* /* Max # sites in n'bor list */ #ifdef DEBUG2 MAX(1.0,NMULT*4.19*CUBE(control.cutoff)/det(system->h)); #else NMULT*4.19*CUBE(control.cutoff)/det(system->h); #endif static int n_cell_list = 1; cell_mt *c_ptr = aalloc(n_cell_list, cell_mt ); spec_mp spec; cell_mt **cell; real *sf0, *sf1, *sf2, *ssf0, *ssf1, *ssf2; ivec_mt *nabor; static boolean init = true; static int n_nabors; static reloc_mt ***reloc = 0; int nthreads = nprocessors(), ithread; double *pe_n = (double *)aalloc(nthreads, double); mat_mt *stress_n = (mat_mt *)aalloc(nthreads, mat_mt); real ***s_f_n; double subcell = control.subcell; /* Local copy. May change it. */ #ifdef DEBUG2 double ppe, rr[3], ss[3]; int im, is, i; mat_mp h = system->h; mat_mt hinv; #endif s_f_n = aalloc(nthreads, real**); s_f_n[0] = site_force; for(ithread = 1; ithread < nthreads; ithread++) { s_f_n[ithread] = (real**)arralloc((size_mt)sizeof(real),2,0,2,0,nsites-1); zero_real(s_f_n[ithread][0],3*nsites); } zero_real(stress_n[0][0],9*nthreads); zero_double(pe_n, nthreads); if(subcell <= 0.0) subcell = control.cutoff/5.0; nx = system->h[0][0]/subcell+0.5; ny = system->h[1][1]/subcell+0.5; nz = system->h[2][2]/subcell+0.5; ncells = nx*ny*nz; if( nx != onx || ny != ony || nz != onz ) { note("MD cell divided into %d subcells (%dx%dx%d)",ncells,nx,ny,nz); if(control.cutoff >= NSH*MIN3(system->h[0][0],system->h[1][1],system->h[2][2])) message(NULLI, NULLP, FATAL, CUTOFF, NSH); if( reloc ) xfree((reloc-NSH*onx)); reloc = (reloc_mt***)arralloc((size_mt)sizeof(reloc_mt),3, -NSH*nx, (NSH+1)*nx-1, -NSH*ny, (NSH+1)*ny-1, -NSH*nz, (NSH+1)*nz-1); for(ix = 0; ix < nx; ix++) for(tx = -NSH*nx; tx <= NSH*nx; tx += nx) for(iy = 0; iy < ny; iy++) for(ty = -NSH*ny; ty <= NSH*ny; ty += ny) for(iz = 0; iz < nz; iz++) for(tz = -NSH*nz; tz <= NSH*nz; tz += nz) { reloc[ix+tx][iy+ty][iz+tz].ncell = NCELL(ix, iy, iz); reloc[ix+tx][iy+ty][iz+tz].rel= NREL(tx/nx,ty/ny,tz/nz); } onx = nx; ony = ny; onz = nz; } if(init) { for(spec = species; spec < species+system->nspecies; spec++) if( spec->framework ) n_cell_list += spec->nmols*spec->nsites; else n_cell_list += spec->nmols; xfree(c_ptr); c_ptr = aalloc(n_cell_list, cell_mt); init = false; } if( control.strict_cutoff ) nabor = strict_neighbour_list(&n_nabors, system->h, control.cutoff +2.0*mol_radius(species, system->nspecies)); else nabor = neighbour_list(&n_nabors, system->h, control.cutoff); cell = aalloc(ncells, cell_mt *); for( icell=0; icell < ncells; icell++) cell[icell] = NULL; /* Construct and fill expanded site-identifier array, id */ id_ptr = id; for (spec = species; spec < species+system->nspecies; spec++) for(imol = 0; imol < spec->nmols; imol++) { memcp(id_ptr, spec->site_id, spec->nsites*sizeof(int)); id_ptr += spec->nsites; } /* Build arrays of pot. pars [max_id][nsites] for access in vector loops */ for(ipot = 0; ipot < n_potpar; ipot++) for(i_id = 1; i_id < max_id; i_id++) { #ifdef titan NOVECTOR #endif for(isite = 0; isite < nsites; isite++) potp[i_id][ipot][isite] = potpar[i_id*max_id+id[isite]].p[ipot]; } fill_cells(system->c_of_m, system->nmols, site, species, system->h, c_ptr, cell, &n_frame_types); if( n_frame_types > 2 ) message(NULLI, NULLP, FATAL, "Multiple framework molecules are not supported"); #ifdef DEBUG2 ppe = 0; spec = species; isite = 0; invert(h, hinv); for(imol = 0, im = 0; imol < system->nmols; imol++, im++) { if(im == spec->nmols) { im = 0; spec++; } for(is = isite; is < isite+spec->nsites; is++) { for(jsite = 0; jsite < isite; jsite++) { for( i=0; i<3; i++) rr[i] = site[i][jsite] - site[i][is]; mat_vec_mul(hinv, rr, ss, 1); for( i=0; i<3; i++) ss[i] -= floor(ss[i]+0.5); mat_vec_mul(h, ss, rr, 1); r_sqr[jsite] = SUMSQ(rr); if( control.strict_cutoff && r_sqr[jsite] > cutoffsq ) r_sqr[jsite] = cutoff100sq; } hist(0,isite,r_sqr); kernel(0,isite,forceij,&ppe,r_sqr,chg,chg[is], norm,control.alpha,system->ptype,potp[id[is]]); } isite += spec->nsites; } histout(); note("Direct pot. energy = %g",ppe*CONV_E); #endif /* * Start of main loop over processors */ #ifdef PARALLEL #ifdef stellar /*$dir parallel*/ #endif /* stellar */ #ifdef titan #pragma ipdep #endif /* titan */ #ifdef __convexc__ #pragma _CNX force_parallel #endif /* --convexc__ */ #ifdef CRAY #pragma _CRI taskloop private(ithread) shared(nthreads,site,chg, potp, id,\ n_nab_sites, n_nabors, nabor, cell, reloc, n_frame_types, \ system, stress_n, pe_n, s_f_n) #endif /* CRAY */ #endif /*PARALLEL */ for(ithread = 0; ithread < nthreads; ithread++) force_inner(ithread, nthreads, site, chg, potp, id, n_nab_sites, n_nabors, nabor, cell, reloc, n_frame_types, system, stress_n[ithread], pe_n+ithread, s_f_n[ithread]); /* * Sum Pot, energies, forces and stress from each parallel invocation */ for(ithread = 0; ithread < nthreads; ithread++) { *pe += pe_n[ithread]; NOVECTOR for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) stress[i][j] += stress_n[ithread][i][j]; } /* * Sum thread's copies of the site forces. s_f_n[ithread] points * to the force arrays for each thread. s_f_n[0] is just * site_force and the others are independant arrays. */ sf0 = site_force[0]; sf1 = site_force[1]; sf2 = site_force[2]; for(ithread = 1; ithread < nthreads; ithread++) { ssf0 = s_f_n[ithread][0]; ssf1 = s_f_n[ithread][1]; ssf2 = s_f_n[ithread][2]; VECTORIZE #ifdef titan #pragma ipdep #endif #ifdef __convexc__ #pragma _CNX vstrip (32) #pragma _CNX force_vector #pragma _CNX force_parallel_ext #endif #ifdef CRAY #pragma _CRI ivdep #endif for(isite = 0; isite < nsites; isite++) { sf0[isite] += ssf0[isite]; sf1[isite] += ssf1[isite]; sf2[isite] += ssf2[isite]; } } #ifdef DEBUG2 histout(); #endif afree((gptr*)(potp+1)); xfree(c_ptr); xfree(cell); xfree(id); xfree(pe_n); xfree(stress_n); xfree(nabor); for( ithread = 1; ithread < nthreads; ithread++) afree((gptr*)s_f_n[ithread]); xfree(s_f_n); } #ifdef titan #ifdef PARALLEL #pragma opt_level 2 #endif #endif /****************************************************************************** * Force_inner() Paralellised inner loops of force_calc. Loops over cells * * in MD cell with stride = nomber of processors available. Should be * * called once for each parallel thread. * ******************************************************************************/ void force_inner(ithread, nthreads, site, chg, potp, id, n_nab_sites, n_nabors, nabor, cell, reloc, n_frame_types, system, stress, pe, site_force) int ithread, nthreads; real **site, **site_force; real chg[]; real ***potp; int id[]; int n_nab_sites; int n_nabors; int n_frame_types; system_mt *system; cell_mt **cell; reloc_mt ***reloc; ivec_mt *nabor; real *pe; mat_mt stress; { int *nab = ialloc(n_nab_sites), /* Neigbour site gather vector*/ *reloc_i = ialloc(n_nab_sites), /* Vector of pbc relocations */ *work = ialloc(4*n_nab_sites); /* Workspace for s_n_list */ real *nab_sx = dalloc(n_nab_sites), /* 'Gathered' list of */ *nab_sy = dalloc(n_nab_sites), /* neighbour site co-ords */ *nab_sz = dalloc(n_nab_sites), /* - x,y,z components. */ *forcejx = dalloc(n_nab_sites), /* List of neighbour site */ *forcejy = dalloc(n_nab_sites), /* forces in gathered form */ *forcejz = dalloc(n_nab_sites), /* - xyz components. */ *rx = dalloc(n_nab_sites), /* Reference to neigbour site */ *ry = dalloc(n_nab_sites), /* - site vector adjusted for */ *rz = dalloc(n_nab_sites), /* periodic boundaries. xyz. */ *r_sqr = dalloc(n_nab_sites), /* Squared site-site distance */ *nab_chg = dalloc(n_nab_sites), /* Gathered neig. site charges*/ *forceij = dalloc(n_nab_sites), /* -V'(r) / r */ *R = dalloc(n_nab_sites); /* pbc site relocation cpt */ real **nab_pot /* Gathere'd pot par array */ = (real**)arralloc((size_mt)sizeof(real), 2, 0, system->n_potpar-1, 0, n_nab_sites-1); real force_cpt, site0, site1, site2, s00, s01, s02, s11, s12, s22; register real rrx,rry,rrz; real reloc_v[3][CUBE(NSHELL)]; /* PBC relocation vectors */ real **pp, **ppp; int ix, iy, iz; /* 3-d cell indices for ref and neig. */ int icell, /* Index for cells of molecule pair */ nnab, jbeg, jmin, jmax, /* Number of sites in neighbour list */ isite, jsite, ipot, lim; int nsites = system -> nsites; int nfnab[2]; cell_mt *cmol; double norm = 2.0*control.alpha/sqrt(PI); /* Coulombic prefactor*/ double cutoffsq = SQR(control.cutoff), cutoff100sq = 10000.0*cutoffsq; s00 = s01 = s02 = s11 = s12 = s22 = 0.0; /* Accumulators for stress */ reloc_alloc(system->h, reloc_v); #ifdef DEBUG6 { int i; for(i = 0; i < CUBE(NSHELL); i++) printf("%f %f %f\n", reloc_v[0][i], reloc_v[1][i], reloc_v[2][i]); } #endif /****************************************************************************** * Start of main loops. Loop over species, ispec, molecules, imol, and * * sites, isite_mol on imol. Isite is index into 'site' of site specified * * by isite_mol, imol and ispec. Jbase is set to first site of imol+1, ispec* * so jsite, counts from jbase to end. Thus isite, jsite run over all site * * site pairs on distinct molecules. * ******************************************************************************/ for( icell = ithread; icell < nx*ny*nz; icell += nthreads) { if(cell[icell] == NULL) continue; /* Empty cell - go on to next */ ix = icell/ (ny*nz); iy = icell/nz - ny*ix; iz = icell - nz*(iy + ny*ix); nnab = 0; #ifdef DEBUG1 printf("Working on cell %4d (%d,%d,%d) (sites %4d to %4d)\n", icell, ix,iy,iz,cell[icell]->isite,cell[icell]->isite+cell[icell]->num-1); printf("\n jcell\tjx jy jz\tNsites\n"); #endif /* * Build site neighbour list 'nab' from cell list. */ nnab = site_neighbour_list(nab, reloc_i,n_nab_sites,nfnab,n_frame_types, n_nabors, ix, iy, iz, nabor, cell, reloc, work); #ifdef DEBUG4 for(jsite=0; jsitenext) { if( cmol->frame_type ) { jmin = 0; jmax = nfnab[0]; } else { jmin = jbeg += cmol->num; jmax = nnab; } lim = cmol->isite + cmol->num; for(isite = cmol->isite; isite < lim; isite++) { /* Loop over sites in molecule */ pp = potp[id[isite]]; ppp = nab_pot; for(ipot = 0; ipot < system->n_potpar; ipot++) { gather(jmax, *ppp++, *pp++, nab, nsites); } #ifdef DEBUG1 if(isite == 100) #endif #if defined(DEBUG1) || defined(DEBUG5) { int jnab; for(jnab = jmin; jnab < jmax; jnab++) printf("%4d %4d\n", jnab,nab[jnab]); } #endif site0=site[0][isite]; site1=site[1][isite]; site2=site[2][isite]; VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { rrx = nab_sx[jsite] - site0; rry = nab_sy[jsite] - site1; rrz = nab_sz[jsite] - site2; r_sqr[jsite] = rrx*rrx+rry*rry+rrz*rrz; rx[jsite] = rrx; ry[jsite] = rry; rz[jsite] = rrz; } if( (jsite = jmin+search_lt(jmax-jmin, r_sqr+jmin, 1, TOO_CLOSE)) < jmax ) message(NULLI, NULLP, WARNING, TOOCLS, isite, nab[jsite], sqrt(TOO_CLOSE)); if( control.strict_cutoff ) for(jsite = jmin; jsite < jmax; jsite++) if( r_sqr[jsite] > cutoffsq ) r_sqr[jsite] = cutoff100sq; #ifdef DEBUG2 hist(jmin, jmax, r_sqr); #endif /* Call the potential function kernel */ kernel(jmin, jmax, forceij, pe, r_sqr, nab_chg, chg[isite], norm, control.alpha, system->ptype, nab_pot); site0 = site1 = site2 = 0.0; VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { force_cpt = forceij[jsite]*rx[jsite]; s00 += force_cpt * rx[jsite]; s02 += force_cpt * rz[jsite]; s01 += force_cpt * ry[jsite]; site0 -= force_cpt; forcejx[jsite] += force_cpt; } VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { force_cpt = forceij[jsite]*ry[jsite]; s11 += force_cpt * ry[jsite]; s12 += force_cpt * rz[jsite]; site1 -= force_cpt; forcejy[jsite] += force_cpt; } VECTORIZE for(jsite=jmin; jsite < jmax; jsite++) { force_cpt = forceij[jsite]*rz[jsite]; s22 += force_cpt * rz[jsite]; site2 -= force_cpt; forcejz[jsite] += force_cpt; } site_force[0][isite] += site0; site_force[1][isite] += site1; site_force[2][isite] += site2; #ifdef DEBUG3 printf("PE = %f\n",pe[0]); #endif } } spxpy(nnab, forcejx, site_force[0], nab); spxpy(nnab, forcejy, site_force[1], nab); spxpy(nnab, forcejz, site_force[2], nab); } stress[0][0] += s00; stress[0][1] += s01; stress[0][2] += s02; stress[1][1] += s11; stress[1][2] += s12; stress[2][2] += s22; afree((gptr*)nab_pot); xfree(work); xfree(nab); xfree(reloc_i); xfree(nab_chg); xfree(r_sqr); xfree(R); xfree(forceij); xfree(rx); xfree(ry); xfree(rz); xfree(forcejx); xfree(forcejy); xfree(forcejz); xfree(nab_sx); xfree(nab_sy); xfree(nab_sz); } $EOD $! $CREATE ewald-RIL.c $DECK /* MOLecular DYnamics simulation code, Moldy. Copyright (C) 1988, 1992, 1993 Keith Refson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ /****************************************************************************** * Ewald The reciprocal-space part of the standard Ewald sum technique * ****************************************************************************** * Revision Log * $Log: ewald.c,v $ * Revision 2.8.1.6 1996/11/12 15:33:52 keith * Updated to match Ewald.c 2.13 with cache tuning etc. * * Revision 2.8.1.5 1996/03/25 17:36:15 keith * Fixed memory leak introduced in previous revision. * Now prints # k-vectors just like RKL version * * Revision 2.8.1.4 1996/02/07 20:51:44 keith * Restructured for convergence of std and RIL versions * - Implemented pre-computed k-vector set * - Re-based trig arrays to start at zero for ANSI conformance. * * Revision 2.8.1.3 1996/01/25 21:01:41 keith * Fixed bug in allocation of sites to processors which caused * crash on large # procs. * * Revision 2.8.1.2 1995/12/06 15:07:50 keith * Fixed bug which caused core dump for small k-cutoff (hmax=0) * * Revision 2.8.1.2 1994/12/30 11:53:51 keith * Finxed bug which caused core dump for small k-cutoff (hmax=0) * * Revision 2.8.1.1 1994/07/19 10:40:57 keith * Implementation of W. Smith's RIL parallelization strategy * (Comp Phys Commun, 67, (1992) 293-406 * This involves distributing memory better but does communication * in the inner k-vector loop. On most machines this seems to * defeat the parallelization altogether - it runs more slowly * in parallel on the Titan than in serial mode even for 32772 sites. * * Revision 2.8 1994/06/22 09:37:02 keith * Performance optimization of "trig rules" loops. * * Revision 2.7 1994/06/08 13:13:59 keith * New version of array allocator which breaks up requests for DOS. * Now must use specific "afree()" paired with arralloc(). * * Revision 2.6 1994/02/17 16:38:16 keith * Significant restructuring for better portability and * data modularity. * * Got rid of all global (external) data items except for * "control" struct and constant data objects. The latter * (pot_dim, potspec, prog_unit) are declared with CONST * qualifier macro which evaluates to "const" or nil * depending on ANSI/K&R environment. * Also moved as many "write" instantiations of "control" * members as possible to "startup", "main" leaving just * "dump". * * Declared as "static" all functions which should be. * * Revision 2.5 1994/01/18 13:32:27 keith * Null update for XDR portability release * * Revision 2.3 93/10/28 10:27:48 keith * Corrected declarations of stdargs functions to be standard-conforming * * Revision 2.1 93/09/02 12:31:55 keith * Optimized qsincos() -- should give up to 25% speed improvement on * compilers without assert no aliasing options. * * Revision 2.1 93/05/17 10:42:22 keith * Optimized qsincos() -- should give up to 25% speed improvement on * compilers without assert no aliasing options. * * Revision 2.0 93/03/15 14:49:02 keith * Added copyright notice and disclaimer to apply GPL * to all modules. (Previous versions licensed by explicit * consent only). * * Revision 1.23 93/03/12 12:22:38 keith * Reorganized defines to recognise all ANSI (__type__) forms. * Moved spxpy() from aux.c to force.c and force_parallel.c * * * Revision 1.23 93/03/12 12:21:50 keith * *** empty log message *** * * Revision 1.22 93/03/09 15:58:28 keith * Changed all *_t types to *_mt for portability. * Reordered header files for GNU CC compatibility. * * Revision 1.21 92/06/26 17:02:58 keith * Got rid of assumption that memory returned by talloc() or * arralloc() is zeroed. This enhances ANSI compatibility. * Removed memory zeroing from alloc.c() in consequence. * * Revision 1.20 91/11/26 10:26:34 keith * Corrected calculation of sheet energy term for charged framework. * Split force loop so as to omit frame-frame force (and stress) terms. * * Revision 1.19 91/08/15 18:11:52 keith * Modifications for better ANSI/K&R compatibility and portability * --Changed sources to use "gptr" for generic pointer -- typedefed in "defs.h" * --Tidied up memcpy calls and used struct assignment. * --Moved defn of NULL to stddef.h and included that where necessary. * --Eliminated clashes with ANSI library names * --Modified defs.h to recognise CONVEX ANSI compiler * --Modified declaration of size_mt and inclusion of sys/types.h in aux.c * for GNU compiler with and without fixed includes. * * Revision 1.18 91/05/29 16:33:01 keith * Modified code for speed improvement in TITAN * * Revision 1.17 91/03/12 15:42:31 keith * Tidied up typedefs size_mt and include file * Added explicit function declarations. * * Revision 1.16 91/02/07 16:52:18 keith * Rewrote trig identity loops for better vectorization on Titan. * Finally deleted ancient commented-out code (#if OLDEWALD and VCALLS). * * Revision 1.15 90/09/28 13:29:15 keith * Inserted braces around VECTORIZE directives and changed include files * for STARDtardent 3000 series (via cond. comp symbol "ardent"). * * Revision 1.14 90/08/29 11:01:19 keith * Modified to keep consistency with ewald_parallel.c r1.8 * * Revision 1.13 90/08/02 15:50:17 keith * Modified to exclude framework-framework interactions. * N.B. Excluded from pe and stress but NOT forces (as they sum to 0). * * Revision 1.12 90/05/16 18:40:04 keith * Renamed own freer from cfree to tfree. * * Revision 1.11 90/05/02 15:33:27 keith * Make declaration of saxpy() conditional along with use. * * Revision 1.10 90/01/15 12:24:05 keith * Corrected declaration of arralloc from void* to char* to keep lint happy. * * Revision 1.9 90/01/01 20:07:20 keith * Parcelled up generation of qcoskr etc into separate function and * created temp's site_fx etc to point at site_force[0] etc. * - Generates substabtially better code on Stellar. * * Revision 1.8 89/12/22 19:31:53 keith * New version of arralloc() orders memory so that pointers come FIRST. * This means you can simply free() the pointer returned (if l.b. = 0). * * Revision 1.7 89/12/21 16:29:47 keith * Reversed indices in 'site' and 'site_force' to allow stride of 1 in ewald. * * Revision 1.6 89/12/15 12:56:26 keith * Added conditional ionclusion of for stellar * * Revision 1.5 89/11/01 17:29:10 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * 'Uniform charge sheet' term added in case of electrically charged system. * * Revision 1.5 89/10/26 11:29:26 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * 'Uniform charge sheet' term added in case of electrically charged layer. * * Revision 1.5 89/10/26 11:27:31 keith * Sin and cos loop vectorised - mat_vec_mul extracted from loop. * * Revision 1.4 89/10/02 11:39:14 keith * Fixed error in *star macros which assumed rlv's were cols of h(-1) r.t. rows. * * Revision 1.3 89/06/09 13:38:17 keith * Older code for computation of q cos/sin k.r restored conditionally by * use of macro OLDEWALD. This is for more primitive vectorising compilers. * * Revision 1.2 89/06/08 10:42:51 keith * Modified to circumvent compiler bug in VMS/VAXC 2.4-026 * * Revision 1.1 89/04/20 16:00:39 keith * Initial revision * */ #ifndef lint static char *RCSid = "$Header: /home/eeyore_data/keith/md/moldy/RCS/ewald.c,v 2.8.1.6 1996/11/12 15:33:52 keith Exp $"; #endif /*========================== Program include files ===========================*/ #include "defs.h" /*========================== Library include files ===========================*/ #ifdef stellar # include #else #ifdef titan # include #else # include #endif #endif #include "stddef.h" #include "stdlib.h" #include "string.h" /*========================== Program include files ===========================*/ #include "structs.h" #include "messages.h" /*========================== External function declarations ==================*/ gptr *talloc(); /* Interface to memory allocator */ void tfree(); /* Free allocated memory */ void afree(); /* Free allocated array */ double err_fn(); /* Error function */ double det(); /* Determinant of 3x3 matrix */ void invert(); /* Inverts a 3x3 matrix */ void mat_vec_mul(); /* Multiplies a 3x3 matrix by 3xN vect*/ void mat_sca_mul(); /* Multiplies a 3x3 matrix by scalar */ void transpose(); /* Transposes a 3x3 matrix */ void zero_real(); /* Initialiser */ void zero_double(); /* Initialiser */ double sum(); /* Sum of elements of 'real' vector */ #if defined(ANSI) || defined(__STDC__) gptr *arralloc(size_mt,int,...); /* Array allocator */ void note(char *,...); /* Write a message to the output file */ void message(int *,...); /* Write a warning or error message */ #else gptr *arralloc(); /* Array allocator */ void note(); /* Write a message to the output file */ void message(); /* Write a warning or error message */ #endif /*========================== External data references ========================*/ extern contr_mt control; /* Main simulation control record */ extern int ithread, nthreads; /*========================== Macros ==========================================*/ #define astar hinvp[0] #define bstar hinvp[1] #define cstar hinvp[2] #define moda(hmat) (hmat[0][0]) #define modb(hmat) sqrt(SQR(hmat[0][1]) + SQR(hmat[1][1])) #define modc(hmat) sqrt(SQR(hmat[0][2]) + SQR(hmat[1][2]) + SQR(hmat[2][2])) /*========================== Cache Parameters=================================*/ /* The default values are for the Cray T3D but are probably good enough * for most other systems too. */ #ifndef NCACHE # define NCACHE (256*sizeof(double)/sizeof(real)) #endif #ifndef NLINE # define NLINE (4*sizeof(double)/sizeof(real)) #endif /*============================================================================*/ struct s_hkl {double kx, ky, kz; int h,k,l;}; /***************************************************************************** * qsincos(). Evaluate q sin(k.r) and q cos(k.r). This is in a separate * * function because some compilers (notably Stellar's) generate MUCH better * * vector code this way. * *****************************************************************************/ static void qsincos(coshx,sinhx,cosky,sinky,coslz,sinlz,chg, qcoskr,qsinkr,k,l,nsites) real coshx[], sinhx[], cosky[], sinky[], coslz[], sinlz[], chg[], qcoskr[], qsinkr[]; int k,l,nsites; { int is; real qckr; if( k >= 0 ) if( l >= 0 ) { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*coslz[is] - (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*coslz[is] + (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*coslz[is] + (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] + coshx[is]*sinky[is])*coslz[is] - (coshx[is]*cosky[is] - sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else if( l >= 0 ) { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*coslz[is] - (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*coslz[is] + (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } else { VECTORIZE for(is = 0; is < nsites; is++) { qckr = chg[is]*( (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*coslz[is] + (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*sinlz[is]); qsinkr[is] = chg[is]*( (sinhx[is]*cosky[is] - coshx[is]*sinky[is])*coslz[is] - (coshx[is]*cosky[is] + sinhx[is]*sinky[is])*sinlz[is]); qcoskr[is] = qckr; } } } /****************************************************************************** * Calculate cos and sin of astar*x, bstar*y & cstar*z for each charged site * * Use addition formulae to get sin(h*astar*x)=sin(Kx*x) etc for each site * ******************************************************************************/ static void trig_recur(chx,shx,sin1x,cos1x,site0,site1,site2,kstar,hmax,ns0,ns1) real **chx, **shx, sin1x[],cos1x[], *site0, *site1, *site2, *kstar; int ns0, ns1, hmax; { int h, is; real *coshx, *sinhx, *cm1, *sm1, coss, kr; real ksx = kstar[0], ksy = kstar[1], ksz = kstar[2]; sinhx = shx[0]; coshx = chx[0]; VECTORIZE for(is = ns0; is < ns1; is++) { coshx[is] = 1.0; sinhx[is] = 0.0; } if( hmax >= 1 ) { coshx = chx[1]; sinhx = shx[1]; VECTORIZE for(is = ns0; is < ns1; is++) { kr = ksx*site0[is]+ksy*site1[is]+ksz*site2[is]; coshx[is] = cos(kr); sinhx[is] = sin(kr); } memcp(cos1x+ns0, coshx+ns0, (ns1-ns0)*sizeof(real)); memcp(sin1x+ns0, sinhx+ns0, (ns1-ns0)*sizeof(real)); for(h = 2; h <= hmax; h++) { coshx = chx[h]; sinhx = shx[h]; cm1 = chx[h-1]; sm1 = shx[h-1]; VECTORIZE for(is = ns0; is < ns1; is++) { coss = cm1[is]*cos1x[is] - sm1[is]*sin1x[is]; sinhx[is] = sm1[is]*cos1x[is] + cm1[is]*sin1x[is]; coshx[is] = coss; } } } } /****************************************************************************** * allocate_arrays(). Memory allocation for Ewald's arrays. We malloc one * * large block and divide it out so as to precisely control the relative * * offsets of the arrays. This is to avoid cache conflicts. * * Revert to bog-standard method for MSDOS * ******************************************************************************/ static real* allocate_arrays(nsarray, hmax, kmax, lmax, chx, cky, clz, shx, sky, slz, chg, cos1x, cos1y, cos1z, sin1x, sin1y, sin1z, qcoskr, qsinkr) int nsarray, hmax, kmax, lmax; real ***chx, ***cky, ***clz, ***shx, ***sky, ***slz; real **cos1x, **cos1y, **cos1z, **sin1x, **sin1y, **sin1z; real **chg, **qcoskr, **qsinkr; { int h, k,l; real *csp, *base; #ifndef __MSDOS__ /* * Attempt to cache-align these arrays for optimum performance. * This requires NON-ANSI pointer conversion and arithmetic. * It should work with any UNIX address space, so make it conditional. */ base = dalloc((2*(hmax+kmax+lmax)+15)*nsarray+10*NLINE+NCACHE); #if defined(unix) && !defined(__BOUNDS_CHECKING_ON) csp = (real*)0 + (((base - (real*)0) - 1 | NCACHE-1) + 1); #else csp = base; #endif *chx = (real**)arralloc(sizeof(real*),1,0,hmax); *cky = (real**)arralloc(sizeof(real*),1,0,kmax); *clz = (real**)arralloc(sizeof(real*),1,0,lmax); *shx = (real**)arralloc(sizeof(real*),1,0,hmax); *sky = (real**)arralloc(sizeof(real*),1,0,kmax); *slz = (real**)arralloc(sizeof(real*),1,0,lmax); *qcoskr = csp; csp += nsarray + NLINE; *qsinkr = csp; csp += nsarray + NLINE; *chg = csp; csp += nsarray + NLINE; for(h = 0; h <= hmax; h++, csp += nsarray) (*chx)[h] = csp; csp += NLINE; for(h = 0; h <= hmax; h++, csp += nsarray) (*shx)[h] = csp; csp += NLINE; for(k = 0; k <= kmax; k++, csp += nsarray) (*cky)[k] = csp; csp += NLINE; for(k = 0; k <= kmax; k++, csp += nsarray) (*sky)[k] = csp; csp += NLINE; for(l = 0; l <= lmax; l++, csp += nsarray) (*clz)[l] = csp; csp += NLINE; for(l = 0; l <= lmax; l++, csp += nsarray) (*slz)[l] = csp; csp += NLINE; *cos1x = csp; csp += nsarray; *cos1y = csp; csp += nsarray; *cos1z = csp; csp += nsarray + NLINE; *sin1x = csp; csp += nsarray; *sin1y = csp; csp += nsarray; *sin1z = csp; csp += nsarray; #else *chx = (real**)arralloc((size_mt)sizeof(real),2, 0, hmax, 0, nsarray-1); *cky = (real**)arralloc((size_mt)sizeof(real),2, 0, kmax, 0, nsarray-1); *clz = (real**)arralloc((size_mt)sizeof(real),2, 0, lmax, 0, nsarray-1); *shx = (real**)arralloc((size_mt)sizeof(real),2, 0, hmax, 0, nsarray-1); *sky = (real**)arralloc((size_mt)sizeof(real),2, 0, kmax, 0, nsarray-1); *slz = (real**)arralloc((size_mt)sizeof(real),2, 0, lmax, 0, nsarray-1); *cos1x = (*chx)[1]; *cos1y = (*cky)[1]; *cos1z = (*clz)[1]; *sin1x = (*shx)[1]; *sin1y = (*sky)[1]; *sin1z = (*slz)[1]; csp = base = dalloc(3*nsarray); *chg = csp; csp += nsarray; *qcoskr = csp; csp += nsarray; *qsinkr = csp; csp += nsarray; #endif return base; } /****************************************************************************** * Ewald Calculate reciprocal-space part of coulombic forces * ******************************************************************************/ void ewald(site,site_force,system,species,chgx,pe,stress) real **site, /* Site co-ordinate arrays (in) */ **site_force; /* Site force arrays (out) */ system_mp system; /* System record (in) */ spec_mt species[]; /* Array of species records (in) */ real chgx[]; /* Array of site charges (in) */ double *pe; /* Potential energy (out) */ mat_mt stress; /* Stress virial (out) */ { mat_mt hinvp; /* Matrix of reciprocal lattice vects*/ int h, k, l; /* Recip. lattice vector indices */ int i, j, is, ssite; /* Counters. */ spec_mp spec; /* species[ispec] */ int nsites = system->nsites; double pe_k, /* Pot'l energy for current K vector */ coeff, coeff2; /* 2/(e0V) * A(K) & similar */ double r_4_alpha = -1.0/(4.0 * control.alpha * control.alpha); double sqcoskr,sqsinkr, /* Sum q(i) sin/cos(K.r(i)) */ sqcoskrn, sqsinkrn, sqcoskrf, sqsinkrf; double ksq, /* Squared magnitude of K vector */ kcsq = SQR(control.k_cutoff); double kx,ky,kz,kzt; vec_mt kv; /* (Kx,Ky,Kz) */ real force_comp, kv0, kv1, kv2, sfx, sfy; struct s_hkl *hkl, *phkl; int nhkl = 0; /* * Maximum values of h, k, l s.t. |k| < k_cutoff */ int hmax = floor(control.k_cutoff/(2*PI)*moda(system->h)), kmax = floor(control.k_cutoff/(2*PI)*modb(system->h)), lmax = floor(control.k_cutoff/(2*PI)*modc(system->h)); real sqexpkr[4]; mat_mt stress_ew; /* * lower and upper limits for parallel loops. This doles out the sites * in parcels of "nsnode0" sites on "nns" threads and "nsnode0+1" sites * on the rest. "ns0" marks the beginning of the sites for this thread * and "nsarr0" the number of sites allocated to the node. * N. B. The parcelling algorithm in W. Smith's paper FAILS if * nthreads**2 > nsites. */ int nsnode0 = nsites/nthreads; int nns = nthreads*(nsnode0 + 1 ) - nsites; int nsarr0 = nsnode0 + ((ithread < nns)?0:1); int ns0 = MIN(ithread, nns)*nsnode0 + MAX(ithread-nns,0)*(nsnode0+1); int ns1 = ns0 + nsarr0, ns0f, ns1f; /* * Round up size of arrays to cache sub-multiple size. */ #if 1 int nsarray = (nsarr0 - 1 | NCACHE - 1) + 1; #else int nsarray = nsarr0; #endif /* * Arrays for cos & sin (h x(i)), (k y(i)) and (l z(i)) eg chx[h][isite] * and pointers to a particular h,k or l eg coshx[is] = chh[2][is] */ real **chx, **cky, **clz, **shx, **sky, **slz; real *cshkl; real *coshx, *cosky, *coslz, *sinhx, *sinky, *sinlz; real *cos1x, *cos1y, *cos1z, *sin1x, *sin1y, *sin1z; real *chg; real *site_fx = site_force[0]+ns0, *site_fy = site_force[1]+ns0, *site_fz = site_force[2]+ns0; real *qcoskr, /* q(i) cos(K.R(i)) */ *qsinkr; /* q(i) sin(K.R(i)) */ double vol = det(system->h); /* Volume of MD cell */ static double self_energy, /* Constant self energy term */ sheet_energy; /* Correction for non-neutral system. */ static boolean init = true; /* Flag for the first call of function*/ static int nsitesxf; /* Number of non-framework sites. */ /* * Trig array set-up. The precise storage layout is to avoid cache conflicts. */ cshkl = allocate_arrays(nsarray, hmax, kmax, lmax, &chx, &cky, &clz, &shx, &sky, &slz, &chg, &cos1x, &cos1y, &cos1z, &sin1x, &sin1y, &sin1z, &qcoskr, &qsinkr); memcp(chg, chgx+ns0, nsarr0*lsizeof(real)); /* * First call only - evaluate self energy term and store for subsequent calls * Self energy includes terms for non-framework sites only. */ if(init) { double sqsq = 0, sq = 0, sqxf, intra, r; int js, frame_flag; self_energy = sheet_energy = 0; ssite = 0; spec = species; while( spec < species+system->nspecies && ! spec->framework) { intra = 0.0; for(is = 0; is < spec->nsites; is++) for(js = is+1; js < spec->nsites; js++) { r = DISTANCE(spec->p_f_sites[is], spec->p_f_sites[js]); intra += chgx[ssite+is] * chgx[ssite+js] *err_fn(control.alpha * r) / r; } self_energy += spec->nmols * intra; ssite += spec->nsites*spec->nmols; spec++; } nsitesxf = ssite; frame_flag = (spec != species+system->nspecies); for(is = 0; is < nsitesxf; is++) { sq += chgx[is]; sqsq += SQR(chgx[is]); } self_energy += control.alpha / sqrt(PI) * sqsq; /* * Sqxf is total non-framework charge. Calculate grand total in sq. */ sqxf = sq; for(; is < nsites; is++) sq += chgx[is]; /* * Charged-system/uniform sheet correction terms (really in direct * space term but included here for convenience). * 1) For charged framework only. */ if( frame_flag ) { sheet_energy = PI*SQR(sq-sqxf) / (2.0*SQR(control.alpha)); message(NULLI, NULLP, INFO, FRACHG, (sq-sqxf)*CONV_Q, sheet_energy/vol*CONV_E); } /* * 2) Case of entire system non-neutral. */ if( fabs(sq)*CONV_Q > 1.0e-5) { sheet_energy -= intra = PI*SQR(sq) / (2.0*SQR(control.alpha)); message(NULLI, NULLP, WARNING, SYSCHG, sq*CONV_Q, intra/vol*CONV_E); } note("Ewald self-energy = %f Kj/mol",self_energy*CONV_E); } *pe -= self_energy; /* Subtract self energy term */ *pe += sheet_energy/vol; /* Uniform charge correction */ zero_real(stress_ew, 9); for(i=0; i<3; i++) stress_ew[i][i] += sheet_energy/vol; invert(system->h, hinvp); /* Inverse of h is matrix of r.l.v.'s */ mat_sca_mul(2*PI, hinvp, hinvp); /* * Build array hkl[] of k vectors within cutoff */ hkl = aalloc(4*(hmax+1)*(kmax+1)*(lmax+1), struct s_hkl); for(h = 0; h <= hmax; h++) for(k = (h==0 ? 0 : -kmax); k <= kmax; k++) { kx = h*astar[0] + k*bstar[0]; ky = h*astar[1] + k*bstar[1]; kzt = h*astar[2] + k*bstar[2]; ksq = SQR(kx) + SQR(ky); for(l = (h==0 && k==0 ? 1 : -lmax); l <= lmax; l++) { kz = kzt + l*cstar[2]; if( SQR(kz)+ksq < kcsq ) { hkl[nhkl].h = h; hkl[nhkl].k = k; hkl[nhkl].l = l; hkl[nhkl].kx = kx; hkl[nhkl].ky = ky; hkl[nhkl].kz = kz; nhkl++; } } } if( init ) note("%d K-vectors included in reciprocal-space sum",nhkl); init = false; /* * Calculate cos and sin of astar*x, bstar*y & cstar*z for each charged site * Use addition formulae to get sin(h*astar*x)=sin(Kx*x) etc for each site */ trig_recur(chx,shx,sin1x,cos1x, site[0]+ns0,site[1]+ns0,site[2]+ns0,astar,hmax,0,nsarr0); trig_recur(cky,sky,sin1y,cos1y, site[0]+ns0,site[1]+ns0,site[2]+ns0,bstar,kmax,0,nsarr0); trig_recur(clz,slz,sin1z,cos1z, site[0]+ns0,site[1]+ns0,site[2]+ns0,cstar,lmax,0,nsarr0); /* * Start of main loops over K vector indices h, k, l between -*max, *max etc. * To avoid calculating K and -K, only half of the K-space box is covered. * Points on the axes are included once and only once. (0,0,0) is omitted. */ for(phkl = hkl; phkl < hkl+nhkl; phkl++) { /* * Calculate actual K vector and its squared magnitude. */ h = phkl->h; k = phkl->k; l = phkl->l; kv0 = kv[0] = phkl->kx; kv1 = kv[1] = phkl->ky; kv2 = kv[2] = phkl->kz; ksq = SUMSQ(kv); /* * Calculate pre-factors A(K) etc */ coeff = 2.0 / (EPS0 * vol) * exp(ksq * r_4_alpha) / ksq; coeff2 = 2.0 * (1.0 - ksq * r_4_alpha) / ksq; /* * Set pointers to array of cos (h*astar*x) (for efficiency & vectorisation) */ coshx = chx[h]; cosky = cky[abs(k)]; coslz = clz[abs(l)]; sinhx = shx[h]; sinky = sky[abs(k)]; sinlz = slz[abs(l)]; /* * Calculate q(i)*cos/sin(K.R(i)) by addition formulae. Note handling of * negative k and l by using sin(-x) = -sin(x), cos(-x) = cos(x). For * efficiency & vectorisation there is a loop for each case. */ qsincos(coshx,sinhx,cosky,sinky,coslz,sinlz,chg, qcoskr,qsinkr,k,l,nsarr0); ns1f = MIN(ns1, nsitesxf); ns0f = MAX(ns0, nsitesxf); sqexpkr[0] = sum(ns1f-ns0, qcoskr, 1); sqexpkr[1] = sum(ns1f-ns0, qsinkr, 1); sqexpkr[2] = sum(ns1-ns0f, qcoskr+(ns0f-ns0), 1); sqexpkr[3] = sum(ns1-ns0f, qsinkr+(ns0f-ns0), 1); #ifdef SPMD par_rsum(sqexpkr, 4); #endif sqcoskrn = sqexpkr[0]; sqsinkrn = sqexpkr[1]; sqcoskrf = sqexpkr[2]; sqsinkrf = sqexpkr[3]; sqcoskr = sqcoskrn + sqcoskrf; sqsinkr = sqsinkrn + sqsinkrf; /* * Evaluate potential energy contribution for this K and add to total. * Exclude frame-frame interaction terms. */ pe_k = 0.5 * coeff * (sqcoskrn*(sqcoskrn+sqcoskrf+sqcoskrf) + sqsinkrn*(sqsinkrn+sqsinkrf+sqsinkrf)); *pe += pe_k; sqsinkr *= coeff; sqcoskr *= coeff; sqsinkrn *= coeff; sqcoskrn *= coeff; /* * Calculate long-range coulombic contribution to stress tensor */ NOVECTOR for(i = 0; i < 3; i++) { stress_ew[i][i] += pe_k; NOVECTOR for(j = i; j < 3; j++) stress_ew[i][j] -= pe_k * coeff2 * kv[i] * kv[j]; } /* * Evaluation of site forces. Non-framework sites interact with all others */ VECTORIZE for(is = 0; is < ns1f-ns0; is++) { force_comp = qsinkr[is]*sqcoskr - qcoskr[is]*sqsinkr; sfx = site_fx[is] + kv0 * force_comp; sfy = site_fy[is] + kv1 * force_comp; site_fz[is] += kv2 * force_comp; site_fx[is] = sfx; site_fy[is] = sfy; } /* * Framework sites -- only interact with non-framework sites */ VECTORIZE for(is = ns0f-ns0; is < ns1-ns0; is++) { force_comp = qsinkr[is]*sqcoskrn - qcoskr[is]*sqsinkrn; sfx = site_fx[is] + kv0 * force_comp; sfy = site_fy[is] + kv1 * force_comp; site_fz[is] += kv2 * force_comp; site_fx[is] = sfx; site_fy[is] = sfy; } /* * End of loop over K vectors. */ } *pe /= nthreads; for(i=0; i<3; i++) for(j=0; j<3; j++) stress[i][j] += stress_ew[i][j] / nthreads; afree((gptr*)chx); afree((gptr*)cky); afree((gptr*)clz); afree((gptr*)shx); afree((gptr*)sky); afree((gptr*)slz); xfree(cshkl); xfree(hkl); } $EOD $! $CREATE getopt.c $DECK /* I got this off net.sources from Henry Spencer. It is a public domain getopt(3) like in System V. I have made the following modifications: index(s,c) was added because too many people could not compile getopt without it. A test main program was added, ifdeffed by GETOPT. This main program is a public domain implementation of the getopt(1) program like in System V. The getopt program can be used to standardize shell option handling. e.g. cc -DGETOPT getopt.c -o getopt */ #include #ifndef lint static char sccsfid[] = "@(#) getopt.c 5.0 (UTZoo) 1985"; #endif #define ARGCH (int)':' #define BADCH (int)'?' #define EMSG "" #define ENDARGS "--" /* this is included because index is not on some UNIX systems */ static char * index (s, c) register char *s; register int c; { while (*s) if (c == *s) return (s); else s++; return (NULL); } /* * get option letter from argument vector */ int opterr = 1, /* useless, never set or used */ optind = 1, /* index into parent argv vector */ optopt; /* character checked for validity */ char *optarg; /* argument associated with option */ #define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \ fputc(optopt,stderr);fputc('\n',stderr);return(BADCH); getopt(nargc,nargv,ostr) int nargc; char **nargv, *ostr; { static char *place = EMSG; /* option letter processing */ register char *oli; /* option letter list index */ char *index(); if(!*place) { /* update scanning pointer */ if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF); if (*place == '-') { /* found "--" */ ++optind; return(EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == ARGCH || !(oli = index(ostr,optopt))) { if(!*place) ++optind; tell(": illegal option -- "); } if (*++oli != ARGCH) { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) optarg = place; /* no white space */ else if (nargc <= ++optind) { /* no arg */ place = EMSG; tell(": option requires an argument -- "); } else optarg = nargv[optind]; /* white space */ place = EMSG; ++optind; } return(optopt); /* dump back option letter */ } #ifdef GETOPT #ifndef lint static char sccspid[] = "@(#) getopt.c 5.1 (WangInst) 6/15/85"; #endif main (argc, argv) char **argv; { char *optstring = argv[1]; char *argv0 = argv[0]; extern int optind; extern char *optarg; int opterr = 0; int C; char *opi; if (argc == 1) { fprintf (stderr, "Usage: %s optstring args\n", argv0); exit (1); } argv++; argc--; argv[0] = argv0; while ((C = getopt (argc, argv, optstring)) != EOF) { if (C == BADCH) opterr++; printf ("-%c ", C); opi = index (optstring, C); if (opi && opi[1] == ARGCH) if (optarg) printf ("\"%s\" ", optarg); else opterr++; } printf ("%s", ENDARGS); while (optind < argc) printf (" \"%s\"", argv[optind++]); putchar ('\n'); exit (opterr); } #endif $EOD $! $CREATE READ.ME $DECK # # ####### # ###### # # ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ####### ####### ###### # Copyright Keith Refson January 1990 All rights reserved Moldy is a general-purpose molecular dynamics simulation program which I wrote initially for my own research into aqueous solutions at mineral surfaces. However it is sufficiently flexible that it ought to be useful for a wide range of simulation calculations of atomic, ionic and molecular systems. Moldy is available by anonymous file transfer from Oxford. Connect to "earth.ox.ac.uk" using "ftp", with an account name of "anonymous" and your email address as password. The relevant files are all in the "/pub" directory and are * moldy-2.yy.tar.gz - The Unix distribution (also for MSDOS/Windoze) * moldy-2.yy.com - The VMS distribution * moldy-manual.ps.Z - The Manual in PostScript form. Note that the distribution files already contain the LaTeX source. Please note that moldy is copyrighted and distributed under the GNU public license which is designed to encourage its distribution and modification. This is to ensure that the source code of moldy and any improvements made to it by anybody remains available to anyone who wishes to use it. If you change or improve Moldy, please tell me and if practical and appropriate I will incorporate your modifications into a future release. I hope that as time goes on Moldy will become yet more comprehensive as a result of your input. I am also keeping a list of email addresses of anyone who uses the program for notification of updates, bugs and so forth. Please notify me if you would like to be added to this list, preferably by email to Keith.Refson@earth.ox.ac.uk. Contents of the distribution: accel.c algorith.c alloc.c ansi.c auxil.c beeman.c These files are the source code for Moldy. convert.c dump.c ewald.c force.c input.c eigens.c kernel.c main.c matrix.c output.c quaterns.c rdf.c restart.c startup.c values.c xdr.c parallel.c defs.h messages.h 'Include' files for above files structs.h xdr.h stddef.h time.h replacement ANSI C include files for non-ANSI systems. stdlib.h string.h dumpanal.c dumpconv.c dumpext.c Source code for 'utility' programs. mdshak.c mextract.c getopt.c Support routine for utility progs. Makefile Make file for Moldy. compile.com Master compile file for VMS. Calls all the others. compile_moldy.com Compile file for "moldy" itself. compile_utils.com Link file for "moldy" itself. link_moldy.com Compile file for utilities. link_utils.com Link file for utilities. defcomm.com Defines comands - execute from your LOGIN.COM moldy.tex LaTeX source for manual moldy.bbl fig_*.ps Encapsulated Postscript versions of figures. fig_*.tex LaTeX annotation for figures. fig_*-eepic.tex Alternative version of figures in eepic form. tips2.in tip4p.in methane.in mcy.in mgclh2o.in Example system specification files control.clay argon.in quartz-vbst.in control.mgclh2o control.tip4p Example control files control.water control.clay control.argon control.tips2 control.quartz control.mgclh2o water-example.out argon-example.out Output from example runs in manual tips2-example.out tip4p-example.out mgclh2o-example.out quartz-example.out clay-example.out UNPACKING --------- A. Unix distribution This distribution of Moldy takes the form of a compressed tar archive. The archive is unpacked with % gunzip moldy.tar (.gz) or % uncompress moldy.tar (.Z) % tar xvf moldy.tar B. VMS The VMS version of Moldy comes as a DCL archive, moldy.com. To unpack: $ @moldy This creates all the files needed in the current directory. Alternatively, versions of "uncompress" and "tar" are available for VMS, though they are not standard. If you have them then you can unpack the "moldy.tar.Z" archive (suitably renamed) in the same way. COMPILING --------- Here are some brief notes. There are more detailed instructions in the manual. A. UNIX Stage 1. You ought to be able to type "make moldy utilities" on just about any flavour of unix and build a working version. However if you want to get the best performance you will have to work a bit harder with compiler options. You may also find that the compile fails for obscure reasons. Don't worry, some compile options will probably sort that out too. Stage 2. Edit "Makefile", choose a suitable set of compiler options for your machine and uncomment them. Moldy has been test compiled on most modern workstations as well as vector super and minisuper-computers, so you only have to select the preset options. Stage 3. This section describes how to "hand-tune" compiler options. If you get this far you have probably got a different machine or compiler system from any of the tested ones. Moldy recognises a number of C preprocessor macros which adjust its expectations of the compiler and operating system. These are best defined using the "-DMACRO-NAME" option of most unix C compilers. MACRO Purpose ----- ------- The following two macros are used to select the ANSI C "stdarg" mechanism. Default is older "varargs" mechanism. __STDC__ Automatically defined by ANSI compilers in strict mode. ANSI Alternative for ANSI compiler in non-strict mode which does not define __STDC__. ANSI_LIBS Set this if your libraries and header files conform to those expected in the ANSI 89 Standard. Otherwise extra replacement routines and header files to remedy the deficiencies of older systems are included. Set this if at all possible. Only in an ANSI environment can you be sure that all needed headers and library routines will be present. The alternative is a kludge which works most of the time on most machines. This is automatically set in "defs.h" for some machines/compilers vhich are known to have ANSI libraries. USE_XDR Turn on support for the portable binary dump and restart files using the XDR mechanism. This is the only area where Moldy departs substantially from the ANSI C standard so it is optional. Nevertheless it is so massively useful that it is on by default. As this is not part of the standard it may not compile correctly on some systems if the compiler is in "strict ANSI" mode. Use the default or the "relaxed" or "extended" ansi mode often provided. You may well need to add a library to the link using the LDFLAGS variable in the Makefile. For example, solaris 2 on Suns needs the "-lnsl" option and SGI's need the "-lsun" option. You may also need to define some other macro to get the headers correctly included viz: _ALL_SOURCE (IBM RS6000) _HPUX_SOURCE (HPUX) These are needed to enable stuff needed for the XDR routines and headers on IBM and HP machines. N.B. These are actually set automatically in the Moldy header "defs.h" However other systems may require something similar . SPMD Compile for SPMD (Single Program Multiple Data) parallel execution. You must also specify one of the macros BSP, MPI or TCGMSG to select a message-passing library and have the appropriate include paths and libraries defined in the Makefile. BSP/MPI/TCGMSG/SHMEM (parallel.c only) These select the parallel interface library. Portable implementations of the first three are available for most parallel architectures, and MPI should be available on most true parallel machines. MPPMANY (Ewald.c only) Selects parallelization of some of the trig initialization code for the reciprocal-space sum. This is a loser on all but the highest-bandwidth parallel machines. It increases run time on the IBM SP2. However it DOES give a speedup on the T3D when used in conjunction with the SHMEM or BSP library interface. B. VMS (VAX/VMS and OpenVMS/AXP) Just execute the "compile.com" DCL command file which will build Moldy and the utilities. All the required macros are set in "defs.h". It also executes the command file "defcomm.com" which defines the command symbols to execute the programs. It is a good idea to execute this file from your LOGIN.COM to make them available every time you log in. N.B. Depending on how your VMS system is set up you may need to take additional steps to link moldy with the C runtime library. Consult your local documentation or systems staff. If the C library isn't linked by default the command $ assign sys$library:vaxcrtl lnk$library before the executing the compile command file $ @compile may well do the trick. RUNNING ------- Try it out by typing moldy control.water to do a 10 timestep simulation of water. PRINTING THE MANUAL ------------------- The LaTeX source, "moldy.tex" and bibliography file, "moldy.bbl" are supplied. If you have LaTeX, "latex moldy" a couple of times to get the cross-references correct and print the dvi file using dvips or dvi2ps, or whatever dvi output you normally use. There is a "moldy.dvi" target in the make file so just "make moldy.dvi" ought to do the trick. PARALLEL VERSION ---------------- A. Distributed Memory ------------------ To build this version you must have one of the three supported message-passing libraries installed on the target system. These are the Oxford BSP library, MPI (the new standardised message-passing library interface) and TCGMSG (the Theoretical Chamistry message-passing system). Then define the macro PARLIBC in the Makefile to contain the "include" path for the library header files, and the preprocessor symbols SPMD and one of MPI, BSP and TCGMSG. The macro PARLIBL should be defined to link with the appropriate libraries. For the Cray T3D, there is also an interface to the SHMEM libraries which provides the very fastest interprocessor communication. This may be used in conjunction with the MPPMANY option in Ewald.c. To find out how to set up a parallel run, consult the documentation for your parallel system, as this varies. The parallel performance increses with system size as the amount of work in the force and ewald sum loops increases as a proportion of the total work and with respect to the communication overhead. A speedup of nearly 7 on an 8-processor IBM SP1 has been demonstrated for the run "control.big", and in general the larger the system the better the parallel performance. The parallel interface is contained within a single file "parallel.c" and versions for other MP libraries should be relatively easy to add with a few hours of programming effort. Alternative Ewald: ------------------ There is an alternative version of Ewald.c which uses W. Smith's RIL paralellization strategy in ewald-RIL.c. This uses far less memory but at the cost of doing parallel communication in the inner loops. This works reasonably on parallel machines with very short latencies such as the Cray T3D, but on lesser beasts it serializes the whole code! B. Shared memory. ------------- The sources contain separate versions of ewald.c and force.c with the appropriate code and compiler directives for compilation on certain shared-memory parallel machines including Stardent Titan, Convex and Cray architectures. To use, you must REPLACE ewald.c and force.c with the file ewald_parallel.c and force_parallel.c respecively. You must also define the preprocessor symbol PARALLEL during the compilation (eg with the compiler option -DPARALLEL). The code reads the environment to decide how many processors to execute on. The name of the env variable is usually the same one as the manufacturers use for the same purpose NCPUS for the CRAY and THREADS on everything else. Use the SETENV command (for c-chell) or the bourne-shell equivalent to before starting a run. Note. The Stardent Titan version does not work as shipped because the system supplied version of "malloc" can not be safely called from a parallel program. Contact the author for a "thread-safe" version which can. $EOD $! $CREATE BENCHMARK $DECK Using MOLDY as a Benchmark __________________________ Moldy has been tested on a variety of machines and provides a reasonable example of a scientific floating point program which is not a heavy user of I/O or memory. However it does access memory quite rapidly in the inner loops, and in some at 1 memory operation per floating point operation. It is well suited to vector machines but for several reasons does not usually approach the "peak" figure. There are two major parts to the computation. 1) The "Ewald sum" consists mainly of linear passes through arrays doing multiplies and adds, with a few sum reductions. This is expensive on scalar machines but very fast on vector machines with good memory bandwidth. One function, qsincos(), was measured by the PERFTRACE utility on the Cray XMP to be achieving 230 Mflop/s -- exactly the peak! 2) The "real space force calculation" which has some scalar overhead and a vectorisable part which makes heavy use of gather/scatter operations and math library functions, especially sqrt() and exp(). These should all make use of vector hardware but the combination reduces the MFlop rate substantially. It is thus reasonably demanding of both compilers and hardware and tests mainly CPU rate and memory bandwidth. To use: compile and build the program (see READ.ME) and execute with the test case control file "control.water", directing the output to some other file. % moldy control.water > bench.out This run executes 10 timesteps of the standard benchmark test case, and prints timing information as the bottom of the file. The output should be numerically identical to the sample in "water-canon.out", which was run on a SparcStation II. (Floating point roundoff should *not* make any significant difference.) For a reasonable supercomputer this run is probably too short, so try the run in "control.100" (which performs 100 steps) instead, and divide the times by 10. Rules of the Benchmark ______________________ The idea is to allow minor machine-specific optimizations, such as adding compiler directives, replacing the BLAS-like calls in "aux.c" with calls to assembler libraries, but not to change the substance of the algorithm. Minor rewriting of loops to enable efficient vectorization is allowed. The results must, of course, be correct. Parallel Version ________________ This is still experimental and not so portable. It is designed for compilers with the ability to parallelise loops. Replace "ewald.c" and "force.c" with their "x_parallel.c" variants. The loops over the calls to functions "ewald_inner()" and "force_inner()" are the ones which must parallelize, and be executed one iteration per processor. The program reads the environment variable "THREADS" to determine the number of processors to use. This version has been tested on the Stardent 1000, 2000 and 3000 (titan) series machines and the Convex C2 (though it has not been benchmarked on the latter). For the Stardent Titan the macro PARALLEL must be defined for the compilation of main.c and alloc.c to set up correctly for a parallel run. Good luck. Keith Refson, August 1991 $EOD $! $CREATE COPYING $DECK GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. $EOD $! $CREATE RELNOTES $DECK Release 2.11 ------------ * The manual is finished! There is a new chapter on the organization and internals plus other minor rewrites and clarifications. All the LaTeX sources are supplied. You need a modern LaTeX2e installation to format and print it. A preformatted postscript version is also available but not included in the distribution file. * Tuning and optimization for various architectures. - Tuned ewald sum to avoid cache conflicts. Gains of 10-20% on T3D, Sun, DEC, 400% on IBM RS6000 for systems with powers-of-2 numbers of sites. - Tuned compiler options. Gain of 80% on SGI R8000 and Sun SPARC under Solaris 2. - Tuned kernel.c to improve pipelining on DEC Alpha. * Rewrote parts of link-cell short-ranged force in force.c - eliminated huge tables of PBC relocation vectors. got rid of NSH macro and arbitrary limit to cutoff and RDF limit. These are unlimited now. The code is more transparent and easier to understand too. It's also a little bit faster. * Fixed bug in restart file format in 2.10 which meant that thermostat parameters were not stored retrievably. 2.11 can read 2.10 XDR restart files, though you have to reset the thermostat mass parameters and turn thermostatting back on by hand in the control file. For non XDR files there's nothing that can be done. * Fixed initialization problem which caused FP error on Cray T3D (non-ieee) * Corrected error in implementation of integration of thermostat equations of motion. This seems to make no practical diff at all. * Included workaround for bug in Cray T3D compiler version 4.0.5 which caused crash. * Added test for divergent trajectories when running in parallel. * New back-end to "mdshak" program writes "XYZ" format files that can be read by RasMol, XMol, etc. If mdshak is renamed to "mdxyz" this is invoked automatically. Release 2.10 ------------ * Added Nose-Hoover and Hoover (Gaussian) thermostats. (V. Murachov) * Fixed bug in calculation of long-range-correction to pressure. * Fixed bug whereby large rc used with strict-cutoff overran tables and caused crash. Simply tighten up test to abort gracefully. * Fixed bug in reciprocal-space sum where v. small k_cutoff caused crash. * Fixed bug in input parser whereby faulty control file with missing "=" would apparently succeed but in fact return junk. * Many updates an improvements to manual. * Manual now requires LaTeX2e to process the source. * IMPORTANT: Updated fundamental constants to more accurate values from CODATA 1986. This will produce changes of order 1e-5 in some results. If you want to continue using the old values compile with -DOLDCONSTS. * RDF calculation parallelised. Now uses pair distances from link-cell force calculation, and is therefore limited only by "rdf-limit". * Fixed problem whereby rescaling species separately led to net velocities of whole system. * Added SHMEM library interface for Cray T3D. Release 2.9 ----------- * Ewald sum parameter and cutoffs now automatically chosen from Fincham's formulae if no value specified in control file. * Various minor bugs fixed. NOTE 2.8c 24/11/94: The init code for the TCGMSG version of par_begin got the arguments wrong. Now fixed. Also fixed problem with dump sequence continuity. NOTE 2.8b 14/9/94: The definition of bspstart in the bsp lib CHANGED to include argc and argv as params. New version of parallel.c incorporates modified arg list. Release 2.8 ----------- * Port to distributed-memory MIMD parallel machines. - This port is based on a message-passing paradigm, and contains interfaces to three different message-passing systems - the Oxford BSP library, MPI (the new standardised message-passing library interface) and TCGMSG (the Theoretical Chamistry message-passing system). The parallel interface is contained within a single file "parallel.c" and versions for other MP libraries should be relatively easy to add. - To use, define the macro PARLIBC in the Makefile to contain the "include" path, -DSPMD and one of -DMPI, -DBSP and -DTCGMSG. The macro PARLIBL should be defined to link with the appropriate libraries. * Performance optimizations for IBM RS6000. The 4-way associative cache on the high-end machines in the IBM RS6000 line leads to a severe inefficiency when the number of sites is a power of 2. This version declares the arrays larger than the system size to avoid the problem. Release 2.7 ----------- * Added casts for size_mt in arralloc() calls - for K&R/ANSI compat. * New version of array allocator which breaks up requests for DOS. * Changed all timestep-related parameters to type "long". This means that 16-bit DOS compilers can do more than 32767 timesteps. NOTE: This changes the size of "native" format dump and restart files on a machine where sizeof(long) > sizeof(int), in particular DEC Alpha machines and possibly SGI R4000 based ones. Version 2.7 will not be able to read these "native" format files written by earlier versions, though the recommended XDR format will work. Versions 2.6 of "dumpconv -x" should be used to convert dump files to XDR format and moldy itself to convert restart files. * Utilities renamed for systems with short filenames. dumpextract ==> dumpext dumpconvert ==> dumpconv dumpanalyze ==> dumpanal moldyextract ==> moldyext moldyanalyze ==> manalyze * Strengthened error checking in "mdshak" which previously just gave ridiculous answers if you specified wrong arguments. It now calls "dumpext" via a pipe if it needs to read dump files. * Arguments of "dumpext" simplified. You can now specify the dump files as EITHER the complete set in any order (eg by unix shell wildcard expansion OR as a proforma exactly as in the control file. "dumpext" just tries plugging in numbers with "sprintf" to locate files. This eliminates the need for the "-n" option. (However if you start your run with an index > 500 it will not find them.) Release 2.6 ----------- * Port to PCs running MS-DOS * Significant internal restructuring. This consists of eliminating global data and improving data locality throughout the code. No external impact, but a gain in code quality which should make improvements and porting, esp to parallel machines much easier. * Yet more portability improvements * Bugs corrected - Fixed serious bug whereby linear molecules weren't recognised. Caused failure on RS6000 and possibly others, but not Sun or DEC Alpha. Release 2.5 ----------- This is to announce the release of version 2.5 of Moldy. This is mainly a bugfix and portability release with no major changes in functionality. It incorporates all the experience gained from the "beta-test" releases of 2.2 and 2.3. Major points are: * Greatly improved portability. Tested on Sun, SGI, HP, DEC, Convex IBM and Cray systems and should compile without problems on many more. * VMS support consolidated. Now compiles on VAX/VMS and OpenVMS/AXP systems without problems. Distribution comes in form of "moldy.com" script for ftping and contains "compile.com" to compile everything. * Better and more comprehensive install notes in READ.ME file. * Bugs corrected/mods since 2.2. - "Divide-by-zero" error on velocity rescale of atomic systems fixed. - Relaxed "dump"s checks to allow dump run to continue after backup restart without changing dump file names. - Minor optimization in real-space force calculation. A few percent faster. - Added distant-correction for "generic" potential type GENPOT - XDR mode for dump/restart files is now active by default. - Various minor portability bugs in utility programs corrected. $EOD $! $CREATE moldy.tex $DECK %MOLecular DYnamics simulation code, Moldy. %Copyright (C) 1988, 1992, 1993 Keith Refson % %This program is free software; you can redistribute it and/or modify it %under the terms of the GNU General Public License as published by the %Free Software Foundation; either version 2, or (at your option) any %later version. % %This program is distributed in the hope that it will be useful, %but WITHOUT ANY WARRANTY; without even the implied warranty of %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %GNU General Public License for more details. % %You should have received a copy of the GNU General Public License %along with this program; if not, write to the Free Software %Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. % %In other words, you are welcome to use, share and improve this program. %You are forbidden to forbid anyone else to use, share and improve %what you give them. Help stamp out software-hoarding! */ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%% This document requires LaTeX2e to format it and it will %%%%%%%%% %%%%%% not run under obsolete (LaTeX 2.09) installations. %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \documentclass[a4paper,twoside]{report} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Use Times-Roman fonts. This works for PSNFSS Latex2e%%%%%%%% %%%%%%%%%%% mode. Just comment it out if it doesn't work %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\usepackage{pslatex} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Use the "geometry" package to set page layout. %%%%%%%% %%%%%%%%%%% Hard coded params are given as comments below if nec. %%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%\usepackage{geometry} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Needed for tables 3.1 and 3.2. If you get rid of it %%%%%%% %%%%%%%%%%% edit the tabular header to excise the >{} descriptor.%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{array} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Prettifies some script letters. Omit if necessary. %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\usepackage[mathcal]{eucal} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Not really essential, but it will be the default soon. %%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\usepackage[T1]{fontenc} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Postscript figure inclusion. Epsfig is part of the %%%%%%%% %%%%%%%%%%% "graphics" bundle. Install it if necessary. %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{epsfig} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Eepic graphics work well if you don't have PostScript %%%%%%%%%%% but you DO have a graphics driver which supports the %%%%%%%%%%% "tpic" \special's, (iptex,dviis). Even if you don't %%%%%%%%%%% you can use the "eepicemu" package at a pinch but the %%%%%%%%%%% quality is poor. %%%%%%%%%%% To use it, rename the eepic figures "fig_*-eepic.tex" %%%%%%%%%%% to "fig_*.tex" and then run latex. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%\usepackage{epic} % For eepic or eepicemu %%\usepackage{eepic} % Tpic specials *or* %%%%\usepackage{eepicemu} % No special support. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% Dimensions and settings %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\geometry{body={160mm,230mm},top=40mm,nohead} %% This gives the following settings on A4 paper. For printing %% on US letter size, re-enable the \geometry and its \usepackage \textwidth 455.24408pt \textheight 654.41338pt \oddsidemargin 18.86191pt \evensidemargin -21.13809pt \topmargin 41.54103pt \headheight 0.0pt \headsep 0.0pt \renewcommand{\topfraction}{0.9} \renewcommand{\textfraction}{0.1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%% Font selection macros to parameterize document %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Extra emphasis - use bold. % \newcommand{\Emph}[1]{\textbf{#1}} % % Set font for filename display - sans-serif is nice. % \newcommand{\Fname}[1]{{\upshape\mdseries\sffamily#1}} \newenvironment{Fndescription}{\begingroup% \renewcommand{\descriptionlabel}[1]{\Fname{##1}}\begin{description}}% {\end{description}\endgroup} % % Set font for literal text display (typed commands, file contents % input/output and code fragments. % \newcommand{\Litf}{\ttfamily\upshape\mdseries} %\newcommand{\Lit}[1]{{\Litf#1}} \DeclareTextFontCommand{\Lit}{\Litf} \newenvironment{Litdescription}{\begingroup% \renewcommand{\descriptionlabel}[1]{\Lit{##1}}\begin{description}}% {\end{description}\endgroup} % % Abbreviation for bold math. Set to \mathbf for LaTeX2e % \newcommand{\bm}[1]{\mathbf{#1}} % % Calculus infinitesimal - upright ``d'' % \newcommand{\Calcd}{\mathrm{d}} % % Quaternion - bold sans-serif. % \newcommand{\Quat}[1]{\mbox{\mathversion{bold}$\mathsf{#1}$}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \makeatletter \def\sideset#1#2#3{% \setbox\z@\hbox{$\displaystyle{\vphantom{#3}}#1{#3}\m@th$}% \setbox\tw@\hbox{$\displaystyle{#3}#2\m@th$}% \hskip\wd\z@\hskip-\wd\tw@\mathop{\hskip\wd\tw@\hskip-\wd\z@ {\vphantom{#3}}#1{#3}#2}} \makeatother %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Define superfig and partfigure environments for multi-page figures %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcounter{subfig} \newenvironment{superfig}{% \setcounter{subfig}{0} \addtocounter{figure}{1} }{\setcounter{subfig}{0}} \makeatletter \newenvironment{partfigure}[1][tbp]{% \addtocounter{subfig}{1}\addtocounter{figure}{-1}% \@float{figure}[#1]% \renewcommand{\thefigure}{\thechapter.\arabic{figure}(\alph{subfig})}% }{\end@float} \renewcommand{\l@figure}{\@dottedtocline{1}{1.5em}{3em}} \makeatother %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% Useful shorthand macros %%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand{\moldy}{\emph{Moldy}} \newcommand{\etc}{\emph{etc.}} \newcommand{\eg}{\emph{e.g.}} \newcommand{\ie}{\emph{i.e.}} \newcommand{\erf}{\mbox{erf}} \newcommand{\erfc}{\mbox{erfc}} \newcommand{\insqrt}{\sqrt{\mathstrut}} \newcommand{\saferagged}{\let\temp=\\\protect\raggedright\let\\=\temp} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% Hyphenation %%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \hyphenation{algo-rithm time-slice time-slices} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% RCS Emulation stuff %%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand{\RCSrevision}{$ $Revision: 2.11 $ $} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% Document fromt matter/titlepage stuff %%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \title{{\Huge Moldy User's Manual}\\Release \RCSrevision} \author{Keith Refson\\Department of Earth Sciences\\Parks Road \\Oxford OX1 3PR\\keith@earth.ox.ac.uk\\} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \pagenumbering{roman} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \maketitle \thispagestyle{empty} Copyright \copyright\ 1988, 1993--1996 Keith Refson. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section*{Acknowledgements} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The initial implementation of the Nos\'{e}-Hoover and Gaussian thermostats was by Vladimir Murashov at Dalhousie University. Rafael R. Pappalardo contributed the modifications to ``mdshak'' to write XYZ format molecular graphics files. Thanks are due to Craig Fisher and Jos\'{e} Manuel Martinez Fernandez for diligent proofreading of several versions of the manual and many helpful suggestions on how to improve it. Any mistakes that remain are my own. \cleardoublepage \setcounter{page}{1} \tableofcontents \listoftables \listoffigures \cleardoublepage \pagenumbering{arabic} \setcounter{page}{1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Introduction} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \moldy\ is a computer program for performing molecular dynamics simulations of condensed matter. It can handle any assembly of rigid polyatomic molecules, atoms or ions and any mixture thereof. It uses the `link cell' method to calculate short-range forces and the Ewald sum technique to handle long-range electrostatic forces. Simulations may be performed either in the usual $NVE$ ensemble or in $NVT$, $N\sigma H$ or $N\sigma T$ ensembles using Nos\'e-Hoover thermostat and Parrinello and Rahman constant-stress methods. As the MD cell need not be cubic, the program is equally suitable for simulations of solids and liquids. Most existing MD programs are limited in their capabilities, for example to one kind of potential function, or molecular symmetry, or to some restricted number of molecules. \moldy\ is (as far as possible) free from such arbitrary constraints. The system is specified at the beginning of each run and its size is only limited by the amount of memory available to the program: if a system is too large to handle, the solution is to buy some more memory. The system may contain a mixture of an arbitrary number of molecular species, each with an arbitrary number of atoms and an arbitrary number of molecules of each. Molecules or ions may be monatomic or polyatomic, linear or three dimensional in any combination. The potential functions may be of the Lennard-Jones, Buckingham (including Born-Mayer) or MCY types, and other potential types may be easily added. Such flexibility is possible because \moldy\ is written in the `C' language which permits dynamic memory allocation. \moldy\ is written to be highly portable and has been tested on a wide range of computers and operating systems, including VAX/VMS, MS-DOS and Unix\footnote{Goodness knows who will own the Unix registered trademark by the time you read this.} (both BSD and system V varieties). It should be straightforward to move it to any other machine with a good `C' compiler. To be of real use a simulation program must run efficiently on modern high-speed computers, which are increasingly of vector or parallel architectures. \moldy\ is written so as to be highly vectorizable and has been tested on a range of vector machines from manufacturers including Cray, Convex, Stardent and Alliant. On the cray XMP-48 its performance can exceed 100 MFlop/sec (on a suitably large system). \moldy\ is also able to run on a parallel computer of either shared or distributed memory architectures, and has been tested on multiprocessors from Stardent, Convex, Cray Research, SGI and IBM SP1 and Cray Research T3D massively parallel machines. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Terms and Conditions}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Permission to compile and run \moldy\ is granted to any individual or organization without restriction. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. \moldy\ is free software; you may redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. The terms of the GNU General Public License are described in the file \Fname{COPYING} which is included with the source distribution, or from the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Algorithms and Equations} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% This chapter describes the implementation of the molecular dynamics technique as used in \moldy. It is not intended as an introduction to MD simulations, and does assume some familiarity with the basic concepts of microscopic models and simulations thereof. The book by Allen and Tildesley\cite{allen:87} is a very good introductory text, covering both the theory and the practicalities and is highly recommended. It also contains comprehensive references to the scientific literature of microscopic computer simulation. \moldy\ is designed to simulate a common class of models of atomic or molecular systems. The assumptions are: that the system is an assembly of \emph{rigid molecules}, atoms or ions; that the forces of interaction are derived from \emph{continuous potential functions} acting between (usually atomic) \emph{sites} on each molecule; that the dynamics are governed by the \emph{classical} Newton-Euler equations of motion. A major aim of \moldy\ has been to allow the most general of models within that class and to impose as few restrictions as possible. In particular arbitrary mixtures of different molecules are allowed and several popular forms of potential functions are catered for. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{The Equations of Motion} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% If we denote the force exerted by atom $\alpha$ of molecule $i$ on atom $\beta$ of molecule $j$ by $\bm{f}_{i\alpha j\beta}$\footnote{A comment on notation is appropriate here. In this chapter, site quantities are denoted by \emph{lowercase} letters, molecular quantities by \emph{uppercase}, sites are indexed by \emph{greek} letters and molecules by \emph{roman}. A missing index denotes a sum over the corresponding sites or molecules so that, for example $\bm{r}_{i\alpha j\beta}$ is a site-site vector and $\bm{F}_{ij}$ the molecule-molecule force.} then the total force acting on molecule $i$ is \begin{equation} \label{eqn:comf} \bm{F}_i = \sum_j \sum_\beta \sum_\alpha \bm{f}_{i\alpha j\beta} \end{equation} and the torque is given by \begin{equation} \label{eqn:comt} \bm{N}_i = \sum_\alpha (\bm{r}_{i \alpha} - \bm{R}_{i}) \times\bm{f}_{i\alpha} \end{equation} where $\bm{R}_{i} = 1/M_i \sum_\alpha m_{i\alpha} \bm{r}_{i\alpha}$ is the centre of mass of molecule $i$. The motion is governed by the Newton-Euler equations \begin{equation} M_i\ddot{\bm{R}}_i = \bm{F}_i \label{eqn:newton} \end{equation} \begin{equation} \bm{I}_i \cdot \dot{\bm\omega}_i - \bm\omega_i \times \bm{I}_i \cdot \bm\omega_i = \bm{N}_i \label{eqn:euler} \end{equation} where $\bm\omega_i$ is the angular velocity of the molecule, $ \bm{I}_i = \sum_{\alpha} m_{i\alpha} ( p_{i\alpha}^2 \bm{1} - \bm{p}_{i\alpha}\bm{p}_{i\alpha} ) $ is the inertia tensor and $\bm{p}_{i\alpha} = \bm{r}_{i\alpha} - \bm{R}_i $ is the atomic site co-ordinate relative to the molecular centre of mass. % Quaternions \label{sec:quaternions} The orientations of the molecules are represented by \emph{quaternions} as has now become common practice. They are preferred over Euler angles for two reasons. Firstly they lead to equations of motion which are free of singularities\cite{evans:77} which means that no special-case code is required. This leads to much improved numerical stability of the simulation\cite{evans:77b}. Secondly, molecular symmetry operations and combinations of rotations are elegantly expressed in terms of a simple quaternion algebra\cite{evans:77b,pawley:85b}. A quaternion is an ordered number quartet which obeys the algebra given by Pawley\cite{pawley:81}. The multiplication rule in that reference may be restated as a matrix product treating each quaternion as a 4-vector. If $\Quat{p} \equiv (p_0,p_1,p_2,p_3)$ and $\Quat{q} \equiv (q_0,q_1,q_2,q_3)$ are quaternions then \begin{equation} \Quat{pq} = \left( \begin{array}{rrrr} p_0 & -p_1 & -p_2 & -p_3 \\ p_1 & p_0 & -p_3 & p_2 \\ p_2 & p_3 & p_0 & -p_1 \\ p_3 & -p_2 & p_1 & p_0 \end{array} \right) \left( \begin{array}{r} q_0 \\ q_1 \\ q_2 \\ q_3 \end{array} \right) \end{equation} The quaternion $ \Quat{\tilde{q}} $ conjugate to $\Quat{q}$ is defined as $\Quat{\tilde{q}} = (q_0,-q_1,-q_2,-q_3)$ so that \begin{equation} \Quat{q\tilde{q}} = (q_0^2+q_1^2+q_2^2+q_3^2,0,0,0). \label{eqn:qnorm} \end{equation} The \emph{norm} is defined as $ |\Quat{q}| \equiv \sqrt{q_0^2+q_1^2+q_2^2+q_3^2} $ and $\Quat{q}$ is called a \emph{unit} quaternion if $ |\Quat{q}| = 1 $. Any possible rotation can be represented by a unit quaternion. Du Val shows\cite{duval:64} that if $ \Quat{q} \! = \! (\cos \frac{\alpha}{2}, \bm{l} \sin \frac{\alpha}{2}) $ (where we have combined the last three components to form a 3-vector) and $\Quat{p} = (0,\bm{r})$ then the operation \begin{equation} \Quat{p'} \equiv (0,\bm{r'}) = \Quat{q p \tilde{q}} \end{equation} corresponds to a rotation of the vector $\bm{r}$ by an angle of $\alpha$ about the axis $\bm{l}$. The components may also be expressed in terms of the Euler angles as\footnote{The definition of quaternions used here differs from that used in Evans' paper\cite[equation 21]{evans:77} in the sign of $q_2$ or $\xi$. This error has been compounded by subsequent authors\cite{sonnenschein:85,smith:82,laakonsen:85} who also managed to permute the components which means that the parameters do not form an ordered number quartet which obeys quaternion algebra. Like Allen and Tildesley\cite[page 88]{allen:87} we follow the definition of Goldstein\cite[pages 143 and 155]{goldstein:80}.} \begin{eqnarray} q_0 & = & \cos \frac{\phi+\psi}{2} \cos \frac{\theta}{2} \nonumber \\ q_1 & = & \sin \frac{\phi-\psi}{2} \sin \frac{\theta}{2} \nonumber \\ q_2 & = & \cos \frac{\phi-\psi}{2} \sin \frac{\theta}{2} \nonumber \\ q_3 & = & \sin \frac{\phi+\psi}{2} \cos \frac{\theta}{2}. \end{eqnarray} The relationship between the time derivative of a quaternion and the principal frame angular velocity was given by Evans\cite[Equation 27]{evans:77} and rewritten using quaternion algebra by Refson\cite{refson:87a} as \begin{equation} 2 \Quat{\dot{q}} = \Quat{q}(0,\bm\omega^p) \label{eqn:qomega} \end{equation} The second derivative is given by \begin{eqnarray} \nonumber 2\Quat{\ddot{q}} & = & \Quat{q}(- 1/2 (\omega^p)^2,\dot{\bm\omega}^p) \\ & = & \Quat{q}(-2 |\Quat{\dot{q}}|^2,\dot{\bm\omega}^p) \label{eqn:qddot} \end{eqnarray} Equations~\ref{eqn:qddot} and~\ref{eqn:euler} allow the simulation to be implemented using quaternions and their derivatives as the dynamic variables for rotational motion, and this is the method employed in \moldy. This second order formulation was first used by Powles \emph{et al}.\cite{powles:79} and Sonnenschein showed\cite{sonnenschein:85} that it gives substantially better stability than if angular velocities and accelerations are used as dynamic variables. Using equations~\ref{eqn:qddot} to describe the dynamics means that they are integrated as if all four components were independent. Therefore the normalization condition $\Quat{q \tilde{q}} = \Quat{1}$ may not be exactly satisfied after performing an integration step. \moldy\ adopts the usual practice of scaling all components of the quaternion after each timestep to satisfy the normalization condition\cite{evans:77b}. It is less widely realized that the second order equations (\ref{eqn:qddot}) introduce a \emph{second} unconstrained variable into the procedure. Differentiating equation~\ref{eqn:qnorm} gives a constraint on the quaternion derivatives \begin{equation} q_0\dot{q_0} + q_1\dot{q_1} + q_2\dot{q_2} + q_3\dot{q_3} = 0 \label{eqn:qconst} \end{equation} which is just the $q_0$ component of equation~\ref{eqn:qomega}. Just as with the normalization condition, the integration algorithm will not preserve this condition exactly unless explicit measures are taken. After each timestep the constraint may be re-established by subtracting the discrepancy from the quaternion derivatives. If $\delta = q_0\dot{q_0} + q_1\dot{q_1} + q_2\dot{q_2} + q_3\dot{q_3}$ then the corrected quaternion derivatives are given by \begin{equation} \Quat{\dot{q}^\prime } = \Quat{\dot{q}} - \delta \Quat{q}. \label{eqn:qconcorr} \end{equation} Experiments conducted while developing \moldy\ show that enforcing this constraint significantly decreases the fluctuations in the total energy. Linear molecules are a slightly special case as the moment of inertia about the molecular axis is zero. Though there are unique methods to represent this situation\cite[page 90]{allen:87} \moldy\ uses a minor modification of the quaternion algorithm. All that is necessary is a little special-case code to avoid dividing by the zero component of inertia in the solution of equation~\ref{eqn:euler} and to hold the components of angular velocity and acceleration about the molecular axis to zero. This has the considerable advantage of uniform treatment of all kinds of molecules which is convenient when dealing with heterogeneous mixtures. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Integration Algorithms} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:beeman} The dynamical equations~\ref{eqn:newton} and~\ref{eqn:euler} are integrated using this author's modification\cite{refson:85} of the Beeman algorithm\hspace{0pt}\cite{beeman:76}. For atomic systems the accuracy is of the same order as the commonly used Verlet algorithm\cite{verlet:67}. The accuracy of common integration algorithms was discussed by Rodger\cite{rodger:89} who showed that the Beeman algorithm is the most accurate of the supposedly ``Verlet-equivalent'' algorithms. The Beeman algorithm is the only one accurate to $O(\delta t^4)$ in the co-ordinates and $O(\delta t^3)$ in the velocities compared to the velocity Verlet algorithm which is only $O(\delta t)$ in the velocities. This is insufficient for an accurate determination of the kinetic energy, pressure and other dynamic quantities. More seriously, it fails badly in the case of polyatomic molecules and for constant-pressure and constant-temperature methods where the (generalized) velocities enter the dynamical equations themselves. Velocity-dependent forces occur in equations~\ref{eqn:euler} and~\ref{eqn:qddot}, in the Parrinello-Rahman constant-pressure equations (section~\ref{sec:const-stress}) and in the Nos\'e-Hoover heat bath algorithms (section~\ref{sec:const-temp}). These usually present a problem to non ``predictor-corrector'' algorithms which are based on the assumption that the forces depend only on the co-ordinates. Fincham has devised a scheme to allow integration of the rotational equations using Verlet-like algorithms\cite{fincham:81}, which is widely used despite the potential problems caused by the low accuracy of the velocities being propagated into the dynamics. These cases are easily and accurately handled by the modification to Beeman's equations proposed by the author\cite{refson:85}. These may be summarized using the symbol $x$ to represent any dynamic variable (centre-of-mass co-ordinate, quaternion or MD cell edge), $\dot{x}^{(p)}$ and $\dot{x}^{(c)}$ to represent ``predicted'' and ``corrected'' velocities respectively. \begin{equation} \begin{array}[c]{llcl} \textup{i} \quad & x(t+\delta t) &=& x(t) + \delta t \, \dot{x}(t) + \frac{\delta t^2}{6} \left [ 4 \ddot{x}(t) - \ddot{x}(t-\delta t) \right ] \\ \textup{ii} & \dot{x}^{(p)}(t+\delta t) & = & \dot{x}(t) + \frac{\delta t}{2} \left [ 3 \ddot{x}(t)- \ddot{x}(t-\delta t) \right ]\\ \textup{iii} & \ddot{x}(t+\delta t) & = & F(\{ x_i(t+\delta t), \dot{x}_i^{(p)}(t+\delta t)\}, i = 1\ldots n) \\ \textup{iv} & \dot{x}^{(c)}(t+\delta t) & = & \dot{x}(t) + \frac{\delta t}{6} \left [ 2 \ddot{x}(t+\delta t) + 5 \ddot{x}(t)- \ddot{x}(t-\delta t) \right ]\\ \textup{v} & \multicolumn{3}{l}{ \textnormal{Replace $ \dot{x}^{(p)}$ with $\dot{x}^{(c)}$ and goto \emph{iii}. Iterate to convergence}} \end{array} \begin{array}[c]{l} \begin{array}{l} \strut\\ \strut \end{array}\\ \left . \begin{array}{l} \strut\\ \strut\\ \strut \end{array} \right \} \end{array} \label{eqn:beeman} \end{equation} The predictor-corrector cycle of steps \emph{iii} to \emph{v} are iterated until the predicted and corrected velocities have converged to a relative precision of better than 1 part in $10^{-7}$, which in practice takes 2 or 3 cycles. This iteration is not as inefficient as it might at first appear as it does \emph{not} include the expensive part of the calculation --- the recalculation of the site forces. Only the angular accelerations and quaternion second derivatives must be evaluated at each iteration using equations~\ref{eqn:euler} and~\ref{eqn:qddot}, and this operation is relatively cheap. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Potentials and Short-Range Forces}%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The forces determining the dynamics of the system are derived from the potential function denoted by $\phi_{i\alpha j\beta}(\bm{r} _{i\alpha j\beta})$. The indices $i$ and $j$ run over all molecules in the system and $\alpha$ and $\beta$ over sites on the respective molecule. The total potential energy of the system is \begin{equation} \label{eqn:toten} U = \sum_i \sum_{j > i} \sum_\alpha \sum_\beta \phi_{i\alpha j\beta}( \bm{r}_{i\alpha j\beta}). \end{equation} where $\bm{f}_{i\alpha j\beta} = - \bm\nabla \phi_{i\alpha j\beta}( \bm{r}_{i\alpha j\beta})$ is the force acting on site $\beta$ of molecule $j$ from site $\alpha$ of molecule $i$. The total force and torque acting on any particular molecule are calculated using equations~\ref{eqn:comf} and~\ref{eqn:comt}. Since $\bm{f}_{i\alpha j\beta}$ and therefore $\bm{F}_{ij}$ are short-ranged forces (\ie they decay faster than $r^{-3}$) one can define a \emph{cutoff} radius, $r_c$. Interactions between sites whose separation $r_{ij}$ is greater than $r_c$ are assumed to be negligible and need not be evaluated. In the case of a polyatomic molecular system it is usual to apply the cutoff according to the \emph{intermolecular} separation $R_{ij}$. \subsection{Pressure and Stress} The internal stress of a system of interacting molecules is given by Allen and Tildesley\cite[pp 46-49]{allen:87} in terms of the molecular virial, but we may rewrite it more conveniently in terms of the atomic site virial as \begin{eqnarray} \label{eqn:stress-sr} V \bm\pi^{sr} & = & \left < \sum_i M_i \bm{V}_i \bm{V}_i + \sum_i \sum_{j>i} \bm{R}_{ij} \bm{F}_{ij} \right > \\ \nonumber & = & \left < \sum_i M_i \bm{V}_i \bm{V}_i + \sum_{i} \sum_{j>i} \sum_\alpha \sum_\beta \bm{r}_{i\alpha j\beta} \bm{f}_{i\alpha j\beta} - \sum_i \sum_\alpha \bm{p}_{i\alpha} \bm{f}_{i\alpha} \right > \end{eqnarray} The quantity $\bm{p}_{i\alpha} \equiv \bm{r}_{i\alpha} - \bm{R}_i$ is the co-ordinate of each site relative to the molecular centre-of-mass. The pressure is easily evaluated as one third of the trace of the stress tensor. \subsection{Long Range Corrections} The truncation of the interactions at the cut-off radius does introduce some errors into the calculated potential energy and stress. By neglecting density fluctuations on a scale longer than the cutoff radius we may approximate the errors and calculate correction terms\cite[pp 64-65]{allen:87}. \begin{eqnarray} U_c & = & \frac{2\pi}{V} \sum_\alpha \sum_\beta N_\alpha N_\beta \int_{r_c}^\infty r^2 \phi_{\alpha\beta}(r) \, \Calcd r \\ P_c V & = & \frac{2\pi}{3 V} \sum_\alpha \sum_\beta N_\alpha N_\beta \int_{r_c}^\infty r^3 \frac{\Calcd\phi_{\alpha\beta}(r)}{\Calcd r} \, \Calcd r \nonumber \\ & = & U_c + \frac{2\pi}{3 V} \sum_\alpha \sum_\beta N_\alpha N_\beta r_c^3 \phi_{\alpha\beta}(r_c) \\ \bm\pi_c & = & P_c \bm\delta \end{eqnarray} where the sums run over all the distinct kinds of sites, $N_\alpha$ is the total number of sites of type $\alpha$ in the system and $\bm\delta$ is the unit matrix. \subsection{Potential Functions} \label{sec:potentials} % LJ, Buckingham (Born-Mayer) & MCY \moldy\ supports most common forms of potential function. In particular, \begin{list}{}{\labelwidth=1in \labelsep=0.25in \leftmargin=1.5in \parsep=0in \renewcommand{\makelabel}[1]{\emph{#1} \hfil}} \item[Lennard-Jones] $\phi(r) = \epsilon((\frac{\sigma}{r})^{12}) - (\frac{\sigma}{r})^{6})$ \item[6-exp] $\phi(r) = -\frac{A}{r^{6}} + B\exp(-Cr)$\\ This is the most general 6-exp form and includes potential of the \emph{Born-Mayer} and \emph{Buckingham} forms. \item[MCY] $\phi(r) = A \exp(-Br) - C \exp(-Dr)$ \item[generic] $\phi(r) = A \exp(-Br) + C/r^{12} - D/r^4 -E/r^6 -F/r^8$\\ This is a composite which contains terms of several inverse powers which may be useful for ionic solution simulations. \end{list} In addition to the short-range potential electric charges may be specified for each atomic site which interact according to Coulomb's Law. See the following section for details. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{The Ewald Sum}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:ewald} The long range Coulomb interactions are handled using the Ewald Sum technique in three dimensions\cite[p.\ 156]{berthaut:52,allen:87}. The electrostatic potential of a system of charges is expressed as a sum of short-range and long-range contributions. Each term is written as a series, the first in real space and the second, obtained by Fourier transformation using the periodicity of the MD cell, in reciprocal space. The expression for the Coulomb energy $U$ is \begin{eqnarray} \label{eqn:ewald} U & = & \underbrace{\frac{1}{4 \pi \epsilon_0} \sideset{}{^\dag}\sum_{\bm{n}} \sum_{i=1}^{N} \sum_{j=i+1}^{N} q_iq_j \frac{\erfc( \alpha | \bm{r}_{ij} + \bm{n} |)}{| \bm{r}_{ij} + \bm{n} | }}_{\textnormal{Real-space term}} \nonumber \\ & + & \underbrace{\frac{1}{\epsilon_0 V} \sum_{\bm{k} > 0} \frac{1}{k^2} e^{-\frac{k^2}{4 \alpha^2}} \left \lbrace \left | \sum_{i=1}^{N} q_i \cos(\bm{k \cdot r}_i) \right |^2 + \left | \sum_{i=1}^{N} q_i \sin(\bm{k \cdot r}_i) \right |^2 \right \rbrace}_{\textnormal{Reciprocal-space term}}\\ & - & \underbrace{\frac{\alpha}{4 \pi^\frac{3}{2} \epsilon_0} \sum_{i=1}^{N} q_i^2}_{\textnormal{Point self-energy}} - \underbrace{\frac{1}{4 \pi \epsilon_0} \sum_{n=1}^M \sum_{\kappa=1}^{N_m} \sum_{\lambda=\kappa+1}^{N_m} q_{n\kappa} q_{n\lambda} \frac{\erf( \alpha | \bm{r}_{\kappa\lambda} |)}{| \bm{r}_{\kappa\lambda}| }}_{\textnormal{Intra-molecular self energy}} \nonumber \\ & - & \underbrace{ \frac{1}{8 \epsilon_0 V \alpha^2} \left | \sum_{i=1}^N q_i \right |^2}_{\textnormal{Charged system term}} + \; \underbrace{\left [ \frac{1}{6 \epsilon_0 V} \left | \sum_{i=1}^N q_i \bm{r}_i \right |^2 \right ]}_{\textnormal{Surface dipole term}} \nonumber \end{eqnarray} where the ``daggered'' summation indicates omission of site pairs $i, j$ belonging to the same molecule if $\bm{n}=\bm{0}$. The meaning of the symbols is \begin{tabbing} \rule{2cm}{0cm} \= \rule{2cm}{0cm} \=\\ \> $\bm{n}$ \> lattice vector of periodic array of MD cell images \\ \> $\bm{k}$ \> reciprocal lattice vector of periodic array of MD cell images \\ \> $k$ \> modulus of $\bm{k}$ \\ \> $i,j$ \> absolute indices of all charged sites \\ \> $n$ \> index of molecules \\ \> $\kappa,\lambda$ \> indices of sites within a single molecule \\ \> $N$ \> total number of charged sites \\ \> $M$ \> total number of molecules \\ \> $N_m$ \> number of sites on molecule $m$ \\ \> $\bm{p}_i$ \> co-ord of site $i$ relative to molecular centre-of-mass, $\bm{r}_i - \bm{R}_i$ \\ \> $q_i$ \> charge on absolute site $i$ \\ \> $q_{m\kappa}$ \> charge on site $\kappa$ of molecule $m$ \\ \> $\bm{r}_i$ \> Cartesian co-ordinate of site $i$ \\ \> $\bm{r}_{ij}$ \> $\bm{r}_j - \bm{r}_i$ \\ \> $\alpha$ \> real/reciprocal space partition parameter \\ \> $\pi_{lm}$ \> instantaneous stress tensor \\ \> $\delta_{lm}$ \> Kronecker delta symbol \\ \> $l, m$ \> $xyz$ tensor indices \\ \> $V$ \> volume of MD cell \end{tabbing} and the force on charge $i$ is given by \begin{eqnarray} \label{eqn:ewald-force} \bm{f}_i &=& - \nabla_{\bm{r}_i} U \nonumber \\ & = & \underbrace{\frac{q_i}{4 \pi \epsilon_0} \sideset{}{^\dag}\sum_{\bm{n}} \sum_{j=1 \atop j \neq i}^{N} q_j \left \lbrace \frac{\erfc( \alpha | \bm{r}_{ij} + \bm{n} |)}{| \bm{r}_{ij} +\bm{n} | } + \frac{2 \alpha}{\sqrt{\pi}}e^{- \alpha^2 | \bm{r}_{ij} + \bm{n} |^2} \right \rbrace \frac{\bm{r}_{ij} + \bm{n}}{| \bm{r}_{ij} + \bm{n} |^2} }_{\textnormal{Real-space term}} \nonumber \\ & + & \underbrace{\frac{2}{\epsilon_0 V} \sum_{\bm{k} > 0} q_i \frac{\bm{k}}{k^2} e^{-\frac{k^2}{4 \alpha^2}} \left \lbrace \sin(\bm{k \cdot r}_i) \sum_{j=1}^{N} q_j \cos(\bm{k \cdot r}_j) - \cos(\bm{k \cdot r}_i) \sum_{j=1}^{N} q_j \sin(\bm{k \cdot r}_j) \right \rbrace}_{\textnormal{Reciprocal-space term}}\\ & + & \underbrace{\left [ \frac{q_i}{6 \epsilon_0 V} \left ( \sum_{j=1}^N q_j \bm{r}_j \right ) \right ]}_{\textnormal{Surface dipole term}} \nonumber \end{eqnarray} The molecular forces and torques $\bm{F}$ and $\bm{N}$ are evaluated from the site forces $\bm{f}_i$ using equations~\ref{eqn:comf} and~\ref{eqn:comt}. Notice that the equation~\ref{eqn:ewald} for the energy contains a correction for the intra-molecular self-energy, whose derivative is absent from the equation for the forces (equation~\ref{eqn:ewald-force}). This term corrects for interactions between charges on the \emph{same} molecule which are implicitly included in the reciprocal space sum, but are not required in the rigid-molecule model. Though the site forces $\bm{f}_i$ do therefore include unwanted terms these sum to zero in the evaluation of the molecular centre-of-mass forces and torques (equations~\ref{eqn:comf} and~\ref{eqn:comt}) (by the conservation laws for linear and angular momentum). \subsection{Parameter Values} \label{sec:ewald-auto} Both the real- and reciprocal-space series (the sums over $\bm{n}$ and $\bm{k}$) converge fairly rapidly so that only a few terms need be evaluated. We define the \emph{cut-off} distances $r_c$ and $k_c$ so that only terms with $| \bm{r}_{ij} +\bm{n} | < r_c$ and $|\bm{k}| < k_c$ are included. The parameter $\alpha$ determines how rapidly the terms decrease and the values of $r_c$ and $k_c$ needed to achieve a given accuracy. For a fixed $\alpha$ and accuracy the number of terms in the real-space sum is proportional to the total number of sites, $N$ but the cost of the reciprocal-space sum increases as $N^2$. An overall scaling of $N^\frac{3}{2}$ may be achieved if $\alpha$ varies with $N$. This is discussed in detail in an excellent article by David Fincham\cite{fincham:94}. The optimal value of $\alpha$ is % \begin{equation} \alpha = \sqrt{\pi} \left ( \frac{t_R}{t_F} \frac{N}{V^2}\right ) ^\frac{1}{6} \label{eqn:ewald-alpha} \end{equation} % where $t_R$ and $t_F$ are the execution times needed to evaluate a single term in the real- and reciprocal-space sums respectively. If we require that the sums converge to an accuracy of $ \epsilon = \exp ( -p )$ the cutoffs are then given by \begin{eqnarray} r_c = \frac{\sqrt{p}}{\alpha} \\ k_c = 2 \alpha \sqrt{p} \label{eqn:ewald-cut} \end{eqnarray} A representative value of $t_R/t_F$ specific to \moldy\ has been established as 5.5. Though this will vary on different processors and for different potentials its value is not critical since it enters the equations as a sixth root. It must be emphasized that the $r_c$ is used as a cutoff for the short-ranged potentials as well as for the electrostatic part. The value chosen above \emph{does not} take the nature of the non-electrostatic part of the potential into account. It is therefore the responsibility of the user to ensure that $r_c$ is adequate for this part too. \subsection{Uniform Sheet Correction} The 5th term in equation~\ref{eqn:ewald} is necessary only if the system has a non-zero net electric charge, and is useful in special cases such as framework systems. In a periodic system the electrostatic energy is finite only if the total electric charge of the MD cell is zero. The reciprocal space sum in equation~\ref{eqn:ewald} for $\bm{k}=0$ takes the form \[\frac{1}{k^2}e^{-\frac{k^2}{4 \alpha^2}} \left | \sum_{i=1}^{N} q_i \right |^2\] which is zero in the case of electroneutrality but infinite otherwise. Its omission from the sum in equation~\ref{eqn:ewald} is physically equivalent to adding a uniform jelly of charge which exactly neutralizes the unbalanced point charges. But though the form of the reciprocal space sum is unaffected by the uniform charge jelly the real-space sum is not. The real-space part of the interaction of the jelly with each point charge as well as the self-energy of the jelly itself must be included giving the fifth term in equation~\ref{eqn:ewald}. \subsection{Surface Dipole Term} The optional final term in equations~\ref{eqn:ewald} and~\ref{eqn:ewald-force} if used performs the calculations under different periodic boundary conditions. It was suggested by De Leeuw, Perram and Smith\cite{deleeuw:80} in order to accurately model dipolar systems and is necessary in any calculation of a dielectric constant. The distinction arises from considerations of how the imaginary set of infinite replicas is constructed from a single copy of the MD box\cite[pp 156-159]{allen:87}. Consider a near-spherical cluster of MD cells. The ``infinite'' result for any property is the limit of its ``cluster'' value as the size of the cluster tends to infinity. However this value is non-unique and depends on the dielectric constant, $\epsilon_s$ of the physical medium surrounding the cluster. If this medium is conductive ($\epsilon_s=\infty$) the dipole moment of the cluster is neutralized by image charges, whereas in a vacuum ($\epsilon_s=1$) it remains. It is trivial to show that in that case the dipole moment per unit volume (or per MD cell) does \emph{not} decrease with the size of the cluster. The final term in equation~\ref{eqn:ewald} is just the dipole energy, and ought to be used in any calculation of the dielectric constant of a dipolar molecular system. It is switched on by \moldy's control parameter \Lit{surface-dipole}. Note that as it represents the dipole at the surface of the cluster the system is no longer truly periodic. Conversely it \emph{must not} be used if the simulated system contains mobile ions. Consider an ion crossing a periodic boundary and jumping from one side of the MD cell to another. In that case the dipole moment of the MD cell changes discontinuously. Because of the surface dipole term the calculation would model a discontinuous macroscopic change in the dipole moment of the whole system caused by an infinite number of ions jumping an infinite distance. This is manifested in practice by a large and discontinuous change in the energy of the system and on the force on each charge within it. This situation is completely non-physical but is easily avoided. However the problem may also arise more subtly even when there are no mobile ions if a framework is being simulated (section~\ref{sec:frameworks}). The framework is treated as a set of discrete, but fixed atoms rather than a molecular unit. If the shape of the unit cell is allowed to vary then ions constituting the framework may indeed cross MD cell boundaries causing the aforementioned problems. \subsection{Stress} The internal stress (and pressure) of an atomic system is given by the volume-derivative of the internal energy. The situation is slightly more complicated for rigid molecules since molecules do not scale with volume and only the inter-molecular distances vary. The resulting expression for the Coulombic part of the instantaneous stress $\pi_{ik}^e$ is\cite[Appendix A]{nose:83} \begin{eqnarray} \label{eqn:ewald-stress} V\pi_{lm}^e & = & \underbrace{\frac{1}{4 \pi \epsilon_0} \sideset{}{^\dag}\sum_{\bm{n}}\sum_{i=1}^{N} \sum_{j=i+1}^{N} q_iq_j \left \lbrace \frac{\erfc( \alpha | \bm{r}_{ij} + \bm{n} |)}{| \bm{r}_{ij} +\bm{n} | } + \frac{2 \alpha}{\sqrt{\pi}}e^{- \alpha^2 | \bm{r}_{ij} + \bm{n} |^2} \right \rbrace \frac{(\bm{r}_{ij} + \bm{n})_l(\bm{r}_{ij} + \bm{n})_m}{| \bm{r}_{ij} + \bm{n} |^2}}_{\textnormal{Real-space term}} \nonumber \\ & + & \underbrace{\frac{1}{\epsilon_0 V} \sum_{\bm{k} > 0} \frac{1}{k^2} e^{-\frac{k^2}{4 \alpha^2}} \left ( \delta_{lm} \!- \! 2 \left [ \frac{1}{k^2} \! + \! \frac{1}{4 \alpha^2} \right ] \bm{k}_l\bm{k}_m \right )\left \lbrace % \left | \sum_{i=1}^{N} q_i \cos(\bm{k \cdot r}_i) \right |^2 + \left | \sum_{i=1}^{N} q_i \sin(\bm{k \cdot r}_i) \right |^2 \right \rbrace}_{\textnormal{Reciprocal-space term}} \nonumber \\ & - & \underbrace{\sum_{i=1}^{N} (\bm{F}_i)_l (\bm{p}_i)_m}_{\textnormal{Molecular Virial Correction}} - \underbrace{ \frac{\delta_{lm}}{8 \epsilon_0 V \alpha^2} \left | \sum_{i=1}^N q_i \right |^2}_{\textnormal{Charged system term}} \end{eqnarray} The true internal stress is the ensemble average, $\pi_{lm} = \left < \pi_{lm}^e + \pi_{lm}^{\textnormal{s.r.}} + \pi_{lm}^K \right >$, where $\pi_{lm}^{\textnormal{s.r.}}$ and $\pi_{lm}^K$ are the short-range force and kinetic contributions respectively. $\pi_{lm}^e$ enters into the Parrinello-Rahman equations of motion (see section~\ref{sec:const-stress}). The term marked \emph{Molecular Virial Correction} in equation~\ref{eqn:ewald-stress} is the difference between the site-site virial $\sum_i \bm{f}_i \cdot \bm{r}_i$ and the molecular virial $\sum_i \bm{F}_i \cdot \bm{R}_i$ and is subtracted after all of the site forces and the molecular forces have been calculated including the short-range potential components which are not included in the equations above. Though it is not apparent in reference\cite[Appendix A]{nose:83} this term has exactly the same form for all parts of the stress --- the short-range potential and the real- and reciprocal space Coulombic parts. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Periodic Boundaries --- the Link Cell Method}%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:link-cell} The real space part of the Ewald (equation~\ref{eqn:ewald}) and short-range potential energy is a sum of contributions over pairs of sites. In both cases the interaction decays rapidly with separation, which means that only site pairs closer then some \emph{cutoff} distance $r_c$ need be considered. Several methods are available to enumerate site pairs and choose those within the cutoff. Most simple MD codes simply loop over all pairs of particles in the MD box and compute the separation $r$ for each. If $r < r_c$ the interaction is computed. This method suffers from several disadvantages. Since for any given site, the interaction with any other site is considered only once, only the \emph{nearest} periodic image of that site is included (the \emph{minimum-image} convention). However this restricts the cutoff radius to less than half the MD cell dimension $r_c < 2L$. More serious is the way the computational time scales with the number of sites. If there are $N$ sites, there are $O(N^2)$ separations to compute and the overall time therefore scales as $O(N^2)$. The Verlet \emph{Neighbour List} scheme\cite[pp 146-149]{allen:87} makes use of the spatial locality of the interaction potential by maintaining a list for each site of all the ``neighbouring'' sites (\ie\ all those within the cutoff distance). This can give considerable gains for moderate numbers of sites, but it ultimately requires $O(N^2)$ time (to build the lists) as well as $O(N)$ storage for the lists. \moldy\ uses an implementation of the link cell method of Quentrec \emph{et al}.\cite{quentrec:75} described in Allen and Tildesley's book\cite[pp 149-152]{allen:87} which is a true $O(N)$ algorithm. The fundamental idea is that the MD cell is partitioned into a number of smaller cells, known as \emph{subcells}. Every timestep a linked list of all the particles contained in each subcell is constructed. The selection of all pairs of \emph{particles} within the cutoff is achieved by looping over all pairs of \emph{subcells} within the cutoff and particles within the subcells. Because of their regular arrangement, the list of neighbouring subcells is fixed and may be precomputed. Its construction takes only $O(N)$ operations and only $O(N)$ pair interactions need be calculated. % Molecular nature of cutoffs. When the system consists of polyatomic molecules it is important that all sites belonging to a particular molecule are assigned to the same cell. Otherwise it is impossible to calculate the stress and pressure (equation~\ref{eqn:ewald-stress}) correctly as MD cell vectors are added to some intra-molecular distances. Therefore all sites of any molecule are assigned to a cell if the molecular centre-of-mass lies inside it. One drawback of the link cell method has been the difficulty of implementing it efficiently for vector processors. The linked list of ``neighbour'' particles is not stored in the regular-stride array which is required for vectorization. Heyes and Smith\cite{heyes:87} pointed out that \emph{gather} operations might be used to assemble a temporary array of neighbour particle co-ordinates from which the interaction potential and forces could be evaluated in vector mode. A \emph{scatter} operation is then used to add the resulting forces to the total force array. This is the technique used in \moldy. Almost all modern vector machines have scatter/gather hardware which means these operations are fairly cheap. \subsection{No minimum-image convention} One notable feature of the implementation of the link cell method in \moldy\ is that it does \emph{not} follow the \emph{minimum image} convention used in most MD codes. Instead the list of neighbouring cells, and hence interactions considered, includes \emph{all} periodic images of a particle which are within the cutoff. This means that it is quite safe to use a cutoff of more than half of the MD cell side in any direction. % quick 'n dirty vs strict. \subsection{Cell or Strict cutoff} \label{sec:strict-cutoff} There are two options for the way in which site-site interactions are selected for inclusion in the total energy and forces. These are \emph{cell-based} cutoff and \emph{strict} cutoff and are selected by the \Lit{strict-cutoff} control parameter. In cell-based mode (\Lit{strict-cutoff=0}) the neighbour cell list is built to include only those cells whose centre is within the cutoff radius of the centre of the reference cell. All interactions between sites belonging to molecules in the neighbouring cell list are computed. This is a ``quick and dirty'' method as some interactions between sites closer than the cutoff will inevitably be excluded whereas some outside the cutoff range will be included. In strict mode (\Lit{strict-cutoff=1}) all interactions between pairs of \emph{sites} within the cutoff are included. The neighbouring cell list contains all pairs of cells with any parts closer than the cutoff plus twice the greatest molecular radius. This ensures that all appropriate interactions are included. Furthermore, all interactions between sites further apart than the cutoff are excluded (by the expedient of setting their separation to a large value in the potential calculation). This means that large and asymmetric molecules are handled correctly. For a given cutoff radius the cell-based mode is rather quicker than the strict mode since the neighbouring cell list is much smaller and fewer interactions are computed. However to ensure that significant interactions are not omitted, the cutoff ought to be set to a greater value than strictly required. This tends to offset the potential speed gain. On the other hand, if strict isotropy is required in a liquid simulation for example then the strict cutoff option ought to be used. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Temperature Initialization and Control}%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From the equipartition theorem, every degree of freedom in the system, $f$ has the same kinetic energy, given by $\left < {\mathcal K} \right >_f~=~\frac{1}{2}k_BT$. The effective temperature of the system is therefore given by the ensemble average of its kinetic energy. \begin{equation} \label{eqn:equipartition} T = \left < {\mathcal T} \right > = \frac{2}{gk_B} \left < \sum_{f=1}^{g} {\mathcal K}_f \right > = \frac{1}{3Nk_B}\left < \sum_{i=1}^N m_i \bm{v}_i^2 + \bm\omega_i \cdot \bm{I} \cdot \bm\omega_i \right > \end{equation} Here ${\mathcal K}_f$ is the instantaneous kinetic energy of degree of freedom $f$, $g$ is the number of degrees of freedom, $N$ is the number of molecules, $\mathcal T$ is an instantaneous ``temperature''. It is almost always desirable that a simulation be conducted so that the temperature is the supplied parameter rather than the kinetic energy. This requires some mechanism to fix the \emph{average} kinetic energy at thermal equilibrium. The \emph{initial} kinetic energy may be set approximately by choosing random velocities which sample the Maxwell-Boltzmann distribution at the desired temperature, and this is indeed what \moldy\ does on starting a new run (see section~\ref{sec:velinit}). But because the initial configuration is usually far from equilibrium it will have too much potential energy. As the run progresses this will be converted into kinetic energy, raising the temperature above the desired value. It is therefore necessary to have some mechanism for removing excess kinetic energy as the run progresses. \moldy\ offers several mechanisms to control the temperature. The common technique of \emph{velocity scaling} is suitable for use during the equilibration period but does not generate meaningful particle trajectories. The Nos\'e-Hoover method couples the system to a heat bath using a fictional dynamical variable and the Gaussian thermostat replaces the Newton-Euler equations by variants of which the kinetic energy is a conserved quantity. \subsection{Rescaling} \label{sec:rescaling} At periodic intervals linear and angular velocities are multiplied by a factor of \begin{equation} \label{eqn:scaling} s = \sqrt{\frac{gk_BT}{2\mathcal K}} \end{equation} where $T$ is the desired temperature. By repeatedly setting the ``instantaneous'' temperature to the correct value while the system approaches its equilibrium state, the kinetic energy is made to approach its desired value. \emph{Scaling} may be performed every timestep, or every few depending on the simulation conditions. An MD run with scaling does not generate a valid statistical ensemble, and it must therefore be switched off before any calculation of thermodynamic averages is performed. \moldy\ incorporates two refinements to the basic scaling algorithm (which are selected by the control parameter \Lit{scale-options}). Linear and angular velocities can be scaled independently, either for the whole system or for each species individually. In this way, one does not rely on the interactions of these degrees of freedom for convergence to equilibrium. In many systems these degrees of freedom are loosely coupled and the exchange of energy between them is slow. In these cases individual scaling can speed up the approach to equilibrium considerably. The other refinement addresses the problem of setting the temperature accurately. At equilibrium the system's kinetic energy fluctuates with mean-square amplitude\footnote{This formula actually applies to the Canonical rather than the microcanonical ensemble, but it serves for the purpose of this argument.} $\left < \delta {\mathcal K}^2\right > = \frac{1}{2}g\left(k_BT\right)^2$, which corresponds to a rms fluctuation in the instantaneous ``temperature'' $\sqrt{\left < \delta {\mathcal T}^2\right >} = \sqrt{2 /g} T$. The difficulty with applying equation~\ref{eqn:scaling} is the instantaneous kinetic energy $\mathcal K$ in the denominator. Strictly, scaling ought to use the \emph{average} kinetic energy $\left<\mathcal K \right>$ as in equation~\ref{eqn:equipartition}, but this quantity is not known until after the run is completed. Because of this equation~\ref{eqn:scaling} can only set the temperature to an accuracy of $\sqrt{1/g}$. This is often inadequate for purposes of comparison with experiment. In order to allow the temperature to be set with greater accuracy, \moldy\ allows the use of a partial average in the denominator, \begin{equation} \label{eqn:rav-scaling} s = \sqrt{\frac{gk_BT}{2\left < {\mathcal K}\right >^\prime}} \end{equation} where $\left < {\mathcal K}\right >^\prime$ is the ``rolling'' average of $\mathcal K$ over some number of preceding timesteps. That number is determined by the control parameter \Lit{roll-interval}. This option should be used cautiously. The change in $\left <{\mathcal K}\right >$ upon scaling only has a significant effect on the average after many timesteps. If the subsequent scaling is performed before this change is reflected in the value of $\left < {\mathcal K}\right >^\prime$ it will use an out-of-date value of the average kinetic energy. It is therefore recommended that the number of timesteps between scalings be greater than or equal to the number used to compute the rolling average. Otherwise it is possible to produce wild overshoots and oscillations in the temperature. Finally, there is a method for tackling really difficult cases when even individual scaling is unable to keep the temperature under control. This might be a far-from-equilibrium configuration where the potentials are so strong that velocities rapidly become very large, or when a single molecule acquires a very large velocity. In that case the velocities can all be re-initialized randomly from the Maxwell-Boltzmann distribution periodically. This provides a kind of pseudo Monte-Carlo equilibration for difficult cases. \subsection{Nos\'e-Hoover Thermostat} \label{sec:const-temp} A more sophisticated approach than rescaling is to couple the system to a heat bath. Nos\'e\cite{nose:84} proposed an extended-system Hamiltonian to represent the degrees of freedom of the thermal reservoir: \moldy\ uses the simpler but equivalent formulation by Hoover\cite{hoover:85,allen:87}. The equations of motion (equations~\ref{eqn:newton} and~\ref{eqn:euler}) are modified thus \begin{eqnarray} \label{eqn:nhtherm} \ddot{\bm{R}}_i = \frac{\bm{F}_i}{M_i} - \zeta \dot{\bm{R}}_i \nonumber \\ \bm{I}_i \cdot \dot{\bm\omega}_i - \bm\omega_i \times \bm{I}_i \cdot \bm\omega_i = \bm{N}_i - \zeta \bm{I}_i \cdot \bm\omega_i \\ \dot{\zeta} = \frac{g}{Q}\left ( k_B {\mathcal T} - k_B T \right ) \nonumber \end{eqnarray} \noindent where most of the symbols have their previous meanings, $g$ is the number of degrees of freedom in the system. $\zeta$ is a new ``heat bath'' dynamic variable and $Q$ is the associated fictitious ``mass'' parameter. With a suitable choice of $Q$ these equations generate trajectories which sample the canonical ensemble\cite{nose:84}. In other words both averages and fluctuations calculated as time averages from a simulation run tend to their canonical ensemble limits.% \footnote{There has been some discussion in the literature of the validity of representing a heat bath by a single dynamical variable, which the more diligent reader may wish to explore\cite{cho:93,nose:91}.} This does not necessarily guarantee the correctness of \emph{dynamical} quantities. It is apparent from equations~\ref{eqn:nhtherm} that $\zeta$ has the dimensions of a time derivative, and is analogous to the unit cell velocities in equations~\ref{eqn:par}. It is therefore treated as if it was a velocity and updated using only steps \emph{ii--v} of the Beeman integration procedure (equations~\ref{sec:beeman}). Note that the equation for the centre-of-mass acceleration depends \emph{indirectly} on the velocities through $\mathcal T$ as well as explicitly. The iteration on steps \emph{iii--v} of equations~\ref{sec:beeman} is therefore essential to integrate these equations consistently. There are two criteria to be considered when choosing the value of $Q$. The coupling to the heat bath introduces non-physical oscillations of period $t_0 = 2 \pi \sqrt{Q / 2 g k_B T}$ which may be easily detected in the total energy\cite{nose:91}. Firstly it must be arranged that there are sufficiently many oscillations during a simulation run that the computed thermodynamic values represent averages over many periods $t_0$. This ensures that the configurations used to calculate the averages sample the whole of the phase space generated by the fluctuations in $\zeta$ to represent the canonical ensemble. Secondly $Q$ should be chosen so that $t_0$ is large compared to the characteristic decay time of dynamical correlation functions. This is to ensure that the fictitious dynamics of the heat bath are decoupled from the real molecular dynamics, and is particularly important in a simulation of dynamic properties\cite{cho:92} such as velocity correlation functions. Since the first criteria favours a small $Q$ and the second a large one, it may be necessary to increase the total simulation time in order to satisfy them both. \subsection{Gaussian Thermostat} An alternative approach is known as ``constrained dynamics'' whereby the equations of motion are modified to generate trajectories which exactly satisfy ${\mathcal T} = T$ at all times. One such is the Gaussian constraint (see Allen and Tildesley\cite{allen:87} pp 230-231). The equations of motion are \begin{eqnarray} \label{eqn:gtherm} \itemsep=0.5em \ddot{\bm{R}}_i = \frac{\bm{F}_i}{M_i} - \zeta_T \dot{\bm{R}}_i \nonumber \\ \zeta_T = \frac{\sum_j\bm{v}_j \cdot \bm{F}_j}{\sum_j M_j\bm{v}_j^2} \\ \bm{I}_i \cdot \dot{\bm\omega}_i - \bm\omega_i \times \bm{I}_i \cdot \bm\omega_i = \bm{N}_i - \zeta_R \bm{I}_i \cdot \bm\omega_i \nonumber \\ \zeta_R = \frac{\sum_j\bm\omega_j \cdot \bm{N}_j}{\sum_j \bm\omega_j \cdot \bm{I}_j \cdot \bm\omega_j}\nonumber \end{eqnarray} These bear a superficial resemblance to equations~\ref{eqn:nhtherm} but now $\zeta$ is not itself a dynamical variable but a function of the other dynamical variables. Note that $T$ does not enter explicitly into equations~\ref{eqn:gtherm} since ${\mathcal T}$ is now a conserved quantity equal to its initial value at all subsequent times. Perhaps surprisingly these equations of motion generate configurational \emph{averages} from the canonical ensemble, but this does \emph{not} hold true for the momenta and therefore dynamics nor for fluctuations. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Constant Stress}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:const-stress} It is frequently desirable to conduct simulations under conditions of constant pressure or stress, rather than constant volume. For example, this allows the simulation of a solid-state phase transition with a change of symmetry or unit cell size. \moldy\ incorporates the constant pressure method of Parrinello and Rahman\cite{parrinello:81}. In a constant-stress simulation the MD cell changes in size and shape in response to the imbalance between the internal and externally applied pressure. For an exposition of the method the reader should refer to Parrinello and Rahman's paper\cite{parrinello:81} and to Nos\'{e} and Klein's extension to rigid molecular systems\cite{nose:83}. The equation of motion for the reduced centre-of-mass co-ordinates $\bm{S}_i = \bm{h}^{-1}\bm{R}_i$ is \begin{equation} \label{eqn:par} M_i\ddot{\bm{S}}_i = \bm{h}^{-1} \bm{F}_i - M_i \bm{G}^{-1}\dot{\bm{G}}\dot{\bm{S}}_i \end{equation} replacing the straightforward Newton equation~\ref{eqn:newton}. $\bm{h}$ denotes the $3 \times 3$ MD cell matrix whose columns are the MD cell vectors $\bm{a}, \bm{b}$ and $\bm{c}$, $\bm{F}_i$ is the centre-of-mass force and $\bm{G} =\bm{h^\prime h}$. Equation~\ref{eqn:euler}, the Euler equation, governs the angular motion exactly as in the constant-volume case. The dynamics of the unit cell matrix $\bm{h}$ are governed by the equation \begin{equation} \label{eqn:rahman} W\ddot{\bm{h}} = \left ( \bm\pi - p \right ) \bm\sigma \end{equation} where $W$ is a fictitious mass parameter, $\bm\sigma = V \bm{h}^{\prime-1}$ and $p$ is the external pressure. The instantaneous internal stress $\bm\pi$ is given by \begin{equation} \label{eqn:prstress} \bm\pi = \frac{1}{V}\sum_{i=1}^N m_i (\bm{h}_i\dot{\bm{s}}_i)^2 + \bm\pi^{\textnormal{s.r.}} + \bm\pi^e \end{equation} with the short-ranged and electrostatic components given by equations~\ref{eqn:stress-sr} and~\ref{eqn:ewald-stress} respectively. The choice of fictitious mass, $W$ is governed by similar considerations to those concerning the heat bath mass, $Q$ discussed in section~\ref{sec:const-temp}. Nos\'{e} and Klein\cite{nose:83} describe and address the problem of the whole MD cell rotating during the course of the simulation. This is because angular momentum is not conserved in a periodic system, and because the $\bm{h}$ matrix has 9 degrees of freedom, three more than needed to specify the position and orientation of the MD cell. Their solution is to constrain the $\bm{h}$ matrix to be symmetric, and involves a modification of the Parrinello-Rahman equations. \moldy\ incorporates a rather different constraint which is not only simpler to implement (as it does not require modification of the equations of motion) but which also has a more obvious physical interpretation. The lower three sub-diagonal elements of the $\bm{h}$ matrix are constrained to zero. In other words the MD cell vector $\bm{a}$ is constrained to lie along the $x$-axis and $\bm{b}$ is constrained to lie in the $xy$-plane. Physically this may be thought of as implementing an MD box lying on a horizontal surface under the influence of a weak gravitational field. The implementation is trivial; at each timestep the acceleration of those components, $\ddot{\bm{h}}_{ij}$, is set to zero which is equivalent to adding a fictitious opposing force. This constraint technique is not restricted merely to eliminating redundant degrees of freedom, but can also be used for other purposes. For example it may be used to allow uniaxial expansion only. The most important use of $\bm{h}$ matrix constraints however is probably for simulations of liquids. Since a liquid can not support shear stress there is no restoring force to keep the simulation cell nearly cubic, and it will therefore drift to a parallelepiped shape. To counter this tendency $\bm{h}$ may be constrained so that only the diagonal elements are non-zero and allowed to change. This does not give a completely isotropic MD cell expansion, but the time average should tend towards a cubic cell. MD cell constraints are selected using the control parameter \Lit{strain-mask} (see section~\ref{sec:cp-constraints}). A value of 238 will freeze the off-diagonal components of $\bm{h}$. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Radial Distribution Functions}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%` \label{sec:rdf} The \emph{radial distribution function} or RDF is one of the most important structural quantities characterizing a system, particularly for liquids. For a one-component system, the RDF is defined as\cite[p445]{hansen:86} \begin{eqnarray} g(r) & = & \frac{1}{\rho^2} \left < \sum_i \sum_{j\neq i} \delta(\bm{r} + \bm{r}_i - \bm{r}_j) \right > \\ \nonumber & \approx & V \left < \delta(\bm{r} + \bm{r}_1 - \bm{r}_2) \right > \end{eqnarray} where we use the angle brackets to denote a spherical average as well as the usual configurational average. Allen and Tildesley\cite[pp184,185]{allen:87} describe how to evaluate $g(r)$ from a histogram of pair distances accumulated during a simulation run. With the notation that $N$ is the total number of particles, $b$ is the number of the histogram bins, $\delta r$ is the bin width (so that $r = b \delta r$), $n_{\textnormal{his}}(b)$ is the accumulated number per bin, $\tau$ is the number of steps when binning was carried out \begin{equation} \label{eqn:rdf-atom} g(r + \delta r/2) = \frac{3 n_{\textnormal{his}}(b)}{4 \pi \rho N \tau [(r + \delta r)^3 - r^3]} \end{equation} In the case of a molecular system, the partial RDF for atoms $\alpha$ and $\beta$ is defined as\cite[p 445]{hansen:86} \begin{equation} g_{\alpha \beta}(r) = \frac{1}{\rho^2 V} \left < N(N-1)\delta(\bm{r} + \bm{r}_{1\alpha} - \bm{r}_{2\beta}) \right > \end{equation} which may be rewritten more usefully for an arbitrary multi-component mixture by eliminating the molecular density $\rho$ and number $N$ as \begin{equation} g_{\alpha \beta}(r) = V \left < \delta(\bm{r} + \bm{r}_{1\alpha} - \bm{r}_{2\beta}) \right > \end{equation} In the simulation this is evaluated by an expression very similar to equation~\ref{eqn:rdf-atom} \begin{equation} \label{eqn:rdf-site} g_{\alpha \beta}(r + \delta r/2) = \frac{3 N n_{\textnormal{his}}(b)}{4 \pi \rho N_\alpha N_\beta \tau [(r + \delta r)^3 - r^3]} \end{equation} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{The Initial Configuration}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% One of the more trying aspects of initiating a molecular dynamics simulation is getting it started in the first place. It is not hard to see the reason why. An MD integration algorithm will only generate a good approximation to the correct equations of motion if the forces and velocities of the particles are less than some value. The timestep is chosen so that this criterion is satisfied for near-equilibrium configurations. But if the configuration is far from equilibrium certain forces may be extremely large (due to atoms approaching each other too closely). And worse, the breakdown of the integrator leads to breakdown of the conservation laws and the system evolves to a state even further from equilibrium. One way around this difficulty is to start the system from a configuration known to be near-equilibrium, such as a known crystal structure. For a solid-state simulation this is the method of choice, and \moldy\ allows any initial structure to be specified and replicated to fill the MD cell. In the case of a liquid, a crystalline initial state is less desirable, and indeed, none may be known. Furthermore such a starting configuration restricts the allowed number of molecules to a multiple of the number in the unit cell and worse, may force the use of a non-cubic MD cell. \moldy\ incorporates a novel method of generating an initial configuration which, in the main, overcomes these problems. \subsection{The Skew Start Method} \label{sec:skewstart} The essence of the \emph{Skew Start} method is to generate a configuration which, though not periodic in 3 dimensions, nevertheless is sufficiently regular to guarantee a minimum separation between molecular centres of mass. Figure~\ref{fig:skewstart} demonstrates the principle in 2 dimensions. \begin{figure} \setlength{\unitlength}{0.012500in}% \input{fig_skewstart} \caption[The Skew Start method]{The Skew Start method. $N$ molecules are placed at evenly-spaced intervals, $a$ on a line joining a corner of the MD cell to its image $k$ cells away (5 in this illustration). When mapped back into the original cell this guarantees a minimum separation of $min(d,a)$.} \label{fig:skewstart} \end{figure} The $N$ molecules are placed at some suitable interval $a$ on a line drawn between one corner of the MD cell (of side $L$) and one of its periodic images. Clearly the index $(h,k)$ of the image cell corner should be chosen so that the molecule spacing, $a$ is close to the spacing of the line's images, $d$. For simplicity, choose $k=1$ which leads to the condition: \begin{eqnarray} \nonumber &a = \frac{L \sqrt{h^2+1}}{N} \approx \frac{L}{\sqrt{h^2+1}} = d \\ & \Rightarrow h \approx \sqrt{N-1} \end{eqnarray} Therefore the optimum value of $h$ is the nearest integer to $\sqrt{N-1}$. The formalism may be extended to three dimensions, and yields the results for the molecular and ``inter-line'' spacings $a$, $d_y$ and $d_z$ respectively \begin{eqnarray} \label{eqn:skew-hkl} \nonumber a & = & \frac{L}{N}\sqrt{h^2+k^2+l^2}\\ d_y & = & L \frac{\sqrt{k^2+l^2}}{\sqrt{h^2+k^2+l^2}} \\ d_z & \approx & L\frac{l}{k} \qquad\textnormal{(assuming $h/k$ is an integer)} \nonumber \end{eqnarray} The ``equal spacing'' requirements are satisfied approximately by \begin{eqnarray} \nonumber h & \approx & N^{2/3} \\ k & \approx & N^{1/3} \\ \nonumber l & = & 1 \end{eqnarray} which when substituted into equation~\ref{eqn:skew-hkl} yields \begin{equation} a \approx d_y \approx d_z \approx LN^{-1/3} \end{equation} Using this method an arbitrary number of molecules may be packed into a cubic cell with a guaranteed minimum centre-of-mass separation of approximately $LN^{-1/3}$. In contrast to other methods, such as random placement with excluded volume, it will always yield a configuration no matter how high the density. It is also very simple to implement. It still remains to determine the initial orientations of the molecules in the case of polyatomics. In the current implementation these are assigned randomly, which works well for small or near-spherical molecules. Further refinements which may help avoid overlaps for elongated molecules are possible, such as a periodic sequence of orientations along the line, but no investigation of this possibility has yet been carried out. In practice the method has proved to work well for water and aqueous systems and always yields a configuration which may be evolved towards equilibrium by the MD equations of motion. Any feedback on its performance in more difficult cases will be welcome. \subsection{Initial Velocities} \label{sec:velinit} It remains to choose the initial velocities of the molecules to complete the specification of the initial configuration. The recipe is the same irrespective of whether the molecules are started on a lattice or from a skew start. The initial centre-of-mass velocities are chosen from the Maxwell-Boltzmann distribution at the temperature specified for the simulation\cite[pp 170]{allen:87}. That is, the velocities are chosen from a set of random numbers with a Gaussian distribution and normalized so that the probability density $p(v)$ of the $xyz$ component of the velocity $v_{ik}$ of molecule $k$ is \begin{equation} p(v_{ik}) = \left ( \frac{m_k}{2 \pi k_B T}\right )^{1/2} \exp(-\frac{m_k v_{ik}^2}{2 k_B T}) \end{equation} This is easily accomplished given a random number generator which samples from a Gaussian distribution with unit variance. Given a random number $R_{ik}$, each component of velocity is set to \begin{equation} v_{ik} = \sqrt{\frac{k_B T}{m_k}} R_{ik} \end{equation} Each component of the angular velocity (expressed in the principal frame) has a probability distribution \begin{equation} p(\omega^p_{ik}) = \left ( \frac{I_{ik}}{2 \pi k_B T}\right )^{1/2} \exp(-\frac{I_{ik} (\omega^p_{ik})^2}{2 k_B T}) \end{equation} which is ensured by assigning a random velocity \begin{equation} \label{eqn:omega-rand} \omega^p_{ik} = \sqrt{\frac{k_B T}{I_{ik}}} R_{ik} \end{equation} Since the dynamical variables used by \moldy\ for the angular co-ordinates are in fact the quaternions and their derivatives, we must set the quaternion derivatives and accelerations to the corresponding values. Using equations~\ref{eqn:qomega} and~\ref{eqn:qddot} we have \begin{equation} \Quat{\dot{q}} = \Quat{q}(0,\bm\omega^p/2) \end{equation} and \begin{equation} \Quat{\ddot{q}} = -\frac{1}{4}(\omega^p)^2 \Quat{q} \end{equation} Finally, we note that if a molecule has less than three degrees of freedom, that is $I_{ik}=0$ for some $i$ the corresponding angular velocities \etc\ are simply set to zero. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Frameworks}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:frameworks} In addition to the bulk properties of solids and liquids, much attention has been devoted in recent years to using MD simulation to model atoms or molecules interacting with surfaces or other structures such as zeolites. The distinctive feature of such a situation is that the 2- or 3-dimensional surface or structure is larger than the interacting molecules by many orders of magnitude. In fact the idealization of this system makes the structure infinite in extent. An atomistic model of this kind of a system necessitates choosing the periodic boundary conditions of the MD cell to be commensurate with the periodicity of the surface or structure. This manual will refer to an infinitely repeating crystalline surface or structure as a \emph{framework}. There are two possible formulations of a system of this kind for use in a MD simulation. Firstly the framework may be modelled as a set of independent atoms interacting via pair potentials. This merely requires specifying the correct initial structure and MD cell plus a suitable set of pair potentials. The latter model both the internal forces which determine the crystal structure of the framework and its interaction with the atoms or molecules of the fluid. Conceptually there is no distinction between this situation and a regular solid or liquid system, and the mechanics of initiating a simulation are handled in exactly the usual manner. However there are situations in which this ``atomic'' approach is impractical. Because the system being modelled is essentially ``two-phase'' the atoms of the framework find themselves under the influences of two distinct kinds of force. There are the strong forces, usually covalent or ionic, which bind the atoms to form the framework itself and the weaker, non-bonded forces of the interaction with the fluid. Ideally these could all be modelled by a single consistent set of interatomic potentials which are sufficiently transferable to yield an accurate crystal structure for the framework as well as the molecular structure of the fluid and its interaction with the surface. Regrettably such potentials are hard to find. Furthermore the characteristic vibrational frequencies of the solid framework will probably be much higher than those of the fluid. Consequently the timestep must be chosen sufficiently small to accurately model the crystalline vibrations. This will usually be far smaller than the value required for the fluid, necessitating very lengthy MD runs to model both regimes properly. This is, of course, exactly the argument used to justify rigid-molecule models. \moldy\ implements a variation on the rigid-molecule model to simulate a rigid framework structure periodically extended throughout space. There are a few subtleties which must be correctly handled to achieve a consistent implementation, which are described hereafter. \subsection{Implementation} The framework is in many respects exactly like an ordinary molecule. It should be defined to exactly fill the MD cell so that the periodic repeat of the cell generates the periodicity of its crystal structure. The distinctive features of a framework molecule are: \begin{itemize} \item The framework is fixed in space and is not allowed to rotate. Any rotation would of course destroy the 3D structure. For most purposes it is convenient to regard the framework as being at rest, hence translational motion is forbidden also. \item No interactions between sites on a framework molecule and on itself or any of its periodic images are evaluated. That is, framework-framework interactions, both potentials and forces, are systematically excluded from the real-space and reciprocal-space parts of the Ewald sum, including the point and intra-molecular self terms of equation~\ref{eqn:ewald}. (The exact modifications to equations~\ref{eqn:ewald},\ref{eqn:ewald-force} \etc\ are left as an exercise for the reader.) \item In the real-space force calculation, sites are treated as being independent atoms rather than belonging to a molecule. In particular the cutoff is applied on the basis of the (framework) site to (fluid) molecule distance. By virtue of the ``all-image'' convention, all the requisite molecule-framework interactions are correctly included. When assigning sites to sub-cells, each site is therefore placed in the sub-cell which contains its co-ordinate. (By contrast sites belonging to an ordinary molecule are placed in the cell which contains the molecular centre of mass.) \end{itemize} With these modifications, \moldy\ is able to successfully model a fluid in contact with a 3D rigid framework. 2-dimensional systems such as a fluid at a surface or between two surfaces may be represented as a 3D system by adding an artificial periodicity in the third dimension. To reduce the errors so introduced, the framework can be made ``large with space inside'' to fill a MD cell with a large $c$-axis. In the case of a 3D framework it is clearly not sensible to allow the MD cell to change shape or size, since this would destroy the internal structure of the framework. However if the framework represents a 2D layer or surface, then the layer spacing may be allowed to vary using the constant-stress equations (section~\ref{sec:const-stress}) and applying constraints to allow only the $c$-axis to fluctuate. In that case, bear in mind that the dynamics are governed by the Parrinello-Rahman equations of motion for the cell, rather than the Newtonian equations for the layer. In particular the mass is given by the parameter $W$ rather than the mass of the framework molecule. (These may, of course be set equal if required.) Note also that no layer-layer interactions are calculated, and any force is the result of the externally applied pressure.\footnote{This is a restriction of the current implementation and may be lifted in future versions.} Finally there are two subtle complications which arise from the framework concept. \subsection{Stress and Pressure Undefined} There is no unique definition of the internal stress or pressure of a framework system. The pressure of a system in a space with periodic boundary conditions is defined in terms of the molecular virial \begin{equation} \label{eqn:virial} {\mathcal W} = \frac{1}{3} \sum_{i=1}^N \sum_{j \neq i}^N \bm{R}_{ij} \cdot \bm{F}_{ij} \end{equation} But the framework has no centre-of-mass, and so the quantity $\bm{R}_{ij}$ can not be defined. The site-virial formulation of equation~\ref{eqn:stress-sr} is of no assistance as the definition of the ``internal'' co-ordinate $\bm{p}_{i\alpha}$ involves the centre of mass co-ordinate $\bm{R}_i$. Neither can one simply choose a convenient reference $\bm{R}_i$. Since the force exerted by the fluid acting on the framework is in general non-zero, the term \begin{equation} \sum_i \sum_\alpha \bm{p}_{i\alpha} \bm{f}_{i\alpha} = \sum_i \sum_\alpha \bm{r}_{i\alpha} \bm{f}_{i\alpha} - \sum_i \bm{R}_i \bm{F}_i \end{equation} clearly depends on $\bm{R}_i$. The situation may also be viewed physically. The definition of pressure of a system is the derivative of the free energy with respect to volume. But with an infinite rigid framework the volume derivative can not be defined. The useful quantity in this case is the partial pressure of the fluid. Though not currently implemented, this may be rectified in a future version of \moldy. Finally we note that in the case of a 2D layer structure, which is \emph{not} rigid in the third dimension the perpendicular component if the stress tensor \emph{does} have a physical meaning and is correctly calculated. \subsection{Charged Frameworks} A minor complication arises when using a framework which has a non-zero net electric charge. Although the system as a whole may be electrically neutral, the omission of framework-framework interactions from the calculation also means that the $\bm{k}=0$ term does not vanish. To see this examine equation~\ref{eqn:ewald}. In the non-framework case the indices $i$ and $j$ in the terms \begin{displaymath} \left | \sum_{i=1}^{N} q_i \cos(\bm{k \cdot r}_i) \right |^2 = \sum_{i=1}^{N} \sum_{j=1}^{N} q_i q_j \cos(\bm{k \cdot r}_i)\cos(\bm{k \cdot r}_j) \end{displaymath} run over all site pairs. If $\bm{k}=0$ the squared sum is \begin{displaymath} \left | \sum_{i=1}^{N} q_i \right |^2 = 0 \end{displaymath} If a framework is present the formulation becomes \begin{displaymath} \left | \sum_{i=1}^{N} q_i \cos(\bm{k \cdot r}_i) \right |^2 - \left | \sum_{i=M\!+\!1}^{N} q_i \cos(\bm{k \cdot r}_i) \right |^2 \end{displaymath} assuming sites $M+1 \ldots N$ are the framework sites. On setting $\bm{k}=0$ this reduces to \begin{displaymath} \left | \sum_{i=1}^N q_i \right |^2 - \left | \sum_{i=M\!+\!1}^N q_i \right |^2 \end{displaymath} It is therefore necessary to modify the charged-system term of equation~\ref{eqn:ewald} to \begin{equation} U_z = - \frac{1}{8 \epsilon_0 V \alpha^2} \left \lbrace \left | \sum_{i=1}^N q_i \right |^2 - \left | \sum_{i=M\!+\!1}^N q_i \right |^2 \right \rbrace \end{equation} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Running Moldy} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The way \moldy\ is invoked depends to some extent on the operating system, but usually by issuing the command \Lit{moldy}.\footnote{On VMS, \Lit{moldy} may be defined as a foreign command by \Lit{\$ moldy :== \$mydisk:[mydir]moldy}} For Unix(tm) and MS-DOS the executable file \Fname{moldy} or \Fname{MOLDY.EXE} should be placed in the shell search path (\eg\ in the current directory). There are two optional arguments - the name of the control file (see section~\ref{sec:control}) and the output file (see section~\ref{sec:output}). If either is omitted, control input is read from the ``standard input'' which may be a terminal or a job command file depending on the operating system and circumstances, and the output is written to ``standard output'' which may be a terminal or batch job logfile.\footnote{Some operating systems (Unix and MS-DOS) allow \emph{file redirection} whereby the standard input is associated with some file. This may also be used to supply the control file, provided that no command line parameter is given.} Here are examples for VAX/VMS and Unix (tm), which assume that in each case the command has been set up to invoke \moldy. Under VMS the commands \begin{verbatim} $ moldy control.dat output.lis $ moldy control.dat \end{verbatim} will start \moldy\ which will read its input from \Fname{control.dat}. The output will be directed to the file \Fname{output.lis} in the first case and written to the terminal or batch log in the second. Under UNIX any of \begin{verbatim} % moldy < control > output.lis % moldy control output.lis % moldy control \end{verbatim} will cause moldy to read from the file called \Fname{control} and in the first two examples to write its output to \Fname{output.lis}. The command-line interface for MS-DOS is very similar. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{The Control File}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:control} The information needed to initiate and control a run of \moldy\ is specified in a file known as the \emph{control file}. This contains the parameters governing the run \eg\ the number of timesteps to be executed or the frequency of output, and the names of files to be used \eg\ for reading a restart configuration from or for writing the output to. Parameters in the control file are specified by entries of the form \Lit{keyword~=~value} which appear one to a line, terminated by the special keyword \Lit{end}. Spaces and blank lines are ignored as are comments (\ie\ the remainder of a line following a \Lit{\#}~symbol) and keywords may be entered in upper or lower case. For example \begin{verbatim} title= Moldy example # This is a comment # The above blank line is ignored nsteps = 1000 step=0.0005 restart-file = RESTART.DAT end # The control file ends here \end{verbatim} sets the title of the simulation to ``Moldy example'', the number of steps to execute to 1000, the timestep to 0.0005ps and supplies the name of a restart file to read from. It is not necessary to specify all of the parameters on each run. Unless it is explicitly assigned a value in the control file, each parameter has a default value. This is either the value listed in table~\ref{tab:parameters} or, in the case where the simulation is continuing from a restart file, the value it had on the previous run (see section~\ref{sec:restarting}). Parameters are read in sequence from the control file and if one appears more than once only the final instance is used. The two most important parameters are \Lit{step} which sets the size of the simulation timestep (in ps), and \Lit{nsteps} which specifies the number of steps to perform. Together these control the length of time to be simulated. It is also possible to specify that a run should be terminated after a certain amount of computer time has been used - given by parameter \Lit{cpu-limit}. This will be particularly useful in batch mode systems, where the run is killed after some specified CPU time has elapsed. Setting \Lit{cpu-limit} to the maximum time allowed will cause \moldy\ to terminate the run \emph{before} the limit is reached and write out a backup file (see section~\ref{sec:backup}). There are several kinds of parameters: \begin{description} \item[character strings] Apart from \Lit{title} these are just file names \eg\ \Lit{sys-spec-file}. No checks are performed on the validity of the name (because \moldy\ has to work on many different computer systems), so if you make a mistake you are likely to get an error message to the effect that \moldy\ couldn't find the file you asked for. To remove a default value, just specify a null string \eg\ \Lit{save-file = }. \item[booleans] These are just switches which turn a feature off or on. `0' means off or false and `1' means on or true. The parameters \Lit{text-mode-save}, \Lit{new-sys-spec}, \Lit{surface-dipole} and \Lit{lattice-start} are booleans. \item[real parameters] Several parameters are real numbers \eg\ \Lit{step} which specifies the timestep. They may be entered in the usual floating point or scientific notation \eg\ \Lit{step~=~0.0005} or \Lit{step~=~.5e-3}, and are taken to be in the units given in table~\ref{tab:parameters}. \item[integer parameters] Parameters such as \Lit{dump-level} take a numeric value, which should be an integer. \item[timestep-related parameters] Several parameters govern when some calculation begins and ends and how frequently it is performed in between. These are known as ``begin'', ``end'' and ``interval'' parameters, but are really a special case of integer parameters. For example \Lit{begin-average}, \Lit{dump-interval} and \Lit{scale-end}. The calculation begins \emph{on} the timestep specified on the \Lit{begin} parameter, occurs every \Lit{interval} timesteps thereafter and ends \emph{after} the timestep specified by the \Lit{end} parameter. Setting the \Lit{interval} parameter to zero is the usual method of turning that calculation off. The \Lit{begin} and \Lit{end} parameters behave in a special fashion when the simulation is continued from a restart file; they are interpreted \emph{relative} to the current timestep. Notice especially that \Lit{nsteps}, the number of timesteps is treated in this way. \end{description} A complete list of the parameters, their meanings and default values appears in table~\ref{tab:parameters}. \begin{table} \begin{minipage}{\textwidth} \caption{Control Parameters} \label{tab:parameters} \setlength{\rightskip}{0pt plus 2cm} \begin{tabular}{|l|l|l|>{\saferagged}p{2.9in}|} \hline \textbf{name} & \textbf{type}\footnote{See section~\ref{sec:control}} & \textbf{default} & \textbf{function} \\ \hline \hline \Lit{title} & character & {\small Test Simulation} & A title to be printed on all output. \\ \Lit{nsteps} & integer & 0 & Number of MD steps to execute. \\ \Lit{cpu-limit} & real & 1e20 & Terminate run if excessive CPU time used. \\ \Lit{step} & real & 0.005 & Size of timestep \\ \hline \Lit{sys-spec-file} & character & null & Name of system specification file. Appended to control file if null. \\ \Lit{lattice-start} & boolean & false & Switch for crystalline initial configuration. \\ \Lit{save-file} & character & null & File to save restart configuration in. \\ \Lit{restart-file} & character & null & File to read restart configuration from. \\ \Lit{new-sys-spec} & boolean & false & Read restart configuration with changed system specification. \\ \Lit{text-mode-save} & boolean & false & Write a portable ``restart'' file consisting of control, system specification and lattice start files. \\ \hline \Lit{density} & real & 1.0 & Initial density in g\,cm$^{-3}$. Used by \emph{skew start} only to determine initial MD cell dimensions. \\ \hline \Lit{scale-interval} & integer & 10 & Number of steps between velocity scalings. \\ \Lit{scale-end} & integer & 1000000 & When to stop scaling. \\ \Lit{const-temp} & integer & 0 & 1 for Nos\'e-Hoover, 2 for Gaussian thermostat. \\ \Lit{ttmass} & real & 100 & Translational inertia parameter for Nos\'e-Hoover thermostat (kJ\,mol$^{-1}$\,ps$^2$).\\ \Lit{rtmass} & real & 100 & Rotational inertia parameter for Nos\'e-Hoover thermostat (kJ\,mol$^{-1}$\,ps$^2$).\\ \Lit{scale-options} & integer & 0 & Select variations on scaling or thermostat. \\ \Lit{temperature} & real & 0 & Temperature of initial configuration for scaling and thermostat (K). \\ \hline \Lit{const-pressure} & boolean & false & Whether to use Parrinello and Rahman constant stress. \\ \Lit{w} & real & 100.0 & Value of P \& R mass parameter (amu). \\ \Lit{pressure} & real & 0 & External applied pressure (MPa). \\ \Lit{strain-mask} & integer & 200 & Bitmask controlling $\bm{h}$ matrix constraint. \\ \hline \Lit{alpha} & real & \emph{auto} & $\alpha$ parameter for Ewald sum. \\ \Lit{k-cutoff} & real & \emph{auto} & Reciprocal space cut off distance in \AA$^{-1}$. \\ \Lit{cutoff} & real & \emph{auto} & Direct space cutoff distance in \AA. \\ \Lit{strict-cutoff} & boolean & false & Flag to select rigorous or cheap but approximate cutoff algorithm. \\ \Lit{surface-dipole} & boolean & false & Include De Leeuw \& Perram term in Ewald sum. \\ \hline \Lit{roll-interval} & integer & 10 & Period over which to calculate rolling averages. \\ \Lit{print-interval} & integer & 10 & How frequently to print normal output. \\ \hline \end{tabular} \end{minipage} \end{table} \begin{table} \begin{minipage}{\textwidth} \caption{Control Parameters (continued)} \setlength{\rightskip}{0pt plus 2cm} \begin{tabular}{|l|l|l|>{\saferagged}p{2.9in}|} \hline \textbf{name} & \textbf{type}\footnote{See section~\ref{sec:control}} & \textbf{default} & \textbf{function} \\ \hline \hline \Lit{begin-average} & integer & 1001 & When to start accumulating the thermodynamic averages. \\ \Lit{average-interval} & integer & 5000 & How frequently to calculate and print averages. \\ \Lit{reset-averages} & boolean & false & Discard accumulated averages in restart file. \\ \hline \Lit{begin-rdf} & integer & 1000000 & When to start accumulating radial distribution function information. \\ \Lit{rdf-interval} & integer & 20 & How frequently binning calculation is performed. \\ \Lit{rdf-out} & integer & 5000 & How frequently to calculate and print RDFs. \\ \Lit{rdf-limit} & real & 10 & Calculate RDFs up to what distance? (\AA) \\ \Lit{nbins} & integer & 100 & Number of binning intervals between 0 and rdf-limit. \\ \hline \Lit{xdr} & boolean & true & Write restart, backup and dump files in portable binary format using Sun XDR. \\ \hline \Lit{dump-file} & character & null & Template of file names used for data dumps. \\ \Lit{begin-dump} & integer & 1 & Timestep to begin dumping at. \\ \Lit{dump-interval} & integer & 20 & How frequently to perform dumps. \\ \Lit{dump-level} & integer & 0 & Amount of information to include in dump. \\ \Lit{ndumps} & integer & 250 & Number of dump records in each dump file. \\ \hline \Lit{backup-interval} & integer & 500 & Frequency to write backup file. \\ \Lit{backup-file} & character & \Fname{MDBACKUP} & Name of backup file. \\ \hline \Lit{temp-file} & character & \Fname{MDTEMPX} & Name of temporary file used for writing restart configurations. \\ \hline \Lit{subcell} & real & 0 & Size of sub-cell (in \AA) to divide MD cell into for link cell force calculation. \\ \hline \Lit{seed} & integer & 1234567 & Seed for random number generator. \\ \hline \Lit{page-width} & integer & 132 & Number of columns on output paper. \\ \Lit{page-length} & integer & 44 & Number of lines on a page of output. \\ \hline \Lit{mass-unit} & real & 1.6605402e-27 & Unit of mass for system specification file. \\ \Lit{length-unit} & real & 1e-10 & Unit of length for system specification file. \\ \Lit{time-unit} & real & 1e-13 & Unit of time for system specification file. \\ \Lit{charge-unit} & real & 1.60217733e-19 & Unit of charge for system specification file. \\ \hline \end{tabular} \end{minipage} \end{table} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Setting up the System}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{System Specification} \label{sec:sys-spec} The information which describes to \moldy\ the system to be simulated and the interaction potentials is contained in a file known as the \emph{system specification file}. This may be presented to \moldy\ in either of two ways: If the control file parameter \Lit{sys-spec-file} is null or absent, it is assumed to be appended to the end of the control file. Otherwise it is read from the file whose name is the value of \Lit{sys-spec-file}. This file is divided into two sections. First is the description of the molecules, atoms or ions, which is followed by the potential functions. As for the control file, the input is case independent and free format, but line structured. Blank lines, spacing and comments are ignored. The physical description consists of a series of entries, one for each molecular species, terminated by the keyword \Lit{end}. The entry for species $i$ should have the form \begin{displaymath} \begin{array}{lllllll} \multicolumn{7}{l}{\textit{species-name}_{i} \quad N_{i}} \\ id_{1} & x_{1} & y_{1} & z_{1}& m_{1} & q_{1} & name_{1} \\ id_{2} & x_{2} & y_{2} & z_{2}& m_{2} & q_{2} & name_{2} \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ id_{n_{i}} & x_{n_{i}} & y_{n_{i}} & z_{n_{i}}& m_{n_{i}} & q_{n_{i}} & name_{n_{i}} \\ \end{array} \end{displaymath} where \textit{species-name}$_{i}$ is the name of the molecule and $N_{i}$ is the number of molecules of that type in the system. Each molecule has $n_{i}$ atoms, one for each line in that group and each kind of atom is identified by a number $id_{i}$ (the site id) which will be used to specify the appropriate potential parameters. Its co-ordinates are $(x_{i},y_{i},z_{i})$, its mass is $m_{i}$, its charge is $q_{i}$ and its name is $name_{i}$. See Appendix~\ref{sec:examples} for some sample system specification files. If there is more than one atom of any type (in the system - not just the same molecule) it is sufficient to identify it by its $id$ (and the site co-ordinates!). If $m_{i}$, $q_{i}$ or $name_{i}$ \emph{are} given they must agree exactly with the previous values or an error will be signalled. Site ids, masses and charges are all checked for `reasonableness' and impossible values cause an error. The set of site ids does not have to start at 1 or be contiguous, but since this may indicate a mistake, a warning is issued. Following the physical specification is the specification of the potential functions. This takes the form \begin{displaymath} \begin{array}{llllll} \multicolumn{4}{l}{\textit{potential-type}} \\ i & j & p^{1}_{ij} & p^{2}_{ij} & \ldots & p^{r}_{ij} \\ k & l & p^{1}_{kl} & p^{2}_{kl} & \ldots & p^{r}_{kl} \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ m & n & p^{1}_{mn} & p^{2}_{mn} & \ldots & p^{r}_{mn} \\ \Lit{end} \\ \end{array} \end{displaymath} where \emph{potential-type} is one of the keywords \Lit{Lennard-Jones}, \Lit{Buckingham} or \Lit{MCY} or \Lit{generic} to identify the kind of potentials to be used, $i, j, k, l, m, n$ are site ids and $p^{\alpha}_{ij}$ is the $\alpha^{th}$ potential parameter between sites $i$ and $j$. There should be one line for each distinct pair of site ids. If any pair is omitted a warning is issued and the parameter values are set to zero. The meaning of the parameters for the currently defined potentials is as follows: \begin{Litdescription} \item[Lennard-Jones] The potential is \[\phi(r_{ij}) = \epsilon((\sigma/r_{ij})^{12}) - (\sigma/r_{ij})^{6}),\] and has two parameters, $\epsilon ( \equiv p^{1}_{ij})$ and $\sigma ( \equiv p^{2}_{ij})$, which occur on each line in that order. Note that the definition of $\epsilon$ \emph{includes} the factor of 4 more usually separated out. The control parameter \Lit{time-unit} may be divided by four to read potentials specified in the standard form. \item[Buckingham] This includes potentials of the Born-Mayer type and has formula \[\phi(r_{ij}) = -A_{ij}/r^{6}_{ij} + B_{ij}\exp(-C_{ij}r_{ij}).\] The three parameters appear on each line in the order $A, B, C$. \item[MCY] This type supports potentials of the same form as the water model of Matsuoka, Clementi and Yoshimine\cite{matsuoka:75}, \[\phi(r_{ij}) = A_{ij}\exp(-B_{ij}r_{ij}) - C_{ij}\exp(-D_{ij}r_{ij}),\] and the four parameters appear on the line in the order $A, B, C, D$. \item[generic] This contains a number of inverse power terms and an exponential repulsion in support of ionic solution models. It takes the form \[\phi(r_{ij}) = A_{ij} \exp(-B_{ij}r_{ij}) + C_{ij}/r_{ij}^{12} - D_{ij}/r_{ij}^4 -E_{ij}/r_{ij}^6 -F_{ij}/r_{ij}^8\] with the six parameters $A_{ij}$ -- $F_{ij}$. \end{Litdescription} \noindent Other types of potential may be easily added: see section~\ref{sec:newpot}. It is possible to specify the units in which these quantities are given by means of the control file parameters \Lit{mass-unit}, \Lit{length-unit}, \Lit{time-unit} and \Lit{charge-unit} (which are themselves specified in SI units). All quantities read from the system specification file (dimensions as well as potentials) are taken to be in those units. Their default values are amu, \AA, 0.1ps and $q_{e}$, which means that the unit of energy is kJ mol$^{-1}$. So to read in \AA, amu and kcal mol$^{-1}$, specify \Lit{time-unit=4.8888213e-14}. Once the system specification has been read in, all quantities are converted to `internal' units: a.m.u., \AA, ps, and $\insqrt ( \textnormal{a.m.u. \AA}^{3} \textnormal{ps}^{-2}/(4 \pi \epsilon_{0}) )$. The prototype molecule for each species is then shifted so that its zero of coordinates lies on its centre of mass, and rotated into the principal frame (polyatomics only). \subsection{The Initial Configuration} \moldy\ provides two methods of setting up an initial configuration. By default the \emph{skew start} method of section~\ref{sec:skewstart} is used to place the molecular centres of mass in a regular arrangement which ensures molecular separation. If there is more than one species present, molecules of each are chosen randomly for each site. Molecular orientations are chosen randomly from a uniform distribution. This method has been found to work well for reasonably small or fairly isotropic molecules and it is anticipated that it will be the usual method of starting a simulation of the liquid state. On the other hand, if the constituent molecules are sufficiently large and irregular, or if it is intended to simulate the solid state then the \emph{lattice start} method will be more appropriate. This method is activated by setting the control parameter \Lit{lattice-start} to 1, and creates the initial configuration by periodic replication of some crystalline unit cell. In that case \moldy\ expects to find, following the \Lit{end} which terminates the system specification, an initial configuration specification of the following form: \begin{displaymath} \begin{array}{llllllll} \multicolumn{8}{l}{a \quad b \quad c \quad \alpha \quad \beta \quad \gamma \quad n_{x} \quad n_{y} \quad n_{z}} \\ \textit{species-name}_{1} & X_{1} & Y_{1} & Z_{1} & q_{10} & q_{11} & q_{12} & q_{13} \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ \textit{species-name}_{i} & X_{i} & Y_{i} & Z_{i} \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ \textit{species-name}_{n} & X_{n} & Y_{n} & Z_{n} & q_{n0} & q_{n1} & q_{n2} & q_{n3} \\ \Lit{end}. \\ \end{array} \end{displaymath} Here $a, b, c$ and $\alpha, \beta, \gamma$ are the crystal unit cell parameters, and $n_{x}, n_{y}, n_{z}$ are the number of unit cells in each direction which comprise the MD cell. The next $n$ lines describe the $n$ molecules of the basis which will be replicated to form the full configuration. Molecules may appear in any order, but of course the total number of each, multiplied by the number of unit cells $n_{x} n_{y} n_{z}$ must agree with that given in the system specification file. Each molecule is identified by its name, as given in the system specification file. $X, Y$ and $Z$ are \emph{fractional} co-ordinates, between 0 and 1 giving the location of the molecular centres of mass in the crystal unit cell. The orientation is given by the four quaternions $q_{0}, q_{1}, q_{2}, q_{3}$ which specify a rotation \emph{relative to the orientation of the prototype molecule in the system specification file}. (Notice the slight inconsistency with the positions, which are of the centres of mass, \emph{not} the zeroes of co-ordinates in the system specification file. This may be fixed in future releases.) Quaternions need only be included for polyatomic species, that is molecules $1$ and $n$ above, and omitted for the monatomic species $i$. After the molecular positions and orientations have been set up, their velocities (and angular velocities if appropriate) are initialized. Their values are sampled at random from the Maxwell-Boltzmann distribution for the temperature $T$, as given by the control parameter \Lit{temperature}. This is done for both starting methods. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Restarting from a Previous Run}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:restarting} At the end of a simulation run, it is often desirable to store the configuration of the system in a file. This \emph{restart file} may be used at a later date to continue the simulation from that point rather than from scratch. To instruct \moldy\ to write a restart file, simply set the control parameter \Lit{save-file} to a suitable filename; to start from a restart file, set \Lit{restart-file} to be the name of that file. Each restart file is a binary file which contains enough information to reconstruct the exact state of the system and of the program. It includes a copy of all the control parameters in force, the current timestep number, a complete system specification, all the simulation dynamic variables and the intermediate data used in the calculation of averages and radial distribution functions. Thus a run continued from a restart file will proceed just as if there had been no interruption and will generate identical results (provided the control parameters are not changed). When continuing a simulation, it is only necessary to explicitly specify control parameters which are to be changed. Their previous values are read from the restart file and are used as defaults when reading the control file. Consequently control files for restarting tend to be rather short. \Emph{Caution}: always include a new (possibly null) value for \Lit{save-file}. Otherwise when the new run terminates, the new restart file may overwrite the old one.\footnote{Whether the old file is lost depends on the operating system. Under systems such as VMS which have version numbers a new version is created and the old one remains. Under Unix, the old file is renamed by the addition of a ``\%'' character and thus is saved. On other systems it will be lost.} Neither is it necessary to repeat the system specification since that too is stored in the restart file. However there are occasions when it is desirable to do just that, for example if the value of one of the potential parameters is to be modified. In that case, set the switch \Lit{new-sys-spec} to 1 (true) and provide a system specification as per a new simulation. This is checked for consistency with the existing one and if correct replaces it. The following checks are applied, which only verify that it is sensible to assign the old dynamic variables to the new system. \emph{1}. The number of species must be the same. \emph{2}. Each species must have the same number of rotational degrees of freedom as its predecessor. It is not possible to replace a polyatomic by a monatomic or linear molecule, for example. \emph{3}. The number of molecules of each species must not change. This means that the order in the specification file must be identical too. It is however possible to change the number of sites on a molecule, subject to \emph{2}. \subsection{Periodic Backup} \label{sec:backup} Closely related to restarting is the backup mechanism. This is provided to guard against the complete loss of a simulation due to computer failure. Periodically during a run, \moldy\ writes its state to a \emph{backup file} -- which is in fact just a restart file. In the event of a crash, the simulation can be restarted from the point the last backup was written rather than from the beginning. The related control parameters are \Lit{backup-file} which specifies the file name and \Lit{backup-interval} which gives the frequency of backups. It should not normally be necessary to change the name, but the optimum interval will depend on the size of the simulated system and the speed of the computer. By default it is 500. At the successful end of a run the backup file is deleted so that only if there is an abnormal termination does one remain.\footnote{A backup file is also written if the run is terminated for exceeding its cpu limit.} The restart from a backup is entirely automatic. If a backup file exists when a run is started, it is read in and the run continues from it. In contrast to a normal restart all of the control parameters are taken from the backup file and the control file (and a restart file if one is specified) is ignored.\footnote{This is not quite true. \moldy\ does read the control file and any restart file but only to determine the name of the backup file. Thus even if the backup has a non-standard name it can still be found.} In consequence, if a run is aborted or stops abnormally for some reason, the backup file must be removed manually otherwise next time a run starts, the unwanted simulation will continue instead. If a run terminates abnormally there may also be a \emph{lock file} called \Fname{MDBACKUP.lck} which ought to be removed. \moldy\ attempts to prevent two runs from overwriting each other's backup files by creating a lock file whose name is formed from the backup name by appending \Fname{.lck}. A second run which attempts to use the same backup file will test for the presence of the lock file and abort the run if it finds it. A restart or backup file is created by first writing the data to a temporary file which is then renamed to the final name. This ensures that there is no possibility of a file being left incomplete or corrupt if the computer crashes part-way through the write. If the file already exists either it is replaced (on systems which only keep one version of a file) or a new version is created (on systems such as VMS which retain multiple versions). In the unlikely event of it being necessary to change where the temporary file is kept,\footnote{This may be necessary if the restart file is located on a different device or disk partition from the current directory. To rename the temporary file successfully, it must reside in the same partition or device as the restart file.} it may be specified with the control parameter \Lit{temp-file}. \subsection{Portable Restart Files} \label{sec:xdr} \moldy\ is able\footnote{From version 2.1 onwards} to read and write restart and dump files in a portable binary format which is transportable between computers of different architectures. So a restart file written on, for example, a Sun may be used to initiate a new run on a Cray, and the dump files generated on the Cray may be analyzed on the Sun. This feature will also be of considerable use in modern heterogeneous networks where diverse machines frequently share a common file space. The format is based on Sun Microsystems XDR protocol\cite{sunxdr}. The XDR routines are available on almost every modern Unix machine, and are simple enough to implement on any other system.\footnote{Because the XDR calls are not part of ANSI standard C, however, the XDR code is conditionally compiled into \moldy\ only if the \Lit{USE\_XDR} preprocessor symbol is defined during compilation.} If the control parameter \Lit{xdr} is set to 1 then all files will be written using this format. \moldy\ automatically determines whether a restart file was written using XDR (by examining the file header) and reads it in the appropriate fashion irrespective of the value of \Lit{xdr}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Setting the Temperature}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \moldy\ implements three different methods to control the temperature of the simulated system. These are the velocity rescaling technique described in section~\ref{sec:rescaling}, the Nos\'e-Hoover thermostat and constrained equations of motion (section~\ref{sec:const-temp}). Scaling is selected by the parameters \Lit{scale-interval} \etc\ % Every \Lit{scale-interval} timesteps until \Lit{scale-end}, the velocities are adjusted so that the kinetic energy corresponds exactly to the desired temperature (the value of control parameter \Lit{temperature}). The Nos\'e-Hoover and constrained thermostat are selected by setting \Lit{const-temp} equal to \Lit{1} or \Lit{2} respectively. The control parameter \Lit{scale-options} selects refinements to the basic scaling or thermostat algorithms. This is an integer parameter interpreted as a set of bit flags with the following meanings. \begin{description} \item[bit 0] perform scaling or thermostatting for each molecular species individually. \item[bit 1] scale/thermostat the rotational and translational components of the kinetic energy separately. \item[bit 2] use the rolling averages of kinetic energy to calculate the scale factor rather than the instantaneous values. \item[bit 3] discard all existing velocities and accelerations and re-initialize from the Maxwell-Boltzmann distribution. \end{description} The bits may be set in any combination so, for example \Lit{scale-options=6} sets bits 1 and 2 ($ 6 = 2^1 + 2^2$) and scales separately for rotation/translation using the rolling averages. If bit 3 is set the others are ignored. Only bits 0 and 1 have any meaning in the case of a thermostat, and signify that each species, or the translational and rotational degrees of freedom are isolated from each other and coupled to their own, individual heat baths. The options for scaling separately rotation and translation, and per species may be useful for achieving equilibration in ``difficult'' systems where mode-coupling is ineffective. In those situations it is otherwise possible for all the energy to be transferred into the rotational modes of a particular species, halting any progress to equilibrium for other degrees of freedom. These options ensure that all degrees of freedom have some thermal energy. The option controlled by bit 3, to discard all existing information and start from a random set of velocities may be of use when starting from far-from-equilibrium situations. In such cases the forces are frequently so large that the velocities and accelerations exceed the limits of the integration algorithm and timestep, which results in \moldy\ stopping with a \emph{quaternion normalization} or \emph{quaternion constraint} error. Judicious use of this option every few timesteps (using \Lit{scale-interval}) ought to allow the system to relax to a state sufficiently close to equilibrium for normal scaling to take over. Bit 2 is intended to deal with the problem of setting the temperature accurately using scaling. The \emph{ensemble average} kinetic energy which characterizes the temperature of the system and the instantaneous value fluctuates about this value. However in the traditional implementation of scaling, velocities are multiplied by a factor of $\sqrt{\emph{desired KE} / {\emph{instantaneous KE}}}$. Thus the scaling factor is ``wrong'' by the ratio of the instantaneous to average KE's which means that the temperature can not be set more accurately than the relative size of the fluctuations in the KE\@. The option selected by bit 2 goes some way towards the ideal scaling factor by using the rolling average KE instead of the instantaneous value. The fluctuations in this short-term average should be much lower than in the instantaneous value, allowing more accurate temperature control. However it will almost always be easier to use a true thermostat to achieve this goal. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Output}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:output} At the beginning of each run \moldy\ writes a \emph{banner page} containing a summary of the system being simulated and details of the important control parameters. The bulk of the output file is the \emph{periodic output} which contains the instantaneous values of various thermodynamic variables, their rolling averages and associated standard deviations. The \emph{rolling average} is just the mean over the preceding $n$ timesteps where $n$ is set by the control parameter \Lit{roll-interval}. An annotated example is given in figure~\ref{fig:output}. The frequency of periodic output may be altered by setting the control parameter \Lit{print-interval} to the interval required. (This may be necessary to constrain the size of the output file which can grow to be very large indeed with the default interval of only 10.) \begin{figure} \tiny % \begin{tabular}{rrrrrrrr @{\hspace{1em}}r@{\hspace{1em}}rr@{\hspace{1em}}r@{\hspace{1em}}r} \multicolumn{6}{r}{\hfill Nov 17 15:13:06 1989 \hfill Water\_test \hfill Page 4} & & & & & & &\\ Trans KE & Rot KE & Pot Energy & Tot Energy & TTemp & RTemp & Temp & h(1,*) & h(2,*) & h(3,*) & Stress & Stress & Stress \\ \multicolumn{13}{l}{======== Timestep 10 Current values ======================================================== } \\ 243.88 & 453.88 & -187.35 & 533.5 & 305.5 & 568.6 & 424.4 & 12.53 & 0.00 & 0.00 & 589 & 46.4 & 120 \\ 22.053 & 0 & 1.0401 & & 221.0 & 0.0 & & 0.00 & 12.53 & 0.00 & 46.4 & 373 & 90.1 \\ & & & & & & & 0.00 & 0.00 & 12.53 & 120 & 90.1 & -207 \\ \multicolumn{13}{l}{-------- Rolling averages over last 10 timesteps -------------------------------------------------------------------------- ------------------------------------------------ } \\ 240.27 & 319.31 & -82.472 & 533.39 & 301.0 & 400.0 & 342.9 & 12.53 & 0.00 & 0.00 & 1.2e+03 & 296 & 127 \\ 22.077 & 0 & 34.205 & & 221.3 & 0.0 & & 0.00 & 12.53 & 0.00 & 296 & 589 & 133 \\ & & & & & & & 0.00 & 0.00 & 12.53 & 127 & 133 & -132 \\ \multicolumn{13}{l}{-------- Standard deviations --------------------------------------------------------------------------------------------------------------------------------------------------- } \\ 1.8214 & 71.893 & 56.441 &.19942 & 2.3 & 90.1 & 43.4 & 0.00 & 0.00 & 0.00 & 1.32e+03 & 750 & 51 \\ 0.013 & 0 & 17.173 & & 0.1 & 0.0 & & 0.00 & 0.00 & 0.00 & 750 & 119 & 55.2 \\ & & & & & & & 0.00 & 0.00 & 0.00 & 51 & 55.2 & 49 \\ \end{tabular} \caption[Sample \moldy\ output.]{Sample \moldy\ output from a simulation of a two component mixture. The first component is a polyatomic molecule and the second is atomic. There are three \emph{frames}, for the instantaneous values, the rolling averages and their associated standard deviations. Within a frame, each row has the following meaning: for translational and rotational kinetic energies and temperatures it is the per-species value; for the potential energy it is the direct and reciprocal space components, and the MD cell matrix, \Lit{h} and the stress are laid out as $3\times 3$ matrices.} \label{fig:output} \end{figure} As well as the short term rolling averages, long term averages are calculated and printed out at regular but usually infrequent intervals. Accumulation starts on the timestep given by the control parameter \Lit{begin-average} and every \Lit{average-interval} timesteps thereafter, the means and standard deviations are calculated and printed. This output is interspersed with the periodic output and is formatted with one variable to a line in the form \emph{mean +/- s.d}.. Where a variable has more than one component (such as multiple species for the translational temperature or Cartesian components for the mean square forces) the components are printed across the page.\footnote{Remember that the standard deviation is a measure of the \emph{fluctuations} about the mean, \Emph{not} the \emph{uncertainty} in the mean. For that the standard error in the mean is required, which is more difficult to evaluate. Theoretically it is the \emph{s.d.} divided by $\sqrt N$ where $N$ is the number of independent observations. But successive timesteps are highly correlated and do not count as independent. See ref~\cite{allen:87} section 6.4, page 191 onwards for a full discussion.} In addition to those variables printed as part of the periodic output, the pressure, the virial, mean square forces, mean square torques and total dipole moments are calculated. \subsection{Output units} All of the various forms of output use the same units, though for brevity they are not explicitly mentioned on the periodic output. Lengths are measured in \AA, energies are all expressed in kJ mol$^{-1}$, temperatures in Kelvin, pressure and stress in MPa, mean square forces and torques in N$^2$ mol$^{-1}$ and Nm$^2$ mol$^{-1}$, charge in electron charges and dipole moments in Debye. Because energy is an extensive quantity the printed values refer to the \emph{whole system}. (There is no practical way of expressing energies per mole of any particular constituent in a program capable of simulating arbitrary mixtures.) If these units do not suit, they can be changed in the configuration file \Fname{defs.h}, where the conversion from internal to output units is parameterized. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Radial Distribution Functions}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Radial distribution functions are calculated by binning site pair distances periodically throughout the simulation (see section~\ref{sec:rdf}). As this process is expensive in computer time the binning subroutine is invoked only every few timesteps, as set by the control parameter \Lit{rdf-interval} (20 by default). Since the pair distances only change a little on each timestep, very little statistical information is lost. Collection of binning data may also be turned off during an equilibration period: specify when binning is to start by means of the parameter \Lit{begin-rdf}. The parameters \Lit{rdf-limit} and \Lit{nbins} control the details of binning, giving respectively the largest distance counted and the number of bins that interval is divided into. The calculation of the interatomic distances is done separately from that used in the evaluation of the forces, using the same link cell scheme. This ensures that all site pairs separated by less than \Lit{rdf-limit} are included. This parameter may be varied independently of the interaction cutoff, thereby allowing RDFs to be evaluated out to large distances without incurring the time penalty of increasing the cutoff.% \footnote{In previous versions of \moldy\ the calculation of the interatomic distances was done on the basis of the ``minimum image'' convention. Consequently the calculated value of $g_{\alpha\beta}(r)$ tailed off for $r_c > L/2$. This restriction is now lifted} Every \Lit{rdf-out} timesteps (by default 5000) the RDFs are calculated from the binned distances and printed out, and the counters are reset to zero to begin accumulation again. Distances are binned and RDFs $g_{\alpha \beta}(r)$ calculated separately for each distinct type of atom-atom (or site-site) pair. An explanation of the output format is given in figure~\ref{fig:rdf-output}. Note that each number should be considered as the value at the \emph{centre} of its bin, so that entry $i$ in each list is the value of $g_{\alpha\beta}((i+1/2)b)$ where $b$ is the bin width. \begin{figure} \begin{tiny} \begin{verbatim} Radial Distribution Functions Bin width=0.1 O-O RDF 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000481 0.035710 0.183334 0.442186 0.613992 1.024402 1.046396 0.964906 0.830174 0.660035 0.693341 0.615902 0.593192 0.510595 0.530697 0.532030 0.535959 0.524457 0.523221 0.466219 0.496028 0.438487 0.456500 0.410547 0.443861 0.457956 0.446822 0.452202 0.419768 0.439333 0.465509 0.486887 0.461970 0.475745 0.478883 0.480854 0.509090 0.533728 0.552747 0.552555 0.575402 0.547278 0.544836 0.493597 0.488168 0.520727 0.508073 0.479948 0.501159 0.484000 0.485378 0.489160 0.464448 0.466791 0.476508 0.446576 0.470948 0.474468 0.449340 0.462169 0.501220 0.519107 0.513338 0.510192 0.499766 0.525963 0.504663 0.517673 0.498359 0.512156 0.507061 0.466390 0.464342 0.445886 0.417555 0.407778 0.387220 0.374041 O-H RDF 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 26.976688 0.000000 0.000000 0.000000 0.000000 0.000000 0.016214 0.061257 0.304082 0.647342 0.847404 0.757188 0.601222 0.478273 0.462682 0.449614 0.450424 0.518998 0.572242 0.689704 0.914269 1.184674 1.441772 1.570390 1.609068 1.600392 1.430457 1.322722 1.183606 1.103701 1.061788 0.980018 0.960570 0.924390 0.908883 0.877591 0.857668 0.890761 0.852463 0.815447 0.824963 0.841255 0.890416 0.929030 0.960589 0.984145 1.020650 1.028199 1.047496 1.064600 1.099812 1.095715 1.073793 1.078131 1.049212 1.052160 1.052001 1.020737 1.010782 0.979748 0.983158 0.988946 0.967620 0.955655 0.944384 0.952145 0.948509 0.946692 0.960097 0.959299 0.964074 0.969219 0.972704 0.998504 1.027791 1.041576 1.037637 1.039961 1.016804 1.004726 1.026805 1.030903 1.006268 0.972421 0.948140 0.908959 0.877089 0.849855 0.817964 0.776986 0.721485 \end{verbatim} %%\hrulefill \end{tiny} \caption[Example output of radial distribution functions.]{Example output of radial distribution functions. After the header line consisting of underscores there is an indication of the bin width $b$ (that is the distance between points at which the RDF is tabulated). Then for each site type pair $\alpha\beta$ there is a line listing which pair (\eg\ \Lit{O-O RDF}) followed by \Lit{nbins} values of $g_{\alpha\beta}((i+1/2)b)$. } \label{fig:rdf-output} \end{figure} There are a couple of tricks which may be played with the system specification if the atomic pair RDFs do not give exactly the functions required. Firstly, it is possible to calculate RDFs about a particular site, distinguishing it from otherwise identical atoms by assigning it a new and unique site id in the system specification file. (This is the MD equivalent of the isotopic substitution method used in neutron diffraction). Secondly, if the \emph{molecular} pair correlation is required, this is identical to the RDF of an atom located at the molecular centre-of-mass. A ``ghost'' site without charge, mass or potentials may be added if necessary. \pagebreak[3] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Dumping}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:dumping} The dump facility is provided in order to allow the calculation of dynamic properties, such as time correlation functions and additional static averages not normally calculated by \moldy. During a run, dump files are produced which contain a record of the simulation dynamic variables (positions, quaternions \etc) at varying degrees of detail. Any property of interest, dynamic or static, may then be evaluated using the data in the dump. A dump consists of a sequence of files since the amount of data generated in a run can be very large indeed and it is usually more convenient to manipulate a series of smaller files rather than one large and unwieldy one. \moldy\ takes considerable pains to ensure that a contiguous sequence of dump files is maintained and also ensures that dumps from different runs are not accidentally intermixed. There is no requirement that a dump file be produced by a single run of \moldy\ , which extends an existing file or starts a new one as appropriate. A simulation may stop and be restarted many times without disturbing the dump file sequence. The sequence should (in most cases) even survive a system crash and a restart from a backup file (see section~\ref{sec:backup}). Each dump file in a sequence is a binary file consisting of a \emph{dump header}, which contains information about the contents of the file followed by a number of \emph{dump records} which contain the actual data. Several control parameters govern dumping. It starts at the timestep specified by \Lit{begin-dump}, and a dump record is written every \Lit{dump-interval} timesteps thereafter. After \Lit{ndumps} dump records have been written to a file, it is closed and another is begun. Filenames are generated from a prototype (given by the parameter \Lit{dump-file}) by appending a number, so that if the prototype is \Fname{MDDUMP} then successive files will be named \Fname{MDDUMP0}, \Fname{MDDUMP1}, \Fname{MDDUMP2} \etc\ If it is not convenient for the sequence number to appear at the end of the file, include the characters ``\%d'' at an appropriate point.\footnote{This is actually the code \Lit{sprintf()}, the C library function uses to signify converting an integer to a decimal character string. This function is used to create the actual file name from the prototype and the integer dump sequence number. (See any C library manual for details.)} For example under VMS, specifying \Lit{dump-file=mddump\%d.dat} will name the files \Fname{mddump0.dat}, \Fname{mddump1.dat} \etc Each dump record is a sequence of single-precision floating point binary numbers. These are written either in native (\ie\ the machine's own) format or XDR format (see section~\ref{sec:xdr}) depending on the value of the control parameter \Lit{xdr}. The record's exact contents are determined by the control parameter \Lit{dump-level} which is a bit flag \ie\ a value of $2^{n}$ means that bit $n$ is set. Four bits are used and any combination may be specified but the cumulative values 1, 3, 7 and 15 are most useful. A value of 0 disables dumping. The data dumped for each bit are as follows: \begin{description} \item[bit 0] centre of mass co-ordinates, quaternions, unit cell matrix and potential energy. \item[bit 1] centre of mass velocities, quaternion and unit cell matrix derivatives. \item[bit 2] centre of mass accelerations, quaternion and unit cell matrix second derivatives. \item[bit 3] forces, torques and stress tensor. \end{description} Items selected are written in the order laid out above. Within each set of variables, values are ordered primarily by species in the order they appeared in the system specification. Within a species ordering is by molecule (or atom) and at the finest level by $x$, $y$ or $z$ component ($q_{0}, \ldots q_{3}$ for quaternions). Therefore if $n$ is the total number of molecules and $n_{r}$ is the number with rotational freedom the size of each record is \begin{displaymath} \begin{array}{cll} & 3n + 4n_{r} + 9 + 1 & \textnormal{(if bit 0 is set)} \\ + & 3n + 4n_{r} + 9 & \textnormal{(if bit 1 is set)} \\ + & 3n + 4n_{r} + 9 & \textnormal{(if bit 2 is set)} \\ + & 3n + 3n_{r} + 9 & \textnormal{(if bit 3 is set)} \\ \end{array} \end{displaymath} single precision floating point numbers. The header is a copy of a \Lit{struct dump\_t} (see appendix~\ref{sec:structs} for the format). It contains the simulation title and version number, the timestep at the beginning of the file, the control parameters \Lit{dump-interval} and \Lit{dump-level}, the maximum and actual number of dump records in the file, a unique marker (actually a timestamp), common to all the files in a dump run, and the timestamp\footnote{A timestamp is simply the number of seconds elapsed since midnight on January 1, 1970.} of any restart file used to start the run. It is not possible to dump directly to magnetic tape. \moldy\ must rewind to the beginning of a file to keep the header up to date with the number of dumps in the file, as well as extend existing files. Neither operation is allowed on a tape drive. Large disk stores are now very cheap so this should not be a problem in practice. If disk store \emph{is} limited then the simulation may be divided into multiple \moldy\ runs interspersed with copying of dump files to tape. Notice that \moldy\ must sometimes read an existing but complete dump file to propagate the unique marker to all of the files in a sequence. Therefore when continuing a simulation and a dump run, at least the immediately preceding dump file must still be accessible. This should be borne in mind when copying dumps to tape! \moldy\ is careful to ensure that existing files are not overwritten - especially necessary since dump records are added to the end of an existing dump file. Whenever \moldy\ prepares to start a new dump file it checks to see if one of that name is already present. If so, a new name is chosen by ``mutating'' the old one, and a warning message to that effect is written to the output file. On the other hand, if the \emph{first} file of a new dump run (including one initiated because of some error in continuing an old one) already exists, the \emph{prototype} file name is mutated as above and the whole dump run is written to files based on the mutated name. When a run is restarted checks are made to ensure that the values of the dump control parameters have not been altered. If they have, it is not possible to continue an existing dump sequence and a new one will be started. (If existing dump files are present the new sequence will have mutated file names.) This also happens if an existing file does not appear to be a \moldy\ dump. Existing dump files are also tested to ensure that there is no corruption (due, for example to a system crash) and that they contain the correct number of records. If the dump sequence can not be continued in these circumstances, \moldy\ terminates with a fatal error rather than waste computer time. %To ensure that the header always records the correct number of dump %records in a file, it is updated \emph{after} the actual record has %been written. It is possible that following s crash there may be one %more record than recorded. \moldy\ ignores it and recalculates and %dumps the data. Two utility programs included in the distribution are \emph{dumpanal} which identifies dump files by printing out the headers and \emph{dumpext} which extracts atomic or molecular trajectories. The latter should be useful as a prototype for writing programs to analyse dump data. It is frequently convenient to perform analysis of dump data, and perhaps graphical output on a different computer to that which generated the data. In the past it has not usually been possible to sensibly transfer binary data between computers of different architectures. However \moldy\ is able to write dump files in a portable format using XDR (see section~\ref{sec:xdr}) which may be read by \emph{dumpext} on any machine. The control parameter \Lit{xdr} enables XDR mode for dumps as well as restart files. As yet, XDR is not available on every machine. Therefore a program called \emph{dumpconv} is provided which converts dump files to a portable text file format (which may be easily moved between machines) and back again. It is described in appendix~\ref{sec:dumpconv}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Constant Stress Simulation}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Setting the control parameter \Lit{const-pressure} switches from a constant-volume simulation to a con\-stant-stress simulation using the method of Parrinello and Rahman\cite{parrinello:81} (see section~\ref{sec:const-stress}). The value of the MD cell mass parameter, $W$, is given by the control parameter \Lit{w} and the external pressure by \Lit{pressure}. At present it is not possible to specify an anisotropic external stress, though this capability may be added in future versions of the program. \label{sec:cp-constraints} The $\bm{h}$ matrix may be constrained so as to disable motion of any or all of its components using the parameter \Lit{strain-mask}. \Lit{Strain-mask} is a bitmap: each ``bit'' of the integer freezes one of the components of $\bm{h}$; bit $i$ freezes $ \bm{h}_{kl}$ with $ i = 3 (k\!-\!1)\! +\! l\! -\!1$. The bitmask is the sum of $2^i$ over the $i$'s to be set, so the \Lit{strain-mask} values \begin{displaymath} \left ( \begin{array}{rrr} 1 & 2 & 4 \\ 8 & 16 & 32 \\ 64 & 128 & 256 \end{array} \right ) \textnormal{constrain the corresponding components of } h, \left ( \begin{array}{rrr} h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33} \end{array} \right ). \end{displaymath} \noindent Thus the default constraint of $\bm{h}_{?1} = \bm{a} = (a_x,0,0), \bm{h}_{?2} = \bm{b} = (b_x,b_y,0)$ is given by \Lit{strain-mask=200} \linebreak[2] (8+64+128). Another useful value is 238 which freezes all the off-diagonal components. This is needed for a liquid simulation since there are no shear restoring forces acting on those components. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Cutoffs and Adjustable Parameters}%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% There are four parameters related to the Ewald sum method of force evaluation (see section~\ref{sec:ewald}), $\alpha$, $r_c$, $k_c$, and \Lit{subcell}. In addition the two options \Lit{strict-cutoff} and \Lit{surface-dipole} select how rigorously the real-space cutoff is applied and whether to include the De Leuuw surface dipole term. By default $\alpha$, $r_c$ and $k_c$ are chosen automatically, using equations~\ref{eqn:ewald-cut} to give a default accuracy of $\epsilon = \exp(-p) = 10^{-5}$ (\ie\ $p = 11.5$) in the Coulombic potential energy evaluation. An empirically determined value of $t_R/t_F = 5.5$ is used. If a different accuracy is desired the cutoffs may be adjusted using equations~\ref{eqn:ewald-cut}. The $\alpha$ parameter is specified by \Lit{alpha} in units of \AA$^{-1}$ and the direct and reciprocal space cutoff distances $r_{c}$ and $k_{c}$ by \Lit{cutoff} and \Lit{k-cutoff} in units of \AA\ and \AA$^{-1}$ respectively. The value of $\alpha$ should only be changed after careful timing tests if the system size is large. The power-law given in equation~\ref{eqn:ewald-alpha} gives a theoretical scaling of execution time with number of ions of $T \propto N^{1.5}$. In practise $T \propto N^{1.57}$ has been achieved over a range of $N$ from 72 to 7800, which is very close to optimal. \Emph{Important note:} The automatically determined value of $r_c$ is chosen to converge the Coulombic part of the potential only. Due to the very general nature of the potentials it is not possible to choose $r_c$ automatically so as to guarantee convergence of the non-electrostatic part. Although in many cases the automatic value will be adequate \Emph{it is the user's responsibility to ensure that it is large enough}. If there are no charges in the system specification file then $r_c$ is not set and an error message is issued. As an example of manual determination of the parameters, for a simulation of 512 MCY water molecules the values $\alpha = 0.3$\AA$^{-1}$, $r_{c} = 9$\AA\ and $k_{c} = 1.9$\AA$^{-1}$ give potential energies correct to approximately 1 part in $10^{5}$. For a simulation including ions - 1.1 Molal Magnesium Chloride solution - the same accuracy is attained with $\alpha = 0.45$\AA$^{-1}$, $r_{c} = 9$\AA\ and $k_{c} = 3$\AA$^{-1}$. The other relevant parameter is the switch \Lit{surface-dipole} which includes the dipole surface energy term of De Leeuw, Perram and Smith\cite{deleeuw:80}. See the note in section~\ref{sec:ewald} for an explanation of why this term should \emph{never} be used for an ionic (as opposed to dipolar) system. The two adjustable parameters which control the link cell force calculation (see section~\ref{sec:link-cell}) are \Lit{subcell} and \Lit{strict-cutoff}. The former specifies the length (in \AA) of the side of a link cell and determines the number of cells the MD cell is divided into. In fact the MD cell is divided into a whole number of subcells whose side in each of the three directions is nearest to the value of \Lit{subcell}. (The default of zero though, is special and sets subcell to one fifth of the cutoff radius.) In general the smaller the link cell, the more accurately the cutoff radius is implemented, but too many of them reduces the efficiency of the program. In the default cutoff mode \Lit{strict-cutoff=false} the list of neighbour cells is constructed to include all cells whose centre-centre distance is less than the cutoff. This means that some molecule pairs separated by more than the cutoff will be included and some by less will be omitted. Setting \Lit{strict-cutoff} to true generates a larger cell neighbour list which is guaranteed to include all appropriate molecule pairs. Furthermore, molecules separated by more than the cutoff are excluded from the force calculation by setting their separation to a large number, 100 times the cutoff, at which distance it is assumed the potential is very close to zero. This is therefore the mode of choice for liquid simulations where any artificial anisotropy is undesirable. See section~\ref{sec:link-cell} for a full explanation. It is worth noting that it is unnecessary to recompile the program or change anything else when the cutoffs are modified. Unlike most MD codes, \moldy\ employs dynamic array allocation and automatically sets up arrays of the correct size (and no more!) for any given $k_{c}$. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Framework Simulations}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% There has recently been much interest in simulations of systems of molecules interacting with some rigid framework such as zeolites, clays and other surfaces. \moldy\ has the capability to include such a framework in a simulation by defining it as a special kind of molecule. The system specification should contain an entry, similar to that for a normal molecule, which describes the atomic sites belonging to one MD cell's worth of the framework. Its periodic images should fill space to construct the required infinite framework. This is notified to the program by modifying the first line of the specification of that molecule to read \begin{displaymath} \begin{array}{lllllll} \multicolumn{7}{l}{\textit{species-name}_{i} % \quad \Lit{1} \quad \Lit{Framework}} \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ \end{array} \end{displaymath} (compare with section~\ref{sec:sys-spec}). The effect of the special keyword \Lit{framework} is \begin{enumerate} \item to remove the rotational freedom of the molecule. This preserves the infinite structure over MD cell repeats by disallowing relative motion of its parts. (Linear motion does not destroy the structure and \emph{is} allowed.) \item to modify the effect of the periodic boundary conditions. Normally a molecule is assumed to be ``small'' and periodic relocations are applied to \emph{all} of its atoms depending on its centre-of-mass co-ordinates relative to some interacting molecule. In contrast, the atoms of a framework are independently relocated. This ensures that each molecule ``sees'' all framework atoms from any unit cell which are within the cut-off distance. \end{enumerate} In the present version of the program, only one framework molecule is allowed, though more may be permitted in future versions. Consequently the configuration given as a lattice start must fill the entire MD box. (A skew start is not sensible under these circumstances since the orientation of the framework must be explicitly specified to construct a good space-filling structure.) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Messages and Errors}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Apart from the periodic output, there are occasional once-off messages which \moldy\ writes to the usual output file. Such messages begin with the characters \Lit{*I*}, \Lit{*W*}, \Lit{*E*} or \Lit{*F*} denoting the classes \emph{information}, \emph{warning}, \emph{error} or \emph{fatal} respectively. Their meanings are \begin{Litdescription} \item[*I*] information. These are often produced by subroutines to give useful information on their particular calculations. For example when temperature scaling is turned off a message to that effect is recorded in the output file. Various routines which calculate internal quantities such as the Ewald sum self energies and distant potential corrections also record their values using an information message. \item[*W*] warning. When the system specification is suspicious but not clearly wrong, or some untoward condition is detected such as two atoms approaching too closely, a warning message is issued. \item[*E*] error. Error messages are issued when a mistake is detected reading any of the input files. To make correction easier, processing continues until the end of that file, so that all of the errors are found. The simulation is then stopped with a fatal error. \item[*F*] fatal. The simulation is terminated immediately. Faulty input files generate fatal errors after they have been completely processed. There are many other conditions which also generate fatal errors, for example if the simulation algorithms violate some criterion such as quaternion normalization or constraints (see section~\ref{sec:quaternions}), if the program runs out of memory or if a restart file can not be correctly opened or is of the wrong format. \end{Litdescription} Most of the messages are self-explanatory. However there are two fatal errors which occasionally arise and are somewhat cryptic: \Lit{*F* Quaternion n (x,x,x,x) - normalization error in beeman} and \Lit{*F* Quaternion n - constraint error (x)} \noindent Technically these refer to violations of the conditions that the quaternions representing the angular co-ordinates be normalized to 1 and that equation~\ref{eqn:qconst} be satisfied. Either may occur if the angular velocity of some molecule becomes too high for accurate integration of the equations of motion. This may have a number of causes. First the timestep may simply be too large. Second the system may be in a state where atoms are so close as to generate large torques which accelerate the molecule to a high angular velocity. This commonly arises if the starting configuration is very far from equilibrium, particularly in the case of molecules with small moments of inertia, such as methane. In most cases the simulation may be restarted using strong rescaling or a Gaussian thermostat to limit velocities during the approach to equilibrium. Occasionally a smaller timestep may help during equilibration. The third cause of normalization or constraint errors is an error in the potentials or the units which allows for a state with high or infinite negative binding energy. Note that these messages only occur for polyatomic molecules. If the system is monatomic the errors mentioned above may still be present but will not be detected and the simulation may fail in some less predictable manner, for example particles may approach too closely and/or acquire high velocities and fly off to infinity. The message \Lit{*W* Sites n and m closer than 0.5A.} \noindent gives some warning of this condition. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Compiling and Modifying Moldy} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The \moldy\ distribution consists of numerous files of ``C'' source code for \moldy\ and the utility programs, command or job files to compile the source, \LaTeX\ input for the manual and example control and system specification files. For ease of transport these are packed into one large archive file, whose format and method of unpacking depends on the operating system of the target machine. At present it is available for: \begin{description} \item[unix] The archive is usually a tar archive called \Fname{moldy.tar} possibly compressed with the ``compress'' or ``gzip'' programs and named \Fname{moldy.tar.Z} or \Fname{moldy.tar.gz}. These files may be uncompressed using the ``gunzip'' or ``uncompress'' programs, \emph{viz.} \Lit{gunzip moldy.tar.gz} or \Lit{uncompress moldy.tar.Z} whereupon the archive is unpacked by the command \Lit{tar xvf moldy.tar}. An alternative form of archive for those unusual systems without a ``tar'' program is a shell archive --- a Bourne shell script called \Fname{moldy.shar}. This is unpacked by \Lit{/bin/sh moldy.shar}. \item[VMS] The archive is a DCL command file called \Fname{moldy.com}, and is unpacked by the command \Lit{@moldy}. \item[MS Windows 3/Windows 95] The shareware program ``winzip'' may be used to unpack the compressed tar archive \Fname{moldy.tar.gz}. \item[MS-DOS] The files must be unpacked from the tar archive on another host and transferred to the PC by disk or ftp. \end{description} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Compilation}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The source code of \moldy\ consists of 23 files of C programs (which have suffix ``\Fname{.c}'') and 8 header files (suffix ``\Fname{.h}''). To build \moldy, all of the \Fname{.c} files must be compiled and linked together to form an executable. The method of doing this depends on the operating system of the target computer. \begin{description} \item[unix] The ``make'' program is used and the make file is supplied in the distribution. The \Fname{Makefile} supplied will attempt to compile using the command \Lit{cc -O -DUSE\_XDR} which will usually be sufficient to build a working executable on most operating systems. However some systems may require extra libraries to be specified and it will usually be possible to build a faster-running executable by judicious use of optimization options. Options for many common compilers/operating systems are listed in commented-out form. To enable them, simply uncomment the appropriate lines in the makefile. Then just type \Lit{make} to compile and link \moldy\ and \Lit{make utilities} for the utility programs. \item[VMS] Simply type \Lit{@compile} to execute the command file \Fname{compile.com}. This will build \moldy\ and the utilities. \item[DOS] There is a makefile for Borland Turbo C called \Fname{Makefile.mak} in the standard distribution. This must be edited to select the appropriate compiler options before executing \emph{make}.\footnote{Be sure to delete or rename the unix make file \Fname{Makefile} since Turbo C \emph{make} will attempt to execute this in preference to \Fname{Makefile.mak}} Alternatively the programs may be built within the interactive environment. Consult the \Fname{makefile} to find out which source files to link to build \moldy\ and the utilities. Moldy has also been built using Watcom C. \item[MS Windows 3/Windows 95] It is probable that the Borland C \Fname{Makefile.mak} will work under Borland C for Windows or Windows 95.\footnote{The author's experience of Windows 3 and Windows 95 platforms is very limited. I would very much welcome any reports from users on how to build \moldy\ in these environments for inclusion in future versions of this manual.} \end{description} \subsection{XDR Dump and Restart} As described in section~\ref{sec:xdr} binary restart and dump files may be written and read in a portable way using the Sun XDR calls. Since these are are not part of the ANSI C standard libraries, this code is conditionally included by defining the C preprocessor macro \Lit{USE\_XDR}. Though non-standard, XDR is almost universally available on unix operating systems, so the makefile defines this by default, assuming the syntax of the compiler flag \Lit{-DUSE\_XDR} to do so. If the XDR headers and libraries are not present on your system, then comment out the line reading \Lit{XDR=-DUSE\_XDR} at the top of the makefile to deactivate this feature. On certain systems (\eg\ older versions of SGI IRIX and Sun Microsystems Solaris 2.x) it may be necessary to include some additional library in the link, via the \Lit{LDFLAGS} make macro. \subsection{Parallel Version (Message Passing)} \label{sec:spmdpar} The parallel version of \moldy\ relies on an interface with a suitable message-passing library. This is the recommended version and supersedes the ``shared-memory'' parallel implementation described in section~\ref{sec:shmpar}. The current release contains interfaces to the MPI library\cite{mpi:94}, the TCGMSG library and the Oxford BSP library. MPI is the most recommended interface since it is the new standard for message-passing libraries, and should become ubiquitous. If none of these are installed on your machine, some public-domain implementations are available for workstation clusters, multiprocessors and many distributed-memory parallel machines. \begin{description} \raggedright \item[MPI] The MPICH and CHIMP implementations can be fetched by anonymous ftp from the URLs \Lit{ftp://info.mcs.anl.gov/pub/mpi/mpich} and \Lit{ftp://ftp.epcc.ad.ac.uk/pub/chimp/release}. \item[TCGMSG] This may be obtained by anonymous ftp from \Lit{ftp://ftp.tcg.anl.gov/pub/tcgmsg/tcgmsg.4.04.tar.Z}. \item[BSP] The Oxford BSP Library is available through Oxford Parallel's WWW server \Lit{http://www.comlab.ox.ac.uk/oucl/oxpara/bsplib1.htm} or by anonymous ftp \Lit{ftp://ftp.comlab.ox.ac.uk/pub/Packages/BSP/bsp1.2.tar.Z}. \item[SHMEM] The CRI native communications library for T3D and T3E systems. \end{description} \noindent Alternatively a port to another parallel interface should be quite straightforward, see section~\ref{sec:parport}. Once a suitable message-passing library is installed the procedure for building \moldy\ is quite simple. The C preprocessor macro \Lit{SPMD} must be defined as well as one of \Lit{MPI}, \Lit{TCGMSG}, \Lit{BSP} or \Lit{SHMEM}. This is usually done in the makefile by setting the Make macro \Lit{PARLIBC=-DSPMD -DMPI}, for example. This macro should also include a \Lit{-I} directive specifying the directory for the library's header files if these are not in the default path searched by the compiler. The similar make macro \Lit{PARLIBL} should contain the linker directives necessary to link to the library itself. Examples are provided at the top of the supplied \Fname{Makefile}. This parallel implementation makes use of the \emph{replicated data} approach\cite{smith:91} whereby every processor has a complete copy of all the arrays containing dynamical variables and every site on every molecule. The computation of the real-space potential and forces is distributed over processors on the basis of link cells. For the reciprocal-space part of the Ewald sum, the \emph{k}-vectors are distributed among processors. This is an extremely efficient way of implementing parallelism since the forces \etc\ must be summed over processors only once per timestep, thus minimizing interprocessor communication costs. It is therefore possible to get considerable speedup for a small number of workstations coupled by a fast network such as an Ethernet. The biggest disadvantage of the replicated data strategy is that every processor must maintain a copy of all of the data, and therefore that the memory requirement per processor increases with the size of the system. In many cases this is not a severe problem, as MD memory requirements are not large compared with memory sizes of modern computers. However the poor scaling will eventually limit the number of processors which may be used. On a shared-memory multiprocessor, the alternative parallel version in section~\ref{sec:shmpar} may provide a solution, if it can be ported to that machine. The memory limitation will be most acute when the goal is to simulate an extremely large system on a massively parallel distributed-memory computer where it is desirable to scale the system size with the number of processors. In such architectures the available memory per processor is usually a constant independent of the number of processors. But the memory needed \emph{per processor} increases with system size. Mostly the scaling is linear, but the reciprocal-space sum uses temporary arrays whose size scales with the product of the number of sites and \emph{k}-vectors, and hence to the {\small$\frac{3}{2}^{\textnormal{th}}$} power of the system size. An alternative version of \Fname{ewald.c} which implements the reciprocal-space term of the Ewald sum by distributing over \emph{sites} rather than \emph{k}-vectors is included in the distribution as \Fname{ewald-RIL.c}. It is based on the RIL algorithm of Smith~\cite{smith:92} and \emph{distributes} the temporary arrays containing the $\cos(\bm{k} \cdot \bm{r}_i)$ and $\sin(\bm{k} \cdot \bm{r}_i)$ over the nodes. In other words, each node only stores the terms involving the $\bm{r}_i$'s to be considered on that node. Since these arrays are by far the largest users of memory there is a substantial decrease in overall memory requirement. Moreover the size per node now scales \emph{linearly} with the number of \emph{k}-vectors and therefore (assuming $\alpha$ is optimized), to the two-thirds power of the number of sites. These arrays will not therefore dominate the memory requirement in the limit of large numbers of processors and system size. The disadvantage of the RIL scheme is that the partial sums of $\cos(\bm{k} \cdot \bm{r}_i)$ and $\sin(\bm{k} \cdot \bm{r}_i)$ must be summed over nodes separately for each \emph{k}-vector. Though the amount of data transferred each time is small, the communication and inter-processor synchronization is far more frequent than for the RKL scheme and the parallelism becomes very fine-grained. The upshot is that only machines with very low communications latency can run this version effectively. Practical tests show that the communications overhead completely negate any parallel gain on systems of networked workstations and most multiprocessors. However a significant speedup is obtained on a Cray T3D, which is exactly the case where this version is needed. \subsection{Shared-Memory Parallel Version} \label{sec:shmpar} An alternative parallel version is available for shared-memory multiprocessors with ``parallelizing'' compilers. This relies on the compiler handling the multi-threading, synchronization and allocation of local memory stacks for inner function calls. It requires compiler-specific directives to be inserted in the code and is therefore less portable than the distributed-memory version of the previous section. (Note that that version works on this class of machines too under the message-passing interface.) Nevertheless, it works and has been run on Stardent, Convex and Cray computers. It consists of replacements for files \Fname{force.c} and \Fname{ewald.c} called \Fname{force\_parallel.c} and \Fname{ewald\_parallel.c}. Then the program should be compiled with the preprocessor macro \Lit{PARALLEL} defined (not \Lit{SPMD}). The distributed-memory parallel version (section~\ref{sec:spmdpar}) is generally recommended over this one. However because the parallel sections reference a single global copy of most of the arrays, the shared-memory version uses much less memory. This version may therefore be of use if memory limits the size of the system on a multiprocessor machine. % The approach taken is to retain the vectorized inner loops and % parallelize the the outer loops, over cells for \Fname{force.c} and {\bf % k} vectors for \Fname{ewald.c}. The two parallel loops are structured by % the method developed by the Kingston group\cite{wojcik:85}. That is, a % loop of the form % \begin{verbatim} % for(i = 0; i < N; i++) % % \end{verbatim} % is transformed into % \begin{verbatim} % for(processor = 0; processor < NPROCESSORS; processor++) % for(i = processor; i < N; i += NPROCESSORS) % % \end{verbatim} % so that the outer loop is over the number of available processors, % and the inner loop has an increment of that number. Note that this % transformation reorders the loop iterations. % % If the outer loop is to execute concurrently, each sub-process or % thread must have local copies of any temporary variables, notably % \Lit{i}. Therefore the contents of each loop are isolated into a % separate function. Each thread executes a separate incarnation % of the function. A shared-memory model is assumed, in which each % thread accesses a single copy of the parameters and global % variables, but has a unique copy of all of its local variables. % % The ``master'' thread maintains separate copies of result variables % and arrays, (\ie\ the forces, potential energy and stress virial) so % that each incarnation of the function can write to its own copy % without interference from other threads. After all of the threads % recombine, the separate copies are summed to give the final result of % the calculation. This method avoids the need for explicit % synchronization between threads, but will add to the serial overhead % on highly parallel machines. % % The method of actually parallelizing the outer loop will vary from % machine to machine. The stellar compiler is able to generate parallel % code, and the directive \Lit{/*\$dir}~\Lit{no\_recurrence*/} % instructs it to parallelize the following loop. The Ardent, Convex % and Cray compilers use \Lit{\#pragma} directives, namely % \Lit{\#pragma ipdep}, \Lit{\#pragma \_CNX force\_parallel} and % \Lit{\#pragma \_CRI taskloop} respectively. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Portability}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% A major goal in writing \moldy\ was that it be as portable as possible between different computers and operating systems. It is written in the Kernighan and Ritchie\cite{kernighan:78} compatible subset of ANSI C and assumes the library calls and header files defined for a hosted implementation of the standard. It should therefore be possible to compile and run \moldy\ on any computer which has a good C compiler. There are two possible sources of difficulty in moving \moldy\ to a new machine. Though hosted ANSI standard C environments are now commonly available it may still be necessary to compile \moldy\ using a pre-ANSI compiler. In that case some library functions and header files may not be present. Secondly, to make good use of vector or parallel architectures, compiler directives or calls to specialized library functions are usually required. Replacement ANSI library functions are supplied in \Fname{ansi.c} for the VMS and unix (both Berkeley and AT\&T system V varieties) operating systems. Different versions of a function are selected by the C preprocessor and conditionally compiled according to the pre-defined preprocessor symbols (see the documentation for your compiler). For ease of portability \emph{all other system-dependent functions are in the module \Fname{auxil.c}} and \emph{all preprocessor conditionals are in the header file \Fname{defs.h}}. If the target machine has ANSI conformant C libraries, all that must be done is to define the preprocessor symbol \Lit{ANSI\_LIBS}, either in \Fname{defs.h} or by using a compiler option \eg\ \Lit{-DANSI\_LIBS}. This is done automatically in \Fname{defs.h} for several machines known to have conformant environments. If the target operating system is the system V variant of UNIX, the preprocessor symbol \Lit{USG} is defined automatically in \Fname{defs.h}. It is possible that some environments may defeat the selection making it necessary to define it by hand, either in \Fname{defs.h} or by setting the compiler option \Lit{-DUSG} in the makefile. \subsection{System Dependencies} In this section, details of system-dependent functions are described for the major operating systems. \begin{description} \item[Replacement ANSI header files] \begin{sloppypar} The ANSI header files \Fname{string.h}, \Fname{stdlib.h}, \Fname{stddef.h} and \Fname{time.h} are missing from Berkeley unix, or incomplete. Replacements are included which may be dispensed with on an ANSI conformant system - If the symbol \Lit{ANSI\_LIBS} is defined they simply include the system version. \end{sloppypar} \item[Replacements for ANSI functions] \hspace*{1em} \noindent \begin{itemize} \item The ANSI function to delete a file, \Lit{remove()}, the signalling function \Lit{raise()} and the string functions \Lit{strstr()} and \Lit{strerror()} are missing from pre-ANSI libraries. Replacements are supplied in \Fname{ansi.c}. \item Replacements are provided in \Fname{ansi.c} for functions \Lit{memset()}, \Lit{memcpy()} and \Lit{strchr()} which are missing from Berkeley UNIX. \item The function \Lit{vprintf()} is often absent from older libraries. Replacements are provided which \emph{a)} call the internal function \Lit{\_doprnt()} or \emph{b)} implements a portable \Lit{vprintf()}. Use the preprocessor macros \Lit{HAVE\_VPRINTF} or \Lit{HAVE\_DOPRNT} to select which. \end{itemize} \item[Timing routines] The supplied \Lit{clock()} function on 32-bit UNIX systems resets to zero after 36 minutes. Replacements, called \Lit{cpu()} for system V and Berkeley UNIXes and POSIX are supplied in \Fname{auxil.c}. The function \Lit{rt\_clock()} is also defined and returns the elapsed time in seconds. For a non-unix system \Lit{cpu()} and \Lit{rt\_clock()} simply call the ANSI functions \Lit{clock()} and \Lit{time()}. \item[File manipulation routines] \Fname{Auxil.c} contains the functions \Lit{replace()} and \Lit{purge()}. \Lit{replace()} renames a file, making a backup of any existing file of that name. \Lit{purge()} removes the previous or backup version of a file. These functions make use of the file name syntax of the host operating system and are therefore system-dependent. Unix file systems do not have explicit version numbers but \moldy\ keeps a single previous version by appending a ``\%'' character to the name. The pure ANSI versions just interface to \Lit{rename()} and do nothing respectively. \end{description} \subsection{Optimization and Vectorization} \moldy\ has been designed to run fast on a wide range of computers, and in particular on those with vector, multiprocessor and parallel architectures. This is a difficult problem, since the constructs which run fast on different architectures may be quite distinct and occasionally in conflict. Nonetheless, it has been found that following a few basic rules gives extremely good performance on a wide range of computer architectures. In a rough order of importance these are: \begin{enumerate} \item Minimize the number of memory references to floating point data in critical loops. Memory access is the major bottleneck on almost every modern computer, scalar, vector or parallel. \item Minimize the number of memory references to floating point data in critical loops. This cannot be emphasized enough. \item Ensure that memory is accessed contiguously within critical loops. That is, arrays should be accessed with a stride of 1 and with the last index varying most rapidly.\footnote{C uses the opposite convention to FORTRAN in storage layout of multidimensional arrays} This is absolutely critical on machines where memory is accessed via a cache, \ie\ all workstations and many parallel systems, and frequently very important on machines with interleaved memory (\ie\ most vector machines). \item If the value of any array element is used more than once in a loop, write the loop using temporary scalars to store results and assign them to the arrays at the end of the loop. This allows the compiler to optimize memory references.\footnote{Technically, the C standard treats arrays passed as formal function parameters as pointers which are permitted to refer to overlapping areas of memory. The compiler must therefore assume that if an array element is written in a loop then elements of any other arrays may also be changed. It must therefore reload from memory even though it already has a copy of the value in a register. But if all loads are completed before any stores then the compiler is at liberty to re-use the values and save memory accesses.} \item Minimize the floating-point operation count in critical loops. \item Minimize integer arithmetic in critical code. CRAY vector machines in particular have no integer multiplication hardware, and integer operations are slow as a result. \end{enumerate} The performance of \moldy\ has been carefully studied using profiling tools, and all critical regions of code are written as efficiently vectorizable loops. The most critical sections of code (\ie\ those which use the majority of the computer time) are all to do with the site forces calculation. Thus it is the inner loops in \Fname{force.c}, \Fname{ewald.c} and \Fname{kernel.c} to which most attention should be paid. The pair-distance loop of \Lit{rdf\_calc()} in \Fname{rdf.c} should vectorize for efficient radial distribution function evaluation. Others which are of minor importance are in \Fname{beeman.c}, \Fname{matrix.c}, \Fname{quaterns.c} and \Fname{algorith.c}. \Fname{Auxil.c} contains alternative versions of various sum, dot product, scatter and gather routines \etc\ which are interfaces to machine-specific libraries \eg\ Cray scilib, Convex veclib (which usually have FORTRAN calling conventions). There are also default versions coded in C which do vectorize, for machines lacking specialist libraries as well as for scalar computers. \subsection{Optimization for Vector Architectures} The program should, of course, be compiled with options specifying vectorization. Since highly optimizing and vectorizing compilers frequently contain bugs, and since some options generate ``unsafe'' optimizations, it may be necessary to restrict the highest optimization level to those modules which contain critical code. To allow the compiler to generate vector code, it must be instructed to ignore apparent vector recurrences. The reason is that the run-time dimensioned arrays necessary to implement such a flexible program must use pointers as their base. (See any C textbook, \eg\ Kernighan and Ritchie\cite[Chapter 5]{kernighan:88} for an explanation of C pointers and arrays.) Unfortunately this means that the compiler can not determine that each iteration of the loop is independent of the preceding iterations. In the jargon of vectorizing compilers, there may be a \emph{vector dependency} or \emph{recurrence}. The compiler can be notified that these are not genuine recurrences either globally by use of a command-line directive or on a per-loop basis using machine-specific compiler directives inserted into the source. Most compilers also have an option which directs it to ignore recurrences throughout the whole program, \eg\ \Lit{-va} on the Convex, \Lit{-va} and \Lit{-h ivdep} on the Cray compilers. It should normally be safe to use these options. Each manufacturer's compiler has its own peculiar set of inline directives. For example the CRAY compilers use a \Lit{\#pragma}~\Lit{ivdep} statement whereas the convex and Stellar compilers use a ``significant comment'' \Lit{/*\$dir no\_recurrence*/}.\footnote{A mechanism is provided to insert appropriate directives using the C preprocessor. The text \Lit{VECTORIZE} has been placed before each loop which ought to be vectorized, and the file \Fname{defs.h} contains machine-conditional \Lit{\#define}s to replace it with the appropriate directive. Currently directives for the CRAY, Stellar and Convex compilers are included, and null text is substituted for other machines. Notice that in each case the substituted text is \emph{not} the directive described in the manual, but rather that directive \emph{after} it has been passed through the preprocessor. To determine what should be substituted on a new vector machine, create a small test containing the documented directive and use the C preprocessor on that file. The output will show the form that should be defined in \Fname{defs.h}. Unfortunately this method had been made obsolete by the ANSI C standard, which makes it impossible to insert pragmas using the preprocessor. } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Modifying Moldy}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Adding a New Potential} \label{sec:newpot} By default \moldy\ supports potential functions of the Lennard-Jones, six-exp and MCY forms. However it should be very easy to add further types. The program is written in a highly modular fashion so that \emph{the only code which need be altered is in file \Fname{kernel.c}} (and occasionally in \Fname{defs.h}). The calculation of the potential and forces is performed entirely in the function \Lit{kernel()}. This function is called repeatedly with a vector of (squared) distances between some reference site and its neighbour sites. Vectors of potential parameters and charges are supplied which bear a one to one correspondence with the elements of the distance vector. It calculates the corresponding values of ${dU(r_{ij})} \over {dr_{ij}}$ which it stores in \Lit{forceij[]}. There are several variants of the force-calculation loop, one for each kind of potential. The potential type in use is passed as a parameter to \Lit{kernel()} and is used in a \Lit{switch} statement to select the appropriate code. To add a new potential the array of structs called \Lit{potspec[]} must be extended. The new array element should contain the name of the new potential (against which, the names given in system specification files will be matched) and the number of potential parameters for each site pair.\footnote{By default the arrays are sized for up to seven parameters. If this is not sufficient, the limit, set by the value of the constant \Lit{NPOTP} defined in \Fname{defs.h} may be increased.} In parallel with \Lit{potspec[]}, the array \Lit{pot\_dim[]} must also be updated with a new entry which describes the dimensions of each parameter for the new potential. It is used by the input routines to convert from the input units into program units. The entry consists of triplets containing the powers of mass, length and time, one for each parameter. Then define a new preprocessor symbol to the index of the new type in the array \Lit{potspec[]} (after the line \Lit{\#define~MCYPOT~2}). The value must correspond to the index of the new entry in \Lit{potspec[]} starting from 0 in accordance with the usual C convention. This constant should be used to define a new case in the \Lit{switch} statement of \Lit{kernel()}, and this is where the code to evaluate the potential goes. The existing cases may be used as a model, especially for the evaluation of the electrostatic term $\erfc(\alpha r) / r$ which is evaluated by the polynomial expansion of Abramowitz and Stegun\cite[section 7.1.26]{abramowitz:70}. There are currently \emph{two} versions of each loop, the second omitting this term for efficiency when all the electric charges are zero (which case is flagged by a negative value of $\alpha$). Finally, the distant potential correction for the new potential should be added as a new case to function \Lit{dist\_pot()}. The code should evaluate \[ - \int^{\infty}_{r_c} r^2 U(r) \, \Calcd r \] for the potential $U(r)$. \subsection{Porting the Parallel Version} \label{sec:parport} It should be relatively straightforward to port the distributed-memory parallel version to a new message-passing library. Section~\ref{sec:parstrat} describes the parallel implementation. All of the interface code is contained in \Fname{parallel.c} and it will only be necessary to modify this file. A new port should declare a new preprocessor macro along the lines of \Lit{MPI} \etc\ which should be used to conditionally compile its code only. Any header files may be included in the appropriate place in \Fname{parallel.c}. Then the interface functions should be written to call the underlying message passing library. These should again be conditionally compiled. It should be obvious where to place them in the file and the existing versions will provide a model. Their specifications are: \begin{Litdescription} \sloppy \item[par\_sigintreset(void)] Moldy sets a handler for SIGINT\@. This function is called from the signal handler to restore the default. \item[par\_begin(int *argc, char ***argv, int *ithread, int *nthreads)] Initialize the library and return the number of processes and the ID of this process. \item[par\_finish(void)] Terminate the parallel run normally. \item[par\_abort(int code)] Terminate the run abnormally. Return code if possible. \item[par\_broadcast(void *buf, int n, size\_mt size, int ifrom)] Broadcast the specified buffer from node \Lit{ifrom} to all nodes. \item[par\_\{r,d,i\}sum(void *buf, int n)] Perform a global parallel sum reduction on the buffer containing n reals,\footnote{\Lit{real} is a typedef defined in \Fname{defs.h} which is set either to \Lit{float} or \Lit{double} (see section~\ref{sec:types}). The code for \Lit{par\_rsum()} must handle either case, which may be tested using the \Lit{sizeof} operator. For example the preprocessor macro \Lit{\#define M\_REAL (sizeof(real)==sizeof(double)?MPI\_DOUBLE:MPI\_FLOAT)} is used to determine which constant to pass to the MPI sum function.} doubles or ints. \item[par\_imax(int *idat)] Perform a global maximum reduction on the single int argument. \fussy \end{Litdescription} The SPMD parallel strategy updates the dynamic variables independently on all processors (see section~\ref{sec:parstrat}). To update the separate copies of the co-ordinates and other dynamic variables synchronously the results of the floating-point arithmetic must be identical. Therefore the result returned by \Lit{par\_rsum} and \Lit{par\_dsum} must be identical to the last bit on all processors: see the footnote on page~\pageref{sec:parstrat}. Another consequence is that execution on heterogeneous workstation networks is not supported - the identity of floating-point operations in not guaranteed even if all use IEEE arithmetic. \moldy\ periodically tests for divergence of trajectories and will exit with the message \Lit{*F* Trajectories on parallel threads are diverging.} \noindent if this condition is detected. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Program Structure} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The source of \moldy\ consists of 31 different C source files amounting to 167 functions and 9000 lines of code. A complete and detailed description would be a compendious volume of questionable value. Instead, much of the detailed documentation is contained in the source code in the form of comments. This chapter concentrates on describing the organization of the calculation and the data structures used throughout the code, describes some of the more complicated and less obvious algorithms and provides call graphs and brief function descriptions to act as a map of the program structure. \moldy\ is written in modular fashion in adherence to the principles of \emph{structured programming} to as great a degree as practical. This does not mean merely the avoidance \Lit{goto}s but, instead the organization of the program into modules and functions which are independent of each other and of global environmental variables. Functions are kept to a limited size and as far as practical and serve a single, well defined purpose.\footnote{The term ``function'' in C corresponds to both functions and subroutines in FORTRAN.} This ensures that the internal workings of a function are unaffected by changes elsewhere in the program, and do not have any influence on any other part of it, except through the defined interface. In \moldy\, functions are grouped into different files according to a rough classification of their purpose. The other primary consideration in the design of a large computer program is the provision and organization of storage for the data. Structured programming advocates that definitions of data objects be restricted as closely as possible to the code that uses them, and that the code be organized in a modular fashion to encourage data locality. This minimizes the risk of a programming error in one part of the code modifying a variable used in a completely different part and producing difficult-to-locate side effects. With two exceptions,% \footnote{These are the struct \Lit{control} (section~\ref{sec:sysvars}) and the integers \Lit{ithread} and \Lit{nthreads} holding the parallelization parameters (section~\ref{sec:pario}).} global data is avoided in \moldy\ and all arrays are passed as function arguments where necessary. Heavy use is made of C structures (or ``structs'') to further group related data so that it may be manipulated \emph{in toto}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Data Structures}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:structs} \subsection{Types and Typedefs} \label{sec:types} A number of derived types are defined in the header file \Fname{defs.h} for reasons of economy of expression, portability and ease of customization. Most of these derived types are named using a suffix \Lit{\_mt} to mark them as such. These are \begin{Litdescription} \item[real] This is the ``standard precision'' floating-point type used for all the dynamic variables and most other internal variables. It is set to \Lit{double} by default. Changing this to \Lit{float} will give a single-precision version of \moldy\ with a consequent memory saving. However additional work must be done to create a fully single-precision version, since the standard double-precision maths library will still be used. The C standard does not require a single-precision maths library, but most systems do make the functions available. However there is no standardization of the interface so this can not be done portably. \item[boolean] Used for storing logical values. Typed to \Lit{int}. \item[gptr] Generic pointer type, set to \Lit{void} in the case of ANSI C. Pre-ANSI compilers do not support \Lit{void} so \Lit{char} is used instead. \item[time\_mt] This is used to store integer format times and dates as returned by the \Lit{time()} function. It is declared as \Lit{unsigned long} and is used because pre-ANSI compiling systems may not define the \Lit{time\_t} type for this purpose. \item[size\_mt] Used for storage of C object sizes as returned by \Lit{sizeof}. Like \Lit{time\_mt} this would be unnecessary if we were guaranteed an ANSI C compilation system. \item[vec\_mt] Array of 3 \Lit{real}s for holding a vector type. \item[quat\_mt] Array of four reals for holding a quaternion type. \item[mat\_mt] $3 \times 3$ array of reals for storing a matrix. \end{Litdescription} \subsection{Memory Management} The allocation of memory for storage of the multitude of data required in a molecular-dynamics simulation is one of the main design criteria of the code. The general nature of the systems to be accepted by \moldy, namely the arbitrary mixtures of molecules with different numbers and kinds of atoms requires a number of large multidimensional arrays with system-dependent bounds in more than one dimension. It is impractical to declare these statically with dimensions fixed at some suitably large value because total memory use would then be infeasibly large. The availability of standard, portable, dynamic memory allocation was one of the major reasons the author chose to write \moldy\ in C.\footnote{At the time \moldy\ was being planned in 1988 C was the \emph{only} widely available language offering dynamic memory allocation. Fortran 90, which also offers dynamically declared arrays was standardized in 1991 and compilers only became common in the mid-nineties.} \moldy\ uses C's capability of array emulation by pointers and heap-based memory allocation\cite{kernighan:88} rather than true C arrays which, like FORTRAN's, are restricted to bounds fixed at compile-time. Much of the dynamic memory used in \moldy\ is allocated on entry to a function and deallocated before exit to emulate local, variably-dimensioned arrays. The main exceptions are the arrays of dynamical variables which are allocated once during the startup phase and not freed until program exit. All dynamic memory is allocated using the function \Lit{talloc()} which is a wrapper around the standard library function \Lit{malloc()}. Function \Lit{talloc()} simply calls \Lit{malloc()}, tests the return value and calls an error exit function if it failed to allocate the memory requested. Its interface takes advantage of the C preprocessor macros \Lit{\_\_LINE\_\_} and \Lit{\_\_FILE\_\_} to print out the location of a failing call, and a wrapping macro \Lit{aalloc()} is provided in \Fname{defs.h} for this purpose. This also contains other \Lit{\textsl{x}alloc()} macros customized for various data types. The complementary function \Lit{tfree()} calls the library function \Lit{free()} but also allows tracing of allocation and freeing for debugging purposes. All of \moldy's memory-management functions are in the source file \Fname{alloc.c}. Like FORTRAN, C only permits the declaration of arrays of size fixed at compile time. Unlike FORTRAN, C lacks any method of declaring arrays with adjustable innermost dimensions as function formal parameters. However through the use of pointer --- array mapping and dynamic memory allocation, variable-sized multidimensional arrays may be emulated\cite[p107]{kernighan:88},\cite[pp 20--23]{press:92C}. Multidimensional array emulation is done by the function \Lit{arralloc()} (see Figure~\ref{fig:arralloc}). This takes the size of the atomic data-type, the number of dimensions and the lower and upper bounds for each dimension as arguments and returns a pointer to the allocated pseudo-array. This is an array of \emph{pointers} (to an array of pointers to \ldots) to the data area. The C mapping of array notation onto pointer syntax allows this construct to be referenced exactly as if it was a true multidimensional array. For example\\ \parbox{\textwidth}{% \begin{quote} \Litf double **r;\\ r = arralloc(sizeof(double), 2, 0, m, 0, n); \end{quote}}\\ \noindent defines a 2D array, $m \times n$ of \Lit{double} so that \Lit{r[i][j]} is a reference to the $i, j$ th element in the usual manner. This pseudo-array may be passed directly to a function, \eg\\ \parbox{\textwidth}{% \begin{quote} \Litf double doit(r, i, j)\\ double **r;\\ int i, j;\\ \{\\ \hspace*{1cm} r[i][j] = 0.0;\\ \} \end{quote}}\\ \noindent since the underlying pointer arrays contain all the necessary shape information to access it. Function \Lit{arralloc()} is implemented so as to lay out the individual pointer and data arrays as part of a single block of memory which is allocated by a single call to \Lit{talloc()}. It then sets up the values of the pointers to emulate the requested array. The memory can be freed with a single call to \Lit{tfree().} The \Lit{arralloc()} mechanism is unnecessary for 2D arrays where the innermost dimensions are fixed, such as for an array of position co-ordinates which has dimensions \Lit{[n][3]}. In such cases one of the \Lit{\textsl{x}alloc()} macros is used to allocate an array with fixed innermost dimensions and whose type is a pointer to a fixed-size array \Lit{double (*x)[3]} rather than a pointer to a pointer \Lit{double **x}. \begin{figure}[tb] \begin{center} \input{fig_arralloc} \end{center} \caption[Storage layout of a 2-dimensional pointer-based pseudo-array]{Storage layout of a 2-dimensional pointer-based pseudo-array. The base pointer \Lit{r} is of type ``pointer to pointer to double'' and declared \Lit{double **r}. This points at a 1-dimensional array with length $m$ of pointers, which in turn point to the $m$ rows of data arrays. This structure contains all the information needed to access element \Lit{r[i][j]} using pointer indirection rather than an indexing computation and therefore without any reference to the values of $m$ or $n$. Higher dimensional arrays are set out on a similar fashion with more levels of pointer arrays, $n-1$ for an $n$-dimensional array} \label{fig:arralloc} \end{figure} There is one important instance of a more sophisticated use of arrays of pointers; the allocation of the atomic-site, site-force, centre-of-mass force and torque arrays in the main timestep loop function \Lit{do\_step()}. These syntactically resemble 3D arrays declared, \eg\ \Lit{site[nspecies][nsites][3]} but because the number of sites differs between molecular species they do not map onto ``rectangular'' 3D arrays. However the ``array of pointers'' construct does allow for rows of different lengths and this is easily set up. These pseudo-arrays can again be passed straightforwardly as function arguments and used with the obvious and intuitive indexing scheme at the cost of a little extra code to allocate and initialize the pointers. \subsection{System Variables and Data Structures} \label{sec:sysvars} \moldy\ makes consistent use of C language structures or ``structs'' to combine related pieces of data into a single variable. This may then be passed as a single function argument avoiding long and cumbersome argument lists and the consequent risk of programming error. All of the major struct types used in this way are defined in the header file \Fname{structs.h} where each type is carefully annotated with the meaning of its members. The struct \Lit{control} is shared between almost all modules in the program using external linkage.\footnote{This is analogous to a COMMON block in FORTRAN.} It contains the values of the parameters from the control file --- the exact mapping is defined by the array (of structs) \Lit{match[]} declared in source file \Fname{startup.c}. The values are read from the control file by function \Lit{read\_control()} in source file \Fname{input.c} and adjusted by \Lit{start\_up()} in \Fname{startup.c} where the timestep-related parameters are updated and the floating-point values are transformed into program units. These are the only functions which alter values in \Lit{control}. Most of the information needed to describe the system is stored in the struct \Lit{system} and the array of structs \Lit{species[]}. Struct \Lit{system} contains counters to record the total numbers of species (\Lit{nspecies}), atomic sites (\Lit{nsites}), molecules (\Lit{nmols}), polyatomic molecules\footnote{strictly speaking molecules with rotational degrees of freedom.} (\Lit{nmols\_r}) and pointers to the arrays of dynamical variables. Its counterpart \Lit{species[]} is a dynamically allocated array, length \Lit{nspecies}, of structs of type \Lit{spec\_mt} which contains individual data for each molecular or atomic species. This includes the mass, moments of inertia, dipole moment, and charge, the number of sites belonging to this species and the number of molecules. It also contains pointers to the array of site identification numbers, and Cartesian site co-ordinates (expressed in the molecular principal frame) for this species and also to the arrays of dynamical variables. The dynamical variables are stored in dynamically-allocated arrays of total length \Lit{nmols} and \Lit{nmols\_r} which may be regarded as the concatenation of individual arrays containing variables belonging to each molecular species. The pointers in \Lit{species[i]} locate the beginning of the array of variables belonging to species \Lit{i} and those in \Lit{system} to the beginning of the entire array. The variables are manipulated by either route as is most convenient (but never both within a single function). The potential parameters are stored separately in the array \Lit{potpar} since they refer to pairs of site types (\emph{site-id's}). This is an array of structs of type \Lit{pot\_mt}, laid out as a 2-dimensional symmetric matrix of dimension \Lit{system.max\_id} with rows and columns indexed by the site identifiers as given in the system specification file. In fact it is stored in a one-dimensional array of length (\Lit{system.max\_id})$^2$ and the index calculation is performed explicitly when it is referenced. Structure type \Lit{pot\_mt} contains an array \Lit{p} for the actual parameter values. This is a fixed-length array with \Lit{NPOTP} members, where the constant \Lit{NPOTP} is defined in the header file \Fname{defs.h}. If a new potential with more than 7 parameters is to be added to \moldy\ it will be necessary to increase its value. The above primary storage of the potential parameters is convenient for reading in and storing and rereading restart files. However it can not be indexed efficiently to retrieve the potential parameter values in the critical innermost loops. The data is therefore copied into an expanded 3-dimensional array \Lit{potp[max\_id][NPOTP][nsites]} in the force evaluation function \Lit{forces()} before being used. The masses and charges of the various sites are stored in another array of structs \Lit{site\_info[]}, simply indexed by the site identifier. As with the potential parameters this is not convenient for access within the inner force loop, so the data are expanded in \Lit{do\_step()} to fill an array \Lit{chg[nsites]} to allow direct indexing by the loop counter. The two final data structures of importance are those containing accumulated data for computing the usual averages and the radial distribution functions. Both databases are considered private to their respective source modules \Fname{values.c} and \Fname{rdf.c} and are only accessed using the function interfaces provided in those modules. The averages database provides a general and extensible scheme for storing partial sums and computing rolling- and time- averages of instantaneous values such as temperature, kinetic energy \etc\ It consists of two parts, a linear array \Lit{av[]} of structs of type \Lit{av\_mt} (defined in \Fname{values.c}) and an array of classified types of data which contains pointers to \Lit{av[]}, the numbers of components, and to format strings and units conversion factors for output formatting and printing. This is the compile-time struct array \Lit{av\_info[]}, again defined in \Fname{values.c}. To compute averages of a different quantity a new entry should be added to the array \Lit{av\_info}, and another corresponding enum type to \Lit{enum av\_n} in \Fname{defs.h}. The storage, retrieval and averages computation functions will then recognize the new type and may be called from within \Lit{values()} and \Lit{averages()}. The array \Lit{av} itself is set up using the ``struct hack'' to allocate space for the rolling average data. The structure type \Lit{av\_mt} contains as its final entry an array with one element \Lit{roll[1]}. When storage for \Lit{av} is allocated, the amount requested is calculated \emph{as if} the member array was declared \Lit{roll[n]} with $n$ equal to the rolling-average interval. The array member \Lit{roll[]} may then be used as if it had $n$ members. This does mean that the array \Lit{av} can not be simply indexed using pointer arithmetic or array subscripting since the compiler's notion of the size of a pointer of type \Lit{av\_mt~*} is wrong. It is instead accessed solely via the pointers contained in array \Lit{av\_info}. The general functions \Lit{add\_average()} \etc\ in \Fname{values.c} provide the means to store and retrieve values and compute averages. The function \Lit{av\_ptr()} is provided to make the size and base address of the averages database available to the restart file reading and writing functions in \Fname{restart.c}. Radial distribution functions are calculated between all pairs of site types (defined by the site identifier given in the system specification file). Storage for the accumulating binned pair distances is provided by a 3D pseudo-array \Lit{rdf[idi][idj][bin]} with two indices for the site identifiers of the pair and one for the bin. This does not have the geometry of a true 3D array but is set up by function \Lit{init\_rdf()} to economise on memory by making \Lit{rdf[idi][idj][bin]} an alias for \Lit{rdf[idj][idi][bin]}. Both the pointers and the actual data area are of course dynamically allocated. The latter is in a single block of memory whose address is stored in \Lit{rdf\_base} so that it may be easily stored in and retrieved from a restart file. The function \Lit{rdf\_ptr()} is provided to make the size and base address of the RDF database available to the restart file reading and writing functions in \Fname{restart.c}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Files and Functions}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Source Files} The source files consist of 8 ``\Fname{.h}'' header files and 23 ``\Fname{.c}'' code files which contain functions grouped in a modular fashion. A detailed description of the purpose and interface to each function is given in the source code in the form of comments, which should be regarded as the primary documentation for the function. An annotated list of files follows. \begin{Fndescription} \item[structs.h] Definitions of structure types used throughout the program. \item[defs.h] Main \moldy\ header file to be included in all ``\Fname{.c}'' files. It contains machine and operating-system configuration macros., physical constants, unit definitions and global (non-structure) type definitions. \item[string.h, time.h, stddef.h, stdlib.h] These files are replacements for the ANSI C library header files of the same name, included here for portability to pre-ANSI environments. \item[messages.h] Error messages file containing messages in the form of preprocessor macros. This may allow for non-English language customization. \item[xdr.h] Includes the system headers for the usual External Data Representation (XDR) functions and prototypes of additional functions for XDR reading and writing of \moldy--specific structure types. \item[accel.c] Contains \Lit{do\_step()}, which implements the major part of the main MD timestep procedure plus functions for velocity rescaling and thermostatting. \item[algorith.c] Contains functions to implement algorithms and computations related to the dynamical equations of motion. This includes the computation of molecular centre-of-mass forces, torques, the Newton-Euler equations and the constant--stress and --temperature functions. These functions all have an interface which makes no reference to the \Lit{system} or \Lit{species[]} structs. \item[alloc.c] Contains functions for memory management; allocation, (\Lit{talloc()}) freeing (\Lit{tfree()}) and setting up of pointer-based multi-dimensional arrays (\Lit{arralloc()}). \item[ansi.c] Replacements for certain functions required in any ANSI C standard library but missing from pre-ANSI environments. \item[auxil.c] Machine- and OS-dependent support functions. Contains \emph{(a)} Fast vector arithmetic functions, including interface to various vector libraries as well as pure ``C'' versions. \emph{(b)} OS-dependent time and file manipulation functions. \item[beeman.c] Functions implementing the separate stages of the modified Beeman algorithm, including basic steps and the updating of all the necessary dynamical variables. \item[convert.c] Functions for converting the potential parameters and control file parameters from input units to program units and vice versa. \item[dump.c] Functions for managing periodic trajectory \etc\ dumps. \item[ewald.c] Evaluates the reciprocal-space part of the Ewald sum for the long-ranged Coulombic forces. \item[force.c] Implements the calculation of the short-ranged forces and the real-space part of the Ewald sum using the Link Cell algorithm. This excludes the actual evaluation of the potential which is contained in \Lit{kernel()} in \Fname{kernel.c}. \item[input.c] Functions for reading the control and system specification files and allocating the structures to hold the data read in from them. \item[eigens.c] Matrix diagonalizer from the netlib archive. \item[kernel.c] Contains \Lit{kernel()} which actually evaluates the potential given a vector of pair distances. \item[main.c] Function \Lit{main()} is the main program which controls the set up and contains the main MD timestep loop that calls \Lit{do\_step()} to do most of the work of a timestep. \item[matrix.c] Functions for manipulating $3 \times 3$ matrices and applying to $3 \times n$ arrays of co-ordinates \etc \item[output.c] Main output functions responsible for regular output sent to main output file. Also contains error-handling function \Lit{message()} which may terminate simulation. \item[parallel.c] Interface between \moldy\ and various parallel message-passing libraries. Also contains functions to copy \moldy's data structures from the input/output node to other nodes using the parallel interface. \item[quaterns.c] Functions for manipulating arrays of quaternions. \item[rdf.c] Contains \Lit{init\_rdf()} which sets up RDF database, \Lit{rdf\_accum()} which periodically bins pair distances and \Lit{rdf\_out()} which calculates and prints all the radial distribution functions. \item[restart.c] Functions for reading and writing the restart and backup files. \item[startup.c] Primary initialization function \Lit{start\_up()} plus subsidiary functions \Lit{allocate\_dynamics()} to create dynamic variable arrays and \Lit{initialise\_sysdef} to compute molecular and whole-system properties. Also contains functions to create initial configuration for system. \item[values.c] Function \Lit{init\_averages()} allocates and sets up pointers to averages database. Other functions store and retrieve instantaneous values of thermodynamic quantities and compute the averages thereof. \item[xdr.c] Functions to read and write \moldy's own struct types using the External Data Representation (XDR) library. \end{Fndescription} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Flow of Control}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Input and Initialization} \label{sec:startup} \begin{superfig} \begin{partfigure}[tb] \noindent \input{fig_startup-a} \begin{minipage}[b]{2.55in} \raggedright \textbf{Functions called by start\_up()}\\ \footnotesize \setlength{\leftmargini}{1em} \begin{Litdescription} \item[default\_control()] Initialize struct \Lit{control} with default parameter values. \item[read\_control()] Read parameters from control file and store in struct \Lit{control}. \item[convert\_control()] Convert physical values in \Lit{control} between input and program units. \item[read\_sysdef()] Read the system specification file. Allocate storage for arrays \Lit{species}, \Lit{site\_info} and \Lit{potpar} and copy in values from file. \item[initialise\_sysdef()] Finish set up of \Lit{system} and \Lit{species} structs. \item[allocate\_dynamics()] Allocate memory for the dynamic variable arrays and set up pointers in \Lit{system} and \Lit{species} \item[skew\_start()] Set up skew-cyclic initial state. \item[lattice\_start()] Read crystal structure and set up co-ordinates, quaternions and cell vectors. \item[init\_cutoffs()] Determine optimum parameters for Ewald sum. \item[re\_re\_header()] Read the \Lit{restart\_header} and \Lit{control} structs from the restart file. \item[re\_re\_sysdef()] Read the system specification (structs/arrays \Lit{system}, \Lit{species}, \Lit{site\_info} and \Lit{potpar}) from the restart file. \item[read\_restart()] Read dynamic variables and the RDF and averages databases from the restart file. \item[check\_sysdef()] Check new system specification is consistent with old. \item[thermalise()] Set up Maxwell-Boltzmann velocity distribution \item[init\_rdf()] Prepare to bin RDFs. Allocate memory and pointers \item[init\_averages()] Allocate space for and initialize the averages database. \item[convert\_averages()] Update averages database if roll\_interval changed or if old-style restart file. \item[conv\_potentials()] Convert potential params between ``input'' and ``program'' units. \end{Litdescription} \end{minipage} \caption[Block diagram of initialization function \Lit{start\_up()}]{Block diagram of the initialization function \Lit{start\_up()} and a list of the functions called. Continued in Figure~\ref{fig:startup-b}.} \label{fig:startup-a} \end{partfigure} \begin{partfigure}[tb] \begin{center} \input{fig_startup-b} \end{center} \caption[Block diagram of initialization function \Lit{start\_up()}]{Block diagram of the initialization function \Lit{start\_up()} and a list of the functions called. Continued from Figure~\ref{fig:startup-a}. The paths beginning at \textbf{A}, \textbf{B} and \textbf{C} are for a new run, a restart from a save file, and a restart from a backup file respectively.} \label{fig:startup-b} \end{partfigure} \end{superfig} The initialization and input file reading stage of \moldy\ is rather more complicated than is usual in a molecular-dynamics simulation program because \begin{itemize} \item of the use of dynamic data structures. The size of the arrays required can only be determined after the input files have been partially read in, but they must be allocated before the read is complete. Thus reading of input files and array allocation must be interspersed. \item of the general nature of the systems \moldy\ is able to simulate. Many structures that might otherwise be hard-coded must here be read from the input files and set up dynamically. \item \moldy\ has three different modes of start-up; an initial run, a restart and a backup restart. The use of the stored values of the control parameters as defaults on a restart run is an added complication. \item the ability to specify the input units the potential parameters are expressed in requires the appropriate conversion to be performed at start-up. \end{itemize} Initialization is controlled by function \Lit{start\_up()} which is called directly from \Lit{main()}. It calls subsidiary functions to read the control and system specification, restart or backup files. It controls the allocation of dynamic memory for the system description and potential and dynamic variable arrays, and the RDF and averages databases. It oversees the computation of quantities derived from the input parameters and system specification and generally transforms the input data from a form useful for human preparation to one useful for machine computation. Figures~\ref{fig:startup-a} and~\ref{fig:startup-b} show a block diagram of \Lit{start\_up()} and a brief description of the functions it calls. Parameters are read from the control file by \Lit{read\_control()} which assigns their values to the corresponding member of struct \Lit{control}. The default values were previously set by \Lit{default\_control()}. In the case of a restart the saved parameters in the restart file are restored to \Lit{control} by function \Lit{re\_re\_header()}, overwriting all of the current values. In this way the saved values become the defaults for a second call of \Lit{read\_control()} which rereads the control file and assigns any new values. The repeated read is necessary because the \emph{name} of the restart file is supplied by the control file. Note that those parameters representing physical quantities must be converted to and fro between input and program units for consistency since they are stored in program units in the restart file. The three alternative routes within \Lit{start\_up()} for reading the system specification and initializing the dynamic variables \etc\ are shown in Figure~\ref{fig:startup-b}. The case of a new run is reasonably straightforward. Memory for the ``system specification'' arrays \Lit{species[]}, \Lit{potpar[]} and \Lit{site\_info[]} is allocated as the system specification is read in by \Lit{read\_sysdef()}. The raw atomic site co-ordinates are then shifted to the molecular centre-of-mass frame and rotated to the principal frame of the inertia tensor by \Lit{initialise\_sysdef()}, which also computes a number of other molecular quantities and completes the set up of the system specification. Next the dynamic-variable arrays are allocated and initialized and finally the RDF and averages databases are installed. If the run is a restart then those control parameters whose value is interpreted relative to the current timestep (see section~\ref{sec:control}) must have its value added to theirs. This is only done if the parameter was explicitly specified in the new control file, otherwise its saved value is untouched. Function \Lit{re\_re\_sysdef()} reads the system specification variables and arrays \Lit{system}, \Lit{species[]}, \Lit{potpar[]} and \Lit{site\_info[]} from the restart file. These were stored in their final form after being set up by the previous run so a call to \Lit{initialise\_sysdef()} is unnecessary. Alternatively a new system specification file may be used in which case a similar sequence to that for a new run is followed. Memory for the dynamic variable arrays and the RDF and averages databases must be allocated before their saved values are restored by \Lit{read\_restart()}. The simplest startup mode is that from a backup file. Once it has been determined that a backup file exists, setup proceeds much as in the restart case except that the parameters and system specification are restored unchanged. Thus the run continues exactly from the point the backup file was written. A restart file is still opened, but only to obtain the name of a backup file to search for. The final act of \Lit{start\_up()} is to call \Lit{banner\_page()} to print out a nicely formatted page of information to record the simulation details in the output file. Control is then transferred back to the main program where everything is now ready for the molecular dynamics to begin. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Main timestep loop} The initial entry point into \moldy\ is into function \Lit{main()}, which calls \Lit{start\_up()} (section~\ref{sec:startup}) and then proceeds into the main loop over molecular-dynamics timesteps (Figure~\ref{fig:main}). This loop calls \Lit{do\_step()} which computes the forces and advances the co-ordinates, velocities and their angular counterparts by one timestep. Most of the periodic tasks not directly associated with progressing the simulation, such as the accumulation of running averages, velocity rescaling and writing the output files are called directly from \Lit{main()}. The exceptions are the binning of site-pair distances for computing the radial distribution functions which is integrated into the site forces evaluation, and the writing of trajectory data to the dump file which is called from \Lit{do\_step()} since the force arrays are local to that function. \begin{figure}[tb] \input{fig_main} \caption[The main timestep loop]{The main timestep loop in file \Fname{main.c} showing the outermost control structures. Periodic analysis, trajectory dump or output tasks are all shown here including the accumulation of the radial distribution function data which is integrated into the link cell force calculation.} \label{fig:main} \end{figure} \begin{superfig} \begin{partfigure}[tbp] \begin{center} \input{fig_dostep-a} \end{center} \caption[Flow diagram of function \Lit{do\_step()} which performs a single timestep.]{Flow diagram of function \Lit{do\_step()} which performs a single timestep. (\emph{continued in Figure~\ref{fig:dostep-b}})} \label{fig:dostep-a} \end{partfigure} \begin{partfigure}[tbp] \begin{center} \input{fig_dostep-b} \end{center} \caption[Flow diagram of function \Lit{do\_step()} which performs a single timestep.]{Flow diagram of function \Lit{do\_step()} which performs a single timestep. (\emph{continued from Figure~\ref{fig:dostep-a}})} \label{fig:dostep-b} \end{partfigure} \end{superfig} The timestep loop continues until either the requested number of steps have been completed, a \Lit{SIGTERM} or \Lit{SIGXCPU} signal is received or one more step would exceed the CPU time limit set in \Lit{control.cpu\_limit}. Only the normal termination case is shown in Figure~\ref{fig:main}. In the case of an early termination \Lit{write\_restart()} is called to write out a backup file so the simulation may be restarted later. The signal handling functions \Lit{shutdown()} for \Lit{SIGTERM} and \Lit{SIGXCPU} and \Lit{siglock()} for other signals are installed in \Lit{main()} following the call to \Lit{start\_up()}. Function \Lit{shutdown()} simply sets a flag which is checked at the end of every iteration of the timestep loop. This allows for an orderly shutdown if the CPU limit is exceeded or if the run must be interrupted for some other reason. For conditions which require immediate program exit, function \Lit{siglock()} is called to delete the lock files before exiting. The tasks of calculating the forces, implementing the equations of motion and updating the dynamic variables each timestep are managed by function \Lit{do\_step()}. The conceptually simple calculation of forces and stepping of co-ordinates is made lengthy and less transparent by the need to handle the rigid-molecule equations of motion and the constant-pressure and -temperature extended system equations. The procedure is set out in figures~\ref{fig:dostep-a} and~\ref{fig:dostep-b}. The main stages of the calculation are \begin{enumerate} \renewcommand{\theenumi}{\emph{\alph{enumi}}} \item update all of the centre-of-mass co-ordinates, quaternions and extended-system variables according to steps \emph{i} and \emph{ii} of equations~\ref{eqn:beeman}. This is done by function \Lit{step\_1()} which also applies the quaternion normalization and constraints of equations~\ref{eqn:qnorm} and~\ref{eqn:qconst}. \item call \Lit{force\_calc()} and \Lit{ewald()} to evaluate the potential energy and the forces on all atomic sites. The site co-ordinates must themselves be computed from the centre-of mass co-ordinates and the quaternions by function \Lit{make\_sites()}. \item calculate the molecular centre-of-mass forces and torques using equations~\ref{eqn:comf} and~\ref{eqn:comt} which are implemented in functions \Lit{mol\_force()} and \Lit{mol\_torque()}. At this point the accelerations from the previous timestep are ``shuffled down'' from the \Lit{acc}, \Lit{qddot} \etc\ arrays in \Lit{system} and \Lit{species[]} to \Lit{acco}, \Lit{qddoto} to make way for the new accelerations computed in this timestep. \item calculate the internal stress (equation~\ref{eqn:prstress}) and the ``accelerations'' of the MD cell matrix from the Parrinello-Rahman equations of motion. Function \Lit{rahman()} implements equation~\ref{eqn:rahman}. \item calculate the new centre-of-mass and extended-system variable accelerations including the velocity-dep\-end\-ent parts which arise in a constant-pressure or -temperature calculation. Iterate steps \emph{iii}--\emph{v} of equations~\ref{eqn:beeman} until the velocities have converged. \label{loop:vel} \item calculate the new angular and rotational thermostat accelerations. The Euler equations (\ref{eqn:euler}) and equation~\ref{eqn:qddot} are used by function \Lit{euler()} to evaluate the second time-derivatives of the molecular quaternions. Iterate until the corresponding angular velocities have converged. \label{loop:quat} \item call \Lit{step\_2()} to apply the final step \emph{iv} of equations~\ref{eqn:beeman}. \item write requested co-ordinates \etc\ to the dump file. \end{enumerate} The loops of steps~\ref{loop:vel} and~\ref{loop:quat} iterate until the molecular centre-of-mass velocities and quaternion time derivatives have adequately converged (in practice about 3 or 4 iterations). No additional iteration is applied to converge the extended-system dynamic variables, since in any practical system these should be very slowly-varying compared to molecular motion and any error introduced will be very small. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{The Site-Forces Calculation} \begin{figure}[tb] \noindent \input{fig_link-cell} \caption{The Link-Cell short-range force calculation} \label{fig:link-cell} \end{figure} The evaluation of the forces on atomic sites comprises almost all of the run-time of any reasonably sized simulation --- over 95\% for systems of only a few hundred atoms. Efficiency of execution is therefore a primary consideration in this part of the code. It is frequently the case that a straightforward implementation of an algorithm is not optimally fast, which regrettably means that the optimized code is not as transparent to read as for other, less critical parts of the program. The link cell algorithm for the short-ranged part of the forces (section~\ref{sec:link-cell}) is one which scales very well to large systems. In its original form~\cite{quentrec:75} the MD cell is divided into a number of ``subcells'' and a linked-list structure~\cite{knuth:73a} lists the molecules or atoms belonging to each subcell. The inner loops of the force calculation must therefore use an \emph{indirect} indexing operation to obtain the co-ordinates on every iteration: the index of a molecule on each iteration depends on the index of the previous iteration. This kind of loop is inherently un-vectorizable which grossly limits the efficiency on vector computers. \begin{figure}[tb] \noindent \input{fig_ewald} \caption{Evaluation of the reciprocal-space parts of the ewald sum} \label{fig:ewald} \end{figure} To overcome this limitation a further step is needed, as suggested by Heyes and Smith~\cite{heyes:87}. Inside the loop over subcells, the linked list is pre-scanned and used to construct an array containing the indices of the molecules in the list. This is known as the \emph{neighbour list} since it points to the molecules in the region of the subcell under consideration. The co-ordinates are then assembled into a contiguous array using a \emph{gather} operation. The inner force loop then becomes a straightforward DO loop over this temporary array which \emph{is} vectorizable. In addition to the co-ordinates, a corresponding gather operation using the same neighbour list operates on the electric charge and potential parameter arrays. The corresponding temporary arrays are also accessed in the inner loop over neighbour sites with a single array subscript. Finally the computed forces are added to the main site force arrays using a \emph{scatter} operation, inverse to the gather. Although this algorithm was designed for vector machines, it is also highly efficient on modern RISC processors which universally employ a cache-based memory architecture. Since adjacent iterations of the inner loop access adjacent locations in memory, loading a cache line will bring the operands of the next few iterations into cache. Otherwise a (very slow) cache load would be necessary on every loop iteration. The link cell functions are all in \Fname{force.c} (figure~\ref{fig:link-cell}). The outer-level function is \Lit{force\_calc()}. Function \Lit{neighbour\_list()} constructs a list of subcells within the cutoff radius of a reference cell. By adding an offset and applying periodic boundary conditions this list yields the neighbour cells of \emph{any} subcell. This should not be confused with the neighbour \emph{sites} list above. In fact the list contains only a hemisphere of cells since Newton's third law is exploited to halve the computational cost. A more rigorous list may be computed instead by \Lit{strict\_neighbour\_list()} which is selected in strict cutoff mode (see section~\ref{sec:strict-cutoff}). Next an array of potential parameters called \Lit{potp} is constructed. This has an innermost dimension of the number of sites, which maps one-to-one onto the co-ordinates array. It will be used as the argument of the gather operation using the site neighbour list. Function \Lit{fill\_cells()} constructs the linked list of molecules in each subcell. The loops over cells are all contained in \Lit{force\_inner()}. Within the loop over subcells the neighbour list of \emph{sites} for this cell is constructed from the list of neighbour \emph{cells} by \Lit{site\_neighbour\_list()}. This list is then used as the index array to gather the co-ordinates, charges, potential parameters and any periodic boundary vectors. The innermost loops compute the site pair distances, the potential and the forces on the neighbour list sites. The actual potential and scalar-force evaluation is delegated to function \Lit{kernel()} for ease of comprehension and modification. This takes as its arguments an array of squared pair distances and corresponding arrays of potential parameters and site charges and returns the potential energy and an array containing the scalar part of the force, $\phi'(r_{ij})/r_{ij}$. The structure of \Lit{kernel()} is designed to evaluate all the different kinds of potential functions (see section~\ref{sec:potentials}) as efficiently as possible. It contains separate versions of a vector loop for each distinct potential type, both with and without electrostatic charges. For the charged case, the complementary error function is approximated to an accuracy of approximately 1 part in $10^{-6}$ by the formula given in Abramowitz and Stegun\cite[section 7.1.26]{abramowitz:70}. Pair distances for the calculation of radial distribution functions are evaluated by \Lit{rdf\_inner()} whose structure resembles a simplified \Lit{force\_inner()}. It does not call \Lit{kernel()} or compute forces but instead calls \Lit{rdf\_accum()} which bins the computed pair distances. The separate function allows the use of a larger cutoff than for the force and potential evaluation. The reciprocal-space part of the Ewald sum is evaluated in function \Lit{ewald()}, shown in figure~\ref{fig:ewald}. This is a fairly straightforward implementation of the \emph{k}-space terms of equations~\ref{eqn:ewald}, \ref{eqn:ewald-force} and~\ref{eqn:ewald-stress}, and differs from common implementations only in the respect that it must correctly handle parallelepiped-shaped MD cells and therefore a triclinic grid of \emph{k}-vectors. A list of vectors satisfying $\bm{k} > \bm{0}$ and $|\bm{k}| < k_c$ is pre-computed to simplify the control condition of the main \emph{k}-vector loop. Again, computational efficiency dictates much of the structure of \Lit{ewald()}. The values of $\cos(\bm{k \cdot r}_i)$ and $\sin(\bm{k \cdot r}_i)$ must be computed for every site~$i$ and every vector $\bm{k} = h \bm{a}^* + k \bm{b}^* + l \bm{c}^*$ with $|\bm{k}| < k_c$. Since the cosine and sine functions are relatively expensive to evaluate, the values of $\cos(h \bm{a}^*\bm{ \cdot r}_i)$, $\cos(k \bm{b}^*\bm{ \cdot r}_i)$ \etc\ are precomputed for each site~$i$ and $h = 0, 1, \ldots h_{\textnormal{max}}$, $k = 0, 1, \ldots k_{\textnormal{max}}$ and stored in arrays of dimension \Lit{[hmax][nsites]} \etc\ Then within the loop over \emph{k}-vectors the trigonometric addition formulae are used to construct $q_i \cos(\bm{k \cdot r}_i)$ and $q_i \sin(\bm{k \cdot r}_i)$ using only arithmetic operations. That task is delegated to function \Lit{qsincos()} since certain compilers can optimize it better that way. The self-energy and charged-system terms of equations~\ref{eqn:ewald} and~\ref{eqn:ewald-stress} are also evaluated in \Lit{ewald()}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Parallelization}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% It has been predicted since the early 1980s that parallel computers would offer the very highest performance for scientific computing. That vision has been somewhat slow in coming about, in part due to the difficulty of writing programs to explicitly exploit unique and idiosyncratic architectures and the lack of portability or re-usability of the resulting code. It was often necessary to write programs in machine-specific languages~\cite{pawley:82,bowler:87}, use proprietary and obscure library calls~\cite{clementi:85} and be designed around a specific communications topology. Nevertheless molecular-dynamics simulation was one of the earliest applications of parallel computers and many simulations have been undertaken despite the difficulties~\cite{pawley:82,clementi:85,rapaport:88}. The emergence and widespread adoption of the single-program multiple-data (SPMD) programming model and the standardization of parallel communications libraries in the 1990s has much improved the situation. In this model a parallel program is treated as a set of copies of a single program executing asynchronously and independently on different processors and which communicate using library calls. The program is written in a standard language and arranged to divide the calculation among the processors in some way so that each handles a subset of the operations. The model is completed by the addition of a library of communications routines which allow the separate parts of the calculation to be assembled to give the full, desired result. A significant advance was the availability of parallel libraries such as TCGMSG~\cite{tcgmsg:94}, PVM~\cite{pvm:94}, BSP~\cite{bsp:93} and the new standard MPI~\cite{mpi:94}. Together these developments allow a program to be both parallel and sufficiently independent of architectural details to be portable to a wide range of parallel environments. These may include shared-memory and distributed-memory multiprocessors, and even networks of workstations. Of course formal portability is no guarantee of good performance on hardware with widely differing processor and communications performance. That is a function of the granularity of the problem with respect to communications latency and volume of data with respect to communications bandwidth. Both of these depend on the nature of the problem and the parallelization strategy. \subsection{Parallel Strategy} \label{sec:parstrat} \moldy\ uses the ``replicated data'' approach to parallel molecular dynamics~\cite{clementi:85,smith:91} whereby each processor maintains a complete set of dynamical variable arrays for all particles. The short-ranged and reciprocal-space force calculations are divided among the processors and a global sum operation is used to add the separate contributions to the forces and propagate a copy of the complete force array to every processor. This ``parallel'' part of the calculation dominates the execution time and shows a close to linear speed-up. It takes over 95\% of the CPU time even for quite small systems of a few hundred particles. The remainder of the calculation, in particular the integration of the equations of motion is not parallelized but is performed redundantly on every processor simultaneously.\footnote{It is essential that the particle co-ordinates are identical on every processor and remain so throughout the simulation run. Since the equations of motion are chaotic the tiniest numerical difference in the forces between processors will cause the trajectories to diverge. It is not difficult to arrange that a global sum returns results identical to the last decimal place on all processors and this is guaranteed by the BSP, and cray SHMEM implementations and strongly recommended by the MPI standard. \moldy\ relies on this behaviour to ensure that no divergence occurs. If this were not the case it would be necessary to add a step to synchronize the co-ordinates periodically. This may also be an issue for running on networks of workstations - it is assumed that the numerical properties of all the processors are identical. The equality of the separate copies of the co-ordinates is checked periodically and the simulation exits if divergence is detected.} This ``serial'' part of the code will therefore limit the parallel speedup on large numbers of processors by Amdahl's law. However this part of the computational work only grows as $N$ compared with $N^\frac{3}{2}$ for the forces calculation (see section~\ref{sec:ewald-auto}). Consequently the ``serial'' part becomes an increasingly insignificant fraction of the computation as the system size increases. Since one might reasonably expect that in practice $N$ is scaled with the number of processors the serial part does not seriously limit the parallel performance. The advantages of the replicated data strategy are firstly simplicity of programming. Most of the code is identical to the serial program which greatly eases maintenance. Secondly load-balancing is much more straightforward than with domain decomposition methods. This will be discussed below. Thirdly the communications granularity is coarse, consisting of one global summation per timestep. This makes it very suitable for loosely-coupled processors such as a workstation cluster where the communications \emph{latency} is high. Finally it is very efficient for small and medium-sized systems. The big disadvantage is that the scaling to very large numbers of processors is poor, which will eventually limit the size of system which can be simulated. This is because both the amount of memory used per processor and the total amount of data to be communicated per processor increase linearly with $N$, the number of particles in the system. However in comparison with other supercomputing applications, molecular dynamics simulation uses relatively little memory and most supercomputers can easily accommodate simulations of many thousands of particles. Though scaling to multi-million particle systems would be desirable, most practical simulations of solids or liquids can be accomplished using systems of a few tens of thousands of particles or fewer. \subsection{Implementation} Two of the design goals are that the serial and parallel versions of \moldy\ can be built from the same code, and that the code is easily portable to a number of communications libraries. The C preprocessor macro \Lit{SPMD} is used to conditionally include the parallel code. All calls to the parallel library interface are protected by conditional-compilation and if \Lit{SPMD} is undefined at compile time then the serial version is built. These calls are limited to a very few modules --- \Fname{main.c} for the parallel set-up, \Lit{do\_step()} in \Fname{accel.c} for the global summation of the forces, virial and potential energy and \Lit{message()} in \Fname{output.c} for error handling. Furthermore the communications library is not called directly, but through interface functions defined in file \Fname{parallel.c} (these are listed in section~\ref{sec:parport}). This means that only \Fname{parallel.c} need ever be modified if a port to a different communications library is needed, as the rest of the code sees a common interface. As supplied \Fname{parallel.c} contains implementations for the MPI library, the TCGMSG library, the Oxford BSP library and the Cray SHMEM library for the T3D/T3E series machines (see section~\ref{sec:spmdpar}). One of these is selected by conditional compilation of \Fname{parallel.c} with one of the preprocessor symbols \Lit{MPI}, \Lit{TCGMSG}, \Lit{BSP} or \Lit{SHMEM} defined. \subsection{Input/Output and startup} \label{sec:pario} Since each processor runs an identical copy of the program executable, steps must be taken to ensure that input and output are handled by a single processor. Otherwise a parallel run would print P copies of every line if running on P processors. Indeed there are some parallel systems on which only one processor is allowed to perform input or output. It follows that all parts of the code which perform I/O must be aware of which processor this instance is running on. This is done using a global integer variable, \Lit{ithread} which contains the index (or ``rank'') of the processor. Another variable \Lit{nthreads} contains the value of P. These are set up in function \Lit{par\_begin()} called from \Lit{main()} and passed by external linkage to every module which needs them. Processor 0 performs all input/output, which is arranged by testing \Lit{ithread} prior to any I/O call, \eg\\ \parbox{\textwidth}{% \begin{quote} \Litf if( ithread == 0 \&\& control.istep \% control.print\_interval == 0)\\ \hspace*{1cm} output(); \end{quote}}\\ which is the code in \Lit{main()} used to print the regular output. These variables are also present in the serial code, where they are harmlessly redundant. In that case \Lit{ithread} is always set to 0 and \Lit{nthreads} to 1. \Fname{Parallel.c} also contains the function \Lit{replicate()} to pass the system specification and dynamical variables from processor 0 to all of the others. This is called from \Lit{main()} after \Lit{start\_up()} has returned. It allocates memory for the system specification and dynamical variables on all other processors using the same functions as \Lit{start\_up()} itself and calls \Lit{copy\_sysdef()} and \Lit{copy\_dynamics()} to broadcast the data from processor 0 to all of the others. The function \Lit{par\_broadcast()} defined earlier in \Fname{parallel.c} calls the underlying communications library to broadcast the data globally. On exit from \Lit{replicate()} \emph{every} processor now contains a complete set of data and is ready to begin the run. Error or warning conditions are handled by function \Lit{message()} in \Fname{output.c} if called with the \Lit{FATAL} or \Lit{WARNING} flags set in its argument list. In the serial case this prints out a failure message and calls \Lit{exit()} to terminate the run. In a parallel run, an error condition may occur on just one processor or on all simultaneously depending on precisely what caused the problem. Furthermore, if just one processor is involved, it may not be the I/O processor (rank 0). The approach of printing the message only from processor 0 is inadequate since there would be no indication that something has gone wrong. But neither is it appropriate to print on all, since that would result in a multiplicity of messages in some cases. The approach taken is that \Lit{message()} always prints the error irrespective of which processor is executing it, but that calls to \Lit{message()} are made conditional on \Lit{ithread~==~0} for those conditions known to occur on all processors simultaneously. If the condition signalled was \Lit{FATAL} then \Lit{message()} finally calls \Lit{par\_abort()} which terminates the run on all processors. \subsection{Distributed forces calculation} The two parts of the forces calculation which must be parallelized are the short-ranged forces calculation and the reciprocal-space part of the Ewald sum. The outermost loop of the link cell forces calculation in function \Lit{force\_inner()} runs over all subcells within the simulation cell (see figure~\ref{fig:link-cell}). In the serial case, it has the form\\ \parbox{\textwidth}{% \begin{quote} \Litf for( icell = 0; icell < nx*ny*nz; icell++)\\ \{\\ \hspace*{1cm}\textnormal{[\emph{Evaluate forces on particles in cell} \Lit{icell}]}\\ \}. \end{quote}}\\ The iterations of this loop are distributed over processors by rewriting it as\\ \parbox{\textwidth}{% \begin{quote} \Litf for( icell = ithread; icell < nx*ny*nz; icell += nthreads)\\ \{\\ \hspace*{1cm}\textnormal{[\emph{Evaluate forces on particles in cell} \Lit{icell}]}\\ \}. \end{quote}}\\ where the integer variables \Lit{ithread} and \Lit{nthreads} contain the rank of the processor and the total number of processors respectively. Since \Lit{ithread} has a different value on each processor, the separate copies of the force arrays contain only the contributions from the set of subcells assigned to that processor. After completion of the forces calculation the individual arrays are summed in function \Lit{do\_step()}. Similar partial contributions to the potential energy and the stress are also globally summed. Provided that the number of subcells is rather greater than the number of processors and the number of particles per subcell is fairly constant, this algorithm automatically ensures that the computation is divided evenly between the processors. The reciprocal-space sum may be parallelized either by distributing the loop over \emph{k}-vectors over processors~\cite{clementi:85,smith:92} or by partitioning the particles between processors. Smith~\cite{smith:92} called the former strategy the ``reduced k-vector list'' (RKL) method and the latter the ``reduced ion list'' (RIL) method. \moldy\ contains implementations of both methods. In the RKL method, it is necessary to pre-compute a list of \emph{k}-vectors within the cutoff sphere (see figure~\ref{fig:ewald}) which is stored in the array \Lit{hkl[]}. (Each element of \Lit{hkl[]} is a struct containing the values of $h$, $k$, $l$ and the vector components of $\bm{k}$.) The loop over \emph{k}-vectors then takes the form of a single loop over this list, which is easily sliced over processors exactly as the loop over subcells above.\\ \parbox{\textwidth}{% \begin{quote} \Litf for(phkl = hkl+ithread; phkl < hkl+nhkl; phkl += nthreads)\\ \{\\ \hspace*{1cm}\textnormal{[\emph{Compute the contribution of \emph{k}-vector in} \Lit{phkl}]}\\ \}. \end{quote}}\\ At the end of this loop the force arrays contain the contributions to the force on each site from the particular set of \emph{k}-vectors handled by that processor. The total forces are obtained by globally summing these arrays over processors. In fact since the same arrays are used to store both the short-ranged and long-ranged contributions to the force then only one global sum is needed for the forces. Since the contribution at each \emph{k}-point is a sum of fixed length and takes exactly the same time to evaluate as any other, this algorithm is always optimally load-balanced. There is also an implementation of the alternative, RIL parallelization strategy in file \Fname{ewald-RIL.c}, which is a direct replacement for \Fname{ewald.c}. In this case each processor handles a subset of the particles and all \emph{k}-vectors. This involves an extra global sum within the loop over \emph{k}-vectors to evaluate the total structure-factor for each $\bm{k}$. \subsection{Radial Distribution Functions} The accumulation of distances for the radial distribution function calculation is potentially costly since it is a site-pair property. It is therefore handled using the parallel link cell method exactly as for the site forces calculation by functions \Lit{rdf\_inner()} and \Lit{rdf\_accum()}. However the contributions from different processors do \emph{not} need to be summed every time \Lit{rdf\_inner()} is called, but may be left to accumulate separately. The data is globally summed by function \Lit{par\_isum()} only when \Lit{rdf\_out()} is called to calculate and print the RDFs or just before a restart file is written. \appendix %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Example System Specifications} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:examples} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Argon}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{verbatim} # LJ Argon - about as simple as you can get # Parameters from Allen and Tildesley Table 1.1 Argon 108 1 0 0 0 39.948 0 Ar end Lennard-Jones 1 1 3.984 3.41 \end{verbatim} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{TIPS2 Water}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% This is the four-site water model of Jorgensen\cite{jorgensen:82}. Only the oxygen site interacts via the Lennard-Jones potential, and the charge site, M, is displaced 0.15\AA\ from the Oxygen. \begin{verbatim} # Modified TIPS2 water Water 64 1 0 0 0 16 0 O 2 0.7569503 0 -0.5858822 1 0.535 H 2 -0.7569503 0 -0.5858822 3 0 0 -0.15 0 -1.07 M end lennard-jones 1 1 0.51799 3.2407 end \end{verbatim} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Aqueous MgCl$_2$ Solution}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% This is a three-component system consisting of MCY water\cite{matsuoka:75}, magnesium and chloride ions. The Mg$^{2+}$ potential was fitted to the SCF calculations of Dietz and Heinzinger\cite{dietz:82} and the Cl$^-$ to the calculations of Kistenmacher, Popkie and Clementi\cite{kistenmacher:73b}. Note that the potential parameters are expressed in kcal mol$^{-1}$, and the control file must set the parameter \Lit{time-unit=4.8888213e-14}. \begin{verbatim} # MCY Water/ Mg2+ / Cl - solution Water 200 1 0 0 0 16 0 O 2 0.7569503 0 -0.5858822 1 0.717484 H 2 -0.7569503 0 -0.5858822 3 0 0 -0.2677 0 -1.434968 M Magnesium 4 4 0 0 0 24.31 2 Mg2+ Chloride 8 5 0 0 0 35.45 -1 Cl- end MCY 1 1 1088213.2 5.152712 0 0 1 2 1455.427 2.961895 273.5954 2.233264 2 2 666.3373 2.760844 0 0 1 4 47750.0 3.836 546.3 1.253 # New values of Mg potl 2 4 111.0 1.06 0 1.0 1 5 198855.0 3.910 0 0 2 5 1857.0 2.408 77.94 1.369 4 5 28325.5 2.65 0 0 end \end{verbatim} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Quartz}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{verbatim} # Quartz parameters from Van Beest, Kramer and Van Santen # Physical Review Letters 64,(16) p1955 (1990) # Units are eV, A, el chg. so time-unit=1.0181e-14 Oxygen 384 1 0 0 0 16 -1.2 O Silicon 192 2 0 0 0 28.0855 2.4 Si end buckingham 1 1 175.0000 1388.7730 2.76000 1 2 133.5381 18003.7572 4.87318 2 2 0.0 0.0 0.0 end 4.903 4.903 5.393 90 90 120 4 4 4 Oxygen 0.415000 0.272000 0.120000 Oxygen 0.857000 0.5850000 0.453300 Oxygen 0.728000 0.143000 0.453300 Oxygen 0.143000 0.728000 0.880000 Oxygen 0.272000 0.415000 0.546700 Oxygen 0.5850000 0.857000 0.213300 Silicon 0.465000 0 0 Silicon 0.535000 0.535000 0.333300 Silicon 0 0.465000 0.666700 end \end{verbatim} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Utility Programs} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Five utility programs are included in the \moldy\ package, mostly for manipulation and analysis of dump data (see section~\ref{sec:dumping}). They are easily compiled on unix systems using the makefile: the command is ``\Lit{make}~\emph{progname}'' for each program or ``\Lit{make utilities}'' to make the lot. Apart from \emph{mdshak} which must be linked with several modules from \moldy\ itself they are all self-contained in a single source file. They are written with unix systems in mind using unix-style option arguments, but ought to compile and run under VMS if defined as foreign commands. Several of them require you to specify lists of (integer) numbers, for example selected molecules, timeslices \etc, which share a common syntax for such options. The numbers 1, 5, 17 to 20 inclusive and 34,44,54\ldots94 are selected by the command-line argument \mbox{\Lit{-t 1,5,17-20,34-100:10}}. Selectors are separated by commas and each one may be a range separated by a hyphen with an optional increment following a colon. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Moldyext}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% It is usual to plot the instantaneous values of energy, temperature \etc\ during the course of a simulation, for example to monitor the approach to equilibrium. \emph{Moldyext} processes the periodic output produced by \moldy\ (see section~\ref{sec:output}) and extracts this information from each timestep recorded. It is presented in tabular form for input into plotting programs. The command is \begin{center} \Lit{moldyext -f} \textit{fields output-file1 output-file2} \ldots \end{center} where \emph{fields} is a list in the selector format above. The numbering runs from left to right, ignoring newlines and blank columns so that the translational KE's in figure~\ref{fig:output} are fields 1 and 14 and the $\sigma_{zz}$ component of the stress tensor is 30. \emph{Moldyext} can currently only extract information from the ``instantaneous'' section of the output, not the rolling averages or standard deviations. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Dumpanal}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \emph{Dumpanal} examines the dump files given as arguments and prints out the header information to help with identification. For example \begin{center} \Lit{dumpanal} \textit{dump-file1 dump-file2} \ldots \end{center} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Dumpconv}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \label{sec:dumpconv} \emph{Dumpconv} is a tool for moving binary dump files between computers of different architectures. It has mostly been superseded by the portable XDR format dump files introduced in version~2.1 (see section~\ref{sec:xdr}) but is retained in case of machines for which no XDR implementation is available. The command \begin{center} \Lit{dumpconv} \textit{binary-dump-file text-dump-file} \end{center} creates a straightforward ASCII text file with a representation of the dump information in the binary file including the header. The command \begin{center} \Lit{dumpconv -d} \textit{text-dump-file binary-dump-file} \end{center} converts it back. Seven significant decimals are used which ought to retain almost all of the precision of the single precision binary floating-point numbers. You can also convert an old ``native'' format dump into XDR format using the \Lit{-x} option, \emph{viz} \begin{center} \Lit{dumpconv -x} \textit{native-dump-file xdr-dump-file}. \end{center} The \Lit{-x} and \Lit{-d} options may be combined if the input is a text format dump. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Dumpext}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Dumps are designed so that \moldy\ can take care of all the bookkeeping, perform data security checks and to divide a lot of data into manageable portions. It is therefore not in a convenient form for reading by other programs, especially FORTRAN ones. \emph{Dumpext} is a program which processes dump files, extracts a subset of the information and outputs it in a form more suitable for reading by other programs. It is invoked with the command: \begin{center} \Lit{dumpext -R} \textit{nmols} \Lit{-Q} \textit{nquats} \Lit{-c} \textit{components} \Lit{[-t} \textit{timeslices} \Lit{]} \\ \Lit{[-m} \textit{molecules} \Lit{]} \Lit{[-o} \textit{output-file} \Lit{]} \Lit{[-b]} \textit{dump-file1 dump-file2} \ldots \end{center} The meanings of its arguments are \newcommand{\ttlabel}[1]{\Lit{#1}\hfil} \begin{list}{}{\let\makelabel\ttlabel\itemsep=0pt\parsep=3pt\leftmargin=1.5cm} \item[-R] the total number of molecules. This argument is compulsory. \item[-Q] the number of polyatomic molecules. This argument is compulsory. \item[-c] which pieces (``components'') of the information in dump record to extract. This is a selector-format list and may list any combination of \begin{enumerate} \itemsep=0pt \parskip=0pt \item C of M positions \item quaternions \item unit cell matrix \item potential energy \item C of M velocities \item quaternion derivatives \item unit cell velocities \item C of M accelerations \item quaternion accelerations \item unit cell accelerations \item C of M forces \item torques \item stress tensor \end{enumerate} This argument is compulsory. \item[-t] which timeslices (or dump records) to extract. This is a selector format list and is the index in the whole dump sequence, not just a single file. Timeslices or dump records are sequentially numbered in the dump files from 1. Defaults to all timeslices. \item[-m] extract information for selected molecules. This is a selector list specifying the molecule index. Defaults to all molecules. \item[-o] name of optional output file. Defaults to standard output. \item[-b] selects binary output in single-precision floating point numbers. Defaults to ASCII formatted numbers. \end{list} If any of the compulsory arguments are omitted, you will be prompted to supply a value. In particular you must \emph{always} supply the number of molecules and polyatomic molecules. (This information is not recorded in the dump header and is needed to determine the number of co-ordinates and quaternions in each dump record.) You must specify which pieces of information to extract using the \Lit{-c} option. The dump files must, of course, be part of the same dump sequence; this is carefully checked. They may be supplied as arguments in any order; \emph{dumpext} automatically determines the sequence from the information in the headers. This is not as pointless as it sounds, since the list may be generated using unix shell wild-cards which arrange them in alphabetical rather than numeric order. The output is arranged in columns, one line per time slice. So if, for example you wish to extract positions and quaternions there will be 7 columns corresponding to $x,y,z,q_0,q_1,q_2,q_3$. Multiple components are printed in the integer order of the component, \emph{not} the order specified with \Lit{-c}. If binary output is asked for with the \Lit{-b} option the order is the same. The numbers are written sequentially as single-precision floating-point numbers (in machine native format) without record delimiters. The records may be easily read in C with an \Lit{fread()} call with the appropriate number of bytes or from FORTRAN77 using direct-access unformatted read\footnote{The usual FORTRAN sequential unformatted read is not suitable as this expects record size information to be present. \emph{Dumpext} can not write this as its format is entirely determined by the whim of the compiler writer. FORTRAN unformatted sequential files are not guaranteed to be portable even between different compilers on the same machine.} of the appropriate length records\footnote{Be aware that the FORTRAN77 standard does not guarantee what units the record length is specified in. Predictably some manufacturers' compilers use bytes and others words. Consult the documentation!} \Lit{OPEN(\ldots,ACCESS=DIRECT,LRECL=nnn)}. In the above example there are $3 \times 4 + 4 \times 4 = 28$ bytes in each record. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Mdshak/Mdxyz}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \emph{Mdshak} was written as an interface between \moldy\ configurations and a molecular graphics program called SCHAKAL\cite{schakal:88}. It will also, optionally, write the output in XYZ form, suitable for input to the freely available viewers \emph{Xmol} and \emph{RasMol}. The output format is sufficiently transparent that it should not be hard to modify it for any other molecular graphics package, but note that the \emph{babel} package, also freely available on the Internet will convert between the XYZ file format and many others. There is also a SCHAKAL file viewer called ``read\_shak'' written by the author for use with AVS, the general purpose visualization program, and available free from the International AVS Center.\footnote{It may be obtained using anonymous ftp from \Lit{avs.ncsc.org} or by writing to The International AVS Center, PO Box 12889, 3021 Cornwallis Road, RTP, NC 27709, USA.} \emph{Mdshak} writes a SCHAKAL file containing the co-ordinates of a single or of multiple time slices during a MD run. It can read configurations from (\emph{a}) a system specification file plus lattice start, (\emph{b}) a system specification file plus dump file (\emph{c}) a restart file or (\emph{d}) a restart file plus dump file. It can be driven either interactively or using command-line arguments. If the executable file is named \Fname{mdshak} then the default output is in SCHAKAL file format. If it is renamed to \Fname{mdxyz} then the default is XYZ file format. In interactive mode you are prompted for the source of the system specification (sys-spec or restart file) and the configurational information (restart or dump file). But you must either redirect the output (using \Lit{>} on unix) or specify an output file with \Lit{-o} or the output will go to the screen! Alternatively, the command line options are \begin{center} \Lit{mdshak} \Lit{[-s} \textit{system-specification} \Lit{]|}% \Lit{[-r} \textit{restart-file} \Lit{]} \Lit{[-d} \textit{dump-file-format} \Lit{]} \Lit{[-t} \textit{dump-range} \Lit{]} \\ \Lit{[-c]} \Lit{[-x]|[-b]} \Lit{[-i} \textit{extra-text} \Lit{]} \Lit{[-o} \textit{output-file} \Lit{]} \end{center} where the meanings of the options are \begin{list}{}{\let\makelabel\ttlabel\itemsep=0pt\parsep=3pt\leftmargin=1.5cm} \item[-s] read a system specification file \item[-r] read a restart file. Only one of \Lit{-s} or \Lit{-r} may be given. \item[-c] if reading a system specification file, skip any preceding control parameter info. \item[-d] read the configurational information from a dump file. The argument is a dump prototype name containing a \Lit{printf()} format string -- see section~\ref{sec:dumping}. \item[-t] range of records in dump file, specified in ``selector'' format. \item[-i] this inserts its argument into the output file and is used to add extra SCHAKAL commands, such as BOX. \item[-x] Write an output file in XYZ format suitable for \emph{Xmol} or \emph{RasMol} \item[-b] Write the atom co-ordinates in raw binary (unformatted) format. \end{list} \emph{Mdshak} may be useful for more than just visualization purposes as it extracts atomic co-ordinates from the system specification, positions and quaternions. It is written so that only the output routine (called \Lit{schakal\_out()}) is SCHAKAL specific. This is quite short and can easily be replaced with one tailored to a different purpose. \bibliography{simulation,mypubs} \bibliographystyle{amsplain} \end{document} % LocalWords: Fndescription Litdescription erf erfc subfig superfig Refson MCY % LocalWords: Parrinello Rahman Lennard Buckingham Stardent Alliant cray XMP % LocalWords: MFlop SGI SP Tildesley Pawley Powles Sonnenschein Rodger Nos co % LocalWords: Fincham Beeman's Perram Tildesley's subcells subcell Heyes % LocalWords: Rahman's RDF dat const Matsuoka Clementi Yoshimine MDBACKUP KE % LocalWords: Microsystems RDFs Leuuw Coulombic Leeuw unix DUSE TCGMSG BSP MPI % LocalWords: SPMD SHMEM defs struct structs auxil beeman ewald eigens rdf xdr % LocalWords: quaterns sysdef init potpar thermalise conv Abramowitz Stegun kJ % LocalWords: PVM accel ithread nthreads istep icell icell Moldyext KE's AVS % LocalWords: Dumpanal Dumpconv dumpconv SCHAKAL Quentrec nsteps rtmass mol ps % LocalWords: amu MPa nbins ndumps Debye MDDUMP dumpanal stdlib stddef LIBS mt % LocalWords: aalloc alloc arralloc talloc tfree nspecies nsites nmols NPOTP % LocalWords: algorith ansi pre $EOD $! $CREATE moldy.bbl $DECK \providecommand{\bysame}{\leavevmode\hbox to3em{\hrulefill}\thinspace} \begin{thebibliography}{10} \bibitem{abramowitz:70} M.~Abramowitz and I.~A. Stegun, \emph{Handbook of mathematical functions}, Dover, New York, 1970. \bibitem{allen:87} M.~P. Allen and D.~J. Tildesley, \emph{Computer simulation of liquids}, Clarendon Press, Oxford, 1987. \bibitem{beeman:76} D.~Beeman, \emph{Some multistep methods for use in molecular dynamics calculations}, Journal of Computational Physics \textbf{20} (1976), 130--139. \bibitem{berthaut:52} F.~Berthaut, \emph{L'\'{e}nergie \'{e}lectrostatique de r\`{e}seaux ioniques}, J. Phys. Radium \textbf{13} (1952), 499--505. \bibitem{bowler:87} K.~C. Bowler, R.~D. Kennaway, G.~S. Pawley, and D.~Roweth, \emph{An introduction to {OCCAM-2} programming}, Chartwell-Bratt, 1987. \bibitem{cho:92} K.~Cho and J.~D. Joannopoulos, \emph{Ergodicity and dynamical properties of constant-temperature molecular dynamics}, Physical Review A \textbf{45} (1992), no.~10, 7089--7097. \bibitem{cho:93} K.~Cho, J.~D. Joannopoulos, and L.~Kleinman, \emph{Constant-temperature molecular dynamics with momentum conservation}, Physical Review E \textbf{47} (1993), no.~5, 3145--3151. \bibitem{clementi:85} E.~Clementi, G.~Corongiu, and J.~H. Detrich, \emph{Parallelism in computations in quantum and statistical mechanics}, Computer Physics Communications \textbf{37} (1985), 287--294. \bibitem{dietz:82} W.~Deitz, W.~O. Riede, and K.~Heinzinger, \emph{Molecular dynamics simulation of an aqueous {M}g{C}l$_2$ solution}, Z. Naturforsch \textbf{37a} (1982), 1038--1048. \bibitem{evans:77} D.~J. Evans, \emph{On the representation of orientation space}, Molecular Physics \textbf{34} (1977), no.~2, 317--325. \bibitem{evans:77b} D.~J. Evans and S.~Murad, \emph{Singularity free algorithm for molecular dynamics simulation of rigid polyatomics}, Molecular Physics \textbf{34} (1977), no.~2, 327--331. \bibitem{fincham:81} D.~Fincham, \emph{Rotational verlet}, Information Quarterly - {CCP5} \textbf{5} (1981), 6. \bibitem{fincham:94} D.~Fincham, \emph{Optimization of the {E}wald sum for large systems}, Molecular Simulation \textbf{13} (1994), no.~1, 1--9. \bibitem{mpi:94} Message Passing~Interface Forum, \emph{{MPI}: A message-passing interface standard}, International Journal of Supercomputer Applications \textbf{8} (1994), no.~3-4, 165. \bibitem{pvm:94} Al~Geist, Adam Beguelin, Jack Dongarra, Weicheng Jiang, Robert Manchek, and Vaidy Sunderam, \emph{{PVM}: Parallel virtual machines, a user's guide and tutorial for networked parallel computing}, MIT Press, Cambridge, {MA}, 1994. \bibitem{goldstein:80} H.~Goldstein, \emph{Classical mechanics}, 2nd ed., Addison--Wesley, Reading, MA, 1980. \bibitem{hansen:86} J.~P. Hansen and I.~R. McDonald, \emph{Theory of simple liquids}, 2nd ed., Academic Press, London, 1986. \bibitem{tcgmsg:94} Robert~J. Harrison, \emph{Tcgmsg send/receive subroutines}, Battelle Pacific Northwest Laboratory, 1994, Available by internet ftp from url ftp://ftp.tcg.anl.gov/pub/tcgmst/tcgmsg-4.04.tar.Z. \bibitem{heyes:87} D.~M. Heyes, \emph{Large numbers of particles on the {C}ray-1}, Information Quarterly - {CCP5} \textbf{25} (1987), 57--61. \bibitem{hoover:85} W.~G. Hoover, \emph{Canonical dynamics: equilibrium phase-space distributions}, Physical Review A \textbf{31} (1985), 1695--1697. \bibitem{sunxdr} Sun~Microsystems Inc, \emph{External data representation: Protocol specification}, Tech. Report RFC1014, 1987. \bibitem{jorgensen:82} W.~L. Jorgensen, \emph{Revised {TIPS} model for simulations of liquid water and aqueous solutions}, Journal of Chemical Physics \textbf{77} (1982), 4156--63. \bibitem{schakal:88} E.~Keller, \emph{Neues von {SCHAKAL}}, Chemie in unserer Zeit \textbf{20} (1986), no.~6, 178--181. \bibitem{kernighan:78} B.~W. Kernighan and D.~Ritchie, \emph{The {C} programming language}, 1st ed., Prentice Hall, Cambridge, 1978. \bibitem{kernighan:88} \bysame, \emph{The {C} programming language}, second ed., Prentice Hall, Cambridge, 1988. \bibitem{kistenmacher:73b} H.~Kistenmacher, H.~Popkie, and E.~Clementi, \emph{Study of the structure of molecular complexes {III}. {E}nergy surface of a water molecule in the field of a fluorine or chlorine anion.}, Journal of Chemical Physics \textbf{58} (1973), no.~4, 5842. \bibitem{knuth:73a} Donald~E. Knuth, Fundamental Algorithms, The Art of Computer Programming, vol.~1, section 1.2, The Art of Computer Programming, Addison-Wesley, second ed., 1973. \bibitem{laakonsen:85} A.~Laakonsen, \emph{Computer simulation package for liquids and solids with polar interactions. {I}. {McMOLDYN/H2O}: aqueous systems}, Internal Report KGN-41, IBM Corporation, Kingston, N.Y.12401, USA, 1985. \bibitem{deleeuw:80} S.~W.~De Leeuw, J.~W. Perram, and E.~R. Smith, \emph{Simulation or electrostatic systems in periodic boundary conditions. {I} {L}attice sums and dielectric constant}, Proceedings of the Royal Society \textbf{A373} (1980), 27--56. \bibitem{matsuoka:75} O.~Matsuoka, E.~Clementi, and M.~Yoshimine, \emph{{CI} study of the water dimer potential surface}, Journal of Chemical Physics \textbf{64} (1976), no.~4, 1351--1361. \bibitem{bsp:93} Richard Miller, \emph{A library for bulk-synchronous parallel computing}, Parallel Processing Specialist Group workshop on General Purpose Parallel Computing, British Computer Society, 1993. \bibitem{nose:84} S.~Nos{\'e}, \emph{A molecular dynamics method for simulations in the canonical ensemble}, Molecular Physics \textbf{52} (1984), 255--268. \bibitem{nose:91} \bysame, \emph{Molecular dynamics simulations at constant temperature and pressure}, Computer Simulation in Materials Science (M.~Meyer and V.~Pontikis, eds.), vol. E205, Kluwer, Dordrecht, 1991, NATO ASI, pp.~21--42. \bibitem{nose:83} S.~Nos\'{e} and M.~L. Klein, \emph{Constant pressure molecular dynamics for molecular systems}, Molecular Physics \textbf{50(5)} (1983), 1055--1076. \bibitem{parrinello:81} M.~Parrinello and A.~Rahman, \emph{Polymorphic transitions in single crystals: {A} new molecular dynamics method}, Journal of Applied Physics \textbf{52} (1981), no.~12, 7182--7190. \bibitem{pawley:81} G.~S. Pawley, \emph{Molecular dynamics simulation of the plastic phase; a model for {SF}$_6$}, Molecular Physics \textbf{43} (1981), no.~6, 1321--1330. \bibitem{pawley:82} \bysame, \emph{Computer simulation of the plastic-to-crystalline phase transition in {SF}6}, Physical Review Letters \textbf{48} (1982), 410--413. \bibitem{pawley:85b} G.~S. Pawley and M.~T. Dove, \emph{Quaternion-based reorientation conditions for molecular dynamics analyses}, Molecular Physics \textbf{55} (1985), no.~5, 1147--1157. \bibitem{powles:79} J.~G. Powles, W.~A.~B. Evans, E.~McGrath, K.~E. Gubbins, and S.~Murad, \emph{A computer simulation for a simple model of liquid hydrogen chloride}, Molecular Physics \textbf{38} (1979), 893--908. \bibitem{press:92C} William~H. Press, Saul~A. Teukolsky, William~T. Vetterling, and Brian~P. Flannery, \emph{Numerical recipes in {C} the art of scientific computing}, 2nd ed., Cambridge University Press, 1992. \bibitem{quentrec:75} B.~Quentrec and C.~Brot, \emph{New methods for searching for neighbours in molecular dynamics computations}, Journal of Computational Physics \textbf{13} (1975), 430--432. \bibitem{rapaport:88} D.C. Rapaport, \emph{Large-scale molecular-dynamics simulation using vector and parallel computers}, Computer Physics Reports \textbf{9} (1988), no.~1, 1--53. \bibitem{refson:85} K.~Refson, \emph{Molecular dynamics simulation of solid {\em n}-butane}, Physica \textbf{131B} (1985), 256--266. \bibitem{refson:87a} K.~Refson and G.~S. Pawley, \emph{Molecular dynamics studies of the condensed phases of {\em n}-butane and their transitions, {I} {T}echniques and model results}, Molecular Physics \textbf{61} (1987), no.~3, 669--692. \bibitem{rodger:89} P.~M. Rodger, \emph{On the accuracy of some common molecular dynamics algorithms}, Molecular Simulations \textbf{3} (1989), 263--269. \bibitem{smith:91} W.~Smith, \emph{Molecular dynamics on hypercube parallel computers}, Computer Physics Communications \textbf{62} (1991), 229--248. \bibitem{smith:92} \bysame, \emph{A replicated-data molecular dynamics strategy for the parallel {E}wald sum}, Computer Physics Communications \textbf{67} (1992), 392--406. \bibitem{smith:82} W.~Smith and D.~Fincham, \emph{The program {MDMPOL}}, SERC, Daresbury Laboratory, 1982, CCP5 Program Library. \bibitem{sonnenschein:85} R.~Sonnenschein, \emph{An improved algorithm for molecular dynamics simulation of rigid molecules}, Journal of Computational Physics \textbf{59} (1985), no.~2, 347--350. \bibitem{duval:64} P.~Du Val, \emph{Homographies, quaternions and rotations}, Oxford Mathematical Monograph, 1964. \bibitem{verlet:67} L.~Verlet, \emph{Computer `experiments' on classical fluids. {I}. thermodynamical properties of lennard-jones molecules}, Physical Review \textbf{165} (1967), 201--214. \end{thebibliography} $EOD $! $CREATE fig_arralloc.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_arralloc.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(8719,5131)(566,-4744) \put(883,-4250){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\ttdefault}{\mddefault}{\updefault}r}}} \put(2526,-4210){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\ttdefault}{\mddefault}{\updefault}r[i]}}} \put(6545,-4189){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\ttdefault}{\mddefault}{\updefault}r[i][j]}}} \put(953,-4699){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\familydefault}{\mddefault}{\updefault}(pointer)}}} \put(2770,-4699){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\familydefault}{\mddefault}{\updefault}(array of \textit{m} pointers)}}} \put(6959,-4699){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\familydefault}{\mddefault}{\updefault}(\textit{m} arrays of \textit{n} data objects)}}} \put(5023,255){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}1}}} \put(5570,255){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}2}}} \put(7945,255){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}n-2}}} \put(9285,-354){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}0}}} \put(9285,-902){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}1}}} \put(9224,-2606){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}m-2}}} \put(4414,255){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}0}}} \put(7336,255){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}n-3}}} \put(8615,255){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}n-1}}} \put(9224,-3215){\makebox(0,0)[lb]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}m-1}}} \end{picture} $EOD $! $CREATE fig_dostep-a.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_dostep-a.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(10599,10570)(214,-9944) \put(8551,-106){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Calculation of molecular}}} \put(8551,-309){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}centre-of-mass forces}}} \put(8551,-512){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}and torques.}}} \put(1801,-691){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}first call?}}} \put(1171,-1636){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Allocate arrays}}} \put(1171,-1839){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}for sites and}}} \put(1171,-2042){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}site forces}}} \put(1171,-2806){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Set up array of}}} \put(1171,-3009){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}site charges}}} \put(1801,-3931){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}step\_1()}}} \put(3286,-511){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc. distant}}} \put(3286,-691){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}pot'l \& pressure}}} \put(3286,-871){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}correction}}} \put(1801,-5281){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}make\_sites()}}} \put(1801,-5461){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc. site co-ords.}}} \put(4051,-7531){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}ewald()}}} \put(4051,-7756){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}recip-space forces}}} \put(2701,-7486){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1576,-8161){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1576,-1186){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(2701,-511){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1801,-6421){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_calc()}}} \put(1801,-7681){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}coulomb forces?}}} \put(1801,-8716){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}surface-dipole}}} \put(8329,-5913){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(7204,-6580){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(7429,-9647){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}} \put(9676,-1321){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}mol\_torque()}}} \put(7471,-4606){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}newton()}}} \put(7426,-181){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}mol\_force()}}} \put(7436,-1261){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}any}}} \put(7436,-1464){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}polyatomics?}}} \put(6746,-2544){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}molecular virial}}} \put(6746,-2747){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}correction term.}}} \put(6751,-3639){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}last timestep in}}} \put(6751,-3842){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}"old" arrays etc.}}} \put(8326,-1186){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(7201,-1861){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(9676,-7066){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rahman()}}} \put(9676,-8206){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}} \put(1801,-4118){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Apply Beeman steps \textit{i, ii} to}}} \put(2978,-5213){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(b)}}} \put(1801,-6624){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}real-space forces}}} \put(1801,-7479){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}need}}} \put(1801,-8882){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}switch on?}}} \put(3241,-8859){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}forces \& energy.}}} \put(3241,-8656){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get surf. dipole}}} \put(8409,-52){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(c)}}} \put(7421,-368){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get C of M forces.}}} \put(9679,-1516){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get torques.}}} \put(6751,-3436){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Store acc's from}}} \put(6746,-2341){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get atomic,}}} \put(7421,-6093){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Const stress?}}} \put(6311,-5700){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(d)}}} \put(7429,-4810){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}New C of M acc's}}} \put(676,-3670){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(a)}}} \put(9676,-8405){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Step cell velocities}}} \put(9671,-7254){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get unit cell acc's}}} \put(3166,-5221){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Calculation of atomic}}} \put(3166,-5424){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}site forces and}}} \put(3166,-5627){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}potential energy.}}} \put(1801,-4284){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}update dynamic variables}}} \put(1801,315){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}do\_step()}}} \put(2701,-8626){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1576,-9278){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(9676,-5971){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}energy\_dyad()}}} \put(9661,-6166){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} kinetic stress term}}} \end{picture} $EOD $! $CREATE fig_dostep-b.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_dostep-b.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(10449,10378)(364,-9752) \put(7951,-4126){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(f)}}} \put(8201,-4303){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}derivatives using Beeman}}} \put(8201,-4144){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Iteratively update quatern}}} \put(8201,-4454){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}step \emph{iv}.}}} \put(2806,-5821){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(e)}}} \put(3006,-5816){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Iteratative loop to step}}} \put(3011,-5976){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}C of M velocities using}}} \put(3011,-6120){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Beeman step \emph{iv}.}}} \put(2041,-9436){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(2731,-8821){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(7197,-278){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Thermostat ?}}} \put(6050,-60){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}None}}} \put(7415,-792){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gaussian}}} \put(8239, 37){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Nose-Hoover}}} \put(7180,-1338){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}gtherm()}}} \put(8155,-5840){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(7216,-4703){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}} \put(7193,-3608){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}euler()}}} \put(7231,-2528){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}hoover\_rot()}}} \put(7430,-6410){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(7216,-7100){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}step\_2()}}} \put(7201,-9560){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}} \put(9440,-1336){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}} \put(9440,-88){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}nhtherm()}}} \put(9451,-1576){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Predict N-H $\zeta$}}} \put(9436,-331){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get N-H $\dot{\zeta}$}}} \put(7186,-1591){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc. gaussian $\zeta$}}} \put(7195,-5803){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}quatern}}} \put(7195,-6092){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}converged?}}} \put(7195,-5945){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}derivatives}}} \put(7206,-7271){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Apply Beeman step \textit{iv} to}}} \put(7216,-7443){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}dynamic var derivatives}}} \put(7201,-4881){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}step quatern derivs}}} \put(7196,-2706){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get torque corr.}}} \put(7201,-3801){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc angular accs}}} \put(7186,-8596){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump\_interval}}} \put(7185,-8429){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}every}}} \put(7186,-8764){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}steps}}} \put(8296,-6811){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(g)}}} \put(9455,-8422){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump()}}} \put(9432,-8585){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}write trajectories,}}} \put(9432,-8747){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}forces \emph{etc.}}}} \put(1801,134){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}} \put(901,-646){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(2033,-1314){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1801,-719){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}const-stress}}} \put(1801,-883){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}or thermostat?}}} \put(1801,-2116){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}simulation?}}} \put(1808,-3209){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Thermostat ?}}} \put(661,-2991){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}None}}} \put(2026,-3723){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gaussian}}} \put(2850,-2894){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Nose-Hoover}}} \put(4051,-3064){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}nhtherm()}}} \put(1811,-5394){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}hoover\_tr()}}} \put(1791,-4269){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}gtherm()}}} \put(4051,-4317){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}} \put(1786,-6554){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}} \put(1816,-7858){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}converged?}}} \put(1816,-7681){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}velocities}}} \put(2716,-7621){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1801,-1938){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Const stress}}} \put(4061,-1858){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}parinello()}}} \put(4051,-3286){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get N-H $\dot{\zeta}$}}} \put(4066,-4524){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Step N-H $\zeta$}}} \put(1801,-4546){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get gaussian $\zeta$}}} \put(4056,-2081){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Get P\&R acc corr.}}} \put(1786,-6766){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}step C of M vels}}} \put(1801,-5626){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc N-H acc corr.}}} \put(1954,-8243){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1801,-8851){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}any}}} \put(1801,-9006){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}polyatomics?}}} \end{picture} $EOD $! $CREATE fig_ewald.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_ewald.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(4794,9250)(160,-8624) \put(736,-2310){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Set up $\sin \mathbf{k \cdot r}_i$ and }}} \put(736,-2477){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$\cos\mathbf{k \cdot r}_i$ arrays for}}} \put(736,-2664){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$\mathbf{k}=\mathbf{0}, \mathbf{a}^*, \mathbf{b}^*, \mathbf{c}^*$}}} \put(736,-3401){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$\mathbf{k}= h\mathbf{a}^*, k\mathbf{b}^*, l\mathbf{c}^*$}}} \put(736,-3212){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Get $\sin$, $\cos \mathbf{k \cdot r}_i $ for}}} \put(736,-3568){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}using recursion}}} \put(736,-4967){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Calc. pre-factors}}} \put(736,-5134){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}for energy, force}}} \put(1576,-6111){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}for this $\mathbf{k}$ and all sites $i$}}} \put(1576,-5879){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Evaluate $\sin$ and $\cos \mathbf{k \cdot r}_i$}}} \put(1576,-5670){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}qsincos()}}} \put(736,-6941){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}and energy term}}} \put(736,-6767){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Eval. struct. factor}}} \put(736,-7441){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Eval. forces on all}}} \put(736,-7608){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}sites \& add to total}}} \put(1561,329){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}ewald()}}} \put(3277,-619){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}terms}}} \put(3277,-278){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Calculate self-}}} \put(3277,-453){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}and sheet-energy }}} \put(1576,-457){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}first call?}}} \put(1576,-4350){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}\emph{k}-vectors}}} \put(1576,-4168){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}loop over}}} \put(736,-1391){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Precompute list of}}} \put(736,-1580){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$h,k,l$ for \emph{k}-vectors}}} \put(736,-1769){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}within cutoff}}} \put(1561,-8431){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}} \end{picture} $EOD $! $CREATE fig_link-cell.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_link-cell.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(9933,11049)(664,-10648) \put(8320,-6348){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(7442,-6963){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1486,-7966){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_inner()}}} \put(1486,-9121){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}} \put(7254,-10442){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}} \put(7254,-7307){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}kernel()}}} \put(7314,-1538){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}site\_neighbour\_list()}}} \put(9745,-6536){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Print warning.}}} \put(7284,-7789){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}on neighbour list.}}} \put(7329,-6586){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}site approaches}}} \put(7314,-6421){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}test for close}}} \put(7314,-3676){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}loop over}}} \put(7329,-2026){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}range of current cell.}}} \put(7329,-1778){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Build list of all sites within}}} \put(7366,-661){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}loop- over all cells}}} \put(6189,-9304){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Distribute neighbour list}}} \put(6189,-8659){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}on sites in neighbour list.}}} \put(6101,-3013){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}vectors into neighbour lists}}} \put(6101,-2788){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gather site co-ords reloc,}}} \put(6123,-4588){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gather potential params}}} \put(6123,-4858){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}into neighbour list arrays.}}} \put(6114,-5503){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calculate squared pair site}}} \put(6114,-5728){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}distances in neighbour list.}}} \put(7284,-7549){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Evaluate potential \& force}}} \put(6189,-8434){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calculate stress \& forces}}} \put(6189,-9529){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}forces onto force array.}}} \put(901,-2326){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Create list of neighbouring cells.}}} \put(1441,104){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force()}}} \put(2926,-2881){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}neighbour\_list()}}} \put(2251,-766){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1621,-1756){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(3466,-721){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Set up arrays of}}} \put(3496,-946){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}P.B.C. relocation}}} \put(3181,-1171){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}vectors.}}} \put(3001,-4045){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}site\_neighbour\_list()}}} \put(1432,-4108){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1456,-2764){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(751,-5041){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Allocate and fill}}} \put(751,-5491){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}of pot'l params.}}} \put(751,-5266){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}expanded array}}} \put(1491,-6426){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}fill\_cells()}}} \put(1491,-6626){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Build linked list }}} \put(1486,-6816){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}of mols in cells}}} \put(1577,-3481){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}strict cutoff?}}} \put(7299,-4006){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}in cell}}} \put(7299,-3833){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}molecules and sites}}} \put(1464,-1316){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}changed.}}} \put(1434,-1091){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} cell size/shape}}} \put(1464,-888){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}first call or}}} \put(7329, 90){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_inner()}}} \end{picture} $EOD $! $CREATE fig_main.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_main.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(8798,10824)(218,-10197) \put(2702,-1176){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}loop}}} \put(3608,-8384){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}on}}} \put(1793,-8369){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}off}}} \put(2695,-282){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}start\_up()}}} \put(7027,-1085){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rdf\_inner()}}} \put(8122,-2741){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump()}}} \put(2695,-2097){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}do\_step()}}} \put(2700,-2987){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}values()}}} \put(2710,-4065){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}print\_interval}}} \put(2702,-4965){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}scale\_interval}}} \put(2710,-8549){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}text\_mode\_save}}} \put(5417,-2893){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump\_interval}}} \put(5410,-3892){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}output()}}} \put(5410,-4792){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rescale()}}} \put(5405,-5722){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}averages()}}} \put(5390,-6622){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}print\_rdf()}}} \put(4270,-8992){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}print\_config()}}} \put(2700,-10002){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}exit()}}} \put(1120,-9052){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}write\_restart()}}} \put(2701,-4771){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}} \put(5416,-2716){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}} \put(2701,-7486){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}} \put(2701,-3896){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}} \put(2701,-4246){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}} \put(2701,-6046){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}} \put(2701,-5146){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}} \put(2686,-5686){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}} \put(2701,-6591){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}} \put(2702,-6762){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rdf\_out}}} \put(2696,-6946){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}} \put(5431,-3061){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}} \put(5415,-6853){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}calc/print RDFs}}} \put(5400,-5048){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}scale velocities}}} \put(1125,-9234){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write save file}}} \put(5400,-5910){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}calc/print averages}}} \put(7067,-1297){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}link-cell RDF calc}}} \put(8116,-2961){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write trajectories}}} \put(4290,-9201){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write text restart}}} \put(5408,-7768){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write backup file}}} \put(2695,-3171){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}log thermo. values}}} \put(2701,-2291){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Step co-ords by \textit{dt}}}} \put(2702,-484){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}input/initialization}}} \put(5402,-4108){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}periodic write}}} \put(2700,330){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}main()}}} \put(2702,-1521){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}istep}}} \put(2702,-1355){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}over timesteps}}} \put(4982,-1160){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_calc()}}} \put(8112,-2085){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}bin pair distances}}} \put(8097,-1888){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rdf\_accum()}}} \put(2702,-5872){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}average\_interval}}} \put(2701,-7846){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}} \put(2702,-7687){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}backup\_interval}}} \put(5410,-7604){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}write\_restart()}}} \end{picture} $EOD $! $CREATE fig_skewstart.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_skewstart.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(10761,5513)(52,-4721) \end{picture} $EOD $! $CREATE fig_startup-a.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_startup-a.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(6096,10374)(438,-9748) \put(1351,-4046){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}restart?}}} \put(2246,-3886){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1131,-4686){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1351,-5346){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}exist?}}} \put(2246,-4991){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(3491,-5176){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Abort}}} \put(1131,-5636){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1346,-7081){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}backup}}} \put(1346,-7261){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}file exists?}}} \put(2251,-7026){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(2246,-8156){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1581,-7711){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1576,-8836){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(1356,-9446){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}} \put(3826,-8361){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}B}}} \put(3826,-7236){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}C}}} \put(1346,336){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}start\_up()}}} \put(616,-6086){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Create backup \&}}} \put(616,-6266){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}dump lock files}}} \put(3856,-1433){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}get saved params}}} \put(3856,-3218){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}get new params}}} \put(3833,-2347){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}to "input" units}}} \put(3818,-4163){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}to prog units}}} \put(1351,-4986){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} dump}}} \put(1351,-5166){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}/backup lockfiles}}} \put(3826,-1230){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_header()}}} \put(3826,-2123){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_control()}}} \put(3831,-3028){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_control()}}} \put(3826,-3924){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_control()}}} \put(1356,-632){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}default\_control()}}} \put(1351,-1741){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_control()}}} \put(1346,-2885){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_control()}}} \put(5626,-7466){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}} \put(5631,-8438){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}banner\_page()}}} \put(5626,-8645){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write output file}}} \put(5648,-9529){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}} \put(1351,-8309){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}restart?}}} \end{picture} $EOD $! $CREATE fig_startup-b.tex $DECK \begin{picture}(0,0)% \epsfig{file=fig_startup-b.ps}% \end{picture}% \setlength{\unitlength}{0.00057700in}% % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% \begin{picture}(10612,10829)(443,-10207) \put(2483,-3209){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}allocate\_}}} \put(2483,-3374){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dynamics()}}} \put(2476,-2353){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}initialise\_}}} \put(2476,-2518){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}sysdef()}}} \put(10134,-2543){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}allocate\_}}} \put(10134,-2708){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dynamics()}}} \put(5626,-4128){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}allocate\_}}} \put(5626,-4293){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dynamics()}}} \put(7919,-3230){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}initialise\_}}} \put(7919,-3395){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}sysdef()}}} \put(2491,164){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}} \put(5626,149){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}B}}} \put(10156,164){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}C}}} \put(2476,-9968){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}} \put(10126,-7493){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}} \put(2476,-569){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_sysdef()}}} \put(2476,-4281){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}lattice start?}}} \put(3368,-4109){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(1576,-4116){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(10126,-3511){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_averages()}}} \put(2468,-1544){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_potentials()}}} \put(2476,-7126){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_averages()}}} \put(2468,-6232){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}thermalise()}}} \put(3593,-5093){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}lattice\_start()}}} \put(1343,-5093){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}skew\_start()}}} \put(2476,-8025){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_rdf()}}} \put(2483,-8932){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_cutoffs()}}} \put(10116,-817){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_header()}}} \put(10131,-1725){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_sysdef()}}} \put(10096,-4425){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_rdf()}}} \put(10126,-5326){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_restart()}}} \put(4831,-494){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Adjust timestep-}}} \put(4831,-854){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}parameters}}} \put(4831,-674){\makebox(0,0)[lb]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}related control}}} \put(2476,-787){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from sys-spec file}}} \put(10129,-1927){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from backup}}} \put(10129,-5516){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from backup}}} \put(10148,-6291){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}convert\_averages()}}} \put(10129,-1020){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} from backup}}} \put(5611,-9968){\makebox(0,0)[b]{\smash{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}} \put(5626,-1476){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}replace}}} \put(5626,-1656){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}system spec?}}} \put(6526,-1431){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(5858,-2099){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(6526,-8618){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}} \put(5408,-9308){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}} \put(7874,-8678){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}interpolate\_}}} \put(7874,-8843){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}derivatives()}}} \put(5626,-2631){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_sysdef()}}} \put(5671,-5108){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_averages()}}} \put(5626,-6014){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_rdf()}}} \put(5633,-6907){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_restart()}}} \put(7874,-1502){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_sysdef()}}} \put(7881,-4210){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}check\_sysdef()}}} \put(7875,-1717){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from sys-spec file}}} \put(5625,-2842){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from restart file}}} \put(7882,-4437){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}abort if failed}}} \put(5625,-7107){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}dyamic vars etc.}}} \put(7881,-2485){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_potentials()}}} \put(5641,-8715){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}timestep}}} \put(5641,-8895){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}changed?}}} \put(5633,-7891){\makebox(0,0)[b]{\smash{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}convert\_averages()}}} \end{picture} $EOD $! $CREATE fig_arralloc.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_arralloc.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:09 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 378 215 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -23.0 233.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 3013 767 m 2404 767 l 2404 1984 l 3013 1984 l gs col-1 s gr % Polyline n 2404 1375 m 3013 1375 l gs col-1 s gr % Polyline n 3013 3202 m 2404 3202 l 2404 4419 l 3013 4419 l gs col-1 s gr % Polyline n 2404 3811 m 3013 3811 l gs col-1 s gr % Polyline n 577 767 m 1186 767 l 1186 1375 l 577 1375 l cp gs col-1 s gr 15.000 slw % Polyline gs clippath 2091 1011 m 2331 1071 l 2091 1131 l 2415 1131 l 2415 1011 l cp clip n 882 1071 m 2385 1071 l gs col-1 s gr gr % arrowhead n 2091 1011 m 2331 1071 l 2091 1131 l 2091 1071 l 2091 1011 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3936 1011 m 4176 1071 l 3936 1131 l 4260 1131 l 4260 1011 l cp clip n 2647 1071 m 4230 1071 l gs col-1 s gr gr % arrowhead n 3936 1011 m 4176 1071 l 3936 1131 l 3936 1071 l 3936 1011 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3936 1620 m 4176 1680 l 3936 1740 l 4260 1740 l 4260 1620 l cp clip n 2647 1680 m 4230 1680 l gs col-1 s gr gr % arrowhead n 3936 1620 m 4176 1680 l 3936 1740 l 3936 1680 l 3936 1620 l cp gs 0.00 setgray ef gr col-1 s 7.500 slw % Polyline n 3013 767 m 3013 1984 l gs col-1 s gr % Polyline n 3013 3202 m 3013 4419 l gs col-1 s gr 15.000 slw % Polyline gs clippath 3936 4055 m 4176 4115 l 3936 4175 l 4260 4175 l 4260 4055 l cp clip n 2647 4115 m 4230 4115 l gs col-1 s gr gr % arrowhead n 3936 4055 m 4176 4115 l 3936 4175 l 3936 4115 l 3936 4055 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3936 3446 m 4176 3506 l 3936 3566 l 4260 3566 l 4260 3446 l cp clip n 2647 3506 m 4230 3506 l gs col-1 s gr gr % arrowhead n 3936 3446 m 4176 3506 l 3936 3566 l 3936 3506 l 3936 3446 l cp gs 0.00 setgray ef gr col-1 s 7.500 slw % Polyline n 6057 767 m 6057 1984 l gs col-1 s gr % Polyline n 6057 3202 m 6057 4419 l gs col-1 s gr % Polyline n 9101 767 m 9101 1984 l gs col-1 s gr % Polyline n 9101 3202 m 9101 4419 l gs col-1 s gr % Polyline n 4839 3202 m 4230 3202 l 4230 4419 l 4839 4419 l gs col-1 s gr % Polyline n 4230 3811 m 4839 3811 l gs col-1 s gr % Polyline n 4839 767 m 4230 767 l 4230 1984 l 4839 1984 l gs col-1 s gr % Polyline n 4230 1375 m 4839 1375 l gs col-1 s gr % Polyline n 6057 767 m 5448 767 l 5448 1984 l 6057 1984 l gs col-1 s gr % Polyline n 5448 1375 m 6057 1375 l gs col-1 s gr % Polyline n 6057 3202 m 5448 3202 l 5448 4419 l 6057 4419 l gs col-1 s gr % Polyline n 5448 3811 m 6057 3811 l gs col-1 s gr % Polyline n 7883 767 m 7274 767 l 7274 1984 l 7883 1984 l gs col-1 s gr % Polyline n 7274 1375 m 7883 1375 l gs col-1 s gr % Polyline n 9101 767 m 8492 767 l 8492 1984 l 9101 1984 l gs col-1 s gr % Polyline n 8492 1375 m 9101 1375 l gs col-1 s gr % Polyline n 9101 3202 m 8492 3202 l 8492 4419 l 9101 4419 l gs col-1 s gr % Polyline n 8492 3811 m 9101 3811 l gs col-1 s gr % Polyline n 7883 3202 m 7274 3202 l 7274 4419 l 7883 4419 l gs col-1 s gr % Polyline n 7274 3811 m 7883 3811 l gs col-1 s gr % Polyline n 4839 1375 m 5448 1375 l gs col-1 s gr % Polyline n 5448 767 m 4839 767 l 4839 1984 l 5448 1984 l gs col-1 s gr % Polyline n 7883 1375 m 8492 1375 l gs col-1 s gr % Polyline n 8492 767 m 7883 767 l 7883 1984 l 8492 1984 l gs col-1 s gr % Polyline n 7883 3811 m 8492 3811 l gs col-1 s gr % Polyline n 8492 3202 m 7883 3202 l 7883 4419 l 8492 4419 l gs col-1 s gr % Polyline n 4839 3811 m 5448 3811 l gs col-1 s gr % Polyline n 5448 3202 m 4839 3202 l 4839 4419 l 5448 4419 l gs col-1 s gr % Polyline [15 133.3] 133.3 sd n 2404 1984 m 2404 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 3013 1984 m 3013 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 4230 1984 m 4230 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 4839 1984 m 4839 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 5448 1984 m 5448 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 1984 m 6057 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 7274 1984 m 7274 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 7883 1984 m 7883 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 8492 1984 m 8492 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 9101 1984 m 9101 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 3202 m 7274 3202 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 3811 m 7274 3811 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 4419 m 7274 4419 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 1984 m 7274 1984 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 1375 m 7274 1375 l gs col-1 s gr [] 0 sd % Polyline [15 133.3] 133.3 sd n 6057 767 m 7274 767 l gs col-1 s gr [] 0 sd $F2psEnd rs $EOD $! $CREATE fig_dostep-a.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_dostep-a.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:09 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 442 441 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -8.0 449.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /DrawSplineSection { /y3 exch def /x3 exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /xa x1 x2 x1 sub 0.666667 mul add def /ya y1 y2 y1 sub 0.666667 mul add def /xb x3 x2 x3 sub 0.666667 mul add def /yb y3 y2 y3 sub 0.666667 mul add def x1 y1 lineto xa ya xb yb x3 y3 curveto } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 1480 225 m 2155 225 l gs col-1 s gr % Polyline n 1480 675 m 2155 675 l gs col-1 s gr % Open spline gs n 1480.0 225.0 m 1255.0 225.0 l 1255.0 225.0 1030.0 225.0 1030.0 450.0 DrawSplineSection 1030.0 450.0 1030.0 675.0 1255.0 675.0 DrawSplineSection 1480.0 675.0 l gs col-1 s gr gr % Open spline gs n 2155.0 225.0 m 2380.0 225.0 l 2380.0 225.0 2605.0 225.0 2605.0 450.0 DrawSplineSection 2605.0 450.0 2605.0 675.0 2380.0 675.0 DrawSplineSection 2155.0 675.0 l gs col-1 s gr gr % Ellipse n 1800 6180 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7425 10440 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1800 7313 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7425 5535 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7425 1080 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 9682 2201 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 9682 8006 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 9682 6881 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 9682 9131 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1795 4950 1260 450 0 360 DrawEllipse gs col-1 s gr % Ellipse n 4057 8456 900 315 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 1825 956 m 1795 1076 l 1765 956 l 1765 1118 l 1825 1118 l cp clip n 1795 1103 m 1795 675 l gs col-1 s gr gr % arrowhead n 1825 956 m 1795 1076 l 1765 956 l 1795 956 l 1825 956 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 6858 m 1800 6978 l 1770 6858 l 1770 7020 l 1830 7020 l cp clip n 1800 6498 m 1800 7005 l gs col-1 s gr gr % arrowhead n 1830 6858 m 1800 6978 l 1770 6858 l 1800 6858 l 1830 6858 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 4368 m 1800 4488 l 1770 4368 l 1770 4530 l 1830 4530 l cp clip n 1800 4050 m 1800 4515 l gs col-1 s gr gr % arrowhead n 1830 4368 m 1800 4488 l 1770 4368 l 1800 4368 l 1830 4368 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 3228 m 1800 3348 l 1770 3228 l 1770 3390 l 1830 3390 l cp clip n 1800 3375 m 1800 2925 l gs col-1 s gr gr % arrowhead n 1830 3228 m 1800 3348 l 1770 3228 l 1800 3228 l 1830 3228 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 1030 2250 m 2605 2250 l 2605 2925 l 1030 2925 l cp gs col-1 s gr % Polyline n 1030 3375 m 2605 3375 l 2605 4050 l 1030 4050 l cp gs col-1 s gr % Polyline n 3150 1118 m 4725 1118 l 4725 1793 l 3150 1793 l cp gs col-1 s gr % Polyline gs clippath 1830 5718 m 1800 5838 l 1770 5718 l 1770 5880 l 1830 5880 l cp clip n 1800 5400 m 1800 5865 l gs col-1 s gr gr % arrowhead n 1830 5718 m 1800 5838 l 1770 5718 l 1800 5718 l 1830 5718 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 1800 7835 m 1800 7835 l gs col-1 s gr % Polyline gs clippath 1952 10161 m 1832 10131 l 1952 10101 l 1790 10101 l 1790 10161 l cp clip n 4055 9906 m 4055 10131 l 1805 10131 l gs col-1 s gr gr % arrowhead n 1952 10161 m 1832 10131 l 1952 10101 l 1952 10131 l 1952 10161 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 3157 9224 m 4732 9224 l 4732 9899 l 3157 9899 l cp gs col-1 s gr % Polyline gs clippath 3008 9541 m 3128 9571 l 3008 9601 l 3170 9601 l 3170 9541 l cp clip n 2700 9571 m 3155 9571 l gs col-1 s gr gr % arrowhead n 3008 9541 m 3128 9571 l 3008 9601 l 3008 9571 l 3008 9541 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7455 618 m 7425 738 l 7395 618 l 7395 780 l 7455 780 l cp clip n 1800 9930 m 1800 10575 l 5625 10575 l 5625 225 l 7425 225 l 7425 765 l gs col-1 s gr gr % arrowhead n 7455 618 m 7425 738 l 7395 618 l 7425 618 l 7455 618 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 7953 m 1800 8073 l 1770 7953 l 1770 8115 l 1830 8115 l cp clip n 1800 8100 m 1800 7632 l gs col-1 s gr gr % arrowhead n 1830 7953 m 1800 8073 l 1770 7953 l 1800 7953 l 1830 7953 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7460 6378 m 7430 6498 l 7400 6378 l 7400 6540 l 7460 6540 l cp clip n 7430 5850 m 7430 6525 l gs col-1 s gr gr % arrowhead n 7460 6378 m 7430 6498 l 7400 6378 l 7430 6378 l 7460 6378 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7460 9961 m 7430 10081 l 7400 9961 l 7400 10123 l 7460 10123 l cp clip n 7430 7252 m 7430 10108 l gs col-1 s gr gr % arrowhead n 7460 9961 m 7430 10081 l 7400 9961 l 7430 9961 l 7460 9961 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7577 9705 m 7457 9675 l 7577 9645 l 7415 9645 l 7415 9705 l cp clip n 9680 9451 m 9680 9675 l 7430 9675 l gs col-1 s gr gr % arrowhead n 7577 9705 m 7457 9675 l 7577 9645 l 7577 9675 l 7577 9705 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2995 1432 m 3115 1462 l 2995 1492 l 3157 1492 l 3157 1432 l cp clip n 2707 1462 m 3142 1462 l gs col-1 s gr gr % arrowhead n 2995 1432 m 3115 1462 l 2995 1492 l 2995 1462 l 2995 1432 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd n 6075 450 m 10800 450 l 10800 6075 l 6075 6075 l cp gs col-1 s gr [] 0 sd % Polyline gs clippath 7454 5074 m 7424 5194 l 7394 5074 l 7394 5236 l 7454 5236 l cp clip n 7424 4770 m 7424 5221 l gs col-1 s gr gr % arrowhead n 7454 5074 m 7424 5194 l 7394 5074 l 7424 5074 l 7454 5074 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 6640 2970 m 8215 2970 l 8215 3645 l 6640 3645 l cp gs col-1 s gr % Polyline n 6640 4095 m 8215 4095 l 8215 4770 l 6640 4770 l cp gs col-1 s gr % Polyline gs clippath 7455 1698 m 7425 1818 l 7395 1698 l 7395 1860 l 7455 1860 l cp clip n 7425 1395 m 7425 1845 l gs col-1 s gr gr % arrowhead n 7455 1698 m 7425 1818 l 7395 1698 l 7425 1698 l 7455 1698 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 8330 2205 m 7430 1845 l 6530 2205 l 7430 2565 l cp gs col-1 s gr % Polyline gs clippath 7460 2823 m 7430 2943 l 7400 2823 l 7400 2985 l 7460 2985 l cp clip n 7430 2565 m 7430 2970 l gs col-1 s gr gr % arrowhead n 7460 2823 m 7430 2943 l 7400 2823 l 7430 2823 l 7460 2823 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7455 3948 m 7425 4068 l 7395 3948 l 7395 4110 l 7455 4110 l cp clip n 7425 3645 m 7425 4095 l gs col-1 s gr gr % arrowhead n 7455 3948 m 7425 4068 l 7395 3948 l 7425 3948 l 7455 3948 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7582 2775 m 7462 2745 l 7582 2715 l 7420 2715 l 7420 2775 l cp clip n 9675 2520 m 9675 2745 l 7435 2745 l gs col-1 s gr gr % arrowhead n 7582 2775 m 7462 2745 l 7582 2715 l 7582 2745 l 7582 2775 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd n 225 5625 m 5175 5625 l 5175 10350 l 225 10350 l cp gs col-1 s gr [] 0 sd % Polyline gs clippath 8633 6861 m 8753 6891 l 8633 6921 l 8795 6921 l 8795 6861 l cp clip n 8335 6891 m 8780 6891 l gs col-1 s gr gr % arrowhead n 8633 6861 m 8753 6891 l 8633 6921 l 8633 6891 l 8633 6861 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 9705 7548 m 9675 7668 l 9645 7548 l 9645 7710 l 9705 7710 l cp clip n 9675 7200 m 9675 7695 l gs col-1 s gr gr % arrowhead n 9705 7548 m 9675 7668 l 9645 7548 l 9675 7548 l 9705 7548 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 9705 8673 m 9675 8793 l 9645 8673 l 9645 8835 l 9705 8835 l cp clip n 9675 8325 m 9675 8820 l gs col-1 s gr gr % arrowhead n 9705 8673 m 9675 8793 l 9645 8673 l 9675 8673 l 9705 8673 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd n 6075 6300 m 6075 9900 l 8100 9900 l 10800 9893 l 10800 6300 l cp gs col-1 s gr [] 0 sd % Polyline gs clippath 1947 2055 m 1827 2025 l 1947 1995 l 1785 1995 l 1785 2055 l cp clip n 3960 1800 m 3960 2025 l 1800 2025 l gs col-1 s gr gr % arrowhead n 1947 2055 m 1827 2025 l 1947 1995 l 1947 2025 l 1947 2055 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2695 1463 m 1795 1103 l 895 1463 l 1795 1823 l cp gs col-1 s gr % Polyline gs clippath 1824 2103 m 1794 2223 l 1764 2103 l 1764 2265 l 1824 2265 l cp clip n 1794 1823 m 1794 2250 l gs col-1 s gr gr % arrowhead n 1824 2103 m 1794 2223 l 1764 2103 l 1794 2103 l 1824 2103 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3008 8436 m 3128 8466 l 3008 8496 l 3170 8496 l 3170 8436 l cp clip n 2710 8466 m 3155 8466 l gs col-1 s gr gr % arrowhead n 3008 8436 m 3128 8466 l 3008 8496 l 3008 8466 l 3008 8436 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1952 9036 m 1832 9006 l 1952 8976 l 1790 8976 l 1790 9036 l cp clip n 4055 8776 m 4055 9006 l 1805 9006 l gs col-1 s gr gr % arrowhead n 1952 9036 m 1832 9006 l 1952 8976 l 1952 9006 l 1952 9036 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 9064 m 1800 9184 l 1770 9064 l 1770 9226 l 1830 9226 l cp clip n 1800 8826 m 1800 9211 l gs col-1 s gr gr % arrowhead n 1830 9064 m 1800 9184 l 1770 9064 l 1800 9064 l 1830 9064 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 8460 m 1800 8100 l 900 8460 l 1800 8820 l cp gs col-1 s gr % Polyline n 2700 9569 m 1800 9209 l 900 9569 l 1800 9929 l cp gs col-1 s gr % Polyline n 8330 6885 m 7430 6525 l 6530 6885 l 7430 7245 l cp gs col-1 s gr % Polyline gs clippath 8630 2174 m 8750 2204 l 8630 2234 l 8792 2234 l 8792 2174 l cp clip n 8332 2204 m 8777 2204 l gs col-1 s gr gr % arrowhead n 8630 2174 m 8750 2204 l 8630 2234 l 8630 2204 l 8630 2174 l cp gs 0.00 setgray ef gr col-1 s $F2psEnd rs $EOD $! $CREATE fig_dostep-b.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_dostep-b.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:10 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 435 433 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -15.0 441.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /DrawSplineSection { /y3 exch def /x3 exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /xa x1 x2 x1 sub 0.666667 mul add def /ya y1 y2 y1 sub 0.666667 mul add def /xb x3 x2 x3 sub 0.666667 mul add def /yb y3 y2 y3 sub 0.666667 mul add def x1 y1 lineto xa ya xb yb x3 y3 curveto } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 6836 10129 m 7511 10129 l gs col-1 s gr % Polyline n 6836 10579 m 7511 10579 l gs col-1 s gr % Open spline gs n 6836.0 10129.0 m 6611.0 10129.0 l 6611.0 10129.0 6386.0 10129.0 6386.0 10354.0 DrawSplineSection 6386.0 10354.0 6386.0 10579.0 6611.0 10579.0 DrawSplineSection 6836.0 10579.0 l gs col-1 s gr gr % Open spline gs n 7511.0 10129.0 m 7736.0 10129.0 l 7736.0 10129.0 7961.0 10129.0 7961.0 10354.0 DrawSplineSection 7961.0 10354.0 7961.0 10579.0 7736.0 10579.0 DrawSplineSection 7511.0 10579.0 l gs col-1 s gr gr % Ellipse n 9439 2279 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 9446 1057 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7189 2279 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7189 3401 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7192 4523 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7200 8099 1260 450 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7196 5632 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 9434 9386 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1800 605 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 4050 5210 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 4057 3988 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1800 5210 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1800 6332 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1803 7454 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 4057 2786 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 1830 9258 m 1800 9378 l 1770 9258 l 1770 9420 l 1830 9420 l cp clip n 1800 8955 m 1800 9405 l gs col-1 s gr gr % arrowhead n 1830 9258 m 1800 9378 l 1770 9258 l 1800 9258 l 1830 9258 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7053 7395 m 7173 7425 l 7053 7455 l 7215 7455 l 7215 7395 l cp clip n 1804 10140 m 1804 10365 l 5865 10365 l 5865 7425 l 7200 7425 l gs col-1 s gr gr % arrowhead n 7053 7395 m 7173 7425 l 7053 7455 l 7053 7425 l 7053 7395 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1653 9194 m 1773 9224 l 1653 9254 l 1815 9254 l 1815 9194 l cp clip n 892 1620 m 375 1620 l 375 9224 l 1800 9224 l gs col-1 s gr gr % arrowhead n 1653 9194 m 1773 9224 l 1653 9254 l 1653 9224 l 1653 9194 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7224 1804 m 7194 1924 l 7164 1804 l 7164 1966 l 7224 1966 l cp clip n 7194 1439 m 7194 1951 l gs col-1 s gr gr % arrowhead n 7224 1804 m 7194 1924 l 7164 1804 l 7194 1804 l 7224 1804 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7219 2914 m 7189 3034 l 7159 2914 l 7159 3076 l 7219 3076 l cp clip n 7189 2617 m 7189 3061 l gs col-1 s gr gr % arrowhead n 7219 2914 m 7189 3034 l 7159 2914 l 7189 2914 l 7219 2914 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 9439 1389 m 9439 1968 l gs col-1 s gr % Polyline gs clippath 7341 2914 m 7221 2884 l 7341 2854 l 7179 2854 l 7179 2914 l cp clip n 9444 2611 m 9444 2884 l 7194 2884 l gs col-1 s gr gr % arrowhead n 7341 2914 m 7221 2884 l 7341 2854 l 7341 2884 l 7341 2914 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 8397 1023 m 8517 1053 l 8397 1083 l 8559 1083 l 8559 1023 l cp clip n 8099 1053 m 8544 1053 l gs col-1 s gr gr % arrowhead n 8397 1023 m 8517 1053 l 8397 1083 l 8397 1053 l 8397 1023 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7219 4039 m 7189 4159 l 7159 4039 l 7159 4201 l 7219 4201 l cp clip n 7189 3736 m 7189 4186 l gs col-1 s gr gr % arrowhead n 7219 4039 m 7189 4159 l 7159 4039 l 7189 4039 l 7219 4039 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7223 5170 m 7193 5290 l 7163 5170 l 7163 5332 l 7223 5332 l cp clip n 7193 4858 m 7193 5317 l gs col-1 s gr gr % arrowhead n 7223 5170 m 7193 5290 l 7163 5170 l 7193 5170 l 7223 5170 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7225 6245 m 7195 6365 l 7165 6245 l 7165 6407 l 7225 6407 l cp clip n 7195 5952 m 7195 6392 l gs col-1 s gr gr % arrowhead n 7225 6245 m 7195 6365 l 7165 6245 l 7195 6245 l 7225 6245 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7225 9982 m 7195 10102 l 7165 9982 l 7165 10144 l 7225 10144 l cp clip n 7195 9765 m 7195 10129 l gs col-1 s gr gr % arrowhead n 7225 9982 m 7195 10102 l 7165 9982 l 7195 9982 l 7225 9982 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7230 7502 m 7200 7622 l 7170 7502 l 7170 7664 l 7230 7664 l cp clip n 7200 7124 m 7200 7649 l gs col-1 s gr gr % arrowhead n 7230 7502 m 7200 7622 l 7170 7502 l 7200 7502 l 7230 7502 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7230 8853 m 7200 8973 l 7170 8853 l 7170 9015 l 7230 9015 l cp clip n 7200 8554 m 7200 9000 l gs col-1 s gr gr % arrowhead n 7230 8853 m 7200 8973 l 7170 8853 l 7200 8853 l 7230 8853 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7336 477 m 7216 447 l 7336 417 l 7174 417 l 7174 477 l cp clip n 8095 6760 m 10578 6760 l 10578 447 l 7189 447 l gs col-1 s gr gr % arrowhead n 7336 477 m 7216 447 l 7336 417 l 7336 447 l 7336 477 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7042 3910 m 7162 3940 l 7042 3970 l 7204 3970 l 7204 3910 l cp clip n 7189 3940 m 6060 3940 l 6060 1050 l 6289 1050 l gs col-1 s gr gr % arrowhead n 7042 3910 m 7162 3940 l 7042 3970 l 7042 3940 l 7042 3910 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 8382 9354 m 8502 9384 l 8382 9414 l 8544 9414 l 8544 9354 l cp clip n 8104 9384 m 8529 9384 l gs col-1 s gr gr % arrowhead n 8382 9354 m 8502 9384 l 8382 9414 l 8382 9384 l 8382 9354 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7341 9936 m 7221 9906 l 7341 9876 l 7179 9876 l 7179 9936 l cp clip n 9439 9706 m 9439 9906 l 7194 9906 l gs col-1 s gr gr % arrowhead n 7341 9936 m 7221 9906 l 7341 9876 l 7341 9906 l 7341 9936 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 9780 m 1800 9420 l 900 9780 l 1800 10140 l cp gs col-1 s gr % Polyline gs clippath 7220 520 m 7190 640 l 7160 520 l 7160 682 l 7220 682 l cp clip n 2700 9780 m 5625 9780 l 5625 225 l 7190 225 l 7190 667 l gs col-1 s gr gr % arrowhead n 7220 520 m 7190 640 l 7160 520 l 7190 520 l 7220 520 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 8090 1053 m 7190 667 l 6290 1053 l 7190 1439 l cp gs col-1 s gr % Polyline n 8095 6760 m 7195 6400 l 6295 6760 l 7195 7120 l cp gs col-1 s gr % Polyline n 8100 9384 m 7200 8998 l 6300 9384 l 7200 9770 l cp gs col-1 s gr % Polyline [66.7] 0 sd n 5865 330 m 10800 330 l 10800 7316 l 5865 7316 l cp gs col-1 s gr [] 0 sd % Polyline gs clippath 1947 2178 m 1826 2148 l 1947 2118 l 1785 2118 l 1785 2178 l cp clip n 2700 8589 m 5175 8589 l 5175 2150 l 1800 2148 l gs col-1 s gr gr % arrowhead n 1947 2178 m 1826 2148 l 1947 2118 l 1947 2148 l 1947 2178 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1835 3450 m 1805 3570 l 1775 3450 l 1775 3612 l 1835 3612 l cp clip n 1805 3179 m 1805 3597 l gs col-1 s gr gr % arrowhead n 1835 3450 m 1805 3570 l 1775 3450 l 1805 3450 l 1835 3450 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1952 3410 m 1832 3380 l 1952 3350 l 1790 3350 l 1790 3410 l cp clip n 4055 3122 m 4055 3380 l 1805 3380 l gs col-1 s gr gr % arrowhead n 1952 3410 m 1832 3380 l 1952 3350 l 1952 3380 l 1952 3410 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 2785 m 1800 2399 l 900 2785 l 1800 3171 l cp gs col-1 s gr % Polyline gs clippath 3008 2755 m 3128 2785 l 3008 2815 l 3170 2815 l 3170 2755 l cp clip n 2710 2785 m 3155 2785 l gs col-1 s gr gr % arrowhead n 3008 2755 m 3128 2785 l 3008 2815 l 3008 2785 l 3008 2755 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 5845 m 1800 5965 l 1770 5845 l 1770 6007 l 1830 6007 l cp clip n 1800 5548 m 1800 5992 l gs col-1 s gr gr % arrowhead n 1830 5845 m 1800 5965 l 1770 5845 l 1800 5845 l 1830 5845 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 4050 4320 m 4050 4899 l gs col-1 s gr % Polyline gs clippath 1952 5845 m 1832 5815 l 1952 5785 l 1790 5785 l 1790 5845 l cp clip n 4055 5542 m 4055 5815 l 1805 5815 l gs col-1 s gr gr % arrowhead n 1952 5845 m 1832 5815 l 1952 5785 l 1952 5815 l 1952 5845 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1653 6857 m 1773 6887 l 1653 6917 l 1815 6917 l 1815 6857 l cp clip n 1800 6887 m 675 6887 l 675 3983 l 900 3991 l gs col-1 s gr gr % arrowhead n 1653 6857 m 1773 6887 l 1653 6917 l 1653 6887 l 1653 6857 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3008 3954 m 3128 3984 l 3008 4014 l 3170 4014 l 3170 3954 l cp clip n 2710 3984 m 3155 3984 l gs col-1 s gr gr % arrowhead n 3008 3954 m 3128 3984 l 3008 4014 l 3008 3984 l 3008 3954 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 3984 m 1800 3598 l 900 3984 l 1800 4370 l cp gs col-1 s gr % Polyline gs clippath 1830 6970 m 1800 7090 l 1770 6970 l 1770 7132 l 1830 7132 l cp clip n 1800 6667 m 1800 7117 l gs col-1 s gr gr % arrowhead n 1830 6970 m 1800 7090 l 1770 6970 l 1800 6970 l 1830 6970 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 8589 m 1800 8229 l 900 8589 l 1800 8949 l cp gs col-1 s gr % Polyline gs clippath 1834 8077 m 1804 8197 l 1774 8077 l 1774 8239 l 1834 8239 l cp clip n 1804 7789 m 1804 8224 l gs col-1 s gr gr % arrowhead n 1834 8077 m 1804 8197 l 1774 8077 l 1804 8077 l 1834 8077 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 1620 m 1800 1260 l 900 1620 l 1800 1980 l cp gs col-1 s gr % Polyline gs clippath 1830 1113 m 1800 1233 l 1770 1113 l 1770 1275 l 1830 1275 l cp clip n 1800 946 m 1800 1260 l gs col-1 s gr gr % arrowhead n 1830 1113 m 1800 1233 l 1770 1113 l 1800 1113 l 1830 1113 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1830 2246 m 1800 2366 l 1770 2246 l 1770 2408 l 1830 2408 l cp clip n 1800 1982 m 1800 2393 l gs col-1 s gr gr % arrowhead n 1830 2246 m 1800 2366 l 1770 2246 l 1800 2246 l 1830 2246 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1828 4717 m 1798 4837 l 1768 4717 l 1768 4879 l 1828 4879 l cp clip n 1798 4370 m 1798 4864 l gs col-1 s gr gr % arrowhead n 1828 4717 m 1798 4837 l 1768 4717 l 1798 4717 l 1828 4717 l cp gs 0.00 setgray ef gr col-1 s % Polyline [66.7] 0 sd n 540 2040 m 5310 2040 l 5310 9135 l 540 9135 l cp gs col-1 s gr [] 0 sd $F2psEnd rs $EOD $! $CREATE fig_ewald.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_ewald.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:11 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 223 386 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -6.0 394.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /DrawSplineSection { /y3 exch def /x3 exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /xa x1 x2 x1 sub 0.666667 mul add def /ya y1 y2 y1 sub 0.666667 mul add def /xb x3 x2 x3 sub 0.666667 mul add def /yb y3 y2 y3 sub 0.666667 mul add def x1 y1 lineto xa ya xb yb x3 y3 curveto } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 675 2924 m 2475 2924 l 2475 3599 l 675 3599 l cp gs col-1 s gr % Polyline n 675 3826 m 2475 3826 l 2475 4501 l 675 4501 l cp gs col-1 s gr % Polyline n 675 5626 m 2475 5626 l 2475 6076 l 675 6076 l cp gs col-1 s gr % Ellipse n 1575 6748 1348 447 0 360 DrawEllipse gs col-1 s gr % Polyline n 675 7426 m 2475 7426 l 2475 7876 l 675 7876 l cp gs col-1 s gr % Polyline n 675 8100 m 2475 8100 l 2475 8550 l 675 8550 l cp gs col-1 s gr % Polyline n 1245 9001 m 1920 9001 l gs col-1 s gr % Polyline n 1245 9451 m 1920 9451 l gs col-1 s gr % Open spline gs n 1245.0 9001.0 m 1020.0 9001.0 l 1020.0 9001.0 795.0 9001.0 795.0 9226.0 DrawSplineSection 795.0 9226.0 795.0 9451.0 1020.0 9451.0 DrawSplineSection 1245.0 9451.0 l gs col-1 s gr gr % Open spline gs n 1920.0 9001.0 m 2145.0 9001.0 l 2145.0 9001.0 2370.0 9001.0 2370.0 9226.0 DrawSplineSection 2370.0 9226.0 2370.0 9451.0 2145.0 9451.0 DrawSplineSection 1920.0 9451.0 l gs col-1 s gr gr % Polyline n 1245 225 m 1920 225 l gs col-1 s gr % Polyline n 1245 675 m 1920 675 l gs col-1 s gr % Open spline gs n 1245.0 225.0 m 1020.0 225.0 l 1020.0 225.0 795.0 225.0 795.0 450.0 DrawSplineSection 795.0 450.0 795.0 675.0 1020.0 675.0 DrawSplineSection 1245.0 675.0 l gs col-1 s gr gr % Open spline gs n 1920.0 225.0 m 2145.0 225.0 l 2145.0 225.0 2370.0 225.0 2370.0 450.0 DrawSplineSection 2370.0 450.0 2370.0 675.0 2145.0 675.0 DrawSplineSection 1920.0 675.0 l gs col-1 s gr gr % Polyline gs clippath 1605 753 m 1575 873 l 1545 753 l 1545 915 l 1605 915 l cp clip n 1575 675 m 1575 900 l gs col-1 s gr gr % arrowhead n 1605 753 m 1575 873 l 1545 753 l 1575 753 l 1605 753 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 575 1245 m 1575 900 l 2600 1245 l 1575 1575 l cp gs col-1 s gr % Polyline n 3141 900 m 4941 900 l 4941 1575 l 3141 1575 l cp gs col-1 s gr % Polyline gs clippath 2994 1214 m 3114 1244 l 2994 1274 l 3156 1274 l 3156 1214 l cp clip n 2601 1244 m 3141 1244 l gs col-1 s gr gr % arrowhead n 2994 1214 m 3114 1244 l 2994 1274 l 2994 1244 l 2994 1214 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1731 1830 m 1611 1800 l 1731 1770 l 1569 1770 l 1569 1830 l cp clip n 4041 1575 m 4041 1800 l 1584 1800 l gs col-1 s gr gr % arrowhead n 1731 1830 m 1611 1800 l 1731 1770 l 1731 1800 l 1731 1830 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 1873 m 1575 1993 l 1545 1873 l 1545 2035 l 1605 2035 l cp clip n 1575 1570 m 1575 2020 l gs col-1 s gr gr % arrowhead n 1605 1873 m 1575 1993 l 1545 1873 l 1575 1873 l 1605 1873 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2750 5094 m 2630 5064 l 2750 5034 l 2588 5034 l 2588 5094 l cp clip n 1575 8774 m 3150 8774 l 3150 5064 l 2603 5064 l gs col-1 s gr gr % arrowhead n 2750 5094 m 2630 5064 l 2750 5034 l 2750 5064 l 2750 5094 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 7953 m 1575 8073 l 1545 7953 l 1545 8115 l 1605 8115 l cp clip n 1575 7880 m 1575 8100 l gs col-1 s gr gr % arrowhead n 1605 7953 m 1575 8073 l 1545 7953 l 1575 7953 l 1605 7953 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 8853 m 1575 8973 l 1545 8853 l 1545 9015 l 1605 9015 l cp clip n 1575 8550 m 1575 9000 l gs col-1 s gr gr % arrowhead n 1605 8853 m 1575 8973 l 1545 8853 l 1575 8853 l 1605 8853 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 7278 m 1575 7398 l 1545 7278 l 1545 7440 l 1605 7440 l cp clip n 1575 7205 m 1575 7425 l gs col-1 s gr gr % arrowhead n 1605 7278 m 1575 7398 l 1545 7278 l 1575 7278 l 1605 7278 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 6156 m 1575 6276 l 1545 6156 l 1545 6318 l 1605 6318 l cp clip n 1575 6083 m 1575 6303 l gs col-1 s gr gr % arrowhead n 1605 6156 m 1575 6276 l 1545 6156 l 1575 6156 l 1605 6156 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 5475 m 1575 5595 l 1545 5475 l 1545 5637 l 1605 5637 l cp clip n 1575 5402 m 1575 5622 l gs col-1 s gr gr % arrowhead n 1605 5475 m 1575 5595 l 1545 5475 l 1575 5475 l 1605 5475 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 4575 m 1575 4695 l 1545 4575 l 1545 4737 l 1605 4737 l cp clip n 1575 4502 m 1575 4722 l gs col-1 s gr gr % arrowhead n 1605 4575 m 1575 4695 l 1545 4575 l 1575 4575 l 1605 4575 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 575 5067 m 1575 4722 l 2600 5067 l 1575 5400 l cp gs col-1 s gr % Polyline gs clippath 1605 3675 m 1575 3795 l 1545 3675 l 1545 3837 l 1605 3837 l cp clip n 1575 3602 m 1575 3822 l gs col-1 s gr gr % arrowhead n 1605 3675 m 1575 3795 l 1545 3675 l 1575 3675 l 1605 3675 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1605 2775 m 1575 2895 l 1545 2775 l 1545 2937 l 1605 2937 l cp clip n 1575 2702 m 1575 2922 l gs col-1 s gr gr % arrowhead n 1605 2775 m 1575 2895 l 1545 2775 l 1575 2775 l 1605 2775 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 675 2020 m 2475 2020 l 2475 2695 l 675 2695 l cp gs col-1 s gr $F2psEnd rs $EOD $! $CREATE fig_link-cell.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_link-cell.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:11 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 414 460 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -27.0 478.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /DrawSplineSection { /y3 exch def /x3 exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /xa x1 x2 x1 sub 0.666667 mul add def /ya y1 y2 y1 sub 0.666667 mul add def /xb x3 x2 x3 sub 0.666667 mul add def /yb y3 y2 y3 sub 0.666667 mul add def x1 y1 lineto xa ya xb yb x3 y3 curveto } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 1125 9675 m 1800 9675 l gs col-1 s gr % Polyline n 1125 10125 m 1800 10125 l gs col-1 s gr % Open spline gs n 1125.0 9675.0 m 900.0 9675.0 l 900.0 9675.0 675.0 9675.0 675.0 9900.0 DrawSplineSection 675.0 9900.0 675.0 10125.0 900.0 10125.0 DrawSplineSection 1125.0 10125.0 l gs col-1 s gr gr % Open spline gs n 1800.0 9675.0 m 2025.0 9675.0 l 2025.0 9675.0 2250.0 9675.0 2250.0 9900.0 DrawSplineSection 2250.0 9900.0 2250.0 10125.0 2025.0 10125.0 DrawSplineSection 1800.0 10125.0 l gs col-1 s gr gr % Polyline n 6975 11025 m 7650 11025 l gs col-1 s gr % Polyline n 6975 11475 m 7650 11475 l gs col-1 s gr % Open spline gs n 6975.0 11025.0 m 6750.0 11025.0 l 6750.0 11025.0 6525.0 11025.0 6525.0 11250.0 DrawSplineSection 6525.0 11250.0 6525.0 11475.0 6750.0 11475.0 DrawSplineSection 6975.0 11475.0 l gs col-1 s gr gr % Open spline gs n 7650.0 11025.0 m 7875.0 11025.0 l 7875.0 11025.0 8100.0 11025.0 8100.0 11250.0 DrawSplineSection 8100.0 11250.0 8100.0 11475.0 7875.0 11475.0 DrawSplineSection 7650.0 11475.0 l gs col-1 s gr gr % Polyline n 6975 450 m 7650 450 l gs col-1 s gr % Polyline n 6975 900 m 7650 900 l gs col-1 s gr % Open spline gs n 6975.0 450.0 m 6750.0 450.0 l 6750.0 450.0 6525.0 450.0 6525.0 675.0 DrawSplineSection 6525.0 675.0 6525.0 900.0 6750.0 900.0 DrawSplineSection 6975.0 900.0 l gs col-1 s gr gr % Open spline gs n 7650.0 450.0 m 7875.0 450.0 l 7875.0 450.0 8100.0 450.0 8100.0 675.0 DrawSplineSection 8100.0 675.0 8100.0 900.0 7875.0 900.0 DrawSplineSection 7650.0 900.0 l gs col-1 s gr gr % Polyline n 1125 450 m 1800 450 l gs col-1 s gr % Polyline n 1125 900 m 1800 900 l gs col-1 s gr % Open spline gs n 1125.0 450.0 m 900.0 450.0 l 900.0 450.0 675.0 450.0 675.0 675.0 DrawSplineSection 675.0 675.0 675.0 900.0 900.0 900.0 DrawSplineSection 1125.0 900.0 l gs col-1 s gr gr % Open spline gs n 1800.0 450.0 m 2025.0 450.0 l 2025.0 450.0 2250.0 450.0 2250.0 675.0 DrawSplineSection 2250.0 675.0 2250.0 900.0 2025.0 900.0 DrawSplineSection 1800.0 900.0 l gs col-1 s gr gr % Ellipse n 1485 8760 810 450 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7313 2504 1380 555 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7298 8328 1230 435 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1485 7418 810 450 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2925 3675 990 225 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3015 4838 1215 270 0 360 DrawEllipse gs col-1 s gr % Polyline n 7302 4938 m 7302 4938 l gs col-1 s gr % Polyline n 10359 7697 m 10584 6887 l 9009 6887 l 8784 7697 l cp gs col-1 s gr % Polyline n 7284 10563 m 7284 10563 l gs col-1 s gr % Polyline n 6068 8988 m 8543 8988 l 8543 9663 l 6068 9663 l cp gs col-1 s gr % Polyline n 6053 9888 m 8528 9888 l 8528 10563 l 6053 10563 l cp gs col-1 s gr % Polyline n 6285 7304 m 7283 6959 l 8310 7304 l 7298 7634 l cp gs col-1 s gr % Polyline n 6053 6074 m 8528 6074 l 8528 6749 l 6053 6749 l cp gs col-1 s gr % Polyline n 6068 5159 m 8543 5159 l 8543 5834 l 6068 5834 l cp gs col-1 s gr % Polyline n 6285 4604 m 7283 4259 l 8310 4604 l 7298 4934 l cp gs col-1 s gr % Polyline n 6053 3359 m 8528 3359 l 8528 4034 l 6053 4034 l cp gs col-1 s gr % Polyline n 6285 1439 m 7283 1094 l 8310 1439 l 7298 1769 l cp gs col-1 s gr % Polyline gs clippath 1485 9513 m 1455 9633 l 1425 9513 l 1425 9675 l 1485 9675 l cp clip n 1455 9210 m 1455 9660 l gs col-1 s gr gr % arrowhead n 1485 9513 m 1455 9633 l 1425 9513 l 1455 9513 l 1485 9513 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7330 1803 m 7301 1923 l 7270 1804 l 7272 1965 l 7332 1964 l cp clip n 7299 1770 m 7302 1950 l gs col-1 s gr gr % arrowhead n 7330 1803 m 7301 1923 l 7270 1804 l 7300 1803 l 7330 1803 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7318 3212 m 7288 3332 l 7258 3212 l 7258 3374 l 7318 3374 l cp clip n 7288 3059 m 7288 3359 l gs col-1 s gr gr % arrowhead n 7318 3212 m 7288 3332 l 7258 3212 l 7288 3212 l 7318 3212 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7326 5008 m 7295 5128 l 7266 5008 l 7265 5170 l 7325 5170 l cp clip n 7296 4935 m 7295 5155 l gs col-1 s gr gr % arrowhead n 7326 5008 m 7295 5128 l 7266 5008 l 7296 5008 l 7326 5008 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7318 5923 m 7288 6043 l 7258 5923 l 7258 6085 l 7318 6085 l cp clip n 7288 5830 m 7288 6070 l gs col-1 s gr gr % arrowhead n 7318 5923 m 7288 6043 l 7258 5923 l 7288 5923 l 7318 5923 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7303 8833 m 7273 8953 l 7243 8833 l 7243 8995 l 7303 8995 l cp clip n 7273 8762 m 7273 8980 l gs col-1 s gr gr % arrowhead n 7303 8833 m 7273 8953 l 7243 8833 l 7273 8833 l 7303 8833 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7303 9744 m 7272 9864 l 7243 9744 l 7242 9906 l 7302 9906 l cp clip n 7273 9655 m 7272 9891 l gs col-1 s gr gr % arrowhead n 7303 9744 m 7272 9864 l 7243 9744 l 7273 9744 l 7303 9744 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7321 10881 m 7291 11001 l 7261 10881 l 7261 11043 l 7321 11043 l cp clip n 7291 10563 m 7291 11028 l gs col-1 s gr gr % arrowhead n 7321 10881 m 7291 11001 l 7261 10881 l 7291 10881 l 7321 10881 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 6139 1409 m 6259 1439 l 6139 1469 l 6301 1469 l 6301 1409 l cp clip n 7291 10796 m 5604 10796 l 5605 1440 l 6286 1439 l gs col-1 s gr gr % arrowhead n 6139 1409 m 6259 1439 l 6139 1469 l 6139 1439 l 6139 1409 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 6147 4574 m 6267 4604 l 6147 4634 l 6309 4634 l 6309 4574 l cp clip n 5830 10785 m 5830 4604 l 6294 4604 l gs col-1 s gr gr % arrowhead n 6147 4574 m 6267 4604 l 6147 4634 l 6147 4604 l 6147 4574 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7317 947 m 7287 1067 l 7257 947 l 7258 1109 l 7318 1109 l cp clip n 7288 1094 m 7287 909 l gs col-1 s gr gr % arrowhead n 7317 947 m 7287 1067 l 7257 947 l 7287 947 l 7317 947 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7316 4110 m 7284 4230 l 7256 4110 l 7254 4272 l 7314 4272 l cp clip n 7284 4257 m 7287 4038 l gs col-1 s gr gr % arrowhead n 7316 4110 m 7284 4230 l 7256 4110 l 7286 4110 l 7316 4110 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd gs clippath 6370 636 m 6490 666 l 6370 696 l 6532 696 l 6532 636 l cp clip n 2288 8730 m 4958 8730 l 4950 666 l 6517 666 l gs col-1 s gr gr [] 0 sd % arrowhead n 6370 636 m 6490 666 l 6370 696 l 6370 666 l 6370 636 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 8748 7274 m 8868 7304 l 8748 7334 l 8910 7334 l 8910 7274 l cp clip n 8310 7304 m 8895 7304 l gs col-1 s gr gr % arrowhead n 8748 7274 m 8868 7304 l 8748 7334 l 8748 7304 l 8748 7274 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd gs clippath 2442 8850 m 2322 8820 l 2442 8790 l 2280 8790 l 2280 8850 l cp clip n 2295 8820 m 4950 8820 l 4950 11250 l 6502 11250 l gs col-1 s gr gr [] 0 sd % arrowhead n 2442 8850 m 2322 8820 l 2442 8790 l 2442 8820 l 2442 8850 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7311 6810 m 7281 6930 l 7251 6810 l 7252 6972 l 7312 6972 l cp clip n 7282 6957 m 7281 6756 l gs col-1 s gr gr % arrowhead n 7311 6810 m 7281 6930 l 7251 6810 l 7281 6810 l 7311 6810 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7327 7749 m 7297 7869 l 7267 7749 l 7267 7911 l 7327 7911 l cp clip n 7297 7633 m 7297 7896 l gs col-1 s gr gr % arrowhead n 7327 7749 m 7297 7869 l 7267 7749 l 7297 7749 l 7327 7749 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2700 1335 m 4275 1335 l 4275 2235 l 2700 2235 l cp gs col-1 s gr % Polyline n 675 1830 m 1460 1155 l 2250 1830 l 1470 2505 l cp gs col-1 s gr % Polyline n 675 2910 m 4275 2910 l 4275 5160 l 675 5160 l cp gs col-1 s gr % Polyline n 675 5610 m 2250 5610 l 2250 6510 l 675 6510 l cp gs col-1 s gr % Polyline n 787 4281 m 1572 3816 l 2362 4281 l 1582 4729 l cp gs col-1 s gr % Polyline gs clippath 2553 1800 m 2673 1830 l 2553 1860 l 2715 1860 l 2715 1800 l cp clip n 2250 1830 m 2700 1830 l gs col-1 s gr gr % arrowhead n 2553 1800 m 2673 1830 l 2553 1860 l 2553 1830 l 2553 1800 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1632 2730 m 1512 2700 l 1632 2670 l 1470 2670 l 1470 2730 l cp clip n 3465 2235 m 3465 2700 l 1485 2700 l gs col-1 s gr gr % arrowhead n 1632 2730 m 1512 2700 l 1632 2670 l 1632 2700 l 1632 2730 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1470 5463 m 1440 5583 l 1410 5463 l 1410 5625 l 1470 5625 l cp clip n 1440 5160 m 1440 5610 l gs col-1 s gr gr % arrowhead n 1470 5463 m 1440 5583 l 1410 5463 l 1440 5463 l 1470 5463 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1803 3644 m 1923 3674 l 1803 3704 l 1965 3705 l 1965 3645 l cp clip n 1572 3816 m 1572 3672 l 1950 3675 l gs col-1 s gr gr % arrowhead n 1803 3644 m 1923 3674 l 1803 3704 l 1803 3674 l 1803 3644 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1647 4816 m 1767 4847 l 1647 4876 l 1809 4878 l 1809 4818 l cp clip n 1581 4731 m 1581 4845 l 1794 4848 l gs col-1 s gr gr % arrowhead n 1647 4816 m 1767 4847 l 1647 4876 l 1647 4846 l 1647 4816 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1497 2763 m 1467 2883 l 1437 2763 l 1437 2925 l 1497 2925 l cp clip n 1467 2505 m 1467 2910 l gs col-1 s gr gr % arrowhead n 1497 2763 m 1467 2883 l 1437 2763 l 1467 2763 l 1497 2763 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1490 1008 m 1458 1128 l 1430 1008 l 1428 1170 l 1488 1170 l cp clip n 1458 1155 m 1461 900 l gs col-1 s gr gr % arrowhead n 1490 1008 m 1458 1128 l 1430 1008 l 1460 1008 l 1490 1008 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1490 8158 m 1460 8278 l 1430 8158 l 1430 8320 l 1490 8320 l cp clip n 1460 7870 m 1460 8305 l gs col-1 s gr gr % arrowhead n 1490 8158 m 1460 8278 l 1430 8158 l 1460 8158 l 1490 8158 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1485 6813 m 1455 6933 l 1425 6813 l 1425 6975 l 1485 6975 l cp clip n 1455 6510 m 1455 6960 l gs col-1 s gr gr % arrowhead n 1485 6813 m 1455 6933 l 1425 6813 l 1455 6813 l 1485 6813 l cp gs 0.00 setgray ef gr col-1 s $F2psEnd rs $EOD $! $CREATE fig_main.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_main.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:12 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 366 451 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -9.0 459.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /DrawSplineSection { /y3 exch def /x3 exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /xa x1 x2 x1 sub 0.666667 mul add def /ya y1 y2 y1 sub 0.666667 mul add def /xb x3 x2 x3 sub 0.666667 mul add def /yb y3 y2 y3 sub 0.666667 mul add def x1 y1 lineto xa ya xb yb x3 y3 curveto } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 2340 224 m 3015 224 l gs col-1 s gr % Polyline n 2340 674 m 3015 674 l gs col-1 s gr % Open spline gs n 2340.0 224.0 m 2115.0 224.0 l 2115.0 224.0 1890.0 224.0 1890.0 449.0 DrawSplineSection 1890.0 449.0 1890.0 674.0 2115.0 674.0 DrawSplineSection 2340.0 674.0 l gs col-1 s gr gr % Open spline gs n 3015.0 224.0 m 3240.0 224.0 l 3240.0 224.0 3465.0 224.0 3465.0 449.0 DrawSplineSection 3465.0 449.0 3465.0 674.0 3240.0 674.0 DrawSplineSection 3015.0 674.0 l gs col-1 s gr gr % Polyline n 2385 10574 m 3060 10574 l gs col-1 s gr % Polyline n 2385 11024 m 3060 11024 l gs col-1 s gr % Open spline gs n 2385.0 10574.0 m 2160.0 10574.0 l 2160.0 10574.0 1935.0 10574.0 1935.0 10799.0 DrawSplineSection 1935.0 10799.0 1935.0 11024.0 2160.0 11024.0 DrawSplineSection 2385.0 11024.0 l gs col-1 s gr gr % Open spline gs n 3060.0 10574.0 m 3285.0 10574.0 l 3285.0 10574.0 3510.0 10574.0 3510.0 10799.0 DrawSplineSection 3510.0 10799.0 3510.0 11024.0 3285.0 11024.0 DrawSplineSection 3060.0 11024.0 l gs col-1 s gr gr % Ellipse n 1125 9899 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5400 7559 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5400 6659 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2700 1214 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2700 3014 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2700 3914 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 4275 9899 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5400 5737 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7052 2029 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 8087 2794 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 4937 2029 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 8107 3687 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5400 4859 900 315 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5400 8459 900 315 0 360 DrawEllipse gs col-1 s gr % Polyline n 3600 6659 m 2700 6299 l 1800 6659 l 2700 7019 l cp gs col-1 s gr % Polyline n 3600 7559 m 2700 7199 l 1800 7559 l 2700 7919 l cp gs col-1 s gr % Polyline n 3600 8460 m 2700 8100 l 1800 8460 l 2700 8820 l cp gs col-1 s gr % Polyline n 3600 9360 m 2700 9000 l 1800 9360 l 2700 9720 l cp gs col-1 s gr % Polyline gs clippath 2730 752 m 2700 872 l 2670 752 l 2670 914 l 2730 914 l cp clip n 2700 674 m 2700 899 l gs col-1 s gr gr % arrowhead n 2730 752 m 2700 872 l 2670 752 l 2700 752 l 2730 752 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 2545 m 2700 2665 l 2670 2545 l 2670 2707 l 2730 2707 l cp clip n 2700 2503 m 2700 2692 l gs col-1 s gr gr % arrowhead n 2730 2545 m 2700 2665 l 2670 2545 l 2700 2545 l 2730 2545 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 3448 m 2700 3568 l 2670 3448 l 2670 3610 l 2730 3610 l cp clip n 2700 3329 m 2700 3595 l gs col-1 s gr gr % arrowhead n 2730 3448 m 2700 3568 l 2670 3448 l 2700 3448 l 2730 3448 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 4352 m 2700 4472 l 2670 4352 l 2670 4514 l 2730 4514 l cp clip n 2700 4229 m 2700 4499 l gs col-1 s gr gr % arrowhead n 2730 4352 m 2700 4472 l 2670 4352 l 2700 4352 l 2730 4352 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 6152 m 2700 6272 l 2670 6152 l 2670 6314 l 2730 6314 l cp clip n 2700 6119 m 2700 6299 l gs col-1 s gr gr % arrowhead n 2730 6152 m 2700 6272 l 2670 6152 l 2700 6152 l 2730 6152 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 7052 m 2700 7172 l 2670 7052 l 2670 7214 l 2730 7214 l cp clip n 2700 7019 m 2700 7199 l gs col-1 s gr gr % arrowhead n 2730 7052 m 2700 7172 l 2670 7052 l 2700 7052 l 2730 7052 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 7952 m 2700 8072 l 2670 7952 l 2670 8114 l 2730 8114 l cp clip n 2700 7919 m 2700 8099 l gs col-1 s gr gr % arrowhead n 2730 7952 m 2700 8072 l 2670 7952 l 2700 7952 l 2730 7952 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 4305 9437 m 4275 9557 l 4245 9437 l 4245 9599 l 4305 9599 l cp clip n 3599 9359 m 4275 9359 l 4275 9584 l gs col-1 s gr gr % arrowhead n 4305 9437 m 4275 9557 l 4245 9437 l 4275 9437 l 4305 9437 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1641 2119 m 1762 2146 l 1643 2179 l 1805 2176 l 1803 2116 l cp clip n 2700 8850 m 1575 8850 l 1575 2151 l 1789 2146 l gs col-1 s gr gr % arrowhead n 1641 2119 m 1762 2146 l 1643 2179 l 1642 2149 l 1641 2119 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 4353 5729 m 4473 5759 l 4353 5789 l 4515 5789 l 4515 5729 l cp clip n 3600 5759 m 4500 5759 l gs col-1 s gr gr % arrowhead n 4353 5729 m 4473 5759 l 4353 5789 l 4353 5759 l 4353 5729 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 4353 6629 m 4473 6659 l 4353 6689 l 4515 6689 l 4515 6629 l cp clip n 3600 6659 m 4500 6659 l gs col-1 s gr gr % arrowhead n 4353 6629 m 4473 6659 l 4353 6689 l 4353 6659 l 4353 6629 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 4353 7529 m 4473 7559 l 4353 7589 l 4515 7589 l 4515 7529 l cp clip n 3600 7559 m 4500 7559 l gs col-1 s gr gr % arrowhead n 4353 7529 m 4473 7559 l 4353 7589 l 4353 7559 l 4353 7529 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 4353 8429 m 4473 8459 l 4353 8489 l 4515 8489 l 4515 8429 l cp clip n 3600 8459 m 4500 8459 l gs col-1 s gr gr % arrowhead n 4353 8429 m 4473 8459 l 4353 8489 l 4353 8459 l 4353 8429 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 10433 m 2700 10553 l 2670 10433 l 2670 10595 l 2730 10595 l cp clip n 2700 10350 m 2700 10580 l gs col-1 s gr gr % arrowhead n 2730 10433 m 2700 10553 l 2670 10433 l 2700 10433 l 2730 10433 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2730 8853 m 2700 8973 l 2670 8853 l 2670 9015 l 2730 9015 l cp clip n 2700 8820 m 2700 9000 l gs col-1 s gr gr % arrowhead n 2730 8853 m 2700 8973 l 2670 8853 l 2700 8853 l 2730 8853 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 4275 10214 m 4275 10350 l 2700 10350 l gs col-1 s gr % Polyline gs clippath 2862 6262 m 2742 6232 l 2862 6202 l 2700 6202 l 2700 6262 l cp clip n 2715 6232 m 5400 6232 l 5400 6052 l gs col-1 s gr gr % arrowhead n 2862 6262 m 2742 6232 l 2862 6202 l 2862 6232 l 2862 6262 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2862 7162 m 2742 7132 l 2862 7102 l 2700 7102 l 2700 7162 l cp clip n 2715 7132 m 5400 7132 l 5400 6967 l gs col-1 s gr gr % arrowhead n 2862 7162 m 2742 7132 l 2862 7102 l 2862 7132 l 2862 7162 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2862 8047 m 2742 8017 l 2862 7987 l 2700 7987 l 2700 8047 l cp clip n 2715 8017 m 5415 8017 l 5415 7882 l gs col-1 s gr gr % arrowhead n 2862 8047 m 2742 8017 l 2862 7987 l 2862 8017 l 2862 8047 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2847 8880 m 2727 8850 l 2847 8820 l 2685 8820 l 2685 8880 l cp clip n 2700 8850 m 5400 8850 l 5400 8782 l gs col-1 s gr gr % arrowhead n 2847 8880 m 2727 8850 l 2847 8820 l 2847 8850 l 2847 8880 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1155 9437 m 1125 9557 l 1095 9437 l 1095 9599 l 1155 9599 l cp clip n 1125 9584 m 1125 9359 l 1800 9359 l gs col-1 s gr gr % arrowhead n 1155 9437 m 1125 9557 l 1095 9437 l 1125 9437 l 1155 9437 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd gs clippath 3951 2144 m 4027 2046 l 4006 2169 l 4072 2020 l 4017 1996 l cp clip 3687 2889 m 3610 2986 l 3632 2864 l 3566 3013 l 3621 3037 l cp clip n 3600 3011 m 4038 2022 l gs col-1 s gr gr [] 0 sd % arrowhead n 3687 2889 m 3610 2986 l 3632 2864 l 3660 2877 l 3687 2889 l cp gs 0.00 setgray ef gr col-1 s % arrowhead n 3951 2144 m 4027 2046 l 4006 2169 l 3978 2156 l 3951 2144 l cp gs 0.00 setgray ef gr col-1 s % Polyline [100.0] 0 sd gs clippath 7640 2365 m 7707 2468 l 7599 2409 l 7718 2519 l 7758 2475 l cp clip n 7517 2292 m 7727 2487 l gs col-1 s gr gr [] 0 sd % arrowhead n 7640 2365 m 7707 2468 l 7599 2409 l 7619 2387 l 7640 2365 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7060 3657 m 7180 3687 l 7060 3717 l 7222 3717 l 7222 3657 l cp clip n 6307 3687 m 7207 3687 l gs col-1 s gr gr % arrowhead n 7060 3657 m 7180 3687 l 7060 3717 l 7060 3687 l 7060 3657 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 3600 4859 m 2700 4499 l 1800 4859 l 2700 5219 l cp gs col-1 s gr % Polyline gs clippath 4353 4829 m 4473 4859 l 4353 4889 l 4515 4889 l 4515 4829 l cp clip n 3600 4859 m 4500 4859 l gs col-1 s gr gr % arrowhead n 4353 4829 m 4473 4859 l 4353 4889 l 4353 4859 l 4353 4829 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2847 5347 m 2727 5317 l 2847 5287 l 2685 5287 l 2685 5347 l cp clip n 2700 5317 m 5400 5317 l 5400 5182 l gs col-1 s gr gr % arrowhead n 2847 5347 m 2727 5317 l 2847 5287 l 2847 5317 l 2847 5347 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 3600 2144 m 2700 1784 l 1800 2144 l 2700 2504 l cp gs col-1 s gr % Polyline gs clippath 2730 1637 m 2700 1757 l 2670 1637 l 2670 1799 l 2730 1799 l cp clip n 2700 1529 m 2700 1784 l gs col-1 s gr gr % arrowhead n 2730 1637 m 2700 1757 l 2670 1637 l 2700 1637 l 2730 1637 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 3605 5760 m 2705 5400 l 1805 5760 l 2705 6120 l cp gs col-1 s gr % Polyline gs clippath 2730 5253 m 2700 5373 l 2670 5253 l 2670 5415 l 2730 5415 l cp clip n 2700 5219 m 2700 5400 l gs col-1 s gr gr % arrowhead n 2730 5253 m 2700 5373 l 2670 5253 l 2700 5253 l 2730 5253 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 1125 10214 m 1125 10350 l 2700 10350 l gs col-1 s gr % Polyline [100.0] 0 sd gs clippath 4406 3576 m 4485 3671 l 4371 3625 l 4501 3720 l 4537 3672 l cp clip 3701 3137 m 3621 3041 l 3736 3088 l 3606 2993 l 3570 3041 l cp clip n 3600 3026 m 4507 3687 l gs col-1 s gr gr [] 0 sd % arrowhead n 3701 3137 m 3621 3041 l 3736 3088 l 3719 3113 l 3701 3137 l cp gs 0.00 setgray ef gr col-1 s % arrowhead n 4406 3576 m 4485 3671 l 4371 3625 l 4388 3600 l 4406 3576 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 6307 3687 m 5407 3327 l 4507 3687 l 5407 4047 l cp gs col-1 s gr % Polyline [100.0] 0 sd gs clippath 6005 2000 m 6125 2030 l 6005 2060 l 6167 2060 l 6167 2000 l cp clip n 5841 2030 m 6152 2030 l gs col-1 s gr gr [] 0 sd % arrowhead n 6005 2000 m 6125 2030 l 6005 2060 l 6005 2030 l 6005 2000 l cp gs 0.00 setgray ef gr col-1 s $F2psEnd rs $EOD $! $CREATE fig_skewstart.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_skewstart.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:12 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 448 231 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -2.0 232.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Ellipse n 4373 1366 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4525 1366 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 1017 2063 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 1170 2063 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 1867 1888 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 2041 1888 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5222 1235 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5375 1235 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 1061 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 1235 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6072 1061 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6246 1061 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6573 865 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6573 1039 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6878 865 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 7031 865 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 7728 690 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 7880 690 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 8578 516 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 8730 516 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 9406 342 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 9558 342 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 146 2259 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 298 2259 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 647 2085 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 647 2259 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 1475 1932 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 1475 2085 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 2346 1736 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 2346 1910 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 2695 1736 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 2847 1736 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 3152 1583 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 3152 1736 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 3523 1562 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 3675 1562 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 3959 1409 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 3959 1562 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 7358 690 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 7358 865 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 8185 538 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 8185 690 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 9035 364 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 9035 516 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 9863 189 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 9863 342 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 10277 189 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 10430 189 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4373 3196 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4525 3196 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 3043 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 3196 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5222 3043 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5375 3043 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 2891 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 3043 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6072 2869 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6246 2869 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6203 3196 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6203 3370 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5723 3370 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5876 3370 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5288 3392 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5288 3544 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4852 3544 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5004 3544 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4460 4372 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4460 4546 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4852 4372 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5004 4372 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5288 4219 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5288 4372 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5723 4198 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5876 4198 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6203 4023 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6203 4198 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 4742 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 4895 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5222 4742 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5375 4742 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 4568 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 4742 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6072 4568 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6246 4568 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4373 4895 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4525 4895 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4460 3544 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4460 3718 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4373 4045 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4525 4045 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 3893 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 4045 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5222 3893 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5375 3893 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6072 3718 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 6246 3718 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 3740 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 5658 3893 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 1235 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Ellipse n 4830 1387 87 87 0 360 DrawEllipse gs 0.00 setgray ef gr gs col-1 s gr % Polyline n 2346 80 m 2346 2259 l gs col-1 s gr % Polyline n 4460 80 m 4460 2259 l gs col-1 s gr % Polyline n 6573 80 m 6573 2259 l gs col-1 s gr % Polyline n 8687 80 m 8687 2259 l gs col-1 s gr % Polyline n 4460 4459 m 4460 4459 l gs col-1 s gr % Polyline [15 25.0] 25.0 sd n 4460 4895 m 6573 4459 l gs col-1 s gr [] 0 sd % Polyline [15 25.0] 25.0 sd n 4460 4459 m 6573 4045 l gs col-1 s gr [] 0 sd % Polyline [15 25.0] 25.0 sd n 4460 4045 m 6573 3631 l gs col-1 s gr [] 0 sd % Polyline n 6573 3196 m 7292 3043 l gs col-1 s gr % Polyline n 6573 3631 m 7379 3457 l gs col-1 s gr % Polyline n 4830 4808 m 4939 5548 l gs col-1 s gr % Polyline [15 25.0] 25.0 sd n 4460 3631 m 6573 3196 l gs 0.00 setgray ef gr gs col-1 s gr [] 0 sd % Polyline n 10800 2259 m 10800 80 l 233 80 l 233 2259 l cp gs col-1 s gr % Polyline [15 25.0] 25.0 sd n 233 2259 m 10800 59 l gs col-1 s gr [] 0 sd % Polyline n 5309 4699 m 5418 5439 l gs col-1 s gr % Polyline n 5506 5287 m 5397 5221 l 5462 5091 l gs col-1 s gr % Polyline n 4765 5221 m 4895 5309 l 4808 5461 l gs col-1 s gr % Polyline n 7009 2978 m 6922 3108 l 6813 3043 l gs col-1 s gr % Polyline n 6900 3675 m 6987 3544 l 7118 3631 l gs col-1 s gr % Polyline [15 25.0] 25.0 sd n 4460 3196 m 6573 2782 l gs 0.00 setgray ef gr gs col-1 s gr [] 0 sd % Polyline n 6573 4895 m 6573 2782 l 4460 2782 l 4460 4895 l cp gs col-1 s gr /Times-Roman ff 345.00 scf sf 6900 3392 m gs 1 -1 sc (d) col-1 sh gr /Times-Roman ff 345.00 scf sf 5070 5309 m gs 1 -1 sc (a) col-1 sh gr $F2psEnd rs $EOD $! $CREATE fig_startup-a.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_startup-a.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:13 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 254 433 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -18.0 441.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /DrawSplineSection { /y3 exch def /x3 exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /xa x1 x2 x1 sub 0.666667 mul add def /ya y1 y2 y1 sub 0.666667 mul add def /xb x3 x2 x3 sub 0.666667 mul add def /yb y3 y2 y3 sub 0.666667 mul add def x1 y1 lineto xa ya xb yb x3 y3 curveto } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Polyline n 1010 225 m 1685 225 l gs col-1 s gr % Polyline n 1010 675 m 1685 675 l gs col-1 s gr % Open spline gs n 1010.0 225.0 m 785.0 225.0 l 785.0 225.0 560.0 225.0 560.0 450.0 DrawSplineSection 560.0 450.0 560.0 675.0 785.0 675.0 DrawSplineSection 1010.0 675.0 l gs col-1 s gr gr % Open spline gs n 1685.0 225.0 m 1910.0 225.0 l 1910.0 225.0 2135.0 225.0 2135.0 450.0 DrawSplineSection 2135.0 450.0 2135.0 675.0 1910.0 675.0 DrawSplineSection 1685.0 675.0 l gs col-1 s gr gr % Polyline n 3155 5740 m 3830 5740 l gs col-1 s gr % Polyline n 3155 6190 m 3830 6190 l gs col-1 s gr % Open spline gs n 3155.0 5740.0 m 2930.0 5740.0 l 2930.0 5740.0 2705.0 5740.0 2705.0 5965.0 DrawSplineSection 2705.0 5965.0 2705.0 6190.0 2930.0 6190.0 DrawSplineSection 3155.0 6190.0 l gs col-1 s gr gr % Open spline gs n 3830.0 5740.0 m 4055.0 5740.0 l 4055.0 5740.0 4280.0 5740.0 4280.0 5965.0 DrawSplineSection 4280.0 5965.0 4280.0 6190.0 4055.0 6190.0 DrawSplineSection 3830.0 6190.0 l gs col-1 s gr gr % Ellipse n 3826 2139 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3831 3038 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3831 3938 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3831 4843 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 3861 2553 m 3831 2673 l 3801 2553 l 3801 2715 l 3861 2715 l cp clip n 3831 2474 m 3831 2700 l gs col-1 s gr gr % arrowhead n 3861 2553 m 3831 2673 l 3801 2553 l 3831 2553 l 3861 2553 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3861 3453 m 3831 3573 l 3801 3453 l 3801 3615 l 3861 3615 l cp clip n 3831 3374 m 3831 3600 l gs col-1 s gr gr % arrowhead n 3861 3453 m 3831 3573 l 3801 3453 l 3831 3453 l 3861 3453 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3861 4353 m 3831 4473 l 3801 4353 l 3801 4515 l 3861 4515 l cp clip n 3831 4274 m 3831 4500 l gs col-1 s gr gr % arrowhead n 3861 4353 m 3831 4473 l 3801 4353 l 3831 4353 l 3861 4353 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 5310 10125 m 5985 10125 l gs col-1 s gr % Polyline n 5310 10575 m 5985 10575 l gs col-1 s gr % Open spline gs n 5310.0 10125.0 m 5085.0 10125.0 l 5085.0 10125.0 4860.0 10125.0 4860.0 10350.0 DrawSplineSection 4860.0 10350.0 4860.0 10575.0 5085.0 10575.0 DrawSplineSection 5310.0 10575.0 l gs col-1 s gr gr % Open spline gs n 5985.0 10125.0 m 6210.0 10125.0 l 6210.0 10125.0 6435.0 10125.0 6435.0 10350.0 DrawSplineSection 6435.0 10350.0 6435.0 10575.0 6210.0 10575.0 DrawSplineSection 5985.0 10575.0 l gs col-1 s gr gr % Ellipse n 1350 2590 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3825 9110 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1350 10215 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3825 7990 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1350 3715 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1345 1465 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5625 8215 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5625 9340 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 1380 978 m 1350 1098 l 1320 978 l 1320 1140 l 1380 1140 l cp clip n 1350 675 m 1350 1125 l gs col-1 s gr gr % arrowhead n 1380 978 m 1350 1098 l 1320 978 l 1350 978 l 1380 978 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1380 2103 m 1350 2223 l 1320 2103 l 1320 2265 l 1380 2265 l cp clip n 1350 1800 m 1350 2250 l gs col-1 s gr gr % arrowhead n 1380 2103 m 1350 2223 l 1320 2103 l 1350 2103 l 1380 2103 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1380 3228 m 1350 3348 l 1320 3228 l 1320 3390 l 1380 3390 l cp clip n 1350 2925 m 1350 3375 l gs col-1 s gr gr % arrowhead n 1380 3228 m 1350 3348 l 1320 3228 l 1350 3228 l 1380 3228 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2250 7980 m 1350 7620 l 450 7980 l 1350 8340 l cp gs col-1 s gr % Polyline n 2250 9110 m 1350 8750 l 450 9110 l 1350 9470 l cp gs col-1 s gr % Polyline gs clippath 1385 7473 m 1355 7593 l 1325 7473 l 1325 7635 l 1385 7635 l cp clip n 1355 7205 m 1355 7620 l gs col-1 s gr gr % arrowhead n 1385 7473 m 1355 7593 l 1325 7473 l 1355 7473 l 1385 7473 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1380 8613 m 1350 8733 l 1320 8613 l 1320 8775 l 1380 8775 l cp clip n 1350 8340 m 1350 8760 l gs col-1 s gr gr % arrowhead n 1380 8613 m 1350 8733 l 1320 8613 l 1350 8613 l 1380 8613 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1380 9723 m 1350 9843 l 1320 9723 l 1320 9885 l 1380 9885 l cp clip n 1350 9470 m 1350 9870 l gs col-1 s gr gr % arrowhead n 1380 9723 m 1350 9843 l 1320 9723 l 1350 9723 l 1380 9723 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3855 1653 m 3825 1773 l 3795 1653 l 3795 1815 l 3855 1815 l cp clip n 2260 4845 m 2700 4845 l 2700 1575 l 3825 1575 l 3825 1800 l gs col-1 s gr gr % arrowhead n 3855 1653 m 3825 1773 l 3795 1653 l 3825 1653 l 3855 1653 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2558 5935 m 2678 5965 l 2558 5995 l 2720 5995 l 2720 5935 l cp clip n 2250 5965 m 2705 5965 l gs col-1 s gr gr % arrowhead n 2558 5935 m 2678 5965 l 2558 5995 l 2558 5965 l 2558 5935 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3343 7955 m 3463 7985 l 3343 8015 l 3505 8015 l 3505 7955 l cp clip n 2245 7985 m 3490 7985 l gs col-1 s gr gr % arrowhead n 3343 7955 m 3463 7985 l 3343 8015 l 3343 7985 l 3343 7955 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3343 9085 m 3463 9115 l 3343 9145 l 3505 9145 l 3505 9085 l cp clip n 2255 9115 m 3490 9115 l gs col-1 s gr gr % arrowhead n 3343 9085 m 3463 9115 l 3343 9145 l 3343 9115 l 3343 9085 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2255 4845 m 1355 4485 l 455 4845 l 1355 5205 l cp gs col-1 s gr % Polyline gs clippath 1385 4338 m 1355 4458 l 1325 4338 l 1325 4500 l 1385 4500 l cp clip n 1355 4050 m 1355 4485 l gs col-1 s gr gr % arrowhead n 1385 4338 m 1355 4458 l 1325 4338 l 1355 4338 l 1385 4338 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 2250 5960 m 1350 5600 l 450 5960 l 1350 6320 l cp gs col-1 s gr % Polyline gs clippath 1380 5453 m 1350 5573 l 1320 5453 l 1320 5615 l 1380 5615 l cp clip n 1350 5205 m 1350 5600 l gs col-1 s gr gr % arrowhead n 1380 5453 m 1350 5573 l 1320 5453 l 1350 5453 l 1380 5453 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1497 5430 m 1377 5400 l 1497 5370 l 1335 5370 l 1335 5430 l cp clip n 3825 5170 m 3825 5400 l 1350 5400 l gs col-1 s gr gr % arrowhead n 1497 5430 m 1377 5400 l 1497 5370 l 1497 5400 l 1497 5430 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 560 6750 m 2135 6750 l 2135 7200 l 560 7200 l cp gs col-1 s gr % Polyline gs clippath 1380 6603 m 1350 6723 l 1320 6603 l 1320 6765 l 1380 6765 l cp clip n 1350 6325 m 1350 6750 l gs col-1 s gr gr % arrowhead n 1380 6603 m 1350 6723 l 1320 6603 l 1350 6603 l 1380 6603 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5655 8858 m 5625 8978 l 5595 8858 l 5595 9020 l 5655 9020 l cp clip n 5625 8550 m 5625 9005 l gs col-1 s gr gr % arrowhead n 5655 8858 m 5625 8978 l 5595 8858 l 5625 8858 l 5655 8858 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5655 9978 m 5625 10098 l 5595 9978 l 5595 10140 l 5655 10140 l cp clip n 5625 9675 m 5625 10125 l gs col-1 s gr gr % arrowhead n 5655 9978 m 5625 10098 l 5595 9978 l 5625 9978 l 5655 9978 l cp gs 0.00 setgray ef gr col-1 s $F2psEnd rs $EOD $! $CREATE fig_startup-b.ps $DECK %!PS-Adobe-2.0 EPSF-2.0 %%Title: fig_startup-b.fig %%Creator: fig2dev Version 3.1 Patchlevel 2 %%CreationDate: Mon Sep 16 14:51:13 1996 %%For: keith@metropolis (Keith Refson) %Magnification: 0.69 %%Orientation: Portrait %%BoundingBox: 0 0 442 451 %%Pages: 0 %%BeginSetup %%IncludeFeature: *PageSize A4 %%EndSetup %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -18.0 460.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n 0 842 m 0 0 l 595 0 l 595 842 l cp clip 0.04157 0.04157 sc 7.500 slw % Ellipse n 2476 7089 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2481 7988 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2481 8888 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2481 9793 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 2511 7503 m 2481 7623 l 2451 7503 l 2451 7665 l 2511 7665 l cp clip n 2481 7424 m 2481 7650 l gs col-1 s gr gr % arrowhead n 2511 7503 m 2481 7623 l 2451 7503 l 2481 7503 l 2511 7503 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2511 8403 m 2481 8523 l 2451 8403 l 2451 8565 l 2511 8565 l cp clip n 2481 8324 m 2481 8550 l gs col-1 s gr gr % arrowhead n 2511 8403 m 2481 8523 l 2451 8403 l 2481 8403 l 2511 8403 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2511 9303 m 2481 9423 l 2451 9303 l 2451 9465 l 2511 9465 l cp clip n 2481 9224 m 2481 9450 l gs col-1 s gr gr % arrowhead n 2511 9303 m 2481 9423 l 2451 9303 l 2481 9303 l 2511 9303 l cp gs 0.00 setgray ef gr col-1 s % Ellipse n 2476 1464 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2481 2363 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2481 3263 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2481 4168 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 2511 1878 m 2481 1998 l 2451 1878 l 2451 2040 l 2511 2040 l cp clip n 2481 1799 m 2481 2025 l gs col-1 s gr gr % arrowhead n 2511 1878 m 2481 1998 l 2451 1878 l 2481 1878 l 2511 1878 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2511 2778 m 2481 2898 l 2451 2778 l 2451 2940 l 2511 2940 l cp clip n 2481 2699 m 2481 2925 l gs col-1 s gr gr % arrowhead n 2511 2778 m 2481 2898 l 2451 2778 l 2481 2778 l 2511 2778 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2511 3678 m 2481 3798 l 2451 3678 l 2451 3840 l 2511 3840 l cp clip n 2481 3599 m 2481 3825 l gs col-1 s gr gr % arrowhead n 2511 3678 m 2481 3798 l 2451 3678 l 2481 3678 l 2511 3678 l cp gs 0.00 setgray ef gr col-1 s % Ellipse n 10141 1689 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 10146 2588 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 10146 3488 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 10146 4393 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 10176 2103 m 10146 2223 l 10116 2103 l 10116 2265 l 10176 2265 l cp clip n 10146 2024 m 10146 2250 l gs col-1 s gr gr % arrowhead n 10176 2103 m 10146 2223 l 10116 2103 l 10146 2103 l 10176 2103 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 10176 3003 m 10146 3123 l 10116 3003 l 10116 3165 l 10176 3165 l cp clip n 10146 2924 m 10146 3150 l gs col-1 s gr gr % arrowhead n 10176 3003 m 10146 3123 l 10116 3003 l 10146 3003 l 10176 3003 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 10176 3903 m 10146 4023 l 10116 3903 l 10116 4065 l 10176 4065 l cp clip n 10146 3824 m 10146 4050 l gs col-1 s gr gr % arrowhead n 10176 3903 m 10146 4023 l 10116 3903 l 10146 3903 l 10176 3903 l cp gs 0.00 setgray ef gr col-1 s % Ellipse n 10140 8205 335 335 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 10170 7728 m 10140 7848 l 10110 7728 l 10110 7890 l 10170 7890 l cp clip n 10140 7425 m 10140 7875 l gs col-1 s gr gr % arrowhead n 10170 7728 m 10140 7848 l 10110 7728 l 10140 7728 l 10170 7728 l cp gs 0.00 setgray ef gr col-1 s % Ellipse n 10140 560 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 10141 5289 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 10146 6188 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 10146 7088 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline gs clippath 10170 1203 m 10140 1323 l 10110 1203 l 10110 1365 l 10170 1365 l cp clip n 10140 900 m 10140 1350 l gs col-1 s gr gr % arrowhead n 10170 1203 m 10140 1323 l 10110 1203 l 10140 1203 l 10170 1203 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 10176 5703 m 10146 5823 l 10116 5703 l 10116 5865 l 10176 5865 l cp clip n 10146 5624 m 10146 5850 l gs col-1 s gr gr % arrowhead n 10176 5703 m 10146 5823 l 10116 5703 l 10146 5703 l 10176 5703 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 10176 6603 m 10146 6723 l 10116 6603 l 10116 6765 l 10176 6765 l cp clip n 10146 6524 m 10146 6750 l gs col-1 s gr gr % arrowhead n 10176 6603 m 10146 6723 l 10116 6603 l 10146 6603 l 10176 6603 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 10176 4803 m 10146 4923 l 10116 4803 l 10116 4965 l 10176 4965 l cp clip n 10146 4724 m 10146 4950 l gs col-1 s gr gr % arrowhead n 10176 4803 m 10146 4923 l 10116 4803 l 10146 4803 l 10176 4803 l cp gs 0.00 setgray ef gr col-1 s % Ellipse n 5625 565 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2471 10690 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 1350 5962 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 3598 5962 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 2475 570 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5625 3505 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5626 5082 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5631 5981 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5631 6881 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5631 7786 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5625 10703 335 335 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7870 9593 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7876 2381 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7881 3280 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7881 5085 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 7881 4180 900 338 0 360 DrawEllipse gs col-1 s gr % Ellipse n 5631 8680 900 338 0 360 DrawEllipse gs col-1 s gr % Polyline n 4725 1125 m 6525 1125 l 6525 1800 l 4725 1800 l cp gs col-1 s gr % Polyline gs clippath 5655 978 m 5625 1098 l 5595 978 l 5595 1140 l 5655 1140 l cp clip n 5625 900 m 5625 1125 l gs col-1 s gr gr % arrowhead n 5655 978 m 5625 1098 l 5595 978 l 5625 978 l 5655 978 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5655 1878 m 5625 1998 l 5595 1878 l 5595 2040 l 5655 2040 l cp clip n 5625 1800 m 5625 2025 l gs col-1 s gr gr % arrowhead n 5655 1878 m 5625 1998 l 5595 1878 l 5625 1878 l 5655 1878 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2505 978 m 2475 1098 l 2445 978 l 2445 1140 l 2505 1140 l cp clip n 2475 900 m 2475 1125 l gs col-1 s gr gr % arrowhead n 2505 978 m 2475 1098 l 2445 978 l 2475 978 l 2505 978 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2505 4573 m 2475 4693 l 2445 4573 l 2445 4735 l 2505 4735 l cp clip n 2475 4500 m 2475 4720 l gs col-1 s gr gr % arrowhead n 2505 4573 m 2475 4693 l 2445 4573 l 2475 4573 l 2505 4573 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 1380 5481 m 1350 5601 l 1320 5481 l 1320 5643 l 1380 5643 l cp clip n 1575 5085 m 1350 5085 l 1350 5628 l gs col-1 s gr gr % arrowhead n 1380 5481 m 1350 5601 l 1320 5481 l 1350 5481 l 1380 5481 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 3630 5483 m 3600 5603 l 3570 5483 l 3570 5645 l 3630 5645 l cp clip n 3375 5085 m 3600 5085 l 3600 5630 l gs col-1 s gr gr % arrowhead n 3630 5483 m 3600 5603 l 3570 5483 l 3600 5483 l 3630 5483 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2328 6495 m 2448 6525 l 2328 6555 l 2490 6555 l 2490 6495 l cp clip n 1350 6300 m 1350 6525 l 2475 6525 l gs col-1 s gr gr % arrowhead n 2328 6495 m 2448 6525 l 2328 6555 l 2328 6525 l 2328 6495 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2622 6555 m 2502 6525 l 2622 6495 l 2460 6495 l 2460 6555 l cp clip n 3600 6300 m 3600 6525 l 2475 6525 l gs col-1 s gr gr % arrowhead n 2622 6555 m 2502 6525 l 2622 6495 l 2622 6525 l 2622 6555 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2505 6603 m 2475 6723 l 2445 6603 l 2445 6765 l 2505 6765 l cp clip n 2475 6525 m 2475 6750 l gs col-1 s gr gr % arrowhead n 2505 6603 m 2475 6723 l 2445 6603 l 2475 6603 l 2505 6603 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 2510 10213 m 2480 10333 l 2450 10213 l 2450 10375 l 2510 10375 l cp clip n 2480 10135 m 2480 10360 l gs col-1 s gr gr % arrowhead n 2510 10213 m 2480 10333 l 2450 10213 l 2480 10213 l 2510 10213 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5655 3018 m 5625 3138 l 5595 3018 l 5595 3180 l 5655 3180 l cp clip n 5625 2740 m 5625 3165 l gs col-1 s gr gr % arrowhead n 5655 3018 m 5625 3138 l 5595 3018 l 5625 3018 l 5655 3018 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 6525 2385 m 5625 2025 l 4725 2385 l 5625 2745 l cp gs col-1 s gr % Polyline gs clippath 5655 4601 m 5625 4721 l 5595 4601 l 5595 4763 l 5655 4763 l cp clip n 5625 3840 m 5625 4748 l gs col-1 s gr gr % arrowhead n 5655 4601 m 5625 4721 l 5595 4601 l 5625 4601 l 5655 4601 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5661 5496 m 5631 5616 l 5601 5496 l 5601 5658 l 5661 5658 l cp clip n 5631 5417 m 5631 5643 l gs col-1 s gr gr % arrowhead n 5661 5496 m 5631 5616 l 5601 5496 l 5631 5496 l 5661 5496 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5661 6396 m 5631 6516 l 5601 6396 l 5601 6558 l 5661 6558 l cp clip n 5631 6317 m 5631 6543 l gs col-1 s gr gr % arrowhead n 5661 6396 m 5631 6516 l 5601 6396 l 5631 6396 l 5661 6396 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5661 7296 m 5631 7416 l 5601 7296 l 5601 7458 l 5661 7458 l cp clip n 5631 7217 m 5631 7443 l gs col-1 s gr gr % arrowhead n 5661 7296 m 5631 7416 l 5601 7296 l 5631 7296 l 5661 7296 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5661 8197 m 5631 8317 l 5601 8197 l 5601 8359 l 5661 8359 l cp clip n 5631 8118 m 5631 8344 l gs col-1 s gr gr % arrowhead n 5661 8197 m 5631 8317 l 5601 8197 l 5631 8197 l 5661 8197 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 6525 9586 m 5625 9226 l 4725 9586 l 5625 9946 l cp gs col-1 s gr % Polyline gs clippath 6828 9558 m 6948 9588 l 6828 9618 l 6990 9618 l 6990 9558 l cp clip n 6525 9588 m 6975 9588 l gs col-1 s gr gr % arrowhead n 6828 9558 m 6948 9588 l 6828 9618 l 6828 9588 l 6828 9558 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5772 10178 m 5652 10148 l 5772 10118 l 5610 10118 l 5610 10178 l cp clip n 7880 9933 m 7880 10148 l 5625 10148 l gs col-1 s gr gr % arrowhead n 5772 10178 m 5652 10148 l 5772 10118 l 5772 10148 l 5772 10178 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5655 10214 m 5625 10334 l 5595 10214 l 5595 10376 l 5655 10376 l cp clip n 5625 9948 m 5625 10361 l gs col-1 s gr gr % arrowhead n 5655 10214 m 5625 10334 l 5595 10214 l 5625 10214 l 5655 10214 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5655 9080 m 5625 9200 l 5595 9080 l 5595 9242 l 5655 9242 l cp clip n 5625 9015 m 5625 9227 l gs col-1 s gr gr % arrowhead n 5655 9080 m 5625 9200 l 5595 9080 l 5625 9080 l 5655 9080 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7911 2795 m 7881 2915 l 7851 2795 l 7851 2957 l 7911 2957 l cp clip n 7881 2716 m 7881 2942 l gs col-1 s gr gr % arrowhead n 7911 2795 m 7881 2915 l 7851 2795 l 7881 2795 l 7911 2795 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7911 3695 m 7881 3815 l 7851 3695 l 7851 3857 l 7911 3857 l cp clip n 7881 3616 m 7881 3842 l gs col-1 s gr gr % arrowhead n 7911 3695 m 7881 3815 l 7851 3695 l 7881 3695 l 7911 3695 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 7911 4595 m 7881 4715 l 7851 4595 l 7851 4757 l 7911 4757 l cp clip n 7881 4516 m 7881 4742 l gs col-1 s gr gr % arrowhead n 7911 4595 m 7881 4715 l 7851 4595 l 7881 4595 l 7911 4595 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 5772 4320 m 5652 4290 l 5772 4260 l 5610 4260 l 5610 4320 l cp clip n 7875 5420 m 7875 5645 l 6750 5640 l 6750 4290 l 5625 4290 l gs col-1 s gr gr % arrowhead n 5772 4320 m 5652 4290 l 5772 4260 l 5772 4290 l 5772 4320 l cp gs 0.00 setgray ef gr col-1 s % Polyline gs clippath 6834 2354 m 6954 2384 l 6834 2414 l 6996 2414 l 6996 2354 l cp clip n 6531 2384 m 6981 2384 l gs col-1 s gr gr % arrowhead n 6834 2354 m 6954 2384 l 6834 2414 l 6834 2384 l 6834 2354 l cp gs 0.00 setgray ef gr col-1 s % Polyline n 3375 5080 m 2475 4720 l 1575 5080 l 2475 5440 l cp gs col-1 s gr $F2psEnd rs $EOD $! $CREATE fig_arralloc-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(9073,5146)(0,-10) \put(317,494){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\ttdefault}{\mddefault}{\updefault}r}}}}} \put(1960,534){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\ttdefault}{\mddefault}{\updefault}r[i]}}}}} \put(5979,555){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\ttdefault}{\mddefault}{\updefault}r[i][j]}}}}} \put(387,45){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\familydefault}{\mddefault}{\updefault}(pointer)}}}}} \put(2204,45){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\familydefault}{\mddefault}{\updefault}(array of \textit{m} pointers)}}}}} \put(6393,45){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\familydefault}{\mddefault}{\updefault}(\textit{m} arrays of \textit{n} data objects)}}}}} \path(2448,4816)(1839,4816)(1839,3599)(2448,3599) \path(1839,4208)(2448,4208) \path(2448,2381)(1839,2381)(1839,1164)(2448,1164) \path(1839,1772)(2448,1772) \path(12,4816)(621,4816)(621,4208) (12,4208)(12,4816) \path(317,4512)(1820,4512) \blacken\path(1580.000,4452.000)(1820.000,4512.000)(1580.000,4572.000)(1580.000,4452.000) \path(2082,4512)(3665,4512) \blacken\path(3425.000,4452.000)(3665.000,4512.000)(3425.000,4572.000)(3425.000,4452.000) \path(2082,3903)(3665,3903) \blacken\path(3425.000,3843.000)(3665.000,3903.000)(3425.000,3963.000)(3425.000,3843.000) \path(2448,4816)(2448,3599) \path(2448,2381)(2448,1164) \path(2082,1468)(3665,1468) \blacken\path(3425.000,1408.000)(3665.000,1468.000)(3425.000,1528.000)(3425.000,1408.000) \path(2082,2077)(3665,2077) \blacken\path(3425.000,2017.000)(3665.000,2077.000)(3425.000,2137.000)(3425.000,2017.000) \path(5492,4816)(5492,3599) \path(5492,2381)(5492,1164) \path(8536,4816)(8536,3599) \path(8536,2381)(8536,1164) \path(4274,2381)(3665,2381)(3665,1164)(4274,1164) \path(3665,1772)(4274,1772) \path(4274,4816)(3665,4816)(3665,3599)(4274,3599) \path(3665,4208)(4274,4208) \path(5492,4816)(4883,4816)(4883,3599)(5492,3599) \path(4883,4208)(5492,4208) \path(5492,2381)(4883,2381)(4883,1164)(5492,1164) \path(4883,1772)(5492,1772) \path(7318,4816)(6709,4816)(6709,3599)(7318,3599) \path(6709,4208)(7318,4208) \path(8536,4816)(7927,4816)(7927,3599)(8536,3599) \path(7927,4208)(8536,4208) \path(8536,2381)(7927,2381)(7927,1164)(8536,1164) \path(7927,1772)(8536,1772) \path(7318,2381)(6709,2381)(6709,1164)(7318,1164) \path(6709,1772)(7318,1772) \path(4274,4208)(4883,4208) \path(4883,4816)(4274,4816)(4274,3599)(4883,3599) \path(7318,4208)(7927,4208) \path(7927,4816)(7318,4816)(7318,3599)(7927,3599) \path(7318,1772)(7927,1772) \path(7927,2381)(7318,2381)(7318,1164)(7927,1164) \path(4274,1772)(4883,1772) \path(4883,2381)(4274,2381)(4274,1164)(4883,1164) \dottedline{120}(1839,3599)(1839,2381) \dottedline{120}(2448,3599)(2448,2381) \dottedline{120}(3665,3599)(3665,2381) \dottedline{120}(4274,3599)(4274,2381) \dottedline{120}(4883,3599)(4883,2381) \dottedline{120}(5492,3599)(5492,2381) \dottedline{120}(6709,3599)(6709,2381) \dottedline{120}(7318,3599)(7318,2381) \dottedline{120}(7927,3599)(7927,2381) \dottedline{120}(8536,3599)(8536,2381) \dottedline{120}(5492,2381)(6709,2381) \dottedline{120}(5492,1772)(6709,1772) \dottedline{120}(5492,1164)(6709,1164) \dottedline{120}(5492,3599)(6709,3599) \dottedline{120}(5492,4208)(6709,4208) \dottedline{120}(5492,4816)(6709,4816) \put(4457,4999){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}1}}}}} \put(5004,4999){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}2}}}}} \put(7379,4999){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}n-2}}}}} \put(8719,4390){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}0}}}}} \put(8719,3842){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}1}}}}} \put(8658,2138){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}m-2}}}}} \put(3848,4999){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}0}}}}} \put(6770,4999){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}n-3}}}}} \put(8049,4999){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}n-1}}}}} \put(8658,1529){\makebox(0,0)[lb]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\mddefault}{\itdefault}m-1}}}}} \end{picture} } $EOD $! $CREATE fig_dostep-a-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(10599,10585)(0,-10) \path(1267,10558)(1942,10558) \path(1267,10108)(1942,10108) \spline(1267,10558) (817,10558)(817,10108)(1267,10108) \spline(1942,10558) (2392,10558)(2392,10108)(1942,10108) \put(8337,9838){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Calculation of molecular}}}}} \put(8337,9635){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}centre-of-mass forces}}}}} \put(8337,9432){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}and torques.}}}}} \put(1587,4603){\ellipse{1800}{630}} \put(7212,343){\ellipse{670}{670}} \put(1587,3470){\ellipse{1800}{630}} \put(7212,5248){\ellipse{1800}{630}} \put(7212,9703){\ellipse{1800}{630}} \put(9469,8582){\ellipse{1800}{630}} \put(9469,2777){\ellipse{1800}{630}} \put(9469,3902){\ellipse{1800}{630}} \put(9469,1652){\ellipse{1800}{630}} \put(1582,5833){\ellipse{2520}{900}} \put(3844,2327){\ellipse{1800}{630}} \path(1582,9680)(1582,10108) \blacken\path(1552.000,9800.000)(1582.000,9680.000)(1612.000,9800.000)(1552.000,9800.000) \path(1587,4285)(1587,3778) \blacken\path(1557.000,3898.000)(1587.000,3778.000)(1617.000,3898.000)(1557.000,3898.000) \path(1587,6733)(1587,6268) \blacken\path(1557.000,6388.000)(1587.000,6268.000)(1617.000,6388.000)(1557.000,6388.000) \path(1587,7408)(1587,7858) \blacken\path(1557.000,7528.000)(1587.000,7408.000)(1617.000,7528.000)(1557.000,7528.000) \path(817,8533)(2392,8533)(2392,7858) (817,7858)(817,8533) \path(817,7408)(2392,7408)(2392,6733) (817,6733)(817,7408) \path(2937,9665)(4512,9665)(4512,8990) (2937,8990)(2937,9665) \path(1587,5383)(1587,4918) \blacken\path(1557.000,5038.000)(1587.000,4918.000)(1617.000,5038.000)(1557.000,5038.000) \drawline(1587,2948)(1587,2948) \path(3842,877)(3842,652)(1592,652) \blacken\path(1712.000,682.000)(1592.000,652.000)(1712.000,622.000)(1712.000,682.000) \path(2944,1559)(4519,1559)(4519,884) (2944,884)(2944,1559) \path(2487,1212)(2942,1212) \blacken\path(2822.000,1182.000)(2942.000,1212.000)(2822.000,1242.000)(2822.000,1182.000) \path(1587,853)(1587,208)(5412,208) (5412,10558)(7212,10558)(7212,10018) \blacken\path(7182.000,10138.000)(7212.000,10018.000)(7242.000,10138.000)(7182.000,10138.000) \path(1587,2683)(1587,3151) \blacken\path(1557.000,2803.000)(1587.000,2683.000)(1617.000,2803.000)(1557.000,2803.000) \path(7217,4933)(7217,4258) \blacken\path(7187.000,4378.000)(7217.000,4258.000)(7247.000,4378.000)(7187.000,4378.000) \path(7217,3531)(7217,675) \blacken\path(7187.000,795.000)(7217.000,675.000)(7247.000,795.000)(7187.000,795.000) \path(9467,1332)(9467,1108)(7217,1108) \blacken\path(7337.000,1138.000)(7217.000,1108.000)(7337.000,1078.000)(7337.000,1138.000) \path(2494,9321)(2929,9321) \blacken\path(2809.000,9291.000)(2929.000,9321.000)(2809.000,9351.000)(2809.000,9291.000) \dashline{90.000}(5862,10333)(10587,10333)(10587,4708) (5862,4708)(5862,10333) \path(7211,6013)(7211,5562) \blacken\path(7181.000,5682.000)(7211.000,5562.000)(7241.000,5682.000)(7181.000,5682.000) \path(6427,7813)(8002,7813)(8002,7138) (6427,7138)(6427,7813) \path(6427,6688)(8002,6688)(8002,6013) (6427,6013)(6427,6688) \path(7212,9388)(7212,8938) \blacken\path(7182.000,9058.000)(7212.000,8938.000)(7242.000,9058.000)(7182.000,9058.000) \path(8117,8578)(7217,8938)(6317,8578) (7217,8218)(8117,8578) \path(7217,8218)(7217,7813) \blacken\path(7187.000,7933.000)(7217.000,7813.000)(7247.000,7933.000)(7187.000,7933.000) \path(7212,7138)(7212,6688) \blacken\path(7182.000,6808.000)(7212.000,6688.000)(7242.000,6808.000)(7182.000,6808.000) \path(9462,8263)(9462,8038)(7222,8038) \blacken\path(7342.000,8068.000)(7222.000,8038.000)(7342.000,8008.000)(7342.000,8068.000) \dashline{90.000}(12,5158)(4962,5158)(4962,433) (12,433)(12,5158) \path(8122,3892)(8567,3892) \blacken\path(8447.000,3862.000)(8567.000,3892.000)(8447.000,3922.000)(8447.000,3862.000) \path(9462,3583)(9462,3088) \blacken\path(9432.000,3208.000)(9462.000,3088.000)(9492.000,3208.000)(9432.000,3208.000) \path(9462,2458)(9462,1963) \blacken\path(9432.000,2083.000)(9462.000,1963.000)(9492.000,2083.000)(9432.000,2083.000) \dashline{90.000}(5862,4483)(5862,883)(7887,883) (10587,890)(10587,4483)(5862,4483) \path(3747,8983)(3747,8758)(1587,8758) \blacken\path(1707.000,8788.000)(1587.000,8758.000)(1707.000,8728.000)(1707.000,8788.000) \path(2482,9320)(1582,9680)(682,9320) (1582,8960)(2482,9320) \path(1581,8960)(1581,8533) \blacken\path(1551.000,8653.000)(1581.000,8533.000)(1611.000,8653.000)(1551.000,8653.000) \path(2497,2317)(2942,2317) \blacken\path(2822.000,2287.000)(2942.000,2317.000)(2822.000,2347.000)(2822.000,2287.000) \path(3842,2007)(3842,1777)(1592,1777) \blacken\path(1712.000,1807.000)(1592.000,1777.000)(1712.000,1747.000)(1712.000,1807.000) \path(1587,1957)(1587,1572) \blacken\path(1557.000,1692.000)(1587.000,1572.000)(1617.000,1692.000)(1557.000,1692.000) \path(2487,2323)(1587,2683)(687,2323) (1587,1963)(2487,2323) \path(2487,1214)(1587,1574)(687,1214) (1587,854)(2487,1214) \path(8117,3898)(7217,4258)(6317,3898) (7217,3538)(8117,3898) \path(8119,8579)(8564,8579) \blacken\path(8444.000,8549.000)(8564.000,8579.000)(8444.000,8609.000)(8444.000,8549.000) \put(1587,9253){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}first call?}}}}} \put(957,8308){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Allocate arrays}}}}} \put(957,8105){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}for sites and}}}}} \put(957,7902){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}site forces}}}}} \put(957,7138){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Set up array of}}}}} \put(957,6935){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}site charges}}}}} \put(1587,6013){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}step\_1()}}}}} \put(3072,9433){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc. distant}}}}} \put(3072,9253){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}pot'l \& pressure}}}}} \put(3072,9073){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}correction}}}}} \put(1587,4663){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}make\_sites()}}}}} \put(1587,4483){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc. site co-ords.}}}}} \put(3837,2413){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}ewald()}}}}} \put(3837,2188){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}recip-space forces}}}}} \put(2487,2458){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1362,1783){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(1362,8758){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(2487,9433){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1587,3523){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_calc()}}}}} \put(1587,2263){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}coulomb forces?}}}}} \put(1587,1228){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}surface-dipole}}}}} \put(8115,4031){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(6990,3364){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(7215,297){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}}}} \put(9462,8623){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}mol\_torque()}}}}} \put(7257,5338){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}newton()}}}}} \put(7212,9763){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}mol\_force()}}}}} \put(7222,8683){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}any}}}}} \put(7222,8480){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}polyatomics?}}}}} \put(6532,7400){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}molecular virial}}}}} \put(6532,7197){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}correction term.}}}}} \put(6537,6305){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}last timestep in}}}}} \put(6537,6102){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}"old" arrays etc.}}}}} \put(8112,8758){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(6987,8083){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(9462,2878){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rahman()}}}}} \put(9462,1738){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}}}} \put(1587,5826){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Apply Beeman steps \textit{i, ii} to}}}}} \put(2764,4731){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(b)}}}}} \put(1587,3320){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}real-space forces}}}}} \put(1587,2465){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}need}}}}} \put(1587,1062){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}switch on?}}}}} \put(3027,1085){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}forces \& energy.}}}}} \put(3027,1288){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get surf. dipole}}}}} \put(8195,9892){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(c)}}}}} \put(7207,9576){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get C of M forces.}}}}} \put(9465,8428){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get torques.}}}}} \put(6537,6508){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Store acc's from}}}}} \put(6532,7603){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get atomic,}}}}} \put(7207,3851){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Const stress?}}}}} \put(6097,4244){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(d)}}}}} \put(7215,5134){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}New C of M acc's}}}}} \put(462,6274){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(a)}}}}} \put(9462,1539){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Step cell velocities}}}}} \put(9457,2690){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get unit cell acc's}}}}} \put(2952,4723){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Calculation of atomic}}}}} \put(2952,4520){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}site forces and}}}}} \put(2952,4317){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}potential energy.}}}}} \put(1587,5660){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}update dynamic variables}}}}} \put(1587,10259){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}do\_step()}}}}} \put(2487,1318){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1362,666){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(9462,3973){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}energy\_dyad()}}}}} \put(9447,3778){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} kinetic stress term}}}}} \end{picture} } $EOD $! $CREATE fig_dostep-b-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(10449,10393)(0,-10) \path(6473,462)(7148,462) \path(6473,12)(7148,12) \spline(6473,462) (6023,462)(6023,12)(6473,12) \spline(7148,462) (7598,462)(7598,12)(7148,12) \put(7587,5626){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(f)}}}}} \put(7837,5449){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}derivatives using Beeman}}}}} \put(7837,5608){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Iteratively update quatern}}}}} \put(7837,5298){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}step \emph{iv}.}}}}} \put(2442,3931){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(e)}}}}} \put(2642,3936){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Iteratative loop to step}}}}} \put(2647,3776){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}C of M velocities using}}}}} \put(2647,3632){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}Beeman step \emph{iv}.}}}}} \put(9076,8312){\ellipse{1800}{676}} \put(9083,9534){\ellipse{1800}{676}} \put(6826,8312){\ellipse{1800}{676}} \put(6826,7190){\ellipse{1800}{676}} \put(6829,6068){\ellipse{1800}{676}} \put(6837,2492){\ellipse{2520}{900}} \put(6833,4959){\ellipse{1800}{630}} \put(9071,1205){\ellipse{1800}{630}} \put(1437,9986){\ellipse{670}{670}} \put(3687,5381){\ellipse{1800}{676}} \put(3694,6603){\ellipse{1800}{676}} \put(1437,5381){\ellipse{1800}{676}} \put(1437,4259){\ellipse{1800}{676}} \put(1440,3137){\ellipse{1800}{676}} \put(3694,7805){\ellipse{1800}{676}} \path(1437,1636)(1437,1186) \blacken\path(1407.000,1306.000)(1437.000,1186.000)(1467.000,1306.000)(1407.000,1306.000) \path(1441,451)(1441,226)(5502,226) (5502,3166)(6837,3166) \blacken\path(6717.000,3136.000)(6837.000,3166.000)(6717.000,3196.000)(6717.000,3136.000) \path(529,8971)(12,8971)(12,1367)(1437,1367) \blacken\path(1317.000,1337.000)(1437.000,1367.000)(1317.000,1397.000)(1317.000,1337.000) \path(6831,9152)(6831,8640) \blacken\path(6801.000,8760.000)(6831.000,8640.000)(6861.000,8760.000)(6801.000,8760.000) \path(6826,7974)(6826,7530) \blacken\path(6796.000,7650.000)(6826.000,7530.000)(6856.000,7650.000)(6796.000,7650.000) \path(9076,9202)(9076,8623) \path(9081,7980)(9081,7707)(6831,7707) \blacken\path(6951.000,7737.000)(6831.000,7707.000)(6951.000,7677.000)(6951.000,7737.000) \path(7736,9538)(8181,9538) \blacken\path(8061.000,9508.000)(8181.000,9538.000)(8061.000,9568.000)(8061.000,9508.000) \path(6826,6855)(6826,6405) \blacken\path(6796.000,6525.000)(6826.000,6405.000)(6856.000,6525.000)(6796.000,6525.000) \path(6830,5733)(6830,5274) \blacken\path(6800.000,5394.000)(6830.000,5274.000)(6860.000,5394.000)(6800.000,5394.000) \path(6832,4639)(6832,4199) \blacken\path(6802.000,4319.000)(6832.000,4199.000)(6862.000,4319.000)(6802.000,4319.000) \path(6832,826)(6832,462) \blacken\path(6802.000,582.000)(6832.000,462.000)(6862.000,582.000)(6802.000,582.000) \path(6837,3467)(6837,2942) \blacken\path(6807.000,3062.000)(6837.000,2942.000)(6867.000,3062.000)(6807.000,3062.000) \path(6837,2037)(6837,1591) \blacken\path(6807.000,1711.000)(6837.000,1591.000)(6867.000,1711.000)(6807.000,1711.000) \path(7732,3831)(10215,3831)(10215,10144)(6826,10144) \blacken\path(6946.000,10174.000)(6826.000,10144.000)(6946.000,10114.000)(6946.000,10174.000) \path(6826,6651)(5697,6651)(5697,9541)(5926,9541) \blacken\path(5817.000,9571.000)(5697.000,9541.000)(5817.000,9511.000)(5817.000,9571.000) \path(7741,1207)(8166,1207) \blacken\path(8046.000,1177.000)(8166.000,1207.000)(8046.000,1237.000)(8046.000,1177.000) \path(9076,885)(9076,685)(6831,685) \blacken\path(6951.000,715.000)(6831.000,685.000)(6951.000,655.000)(6951.000,715.000) \path(2337,811)(1437,1171)(537,811) (1437,451)(2337,811) \path(2337,811)(5262,811)(5262,10366) (6827,10366)(6827,9924) \blacken\path(6797.000,10044.000)(6827.000,9924.000)(6857.000,10044.000)(6797.000,10044.000) \path(7727,9538)(6827,9924)(5927,9538) (6827,9152)(7727,9538) \path(7732,3831)(6832,4191)(5932,3831) (6832,3471)(7732,3831) \path(7737,1207)(6837,1593)(5937,1207) (6837,821)(7737,1207) \dashline{60.000}(5502,10261)(10437,10261)(10437,3275) (5502,3275)(5502,10261) \path(2337,2002)(4812,2002)(4812,8441)(1437,8443) \blacken\path(1557.018,8472.929)(1437.000,8443.000)(1556.982,8412.929)(1557.018,8472.929) \path(1442,7412)(1442,6994) \blacken\path(1412.000,7114.000)(1442.000,6994.000)(1472.000,7114.000)(1412.000,7114.000) \path(3692,7469)(3692,7211)(1442,7211) \blacken\path(1562.000,7241.000)(1442.000,7211.000)(1562.000,7181.000)(1562.000,7241.000) \path(2337,7806)(1437,8192)(537,7806) (1437,7420)(2337,7806) \path(2347,7806)(2792,7806) \blacken\path(2672.000,7776.000)(2792.000,7806.000)(2672.000,7836.000)(2672.000,7776.000) \path(1437,5043)(1437,4599) \blacken\path(1407.000,4719.000)(1437.000,4599.000)(1467.000,4719.000)(1407.000,4719.000) \path(3687,6271)(3687,5692) \path(3692,5049)(3692,4776)(1442,4776) \blacken\path(1562.000,4806.000)(1442.000,4776.000)(1562.000,4746.000)(1562.000,4806.000) \path(1437,3704)(312,3704)(312,6608)(537,6600) \blacken\path(432.990,6633.717)(312.000,6608.000)(430.858,6573.755)(432.990,6633.717) \path(2347,6607)(2792,6607) \blacken\path(2672.000,6577.000)(2792.000,6607.000)(2672.000,6637.000)(2672.000,6577.000) \path(2337,6607)(1437,6993)(537,6607) (1437,6221)(2337,6607) \path(1437,3924)(1437,3474) \blacken\path(1407.000,3594.000)(1437.000,3474.000)(1467.000,3594.000)(1407.000,3594.000) \path(2337,2002)(1437,2362)(537,2002) (1437,1642)(2337,2002) \path(1441,2802)(1441,2367) \blacken\path(1411.000,2487.000)(1441.000,2367.000)(1471.000,2487.000)(1411.000,2487.000) \path(2337,8971)(1437,9331)(537,8971) (1437,8611)(2337,8971) \path(1437,9645)(1437,9331) \blacken\path(1407.000,9451.000)(1437.000,9331.000)(1467.000,9451.000)(1407.000,9451.000) \path(1437,8609)(1437,8198) \blacken\path(1407.000,8318.000)(1437.000,8198.000)(1467.000,8318.000)(1407.000,8318.000) \path(1435,6221)(1435,5727) \blacken\path(1405.000,5847.000)(1435.000,5727.000)(1465.000,5847.000)(1405.000,5847.000) \dashline{60.000}(177,8551)(4947,8551)(4947,1456) (177,1456)(177,8551) \put(1677,316){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(2367,931){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(6833,9474){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Thermostat ?}}}}} \put(5686,9692){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}None}}}}} \put(7051,8960){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gaussian}}}}} \put(7875,9789){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Nose-Hoover}}}}} \put(6816,8414){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}gtherm()}}}}} \put(7791,3912){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(6852,5049){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}}}} \put(6829,6144){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}euler()}}}}} \put(6867,7224){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}hoover\_rot()}}}}} \put(7066,3342){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(6852,2652){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}step\_2()}}}}} \put(6837,192){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}}}} \put(9076,8416){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}}}} \put(9076,9664){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}nhtherm()}}}}} \put(9087,8176){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Predict N-H $\zeta$}}}}} \put(9072,9421){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get N-H $\dot{\zeta}$}}}}} \put(6822,8161){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc. gaussian $\zeta$}}}}} \put(6831,3949){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}quatern}}}}} \put(6831,3660){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}converged?}}}}} \put(6831,3807){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}derivatives}}}}} \put(6842,2481){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Apply Beeman step \textit{iv} to}}}}} \put(6852,2309){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}dynamic var derivatives}}}}} \put(6837,4871){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}step quatern derivs}}}}} \put(6832,7046){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get torque corr.}}}}} \put(6837,5951){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc angular accs}}}}} \put(6822,1156){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump\_interval}}}}} \put(6821,1323){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}every}}}}} \put(6822,988){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}steps}}}}} \put(7932,2941){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\itdefault}(g)}}}}} \put(9091,1330){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump()}}}}} \put(9068,1167){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}write trajectories,}}}}} \put(9068,1005){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}forces \emph{etc.}}}}}} \put(1437,9886){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}}}} \put(537,9106){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(1669,8438){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1437,9033){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}const-stress}}}}} \put(1437,8869){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}or thermostat?}}}}} \put(1437,7636){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}simulation?}}}}} \put(1444,6543){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Thermostat ?}}}}} \put(297,6761){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}None}}}}} \put(1662,6029){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gaussian}}}}} \put(2486,6858){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Nose-Hoover}}}}} \put(3687,6688){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}nhtherm()}}}}} \put(1447,4358){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}hoover\_tr()}}}}} \put(1427,5483){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}gtherm()}}}}} \put(3687,5435){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}}}} \put(1422,3198){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}beeman\_2()}}}}} \put(1452,1894){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}converged?}}}}} \put(1452,2071){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}velocities}}}}} \put(2352,2131){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(1437,7814){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Const stress}}}}} \put(3697,7894){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}parinello()}}}}} \put(3687,6466){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get N-H $\dot{\zeta}$}}}}} \put(3702,5228){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Step N-H $\zeta$}}}}} \put(1437,5206){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Get gaussian $\zeta$}}}}} \put(3692,7671){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Get P\&R acc corr.}}}}} \put(1422,2986){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}step C of M vels}}}}} \put(1437,4126){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calc N-H acc corr.}}}}} \put(1590,1509){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1437,901){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}any}}}}} \put(1437,746){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}polyatomics?}}}}} \end{picture} } $EOD $! $CREATE fig_ewald-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(5329,9265)(0,-10) \path(516,6539)(2316,6539)(2316,5864) (516,5864)(516,6539) \put(576,6314){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Set up $\sin \mathbf{k \cdot r}_i$ and }}}}} \put(576,6147){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$\cos\mathbf{k \cdot r}_i$ arrays for}}}}} \put(576,5960){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$\mathbf{k}=\mathbf{0}, \mathbf{a}^*, \mathbf{b}^*, \mathbf{c}^*$}}}}} \put(576,5223){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$\mathbf{k}= h\mathbf{a}^*, k\mathbf{b}^*, l\mathbf{c}^*$}}}}} \put(576,5412){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Get $\sin$, $\cos \mathbf{k \cdot r}_i $ for}}}}} \put(576,5056){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}using recursion}}}}} \path(516,5637)(2316,5637)(2316,4962) (516,4962)(516,5637) \path(516,3837)(2316,3837)(2316,3387) (516,3387)(516,3837) \put(576,3657){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Calc. pre-factors}}}}} \put(576,3490){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}for energy, force}}}}} \put(1416,2715){\ellipse{2696}{894}} \put(1416,2513){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}for this $\mathbf{k}$ and all sites $i$}}}}} \put(1416,2745){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Evaluate $\sin$ and $\cos \mathbf{k \cdot r}_i$}}}}} \put(1416,2954){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}qsincos()}}}}} \path(516,2037)(2316,2037)(2316,1587) (516,1587)(516,2037) \put(576,1683){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}and energy term}}}}} \put(576,1857){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Eval. struct. factor}}}}} \path(516,1363)(2316,1363)(2316,913) (516,913)(516,1363) \put(576,1183){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Eval. forces on all}}}}} \put(576,1016){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}sites \& add to total}}}}} \path(1086,462)(1761,462) \path(1086,12)(1761,12) \spline(1086,462) (636,462)(636,12)(1086,12) \spline(1761,462) (2211,462)(2211,12)(1761,12) \path(1086,9238)(1761,9238) \path(1086,8788)(1761,8788) \spline(1086,9238) (636,9238)(636,8788)(1086,8788) \spline(1761,9238) (2211,9238)(2211,8788)(1761,8788) \put(1401,8953){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}ewald()}}}}} \path(1416,8788)(1416,8563) \blacken\path(1386.000,8683.000)(1416.000,8563.000)(1446.000,8683.000)(1386.000,8683.000) \path(416,8218)(1416,8563)(2441,8218) (1416,7888)(416,8218) \path(2982,8563)(4782,8563)(4782,7888) (2982,7888)(2982,8563) \path(2442,8219)(2982,8219) \blacken\path(2862.000,8189.000)(2982.000,8219.000)(2862.000,8249.000)(2862.000,8189.000) \path(3882,7888)(3882,7663)(1425,7663) \blacken\path(1545.000,7693.000)(1425.000,7663.000)(1545.000,7633.000)(1545.000,7693.000) \path(1416,7893)(1416,7443) \blacken\path(1386.000,7563.000)(1416.000,7443.000)(1446.000,7563.000)(1386.000,7563.000) \path(1416,689)(2991,689)(2991,4399)(2444,4399) \blacken\path(2564.000,4429.000)(2444.000,4399.000)(2564.000,4369.000)(2564.000,4429.000) \path(1416,1583)(1416,1363) \blacken\path(1386.000,1483.000)(1416.000,1363.000)(1446.000,1483.000)(1386.000,1483.000) \path(1416,913)(1416,463) \blacken\path(1386.000,583.000)(1416.000,463.000)(1446.000,583.000)(1386.000,583.000) \path(1416,2258)(1416,2038) \blacken\path(1386.000,2158.000)(1416.000,2038.000)(1446.000,2158.000)(1386.000,2158.000) \path(1416,3380)(1416,3160) \blacken\path(1386.000,3280.000)(1416.000,3160.000)(1446.000,3280.000)(1386.000,3280.000) \path(1416,4061)(1416,3841) \blacken\path(1386.000,3961.000)(1416.000,3841.000)(1446.000,3961.000)(1386.000,3961.000) \path(1416,4961)(1416,4741) \blacken\path(1386.000,4861.000)(1416.000,4741.000)(1446.000,4861.000)(1386.000,4861.000) \path(416,4396)(1416,4741)(2441,4396) (1416,4063)(416,4396) \path(1416,5861)(1416,5641) \blacken\path(1386.000,5761.000)(1416.000,5641.000)(1446.000,5761.000)(1386.000,5761.000) \path(1416,6761)(1416,6541) \blacken\path(1386.000,6661.000)(1416.000,6541.000)(1446.000,6661.000)(1386.000,6661.000) \path(516,7443)(2316,7443)(2316,6768) (516,6768)(516,7443) \put(3117,8005){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}terms}}}}} \put(3117,8346){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Calculate self-}}}}} \put(3117,8171){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}and sheet-energy }}}}} \put(1416,8167){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}first call?}}}}} \put(1416,4274){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}\emph{k}-vectors}}}}} \put(1416,4456){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}loop over}}}}} \put(576,7233){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Precompute list of}}}}} \put(576,7044){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}$h,k,l$ for \emph{k}-vectors}}}}} \put(576,6855){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}within cutoff}}}}} \put(1401,193){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}}}} \end{picture} } $EOD $! $CREATE fig_link-cell-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(9933,11064)(0,-10) \path(462,1812)(1137,1812) \path(462,1362)(1137,1362) \spline(462,1812) (12,1812)(12,1362)(462,1362) \spline(1137,1812) (1587,1812)(1587,1362)(1137,1362) \path(6312,462)(6987,462) \path(6312,12)(6987,12) \spline(6312,462) (5862,462)(5862,12)(6312,12) \spline(6987,462) (7437,462)(7437,12)(6987,12) \path(6312,11037)(6987,11037) \path(6312,10587)(6987,10587) \spline(6312,11037) (5862,11037)(5862,10587)(6312,10587) \spline(6987,11037) (7437,11037)(7437,10587)(6987,10587) \path(462,11037)(1137,11037) \path(462,10587)(1137,10587) \spline(462,11037) (12,11037)(12,10587)(462,10587) \spline(1137,11037) (1587,11037)(1587,10587)(1137,10587) \put(822,2727){\ellipse{1620}{900}} \put(6650,8983){\ellipse{2760}{1110}} \put(6635,3159){\ellipse{2460}{870}} \put(822,4069){\ellipse{1620}{900}} \put(2262,7812){\ellipse{1980}{450}} \put(2352,6649){\ellipse{2430}{540}} \drawline(6639,6549)(6639,6549) \path(9696,3790)(9921,4600)(8346,4600) (8121,3790)(9696,3790) \drawline(6621,924)(6621,924) \path(5405,2499)(7880,2499)(7880,1824) (5405,1824)(5405,2499) \path(5390,1599)(7865,1599)(7865,924) (5390,924)(5390,1599) \path(5622,4183)(6620,4528)(7647,4183) (6635,3853)(5622,4183) \path(5390,5413)(7865,5413)(7865,4738) (5390,4738)(5390,5413) \path(5405,6328)(7880,6328)(7880,5653) (5405,5653)(5405,6328) \path(5622,6883)(6620,7228)(7647,6883) (6635,6553)(5622,6883) \path(5390,8128)(7865,8128)(7865,7453) (5390,7453)(5390,8128) \path(5622,10048)(6620,10393)(7647,10048) (6635,9718)(5622,10048) \path(792,2277)(792,1827) \blacken\path(762.000,1947.000)(792.000,1827.000)(822.000,1947.000)(762.000,1947.000) \path(6636,9717)(6639,9537) \blacken\path(6607.004,9656.483)(6639.000,9537.000)(6666.996,9657.483)(6607.004,9656.483) \path(6625,8428)(6625,8128) \blacken\path(6595.000,8248.000)(6625.000,8128.000)(6655.000,8248.000)(6595.000,8248.000) \path(6633,6552)(6632,6332) \blacken\path(6602.546,6452.135)(6632.000,6332.000)(6662.545,6451.862)(6602.546,6452.135) \path(6625,5657)(6625,5417) \blacken\path(6595.000,5537.000)(6625.000,5417.000)(6655.000,5537.000)(6595.000,5537.000) \path(6610,2725)(6610,2507) \blacken\path(6580.000,2627.000)(6610.000,2507.000)(6640.000,2627.000)(6580.000,2627.000) \path(6610,1832)(6609,1596) \blacken\path(6579.509,1716.126)(6609.000,1596.000)(6639.508,1715.872)(6579.509,1716.126) \path(6628,924)(6628,459) \blacken\path(6598.000,579.000)(6628.000,459.000)(6658.000,579.000)(6598.000,579.000) \path(6628,691)(4941,691)(4942,10047)(5623,10048) \blacken\path(5503.044,10017.824)(5623.000,10048.000)(5502.956,10077.824)(5503.044,10017.824) \path(5167,702)(5167,6883)(5631,6883) \blacken\path(5511.000,6853.000)(5631.000,6883.000)(5511.000,6913.000)(5511.000,6853.000) \path(6625,10393)(6624,10578) \blacken\path(6594.352,10512.836)(6625.000,10393.000)(6654.351,10513.160)(6594.352,10512.836) \path(6621,7230)(6624,7449) \blacken\path(6592.646,7350.400)(6621.000,7230.000)(6652.641,7349.578)(6592.646,7350.400) \dashline{90.000}(1625,2757)(4295,2757)(4287,10821)(5854,10821) \blacken\path(5734.000,10791.000)(5854.000,10821.000)(5734.000,10851.000)(5734.000,10791.000) \path(7647,4183)(8232,4183) \blacken\path(8112.000,4153.000)(8232.000,4183.000)(8112.000,4213.000)(8112.000,4153.000) \dashline{90.000}(1632,2667)(4287,2667)(4287,237)(5839,237) \blacken\path(4407.000,267.000)(4287.000,237.000)(4407.000,207.000)(4407.000,267.000) \path(6619,4530)(6618,4731) \blacken\path(6588.403,4649.849)(6619.000,4530.000)(6648.403,4650.148)(6588.403,4649.849) \path(6634,3854)(6634,3591) \blacken\path(6604.000,3711.000)(6634.000,3591.000)(6664.000,3711.000)(6604.000,3711.000) \path(2037,10152)(3612,10152)(3612,9252) (2037,9252)(2037,10152) \path(12,9657)(797,10332)(1587,9657) (807,8982)(12,9657) \path(12,8577)(3612,8577)(3612,6327) (12,6327)(12,8577) \path(12,5877)(1587,5877)(1587,4977) (12,4977)(12,5877) \path(124,7206)(909,7671)(1699,7206) (919,6758)(124,7206) \path(1587,9657)(2037,9657) \blacken\path(1917.000,9627.000)(2037.000,9657.000)(1917.000,9687.000)(1917.000,9627.000) \path(2802,9252)(2802,8787)(822,8787) \blacken\path(942.000,8817.000)(822.000,8787.000)(942.000,8757.000)(942.000,8817.000) \path(777,6327)(777,5877) \blacken\path(747.000,5997.000)(777.000,5877.000)(807.000,5997.000)(747.000,5997.000) \path(909,7671)(909,7815)(1287,7812) \blacken\path(1166.766,7782.953)(1287.000,7812.000)(1167.242,7842.951)(1166.766,7782.953) \path(918,6756)(918,6642)(1131,6639) \blacken\path(1010.589,6610.693)(1131.000,6639.000)(1011.434,6670.687)(1010.589,6610.693) \path(804,8982)(804,8577) \blacken\path(774.000,8697.000)(804.000,8577.000)(834.000,8697.000)(774.000,8697.000) \path(795,10332)(798,10587) \blacken\path(766.414,10452.345)(795.000,10332.000)(826.410,10451.639)(766.414,10452.345) \path(797,3617)(797,3182) \blacken\path(767.000,3302.000)(797.000,3182.000)(827.000,3302.000)(767.000,3302.000) \path(792,4977)(792,4527) \blacken\path(762.000,4647.000)(792.000,4527.000)(822.000,4647.000)(762.000,4647.000) \put(7656,4300){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(6778,3685){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(822,2682){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_inner()}}}}} \put(822,1527){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}}}} \put(6590,206){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}}}} \put(6590,3341){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}kernel()}}}}} \put(6650,9110){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}site\_neighbour\_list()}}}}} \put(9081,4112){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Print warning.}}}}} \put(6620,2859){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}on neighbour list.}}}}} \put(6665,4062){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}site approaches}}}}} \put(6650,4227){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}test for close}}}}} \put(6650,6972){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}loop over}}}}} \put(6665,8622){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}range of current cell.}}}}} \put(6665,8870){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Build list of all sites within}}}}} \put(6702,9987){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}loop- over all cells}}}}} \put(5525,1344){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Distribute neighbour list}}}}} \put(5525,1989){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}on sites in neighbour list.}}}}} \put(5437,7635){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}vectors into neighbour lists}}}}} \put(5437,7860){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gather site co-ords reloc,}}}}} \put(5459,6060){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Gather potential params}}}}} \put(5459,5790){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}into neighbour list arrays.}}}}} \put(5450,5145){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calculate squared pair site}}}}} \put(5450,4920){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}distances in neighbour list.}}}}} \put(6620,3099){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Evaluate potential \& force}}}}} \put(5525,2214){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Calculate stress \& forces}}}}} \put(5525,1119){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}forces onto force array.}}}}} \put(237,8322){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Create list of neighbouring cells.}}}}} \put(777,10752){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force()}}}}} \put(2262,7767){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}neighbour\_list()}}}}} \put(1587,9882){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(957,8892){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(2802,9927){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Set up arrays of}}}}} \put(2832,9702){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}P.B.C. relocation}}}}} \put(2517,9477){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}vectors.}}}}} \put(2337,6603){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}site\_neighbour\_list()}}}}} \put(768,6540){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(792,7884){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(87,5607){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Allocate and fill}}}}} \put(87,5157){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}of pot'l params.}}}}} \put(87,5382){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}expanded array}}}}} \put(827,4222){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}fill\_cells()}}}}} \put(827,4022){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Build linked list }}}}} \put(822,3832){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}of mols in cells}}}}} \put(913,7167){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}strict cutoff?}}}}} \put(6635,6642){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}in cell}}}}} \put(6635,6815){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}molecules and sites}}}}} \put(800,9332){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}changed.}}}}} \put(770,9557){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} cell size/shape}}}}} \put(800,9760){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}first call or}}}}} \put(6665,10738){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_inner()}}}}} \end{picture} } $EOD $! $CREATE fig_main-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(8798,10839)(0,-10) \path(2123,10812)(2798,10812) \path(2123,10362)(2798,10362) \spline(2123,10812) (1673,10812)(1673,10362)(2123,10362) \spline(2798,10812) (3248,10812)(3248,10362)(2798,10362) \path(2168,462)(2843,462) \path(2168,12)(2843,12) \spline(2168,462) (1718,462)(1718,12)(2168,12) \spline(2843,462) (3293,462)(3293,12)(2843,12) \put(908,1137){\ellipse{1800}{630}} \put(5183,3477){\ellipse{1800}{630}} \put(5183,4377){\ellipse{1800}{630}} \put(2483,9822){\ellipse{1800}{630}} \put(2483,8022){\ellipse{1800}{630}} \put(2483,7122){\ellipse{1800}{630}} \put(4058,1137){\ellipse{1800}{630}} \put(5183,5299){\ellipse{1800}{630}} \put(6835,9007){\ellipse{1800}{630}} \put(7870,8242){\ellipse{1800}{630}} \put(4720,9007){\ellipse{1800}{630}} \put(7890,7349){\ellipse{1800}{630}} \put(5183,6177){\ellipse{1800}{630}} \put(5183,2577){\ellipse{1800}{630}} \path(3383,4377)(2483,4737)(1583,4377) (2483,4017)(3383,4377) \path(3383,3477)(2483,3837)(1583,3477) (2483,3117)(3383,3477) \path(3383,2576)(2483,2936)(1583,2576) (2483,2216)(3383,2576) \path(3383,1676)(2483,2036)(1583,1676) (2483,1316)(3383,1676) \path(2483,10362)(2483,10137) \blacken\path(2453.000,10257.000)(2483.000,10137.000)(2513.000,10257.000)(2453.000,10257.000) \path(2483,8533)(2483,8344) \blacken\path(2453.000,8464.000)(2483.000,8344.000)(2513.000,8464.000)(2453.000,8464.000) \path(2483,7707)(2483,7441) \blacken\path(2453.000,7561.000)(2483.000,7441.000)(2513.000,7561.000)(2453.000,7561.000) \path(2483,6807)(2483,6537) \blacken\path(2453.000,6657.000)(2483.000,6537.000)(2513.000,6657.000)(2453.000,6657.000) \path(2483,4917)(2483,4737) \blacken\path(2453.000,4857.000)(2483.000,4737.000)(2513.000,4857.000)(2453.000,4857.000) \path(2483,4017)(2483,3837) \blacken\path(2453.000,3957.000)(2483.000,3837.000)(2513.000,3957.000)(2453.000,3957.000) \path(2483,3117)(2483,2937) \blacken\path(2453.000,3057.000)(2483.000,2937.000)(2513.000,3057.000)(2453.000,3057.000) \path(3382,1677)(4058,1677)(4058,1452) \blacken\path(4028.000,1572.000)(4058.000,1452.000)(4088.000,1572.000)(4028.000,1572.000) \path(2483,2186)(1358,2186)(1358,8885)(1572,8890) \blacken\path(1452.733,8857.205)(1572.000,8890.000)(1451.332,8917.189)(1452.733,8857.205) \path(3383,5277)(4283,5277) \blacken\path(4163.000,5247.000)(4283.000,5277.000)(4163.000,5307.000)(4163.000,5247.000) \path(3383,4377)(4283,4377) \blacken\path(4163.000,4347.000)(4283.000,4377.000)(4163.000,4407.000)(4163.000,4347.000) \path(3383,3477)(4283,3477) \blacken\path(4163.000,3447.000)(4283.000,3477.000)(4163.000,3507.000)(4163.000,3447.000) \path(3383,2577)(4283,2577) \blacken\path(4163.000,2547.000)(4283.000,2577.000)(4163.000,2607.000)(4163.000,2547.000) \path(2483,686)(2483,456) \blacken\path(2453.000,576.000)(2483.000,456.000)(2513.000,576.000)(2453.000,576.000) \path(2483,2216)(2483,2036) \blacken\path(2453.000,2156.000)(2483.000,2036.000)(2513.000,2156.000)(2453.000,2156.000) \path(4058,822)(4058,686)(2483,686) \path(2498,4804)(5183,4804)(5183,4984) \blacken\path(5153.000,4924.000)(5183.000,4804.000)(5213.000,4924.000)(5153.000,4924.000) \path(2498,3904)(5183,3904)(5183,4069) \blacken\path(5153.000,4024.000)(5183.000,3904.000)(5213.000,4024.000)(5153.000,4024.000) \path(2498,3019)(5198,3019)(5198,3154) \blacken\path(5168.000,3139.000)(5198.000,3019.000)(5228.000,3139.000)(5168.000,3139.000) \path(2483,2186)(5183,2186)(5183,2254) \blacken\path(5153.000,2306.000)(5183.000,2186.000)(5213.000,2306.000)(5153.000,2306.000) \path(908,1452)(908,1677)(1583,1677) \blacken\path(1028.000,1707.000)(908.000,1677.000)(1028.000,1647.000)(1028.000,1707.000) \dashline{90.000}(3383,8025)(3821,9014) \blacken\path(3404.162,8146.869)(3383.000,8025.000)(3459.023,8122.573)(3404.162,8146.869) \blacken\path(3799.838,8892.131)(3821.000,9014.000)(3744.977,8916.427)(3799.838,8892.131) \dashline{90.000}(7300,8744)(7510,8549) \blacken\path(7401.651,8608.670)(7510.000,8549.000)(7442.478,8652.638)(7401.651,8608.670) \path(6090,7349)(6990,7349) \blacken\path(6870.000,7319.000)(6990.000,7349.000)(6870.000,7379.000)(6870.000,7319.000) \path(3383,6177)(2483,6537)(1583,6177) (2483,5817)(3383,6177) \path(3383,6177)(4283,6177) \blacken\path(4163.000,6147.000)(4283.000,6177.000)(4163.000,6207.000)(4163.000,6147.000) \path(2483,5719)(5183,5719)(5183,5854) \blacken\path(5153.000,5839.000)(5183.000,5719.000)(5213.000,5839.000)(5153.000,5839.000) \path(3383,8892)(2483,9252)(1583,8892) (2483,8532)(3383,8892) \path(2483,9507)(2483,9252) \blacken\path(2453.000,9372.000)(2483.000,9252.000)(2513.000,9372.000)(2453.000,9372.000) \path(3388,5276)(2488,5636)(1588,5276) (2488,4916)(3388,5276) \path(2483,5817)(2483,5636) \blacken\path(2453.000,5756.000)(2483.000,5636.000)(2513.000,5756.000)(2453.000,5756.000) \path(908,822)(908,686)(2483,686) \dashline{90.000}(3383,8010)(4290,7349) \blacken\path(3497.648,7963.569)(3383.000,8010.000)(3462.310,7915.079)(3497.648,7963.569) \blacken\path(4175.352,7395.431)(4290.000,7349.000)(4210.690,7443.921)(4175.352,7395.431) \path(6090,7349)(5190,7709)(4290,7349) (5190,6989)(6090,7349) \dashline{90.000}(5624,9006)(5935,9006) \blacken\path(5815.000,8976.000)(5935.000,9006.000)(5815.000,9036.000)(5815.000,8976.000) \put(2484,9021){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}loop}}}}} \put(3390,1813){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}on}}}}} \put(1575,1828){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}off}}}}} \put(2477,9915){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}start\_up()}}}}} \put(6809,9112){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rdf\_inner()}}}}} \put(7904,7456){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump()}}}}} \put(2477,8100){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}do\_step()}}}}} \put(2482,7210){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}values()}}}}} \put(2492,6132){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}print\_interval}}}}} \put(2484,5232){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}scale\_interval}}}}} \put(2492,1648){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}text\_mode\_save}}}}} \put(5199,7304){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dump\_interval}}}}} \put(5192,6305){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}output()}}}}} \put(5192,5405){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rescale()}}}}} \put(5187,4475){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}averages()}}}}} \put(5172,3575){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}print\_rdf()}}}}} \put(4052,1205){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}print\_config()}}}}} \put(2482,195){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}exit()}}}}} \put(902,1145){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}write\_restart()}}}}} \put(2483,5426){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}}}} \put(5198,7481){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}}}} \put(2483,2711){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}}}} \put(2483,6301){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}}}} \put(2483,5951){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}}}} \put(2483,4151){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}}}} \put(2483,5051){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}}}} \put(2468,4511){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}}}} \put(2483,3606){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}every}}}}} \put(2484,3435){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rdf\_out}}}}} \put(2478,3251){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}}}} \put(5213,7136){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}}}} \put(5197,3344){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}calc/print RDFs}}}}} \put(5182,5149){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}scale velocities}}}}} \put(907,963){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write save file}}}}} \put(5182,4287){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}calc/print averages}}}}} \put(6849,8900){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}link-cell RDF calc}}}}} \put(7898,7236){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write trajectories}}}}} \put(4072,996){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write text restart}}}}} \put(5190,2429){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write backup file}}}}} \put(2477,7026){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}log thermo. values}}}}} \put(2483,7906){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}Step co-ords by \textit{dt}}}}}} \put(2484,9713){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}input/initialization}}}}} \put(5184,6089){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}periodic write}}}}} \put(2482,10527){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}main()}}}}} \put(2484,8676){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}istep}}}}} \put(2484,8842){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}over timesteps}}}}} \put(4764,9037){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}force\_calc()}}}}} \put(7894,8112){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}bin pair distances}}}}} \put(7879,8309){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}rdf\_accum()}}}}} \put(2484,4325){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}average\_interval}}}}} \put(2483,2351){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\rmdefault}{\mddefault}{\updefault}steps}}}}} \put(2484,2510){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}backup\_interval}}}}} \put(5192,2593){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}write\_restart()}}}}} \end{picture} } $EOD $! $CREATE fig_skewstart-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(10761,5528)(0,-10) \put(4322,4194){\blacken\ellipse{174}{174}} \put(4322,4194){\ellipse{174}{174}} \put(4474,4194){\blacken\ellipse{174}{174}} \put(4474,4194){\ellipse{174}{174}} \put(966,3497){\blacken\ellipse{174}{174}} \put(966,3497){\ellipse{174}{174}} \put(1119,3497){\blacken\ellipse{174}{174}} \put(1119,3497){\ellipse{174}{174}} \put(1816,3672){\blacken\ellipse{174}{174}} \put(1816,3672){\ellipse{174}{174}} \put(1990,3672){\blacken\ellipse{174}{174}} \put(1990,3672){\ellipse{174}{174}} \put(5171,4325){\blacken\ellipse{174}{174}} \put(5171,4325){\ellipse{174}{174}} \put(5324,4325){\blacken\ellipse{174}{174}} \put(5324,4325){\ellipse{174}{174}} \put(5607,4499){\blacken\ellipse{174}{174}} \put(5607,4499){\ellipse{174}{174}} \put(5607,4325){\blacken\ellipse{174}{174}} \put(5607,4325){\ellipse{174}{174}} \put(6021,4499){\blacken\ellipse{174}{174}} \put(6021,4499){\ellipse{174}{174}} \put(6195,4499){\blacken\ellipse{174}{174}} \put(6195,4499){\ellipse{174}{174}} \put(6522,4695){\blacken\ellipse{174}{174}} \put(6522,4695){\ellipse{174}{174}} \put(6522,4521){\blacken\ellipse{174}{174}} \put(6522,4521){\ellipse{174}{174}} \put(6827,4695){\blacken\ellipse{174}{174}} \put(6827,4695){\ellipse{174}{174}} \put(6980,4695){\blacken\ellipse{174}{174}} \put(6980,4695){\ellipse{174}{174}} \put(7677,4870){\blacken\ellipse{174}{174}} \put(7677,4870){\ellipse{174}{174}} \put(7829,4870){\blacken\ellipse{174}{174}} \put(7829,4870){\ellipse{174}{174}} \put(8527,5044){\blacken\ellipse{174}{174}} \put(8527,5044){\ellipse{174}{174}} \put(8679,5044){\blacken\ellipse{174}{174}} \put(8679,5044){\ellipse{174}{174}} \put(9355,5218){\blacken\ellipse{174}{174}} \put(9355,5218){\ellipse{174}{174}} \put(9507,5218){\blacken\ellipse{174}{174}} \put(9507,5218){\ellipse{174}{174}} \put(95,3301){\blacken\ellipse{174}{174}} \put(95,3301){\ellipse{174}{174}} \put(247,3301){\blacken\ellipse{174}{174}} \put(247,3301){\ellipse{174}{174}} \put(596,3475){\blacken\ellipse{174}{174}} \put(596,3475){\ellipse{174}{174}} \put(596,3301){\blacken\ellipse{174}{174}} \put(596,3301){\ellipse{174}{174}} \put(1424,3628){\blacken\ellipse{174}{174}} \put(1424,3628){\ellipse{174}{174}} \put(1424,3475){\blacken\ellipse{174}{174}} \put(1424,3475){\ellipse{174}{174}} \put(2295,3824){\blacken\ellipse{174}{174}} \put(2295,3824){\ellipse{174}{174}} \put(2295,3650){\blacken\ellipse{174}{174}} \put(2295,3650){\ellipse{174}{174}} \put(2644,3824){\blacken\ellipse{174}{174}} \put(2644,3824){\ellipse{174}{174}} \put(2796,3824){\blacken\ellipse{174}{174}} \put(2796,3824){\ellipse{174}{174}} \put(3101,3977){\blacken\ellipse{174}{174}} \put(3101,3977){\ellipse{174}{174}} \put(3101,3824){\blacken\ellipse{174}{174}} \put(3101,3824){\ellipse{174}{174}} \put(3472,3998){\blacken\ellipse{174}{174}} \put(3472,3998){\ellipse{174}{174}} \put(3624,3998){\blacken\ellipse{174}{174}} \put(3624,3998){\ellipse{174}{174}} \put(3908,4151){\blacken\ellipse{174}{174}} \put(3908,4151){\ellipse{174}{174}} \put(3908,3998){\blacken\ellipse{174}{174}} \put(3908,3998){\ellipse{174}{174}} \put(7307,4870){\blacken\ellipse{174}{174}} \put(7307,4870){\ellipse{174}{174}} \put(7307,4695){\blacken\ellipse{174}{174}} \put(7307,4695){\ellipse{174}{174}} \put(8134,5022){\blacken\ellipse{174}{174}} \put(8134,5022){\ellipse{174}{174}} \put(8134,4870){\blacken\ellipse{174}{174}} \put(8134,4870){\ellipse{174}{174}} \put(8984,5196){\blacken\ellipse{174}{174}} \put(8984,5196){\ellipse{174}{174}} \put(8984,5044){\blacken\ellipse{174}{174}} \put(8984,5044){\ellipse{174}{174}} \put(9812,5371){\blacken\ellipse{174}{174}} \put(9812,5371){\ellipse{174}{174}} \put(9812,5218){\blacken\ellipse{174}{174}} \put(9812,5218){\ellipse{174}{174}} \put(10226,5371){\blacken\ellipse{174}{174}} \put(10226,5371){\ellipse{174}{174}} \put(10379,5371){\blacken\ellipse{174}{174}} \put(10379,5371){\ellipse{174}{174}} \put(4322,2364){\blacken\ellipse{174}{174}} \put(4322,2364){\ellipse{174}{174}} \put(4474,2364){\blacken\ellipse{174}{174}} \put(4474,2364){\ellipse{174}{174}} \put(4779,2517){\blacken\ellipse{174}{174}} \put(4779,2517){\ellipse{174}{174}} \put(4779,2364){\blacken\ellipse{174}{174}} \put(4779,2364){\ellipse{174}{174}} \put(5171,2517){\blacken\ellipse{174}{174}} \put(5171,2517){\ellipse{174}{174}} \put(5324,2517){\blacken\ellipse{174}{174}} \put(5324,2517){\ellipse{174}{174}} \put(5607,2669){\blacken\ellipse{174}{174}} \put(5607,2669){\ellipse{174}{174}} \put(5607,2517){\blacken\ellipse{174}{174}} \put(5607,2517){\ellipse{174}{174}} \put(6021,2691){\blacken\ellipse{174}{174}} \put(6021,2691){\ellipse{174}{174}} \put(6195,2691){\blacken\ellipse{174}{174}} \put(6195,2691){\ellipse{174}{174}} \put(6152,2364){\blacken\ellipse{174}{174}} \put(6152,2364){\ellipse{174}{174}} \put(6152,2190){\blacken\ellipse{174}{174}} \put(6152,2190){\ellipse{174}{174}} \put(5672,2190){\blacken\ellipse{174}{174}} \put(5672,2190){\ellipse{174}{174}} \put(5825,2190){\blacken\ellipse{174}{174}} \put(5825,2190){\ellipse{174}{174}} \put(5237,2168){\blacken\ellipse{174}{174}} \put(5237,2168){\ellipse{174}{174}} \put(5237,2016){\blacken\ellipse{174}{174}} \put(5237,2016){\ellipse{174}{174}} \put(4801,2016){\blacken\ellipse{174}{174}} \put(4801,2016){\ellipse{174}{174}} \put(4953,2016){\blacken\ellipse{174}{174}} \put(4953,2016){\ellipse{174}{174}} \put(4409,1188){\blacken\ellipse{174}{174}} \put(4409,1188){\ellipse{174}{174}} \put(4409,1014){\blacken\ellipse{174}{174}} \put(4409,1014){\ellipse{174}{174}} \put(4801,1188){\blacken\ellipse{174}{174}} \put(4801,1188){\ellipse{174}{174}} \put(4953,1188){\blacken\ellipse{174}{174}} \put(4953,1188){\ellipse{174}{174}} \put(5237,1341){\blacken\ellipse{174}{174}} \put(5237,1341){\ellipse{174}{174}} \put(5237,1188){\blacken\ellipse{174}{174}} \put(5237,1188){\ellipse{174}{174}} \put(5672,1362){\blacken\ellipse{174}{174}} \put(5672,1362){\ellipse{174}{174}} \put(5825,1362){\blacken\ellipse{174}{174}} \put(5825,1362){\ellipse{174}{174}} \put(6152,1537){\blacken\ellipse{174}{174}} \put(6152,1537){\ellipse{174}{174}} \put(6152,1362){\blacken\ellipse{174}{174}} \put(6152,1362){\ellipse{174}{174}} \put(4779,818){\blacken\ellipse{174}{174}} \put(4779,818){\ellipse{174}{174}} \put(4779,665){\blacken\ellipse{174}{174}} \put(4779,665){\ellipse{174}{174}} \put(5171,818){\blacken\ellipse{174}{174}} \put(5171,818){\ellipse{174}{174}} \put(5324,818){\blacken\ellipse{174}{174}} \put(5324,818){\ellipse{174}{174}} \put(5607,992){\blacken\ellipse{174}{174}} \put(5607,992){\ellipse{174}{174}} \put(5607,818){\blacken\ellipse{174}{174}} \put(5607,818){\ellipse{174}{174}} \put(6021,992){\blacken\ellipse{174}{174}} \put(6021,992){\ellipse{174}{174}} \put(6195,992){\blacken\ellipse{174}{174}} \put(6195,992){\ellipse{174}{174}} \put(4322,665){\blacken\ellipse{174}{174}} \put(4322,665){\ellipse{174}{174}} \put(4474,665){\blacken\ellipse{174}{174}} \put(4474,665){\ellipse{174}{174}} \put(4409,2016){\blacken\ellipse{174}{174}} \put(4409,2016){\ellipse{174}{174}} \put(4409,1842){\blacken\ellipse{174}{174}} \put(4409,1842){\ellipse{174}{174}} \put(4322,1515){\blacken\ellipse{174}{174}} \put(4322,1515){\ellipse{174}{174}} \put(4474,1515){\blacken\ellipse{174}{174}} \put(4474,1515){\ellipse{174}{174}} \put(4779,1667){\blacken\ellipse{174}{174}} \put(4779,1667){\ellipse{174}{174}} \put(4779,1515){\blacken\ellipse{174}{174}} \put(4779,1515){\ellipse{174}{174}} \put(5171,1667){\blacken\ellipse{174}{174}} \put(5171,1667){\ellipse{174}{174}} \put(5324,1667){\blacken\ellipse{174}{174}} \put(5324,1667){\ellipse{174}{174}} \put(6021,1842){\blacken\ellipse{174}{174}} \put(6021,1842){\ellipse{174}{174}} \put(6195,1842){\blacken\ellipse{174}{174}} \put(6195,1842){\ellipse{174}{174}} \put(5607,1820){\blacken\ellipse{174}{174}} \put(5607,1820){\ellipse{174}{174}} \put(5607,1667){\blacken\ellipse{174}{174}} \put(5607,1667){\ellipse{174}{174}} \put(4779,4325){\blacken\ellipse{174}{174}} \put(4779,4325){\ellipse{174}{174}} \put(4779,4173){\blacken\ellipse{174}{174}} \put(4779,4173){\ellipse{174}{174}} \path(2295,5480)(2295,3301) \path(4409,5480)(4409,3301) \path(6522,5480)(6522,3301) \path(8636,5480)(8636,3301) \drawline(4409,1101)(4409,1101) \dottedline{22}(4409,665)(6522,1101) \dottedline{22}(4409,1101)(6522,1515) \dottedline{22}(4409,1515)(6522,1929) \path(6522,2364)(7241,2517) \path(6522,1929)(7328,2103) \path(4779,752)(4888,12) \dottedline{22}(4409,1929)(6522,2364) \path(10749,3301)(10749,5480)(182,5480) (182,3301)(10749,3301) \dottedline{22}(182,3301)(10749,5501) \path(5258,861)(5367,121) \path(5455,273)(5346,339)(5411,469) \path(4714,339)(4844,251)(4757,99) \path(6958,2582)(6871,2452)(6762,2517) \path(6849,1885)(6936,2016)(7067,1929) \dottedline{22}(4409,2364)(6522,2778) \path(6522,665)(6522,2778)(4409,2778) (4409,665)(6522,665) \put(6849,2168){\makebox(0,0)[lb]{\smash{{{\SetFigFont{14}{16.8}{\rmdefault}{\mddefault}{\updefault}d}}}}} \put(5019,251){\makebox(0,0)[lb]{\smash{{{\SetFigFont{14}{16.8}{\rmdefault}{\mddefault}{\updefault}a}}}}} \end{picture} } $EOD $! $CREATE fig_startup-a-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(6096,10389)(0,-10) \path(573,10362)(1248,10362) \path(573,9912)(1248,9912) \spline(573,10362) (123,10362)(123,9912)(573,9912) \spline(1248,10362) (1698,10362)(1698,9912)(1248,9912) \path(2718,4847)(3393,4847) \path(2718,4397)(3393,4397) \spline(2718,4847) (2268,4847)(2268,4397)(2718,4397) \spline(3393,4847) (3843,4847)(3843,4397)(3393,4397) \put(3389,8448){\ellipse{1800}{676}} \put(3394,7549){\ellipse{1800}{676}} \put(3394,6649){\ellipse{1800}{676}} \put(3394,5744){\ellipse{1800}{676}} \path(3394,8113)(3394,7887) \blacken\path(3364.000,8007.000)(3394.000,7887.000)(3424.000,8007.000)(3364.000,8007.000) \path(3394,7213)(3394,6987) \blacken\path(3364.000,7107.000)(3394.000,6987.000)(3424.000,7107.000)(3364.000,7107.000) \path(3394,6313)(3394,6087) \blacken\path(3364.000,6207.000)(3394.000,6087.000)(3424.000,6207.000)(3364.000,6207.000) \path(4873,462)(5548,462) \path(4873,12)(5548,12) \spline(4873,462) (4423,462)(4423,12)(4873,12) \spline(5548,462) (5998,462)(5998,12)(5548,12) \put(913,7997){\ellipse{1800}{676}} \put(3388,1477){\ellipse{670}{670}} \put(913,372){\ellipse{670}{670}} \put(3388,2597){\ellipse{670}{670}} \put(913,6872){\ellipse{1800}{676}} \put(908,9122){\ellipse{1800}{676}} \put(5188,2372){\ellipse{670}{670}} \put(5188,1247){\ellipse{1800}{676}} \path(913,9912)(913,9462) \blacken\path(883.000,9582.000)(913.000,9462.000)(943.000,9582.000)(883.000,9582.000) \path(913,8787)(913,8337) \blacken\path(883.000,8457.000)(913.000,8337.000)(943.000,8457.000)(883.000,8457.000) \path(913,7662)(913,7212) \blacken\path(883.000,7332.000)(913.000,7212.000)(943.000,7332.000)(883.000,7332.000) \path(1813,2607)(913,2967)(13,2607) (913,2247)(1813,2607) \path(1813,1477)(913,1837)(13,1477) (913,1117)(1813,1477) \path(918,3382)(918,2967) \blacken\path(888.000,3087.000)(918.000,2967.000)(948.000,3087.000)(888.000,3087.000) \path(913,2247)(913,1827) \blacken\path(883.000,1947.000)(913.000,1827.000)(943.000,1947.000)(883.000,1947.000) \path(913,1117)(913,717) \blacken\path(883.000,837.000)(913.000,717.000)(943.000,837.000)(883.000,837.000) \path(1823,5742)(2263,5742)(2263,9012) (3388,9012)(3388,8787) \blacken\path(3358.000,8907.000)(3388.000,8787.000)(3418.000,8907.000)(3358.000,8907.000) \path(1813,4622)(2268,4622) \blacken\path(2148.000,4592.000)(2268.000,4622.000)(2148.000,4652.000)(2148.000,4592.000) \path(1808,2602)(3053,2602) \blacken\path(2933.000,2572.000)(3053.000,2602.000)(2933.000,2632.000)(2933.000,2572.000) \path(1818,1472)(3053,1472) \blacken\path(2933.000,1442.000)(3053.000,1472.000)(2933.000,1502.000)(2933.000,1442.000) \path(1818,5742)(918,6102)(18,5742) (918,5382)(1818,5742) \path(918,6537)(918,6102) \blacken\path(888.000,6222.000)(918.000,6102.000)(948.000,6222.000)(888.000,6222.000) \path(1813,4627)(913,4987)(13,4627) (913,4267)(1813,4627) \path(913,5382)(913,4987) \blacken\path(883.000,5107.000)(913.000,4987.000)(943.000,5107.000)(883.000,5107.000) \path(3388,5417)(3388,5187)(913,5187) \blacken\path(1033.000,5217.000)(913.000,5187.000)(1033.000,5157.000)(1033.000,5217.000) \path(123,3837)(1698,3837)(1698,3387) (123,3387)(123,3837) \path(913,4262)(913,3837) \blacken\path(883.000,3957.000)(913.000,3837.000)(943.000,3957.000)(883.000,3957.000) \path(5188,2037)(5188,1582) \blacken\path(5158.000,1702.000)(5188.000,1582.000)(5218.000,1702.000)(5158.000,1702.000) \path(5188,912)(5188,462) \blacken\path(5158.000,582.000)(5188.000,462.000)(5218.000,582.000)(5158.000,582.000) \put(913,5702){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}restart?}}}}} \put(1808,5862){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(693,5062){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(913,4402){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}exist?}}}}} \put(1808,4757){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(3053,4572){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Abort}}}}} \put(693,4112){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(908,2667){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}backup}}}}} \put(908,2487){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}file exists?}}}}} \put(1813,2722){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1808,1592){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1143,2037){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(1138,912){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(918,302){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}}}} \put(3388,1387){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}B}}}}} \put(3388,2512){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}C}}}}} \put(908,10084){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}start\_up()}}}}} \put(178,3662){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Create backup \&}}}}} \put(178,3482){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}dump lock files}}}}} \put(3418,8315){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}get saved params}}}}} \put(3418,6530){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}get new params}}}}} \put(3395,7401){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}to "input" units}}}}} \put(3380,5585){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}to prog units}}}}} \put(913,4762){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} dump}}}}} \put(913,4582){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}/backup lockfiles}}}}} \put(3388,8518){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_header()}}}}} \put(3388,7625){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_control()}}}}} \put(3393,6720){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_control()}}}}} \put(3388,5824){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_control()}}}}} \put(918,9116){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}default\_control()}}}}} \put(913,8007){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_control()}}}}} \put(908,6863){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_control()}}}}} \put(5188,2282){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}}}} \put(5193,1310){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}banner\_page()}}}}} \put(5188,1103){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}write output file}}}}} \put(5210,219){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}return}}}}} \put(913,1439){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}restart?}}}}} \end{picture} } $EOD $! $CREATE fig_startup-b-eepic.tex $DECK \setlength{\unitlength}{0.00057743in} % \begingroup\makeatletter\ifx\SetFigFont\undefined% \gdef\SetFigFont#1#2#3#4#5{% \reset@font\fontsize{#1}{#2pt}% \fontfamily{#3}\fontseries{#4}\fontshape{#5}% \selectfont}% \fi\endgroup% {\renewcommand{\dashlinestretch}{30} \begin{picture}(10612,10844)(0,-10) \put(2034,3957){\ellipse{1800}{676}} \put(2039,3058){\ellipse{1800}{676}} \put(2039,2158){\ellipse{1800}{676}} \put(2039,1253){\ellipse{1800}{676}} \path(2039,3622)(2039,3396) \blacken\path(2009.000,3516.000)(2039.000,3396.000)(2069.000,3516.000)(2009.000,3516.000) \path(2039,2722)(2039,2496) \blacken\path(2009.000,2616.000)(2039.000,2496.000)(2069.000,2616.000)(2009.000,2616.000) \path(2039,1822)(2039,1596) \blacken\path(2009.000,1716.000)(2039.000,1596.000)(2069.000,1716.000)(2009.000,1716.000) \put(2034,9582){\ellipse{1800}{676}} \put(2039,8683){\ellipse{1800}{676}} \put(2039,7783){\ellipse{1800}{676}} \put(2039,6878){\ellipse{1800}{676}} \path(2039,9247)(2039,9021) \blacken\path(2009.000,9141.000)(2039.000,9021.000)(2069.000,9141.000)(2009.000,9141.000) \path(2039,8347)(2039,8121) \blacken\path(2009.000,8241.000)(2039.000,8121.000)(2069.000,8241.000)(2009.000,8241.000) \path(2039,7447)(2039,7221) \blacken\path(2009.000,7341.000)(2039.000,7221.000)(2069.000,7341.000)(2009.000,7341.000) \put(9699,9357){\ellipse{1800}{676}} \put(9704,8458){\ellipse{1800}{676}} \put(9704,7558){\ellipse{1800}{676}} \put(9704,6653){\ellipse{1800}{676}} \path(9704,9022)(9704,8796) \blacken\path(9674.000,8916.000)(9704.000,8796.000)(9734.000,8916.000)(9674.000,8916.000) \path(9704,8122)(9704,7896) \blacken\path(9674.000,8016.000)(9704.000,7896.000)(9734.000,8016.000)(9674.000,8016.000) \path(9704,7222)(9704,6996) \blacken\path(9674.000,7116.000)(9704.000,6996.000)(9734.000,7116.000)(9674.000,7116.000) \put(9698,2841){\ellipse{670}{670}} \path(9698,3621)(9698,3171) \blacken\path(9668.000,3291.000)(9698.000,3171.000)(9728.000,3291.000)(9668.000,3291.000) \put(9698,10486){\ellipse{670}{670}} \put(9699,5757){\ellipse{1800}{676}} \put(9704,4858){\ellipse{1800}{676}} \put(9704,3958){\ellipse{1800}{676}} \path(9698,10146)(9698,9696) \blacken\path(9668.000,9816.000)(9698.000,9696.000)(9728.000,9816.000)(9668.000,9816.000) \path(9704,5422)(9704,5196) \blacken\path(9674.000,5316.000)(9704.000,5196.000)(9734.000,5316.000)(9674.000,5316.000) \path(9704,4522)(9704,4296) \blacken\path(9674.000,4416.000)(9704.000,4296.000)(9734.000,4416.000)(9674.000,4416.000) \path(9704,6322)(9704,6096) \blacken\path(9674.000,6216.000)(9704.000,6096.000)(9734.000,6216.000)(9674.000,6216.000) \put(2040,6998){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}allocate\_}}}}} \put(2040,6833){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dynamics()}}}}} \put(2033,7854){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}initialise\_}}}}} \put(2033,7689){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}sysdef()}}}}} \put(9691,7664){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}allocate\_}}}}} \put(9691,7499){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dynamics()}}}}} \put(5183,6079){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}allocate\_}}}}} \put(5183,5914){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}dynamics()}}}}} \put(7476,6977){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}initialise\_}}}}} \put(7476,6812){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}sysdef()}}}}} \put(5183,10481){\ellipse{670}{670}} \put(2029,356){\ellipse{670}{670}} \put(908,5084){\ellipse{1800}{676}} \put(3156,5084){\ellipse{1800}{676}} \put(2033,10476){\ellipse{670}{670}} \put(5183,7541){\ellipse{1800}{676}} \put(5184,5964){\ellipse{1800}{676}} \put(5189,5065){\ellipse{1800}{676}} \put(5189,4165){\ellipse{1800}{676}} \put(5189,3260){\ellipse{1800}{676}} \put(5183,343){\ellipse{670}{670}} \put(7428,1453){\ellipse{1800}{676}} \put(7434,8665){\ellipse{1800}{676}} \put(7439,7766){\ellipse{1800}{676}} \put(7439,5961){\ellipse{1800}{676}} \put(7439,6866){\ellipse{1800}{676}} \put(5189,2366){\ellipse{1800}{676}} \path(4283,9921)(6083,9921)(6083,9246) (4283,9246)(4283,9921) \path(5183,10146)(5183,9921) \blacken\path(5153.000,10041.000)(5183.000,9921.000)(5213.000,10041.000)(5153.000,10041.000) \path(5183,9246)(5183,9021) \blacken\path(5153.000,9141.000)(5183.000,9021.000)(5213.000,9141.000)(5153.000,9141.000) \path(2033,10146)(2033,9921) \blacken\path(2003.000,10041.000)(2033.000,9921.000)(2063.000,10041.000)(2003.000,10041.000) \path(2033,6546)(2033,6326) \blacken\path(2003.000,6446.000)(2033.000,6326.000)(2063.000,6446.000)(2003.000,6446.000) \path(1133,5961)(908,5961)(908,5418) \blacken\path(878.000,5538.000)(908.000,5418.000)(938.000,5538.000)(878.000,5538.000) \path(2933,5961)(3158,5961)(3158,5416) \blacken\path(3128.000,5536.000)(3158.000,5416.000)(3188.000,5536.000)(3128.000,5536.000) \path(908,4746)(908,4521)(2033,4521) \blacken\path(1913.000,4491.000)(2033.000,4521.000)(1913.000,4551.000)(1913.000,4491.000) \path(3158,4746)(3158,4521)(2033,4521) \blacken\path(2153.000,4551.000)(2033.000,4521.000)(2153.000,4491.000)(2153.000,4551.000) \path(2033,4521)(2033,4296) \blacken\path(2003.000,4416.000)(2033.000,4296.000)(2063.000,4416.000)(2003.000,4416.000) \path(2038,911)(2038,686) \blacken\path(2008.000,806.000)(2038.000,686.000)(2068.000,806.000)(2008.000,806.000) \path(5183,8306)(5183,7881) \blacken\path(5153.000,8001.000)(5183.000,7881.000)(5213.000,8001.000)(5153.000,8001.000) \path(6083,8661)(5183,9021)(4283,8661) (5183,8301)(6083,8661) \path(5183,7206)(5183,6298) \blacken\path(5153.000,6418.000)(5183.000,6298.000)(5213.000,6418.000)(5153.000,6418.000) \path(5189,5629)(5189,5403) \blacken\path(5159.000,5523.000)(5189.000,5403.000)(5219.000,5523.000)(5159.000,5523.000) \path(5189,4729)(5189,4503) \blacken\path(5159.000,4623.000)(5189.000,4503.000)(5219.000,4623.000)(5159.000,4623.000) \path(5189,3829)(5189,3603) \blacken\path(5159.000,3723.000)(5189.000,3603.000)(5219.000,3723.000)(5159.000,3723.000) \path(5189,2928)(5189,2702) \blacken\path(5159.000,2822.000)(5189.000,2702.000)(5219.000,2822.000)(5159.000,2822.000) \path(6083,1460)(5183,1820)(4283,1460) (5183,1100)(6083,1460) \path(6083,1458)(6533,1458) \blacken\path(6413.000,1428.000)(6533.000,1458.000)(6413.000,1488.000)(6413.000,1428.000) \path(7438,1113)(7438,898)(5183,898) \blacken\path(5303.000,928.000)(5183.000,898.000)(5303.000,868.000)(5303.000,928.000) \path(5183,1098)(5183,685) \blacken\path(5153.000,805.000)(5183.000,685.000)(5213.000,805.000)(5153.000,805.000) \path(5183,2031)(5183,1819) \blacken\path(5153.000,1939.000)(5183.000,1819.000)(5213.000,1939.000)(5153.000,1939.000) \path(7439,8330)(7439,8104) \blacken\path(7409.000,8224.000)(7439.000,8104.000)(7469.000,8224.000)(7409.000,8224.000) \path(7439,7430)(7439,7204) \blacken\path(7409.000,7324.000)(7439.000,7204.000)(7469.000,7324.000)(7409.000,7324.000) \path(7439,6530)(7439,6304) \blacken\path(7409.000,6424.000)(7439.000,6304.000)(7469.000,6424.000)(7409.000,6424.000) \path(7433,5626)(7433,5401)(6308,5406) (6308,6756)(5183,6756) \blacken\path(5303.000,6786.000)(5183.000,6756.000)(5303.000,6726.000)(5303.000,6786.000) \path(6089,8662)(6539,8662) \blacken\path(6419.000,8632.000)(6539.000,8662.000)(6419.000,8692.000)(6419.000,8632.000) \path(2933,5966)(2033,6326)(1133,5966) (2033,5606)(2933,5966) \put(2048,10371){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}A}}}}} \put(5183,10356){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}B}}}}} \put(9713,10371){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}C}}}}} \put(2033,239){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}}}} \put(9683,2714){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}}}} \put(2033,9638){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_sysdef()}}}}} \put(2033,5926){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}lattice start?}}}}} \put(2925,6098){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(1133,6091){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(9683,6696){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_averages()}}}}} \put(2025,8663){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_potentials()}}}}} \put(2033,3081){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_averages()}}}}} \put(2025,3975){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}thermalise()}}}}} \put(3150,5114){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}lattice\_start()}}}}} \put(900,5114){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}skew\_start()}}}}} \put(2033,2182){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_rdf()}}}}} \put(2040,1275){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_cutoffs()}}}}} \put(9673,9390){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_header()}}}}} \put(9688,8482){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_sysdef()}}}}} \put(9653,5782){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_rdf()}}}}} \put(9683,4881){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_restart()}}}}} \put(4388,9713){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Adjust timestep-}}}}} \put(4388,9353){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}parameters}}}}} \put(4388,9533){\makebox(0,0)[lb]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}related control}}}}} \put(2033,9420){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from sys-spec file}}}}} \put(9686,8280){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from backup}}}}} \put(9686,4691){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from backup}}}}} \put(9705,3916){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}convert\_averages()}}}}} \put(9686,9187){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault} from backup}}}}} \put(5168,239){\makebox(0,0)[b]{\smash{{{\SetFigFont{11}{13.2}{\rmdefault}{\bfdefault}{\updefault}D}}}}} \put(5183,8731){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}replace}}}}} \put(5183,8551){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}system spec?}}}}} \put(6083,8776){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(5415,8108){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(6083,1589){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}Y}}}}} \put(4965,899){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}N}}}}} \put(7431,1529){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}interpolate\_}}}}} \put(7431,1364){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}derivatives()}}}}} \put(5183,7576){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}re\_re\_sysdef()}}}}} \put(5228,5099){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_averages()}}}}} \put(5183,4193){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}init\_rdf()}}}}} \put(5190,3300){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_restart()}}}}} \put(7431,8705){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}read\_sysdef()}}}}} \put(7438,5997){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}check\_sysdef()}}}}} \put(7432,8490){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from sys-spec file}}}}} \put(5182,7365){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}from restart file}}}}} \put(7439,5770){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}abort if failed}}}}} \put(5182,3100){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}dyamic vars etc.}}}}} \put(7438,7722){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}conv\_potentials()}}}}} \put(5198,1492){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}timestep}}}}} \put(5198,1312){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\familydefault}{\mddefault}{\updefault}changed?}}}}} \put(5190,2316){\makebox(0,0)[b]{\smash{{{\SetFigFont{8}{9.6}{\ttdefault}{\mddefault}{\updefault}convert\_averages()}}}}} \end{picture} } $EOD $! $CREATE compile_moldy.com $DECK $ write sys$output "Compiling accel" $ CC accel $ write sys$output "Compiling algorith" $ CC algorith $ write sys$output "Compiling alloc" $ CC alloc $ write sys$output "Compiling ansi" $ CC ansi $ write sys$output "Compiling auxil" $ CC auxil $ write sys$output "Compiling beeman" $ CC beeman $ write sys$output "Compiling convert" $ CC convert $ write sys$output "Compiling dump" $ CC dump $ write sys$output "Compiling ewald" $ CC ewald $ write sys$output "Compiling force" $ CC force $ write sys$output "Compiling input" $ CC input $ write sys$output "Compiling eigens" $ CC eigens $ write sys$output "Compiling kernel" $ CC kernel $ write sys$output "Compiling main" $ CC main $ write sys$output "Compiling matrix" $ CC matrix $ write sys$output "Compiling output" $ CC output $ write sys$output "Compiling quaterns" $ CC quaterns $ write sys$output "Compiling rdf" $ CC rdf $ write sys$output "Compiling restart" $ CC restart $ write sys$output "Compiling startup" $ CC startup $ write sys$output "Compiling values" $ CC values $ write sys$output "Compiling xdr" $ CC xdr $ write sys$output "Compiling parallel" $ CC parallel $EOD $! $CREATE link_moldy.com $DECK $ write sys$output "Linking moldy" $ Link/exe=moldy accel,algorith,alloc,ansi,auxil,beeman,convert,dump,ewald,force,input,eigens,kernel,main,matrix,output,quaterns,rdf,restart,startup,values,xdr,parallel $EOD $! $CREATE defcomm.com $DECK $ dir = F$TRNLNM("SYS$DISK")+F$DIRECTORY() $ moldy :== $'dir'moldy $ mdshak :== $'dir'mdshak $ moldyext :== $'dir'moldyext $ dumpanal :== $'dir'dumpanal $ dumpconv :== $'dir'dumpconv $ dumpext :== $'dir'dumpext $ manalyze :== $'dir'manalyze $EOD $! $CREATE compile_utils.com $DECK $ write sys$output "Compiling mdshak" $ CC mdshak $ write sys$output "Compiling getopt" $ CC getopt $ write sys$output "Compiling moldyext" $ CC moldyext $ write sys$output "Compiling dumpanal" $ CC dumpanal $ write sys$output "Compiling dumpconv" $ CC dumpconv $ write sys$output "Compiling dumpext" $ CC dumpext $ write sys$output "Compiling manalyze" $ CC manalyze $EOD $! $CREATE link_utils.com $DECK $ write sys$output "Linking mdshak" $ Link/exe=mdshak mdshak,getopt,algorith,alloc,auxil,ansi,eigens,kernel,input,matrix,quaterns,restart,startup,values,xdr $ write sys$output "Linking moldyext" $ Link/exe=moldyext moldyext,getopt $ write sys$output "Linking dumpanal" $ Link/exe=dumpanal dumpanal,getopt $ write sys$output "Linking dumpconv" $ Link/exe=dumpconv dumpconv,getopt $ write sys$output "Linking dumpext" $ Link/exe=dumpext dumpext,getopt $ write sys$output "Linking manalyze" $ Link/exe=manalyze manalyze,getopt $EOD $! $CREATE compile.com $DECK $ write sys$output "===========Building Moldy============" $ @compile_moldy $ @link_moldy $ write sys$output "===========Building utilities============" $ @compile_utils $ @link_utils $ @defcomm $ write sys$output "===========Done============" $EOD $! $CREATE Makefile.mak $DECK SHELL=/bin/sh # # Compilation Options - choose a suitable set for your machine # # # USE_XDR. Uncomment this line to enable XDR support. #XDR=-DUSE_XDR # # Parallel library support. Uncomment as needed, and set paths to # include directories and library paths. # # TCGMSG library #PARLIBC=-DSPMD -DTCGMSG -I/usr/local/include/tcgmsg #PARLIBL=-L/usr/local/lib -ltcgmsg # BSP library #CC=bspcc #PARLIBC=-DSPMD -DBSP #PARLIBL=-L/usr/local/lib -lbsp # MPI library #CC=mpicc #PARLIBC=-DSPMD -DMPI -I/usr/local/include/mpi #PARLIBL=-L/usr/local/lib -lmpi # MPI library on Edinburgh T3D #PARLIBC=-DSPMD -DMPI #PARLIBL=-lmpi # SHMEM library on Edinburgh T3D #PARLIBC=-DSPMD -DSHMEM #-DMPPMANY #PARLIBL= # **** MSDOS with Turbo C **** CC=tcc CFLAGS= -A -DANSI_LIBS -f287 -mh -O -Z -G $(CFLAGS0) GETOPT=getopt.obj LDFLAGS1= -mh $(LDFLAGS0) # **** Scalar machines using default C compiler **** #CFLAGS= -O $(XDR) $(PARLIBC) $(CFLAGS0) LDFLAGS= $(LDFLAGS0) $(PARLIBL) #INLINE= # **** Scalar machines using gcc - can compile with -g **** #CC= gcc #CFLAGS= -O2 -ffast-math $(XDR) $(PARLIBC) $(CFLAGS0) #CFLAGSAUX=-funroll-loops #LDFLAGS= $(PARLIBL) $(LDFLAGS0) #INLINE= # **** IBM RS6000 **** #CC=cc #CFLAGS= -DRS6000 -qansialias -O3 $(XDR) $(PARLIBC) $(CFLAGS0) #LDFLAGS= $(PARLIBL) $(LDFLAGS0) #INLINE= # **** MIPS for SGI, IRIX 5 **** #CFLAGS= -O2 -mips2 $(XDR) $(PARLIBC) $(CFLAGS0) #LDFLAGS= $(PARLIBL) $(LDFLAGS0) -lsun -lmalloc -lfastm #INLINE= ## **** MIPS for SGI, IRIX 6/R8000 **** #CFLAGS= -DANSI_LIBS -O3 -mips4 -woff 1174 $(XDR) $(PARLIBC) $(CFLAGS0) #LDFLAGS= $(PARLIBL) $(LDFLAGS0) #CFLAGS2=-OPT:alias=restrict:fast_sqrt=on #INLINE= # **** Sun C 3.0.1 #CC=acc #CFLAGS= -fast -xO4 $(PARLIBC) $(XDR) $(CFLAGS0) #CFLAGS2= -fsimple #LDFLAGS= $(PARLIBL) $(LDFLAGS0) -fast #INLINE= # **** Sun Solaris 2 #CFLAGS= -fast -xO4 $(PARLIBC) $(XDR) $(CFLAGS0) #CFLAGS2= -fsimple -xrestrict=%all #LDFLAGS= $(PARLIBL) $(LDFLAGS0) -fast -lnsl #INLINE= # **** Solaris 2 using gcc **** #CC= gcc #CFLAGS= -O2 -ffast-math $(PARLIBC) $(XDR) $(CFLAGS0) #CFLAGSAUX=-funroll-loops #LDFLAGS= $(PARLIBL) $(LDFLAGS0) -lnsl #INLINE= # **** DEC Alpha **** #CC=cc -migrate #CFLAGS= -tune host -O4 $(XDR) $(PARLIBC) $(CFLAGS0) -D_FASTMATH #CFLAGS2=-ansi_alias -O5 #LDFLAGS= $(PARLIBL) $(LDFLAGS0) # **** HP 700 and Convex SPP **** #CC=c89 ##CC=mpicc #CFLAGS= +O3 +Olibcalls $(XDR) $(PARLIBC) $(CFLAGS0) #CFLAGS2= +Onoparmsoverlap #LDFLAGS= $(PARLIBL) $(LDFLAGS0) # **** Stellar **** #CFLAGS= -g -O2 -va -na -nv $(XDR) $(CFLAGS0) #CFLAGS2= +CaliasFreePointers #LDFLAGS= $(LDFLAGS0) -g -z #INLINE= # **** Titan **** #CFLAGS= -O2 -vector_c -vreport $(XDR) $(PARLIBC) $(CFLAGS0) #CFLAGS2= -safe=ptrs #LDFLAGS= $(PARLIBL) $(LDFLAGS0) #CFLAGSAUX=-catalog=auxil.in #INLINE= -inline -Npaths=auxil.in # **** convex **** #CFLAGS= -O2 -na -nv -fi $(XDR) $(PARLIBC) $(CFLAGS0) #CFLAGS2= -alias standard -alias ptr_args -alias array_args ##CFLAGSP= -O3 -re # force,ewald_parallel versions only #LDFLAGS= $(PARLIBL) $(LDFLAGS0) -fi -lveclib #INLINE= # **** Cray **** (SCC 3.0) #CFLAGS= -h nostdc,vector3,scalar3,ivdep,fastaddr $(XDR) $(PARLIBC) $(CFLAGS0) #LDFLAGS= $(LDFLAGS0) -Wl,-D,"HEAP=50000+50000;STACK=10000+10000" -lsci #INLINE= # **** Cray T3D **** #CC=TARGET=cray-t3d cc #CFLAGS= -O2 $(XDR) $(PARLIBC) $(CFLAGS0) #CFLAGS2=-hrestrict=a #LDFLAGS=$(PARLIBL) $(LDFLAGS0) -L/usr/local/lib/bnchlib -lbnch # ***** End ***** LINT= lint TAR= tar DCLAR= dclar PFLAGS= -P EPFLAGS= -2r A2FLAGS= SHFILE= $$file FILES = accel algorith alloc ansi auxil beeman convert dump ewald force input \ eigens kernel main matrix output quaterns rdf restart startup \ values xdr parallel CFILES= accel.c algorith.c alloc.c ansi.c auxil.c beeman.c convert.c dump.c ewald.c force.c input.c eigens.c kernel.c main.c matrix.c output.c quaterns.c rdf.c restart.c startup.c values.c xdr.c parallel.c OFILES= accel.o algorith.o alloc.o ansi.o auxil.o beeman.o convert.o dump.o ewald.o force.o input.o eigens.o kernel.o main.o matrix.o output.o quaterns.o rdf.o restart.o startup.o values.o xdr.o parallel.o LFILES= accel.ln algorith.ln alloc.ln ansi.ln auxil.ln beeman.ln convert.ln dump.ln ewald.ln force.ln input.ln eigens.ln kernel.ln main.ln matrix.ln output.ln quaterns.ln rdf.ln restart.ln startup.ln values.ln xdr.ln parallel.ln INFILES = control.water control.tip4p control.mgclh2o control.clay \ control.argon control.tips2 control.quartz \ tips2.in tip4p.in mgclh2o.in \ argon.in quartz-vbst.in methane.in mcy.in \ water-example.out tip4p-example.out \ mgclh2o-example.out clay-example.out \ argon-example.out tips2-example.out \ quartz-example.out SHAKS= algorith alloc auxil ansi eigens kernel input matrix\ quaterns restart startup values xdr SHAKC= algorith.c alloc.c auxil.c ansi.c eigens.c kernel.c input.c matrix.c quaterns.c restart.c startup.c values.c xdr.c SHAKOBJS=algorith.o alloc.o auxil.o ansi.o eigens.o kernel.o input.o matrix.o quaterns.o restart.o startup.o values.o xdr.o UTILS = moldyext dumpanal dumpconv dumpext manalyze EXTRA0= moldyext.c dumpanal.c dumpconv.c dumpext.c manalyze.c mdshak.c ewald_parallel.c force_parallel.c EXTRAS= moldyext.c dumpanal.c dumpconv.c dumpext.c manalyze.c mdshak.c ewald_parallel.c force_parallel.c ewald-RIL.c HFILES= structs.h defs.h string.h time.h stddef.h stdlib.h messages.h xdr.h FIGTEXPS= fig_arralloc.tex fig_dostep-a.tex fig_dostep-b.tex \ fig_ewald.tex fig_link-cell.tex fig_main.tex \ fig_skewstart.tex fig_startup-a.tex fig_startup-b.tex \ fig_arralloc.ps fig_dostep-a.ps fig_dostep-b.ps \ fig_ewald.ps fig_link-cell.ps fig_main.ps \ fig_skewstart.ps fig_startup-a.ps fig_startup-b.ps \ fig_arralloc-eepic.tex fig_dostep-a-eepic.tex \ fig_dostep-b-eepic.tex fig_ewald-eepic.tex \ fig_link-cell-eepic.tex fig_main-eepic.tex \ fig_skewstart-eepic.tex fig_startup-a-eepic.tex \ fig_startup-b-eepic.tex DOC= READ.ME BENCHMARK COPYING RELNOTES moldy.tex moldy.bbl \ $(FIGTEXPS) VMSBUILD= compile_moldy.com link_moldy.com defcomm.com\ compile_utils.com link_utils.com compile.com DOSBUILD= Makefile.mak OFILES.RSP SHAKOBJS.RSP moldy: $(OFILES) $(EXTRA_OBJ) $(HFILES) $(CC) -o moldy $(LDFLAGS1) @OFILES.RSP $(EXTRA_OBJ) $(LDFLAGS) -lm moldyext: moldyext.c $(GETOPT) $(HFILES) $(CC) $(CFLAGS) -o moldyext $(LDFLAGS1) moldyext.c $(GETOPT) $(LDFLAGS) manalyze: manalyze.c $(HFILES) $(CC) $(CFLAGS) -o manalyze $(LDFLAGS1) manalyze.c $(LDFLAGS) dumpanal: dumpanal.c xdr.o $(HFILES) $(CC) $(CFLAGS) -o dumpanal $(LDFLAGS1) dumpanal.c xdr.o $(LDFLAGS) dumpext: dumpext.c xdr.o $(GETOPT) $(HFILES) $(CC) $(CFLAGS) -o dumpext $(LDFLAGS1) dumpext.c xdr.o $(GETOPT) $(LDFLAGS) dumpconv: dumpconv.c xdr.o $(HFILES) $(CC) $(CFLAGS) -o dumpconv $(LDFLAGS1) dumpconv.c xdr.o $(LDFLAGS) mdshak: mdshak.o $(SHAKOBJS) $(GETOPT) $(CC) -o mdshak $(LDFLAGS1) mdshak.o @SHAKOBJS.RSP $(GETOPT) $(LDFLAGS) -lm utilities: $(UTILS) mdshak $(FIGTEXPS): (cd figures; \ transfig -L pstex -m 0.66; \ $(MAKE); \ mv *.ps *.tex ..;\ transfig -L eepic -m 0.66;\ $(MAKE); \ rename 's/\.tex/-eepic.tex/' *.tex;\ mv *.tex ..) protoize: $(CFILES) $(HFILES) protoize -k $(CFILES) proto-mdshak: mdshak.c $(SHAKC) protoize mdshak.c $(SHAKC) install: moldy $(UTILS) mdshak for file in $?; do install $$file $$HOME/bin/; done install2: moldy $(UTILS) mdshak for file in $?; do install $$file $$HOME/bin.$$HOSTTYPE/; done Makefile: xmakefile @PATH=/usr/5bin:${PATH};\ echo '{{{{{{{\n/^CFILES *=/ c\\\nCFILES=' $(CFILES)\ '\n}\n/^OFILES *=/ c\\\nOFILES=' @OFILES.RSP\ '\n}\n/^LFILES *=/ c\\\nLFILES=' $(LFILES)\ '\n}\n/^EXTRA0 *=/ c\\\nEXTRA0=' $(EXTRA0)\ '\n}\n/^EXTRAS *=/ c\\\nEXTRAS=' $(EXTRAS)\ '\n}\n/^SHAKC *=/ c\\\nSHAKC=' $(SHAKC)\ '\n}\n/^SHAKOBJS *=/ c\\\nSHAKOBJS='@SHAKOBJS.RSP\ '\n}\n/^%\.[a-z][a-z]*: /,/^$$/ d\n'\ '/^moldy.bbl: /,/^$$/ d\n' \ '/^moldy.aux: /,/^$$/ d\n' \ > make.sed sed -f make.sed ./xmakefile > Makefile Makefile.mak: Makefile @PATH=/usr/5bin:${PATH};\ echo 's/^\([ ].*\)$@OFILES.RSP/\1@OFILES.RSP/g\n'\ 's/^\([ ].*\)$@SHAKOBJS.RSP/\1@SHAKOBJS.RSP/g\n'\ 's/\.\/.obj/g\n'\ 's/\.o$$/.obj/g\n'\ 's/ -\ *\(\<[a-z]*\>\)/ -e\1 /\n'\ 's/ -\//\n'\ '/^# \*\*\*\* MSDOS/,/^# \*/ s/^#\([A-Z]\)/\1/\n'\ 's/#XDR=/#XDR=/\n'\ 's/^\(CFLAGS=.*$$(XDR)\)/#\1/\n'\ moldy.tar.gz: moldy.tar gzip moldy.tar moldy.shar: $(CFILES) $(HFILES) Makefile \ $(EXTRAS) $(INFILES) $(DOC) getopt.c $(VMSBUILD) $(DOSBUILD) shar $(CFILES) $(HFILES) Makefile \ $(EXTRAS) $(INFILES) $(DOC) getopt.c $(VMSBUILD) $(DOSBUILD)\ > moldy.shar moldy.shar.Z: moldy.shar compress moldy.shar cray: $(CFILES) $(HFILES) ./cray_make $(CFILES) $(HFILES) > cray.job moldy.job: $(CFILES) $(HFILES) ./make_cray $(CFILES) $(HFILES) > moldy.job compile_moldy.com: Makefile ./make_vms_compile $(FILES) > compile_moldy.com link_moldy.com: Makefile ./make_vms_link moldy $(FILES) > link_moldy.com compile_utils.com: Makefile ./make_vms_compile mdshak getopt $(UTILS) > compile_utils.com link_utils.com: Makefile ./make_vms_link mdshak mdshak getopt $(SHAKS) > link_utils.com for file in $(UTILS); do ./make_vms_link $$file $$file getopt>> \ link_utils.com; done moldy.com: $(CFILES) $(HFILES) $(EXTRAS)\ $(INFILES) Aaaa_Read.Me $(DOC) $(VMSBUILD) $(DOSBUILD) $(DCLAR) Aaaa_Read.Me compile.com $(CFILES) $(HFILES)\ $(INFILES) $(EXTRAS) getopt.c $(DOC) $(VMSBUILD) $(DOSBUILD)\ > moldy.com moldy.com.Z: moldy.com compress moldy.com moldy.ps: moldy.dvi dvips -t a4 moldy -o moldy.ps moldy.dvi: moldy.tex moldy.bbl latex moldy latex moldy @touch moldy.bbl $(LFILES): $(HFILES) # # Dependencies of objects on headers. # eigens.o quaterns.o: defs.h accel.o beeman.o convert.o input.o main.o output.o startup.o values.o parallel.o: \ structs.h defs.h messages.h algorith.o alloc.o matrix.o: defs.h messages.h xdr.o restart.o dump.o: structs.h defs.h messages.h xdr.h # # Special options for performance-critical modules # auxil.o: auxil.c defs.h $(CC) $(CFLAGS) $(CFLAGS2) $(CFLAGSAUX) -c $< ewald.o: ewald.c structs.h defs.h $(CC) $(CFLAGS) $(CFLAGS2) $(CFLAGSP) -c $(INLINE) $< rdf.o: rdf.c structs.h defs.h $(CC) $(CFLAGS) $(CFLAGS2) -c $< kernel.o: kernel.c structs.h defs.h $(CC) $(CFLAGS) $(CFLAGS2) $(CFLAGSP) -c $< force.o: force.c structs.h defs.h $(CC) $(CFLAGS) $(CFLAGS2) $(CFLAGSP) $(INLINE) -c $< # # Rule for checking out source under RCS # ewald-RIL.c: co -pRIL ewald.c > ewald-RIL.c .c.o: $(CC) $(CFLAGS) -c $< $EOD $! $CREATE OFILES.RSP $DECK accel.o algorith.o alloc.o ansi.o auxil.o beeman.o convert.o dump.o ewald.o force.o input.o eigens.o kernel.o main.o matrix.o output.o quaterns.o rdf.o restart.o startup.o values.o xdr.o parallel.o $EOD $! $CREATE SHAKOBJS.RSP $DECK algorith.o alloc.o auxil.o ansi.o eigens.o kernel.o input.o matrix.o quaterns.o restart.o startup.o values.o xdr.o $EOD