Molecular Modeling Software
リビジョン | ecd68891964a02f236a3bd0715977f6cb20a9849 (tree) |
---|---|
日時 | 2016-04-28 00:42:31 |
作者 | toshinagata1964 <toshinagata1964@a2be...> |
コミッター | toshinagata1964 |
A CIF file with multiple structures now can be processed (multiple documents are opened in this case)
git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/molby/trunk@594 a2be9bc6-48de-4e38-9406-05402d4bc13c
@@ -5453,6 +5453,24 @@ s_Molecule_SetErrorMessage(VALUE klass, VALUE sval) | ||
5453 | 5453 | return sval; |
5454 | 5454 | } |
5455 | 5455 | |
5456 | +/* | |
5457 | + * call-seq: | |
5458 | + * set_molecule(Molecule) | |
5459 | + * | |
5460 | + * Duplicate the given molecule and set to self. The present molecule must be empty. | |
5461 | + * This method is exclusively used for associating a new document with an existing molecule. | |
5462 | + */ | |
5463 | +static VALUE | |
5464 | +s_Molecule_SetMolecule(VALUE self, VALUE mval) | |
5465 | +{ | |
5466 | + Molecule *mp1, *mp2; | |
5467 | + Data_Get_Struct(self, Molecule, mp1); | |
5468 | + mp2 = MoleculeFromValue(mval); | |
5469 | + MoleculeInitWithMolecule(mp1, mp2); | |
5470 | + MoleculeCallback_notifyModification(mp1, 1); | |
5471 | + return self; | |
5472 | +} | |
5473 | + | |
5456 | 5474 | #pragma mark ------ Name attributes ------ |
5457 | 5475 | |
5458 | 5476 | /* |
@@ -11462,6 +11480,7 @@ Init_Molby(void) | ||
11462 | 11480 | rb_define_method(rb_cMolecule, "savedcd", s_Molecule_Savedcd, 1); |
11463 | 11481 | rb_define_method(rb_cMolecule, "molload", s_Molecule_Load, -1); |
11464 | 11482 | rb_define_method(rb_cMolecule, "molsave", s_Molecule_Save, -1); |
11483 | + rb_define_method(rb_cMolecule, "set_molecule", s_Molecule_SetMolecule, 1); | |
11465 | 11484 | rb_define_singleton_method(rb_cMolecule, "open", s_Molecule_Open, -1); |
11466 | 11485 | rb_define_singleton_method(rb_cMolecule, "error_message", s_Molecule_ErrorMessage, 0); |
11467 | 11486 | rb_define_singleton_method(rb_cMolecule, "set_error_message", s_Molecule_SetErrorMessage, 1); |
@@ -761,6 +761,7 @@ end_of_header | ||
761 | 761 | alias :savegjf :savecom |
762 | 762 | |
763 | 763 | def loadcif(filename) |
764 | + mol = self | |
764 | 765 | def getciftoken(fp) |
765 | 766 | while @tokens.length == 0 |
766 | 767 | line = fp.gets |
@@ -820,302 +821,329 @@ end_of_header | ||
820 | 821 | end |
821 | 822 | sym |
822 | 823 | end |
823 | - def find_atom_by_name(name) | |
824 | + def find_atom_by_name(mol, name) | |
824 | 825 | name = name.delete(" ()") |
825 | - ap = self.atoms[name] rescue ap = nil | |
826 | + ap = mol.atoms[name] rescue ap = nil | |
826 | 827 | return ap |
827 | 828 | end |
828 | - warn_message = "" | |
829 | - verbose = nil | |
830 | - bond_defined = false | |
831 | - @tokens = [] | |
832 | - special_positions = [] | |
833 | - self.remove(All) | |
829 | + selfname = self.name | |
834 | 830 | fp = open(filename, "rb") |
835 | - cell = [] | |
836 | - cell_trans = cell_trans_inv = Transform.identity | |
837 | - token = getciftoken(fp) | |
838 | - pardigits_re = /\(\d+\)/ | |
839 | - calculated_atoms = [] | |
840 | - while token != nil | |
841 | - if token =~ /^_cell/ | |
842 | - val = getciftoken(fp) | |
843 | - if token == "_cell_length_a" | |
844 | - cell[0], cell[6] = float_strip_rms(val) | |
845 | - elsif token == "_cell_length_b" | |
846 | - cell[1], cell[7] = float_strip_rms(val) | |
847 | - elsif token == "_cell_length_c" | |
848 | - cell[2], cell[8] = float_strip_rms(val) | |
849 | - elsif token == "_cell_angle_alpha" | |
850 | - cell[3], cell[9] = float_strip_rms(val) | |
851 | - elsif token == "_cell_angle_beta" | |
852 | - cell[4], cell[10] = float_strip_rms(val) | |
853 | - elsif token == "_cell_angle_gamma" | |
854 | - cell[5], cell[11] = float_strip_rms(val) | |
855 | - end | |
856 | - if cell.length == 12 && cell.all? | |
857 | - self.cell = cell | |
858 | - puts "Unit cell is set to #{cell.inspect}." if verbose | |
859 | - cell = [] | |
860 | - cell_trans = self.cell_transform | |
861 | - cell_trans_inv = cell_trans.inverse | |
862 | - end | |
863 | - token = getciftoken(fp) | |
864 | - next | |
865 | - elsif token.casecmp("#loop_") == 0 | |
866 | - labels = [] | |
867 | - while (token = getciftoken(fp)) && token[0] == ?_ | |
868 | - labels.push(token) | |
869 | - end | |
870 | - if labels[0] =~ /symmetry_equiv_pos|atom_site_label|atom_site_aniso_label|geom_bond/ | |
871 | - hlabel = Hash.new(-10000000) | |
872 | - labels.each_with_index { |lb, i| | |
873 | - hlabel[lb] = i | |
874 | - } | |
875 | - data = [] | |
876 | - n = labels.length | |
877 | - a = [] | |
878 | - while 1 | |
879 | - break if token == nil || token[0] == ?_ || token[0] == ?# | |
880 | - a.push(token) | |
881 | - if a.length == n | |
882 | - data.push(a) | |
883 | - a = [] | |
884 | - end | |
831 | + data_identifier = nil | |
832 | + @tokens = [] | |
833 | + count_up = 1 | |
834 | + while true | |
835 | + warn_message = "" | |
836 | + verbose = nil | |
837 | + bond_defined = false | |
838 | + special_positions = [] | |
839 | + mol.remove(All) | |
840 | + cell = [] | |
841 | + cell_trans = cell_trans_inv = Transform.identity | |
842 | + token = getciftoken(fp) | |
843 | + pardigits_re = /\(\d+\)/ | |
844 | + calculated_atoms = [] | |
845 | + while token != nil | |
846 | + if token =~ /^\#data_/i | |
847 | + if token.casecmp("#data_global") == 0 | |
848 | + token = getciftoken(fp) | |
849 | + next | |
850 | + elsif data_identifier == nil | |
851 | + # Continue processing of this molecule | |
852 | + data_identifier = token | |
885 | 853 | token = getciftoken(fp) |
854 | + next | |
855 | + else | |
856 | + # Description of another molecule begins here | |
857 | + data_identifier = token | |
858 | + break | |
859 | + end | |
860 | + elsif token =~ /^_cell/ | |
861 | + val = getciftoken(fp) | |
862 | + if token == "_cell_length_a" | |
863 | + cell[0], cell[6] = float_strip_rms(val) | |
864 | + elsif token == "_cell_length_b" | |
865 | + cell[1], cell[7] = float_strip_rms(val) | |
866 | + elsif token == "_cell_length_c" | |
867 | + cell[2], cell[8] = float_strip_rms(val) | |
868 | + elsif token == "_cell_angle_alpha" | |
869 | + cell[3], cell[9] = float_strip_rms(val) | |
870 | + elsif token == "_cell_angle_beta" | |
871 | + cell[4], cell[10] = float_strip_rms(val) | |
872 | + elsif token == "_cell_angle_gamma" | |
873 | + cell[5], cell[11] = float_strip_rms(val) | |
874 | + end | |
875 | + if cell.length == 12 && cell.all? | |
876 | + mol.cell = cell | |
877 | + puts "Unit cell is set to #{cell.inspect}." if verbose | |
878 | + cell = [] | |
879 | + cell_trans = self.cell_transform | |
880 | + cell_trans_inv = cell_trans.inverse | |
881 | + end | |
882 | + token = getciftoken(fp) | |
883 | + next | |
884 | + elsif token.casecmp("#loop_") == 0 | |
885 | + labels = [] | |
886 | + while (token = getciftoken(fp)) && token[0] == ?_ | |
887 | + labels.push(token) | |
886 | 888 | end |
887 | - if labels[0] =~ /^_symmetry_equiv_pos/ | |
888 | - data.each { |d| | |
889 | - symstr = d[hlabel["_symmetry_equiv_pos_as_xyz"]] | |
890 | - symstr.delete("\"\'") | |
891 | - exps = symstr.split(/,/) | |
892 | - sym = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
893 | - exps.each_with_index { |s, i| | |
894 | - terms = s.scan(/([-+]?)(([.0-9]+)(\/([0-9]+))?([xXyYzZ])?|([xXyYzZ]))/) | |
895 | - terms.each { |a| | |
896 | - # a[0]: sign, a[2]: numerator, a[4]: denometer | |
897 | - if a[4] != nil | |
898 | - # The number part is a[2]/a[4] | |
899 | - num = Float(a[2])/Float(a[4]) | |
900 | - elsif a[2] != nil | |
901 | - # The number part is either integer or a floating point | |
902 | - num = Float(a[2]) | |
889 | + if labels[0] =~ /symmetry_equiv_pos|atom_site_label|atom_site_aniso_label|geom_bond/ | |
890 | + hlabel = Hash.new(-10000000) | |
891 | + labels.each_with_index { |lb, i| | |
892 | + hlabel[lb] = i | |
893 | + } | |
894 | + data = [] | |
895 | + n = labels.length | |
896 | + a = [] | |
897 | + while true | |
898 | + break if token == nil || token[0] == ?_ || token[0] == ?# | |
899 | + a.push(token) | |
900 | + if a.length == n | |
901 | + data.push(a) | |
902 | + a = [] | |
903 | + end | |
904 | + token = getciftoken(fp) | |
905 | + end | |
906 | + if labels[0] =~ /^_symmetry_equiv_pos/ | |
907 | + data.each { |d| | |
908 | + symstr = d[hlabel["_symmetry_equiv_pos_as_xyz"]] | |
909 | + symstr.delete("\"\'") | |
910 | + exps = symstr.split(/,/) | |
911 | + sym = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
912 | + exps.each_with_index { |s, i| | |
913 | + terms = s.scan(/([-+]?)(([.0-9]+)(\/([0-9]+))?([xXyYzZ])?|([xXyYzZ]))/) | |
914 | + terms.each { |a| | |
915 | + # a[0]: sign, a[2]: numerator, a[4]: denometer | |
916 | + if a[4] != nil | |
917 | + # The number part is a[2]/a[4] | |
918 | + num = Float(a[2])/Float(a[4]) | |
919 | + elsif a[2] != nil | |
920 | + # The number part is either integer or a floating point | |
921 | + num = Float(a[2]) | |
922 | + else | |
923 | + num = 1.0 | |
924 | + end | |
925 | + num = -num if a[0][0] == ?- | |
926 | + xyz = (a[5] || a[6]) | |
927 | + if xyz == "x" || xyz == "X" | |
928 | + sym[i] = num | |
929 | + elsif xyz == "y" || xyz == "Y" | |
930 | + sym[i + 3] = num | |
931 | + elsif xyz == "z" || xyz == "Z" | |
932 | + sym[i + 6] = num | |
933 | + else | |
934 | + sym[9 + i] = num | |
935 | + end | |
936 | + } | |
937 | + } | |
938 | + puts "symmetry operation #{sym.inspect}" if verbose | |
939 | + mol.add_symmetry(Transform.new(sym)) | |
940 | + } | |
941 | + puts "#{mol.nsymmetries} symmetry operations are added" if verbose | |
942 | + elsif labels[0] =~ /^_atom_site_label/ | |
943 | + # Create atoms | |
944 | + data.each { |d| | |
945 | + name = d[hlabel["_atom_site_label"]] | |
946 | + elem = d[hlabel["_atom_site_type_symbol"]] | |
947 | + fx = d[hlabel["_atom_site_fract_x"]] | |
948 | + fy = d[hlabel["_atom_site_fract_y"]] | |
949 | + fz = d[hlabel["_atom_site_fract_z"]] | |
950 | + uiso = d[hlabel["_atom_site_U_iso_or_equiv"]] | |
951 | + biso = d[hlabel["_atom_site_B_iso_or_equiv"]] | |
952 | + occ = d[hlabel["_atom_site_occupancy"]] | |
953 | + calc = d[hlabel["_atom_site_calc_flag"]] | |
954 | + name = name.delete(" ()") | |
955 | + if elem == nil || elem == "" | |
956 | + if name =~ /[A-Za-z]{1,2}/ | |
957 | + elem = $&.capitalize | |
903 | 958 | else |
904 | - num = 1.0 | |
959 | + elem = "Du" | |
905 | 960 | end |
906 | - num = -num if a[0][0] == ?- | |
907 | - xyz = (a[5] || a[6]) | |
908 | - if xyz == "x" || xyz == "X" | |
909 | - sym[i] = num | |
910 | - elsif xyz == "y" || xyz == "Y" | |
911 | - sym[i + 3] = num | |
912 | - elsif xyz == "z" || xyz == "Z" | |
913 | - sym[i + 6] = num | |
914 | - else | |
915 | - sym[9 + i] = num | |
961 | + end | |
962 | + ap = mol.add_atom(name, elem, elem) | |
963 | + ap.fract_x, ap.sigma_x = float_strip_rms(fx) | |
964 | + ap.fract_y, ap.sigma_y = float_strip_rms(fy) | |
965 | + ap.fract_z, ap.sigma_z = float_strip_rms(fz) | |
966 | + if biso | |
967 | + ap.temp_factor, sig = float_strip_rms(biso) | |
968 | + elsif uiso | |
969 | + ap.temp_factor, sig = float_strip_rms(uiso) | |
970 | + ap.temp_factor *= 78.9568352087149 # 8*pi*pi | |
971 | + end | |
972 | + ap.occupancy, sig = float_strip_rms(occ) | |
973 | + if calc == "c" || calc == "calc" | |
974 | + calculated_atoms.push(ap.index) | |
975 | + end | |
976 | + # Guess special positions | |
977 | + (1...mol.nsymmetries).each { |isym| | |
978 | + sr = ap.fract_r | |
979 | + sr = (mol.transform_for_symop(isym) * sr) - sr; | |
980 | + nx = (sr.x + 0.5).floor | |
981 | + ny = (sr.y + 0.5).floor | |
982 | + nz = (sr.z + 0.5).floor | |
983 | + if (Vector3D[sr.x - nx, sr.y - ny, sr.z - nz].length2 < 1e-6) | |
984 | + # [isym, -nx, -ny, -nz] transforms this atom to itself | |
985 | + # The following line is equivalent to: | |
986 | + # if special_positions[ap.index] == nil; special_positions[ap.index] = []; end; | |
987 | + # special_positions[ap.index].push(...) | |
988 | + (special_positions[ap.index] ||= []).push([isym, -nx, -ny, -nz]) | |
916 | 989 | end |
917 | - } | |
990 | + } | |
991 | + if verbose && special_positions[ap.index] | |
992 | + puts "#{name} is on the special position: #{special_positions[ap.index].inspect}" | |
993 | + end | |
918 | 994 | } |
919 | - puts "symmetry operation #{sym.inspect}" if verbose | |
920 | - add_symmetry(Transform.new(sym)) | |
921 | - } | |
922 | - puts "#{self.nsymmetries} symmetry operations are added" if verbose | |
923 | - elsif labels[0] =~ /^_atom_site_label/ | |
924 | - # Create atoms | |
925 | - data.each { |d| | |
926 | - name = d[hlabel["_atom_site_label"]] | |
927 | - elem = d[hlabel["_atom_site_type_symbol"]] | |
928 | - fx = d[hlabel["_atom_site_fract_x"]] | |
929 | - fy = d[hlabel["_atom_site_fract_y"]] | |
930 | - fz = d[hlabel["_atom_site_fract_z"]] | |
931 | - uiso = d[hlabel["_atom_site_U_iso_or_equiv"]] | |
932 | - biso = d[hlabel["_atom_site_B_iso_or_equiv"]] | |
933 | - occ = d[hlabel["_atom_site_occupancy"]] | |
934 | - calc = d[hlabel["_atom_site_calc_flag"]] | |
935 | - name = name.delete(" ()") | |
936 | - if elem == nil || elem == "" | |
937 | - if name =~ /[A-Za-z]{1,2}/ | |
938 | - elem = $&.capitalize | |
939 | - else | |
940 | - elem = "Du" | |
941 | - end | |
942 | - end | |
943 | - ap = self.add_atom(name, elem, elem) | |
944 | - ap.fract_x, ap.sigma_x = float_strip_rms(fx) | |
945 | - ap.fract_y, ap.sigma_y = float_strip_rms(fy) | |
946 | - ap.fract_z, ap.sigma_z = float_strip_rms(fz) | |
947 | - if biso | |
948 | - ap.temp_factor, sig = float_strip_rms(biso) | |
949 | - elsif uiso | |
950 | - ap.temp_factor, sig = float_strip_rms(uiso) | |
951 | - ap.temp_factor *= 78.9568352087149 # 8*pi*pi | |
952 | - end | |
953 | - ap.occupancy, sig = float_strip_rms(occ) | |
954 | - if calc == "c" || calc == "calc" | |
955 | - calculated_atoms.push(ap.index) | |
956 | - end | |
957 | - # Guess special positions | |
958 | - (1...nsymmetries).each { |isym| | |
959 | - sr = ap.fract_r | |
960 | - sr = (transform_for_symop(isym) * sr) - sr; | |
961 | - nx = (sr.x + 0.5).floor | |
962 | - ny = (sr.y + 0.5).floor | |
963 | - nz = (sr.z + 0.5).floor | |
964 | - if (Vector3D[sr.x - nx, sr.y - ny, sr.z - nz].length2 < 1e-6) | |
965 | - # [isym, -nx, -ny, -nz] transforms this atom to itself | |
966 | - # The following line is equivalent to: | |
967 | - # if special_positions[ap.index] == nil; special_positions[ap.index] = []; end; | |
968 | - # special_positions[ap.index].push(...) | |
969 | - (special_positions[ap.index] ||= []).push([isym, -nx, -ny, -nz]) | |
970 | - end | |
995 | + puts "#{mol.natoms} atoms are created." if verbose | |
996 | + elsif labels[0] =~ /^_atom_site_aniso_label/ | |
997 | + # Set anisotropic parameters | |
998 | + c = 0 | |
999 | + data.each { |d| | |
1000 | + name = d[hlabel["_atom_site_aniso_label"]] | |
1001 | + ap = find_atom_by_name(mol, name) | |
1002 | + next if !ap | |
1003 | + u11 = d[hlabel["_atom_site_aniso_U_11"]] | |
1004 | + if u11 | |
1005 | + usig = [] | |
1006 | + u11, usig[0] = float_strip_rms(u11) | |
1007 | + u22, usig[1] = float_strip_rms(d[hlabel["_atom_site_aniso_U_22"]]) | |
1008 | + u33, usig[2] = float_strip_rms(d[hlabel["_atom_site_aniso_U_33"]]) | |
1009 | + u12, usig[3] = float_strip_rms(d[hlabel["_atom_site_aniso_U_12"]]) | |
1010 | + u13, usig[4] = float_strip_rms(d[hlabel["_atom_site_aniso_U_13"]]) | |
1011 | + u23, usig[5] = float_strip_rms(d[hlabel["_atom_site_aniso_U_23"]]) | |
1012 | + ap.aniso = [u11, u22, u33, u12, u13, u23, 8] + usig | |
1013 | + c += 1 | |
1014 | + end | |
971 | 1015 | } |
972 | - if verbose && special_positions[ap.index] | |
973 | - puts "#{name} is on the special position: #{special_positions[ap.index].inspect}" | |
974 | - end | |
975 | - } | |
976 | - puts "#{self.natoms} atoms are created." if verbose | |
977 | - elsif labels[0] =~ /^_atom_site_aniso_label/ | |
978 | - # Set anisotropic parameters | |
979 | - c = 0 | |
980 | - data.each { |d| | |
981 | - name = d[hlabel["_atom_site_aniso_label"]] | |
982 | - ap = find_atom_by_name(name) | |
983 | - next if !ap | |
984 | - u11 = d[hlabel["_atom_site_aniso_U_11"]] | |
985 | - if u11 | |
986 | - usig = [] | |
987 | - u11, usig[0] = float_strip_rms(u11) | |
988 | - u22, usig[1] = float_strip_rms(d[hlabel["_atom_site_aniso_U_22"]]) | |
989 | - u33, usig[2] = float_strip_rms(d[hlabel["_atom_site_aniso_U_33"]]) | |
990 | - u12, usig[3] = float_strip_rms(d[hlabel["_atom_site_aniso_U_12"]]) | |
991 | - u13, usig[4] = float_strip_rms(d[hlabel["_atom_site_aniso_U_13"]]) | |
992 | - u23, usig[5] = float_strip_rms(d[hlabel["_atom_site_aniso_U_23"]]) | |
993 | - ap.aniso = [u11, u22, u33, u12, u13, u23, 8] + usig | |
994 | - c += 1 | |
995 | - end | |
996 | - } | |
997 | - puts "#{c} anisotropic parameters are set." if verbose | |
998 | - elsif labels[0] =~ /^_geom_bond/ | |
999 | - # Create bonds | |
1000 | - exbonds = [] | |
1001 | - data.each { |d| | |
1002 | - n1 = d[hlabel["_geom_bond_atom_site_label_1"]] | |
1003 | - n2 = d[hlabel["_geom_bond_atom_site_label_2"]] | |
1004 | - sym1 = d[hlabel["_geom_bond_site_symmetry_1"]] || "." | |
1005 | - sym2 = d[hlabel["_geom_bond_site_symmetry_2"]] || "." | |
1006 | - n1 = find_atom_by_name(n1) | |
1007 | - n2 = find_atom_by_name(n2) | |
1008 | - next if n1 == nil || n2 == nil | |
1009 | - n1 = n1.index | |
1010 | - n2 = n2.index | |
1011 | - sym1 = parse_symmetry_operation(sym1) | |
1012 | - sym2 = parse_symmetry_operation(sym2) | |
1013 | - if sym1 || sym2 | |
1014 | - exbonds.push([n1, n2, sym1, sym2]) | |
1015 | - else | |
1016 | - self.create_bond(n1, n2) | |
1017 | - end | |
1018 | - tr1 = (sym1 ? transform_for_symop(sym1) : Transform.identity) | |
1019 | - tr2 = (sym2 ? transform_for_symop(sym2) : Transform.identity) | |
1020 | - if special_positions[n1] | |
1021 | - # Add extra bonds for equivalent positions of n1 | |
1022 | - special_positions[n1].each { |symop| | |
1023 | - sym2x = symop_for_transform(tr1 * transform_for_symop(symop) * tr1.inverse * tr2) | |
1024 | - exbonds.push([n1, n2, sym1, sym2x]) | |
1025 | - } | |
1026 | - end | |
1027 | - if special_positions[n2] | |
1028 | - # Add extra bonds n2-n1.symop, where symop transforms n2 to self | |
1029 | - tr = (sym1 ? transform_for_symop(sym1) : Transform.identity) | |
1030 | - special_positions[n2].each { |symop| | |
1031 | - sym1x = symop_for_transform(tr2 * transform_for_symop(symop) * tr2.inverse * tr1) | |
1032 | - exbonds.push([n2, n1, sym2, sym1x]) | |
1033 | - } | |
1034 | - end | |
1035 | - } | |
1036 | - bond_defined = true | |
1037 | - puts "#{self.nbonds} bonds are created." if verbose | |
1038 | - if calculated_atoms.length > 0 | |
1039 | - # Guess bonds for calculated hydrogen atoms | |
1040 | - n1 = 0 | |
1041 | - calculated_atoms.each { |ai| | |
1042 | - if atoms[ai].connects.length == 0 | |
1043 | - as = find_close_atoms(ai) | |
1044 | - as.each { |aj| | |
1045 | - self.create_bond(ai, aj) | |
1046 | - n1 += 1 | |
1016 | + puts "#{c} anisotropic parameters are set." if verbose | |
1017 | + elsif labels[0] =~ /^_geom_bond/ | |
1018 | + # Create bonds | |
1019 | + exbonds = [] | |
1020 | + data.each { |d| | |
1021 | + n1 = d[hlabel["_geom_bond_atom_site_label_1"]] | |
1022 | + n2 = d[hlabel["_geom_bond_atom_site_label_2"]] | |
1023 | + sym1 = d[hlabel["_geom_bond_site_symmetry_1"]] || "." | |
1024 | + sym2 = d[hlabel["_geom_bond_site_symmetry_2"]] || "." | |
1025 | + n1 = find_atom_by_name(mol, n1) | |
1026 | + n2 = find_atom_by_name(mol, n2) | |
1027 | + next if n1 == nil || n2 == nil | |
1028 | + n1 = n1.index | |
1029 | + n2 = n2.index | |
1030 | + sym1 = parse_symmetry_operation(sym1) | |
1031 | + sym2 = parse_symmetry_operation(sym2) | |
1032 | + if sym1 || sym2 | |
1033 | + exbonds.push([n1, n2, sym1, sym2]) | |
1034 | + else | |
1035 | + mol.create_bond(n1, n2) | |
1036 | + end | |
1037 | + tr1 = (sym1 ? mol.transform_for_symop(sym1) : Transform.identity) | |
1038 | + tr2 = (sym2 ? mol.transform_for_symop(sym2) : Transform.identity) | |
1039 | + if special_positions[n1] | |
1040 | + # Add extra bonds for equivalent positions of n1 | |
1041 | + special_positions[n1].each { |symop| | |
1042 | + sym2x = mol.symop_for_transform(tr1 * mol.transform_for_symop(symop) * tr1.inverse * tr2) | |
1043 | + exbonds.push([n1, n2, sym1, sym2x]) | |
1047 | 1044 | } |
1048 | - end | |
1049 | - } | |
1050 | - puts "#{n1} bonds are guessed." if verbose | |
1051 | - end | |
1052 | - if exbonds.length > 0 | |
1053 | - h = Dialog.run("CIF Import: Symmetry Expansion") { | |
1054 | - layout(1, | |
1055 | - item(:text, :title=>"There are bonds including symmetry related atoms.\nWhat do you want to do?"), | |
1056 | - item(:radio, :title=>"Expand only atoms that are included in those extra bonds.", :tag=>"atoms_only"), | |
1057 | - item(:radio, :title=>"Expand fragments having atoms included in the extra bonds.", :tag=>"fragment", :value=>1), | |
1058 | - item(:radio, :title=>"Ignore these extra bonds.", :tag=>"ignore") | |
1059 | - ) | |
1060 | - radio_group("atoms_only", "fragment", "ignore") | |
1061 | - } | |
1062 | - if h[:status] == 0 && h["ignore"] == 0 | |
1063 | - atoms_only = (h["atoms_only"] != 0) | |
1064 | - if !atoms_only | |
1065 | - fragments = [] | |
1066 | - self.each_fragment { |f| fragments.push(f) } | |
1067 | - end | |
1068 | - debug = nil | |
1069 | - exbonds.each { |ex| | |
1070 | - if debug; puts "extra bond #{ex[0]}(#{ex[2].inspect}) - #{ex[1]}(#{ex[3].inspect})"; end | |
1071 | - ex0 = ex.dup | |
1072 | - (2..3).each { |i| | |
1073 | - symop = ex[i] | |
1074 | - if symop == nil | |
1075 | - ex[i + 2] = ex[i - 2] | |
1076 | - else | |
1077 | - if debug; puts " symop = #{symop.inspect}"; end | |
1078 | - # Expand the atom or the fragment including the atom | |
1079 | - if atoms_only | |
1080 | - ig = IntGroup[ex[i - 2]] | |
1081 | - idx = 0 | |
1045 | + end | |
1046 | + if special_positions[n2] | |
1047 | + # Add extra bonds n2-n1.symop, where symop transforms n2 to self | |
1048 | + tr = (sym1 ? mol.transform_for_symop(sym1) : Transform.identity) | |
1049 | + special_positions[n2].each { |symop| | |
1050 | + sym1x = mol.symop_for_transform(tr2 * mol.transform_for_symop(symop) * tr2.inverse * tr1) | |
1051 | + exbonds.push([n2, n1, sym2, sym1x]) | |
1052 | + } | |
1053 | + end | |
1054 | + } | |
1055 | + bond_defined = true | |
1056 | + puts "#{mol.nbonds} bonds are created." if verbose | |
1057 | + if calculated_atoms.length > 0 | |
1058 | + # Guess bonds for calculated hydrogen atoms | |
1059 | + n1 = 0 | |
1060 | + calculated_atoms.each { |ai| | |
1061 | + if mol.atoms[ai].connects.length == 0 | |
1062 | + as = mol.find_close_atoms(ai) | |
1063 | + as.each { |aj| | |
1064 | + mol.create_bond(ai, aj) | |
1065 | + n1 += 1 | |
1066 | + } | |
1067 | + end | |
1068 | + } | |
1069 | + puts "#{n1} bonds are guessed." if verbose | |
1070 | + end | |
1071 | + if exbonds.length > 0 | |
1072 | + h = Dialog.run("CIF Import: Symmetry Expansion") { | |
1073 | + layout(1, | |
1074 | + item(:text, :title=>"There are bonds including symmetry related atoms.\nWhat do you want to do?"), | |
1075 | + item(:radio, :title=>"Expand only atoms that are included in those extra bonds.", :tag=>"atoms_only"), | |
1076 | + item(:radio, :title=>"Expand fragments having atoms included in the extra bonds.", :tag=>"fragment", :value=>1), | |
1077 | + item(:radio, :title=>"Ignore these extra bonds.", :tag=>"ignore") | |
1078 | + ) | |
1079 | + radio_group("atoms_only", "fragment", "ignore") | |
1080 | + } | |
1081 | + if h[:status] == 0 && h["ignore"] == 0 | |
1082 | + atoms_only = (h["atoms_only"] != 0) | |
1083 | + if !atoms_only | |
1084 | + fragments = [] | |
1085 | + mol.each_fragment { |f| fragments.push(f) } | |
1086 | + end | |
1087 | + debug = nil | |
1088 | + exbonds.each { |ex| | |
1089 | + if debug; puts "extra bond #{ex[0]}(#{ex[2].inspect}) - #{ex[1]}(#{ex[3].inspect})"; end | |
1090 | + ex0 = ex.dup | |
1091 | + (2..3).each { |i| | |
1092 | + symop = ex[i] | |
1093 | + if symop == nil | |
1094 | + ex[i + 2] = ex[i - 2] | |
1082 | 1095 | else |
1083 | - ig = fragments.find { |f| f.include?(ex[i - 2]) } | |
1084 | - ig.each_with_index { |n, ii| if n == ex[i - 2]; idx = ii; break; end } | |
1096 | + if debug; puts " symop = #{symop.inspect}"; end | |
1097 | + # Expand the atom or the fragment including the atom | |
1098 | + if atoms_only | |
1099 | + ig = IntGroup[ex[i - 2]] | |
1100 | + idx = 0 | |
1101 | + else | |
1102 | + ig = fragments.find { |f| f.include?(ex[i - 2]) } | |
1103 | + ig.each_with_index { |n, ii| if n == ex[i - 2]; idx = ii; break; end } | |
1104 | + end | |
1105 | + symop[4] = ex[i - 2] # Base atom | |
1106 | + if debug; puts " expanding #{ig} by #{symop.inspect}"; end | |
1107 | + a = mol.expand_by_symmetry(ig, symop[0], symop[1], symop[2], symop[3]) | |
1108 | + ex[i + 2] = a[idx] # Index of the expanded atom | |
1085 | 1109 | end |
1086 | - symop[4] = ex[i - 2] # Base atom | |
1087 | - if debug; puts " expanding #{ig} by #{symop.inspect}"; end | |
1088 | - a = self.expand_by_symmetry(ig, symop[0], symop[1], symop[2], symop[3]) | |
1089 | - ex[i + 2] = a[idx] # Index of the expanded atom | |
1090 | - end | |
1110 | + } | |
1111 | + if ex[4] && ex[5] && ex[4] != ex[5] | |
1112 | + if debug; puts " creating bond #{ex[4]} - #{ex[5]}"; end | |
1113 | + mol.create_bond(ex[4], ex[5]) | |
1114 | + end | |
1091 | 1115 | } |
1092 | - if ex[4] && ex[5] && ex[4] != ex[5] | |
1093 | - if debug; puts " creating bond #{ex[4]} - #{ex[5]}"; end | |
1094 | - self.create_bond(ex[4], ex[5]) | |
1095 | - end | |
1096 | - } | |
1116 | + end | |
1097 | 1117 | end |
1098 | - end | |
1099 | - puts "#{self.nbonds} bonds are created." if verbose | |
1118 | + puts "#{mol.nbonds} bonds are created." if verbose | |
1119 | + end | |
1120 | + next | |
1121 | + else | |
1122 | + # puts "Loop beginning with #{labels[0]} is skipped" | |
1100 | 1123 | end |
1101 | - next | |
1102 | - else | |
1103 | - # puts "Loop beginning with #{labels[0]} is skipped" | |
1104 | - end | |
1105 | - else | |
1106 | - # Skip this token | |
1107 | - token = getciftoken(fp) | |
1124 | + else | |
1125 | + # Skip this token | |
1126 | + token = getciftoken(fp) | |
1127 | + end | |
1128 | + # Skip tokens until next tag or reserved word is detected | |
1129 | + while token != nil && token[0] != ?_ && token[0] != ?# | |
1130 | + token = getciftoken(fp) | |
1131 | + end | |
1132 | + next | |
1108 | 1133 | end |
1109 | - # Skip tokens until next tag or reserved word is detected | |
1110 | - while token != nil && token[0] != ?_ && token[0] != ?# | |
1111 | - token = getciftoken(fp) | |
1134 | + if !bond_defined | |
1135 | + mol.guess_bonds | |
1112 | 1136 | end |
1113 | - next | |
1137 | + if token != nil && token == data_identifier | |
1138 | + # Process next molecule: open a new molecule and start adding atom on that | |
1139 | + mol = Molecule.new | |
1140 | + count_up += 1 | |
1141 | + (@aux_mols ||= []).push(mol) | |
1142 | + next | |
1143 | + end | |
1144 | + break | |
1114 | 1145 | end |
1115 | 1146 | fp.close |
1116 | - if !bond_defined | |
1117 | - self.guess_bonds | |
1118 | - end | |
1119 | 1147 | # self.undo_enabled = save_undo_enabled |
1120 | 1148 | return true |
1121 | 1149 | end |
@@ -68,6 +68,7 @@ BEGIN_EVENT_TABLE(MyDocument, wxDocument) | ||
68 | 68 | EVT_COMMAND(MyDocumentEvent_insertFrameFromMD, MyDocumentEvent, MyDocument::OnInsertFrameFromMD) |
69 | 69 | EVT_COMMAND(MyDocumentEvent_updateDisplay, MyDocumentEvent, MyDocument::OnUpdateDisplay) |
70 | 70 | EVT_COMMAND(MyDocumentEvent_threadTerminated, MyDocumentEvent, MyDocument::OnSubThreadTerminated) |
71 | + EVT_COMMAND(MyDocumentEvent_openAuxiliaryDocuments, MyDocumentEvent, MyDocument::OnOpenAuxiliaryDocuments) | |
71 | 72 | EVT_MENU(myMenuID_Import, MyDocument::OnImport) |
72 | 73 | EVT_MENU(myMenuID_Export, MyDocument::OnExport) |
73 | 74 | EVT_MENU(myMenuID_ExportGraphic, MyDocument::OnExportGraphic) |
@@ -229,6 +230,12 @@ MyDocument::DoOpenDocument(const wxString& file) | ||
229 | 230 | return false; |
230 | 231 | } |
231 | 232 | |
233 | + /* Does this document have multiple representation of molecules? */ | |
234 | + if (MolActionCreateAndPerform(newmol, SCRIPT_ACTION(";i"), "lambda { @aux_mols ? @aux_mols.count : 0 }", &len) == 0 && len > 0) { | |
235 | + wxCommandEvent myEvent(MyDocumentEvent, MyDocumentEvent_openAuxiliaryDocuments); | |
236 | + wxPostEvent(this, myEvent); | |
237 | + } | |
238 | + | |
232 | 239 | if ((len = strlen(p)) > 4 && strcasecmp(p + len - 4, ".psf") == 0) { |
233 | 240 | // Look for a ".pdb" file with the same basename |
234 | 241 | char *buf; |
@@ -254,6 +261,18 @@ MyDocument::DoOpenDocument(const wxString& file) | ||
254 | 261 | return true; |
255 | 262 | } |
256 | 263 | |
264 | +void | |
265 | +MyDocument::OnOpenAuxiliaryDocuments(wxCommandEvent &event) | |
266 | +{ | |
267 | + MolActionCreateAndPerform(mol, SCRIPT_ACTION(""), | |
268 | + "lambda {\n" | |
269 | + " fn = self.name\n" | |
270 | + " @aux_mols.each_with_index { |am, i| \n" | |
271 | + " m = Molecule.open; m.set_molecule(am)\n" | |
272 | + " m.set_name(fn + \"[#{i + 2}]\")\n" | |
273 | + "}; @aux_mols = nil }"); | |
274 | +} | |
275 | + | |
257 | 276 | bool |
258 | 277 | MyDocument::Revert() |
259 | 278 | { |
@@ -38,7 +38,8 @@ enum { | ||
38 | 38 | MyDocumentEvent_insertFrameFromMD, |
39 | 39 | MyDocumentEvent_threadTerminated, |
40 | 40 | MyDocumentEvent_openFilesByIPC, |
41 | - MyDocumentEvent_documentWillClose | |
41 | + MyDocumentEvent_documentWillClose, | |
42 | + MyDocumentEvent_openAuxiliaryDocuments | |
42 | 43 | }; |
43 | 44 | |
44 | 45 | class MyDocument: public wxDocument |
@@ -151,6 +152,7 @@ public: | ||
151 | 152 | void OnInsertFrameFromMD(wxCommandEvent &event); |
152 | 153 | void OnUpdateDisplay(wxCommandEvent &event); |
153 | 154 | void OnSubThreadTerminated(wxCommandEvent &event); |
155 | + void OnOpenAuxiliaryDocuments(wxCommandEvent &event); | |
154 | 156 | |
155 | 157 | void OnUpdateUI(wxUpdateUIEvent &event); |
156 | 158 |