770 def do_all_trainings(self):
771 """
772 Do all trainings for which we find training data
773 """
774
775 import ROOT
776
777
778 ROOT.PyConfig.StartGuiThread = False
779 job_list = []
780
781 all_stage_particles = get_stages_from_particles(self.particles)
782 if self.config.cache is None:
783 stagesToTrain = range(1, len(all_stage_particles)+1)
784 else:
785 stagesToTrain = [self.config.cache]
786
787 filename = 'training_input.root'
788 if os.path.isfile(filename):
789 f = ROOT.TFile.Open(filename, 'read')
790 if f.IsZombie():
791 B2WARNING(f'Training of MVC failed: {filename}. ROOT file corrupt. No weight files will be provided.')
792 elif len([k.GetName() for k in f.GetListOfKeys()]) == 0:
793 B2WARNING(
794 f'Training of MVC failed: {filename}. ROOT file has no trees. No weight files will be provided.')
795 else:
796 for istage in stagesToTrain:
797 for particle in all_stage_particles[istage-1]:
798 for channel in particle.channels:
799 weightfile = f'{channel.label}.xml'
800 if basf2_mva.available(weightfile):
801 B2INFO(f"FEI-core: Skipping {weightfile}, already available")
802 continue
803 else:
804 treeName = ROOT.Belle2.MakeROOTCompatible.makeROOTCompatible(f'{channel.label} variables')
805 keys = [m for m in f.GetListOfKeys() if treeName in m.GetName()]
806 if not keys:
807 B2WARNING("Training of MVC failed. "
808 f"Couldn't find tree for channel {channel}. Ignoring channel.")
809 continue
810 elif len(keys) > 1:
811 B2WARNING(f"Found more than one tree for channel {channel}. Taking first tree from: {keys}")
812 tree = keys[0].ReadObj()
813 total_entries = tree.GetEntries()
814 nSig = tree.GetEntries(f'{channel.mvaConfig.target}==1.0')
815 nBg = tree.GetEntries(f'{channel.mvaConfig.target}==0.0')
816 B2INFO(
817 f'FEI-core: Number of events for channel: {channel.label}, '
818 f'Total: {total_entries}, Signal: {nSig}, Background: {nBg}')
819 if nSig < Teacher.MinimumNumberOfMVASamples:
820 B2WARNING("Training of MVC failed. "
821 f"Tree contains too few signal events {nSig}. Ignoring channel {channel}.")
822 self.create_fake_weightfile(channel.label)
823 self.upload(channel.label)
824 continue
825 if nBg < Teacher.MinimumNumberOfMVASamples:
826 B2WARNING("Training of MVC failed. "
827 f"Tree contains too few bckgrd events {nBg}. Ignoring channel {channel}.")
828 self.create_fake_weightfile(channel.label)
829 self.upload(channel.label)
830 continue
831 variable_str = "' '".join(channel.mvaConfig.variables)
832
833 spectators = list(channel.mvaConfig.spectators.keys())
834 if channel.mvaConfig.sPlotVariable is not None:
835 spectators.append(channel.mvaConfig.sPlotVariable)
836 spectators_str = "' '".join(spectators)
837
838 treeName = ROOT.Belle2.MakeROOTCompatible.makeROOTCompatible(f'{channel.label} variables')
839 command = (f"{self.config.externTeacher}"
840 f" --method '{channel.mvaConfig.method}'"
841 f" --target_variable '{channel.mvaConfig.target}'"
842 f" --treename '{treeName}'"
843 f" --datafile 'training_input.root'"
844 f" --signal_class 1"
845 f" --variables '{variable_str}'"
846 f" --identifier '{weightfile}'")
847 if len(spectators) > 0:
848 command += f" --spectators '{spectators_str}'"
849 command += f" {channel.mvaConfig.config} > '{channel.label}'.log 2>&1"
850 B2INFO(f"Used following command to invoke teacher: \n {command}")
851 job_list.append((channel.label, command))
852 f.Close()
853
854 if len(job_list) > 0:
855 p = multiprocessing.Pool(None, maxtasksperchild=1)
856 func = functools.partial(subprocess.call, shell=True)
857 p.map(func, [c for _, c in job_list])
858 p.close()
859 p.join()
860 weightfiles = []
861 for name, _ in job_list:
862 if not basf2_mva.available(f'{name}.xml'):
863 B2WARNING("Training of MVC failed. For unknown reasons, check the logfile", f'{name}.log')
864 self.create_fake_weightfile(name)
865 weightfiles.append(self.upload(name))
866 return weightfiles
867
868