| [0b990d] | 1 | #
 | 
|---|
 | 2 | eval 'exec perl $0 $*'
 | 
|---|
 | 3 |     if 0;
 | 
|---|
 | 4 | 
 | 
|---|
 | 5 | use POSIX; # for acos
 | 
|---|
 | 6 | require QCParse;
 | 
|---|
 | 7 | 
 | 
|---|
 | 8 | ##########################################################################
 | 
|---|
 | 9 | 
 | 
|---|
 | 10 | package Molecule;
 | 
|---|
 | 11 | $debug = 0;
 | 
|---|
 | 12 | $fltrx = "((?:-?\\d+|-?\\d+\\.\\d*|-?\\d*\\.\\d+)(?:[eE][+-]?\\d+)?)";
 | 
|---|
 | 13 | 
 | 
|---|
 | 14 | %z_to_sym = (
 | 
|---|
 | 15 |     "1" => "h",
 | 
|---|
 | 16 |     "2" => "he",
 | 
|---|
 | 17 |     "3" => "li",
 | 
|---|
 | 18 |     "4" => "be",
 | 
|---|
 | 19 |     "5" => "b",
 | 
|---|
 | 20 |     "6" => "c",
 | 
|---|
 | 21 |     "7" => "n",
 | 
|---|
 | 22 |     "8" => "o",
 | 
|---|
 | 23 |     "9" => "f",
 | 
|---|
 | 24 |     "10" => "ne",
 | 
|---|
 | 25 |     "11" => "na",
 | 
|---|
 | 26 |     "12" => "mg",
 | 
|---|
 | 27 |     "13" => "al",
 | 
|---|
 | 28 |     "14" => "si",
 | 
|---|
 | 29 |     "15" => "p",
 | 
|---|
 | 30 |     "16" => "s",
 | 
|---|
 | 31 |     "17" => "cl",
 | 
|---|
 | 32 |     "18" => "ar",
 | 
|---|
 | 33 |     "19" => "k",
 | 
|---|
 | 34 |     "20" => "ca",
 | 
|---|
 | 35 |     "21" => "sc",
 | 
|---|
 | 36 |     "22" => "ti",
 | 
|---|
 | 37 |     "23" => "v",
 | 
|---|
 | 38 |     "24" => "cr",
 | 
|---|
 | 39 |     "25" => "mn",
 | 
|---|
 | 40 |     "26" => "fe",
 | 
|---|
 | 41 |     "27" => "co",
 | 
|---|
 | 42 |     "28" => "ni",
 | 
|---|
 | 43 |     "29" => "cu",
 | 
|---|
 | 44 |     "30" => "zn",
 | 
|---|
 | 45 |     "31" => "ga",
 | 
|---|
 | 46 |     "32" => "ge",
 | 
|---|
 | 47 |     "33" => "as",
 | 
|---|
 | 48 |     "34" => "se",
 | 
|---|
 | 49 |     "35" => "br",
 | 
|---|
 | 50 |     "36" => "kr",
 | 
|---|
 | 51 |     "37" => "rb",
 | 
|---|
 | 52 |     "38" => "sr",
 | 
|---|
 | 53 |     "39" => "y",
 | 
|---|
 | 54 |     "40" => "zr",
 | 
|---|
 | 55 |     "41" => "nb",
 | 
|---|
 | 56 |     "42" => "mo",
 | 
|---|
 | 57 |     "43" => "tc",
 | 
|---|
 | 58 |     "44" => "ru",
 | 
|---|
 | 59 |     "45" => "rh",
 | 
|---|
 | 60 |     "46" => "pd",
 | 
|---|
 | 61 |     "47" => "ag",
 | 
|---|
 | 62 |     "48" => "cd",
 | 
|---|
 | 63 |     "49" => "in",
 | 
|---|
 | 64 |     "50" => "sn",
 | 
|---|
 | 65 |     "51" => "sb",
 | 
|---|
 | 66 |     "52" => "te",
 | 
|---|
 | 67 |     "53" => "i",
 | 
|---|
 | 68 |     "54" => "xe",
 | 
|---|
 | 69 |     "55" => "cs",
 | 
|---|
 | 70 |     "56" => "ba",
 | 
|---|
 | 71 |     "57" => "la",
 | 
|---|
 | 72 |     "58" => "ce",
 | 
|---|
 | 73 |     "59" => "pr",
 | 
|---|
 | 74 |     "60" => "nd",
 | 
|---|
 | 75 |     "61" => "pm",
 | 
|---|
 | 76 |     "62" => "sm",
 | 
|---|
 | 77 |     "63" => "eu",
 | 
|---|
 | 78 |     "64" => "gd",
 | 
|---|
 | 79 |     "65" => "tb",
 | 
|---|
 | 80 |     "66" => "dy",
 | 
|---|
 | 81 |     "67" => "ho",
 | 
|---|
 | 82 |     "68" => "er",
 | 
|---|
 | 83 |     "69" => "tm",
 | 
|---|
 | 84 |     "70" => "yb",
 | 
|---|
 | 85 |     "71" => "lu",
 | 
|---|
 | 86 |     "72" => "hf",
 | 
|---|
 | 87 |     "73" => "ta",
 | 
|---|
 | 88 |     "74" => "w",
 | 
|---|
 | 89 |     "75" => "re",
 | 
|---|
 | 90 |     "76" => "os",
 | 
|---|
 | 91 |     "77" => "ir",
 | 
|---|
 | 92 |     "78" => "pt",
 | 
|---|
 | 93 |     "79" => "au",
 | 
|---|
 | 94 |     "80" => "hg",
 | 
|---|
 | 95 |     "81" => "tl",
 | 
|---|
 | 96 |     "82" => "pb",
 | 
|---|
 | 97 |     "83" => "bi",
 | 
|---|
 | 98 |     "84" => "po",
 | 
|---|
 | 99 |     "85" => "at",
 | 
|---|
 | 100 |     "86" => "rn",
 | 
|---|
 | 101 |     "87" => "fr",
 | 
|---|
 | 102 |     "88" => "ra",
 | 
|---|
 | 103 |     "89" => "ac",
 | 
|---|
 | 104 |     "90" => "th",
 | 
|---|
 | 105 |     "91" => "pa",
 | 
|---|
 | 106 |     "92" => "u",
 | 
|---|
 | 107 |     "93" => "np",
 | 
|---|
 | 108 |     "94" => "pu",
 | 
|---|
 | 109 |     "95" => "am",
 | 
|---|
 | 110 |     "96" => "cm",
 | 
|---|
 | 111 |     "97" => "bk",
 | 
|---|
 | 112 |     "98" => "cf",
 | 
|---|
 | 113 |     "99" => "es",
 | 
|---|
 | 114 |     "100" => "fm",
 | 
|---|
 | 115 |     "101" => "md",
 | 
|---|
 | 116 |     "102" => "no",
 | 
|---|
 | 117 |     "103" => "lr",
 | 
|---|
 | 118 |     "104" => "rf",
 | 
|---|
 | 119 |     "105" => "ha"
 | 
|---|
 | 120 | );
 | 
