{"id":306,"date":"2025-01-14T17:53:36","date_gmt":"2025-01-14T17:53:36","guid":{"rendered":"http:\/\/10.220.16.170\/?page_id=306"},"modified":"2025-01-30T08:00:00","modified_gmt":"2025-01-30T08:00:00","slug":"proof","status":"publish","type":"page","link":"https:\/\/micc.jinr.ru\/?page_id=306","title":{"rendered":"PROOF"},"content":{"rendered":"<article class=\"b-manual no-sidebar\">\n<h1>PROOF<\/h1>\n<div class=\"b-content-row\">\n<div class=\"b-content-column\" style=\"width: 35%;\">\n<p><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2025\/01\/proof.png\" alt=\"\" width=\"350\" height=\"400\" \/><\/p>\n<p><a href=\"http:\/\/wwwinfo.jinr.ru\/~tanyusha\/proof_tree_en.html\" target=\"_blank\" rel=\"noopener\">PROOF and object of class TTree. Example<\/a>.<\/p>\n<div class=\"b-content-column-end\"><\/div>\n<\/div>\n<div class=\"b-content-column\" style=\"width: 65%;\">\n<p><strong>PROOF,<\/strong> i.e.\u00a0<strong>P<\/strong>arallel <strong>ROO<\/strong>T <strong>F<\/strong>acility is an extension of ROOT that allows performing parallel analysis of large sets of ROOT files on multiprocessor machines. That is, PROOF can parallelize tasks, which can be formulated as a series of independent subtasks.<\/p>\n<p><strong>PROOF provides:<\/strong><\/p>\n<ul>\n<li>Absence (or a very small number) of differences between the analysis session running on local ROOT and the remote parallel session of PROOF. A typical parsing script should work the same way.<\/li>\n<li>No limit on the number of processors that can be used in parallel.<\/li>\n<li>Adaptability of the session to changes in the remote environment (load changes on the cluster nodes, network interrupts, etc.).<\/li>\n<\/ul>\n<div class=\"b-content-column-end\"><\/div>\n<\/div>\n<\/div>\n<p>In the PROOF implementation, slave servers (&#8220;workers&#8221;) are active components that request the main server for getting new work whenever they are ready to do it. The main goal of PROOF is to minimize the time for performing a common task in the presence of all working workers ending their assigned task at the same time. In this scheme, the performance of parallel processing is a function of duration of carrying out each small task, the &#8220;package&#8221;, i.e. the work volume assigned to the worker, and network bandwidth. The main setting parameter is the size of the package. If the package size is too small, the effect of parallelism will be leveled by a waste of time to the service data transfer caused by the movement of many packages within the network between master and slave servers. If the package size is too large, the effect of the difference in performance is expressed insufficiently. Another very important factor is the location of data. In most cases, it is necessary to process a large amount of data files that are distributed across different cluster nodes or separated from each other geographically. To group these files together, a chain that provides a single logical view of many physical files is used.<\/p>\n<p>A package is a simple data structure of two numbers, i.e. \u201cinitial event\u201d and \u201cnumber of events\u201d. The size of the package is determined dynamically after the work of workers in real time. The main server (&#8220;master&#8221;) generates a package when requesting the slave server, taking into account the time spent on processing the previous batch and the size of the files in the chain. The wizard saves the list of all generated packages to one of the slave servers, so in case any &#8220;worker&#8221; &#8220;dies&#8221; during processing, all its packages can be recycled by the rest of the &#8220;workers&#8221;. A package can be as small as the main processing unit, i.e. an event.<\/p>\n<p>To use PROOF, a user (client) must start a PROOF session. Practically it means the creation of a TProof object or a pointer to it.<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">root[] TRpoof *proof = TProof::Open(&#8220;url&#8221;)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>This class manages Parallel ROOT Facility on a cluster. It starts up worker servers, keeps track of their work, status and other practices, sends messages to all workers, collects results, etc. A full description of the TProof class can be read here. We will only consider main methods of TProof.<\/p>\n<p>The method<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">TProof * TProof::Open(const char * cluster = 0, const char * conffile = 0, const char * confdir = 0, Int_t loglevel = 0)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>runs a Proof session on the specific cluster. The first parameter is URL representing the network address of the cluster master. The second parameter &#8211; conffile &#8211; is a name of the configuration file that describes the remote PROOF cluster (this argument allows you to describe various cluster configurations). The default file is proof.conf. The third parameter &#8211; confdir &#8211; is a directory in which there is a configuration file and other PROOF-related files (for example, motd and noproof files).<\/p>\n<p>The method<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">TProof::Print (Option_t opt)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>displays the final status of the session. By default, it shows information about the following: client, master, ROOT version, platform, location of user directories, number of active and inactive workers, real work time, CPU time and I\/O used in the session, etc.<\/p>\n<p>The method<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">TProof::Exec(const char\u00a0 *cmd)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>allows you to execute ROOT commands on workers or on the master. For example, PROOF diagnoses CINT commands that require a file (&#8216;.L&#8217;, &#8216;.x&#8217; and &#8216;.X&#8217;) and makes sure that the updated file version exists on nodes. The file is loaded only if necessary.<\/p>\n<p>The method<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">TProof::SetParallel(Int_t nodes))<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>tells PROOF how many auxiliary nodes to use in parallel.<\/p>\n<p>When you run a macro for the first time, you may notice some waiting time due to its distribution by workers. When starting a second time and onwards, if the macro has not changed, it goes much faster. By default, the command is executed only on workers, not on the master. To perform it on the master, you can do the following:<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">root [3] proof-&gt;SetParallel(0)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>The Process method has several types of interface:<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>Long64_t TProof::Process(TDSet * dset, const char * selector, Option_t * option = &#8220;&#8221;, Long64_t \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 nentries = -1,<\/p>\n<p>Long64_t first = 0)<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>Processes a data set implemented in ROOT by the special class TDSet using the specified selector file. (.C) or the Tselector object.<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>Long64_t TProof::Process(TFileCollection * fc, const char * selector, Option_t * option = &#8220;&#8221;, Long64_t nentries = -1,<\/p>\n<p>Long64_t first = 0)<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>Processes a data set (TFileCollection) using the specified selector file (.C) or the TSelector object.<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">Long64_t TProof::Process(const char * selector, Long64_t n, Option_t * option = &#8220;&#8221;)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>General (not based on pre-selected data) selector processing: the Process () method of the specified selector object (.C) or TSelector is called &#8220;n&#8221; times. What is a selector?<\/p>\n<p>Selector<\/p>\n<p>To be able to parallelize at the event level, PROOF must adjust the flow of events. This requires that the code be defined in advance, but with a flexible structure. In ROOT, this requirement is provided by the Selector structure defined by the abstract TSelector class, which determines three logical steps:<\/p>\n<p><strong>Begin\u00a0<\/strong>&#8211; where the input data, parameters, a file for output are set; running on the client and workers;<\/p>\n<p><strong>Process\u00a0<\/strong>&#8211; where the actual work is done; is called for every event on workers. This part can be parallelized;<\/p>\n<p><strong>Terminate\u00a0<\/strong>&#8211; where results are processed (fit, visualized &#8230;); called by the client and workers.<\/p>\n<p>That is, you can schematically represent the structure of the Selector as follows:<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>\u00a0<strong>void Begin()<\/strong>\u00a0&#8211; client initialization, performed once on the client<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>\u00a0<strong>void SlaveBegin()<\/strong>\u00a0&#8211; node initialization, performed once on each subordinate node<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\u00a0<strong>void Process(Long64_t entry)<\/strong>\u00a0&#8211; calculation, specified number of times (entry) on each subordinate node<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><strong>void SlaveTerminate()<\/strong>\u00a0&#8211; ffinal processing on the node, performed once on each subordinate node<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>void Terminate() &#8211; processing and output of data on the client, performed once on the client<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>Packetizer<\/p>\n<p>The packetizer is responsible for load balancing between workers. It decides where each piece of work &#8211; package &#8211; must be processed. The packetizer object is created on the master node. The work of workers, as well as the speed of transfer of various files, can vary considerably. To dynamically balance work distribution, the packetizer uses the pull architecture: when workers are ready for the next processing, they ask the packetizer for the next package.<\/p>\n<p>Let us consider an example in which a one-dimensional histogram is created and filled with random numbers obeying the Gauss distribution. First, we will write a script for an ordinary ROOT session without using PROOF.<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>#include &#8220;TH1F.h&#8221;<\/p>\n<p>#include &#8220;TRandom.h&#8221;<\/p>\n<p>#include &#8220;TCanvas.h&#8221;<\/p>\n<p>void gauss(Int_t n=100000){<\/p>\n<p><span style=\"color: red;\">TH1F *fH1F = new TH1F(&#8220;FirstH1F&#8221;,&#8221;First TH1F in PROOF&#8221;,100,-10,10);<\/span><\/p>\n<p><span style=\"color: red;\">TRandom *fRandom=new TRandom3(0);<\/span><\/p>\n<p>for(Int_t i=0;i&lt;n;i++){<\/p>\n<p><span style=\"color: blue;\">Double_t x=fRandom-&gt;Gaus(0.,1.);<\/span><\/p>\n<p><span style=\"color: blue;\">fH1F-&gt;Fill(x);<\/span><\/p>\n<p>}<\/p>\n<p><span style=\"color: green;\">TCanvas *c1=new TCanvas(&#8220;c1&#8243;,&#8221;Proof ProofFirst canvas&#8221;,200,10,400,400);<\/span><\/p>\n<p><span style=\"color: green;\">fH1F-&gt;Draw();<\/span><\/p>\n<p><span style=\"color: green;\">c1-&gt;Update();<\/span><\/p>\n<p>}<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>The red color in the script highlights the definition of the histogram and the random number generator. In blue &#8211; the work of the script &#8211; in this case, the random number generation and filling of the histogram with it. Data output is highlighted in green &#8211; creating a canvas and drawing a histogram on it.<\/p>\n<p>Now, to perform the same work in parallel using PROOF, let us create the ProofFirst class, derived from the TSelector abstract class. A description and methods of TSelector class methods can be viewed here. The header file ProofFirst.h looks like:<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>#ifndef ProofFirst_h<\/p>\n<p>#define ProofFirst_h<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt; TSelector.h &gt;<\/p>\n<p>#include &#8220;TH1F.h&#8221;<\/p>\n<p>#include &#8220;TRandom.h&#8221;<\/p>\n<p>#include &#8220;TCanvas.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>class TH1F;<\/p>\n<p>class TRandom;<\/p>\n<p>&nbsp;<\/p>\n<p>class ProofFirst : public TSelector {<\/p>\n<p>public :<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: red;\">\u00a0\u00a0 TH1F\u00a0\u00a0 *fH1F;\u00a0\u00a0\u00a0<\/span><\/p>\n<p><span style=\"color: red;\">\u00a0\u00a0 TRandom *fRandom;<\/span><\/p>\n<p>ProofFirst();<\/p>\n<p>virtual ~ProofFirst();<\/p>\n<p>virtual Int_t\u00a0\u00a0 Version() const { return 2; }<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 Begin(TTree *tree);<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 SlaveBegin(TTree *tree);<\/p>\n<p>virtual Bool_t\u00a0 Process(Long64_t entry);<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 SetOption(const char *option) { fOption = option; }<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 SetObject(TObject *obj) { fObject = obj; }<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 SetInputList(TList *input) { fInput = input; }<\/p>\n<p>virtual TList\u00a0 *GetOutputList() const { return fOutput; }<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 SlaveTerminate();<\/p>\n<p>virtual void\u00a0\u00a0\u00a0 Terminate();<\/p>\n<p>&nbsp;<\/p>\n<p>ClassDef(ProofFirst,2);<\/p>\n<p>};<\/p>\n<p>#endif<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>and the implementation file ProofFirst.C \u2013<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">\n<p>#include &#8220;ProofFirst.h&#8221;<\/p>\n<p>#include &#8220;TH1F.h&#8221;<\/p>\n<p>#include &#8220;TRandom3.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>ProofFirst::ProofFirst()<\/p>\n<p>{<\/p>\n<p>\/\/ Constructor<\/p>\n<p>fH1F = 0;<\/p>\n<p>fRandom = 0;<\/p>\n<p>}<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>ProofFirst::~ProofFirst()<\/p>\n<p>{<\/p>\n<p>\/\/ Destructor<\/p>\n<p>if (fRandom) delete fRandom;<\/p>\n<p>}<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>void ProofFirst::Begin(TTree * \/*tree*\/)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>void ProofFirst::SlaveBegin(TTree * \/*tree*\/)<\/p>\n<p>{<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: red;\">\u00a0\u00a0 fH1F = new TH1F(&#8220;FirstH1F&#8221;, &#8220;First TH1F in PROOF&#8221;, 100, -10., 10.);<\/span><\/p>\n<p>fOutput-&gt;Add(fH1F);<\/p>\n<p><span style=\"color: red;\">\u00a0\u00a0 fRandom = new TRandom3(0)0<\/span>;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>Bool_t ProofFirst::Process(Long64_t)<\/p>\n<p>{<\/p>\n<p>if (fRandom &amp;&amp; fH1F) {<\/p>\n<p><span style=\"color: blue;\">\u00a0\u00a0\u00a0\u00a0\u00a0 Double_t x = fRandom-&gt;Gaus(0.,1.);<\/span><\/p>\n<p><span style=\"color: blue;\">\u00a0\u00a0\u00a0\u00a0\u00a0 fH1F-&gt;Fill(x);<\/span><\/p>\n<p>}<\/p>\n<p>return kTRUE;<\/p>\n<p>}<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>void ProofFirst::SlaveTerminate()<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>\/\/_____________________________________________________________________________<\/p>\n<p>void ProofFirst::Terminate()<\/p>\n<p>{<\/p>\n<p><span style=\"color: green;\">\u00a0 \u00a0TCanvas *c1 = new TCanvas(&#8220;c1&#8221;, &#8220;Proof ProofFirst canvas&#8221;,200,10,400,400);<\/span><\/p>\n<p>fH1F = dynamic_cast(fOutput-&gt;FindObject(&#8220;FirstH1F&#8221;));<\/p>\n<p>if (fH1F)\u00a0<span style=\"color: green;\">fH1F-&gt;Draw();<\/span><\/p>\n<p><span style=\"color: green;\">\u00a0\u00a0 c1-&gt;Update();<\/span><\/p>\n<p>}<\/p>\n<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>We announce the histogram and the random number generator as data members of the ProofFirst class (red color). In the constructor class, we initialize the histogram and generator pointers to 0. In the destructor, we destroy the random number generator. The histogram belongs to the output list, so it is not destroyed. The SlaveBegin () method creates instances of the histogram and the random number generator (red color). The main job is performed by the Process () method, in this case it is the generation of a random number and filling of the histogram with it (blue color). Finally, the Terminate () method shows the result on the terminal (green color).<\/p>\n<p>Now we are ready to handle this selector. Therefore, we run PROOF<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">TProof* proof=TProof::Open(&#8220;lite:\/\/&#8221;,&#8221;workers=12&#8243;)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p>and call the method<\/p>\n<p><!--\u041d\u0430\u0447\u0430\u043b\u043e \u0431\u043b\u043e\u043a\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c--><\/p>\n<div class=\"b-incut-code\">TProof::Process(&#8220;ProofFirst.C+&#8221;, 1000000000)<\/div>\n<p><!--\u0411\u043b\u043e\u043a \u043a\u043e\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d--><\/p>\n<p><span style=\"color: red;\">Here is what you should see on your screens:<\/span><\/p>\n<p style=\"text-align: center;\"><span style=\"color: red;\"><span style=\"color: red;\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2025\/01\/proof1.bmp\" alt=\"\" width=\"830\" height=\"623\" \/><\/span><\/span><\/p>\n<p>A more complicated example, namely, tree reading, calculations, histogram filling, fitting, can be found on the following\u00a0<a href=\"http:\/\/wwwinfo.jinr.ru\/~tanyusha\/proof_tree.html\" target=\"_blank\" rel=\"noopener\">link<\/a>.<\/p>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>PROOF PROOF and object of class TTree. Example. PROOF, i.e.\u00a0Parallel ROOT Facility is an extension of ROOT that allows performing parallel analysis of large sets of ROOT files on multiprocessor machines. That is, PROOF can parallelize tasks, which can be formulated as a series of independent subtasks. PROOF provides: Absence (or a very small number) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":274,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-root.php","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-306","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/pages\/306","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=306"}],"version-history":[{"count":7,"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/pages\/306\/revisions"}],"predecessor-version":[{"id":614,"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/pages\/306\/revisions\/614"}],"up":[{"embeddable":true,"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=\/wp\/v2\/pages\/274"}],"wp:attachment":[{"href":"https:\/\/micc.jinr.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}