| 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;
 | 
|---|