|---|
 | 121 | 
 | 
|---|
 | 122 | %sym_to_z = (
 | 
|---|
 | 123 |     "h" => "1",
 | 
|---|
 | 124 |     "he" => "2",
 | 
|---|
 | 125 |     "li" => "3",
 | 
|---|
 | 126 |     "be" => "4",
 | 
|---|
 | 127 |     "b" => "5",
 | 
|---|
 | 128 |     "c" => "6",
 | 
|---|
 | 129 |     "n" => "7",
 | 
|---|
 | 130 |     "o" => "8",
 | 
|---|
 | 131 |     "f" => "9",
 | 
|---|
 | 132 |     "ne" => "10",
 | 
|---|
 | 133 |     "na" => "11",
 | 
|---|
 | 134 |     "mg" => "12",
 | 
|---|
 | 135 |     "al" => "13",
 | 
|---|
 | 136 |     "si" => "14",
 | 
|---|
 | 137 |     "p" => "15",
 | 
|---|
 | 138 |     "s" => "16",
 | 
|---|
 | 139 |     "cl" => "17",
 | 
|---|
 | 140 |     "ar" => "18",
 | 
|---|
 | 141 |     "k" => "19",
 | 
|---|
 | 142 |     "ca" => "20",
 | 
|---|
 | 143 |     "sc" => "21",
 | 
|---|
 | 144 |     "ti" => "22",
 | 
|---|
 | 145 |     "v" => "23",
 | 
|---|
 | 146 |     "cr" => "24",
 | 
|---|
 | 147 |     "mn" => "25",
 | 
|---|
 | 148 |     "fe" => "26",
 | 
|---|
 | 149 |     "co" => "27",
 | 
|---|
 | 150 |     "ni" => "28",
 | 
|---|
 | 151 |     "cu" => "29",
 | 
|---|
 | 152 |     "zn" => "30",
 | 
|---|
 | 153 |     "ga" => "31",
 | 
|---|
 | 154 |     "ge" => "32",
 | 
|---|
 | 155 |     "as" => "33",
 | 
|---|
 | 156 |     "se" => "34",
 | 
|---|
 | 157 |     "br" => "35",
 | 
|---|
 | 158 |     "kr" => "36",
 | 
|---|
 | 159 |     "rb" => "37",
 | 
|---|
 | 160 |     "sr" => "38",
 | 
|---|
 | 161 |     "y" => "39",
 | 
|---|
 | 162 |     "zr" => "40",
 | 
|---|
 | 163 |     "nb" => "41",
 | 
|---|
 | 164 |     "mo" => "42",
 | 
|---|
 | 165 |     "tc" => "43",
 | 
|---|
 | 166 |     "ru" => "44",
 | 
|---|
 | 167 |     "rh" => "45",
 | 
|---|
 | 168 |     "pd" => "46",
 | 
|---|
 | 169 |     "ag" => "47",
 | 
|---|
 | 170 |     "cd" => "48",
 | 
|---|
 | 171 |     "in" => "49",
 | 
|---|
 | 172 |     "sn" => "50",
 | 
|---|
 | 173 |     "sb" => "51",
 | 
|---|
 | 174 |     "te" => "52",
 | 
|---|
 | 175 |     "i" => "53",
 | 
|---|
 | 176 |     "xe" => "54",
 | 
|---|
 | 177 |     "cs" => "55",
 | 
|---|
 | 178 |     "ba" => "56",
 | 
|---|
 | 179 |     "la" => "57",
 | 
|---|
 | 180 |     "ce" => "58",
 | 
|---|
 | 181 |     "pr" => "59",
 | 
|---|
 | 182 |     "nd" => "60",
 | 
|---|
 | 183 |     "pm" => "61",
 | 
|---|
 | 184 |     "sm" => "62",
 | 
|---|
 | 185 |     "eu" => "63",
 | 
|---|
 | 186 |     "gd" => "64",
 | 
|---|
 | 187 |     "tb" => "65",
 | 
|---|
 | 188 |     "dy" => "66",
 | 
|---|
 | 189 |     "ho" => "67",
 | 
|---|
 | 190 |     "er" => "68",
 | 
|---|
 | 191 |     "tm" => "69",
 | 
|---|
 | 192 |     "yb" => "70",
 | 
|---|
 | 193 |     "lu" => "71",
 | 
|---|
 | 194 |     "hf" => "72",
 | 
|---|
 | 195 |     "ta" => "73",
 | 
|---|
 | 196 |     "w" => "74",
 | 
|---|
 | 197 |     "re" => "75",
 | 
|---|
 | 198 |     "os" => "76",
 | 
|---|
 | 199 |     "ir" => "77",
 | 
|---|
 | 200 |     "pt" => "78",
 | 
|---|
 | 201 |     "au" => "79",
 | 
|---|
 | 202 |     "hg" => "80",
 | 
|---|
 | 203 |     "tl" => "81",
 | 
|---|
 | 204 |     "pb" => "82",
 | 
|---|
 | 205 |     "bi" => "83",
 | 
|---|
 | 206 |     "po" => "84",
 | 
|---|
 | 207 |     "at" => "85",
 | 
|---|
 | 208 |     "rn" => "86",
 | 
|---|
 | 209 |     "fr" => "87",
 | 
|---|
 | 210 |     "ra" => "88",
 | 
|---|
 | 211 |     "ac" => "89",
 | 
|---|
 | 212 |     "th" => "90",
 | 
|---|
 | 213 |     "pa" => "91",
 | 
|---|
 | 214 |     "u" => "92",
 | 
|---|
 | 215 |     "np" => "93",
 | 
|---|
 | 216 |     "pu" => "94",
 | 
|---|
 | 217 |     "am" => "95",
 | 
|---|
 | 218 |     "cm" => "96",
 | 
|---|
 | 219 |     "bk" => "97",
 | 
|---|
 | 220 |     "cf" => "98",
 | 
|---|
 | 221 |     "es" => "99",
 | 
|---|
 | 222 |     "fm" => "100",
 | 
|---|
 | 223 |     "md" => "101",
 | 
|---|
 | 224 |     "no" => "102",
 | 
|---|
 | 225 |     "lr" => "103",
 | 
|---|
 | 226 |     "rf" => "104",
 | 
|---|
 | 227 |     "ha" => "105"
 | 
|---|
 | 228 | );
 | 
