Molecular Modeling Software
リビジョン | 7d4e8889123a3d42fb146b3844aa53387a3c42c2 (tree) |
---|---|
日時 | 2022-10-20 21:21:42 |
作者 | Toshi Nagata <alchemist.2005@nift...> |
コミッター | Toshi Nagata |
Show MO Surface dialog is improved
@@ -366,68 +366,59 @@ class Molecule | ||
366 | 366 | surface_dialog_attr = @surface_dialog_attr |
367 | 367 | mol = self |
368 | 368 | mol.open_auxiliary_window("MO Surface", :resizable=>true, :has_close_box=>true) { |
369 | - tags = ["mo_ao", "mo", "color", "opacity", "threshold", "expand", "grid"] | |
369 | + tags = ["mo_ao", "mo", "color", "opacity", "threshold", "expand", "grid", "reverse", "basis"] | |
370 | 370 | motype = mol.get_mo_info(:type) |
371 | 371 | alpha = mol.get_mo_info(:alpha) |
372 | 372 | beta = mol.get_mo_info(:beta) |
373 | 373 | ncomps = mol.get_mo_info(:ncomps) |
374 | - mo_index = 1 | |
374 | + mo_index = 0 | |
375 | 375 | mo_ao = nil |
376 | 376 | coltable = [[0,0,1], [1,0,0], [0,1,0], [1,1,0], [0,1,1], [1,0,1], [0,0,0], [1,1,1]] |
377 | 377 | mo_ao_items = ["Molecular Orbitals", "Atomic Orbitals"] |
378 | 378 | mo_ao_keys = ["MO", "AO"] |
379 | - if (nbo = mol.instance_eval { @nbo }) != nil | |
379 | + if (nbo = mol.instance_eval { @nbo }) != nil | |
380 | 380 | nbo.keys.each { |key| |
381 | - if key[0..2] == "AO/" | |
382 | - key2 = key[3..-1] | |
383 | - name2 = key2 | |
384 | - if key2 == "NAO" | |
385 | - name2 = "Natural Atomic Orbitals" | |
386 | - elsif key2 == "NBO" | |
387 | - name2 = "Natural Bond Orbitals" | |
388 | - elsif key2 == "NHO" | |
389 | - name2 = "Natural Hybrid Orbitals" | |
390 | - elsif key2 == "NLMO" | |
391 | - name2 = "Natural Localized Molecular Orbitals" | |
392 | - elsif key2 == "PNAO" | |
393 | - name2 = "Pre-orthogonal Natural Atomic Orbitals" | |
394 | - elsif key2 == "PNHO" | |
395 | - name2 = "Pre-orthogonal Natural Hybrid Orbitals" | |
396 | - elsif key2 == "PNBO" | |
397 | - name2 = "Pre-orthogonal Natural Bond Orbitals" | |
398 | - elsif key2 == "AHO" | |
399 | - name2 = "Atomic Hybrid Orbitals" | |
400 | - elsif key2 == "LHO" | |
401 | - name2 = "Lewis Hybrid Orbitals" | |
402 | - elsif key2 == "PLHO" | |
403 | - name2 = "Pre-orthogonal Lewis Hybrid Orbitals" | |
404 | - elsif key2 == "LPO" | |
405 | - name2 = "Localized Property-optimized Orbitals" | |
406 | - elsif key2 == "CLPO" | |
407 | - name2 = "Chemist's Localized Property-optimized Orbitals" | |
408 | - end | |
409 | - mo_ao_items.push(name2) | |
410 | - mo_ao_keys.push(key2) | |
411 | - end | |
412 | - } | |
381 | + if key[0..2] == "AO/" | |
382 | + key2 = key[3..-1] | |
383 | + name2 = key2 | |
384 | + if key2 == "NAO" | |
385 | + name2 = "Natural Atomic Orbitals" | |
386 | + elsif key2 == "NBO" | |
387 | + name2 = "Natural Bond Orbitals" | |
388 | + elsif key2 == "NHO" | |
389 | + name2 = "Natural Hybrid Orbitals" | |
390 | + elsif key2 == "NLMO" | |
391 | + name2 = "Natural Localized Molecular Orbitals" | |
392 | + elsif key2 == "PNAO" | |
393 | + name2 = "Pre-orthogonal Natural Atomic Orbitals" | |
394 | + elsif key2 == "PNHO" | |
395 | + name2 = "Pre-orthogonal Natural Hybrid Orbitals" | |
396 | + elsif key2 == "PNBO" | |
397 | + name2 = "Pre-orthogonal Natural Bond Orbitals" | |
398 | + elsif key2 == "AHO" | |
399 | + name2 = "Atomic Hybrid Orbitals" | |
400 | + elsif key2 == "LHO" | |
401 | + name2 = "Lewis Hybrid Orbitals" | |
402 | + elsif key2 == "PLHO" | |
403 | + name2 = "Pre-orthogonal Lewis Hybrid Orbitals" | |
404 | + elsif key2 == "LPO" | |
405 | + name2 = "Localized Property-optimized Orbitals" | |
406 | + elsif key2 == "CLPO" | |
407 | + name2 = "Chemist's Localized Property-optimized Orbitals" | |
408 | + end | |
409 | + mo_ao_items.push(name2) | |
410 | + mo_ao_keys.push(key2) | |
411 | + end | |
412 | + } | |
413 | 413 | end |
414 | 414 | mult = (motype == "UHF" ? 2 : 1) |
415 | 415 | mo_menu = ["1000 (-00.00000000)"] # Dummy entry; create later |
416 | 416 | tabvals = [] |
417 | - coeffs = nil | |
417 | + coeffs_matrix = nil # Coefficient matrix for showing surface | |
418 | + coeffs = nil # Coefficient array for showing surface | |
419 | + table_coeffs_matrix = nil # Coefficient matrix for table (based on "basis") | |
418 | 420 | a_idx_old = -1 |
419 | 421 | occ = nil |
420 | - ncomps.times { |i| | |
421 | - a_idx, s_idx, label = mol.get_gaussian_component_info(i) | |
422 | - if a_idx_old != a_idx | |
423 | - a_idx_old = a_idx | |
424 | - a = a_idx.to_s | |
425 | - n = mol.atoms[a_idx].name | |
426 | - else | |
427 | - a = n = "" | |
428 | - end | |
429 | - tabvals.push([a, n, label, a_idx]) | |
430 | - } | |
431 | 422 | on_update_attr = lambda { |
432 | 423 | tags.each { |tag| |
433 | 424 | surface_dialog_attr[tag] = item_with_tag(tag)[:value] |
@@ -445,23 +436,120 @@ class Molecule | ||
445 | 436 | it[:enabled] = true |
446 | 437 | end |
447 | 438 | } |
439 | + update_mo_labels = lambda { |mo_ao_index| | |
440 | + m = [] | |
441 | + if mo_ao_index == 0 | |
442 | + m = (1..(ncomps * mult)).map { |n| | |
443 | + if motype == "UHF" | |
444 | + i1 = (n - 1) / 2 + 1 | |
445 | + i2 = n % 2 | |
446 | + c1 = (i2 == 0 ? "B" : "A") | |
447 | + c2 = (i1 > (i2 == 0 ? beta : alpha) ? "*" : "") | |
448 | + else | |
449 | + i1 = n | |
450 | + i2 = 1 | |
451 | + c1 = "" | |
452 | + if i1 > beta && i1 > alpha | |
453 | + c2 = "*" | |
454 | + elsif i1 > beta || i1 > alpha | |
455 | + c2 = "S" | |
456 | + else | |
457 | + c2 = "" | |
458 | + end | |
459 | + end | |
460 | + en = mol.get_mo_energy(i1 + (i2 == 0 ? ncomps : 0)) | |
461 | + sprintf("%d%s%s (%.8f)", i1, c1, c2, en) | |
462 | + } | |
463 | + elsif mo_ao_index == 1 | |
464 | + m = [] | |
465 | + ncomps.times { |i| | |
466 | + m[i] = sprintf("%d: %s (%s)", i + 1, tabvals[i][2], mol.atoms[tabvals[i][3]].name) | |
467 | + } | |
468 | + else | |
469 | + m = [] | |
470 | + key = mo_ao_keys[mo_ao_index] | |
471 | + labels = nbo[key + "_L"] | |
472 | + if labels == nil && key[0] == ?P | |
473 | + labels = nbo[key[1..-1] + "_L"] | |
474 | + end | |
475 | + ncomps.times { |i| | |
476 | + if labels | |
477 | + lab = sprintf("%d: %s", i + 1, labels[i]) | |
478 | + else | |
479 | + lab = sprintf("%s%d", key, i + 1) | |
480 | + end | |
481 | + m[i] = lab | |
482 | + } | |
483 | + end | |
484 | + return m | |
485 | + } | |
448 | 486 | on_get_value = lambda { |it, row, col| |
449 | - if col < 3 | |
450 | - tabvals[row][col] | |
451 | - else | |
452 | - if coeffs == nil | |
453 | - if mo_ao == 0 | |
454 | - coeffs = mol.get_mo_coefficients(mo_index) | |
455 | - elsif mo_ao == 1 | |
456 | - coeffs = (0...ncomps).map { |i| (i == mo_index ? 1.0 : 0.0) } | |
457 | - else | |
458 | - coeffs = nbo["AO/" + mo_ao_keys[mo_ao]].column(mo_index).to_a[0] | |
459 | - end | |
460 | - end | |
461 | - sprintf("%.6f", coeffs[row]) | |
462 | - end | |
487 | + begin | |
488 | + if !table_coeffs_matrix || !coeffs_matrix | |
489 | + # Update tabvals | |
490 | + tabvals = [] | |
491 | + bs = value("basis") | |
492 | + if bs == 0 # AO | |
493 | + ncomps.times { |i| | |
494 | + a_idx, s_idx, label = mol.get_gaussian_component_info(i) | |
495 | + if a_idx_old != a_idx | |
496 | + a_idx_old = a_idx | |
497 | + a = a_idx.to_s | |
498 | + n = mol.atoms[a_idx].name | |
499 | + else | |
500 | + a = n = "" | |
501 | + end | |
502 | + tabvals.push([a, n, label, a_idx]) | |
503 | + } | |
504 | + else | |
505 | + labels = update_mo_labels.call(bs + 1) | |
506 | + ncomps.times { |i| | |
507 | + label = labels[i] | |
508 | + label = label.gsub(/^\d+: /, "") | |
509 | + tabvals.push([(i + 1).to_s, "", label, i]) | |
510 | + } | |
511 | + end | |
512 | + # Update coeffs_matrix | |
513 | + if !coeffs_matrix | |
514 | + # coeffs_matrix = AO/(orbitals_to_display) | |
515 | + if mo_ao == 0 | |
516 | + m = [] | |
517 | + ncomps.times { |i| | |
518 | + mult.times { |j| | |
519 | + m.push(mol.get_mo_coefficients(i * mult + j + 1)) | |
520 | + } | |
521 | + } | |
522 | + coeffs_matrix = LAMatrix.new(m) # Matrix AO/MO | |
523 | + elsif mo_ao == 1 | |
524 | + coeffs_matrix = LAMatrix.identity(ncomps) # Matrix AO/AO (identity) | |
525 | + else | |
526 | + coeffs_matrix = nbo["AO/" + mo_ao_keys[mo_ao]] | |
527 | + end | |
528 | + end | |
529 | + # m2 = AO/(basis) | |
530 | + if bs == 0 # AO | |
531 | + m2 = LAMatrix.identity(ncomps) | |
532 | + else | |
533 | + m2 = nbo["AO/" + mo_ao_keys[bs + 1]] | |
534 | + end | |
535 | + # (basis)/(orbitals_to_display) | |
536 | + table_coeffs_matrix = m2.inverse * coeffs_matrix | |
537 | + end | |
538 | + # Update coefficient array | |
539 | + if !coeffs | |
540 | + coeffs = coeffs_matrix.column(mo_index).to_a[0] | |
541 | + end | |
542 | + if col < 3 | |
543 | + tabvals[row][col] | |
544 | + else | |
545 | + sprintf("%.6f", table_coeffs_matrix[mo_index, row]) | |
546 | + end | |
547 | + rescue => e | |
548 | + $stderr.write(e.to_s + "\n") | |
549 | + $stderr.write(e.backtrace.inspect + "\n") | |
550 | + end | |
463 | 551 | } |
464 | - h = {"mo"=>nil, "color"=>nil, "opacity"=>nil, "threshold"=>nil, "expand"=>nil, "grid"=>nil} | |
552 | + h = {"mo"=>nil, "color"=>nil, "opacity"=>nil, "threshold"=>nil, "expand"=>nil, "grid"=>nil, "reverse"=>nil, "basis"=>nil } | |
465 | 553 | should_update = true |
466 | 554 | on_action = lambda { |it| |
467 | 555 | tag = it[:tag] |
@@ -475,10 +563,13 @@ class Molecule | ||
475 | 563 | color0 = [1,1,1,opac] |
476 | 564 | mol.set_surface_attr(:color=>color, :color0=>color0) |
477 | 565 | h[tag] = value |
478 | - elsif tag == "threshold" | |
479 | - thres = it[:value].to_f | |
566 | + elsif tag == "threshold" || tag == "reverse" | |
567 | + thres = item_with_tag("threshold")[:value].to_f | |
480 | 568 | thres = 0.001 if thres >= 0.0 && thres < 0.001 |
481 | 569 | thres = -0.001 if thres <= 0.0 && thres > -0.001 |
570 | + if item_with_tag("reverse")[:value] == 1 | |
571 | + thres = -thres | |
572 | + end | |
482 | 573 | mol.set_surface_attr(:thres=>thres) |
483 | 574 | h[tag] = value |
484 | 575 | else |
@@ -498,17 +589,17 @@ class Molecule | ||
498 | 589 | mo = it[:value] |
499 | 590 | if mo_ao == 0 |
500 | 591 | if motype == "UHF" |
501 | - mo_index = (mo / 2) + (mo % 2 == 1 ? ncomps : 0) + 1 | |
502 | - if mo_index <= alpha || (mo_index > ncomps && mo_index <= ncomps + beta) | |
592 | + mo_index = (mo / 2) + (mo % 2 == 1 ? ncomps : 0) | |
593 | + if mo_index < alpha || (mo_index >= ncomps && mo_index < ncomps + beta) | |
503 | 594 | occ_new = 1 |
504 | 595 | else |
505 | 596 | occ_new = 0 |
506 | 597 | end |
507 | 598 | else |
508 | - mo_index = mo + 1 | |
509 | - if mo_index <= alpha && mo_index <= beta | |
599 | + mo_index = mo | |
600 | + if mo_index < alpha && mo_index < beta | |
510 | 601 | occ_new = 1 |
511 | - elsif mo_index <= alpha || mo_index <= beta | |
602 | + elsif mo_index < alpha || mo_index < beta | |
512 | 603 | occ_new = -1 |
513 | 604 | else |
514 | 605 | occ_new = 0 |
@@ -539,58 +630,25 @@ class Molecule | ||
539 | 630 | } |
540 | 631 | on_set_action = lambda { |it| |
541 | 632 | if mo_ao != it[:value] |
542 | - mo_ao = it[:value] | |
543 | - if mo_ao == 0 | |
544 | - mo_menu = (1..(ncomps * mult)).map { |n| | |
545 | - if motype == "UHF" | |
546 | - i1 = (n - 1) / 2 + 1 | |
547 | - i2 = n % 2 | |
548 | - c1 = (i2 == 0 ? "B" : "A") | |
549 | - c2 = (i1 > (i2 == 0 ? beta : alpha) ? "*" : "") | |
550 | - else | |
551 | - i1 = n | |
552 | - i2 = 1 | |
553 | - c1 = "" | |
554 | - if i1 > beta && i1 > alpha | |
555 | - c2 = "*" | |
556 | - elsif i1 > beta || i1 > alpha | |
557 | - c2 = "S" | |
558 | - else | |
559 | - c2 = "" | |
560 | - end | |
561 | - end | |
562 | - en = mol.get_mo_energy(i1 + (i2 == 0 ? ncomps : 0)) | |
563 | - sprintf("%d%s%s (%.8f)", i1, c1, c2, en) | |
564 | - } | |
565 | - elsif mo_ao == 1 | |
566 | - mo_menu = [] | |
567 | - ncomps.times { |i| | |
568 | - mo_menu[i] = sprintf("%d: %s (%s)", i + 1, tabvals[i][2], mol.atoms[tabvals[i][3]].name) | |
569 | - } | |
570 | - else | |
571 | - mo_menu = [] | |
572 | - key = mo_ao_keys[mo_ao] | |
573 | - labels = nbo[key + "_L"] | |
574 | - if labels == nil && key[0] == ?P | |
575 | - labels = nbo[key[1..-1] + "_L"] | |
576 | - end | |
577 | - ncomps.times { |i| | |
578 | - if labels | |
579 | - lab = sprintf("%d: %s", i + 1, labels[i]) | |
580 | - else | |
581 | - lab = sprintf("%s%d", key, i + 1) | |
582 | - end | |
583 | - mo_menu[i] = lab | |
584 | - } | |
585 | - end | |
586 | - it0 = item_with_tag("mo") | |
587 | - it0[:subitems] = mo_menu | |
588 | - #it0[:value] = 0 # Keep the mo number invariant | |
589 | - h["mo"] = nil # "Update" button is forced to be enabled | |
590 | - on_mo_action.call(it0) | |
591 | - end | |
592 | - on_update_attr.call | |
633 | + mo_ao = it[:value] | |
634 | + mo_menu = update_mo_labels.call(mo_ao) | |
635 | + it0 = item_with_tag("mo") | |
636 | + val = it0[:value] | |
637 | + it0[:subitems] = mo_menu | |
638 | + it0[:value] = val # Keep the mo number invariant | |
639 | + h["mo"] = nil # "Update" button is forced to be enabled | |
640 | + coeffs = nil | |
641 | + coeffs_matrix = nil # Matrix needs update | |
642 | + on_mo_action.call(it0) | |
643 | + end | |
644 | + on_update_attr.call | |
593 | 645 | } |
646 | + on_basis_action = lambda { |it| | |
647 | + if h["basis"] != value("basis") | |
648 | + table_coeffs_matrix = nil | |
649 | + item_with_tag("table")[:refresh] = true | |
650 | + end | |
651 | + } | |
594 | 652 | on_update = lambda { |it| |
595 | 653 | h.each_key { |key| |
596 | 654 | h[key] = value(key) |
@@ -603,6 +661,9 @@ class Molecule | ||
603 | 661 | thres = h["threshold"].to_f |
604 | 662 | thres = 0.001 if thres >= 0.0 && thres < 0.001 |
605 | 663 | thres = -0.001 if thres <= 0.0 && thres > -0.001 |
664 | + if h["reverse"] == 1 | |
665 | + thres = -thres | |
666 | + end | |
606 | 667 | expand = h["expand"].to_f |
607 | 668 | expand = 0.01 if expand < 0.01 |
608 | 669 | expand = 10.0 if expand > 10.0 |
@@ -611,7 +672,7 @@ class Molecule | ||
611 | 672 | grid = 10000000 |
612 | 673 | end |
613 | 674 | if mo_ao == 0 |
614 | - idx = mo_index | |
675 | + idx = mo_index + 1 | |
615 | 676 | else |
616 | 677 | idx = 0 |
617 | 678 | mol.set_mo_coefficients(0, 0.0, coeffs) |
@@ -643,14 +704,21 @@ class Molecule | ||
643 | 704 | item(:textfield, :tag=>"opacity", :width=>80, :value=>"0.8", :action=>on_action), |
644 | 705 | item(:text, :title=>"Threshold"), |
645 | 706 | item(:textfield, :tag=>"threshold", :width=>80, :value=>"0.05", :action=>on_action), |
646 | - item(:text, :title=>"Box Limit"), | |
647 | - item(:textfield, :tag=>"expand", :width=>80, :value=>"1.4", :action=>on_action)), | |
648 | - layout(2, | |
707 | + item(:checkbox, :tag=>"reverse", :title=>"Reverse Phase", :action=>on_action), | |
708 | + -1), | |
709 | + layout(4, | |
649 | 710 | item(:text, :title=>"Number of Grid Points"), |
650 | - item(:textfield, :tag=>"grid", :width=>120, :value=>"512000", :action=>on_action)), | |
651 | - item(:table, :width=>300, :height=>300, :tag=>"table", | |
652 | - :columns=>[["Atom", 60], ["Name", 60], ["Label", 60], ["Coeff", 120]], | |
653 | - :on_count=> lambda { |it| tabvals.count }, | |
711 | + item(:textfield, :tag=>"grid", :width=>80, :value=>"512000", :action=>on_action), | |
712 | + item(:text, :title=>"Box Limit"), | |
713 | + item(:textfield, :tag=>"expand", :width=>80, :value=>"1.4", :action=>on_action)), | |
714 | + # table coefficients are based on "basis" (AO, NAO, etc.) | |
715 | + # MO is not allowed as basis, so the "basis" menu begins with "AO" | |
716 | + layout(2, | |
717 | + item(:text, :title=>"Coeffs based on:"), | |
718 | + item(:popup, :tag=>"basis", :subitems=>mo_ao_keys[1..-1], :value=>1, :action=>on_basis_action)), | |
719 | + item(:table, :width=>380, :height=>300, :tag=>"table", | |
720 | + :columns=>[["Atom", 40], ["Name", 60], ["Label", 140], ["Coeff", 120]], | |
721 | + :on_count=> lambda { |it| ncomps }, | |
654 | 722 | :on_get_value=>on_get_value, |
655 | 723 | :flex=>[0,0,0,0,1,1]), |
656 | 724 | layout(3, |
@@ -2065,6 +2065,7 @@ class Molecule | ||
2065 | 2065 | :action=>lambda { |it| |
2066 | 2066 | flag = (it[:value] != 0) |
2067 | 2067 | nbo_desc.each { |nbo| set_attr(nbo, :enabled=>flag) } |
2068 | + set_attr("check_java", :enabled=>flag) | |
2068 | 2069 | }), |
2069 | 2070 | -1, -1, -1, |
2070 | 2071 | # ------ |
@@ -2079,7 +2080,15 @@ class Molecule | ||
2079 | 2080 | -1, |
2080 | 2081 | # ------ |
2081 | 2082 | item(:text, :title=>"* Not JANPA original; Molby extension", :font=>[9]), |
2082 | - -1, -1, -1, | |
2083 | + -1, -1, | |
2084 | + item(:button, :title=>"Check Java...", :tag=>"check_java", | |
2085 | + :action=>lambda { |it| | |
2086 | + if Molecule.is_java_available() | |
2087 | + message_box("Java installation looks OK.", "", :ok) | |
2088 | + else | |
2089 | + Molecule.make_java_available() | |
2090 | + end | |
2091 | + }), | |
2083 | 2092 | # ------ |
2084 | 2093 | item(:line), |
2085 | 2094 | -1, -1, -1, |
@@ -2144,9 +2153,8 @@ class Molecule | ||
2144 | 2153 | set_attr("psi4conda_folder", :enabled=>(values["execute_local"] == 1)) |
2145 | 2154 | set_attr("select_folder", :enabled=>(values["execute_local"] == 1)) |
2146 | 2155 | set_attr("ncpus", :enabled=>(values["execute_local"] == 1)) |
2147 | - #nbos.each { |nao| | |
2148 | - # set_attr(nao, :enabled=>(values["include_nbo"] == 1)) | |
2149 | - #} | |
2156 | + nbo_desc.each { |nbo| set_attr(nbo, :enabled=>(values["run_janpa"] == 1)) } | |
2157 | + set_attr("check_java", :enabled=>(values["run_janpa"] == 1)) | |
2150 | 2158 | } # end Dialog.run |
2151 | 2159 | |
2152 | 2160 | hash.each_pair { |key, value| |
@@ -547,7 +547,7 @@ class Molecule | ||
547 | 547 | break if line =~ /^\s*$/ |
548 | 548 | tokens = line.split(' ') |
549 | 549 | if natoms > 0 && first_frame == nframes |
550 | - if index >= natoms || tokens[0] != atoms[index].element | |
550 | + if index >= natoms || tokens[0].upcase != atoms[index].element.upcase | |
551 | 551 | hide_progress_panel |
552 | 552 | raise MolbyError, "The atom list does not match the current structure at line #{@lineno}" |
553 | 553 | end |