From: Toshi Nagata Date: Sun, 2 Oct 2022 14:52:47 +0000 (+0900) Subject: Start implementing JANPA integration with Psi4 X-Git-Url: http://git.osdn.net/view?p=molby%2FMolby.git;a=commitdiff_plain;h=4915e90a4b6e244c0dcd70016c0255066a9ea3ef Start implementing JANPA integration with Psi4 --- diff --git a/.gitignore b/.gitignore index 2d44466..840b992 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ memo.txt revisionInfo.txt latest_binaries Documents/MolbyDoc/ +JANPA/*.jar + diff --git a/JANPA/License.txt b/JANPA/License.txt new file mode 100644 index 0000000..dbd9301 --- /dev/null +++ b/JANPA/License.txt @@ -0,0 +1,45 @@ +Software License for JANPA package of programs + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +All advertising and/or published materials mentioning features or use +of this software must display the following acknowledgement: + +This product includes components from JANPA package of programs +( http://janpa.sourceforge.net/) developed by Tymofii Nikolaienko + +Neither the name of the developer, Tymofii Nikolaienko, nor the +names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +In case if any results obtained with JANPA package of programs are +published, the following citations for the JANPA package of programs +should be given: + +1) T. Yu. Nikolaienko, L. A. Bulavin; Localized orbitals for optimal +decomposition of molecular properties, Int. J. Quantum Chem. (2019), +Vol. 119, page e25798, DOI: 10.1002/qua.25798 +2) T.Y.Nikolaienko, L.A.Bulavin, D.M.Hovorun; JANPA: an open source +cross-platform implementation of the Natural Population Analysis on the +Java platform, Comput.Theor.Chem.(2014), V.1050, P.15-22, +DOI: 10.1016/j.comptc.2014.10.002 , http://janpa.sourceforge.net + +THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL Tymofii Nikolaienko BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/Makefile b/Makefile index a4cf5b2..fa85e1c 100755 --- a/Makefile +++ b/Makefile @@ -165,6 +165,7 @@ ifeq ($(TARGET_PLATFORM),MSW) cp -r ../bitmaps/bitmaps $(DESTPREFIX)/$(PRODUCT_DIR) cp -r amber11 $(DESTPREFIX)/$(PRODUCT_DIR) cp -r ortep3 $(DESTPREFIX)/$(PRODUCT_DIR) + cp -r ../JANPA $(DESTPREFIX)/$(PRODUCT_DIR) cp -r ../Documents/MolbyDoc $(DESTPREFIX)/$(PRODUCT_DIR) mkdir -p $(DESTPREFIX)/$(PRODUCT_DIR)/Scripts/lib for i in $(RUBY_EXTLIB); do cp $(RUBY_DIR)/lib/$$i $(DESTPREFIX)/$(PRODUCT_DIR)/Scripts/lib; done diff --git a/MolLib/Ruby_bind/ruby_bind.c b/MolLib/Ruby_bind/ruby_bind.c index 520889d..9d7452e 100644 --- a/MolLib/Ruby_bind/ruby_bind.c +++ b/MolLib/Ruby_bind/ruby_bind.c @@ -1012,6 +1012,7 @@ s_Kernel_CallSubProcess(int argc, VALUE *argv, VALUE self) VALUE save_interruptFlag; int n, exitstatus, pid; char *sout, *serr; + const char *pnamestr; FILE *fpout, *fperr; rb_scan_args(argc, argv, "23", &cmd, &procname, &cproc, &stdout_val, &stderr_val); @@ -1056,7 +1057,10 @@ s_Kernel_CallSubProcess(int argc, VALUE *argv, VALUE self) } save_interruptFlag = s_SetInterruptFlag(self, Qnil); - n = MyAppCallback_callSubProcess(StringValuePtr(cmd), StringValuePtr(procname), (cproc == Qnil ? NULL : s_Kernel_CallSubProcess_Callback), (cproc == Qnil ? NULL : (void *)cproc), fpout, fperr, &exitstatus, &pid); + if (procname != Qnil) + pnamestr = StringValuePtr(procname); + else pnamestr = NULL; + n = MyAppCallback_callSubProcess(StringValuePtr(cmd), pnamestr, (cproc == Qnil ? NULL : s_Kernel_CallSubProcess_Callback), (cproc == Qnil ? NULL : (void *)cproc), fpout, fperr, &exitstatus, &pid); s_SetInterruptFlag(self, save_interruptFlag); if (fpout != NULL && fpout != (FILE *)1) diff --git a/Scripts/commands.rb b/Scripts/commands.rb index ee4c7ab..8ce11cd 100755 --- a/Scripts/commands.rb +++ b/Scripts/commands.rb @@ -395,6 +395,14 @@ class Molecule name2 = "Pre-orthogonal Natural Hybrid Orbitals" elsif key2 == "PNBO" name2 = "Pre-orthogonal Natural Bond Orbitals" + elsif key2 == "AHO" + name2 = "Atomic Hybrid Orbitals" + elsif key2 == "LHO" + name2 = "Localized Hybrid Orbitals" + elsif key2 == "LPO" + name2 = "Localized Property-optimized Orbitals" + elsif key2 == "CLPO" + name2 = "Chemist's Localized Property-optimized Orbitals" end mo_ao_items.push(name2) mo_ao_keys.push(key2) diff --git a/Scripts/gamess.rb b/Scripts/gamess.rb index 560082a..66978ab 100755 --- a/Scripts/gamess.rb +++ b/Scripts/gamess.rb @@ -1553,6 +1553,7 @@ class Molecule fp.print "# Generated by Molby at #{now}\n" fp.print "import sys\n" fp.print "import re\n" + fp.print "base = re.sub('\\.\\w*$', '', sys.argv[1]) # Basename of the input file\n" fp.print "molecule mol {\n" charge = Integer(hash["charge"]) mult = Integer(hash["mult"]) @@ -1584,7 +1585,17 @@ class Molecule end runtype = hash['runtype'].downcase fp.print "energy, wfn = #{runtype}('scf', #{options})\n" - fp.print "wfn.write_molden(re.sub('\\.\\w*$', '.molden', sys.argv[1]))\n" + fp.print "wfn.write_molden(f'{base}.molden')\n" + if hash['run_junpa'] != 0 + fp.print "\n" + fp.print "# Interface for JANPA\n" + fp.print "# cf. https://sourceforge.net/p/janpa/wiki/psi4Examples/\n" + fp.print "d = wfn.Da().to_array()\n" + fp.print "s = wfn.S().to_array()\n" + fp.print "c = wfn.Ca().to_array()\n" + fp.print "occs = c.T.dot(s.dot(d).dot(s).dot(c))\n" + fp.print "molden(wfn, f'{base}.da.molden', density_a = psi4.core.Matrix.from_array(occs))\n" + end end if fname == nil s = fp.buffer @@ -1596,6 +1607,42 @@ class Molecule end end + # Execute JUNPA + # inppath is the input file minus extention + # mol is the molecule (may be nil) + def Molecule.execute_janpa(inppath, mol, spherical) + # nbo_desc = # JANPA + janpa_dir = "#{ResourcePath}/JANPA" + status = 0 + if spherical + cmd1 = "java -jar #{janpa_dir}/molden2molden.jar -NormalizeBF -i #{inppath}.da.molden -o #{inppath}.in.molden >#{inppath}.janpa.log" + else + cmd1 = "java -jar #{janpa_dir}/molden2molden.jar -frompsi4v1mo -NormalizeBF -cart2pure -i #{inppath}.da.molden -o #{inppath}.in.molden >#{inppath}.janpa.log" + end + flag = system(cmd1) + if flag + cmd2 = "java -jar #{janpa_dir}/janpa.jar -i #{inppath}.in.molden" + ["nao", "pnao", "aho", "lho", "lpo", "clpo"].each { |type| + if (get_global_settings("psi4.#{type}").to_i != 0) + cmd2 += " -#{type.upcase}_Molden_File #{inppath}.#{type.upcase}.molden" + end + } + cmd2 += " >>#{inppath}.janpa.log" + flag = system(cmd2) + end + if flag + if mol + # import JANPA log and molden output + # Files: inppath.japa.log, inppath.{NAO,PNAO,AHO,LHO,LPO,CLPO}.molden + mol.sub_load_janpa_log(inppath) + end + else + status = $?.exitstatus + message_box("Execution of #{procname} failed with status #{status}.", "JANPA Failed") + end + return status + end + # Execute Psi4 # inpname is the input file # mol (optional) is the molecule from which the Psi4 input was built. @@ -1623,6 +1670,7 @@ class Molecule hf_type = nil nalpha = nil nbeta = nil + spherical = false outfile = inpdir + "/" + inpbody + ".out" if File.exists?(outfile) @@ -1731,6 +1779,8 @@ class Molecule nalpha = Integer($1) elsif line =~ /^ *Nbeta *= *(\d+)/ nbeta = Integer($1) + elsif line =~ /^ *Spherical Harmonics\?: *(\w+)/ + spherical = ($1 == "true") end end if next_index > 0 @@ -1748,6 +1798,7 @@ class Molecule # Terminate callback term_callback = lambda { |m, n| + do_janpa = false begin msg = "Psi4 execution of #{inpbase} " hmsg = "Psi4 " @@ -1793,6 +1844,9 @@ class Molecule $stderr.write("#{e.backtrace.inspect}\n") end end + if (get_global_settings("psi4.run_janpa").to_i == 1) + do_janpa = true + end elsif n == -1 # The child process actually did not start # Restore the old file if outbackfile is not nil @@ -1803,6 +1857,9 @@ class Molecule if outbackfile && File.exists?(outbackfile) File.delete(outbackfile) end + if do_janpa + Molecule.execute_janpa(inpdir + "/" + inpbody, mol, spherical) + end rescue => e $stderr.write("#{e.message}\n") $stderr.write("#{e.backtrace.inspect}\n") @@ -1853,7 +1910,7 @@ class Molecule dfttype_desc = ["B3LYP"] runtype_desc = ["Energy", "Optimize"] scftype_desc = ["RHF", "ROHF", "UHF"] -# nbo_desc = ["nao", "nbo", "nho", "nlmo", "pnao", "pnbo", "pnho", "pnlmo"] + nbo_desc = ["nao", "pnao", "aho", "lho", "lpo", "clpo"] # JANPA user_input = Hash.new defaults = {"scftype"=>0, "runtype"=>0, "move_to_com"=>0, "do_reorient"=>0, "use_symmetry"=>0, "charge"=>"0", "mult"=>"1", @@ -1956,22 +2013,21 @@ class Molecule #item(:line), #-1, -1, -1, # ------ - #item(:checkbox, :title=>"Include NBO instructions", :tag=>"include_nbo", - # :action=>lambda { |it| - # flag = (it[:value] != 0) - # nbos.each { |nbo| set_attr(nbo, :enabled=>flag) } - # }), - #-1, -1, -1, + item(:checkbox, :title=>"Run JANPA after Psi4", :tag=>"run_janpa", + :action=>lambda { |it| + flag = (it[:value] != 0) + nbo_desc.each { |nbo| set_attr(nbo, :enabled=>flag) } + }), + -1, -1, -1, # ------ - #item(:checkbox, :title=>"NAO", :tag=>"nao"), - #item(:checkbox, :title=>"NBO", :tag=>"nbo"), - #item(:checkbox, :title=>"NHO", :tag=>"nho"), - #item(:checkbox, :title=>"NLMO", :tag=>"nlmo"), + item(:checkbox, :title=>"NAO", :tag=>"nao"), + item(:checkbox, :title=>"PNAO", :tag=>"pnao"), + item(:checkbox, :title=>"AHO", :tag=>"aho"), + item(:checkbox, :title=>"LHO", :tag=>"lho"), # ------ - #item(:checkbox, :title=>"PNAO", :tag=>"pnao"), - #item(:checkbox, :title=>"PNBO", :tag=>"pnbo"), - #item(:checkbox, :title=>"PNHO", :tag=>"pnho"), - #item(:checkbox, :title=>"PNLMO", :tag=>"pnlmo"), + item(:checkbox, :title=>"LPO", :tag=>"lpo"), + item(:checkbox, :title=>"CLPO", :tag=>"clpo"), + -1, -1, # ------ item(:line), -1, -1, -1, diff --git a/Scripts/loadsave.rb b/Scripts/loadsave.rb index 888224d..b6735b4 100755 --- a/Scripts/loadsave.rb +++ b/Scripts/loadsave.rb @@ -611,13 +611,22 @@ class Molecule end # mol.set_mo_info should be set before calling this function - def sub_load_molden(fp) + # Optional label is for importing JANPA output: "NAO" or "CPLO" + # If label is not nil, then returns a hash containing the following key/value pairs: + # :atoms => an array of [element_symbol, seq_num, atomic_num, x, y, z] (angstrom) + # :gto => an array of an array of [sym, [ex0, c0, ex1, c1, ...]] + # :moinfo => an array of [sym, energy, spin (0 or 1), occ] + # :mo => an array of [c0, c1, ...] + def sub_load_molden(fp, label = nil) getline = lambda { @lineno += 1; return fp.gets } bohr = 0.529177210903 errmsg = nil ncomps = 0 # Number of components (AOs) occ_alpha = 0 # Number of occupied alpha orbitals occ_beta = 0 # Number of occupied beta orbitals + if label + hash = Hash.new + end catch :ignore do while line = getline.call if line =~ /^\[Atoms\]/ @@ -626,12 +635,16 @@ class Molecule if line =~ /^[A-Z]/ # element, index, atomic_number, x, y, z (in AU) a = line.split(' ') - if atoms[i].atomic_number != Integer(a[2]) || - (atoms[i].x - Float(a[3]) * bohr).abs > 1e-4 || - (atoms[i].y - Float(a[4]) * bohr).abs > 1e-4 || - (atoms[i].z - Float(a[5]) * bohr).abs > 1e-4 - errmsg = "The atom list does not match the current molecule." - throw :ignore + if label + (hash[:atoms] ||= []).push([a[0], Integer(a[1]), Integer(a[2]), Float(a[3]) * bohr, Float(a[4]) * bohr, Float(a[5]) * bohr]) + else + if atoms[i].atomic_number != Integer(a[2]) || + (atoms[i].x - Float(a[3]) * bohr).abs > 1e-4 || + (atoms[i].y - Float(a[4]) * bohr).abs > 1e-4 || + (atoms[i].z - Float(a[5]) * bohr).abs > 1e-4 + errmsg = "The atom list does not match the current molecule." + throw :ignore + end end i += 1 else @@ -642,6 +655,10 @@ class Molecule elsif line =~ /^\[GTO\]/ shell = 0 atom_index = 0 + if label + gtos = [] + hash[:gto] = [] + end while line = getline.call # index, 0? a = line.split(' ') @@ -666,24 +683,40 @@ class Molecule raise MolbyError, "Unknown gaussian shell type '#{a[0]}' at line #{@lineno} in MOLDEN file" end nprimitives = Integer(a[1]) + if label + gtoline = [sym, []] + gtos.push(gtoline) + end nprimitives.times { |i| line = getline.call # exponent, contraction b = line.split(' ') + if label + gtoline[1].push(Float(b[0]), Float(b[1])) + end add_gaussian_primitive_coefficients(Float(b[0]), Float(b[1]), 0.0) } # end of one shell - add_gaussian_orbital_shell(atom_index, sym, nprimitives) + if label == nil + add_gaussian_orbital_shell(atom_index, sym, nprimitives) + end shell += 1 ncomps += n end # end of one atom atom_index += 1 + if label + hash[:gto].push(gtos) + end end redo # The next line will be the beginning of the next block elsif line =~ /^\[MO\]/ m = [] idx_alpha = 1 # set_mo_coefficients() accepts 1-based index of MO idx_beta = 1 + if label + hash[:mo] = [] + hash[:moinfo] = [] + end while true # Loop for each MO m.clear @@ -708,6 +741,9 @@ class Molecule occ_beta += 1 end end + if label + hash[:moinfo].push([sym, ene, (spin == "Alpha" ? 0 : 1), occ]) + end elsif line =~ /^ *([0-9]+) +([-+.0-9e]+)/ m[i] = Float($2) i += 1 @@ -720,6 +756,9 @@ class Molecule idx_beta += 1 end set_mo_coefficients(idx, ene, m) + if label + hash[:mo].push(m.dup) + end break end else @@ -734,11 +773,96 @@ class Molecule end # end catch if errmsg message_box("The MOLDEN file was found but not imported. " + errmsg, "Psi4 import info", :ok) - return false + return (label ? nil : false) end - return true + return (label ? hash : true) end - + + # Import the JANPA log and related molden files + # Files: inppath.{NAO.molden,CLPO.molden,janpa.log} + def sub_load_janpa_log(inppath) + begin + fp = File.open(inppath + ".janpa.log", "rt") rescue fp = nil + if fp == nil + message_box("Cannot open JANPA log file #{inppath + '.janpa.log'}: " + $!.to_s) + return false + end + print("Importing #{inppath}.janpa.log.\n") + lineno = 0 + getline = lambda { lineno += 1; return fp.gets } + h = Hash.new + mfiles = Hash.new + while line = getline.call + if line =~ /^NAO \#/ + h["NAO"] = [] + while line = getline.call + break if line !~ /^\s*[1-9]/ + num = Integer(line[0, 5]) + name = line[5, 21] + occ = Float(line[26, 11]) + # like A1*: R1*s(0) + # atom_number, occupied?, shell_number, orb_sym, angular_number + name =~ /\s*[A-Z]+([0-9]+)(\*?):\s* R([0-9]+)\*([a-z]+)\(([-0-9]+)\)/ + anum = Integer($1) + occupied = $2 + shell_num = Integer($3) + orb_sym = $4 + ang_num = Integer($5) + h["NAO"].push([num, anum, occupied, shell_num, orb_sym, ang_num, occ]) + end + elsif line =~ /^\s*CLPO\s+D e s c r i p t i o n\s+Occupancy\s+Composition/ + h["CLPO"] = [] + while line = getline.call + break if line =~ /^\s*$/ + num = Integer(line[0, 5]) + label1 = line[5, 6].strip + desc = line[11, 30].strip + desc =~ /\s*([-A-Za-z0-9]+)(,\s*(.*$))?/ + desc1 = $1 + desc2 = ($3 || "") + if desc2 =~ /^(.*)*\(NB\)\s*$/ && label1 == "" + label1 = "(NB)" + desc2 = $1.strip + end + # like ["(BD)", "C1-H3", "Io = 0.2237"] + h["CLPO"][num - 1] = [label1, desc1, desc2] + end + elsif line =~ /^ -NAO_Molden_File: (\S*)/ + mfiles["NAO"] = $1 + elsif line =~ /^ -LHO_Molden_File: (\S*)/ + mfiles["LHO"] = $1 + elsif line =~ /^ -CLPO_Molden_File: (\S*)/ + mfiles["CLPO"] = $1 + elsif line =~ /^ -PNAO_Molden_File: (\S*)/ + mfiles["PNAO"] = $1 + elsif line =~ /^ -AHO_Molden_File: (\S*)/ + mfiles["AHO"] = $1 + elsif line =~ /^ -LPO_Molden_File: (\S*)/ + mfiles["LPO"] = $1 + end + end + fp.close + # Read molden files + mfiles.each { |key, value| + fp = Kernel.open(value, "rt") rescue fp = nil + if fp + print("Importing #{value}.\n") + res = sub_load_molden(fp, key) + if res + # Some kind of orbital based on AO + h["AO/#{key}"] = LAMatrix.new(res[:mo]) + end + fp.close + end + } + @nbo = h + return true + rescue => e + $stderr.write(e.message + "\n") + $stderr.write(e.backtrace.inspect + "\n") + end + end + def loadout(filename) retval = false fp = open(filename, "rb") @@ -756,14 +880,20 @@ class Molecule retval = sub_load_psi4_log(fp) if retval # If .molden file exists, then try to read it - mname = filename.gsub(/\.\w*$/, ".molden") + namepath = filename.gsub(/\.\w*$/, "") + mname = "#{namepath}.molden" if File.exists?(mname) fp2 = open(mname, "rb") if fp2 flag = sub_load_molden(fp2) fp2.close + status = (flag ? 0 : -1) end end + if File.exists?("#{namepath}.janpa.log") + flag = sub_load_janpa_log(namepath) + status = (flag ? 0 : -1) + end end break end diff --git a/build-xcode/Molby.xcodeproj/project.pbxproj b/build-xcode/Molby.xcodeproj/project.pbxproj index 86a05e0..673a60e 100644 --- a/build-xcode/Molby.xcodeproj/project.pbxproj +++ b/build-xcode/Molby.xcodeproj/project.pbxproj @@ -91,6 +91,8 @@ E4059FDD28C46A6E0052B36B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4FC7A16183E51570064FB2E /* Foundation.framework */; }; E4059FDE28C46A6E0052B36B /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4FC7B58183E53710064FB2E /* WebKit.framework */; }; E4059FDF28C46A6E0052B36B /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4FC7CAC183F953E0064FB2E /* AudioToolbox.framework */; }; + E40C8B3328E85322003CE26E /* JANPA in Resources */ = {isa = PBXBuildFile; fileRef = E40C8B3228E8522F003CE26E /* JANPA */; }; + E40C8B3428E85357003CE26E /* JANPA in Resources */ = {isa = PBXBuildFile; fileRef = E40C8B3228E8522F003CE26E /* JANPA */; }; E41251B828CD92A100E12983 /* MyListCtrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E41251B728CD92A100E12983 /* MyListCtrl.cpp */; }; E41A7F962307D61200C65830 /* bitmaps in Resources */ = {isa = PBXBuildFile; fileRef = E41A7F952307D61200C65830 /* bitmaps */; }; E420BDEF1885746700A2B983 /* ConsoleFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E420BDE81885746700A2B983 /* ConsoleFrame.cpp */; }; @@ -196,6 +198,7 @@ E403568828D0C8C4008E2C46 /* textctrl_msw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = textctrl_msw.cpp; sourceTree = ""; }; E4059FE428C46A6E0052B36B /* MolbyMacLegacy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MolbyMacLegacy.app; sourceTree = BUILT_PRODUCTS_DIR; }; E4059FE628C46B320052B36B /* Molby_MacLegacy-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Molby_MacLegacy-Info.plist"; sourceTree = ""; }; + E40C8B3228E8522F003CE26E /* JANPA */ = {isa = PBXFileReference; lastKnownFileType = folder; name = JANPA; path = ../JANPA; sourceTree = ""; }; E41251B728CD92A100E12983 /* MyListCtrl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MyListCtrl.cpp; sourceTree = ""; }; E41251BA28CD92AD00E12983 /* MyListCtrl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyListCtrl.h; sourceTree = ""; }; E4196C65190B2FA500183E62 /* menu.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = menu.mm; sourceTree = ""; }; @@ -489,6 +492,7 @@ E4ACACE418C6D32300F08B67 /* ortep3 */, E4FC7C16183E54730064FB2E /* Molby-Info.plist */, E4059FE628C46B320052B36B /* Molby_MacLegacy-Info.plist */, + E40C8B3228E8522F003CE26E /* JANPA */, ); name = Resources; sourceTree = ""; @@ -707,6 +711,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E40C8B3328E85322003CE26E /* JANPA in Resources */, E4FC7F821840C22B0064FB2E /* molby_icon.icns in Resources */, E4FC77D7183E4FFE0064FB2E /* Scripts in Resources */, E4FC7802183E503E0064FB2E /* amber11 in Resources */, @@ -719,6 +724,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E40C8B3428E85357003CE26E /* JANPA in Resources */, E4059F9B28C46A6E0052B36B /* molby_icon.icns in Resources */, E4059F9C28C46A6E0052B36B /* Scripts in Resources */, E4059F9D28C46A6E0052B36B /* amber11 in Resources */, diff --git a/wxSources/MyApp.cpp b/wxSources/MyApp.cpp index c075710..8043438 100755 --- a/wxSources/MyApp.cpp +++ b/wxSources/MyApp.cpp @@ -1419,7 +1419,7 @@ MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback) bool progress_panel = false; char buf[256]; wxString cmdstr(cmdline, WX_DEFAULT_CONV); - wxLongLong startTime; + wxLongLong startTime, lastTime, presentTime; if (m_process != NULL) return -1; // Another process is already running (CallSubProcess() allows only one subprocess) @@ -1433,7 +1433,7 @@ MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback) ShowProgressPanel(buf); progress_panel = true; } - startTime = wxGetUTCTimeMillis(); + startTime = lastTime = wxGetUTCTimeMillis(); // Create log file in the document home directory #if LOG_SUBPROCESS @@ -1479,8 +1479,9 @@ MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback) wxString bufstr; wxString buferrstr; while (1) { - int len1 = m_process->GetLine(bufstr); - if (len1 > 0) { + int len1, len2; + lastTime = wxGetUTCTimeMillis(); + while ((len1 = m_process->GetLine(bufstr)) > 0) { #if LOG_SUBPROCESS dateTime.SetToCurrent(); fprintf(fplog, "%s[STDOUT]%s", (const char *)(dateTime.FormatISOCombined(' ')), (const char *)bufstr); @@ -1495,9 +1496,13 @@ MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback) MyAppCallback_setConsoleColor(0); MyAppCallback_showScriptMessage("%s", (const char *)bufstr); } + presentTime = wxGetUTCTimeMillis(); + if (presentTime > lastTime + 25) { + presentTime = lastTime; + break; + } } - int len2 = m_process->GetErrorLine(buferrstr); - if (len2 > 0) { + while ((len2 = m_process->GetErrorLine(buferrstr)) > 0) { #if LOG_SUBPROCESS dateTime.SetToCurrent(); fprintf(fplog, "%s[STDERR]%s", (const char *)(dateTime.FormatISOCombined(' ')), buf); @@ -1510,8 +1515,12 @@ MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback) MyAppCallback_showScriptMessage("\n%s", (const char *)buferrstr); MyAppCallback_setConsoleColor(0); } + presentTime = wxGetUTCTimeMillis(); + if (presentTime > lastTime + 25) { + presentTime = lastTime; + break; + } } - if (len1 < 0 && len2 < 0) { // The standard/error outputs are exhausted; the process should have terminated // (Normally, this should be detected by wxBetterProcess::OnTerminate()) @@ -1523,12 +1532,11 @@ MyApp::CallSubProcess(const char *cmdline, const char *procname, int (*callback) if (callback_result != 0) interrupted = true; } + ::wxSafeYield(); // This allows updating console and wxProcess status if (progress_panel) { SetProgressValue(-1); if (IsInterrupted()) interrupted = true; - } else { - ::wxSafeYield(); // This allows updating console and wxProcess status } #if LOG_SUBPROCESS