|---|
 | 229 | 
 | 
|---|
 | 230 | sub new {
 | 
|---|
 | 231 |     my $this = shift;
 | 
|---|
 | 232 |     my $class = ref($this) || $this;
 | 
|---|
 | 233 |     my $self = {};
 | 
|---|
 | 234 |     bless $self, $class;
 | 
|---|
 | 235 |     $self->initialize(@_);
 | 
|---|
 | 236 |     return $self;
 | 
|---|
 | 237 | }
 | 
|---|
 | 238 | 
 | 
|---|
 | 239 | sub initialize {
 | 
|---|
 | 240 |     my $self = shift;
 | 
|---|
 | 241 |     my $mol = shift;
 | 
|---|
 | 242 | 
 | 
|---|
 | 243 |     $self->{"position"} = [];
 | 
|---|
 | 244 |     $self->{"element"} = [];
 | 
|---|
 | 245 |     my $i = 0;
 | 
|---|
 | 246 |     while ($mol =~ s/^\s*(\w+)\s+$fltrx\s+$fltrx\s+$fltrx\s*\n//) {
 | 
|---|
 | 247 |         my $sym = $1;
 | 
|---|
 | 248 |         my $x = $2;
 | 
|---|
 | 249 |         my $y = $3;
 | 
|---|
 | 250 |         my $z = $4;
 | 
|---|
 | 251 |         $self->{"element"}[$i] = $sym;
 | 
|---|
 | 252 |         $self->{"position"}[$i] = [ $x, $y, $z ];
 | 
|---|
 | 253 |         $i++;
 | 
|---|
 | 254 |     }
 | 
|---|
 | 255 | 
 | 
|---|
 | 256 |     $self->{"natom"} = $i;
 | 
|---|
 | 257 | }
 | 
|---|
 | 258 | 
 | 
|---|
 | 259 | sub string {
 | 
|---|
 | 260 |     my $self = shift;
 | 
|---|
 | 261 |     my $mol = "";
 | 
|---|
 | 262 |     for ($i = 0; $i < $self->n_atom(); $i++) {
 | 
|---|
 | 263 |         $mol = sprintf "%s  %s  %14.10f %14.10f %14.10f\n",
 | 
|---|
 | 264 |                        $mol, $self->element($i),
 | 
|---|
 | 265 |                        $self->position($i,0),
 | 
|---|
 | 266 |                        $self->position($i,1),
 | 
|---|
 | 267 |                        $self->position($i,2);
 | 
|---|
 | 268 |     }
 | 
|---|
 | 269 | 
 | 
|---|
 | 270 |     $mol;
 | 
|---|
 | 271 | }
 | 
|---|
 | 272 | 
 | 
|---|
 | 273 | sub n_atom {
 | 
|---|
 | 274 |     my $self = shift;
 | 
|---|
 | 275 |     printf "Molecule: returning natom = %d\n", $self->{"natom"} if ($debug);
 | 
|---|
 | 276 |     $self->{"natom"};
 | 
|---|
 | 277 | }
 | 
|---|
 | 278 | 
 | 
|---|
 | 279 | sub element {
 | 
|---|
 | 280 |     my $self = shift;
 | 
|---|
 | 281 |     my $i = shift;
 | 
|---|
 | 282 |     $self->{"element"}[$i];
 | 
|---|
 | 283 | }
 | 
|---|
 | 284 | 
 | 
|---|
 | 285 | sub z {
 | 
|---|
 | 286 |     my $self = shift;
 | 
|---|
 | 287 |     my $i = shift;
 | 
|---|
 | 288 |     $sym_to_z{lc($self->{"element"}[$i])};
 | 
|---|
 | 289 | }
 | 
|---|
 | 290 | 
 | 
|---|
 | 291 | sub position {
 | 
|---|
 | 292 |     my $self = shift;
 | 
|---|
 | 293 |     my $i = shift;
 | 
|---|
 | 294 |     my $xyz = shift;
 | 
|---|
 | 295 |     $self->{"position"}[$i][$xyz];
 | 
|---|
 | 296 | }
 | 
|---|
 | 297 | 
 | 
|---|
 | 298 | sub geometry {
 | 
|---|
 | 299 |     my $self = shift;
 | 
|---|
 | 300 |     my $geom = [];
 | 
|---|
 | 301 |     my $ngeom = 0;
 | 
|---|
 | 302 |     my $fence = $self->{"natom"}-1;
 | 
|---|
 | 303 |     foreach $i (0..$fence) {
 | 
|---|
 | 304 |         foreach $xyz (0..2) {
 | 
|---|
 | 305 |             $geom->[$ngeom] = $self->{"position"}[$i][$xyz];
 | 
|---|
 | 306 |             $ngeom = $ngeom + 1;
 | 
|---|
 | 307 |         }
 | 
|---|
 | 308 |     }
 | 
|---|
 | 309 |     $geom;
 | 
|---|
 | 310 | }
 | 
|---|
 | 311 | 
 | 
|---|
 | 312 | sub atom_xyz {
 | 
|---|
 | 313 |     my $self = shift;
 | 
|---|
 | 314 |     my $i = shift;
 | 
|---|
 | 315 |     my $geom = [];
 | 
|---|
 | 316 |     my $ngeom = 0;
 | 
|---|
 | 317 |     foreach $xyz (0..2) {
 | 
|---|
 | 318 |         $geom->[$ngeom] = $self->{"position"}[$i][$xyz];
 | 
|---|
 | 319 |         $ngeom = $ngeom + 1;
 | 
|---|
 | 320 |     }
 | 
|---|
 | 321 |     $geom;
 | 
|---|
 | 322 | }
 | 
|---|
 | 323 | 
 | 
|---|
 | 324 | sub dot {
 | 
|---|
 | 325 |     my $v1 = shift;
 | 
|---|
 | 326 |     my $v2 = shift;
 | 
|---|
 | 327 |     my $d = 0.0;
 | 
|---|
 | 328 |     foreach $xyz (0..2) {
 | 
|---|
 | 329 |         $d = $d + $v1->[$xyz] * $v2->[$xyz];
 | 
|---|
 | 330 |     }
 | 
|---|
 | 331 |     $d;
 | 
|---|
 | 332 | }
 | 
|---|
 | 333 | 
 | 
|---|
 | 334 | sub diff {
 | 
|---|
 | 335 |     my $v1 = shift;
 | 
|---|
 | 336 |     my $v2 = shift;
 | 
|---|
 | 337 |     my $diff = [];
 | 
|---|
 | 338 |     foreach $xyz (0..2) {
 | 
|---|
 | 339 |         $diff->[$xyz] = $v1->[$xyz] - $v2->[$xyz];
 | 
|---|
 | 340 |     }
 | 
|---|
 | 341 |     $diff;
 | 
|---|
 | 342 | }
 | 
|---|
 | 343 | 
 | 
|---|
 | 344 | sub vecstr {
 | 
|---|
 | 345 |     my $v = shift;
 | 
|---|
 | 346 |     sprintf "%12.8f %12.8f %12.8f", $v->[0], $v->[1], $v->[2];
 | 
|---|
 | 347 | }
 | 
|---|
 | 348 | 
 | 
|---|
 | 349 | # numbering starts at 1 for bond
 | 
|---|
 | 350 | sub bond {
 | 
|---|
 | 351 |     my $self = shift;
 | 
|---|
 | 352 |     my $a1 = shift() - 1;
 | 
|---|
 | 353 |     my $a2 = shift() - 1;
 | 
|---|
 | 354 |     my $d = diff($self->atom_xyz($a1),$self->atom_xyz($a2));
 | 
|---|
 | 355 |     #printf "v1 = %s\n", vecstr($self->atom_xyz($a1));
 | 
|---|
 | 356 |     #printf "v2 = %s\n", vecstr($self->atom_xyz($a2));
 | 
|---|
 | 357 |     #printf "diff = %s\n", vecstr($d);
 | 
|---|
 | 358 |     sqrt(dot($d,$d));
 | 
|---|
 | 359 | }
 | 
|---|
 | 360 | 
 | 
|---|
 | 361 | # numbering starts at 1 for bend
 | 
|---|
 | 362 | sub bend {
 | 
|---|
 | 363 |     my $self = shift;
 | 
|---|
 | 364 |     my $a1 = shift() - 1;
 | 
|---|
 | 365 |     my $a2 = shift() - 1;
 | 
|---|
 | 366 |     my $a3 = shift() - 1;
 | 
|---|
 | 367 |     my $diff12 = diff($self->atom_xyz($a1), $self->atom_xyz($a2));
 | 
|---|
 | 368 |     my $diff32 = diff($self->atom_xyz($a3), $self->atom_xyz($a2));
 | 
|---|
 | 369 |     POSIX::acos(dot($diff12,$diff32)/sqrt(dot($diff12,$diff12)*dot($diff32,$diff32))) * 180.0 / 3.14159265358979323846;
 | 
|---|
 | 370 | }
 | 
|---|
 | 371 | 
 | 
|---|
 | 372 | # numbering starts at 1 for tors
 | 
|---|
 | 373 | sub tors {
 | 
|---|
 | 374 |     my $self = shift;
 | 
|---|
 | 375 |     my $a1 = shift() - 1;
 | 
|---|
 | 376 |     my $a2 = shift() - 1;
 | 
|---|
 | 377 |     my $a3 = shift() - 1;
 | 
|---|
 | 378 |     my $a4 = shift() - 1;
 | 
|---|
 | 379 |     die "Molecule::tors not available";
 | 
|---|
 | 380 | }
 | 
|---|
 | 381 | 
 | 
|---|
 | 382 | 1;
 | 
|---|