File indexing completed on 2025-01-18 10:17:18
0001
0002 from sys import argv
0003 import subprocess
0004 import sys
0005 import os
0006
0007 disapatch_table = {}
0008
0009
0010 def copy_from_source_dir(files_to_copy):
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 jana_scripts_dir = os.path.dirname(os.path.realpath(__file__))
0030 jana_dir = os.path.dirname(jana_scripts_dir)
0031
0032
0033 script_in_source = (os.path.basename(jana_scripts_dir) == "scripts")
0034 script_in_install = (os.path.basename(jana_scripts_dir) == "bin")
0035
0036
0037 Nfile_in_source = sum([1 for f,d in files_to_copy.items() if os.path.exists(jana_dir+"/"+d["sourcedir" ]+"/"+f)])
0038 Nfile_in_install = sum([1 for f,d in files_to_copy.items() if os.path.exists(jana_dir+"/"+d["installdir"]+"/"+f)])
0039 all_files_in_source = (Nfile_in_source == len(files_to_copy))
0040 all_files_in_install = (Nfile_in_install == len(files_to_copy))
0041
0042
0043
0044 Nerrs = 0
0045 use_install = script_in_install and all_files_in_install
0046 use_source = script_in_source and all_files_in_source
0047 if not (use_install or use_source):
0048 use_install = script_in_source and all_files_in_install
0049 use_source = script_in_install and all_files_in_source
0050
0051
0052 if use_install:
0053 for f,d in files_to_copy.items():
0054 files_to_copy[f]["sourcefile"] = jana_dir+"/"+d["installdir"]+"/"+f
0055 if use_source:
0056 for f,d in files_to_copy.items():
0057 files_to_copy[f]["sourcefile"] = jana_dir+"/"+d["sourcedir"]+"/"+f
0058 else:
0059
0060
0061 jana_home = os.getenv("JANA_HOME")
0062 if jana_home is None:
0063 print("ERROR: This script does not look like it is being run from a known")
0064 print(" location and JANA_HOME is also not set. Please set your")
0065 print(" JANA_HOME environment variable to a valid JANA installation.")
0066 sys.exit(-1)
0067 for f,d in files_to_copy.items():
0068 files_to_copy[f]["sourcefile"] = jana_home +"/"+d["installdir"]+"/"+f
0069
0070
0071 Nerrs = 0
0072 for f,d in files_to_copy.items():
0073 try:
0074 cmd = ["cp", d["sourcefile"], d["destname"]]
0075 print(" ".join(cmd))
0076 subprocess.check_call(cmd)
0077 except subprocess.CalledProcessError as cpe:
0078 print("ERROR: Copy failed of " + d["sourcefile"] + " -> " + d["destname"])
0079 Nerrs += 1
0080 if Nerrs > 0:
0081 print("")
0082 print("Errors encountered while copying files to plugin directory. Please")
0083 print("check your permissions, your JANA_HOME environment variable, and")
0084 print("you JANA installation. Continuing now though this may leave you with")
0085 print("a broken plugin.")
0086
0087
0088 def boolify(x, name):
0089 if x==True or x=="True" or x=="true" or x=="1":
0090 return True
0091 elif x==False or x=="False" or x=="false" or x=="0":
0092 return False
0093 else:
0094 raise Exception("Argument "+name+ " must be either 'true' or 'false'")
0095
0096
0097 copyright_notice = """//
0098 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0099 // Jefferson Science Associates LLC Copyright Notice:
0100 // Copyright 251 2014 Jefferson Science Associates LLC All Rights Reserved. Redistribution
0101 // and use in source and binary forms, with or without modification, are permitted as a
0102 // licensed user provided that the following conditions are met:
0103 //
0104 // 1. Redistributions of source code must retain the above copyright notice, this
0105 // list of conditions and the following disclaimer.
0106 // 2. Redistributions in binary form must reproduce the above copyright notice, this
0107 // list of conditions and the following disclaimer in the documentation and/or other
0108 // materials provided with the distribution.
0109 // 3. The name of the author may not be used to endorse or promote products derived
0110 // from this software without specific prior written permission.
0111 //
0112 // This material resulted from work developed under a United States Government Contract.
0113 // The Government retains a paid-up, nonexclusive, irrevocable worldwide license in such
0114 // copyrighted data to reproduce, distribute copies to the public, prepare derivative works,
0115 // perform publicly and display publicly and to permit others to do so.
0116 // THIS SOFTWARE IS PROVIDED BY JEFFERSON SCIENCE ASSOCIATES LLC "AS IS" AND ANY EXPRESS
0117 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0118 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
0119 // JEFFERSON SCIENCE ASSOCIATES, LLC OR THE U.S. GOVERNMENT BE LIABLE TO LICENSEE OR ANY
0120 // THIRD PARTES FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0121 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
0122 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0123 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0124 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0125 // POSSIBILITY OF SUCH DAMAGE.
0126 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0127 //"""
0128
0129
0130 jobject_template_h = """
0131
0132 #ifndef _{name}_h_
0133 #define _{name}_h_
0134
0135 #include <JANA/JObject.h>
0136
0137 /// JObjects are plain-old data containers for inputs, intermediate results, and outputs.
0138 /// They have member functions for introspection and maintaining associations with other JObjects, but
0139 /// all of the numerical code which goes into their creation should live in a JFactory instead.
0140 /// You are allowed to include STL containers and pointers to non-POD datatypes inside your JObjects,
0141 /// however, it is highly encouraged to keep them flat and include only primitive datatypes if possible.
0142 /// Think of a JObject as being a row in a database table, with event number as an implicit foreign key.
0143
0144 struct {name} : public JObject {{
0145 JOBJECT_PUBLIC({name})
0146
0147 int x; // Pixel coordinates centered around 0,0
0148 int y; // Pixel coordinates centered around 0,0
0149 double E; // Energy loss in GeV
0150 double t; // Time in ms
0151
0152
0153 /// Make it convenient to construct one of these things
0154 {name}(int x, int y, double E, double t) : x(x), y(y), E(E), t(t) {{}};
0155
0156
0157 /// Override Summarize to tell JANA how to produce a convenient string representation for our JObject.
0158 /// This can be called from user code, but also lets JANA automatically inspect its own data. See the
0159 /// CsvWriter example. Warning: Because this is slow, it should be used for debugging and monitoring
0160 /// but not inside the performance critical code paths.
0161
0162 void Summarize(JObjectSummary& summary) const override {{
0163 summary.add(x, NAME_OF(x), "%d", "Pixel coordinates centered around 0,0");
0164 summary.add(y, NAME_OF(y), "%d", "Pixel coordinates centered around 0,0");
0165 summary.add(E, NAME_OF(E), "%f", "Energy loss in GeV");
0166 summary.add(t, NAME_OF(t), "%f", "Time in ms");
0167 }}
0168 }};
0169
0170
0171 #endif // _{name}_h_
0172
0173 """
0174
0175 jeventsource_template_h = """
0176
0177 #ifndef _{name}_h_
0178 #define _{name}_h_
0179
0180 #include <JANA/JEventSource.h>
0181 #include <JANA/JEventSourceGeneratorT.h>
0182
0183 class {name} : public JEventSource {{
0184
0185 /// Add member variables here
0186
0187 public:
0188 {name}();
0189
0190 virtual ~{name}() = default;
0191
0192 void Open() override;
0193
0194 void Close() override;
0195
0196 Result Emit(JEvent& event) override;
0197
0198 static std::string GetDescription();
0199
0200 }};
0201
0202 template <>
0203 double JEventSourceGeneratorT<{name}>::CheckOpenable(std::string);
0204
0205 #endif // _{name}_h_
0206
0207 """
0208
0209 jeventsource_template_cc = """
0210
0211 #include "{name}.h"
0212
0213 #include <JANA/JApplication.h>
0214 #include <JANA/JEvent.h>
0215
0216 /// Include headers to any JObjects you wish to associate with each event
0217 // #include "Hit.h"
0218
0219 /// There are two different ways of instantiating JEventSources
0220 /// 1. Creating them manually and registering them with the JApplication
0221 /// 2. Creating a corresponding JEventSourceGenerator and registering that instead
0222 /// If you have a list of files as command line args, JANA will use the JEventSourceGenerator
0223 /// to find the most appropriate JEventSource corresponding to that filename, instantiate and register it.
0224 /// For this to work, the JEventSource constructor has to have the following constructor arguments:
0225
0226 {name}::{name}() : JEventSource() {{
0227 SetTypeName(NAME_OF_THIS); // Provide JANA with class name
0228 SetCallbackStyle(CallbackStyle::ExpertMode);
0229 }}
0230
0231 void {name}::Open() {{
0232
0233 /// Open is called exactly once when processing begins.
0234
0235 /// Get any configuration parameters from the JApplication
0236 // GetApplication()->SetDefaultParameter("{name}:random_seed", m_seed, "Random seed");
0237
0238 /// For opening a file, get the filename via:
0239 // std::string resource_name = GetResourceName();
0240 /// Open the file here!
0241 }}
0242
0243 void {name}::Close() {{
0244
0245 /// Close is called exactly once when processing ends. This is where you should close your files or sockets.
0246 /// It is important to do that here instead of in Emit() because we want everything to be cleanly closed
0247 /// even when JANA is terminated via Ctrl-C or via a timeout.
0248
0249 }}
0250
0251 JEventSource::Result {name}::Emit(JEvent& event) {{
0252
0253 /// Calls to GetEvent are synchronized with each other, which means they can
0254 /// read and write state on the JEventSource without causing race conditions.
0255
0256 /// Configure event and run numbers
0257 static size_t current_event_number = 1;
0258 event.SetEventNumber(current_event_number++);
0259 event.SetRunNumber(22);
0260
0261 /// Insert whatever data was read into the event
0262 // std::vector<Hit*> hits;
0263 // hits.push_back(new Hit(0,0,1.0,0));
0264 // event.Insert(hits);
0265
0266 /// If you are reading a file of events and have reached the end, terminate the stream like this:
0267 /// Note that you should close any file handles or sockets in Close(), not here!
0268 // return Result::FailureFinished;
0269
0270 /// If you are streaming events and there are no new events in the message queue,
0271 /// tell JANA that Emit() was temporarily unsuccessful like this:
0272 // return Result::FailureTryAgain;
0273
0274 return Result::Success;
0275 }}
0276
0277 std::string {name}::GetDescription() {{
0278
0279 /// GetDescription() helps JANA explain to the user what is going on
0280 return "";
0281 }}
0282
0283
0284 template <>
0285 double JEventSourceGeneratorT<{name}>::CheckOpenable(std::string resource_name) {{
0286
0287 /// CheckOpenable() decides how confident we are that this EventSource can handle this resource.
0288 /// 0.0 -> 'Cannot handle'
0289 /// (0.0, 1.0] -> 'Can handle, with this confidence level'
0290
0291 /// To determine confidence level, feel free to open up the file and check for magic bytes or metadata.
0292 /// Returning a confidence <- {{0.0, 1.0}} is perfectly OK!
0293
0294 return (resource_name == "{name}") ? 1.0 : 0.0;
0295 }}
0296 """
0297
0298 plugin_main = """
0299
0300 #include <JANA/JApplication.h>
0301 #include <JANA/JFactoryGenerator.h>
0302
0303 #include "{name}Processor.h"
0304
0305 extern "C" {{
0306 void InitPlugin(JApplication* app) {{
0307
0308 // This code is executed when the plugin is attached.
0309 // It should always call InitJANAPlugin(app) first, and then do one or more of:
0310 // - Read configuration parameters
0311 // - Register JFactoryGenerators
0312 // - Register JEventProcessors
0313 // - Register JEventSourceGenerators (or JEventSources directly)
0314 // - Register JServices
0315
0316 InitJANAPlugin(app);
0317
0318 LOG << "Loading {name}" << LOG_END;
0319 app->Add(new {name}Processor);
0320 // Add any additional components as needed
0321 }}
0322 }}
0323
0324 """
0325
0326 project_cmakelists_txt = """
0327 cmake_minimum_required(VERSION 3.9)
0328 project({name}_project)
0329
0330 if(NOT "${{CMAKE_CXX_STANDARD}}")
0331 set(CMAKE_CXX_STANDARD 14)
0332 endif()
0333 set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Enable -fPIC for all targets
0334
0335 # Expose custom cmake modules
0336 list(APPEND CMAKE_MODULE_PATH "${{CMAKE_CURRENT_LIST_DIR}}/cmake")
0337
0338 # Set install directory to $JANA_HOME
0339 set(CMAKE_INSTALL_PREFIX $ENV{{JANA_HOME}} CACHE PATH "magic incantation" FORCE)
0340
0341 # Find dependencies
0342 find_package(JANA REQUIRED)
0343
0344 """
0345
0346
0347 project_src_cmakelists_txt = """
0348 add_subdirectory(libraries)
0349 add_subdirectory(plugins)
0350 add_subdirectory(programs)
0351 """
0352
0353
0354 plugin_cmakelists_txt = """
0355 {extra_find_packages}
0356
0357 # According to the internet, CMake authors discourage the use
0358 # of GLOB for identifying source files. IMHO, this is due to
0359 # the flawed use of cache files in CMake itself. Here, GLOB
0360 # is used as the default. What this means is you can add source
0361 # files and re-run cmake (after clearing the cache file) and
0362 # they will be found without needing to modify this file.
0363 # You also have the option of switching the following to "false"
0364 # and managing the source file list manually the way they recommend.
0365 if(true)
0366 # Automatically determine source file list.
0367 file(GLOB mysourcefiles *.cpp *.cc *.c *.hpp *.hh *.h)
0368 set( JANAGPUTest_PLUGIN_SOURCES ${{mysourcefiles}} )
0369 else()
0370 # Manually manage source file list
0371 set ({name}_PLUGIN_SOURCES
0372 {name}.cc
0373 {name}Processor.cc
0374 {name}Processor.h
0375 )
0376 endif()
0377
0378 add_library({name}_plugin SHARED ${{{name}_PLUGIN_SOURCES}})
0379
0380 target_include_directories({name}_plugin PUBLIC ${{CMAKE_SOURCE_DIR}} ${{JANA_INCLUDE_DIR}} {extra_includes})
0381 target_link_libraries({name}_plugin ${{JANA_LIBRARY}} {extra_libraries})
0382 set_target_properties({name}_plugin PROPERTIES PREFIX "" OUTPUT_NAME "{name}" SUFFIX ".so")
0383
0384 install(TARGETS {name}_plugin DESTINATION plugins)
0385
0386 file(GLOB my_headers "*.h*")
0387 install(FILES ${{my_headers}} DESTINATION include/{name})
0388
0389 # For root dictionaries
0390 file(GLOB my_pcms "${{CMAKE_CURRENT_BINARY_DIR}}/*.pcm")
0391 install(FILES ${{my_pcms}} DESTINATION plugins)
0392
0393 """
0394
0395
0396 mini_plugin_cmakelists_txt = """
0397 {extra_find_packages}
0398
0399 # According to the internet, CMake authors discourage the use
0400 # of GLOB for identifying source files. IMHO, this is due to
0401 # the flawed use of cache files in CMake itself. Here, GLOB
0402 # is used as the default. What this means is you can add source
0403 # files and re-run cmake (after clearing the cache file) and
0404 # they will be found without needing to modify this file.
0405 # You also have the option of switching the following to "false"
0406 # and managing the source file list manually the way they recommend.
0407 if(true)
0408 # Automatically determine source file list.
0409 file(GLOB mysourcefiles *.cpp *.cc *.c *.hpp *.hh *.h)
0410 set( {name}_PLUGIN_SOURCES ${{mysourcefiles}} )
0411 else()
0412 # Manually manage source file list
0413 set ({name}_PLUGIN_SOURCES
0414 {name}.cc
0415 )
0416 endif()
0417
0418 add_library({name}_plugin SHARED ${{{name}_PLUGIN_SOURCES}})
0419
0420 target_include_directories({name}_plugin PUBLIC ${{CMAKE_SOURCE_DIR}} ${{JANA_INCLUDE_DIR}} {extra_includes})
0421 target_link_libraries({name}_plugin ${{JANA_LIB}} {extra_libraries})
0422 set_target_properties({name}_plugin PROPERTIES PREFIX "" OUTPUT_NAME "{name}" SUFFIX ".so")
0423
0424 install(TARGETS {name}_plugin DESTINATION plugins)
0425
0426 file(GLOB my_headers "*.h*")
0427 install(FILES ${{my_headers}} DESTINATION include/{name})
0428
0429 # For root dictionaries
0430 file(GLOB my_pcms "${{CMAKE_CURRENT_BINARY_DIR}}/*.pcm")
0431 install(FILES ${{my_pcms}} DESTINATION plugins)
0432
0433 """
0434
0435
0436 plugin_tests_cmakelists_txt = """
0437
0438 set ({name}_PLUGIN_TESTS_SOURCES
0439 catch.hpp
0440 TestsMain.cc
0441 IntegrationTests.cc
0442 # Add component tests here
0443 )
0444
0445 add_executable({name}_plugin_tests ${{{name}_PLUGIN_TESTS_SOURCES}})
0446
0447 find_package(JANA REQUIRED)
0448
0449 target_include_directories({name}_plugin_tests PUBLIC ../src)
0450 target_include_directories({name}_plugin_tests PUBLIC ${{JANA_INCLUDE_DIR}})
0451
0452 target_link_libraries({name}_plugin_tests {name}_plugin)
0453 target_link_libraries({name}_plugin_tests ${{JANA_LIBRARY}})
0454
0455 install(TARGETS {name}_plugin_tests DESTINATION bin)
0456
0457 """
0458
0459
0460 plugin_integration_tests_cc = """
0461 #include "catch.hpp"
0462 #include "{name}Processor.h"
0463
0464 #include <JANA/JApplication.h>
0465 #include <JANA/JFactoryGenerator.h>
0466
0467
0468 // This is where you can assemble various components and verify that when put together, they
0469 // do what you'd expect. This means you can skip the laborious mixing and matching of plugins and configurations,
0470 // and have everything run automatically inside one executable.
0471
0472 TEST_CASE("{name}IntegrationTests") {{
0473
0474 auto app = new JApplication;
0475
0476 // Create and register components
0477 // app->Add(new {name}Processor);
0478
0479 // TODO: Add (mocked) event source
0480 // app->Add(new MockEventSource);
0481
0482 // Set test parameters
0483 app->SetParameterValue("nevents", 10);
0484
0485 // Run everything, blocking until finished
0486 app->Run();
0487
0488 // Verify the results you'd expect
0489 REQUIRE(app->GetNEventsProcessed() == 10);
0490
0491 }}
0492
0493 """
0494
0495
0496 plugin_tests_main_cc = """
0497
0498 // This is the entry point for our test suite executable.
0499 // Catch2 will take over from here.
0500
0501 #define CATCH_CONFIG_MAIN
0502 #include "catch.hpp"
0503
0504 """
0505
0506
0507 jeventprocessor_template_h = """
0508 #ifndef _{name}_h_
0509 #define _{name}_h_
0510
0511 #include <JANA/JEventProcessor.h>
0512
0513 class {name} : public JEventProcessor {{
0514
0515 // Shared state (e.g. histograms, TTrees, TFiles) live
0516 std::mutex m_mutex;
0517
0518 public:
0519
0520 {name}();
0521 virtual ~{name}() = default;
0522
0523 void Init() override;
0524 void Process(const std::shared_ptr<const JEvent>& event) override;
0525 void Finish() override;
0526
0527 }};
0528
0529
0530 #endif // _{name}_h_
0531
0532 """
0533
0534
0535 jeventprocessor_template_cc = """
0536 #include "{name}.h"
0537 #include <JANA/JLogger.h>
0538
0539 {name}::{name}() {{
0540 SetTypeName(NAME_OF_THIS); // Provide JANA with this class's name
0541 }}
0542
0543 void {name}::Init() {{
0544 LOG << "{name}::Init" << LOG_END;
0545 // Open TFiles, set up TTree branches, etc
0546 }}
0547
0548 void {name}::Process(const std::shared_ptr<const JEvent> &event) {{
0549 LOG << "{name}::Process, Event #" << event->GetEventNumber() << LOG_END;
0550
0551 /// Do everything we can in parallel
0552 /// Warning: We are only allowed to use local variables and `event` here
0553 //auto hits = event->Get<Hit>();
0554
0555 /// Lock mutex
0556 std::lock_guard<std::mutex>lock(m_mutex);
0557
0558 /// Do the rest sequentially
0559 /// Now we are free to access shared state such as m_heatmap
0560 //for (const Hit* hit : hits) {{
0561 /// Update shared state
0562 //}}
0563 }}
0564
0565 void {name}::Finish() {{
0566 // Close any resources
0567 LOG << "{name}::Finish" << LOG_END;
0568 }}
0569
0570 """
0571
0572
0573 jeventprocessor_template_tests = """
0574 """
0575
0576
0577 jfactory_template_cc = """
0578 #include "{name}.h"
0579
0580 #include <JANA/JEvent.h>
0581
0582 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0583 // Please add the following lines to your InitPlugin or similar routine
0584 // in order to register this factory with the system.
0585 //
0586 // #include "{name}.h"
0587 //
0588 // app->Add( new JFactoryGeneratorT<{name}>() );
0589 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0590
0591
0592 //------------------------
0593 // Constructor
0594 //------------------------
0595 {name}::{name}(){{
0596 SetTag("{tag}");
0597 }}
0598
0599 //------------------------
0600 // Init
0601 //------------------------
0602 void {name}::Init() {{
0603 auto app = GetApplication();
0604
0605 /// Acquire any parameters
0606 // app->GetParameter("parameter_name", m_destination);
0607
0608 /// Acquire any services
0609 // m_service = app->GetService<ServiceT>();
0610
0611 /// Set any factory flags
0612 // SetFactoryFlag(JFactory_Flags_t::NOT_OBJECT_OWNER);
0613 }}
0614
0615 //------------------------
0616 // ChangeRun
0617 //------------------------
0618 void {name}::ChangeRun(const std::shared_ptr<const JEvent> &event) {{
0619 /// This is automatically run before Process, when a new run number is seen
0620 /// Usually we update our calibration constants by asking a JService
0621 /// to give us the latest data for this run number
0622
0623 auto run_nr = event->GetRunNumber();
0624 // m_calibration = m_service->GetCalibrationsForRun(run_nr);
0625 }}
0626
0627 //------------------------
0628 // Process
0629 //------------------------
0630 void {name}::Process(const std::shared_ptr<const JEvent> &event) {{
0631
0632 /// JFactories are local to a thread, so we are free to access and modify
0633 /// member variables here. However, be aware that events are _scattered_ to
0634 /// different JFactory instances, not _broadcast_: this means that JFactory
0635 /// instances only see _some_ of the events.
0636
0637 /// Acquire inputs (This may recursively call other JFactories)
0638 // auto inputs = event->Get<...>();
0639
0640 /// Do some computation
0641
0642 /// Publish outputs
0643 // std::vector<{jobject_name}*> results;
0644 // results.push_back(new {jobject_name}(...));
0645 // Set(results);
0646 }}
0647 """
0648
0649
0650 jfactory_template_h = """
0651 #ifndef _{name}_h_
0652 #define _{name}_h_
0653
0654 #include <JANA/JFactoryT.h>
0655
0656 #include "{jobject_name}.h"
0657
0658 class {name} : public JFactoryT<{jobject_name}> {{
0659
0660 // Insert any member variables here
0661
0662 public:
0663 {name}();
0664 void Init() override;
0665 void ChangeRun(const std::shared_ptr<const JEvent> &event) override;
0666 void Process(const std::shared_ptr<const JEvent> &event) override;
0667
0668 }};
0669
0670 #endif // _{name}_h_
0671 """
0672
0673
0674 jroot_output_processor_h = """
0675 #include <JANA/JEventProcessor.h>
0676 #include <JANA/Services/JGlobalRootLock.h>
0677 #include <TH1D.h>
0678 #include <TFile.h>
0679
0680 class {processor_name}: public JEventProcessor {{
0681
0682 private:
0683 std::string m_tracking_alg = "genfit";
0684 std::shared_ptr<JGlobalRootLock> m_lock;
0685 TH1D* h1d_pt_reco = nullptr;
0686 TDirectory* dest_file = nullptr;
0687 TDirectory* dest_dir=nullptr; // Virtual subfolder inside dest_file used for this specific processor
0688
0689 public:
0690 {processor_name}();
0691
0692 void Init() override;
0693
0694 void Process(const std::shared_ptr<const JEvent>& event) override;
0695
0696 void Finish() override;
0697 }};
0698
0699 """
0700
0701
0702 jroot_output_processor_cc = """
0703 #include "{processor_name}.h"
0704
0705 {processor_name}::{processor_name}() {{
0706 SetTypeName(NAME_OF_THIS); // Provide JANA with this class's name
0707 }}
0708
0709 void {processor_name}::Init() {{
0710 auto app = GetApplication();
0711 m_lock = app->GetService<JGlobalRootLock>();
0712
0713 /// Set parameters to control which JFactories you use
0714 app->SetDefaultParameter("tracking_alg", m_tracking_alg);
0715
0716 /// Set up histograms
0717 m_lock->acquire_write_lock();
0718
0719 if( dest_file == nullptr ){{
0720 dest_file = new TFile("{processor_name}.root", "recreate"); /// TODO: Acquire dest_file via either a JService or a JParameter
0721 }}
0722 dest_dir = dest_file->mkdir("{dir_name}"); // Create a subdir inside dest_file for these results
0723 h1d_pt_reco = new TH1D("pt_reco", "reco pt", 100,0,10);
0724 h1d_pt_reco->SetDirectory(dest_dir);
0725 m_lock->release_lock();
0726 }}
0727
0728 void {processor_name}::Process(const std::shared_ptr<const JEvent>& event) {{
0729
0730 /// Acquire any results you need for your analysis
0731 //auto reco_tracks = event->Get<RecoTrack>(m_tracking_alg);
0732
0733 m_lock->acquire_write_lock();
0734 /// Inside the global root lock, update histograms
0735 // for (auto reco_track : reco_tracks) {{
0736 // h1d_pt_reco->Fill(reco_track->p.Pt());
0737 // }}
0738 m_lock->release_lock();
0739 }}
0740
0741 void {processor_name}::Finish() {{
0742 // TODO: If we did not create this file then we should not delete it
0743 dest_file->Write();
0744 delete dest_file;
0745 dest_file = nullptr;
0746 }};
0747
0748 """
0749
0750
0751 mini_plugin_cc_noroot = """
0752 #include <JANA/JEventProcessor.h>
0753
0754 class {name}Processor: public JEventProcessor {{
0755 private:
0756 std::string m_tracking_alg = "genfit";
0757 std::mutex m_mutex;
0758
0759 public:
0760 {name}Processor() {{
0761 SetTypeName(NAME_OF_THIS); // Provide JANA with this class's name
0762 }}
0763
0764 void Init() override {{
0765 auto app = GetApplication();
0766
0767 /// Set parameters to control which JFactories you use
0768 app->SetDefaultParameter("tracking_alg", m_tracking_alg);
0769 }}
0770
0771 void Process(const std::shared_ptr<const JEvent>& event) override {{
0772
0773 /// Acquire any per-event results you need for your analysis
0774 // auto reco_tracks = event->Get<RecoTrack>(m_tracking_alg);
0775
0776 /// Inside the lock, update any shared state, e.g. histograms
0777 std::lock_guard<std::mutex> lock(m_mutex);
0778
0779 // for (auto reco_track : reco_tracks) {{
0780 // histogram->Fill(reco_track->p.Pt());
0781 // }}
0782 }}
0783
0784 void Finish() override {{
0785 // Write data and close resources
0786 }}
0787 }};
0788
0789 extern "C" {{
0790 void InitPlugin(JApplication *app) {{
0791 InitJANAPlugin(app);
0792 app->Add(new {name}Processor);
0793 }}
0794 }}
0795
0796 """
0797
0798
0799 mini_plugin_cc = """
0800 #include <JANA/JEventProcessor.h>
0801 #include <JANA/Services/JGlobalRootLock.h>
0802 #include <TH1D.h>
0803 #include <TFile.h>
0804
0805 class {name}Processor: public JEventProcessor {{
0806 private:
0807 std::string m_tracking_alg = "genfit";
0808 std::shared_ptr<JGlobalRootLock> m_lock;
0809 TFile* dest_file;
0810 TDirectory* dest_dir; // Virtual subfolder inside dest_file used for this specific processor
0811
0812 /// Declare histograms here
0813 TH1D* h1d_pt_reco;
0814
0815 public:
0816 {name}Processor() {{
0817 SetTypeName(NAME_OF_THIS); // Provide JANA with this class's name
0818 }}
0819
0820 void Init() override {{
0821 auto app = GetApplication();
0822 m_lock = app->GetService<JGlobalRootLock>();
0823
0824 /// Set parameters to control which JFactories you use
0825 app->SetDefaultParameter("tracking_alg", m_tracking_alg);
0826
0827 /// Set up histograms
0828 m_lock->acquire_write_lock();
0829 dest_file = new TFile("{name}.root", "recreate"); /// TODO: Acquire dest_file via either a JService or a JParameter
0830 dest_dir = dest_file->mkdir("{name}"); // Create a subdir inside dest_file for these results
0831 dest_file->cd();
0832 h1d_pt_reco = new TH1D("pt_reco", "reco pt", 100,0,10);
0833 h1d_pt_reco->SetDirectory(dest_dir);
0834 m_lock->release_lock();
0835 }}
0836
0837 void Process(const std::shared_ptr<const JEvent>& event) override {{
0838
0839 /// Acquire any results you need for your analysis
0840 //auto reco_tracks = event->Get<RecoTrack>(m_tracking_alg);
0841
0842 m_lock->acquire_write_lock();
0843 /// Inside the global root lock, update histograms
0844 // for (auto reco_track : reco_tracks) {{
0845 // h1d_pt_reco->Fill(reco_track->p.Pt());
0846 // }}
0847 m_lock->release_lock();
0848 }}
0849
0850 void Finish() override {{
0851 // TODO: If we did not create this file then we should not delete it
0852 dest_file->Write();
0853 delete dest_file;
0854 dest_file = nullptr;
0855 }}
0856 }};
0857
0858 extern "C" {{
0859 void InitPlugin(JApplication *app) {{
0860 InitJANAPlugin(app);
0861 app->Add(new {name}Processor);
0862 }}
0863 }}
0864
0865 """
0866
0867
0868 def create_jobject(name):
0869 """Create a JObject code skeleton in the current directory. Requires one argument:
0870 name: The name of the JObject, e.g. "RecoTrack"
0871 """
0872 filename = name + ".h"
0873 text = jobject_template_h.format(copyright_notice=copyright_notice, name=name)
0874 print(f"Creating {name}:public JObject")
0875 with open(filename, 'w') as f:
0876 f.write(text)
0877
0878
0879 def create_jeventsource(name):
0880 """Create a JEventSource code skeleton in the current directory. Requires one argument:
0881 name: The name of the JEventSource, e.g. "CsvFileSource"
0882 """
0883
0884 with open(name + ".h", 'w') as f:
0885 text = jeventsource_template_h.format(copyright_notice=copyright_notice, name=name)
0886 f.write(text)
0887
0888 with open(name + ".cc", 'w') as f:
0889 text = jeventsource_template_cc.format(copyright_notice=copyright_notice, name=name)
0890 f.write(text)
0891
0892
0893 def create_jeventprocessor(name):
0894 """Create a JEventProcessor code skeleton in the current directory. Requires one argument:
0895 name: The name of the JEventProcessor, e.g. "TrackingEfficiencyProcessor"
0896 """
0897
0898 with open(name + ".h", 'w') as f:
0899 text = jeventprocessor_template_h.format(copyright_notice=copyright_notice, name=name)
0900 f.write(text)
0901
0902 with open(name + ".cc", 'w') as f:
0903 text = jeventprocessor_template_cc.format(copyright_notice=copyright_notice, name=name)
0904 f.write(text)
0905
0906 with open(name + "Tests.cc", 'w') as f:
0907 text = jeventprocessor_template_tests.format(copyright_notice=copyright_notice, name=name)
0908 f.write(text)
0909
0910
0911 def create_root_eventprocessor(processor_name, dir_name):
0912 """Create a ROOT-aware JEventProcessor code skeleton in the current directory. Requires two positional arguments:
0913 [processor_name] The name of the JEventProcessor, e.g. "TrackingEfficiencyProcessor"
0914 [dir_name] The name of the virtual directory in the ROOT file where everything goes, e.g. "trk_eff"
0915 """
0916 with open(processor_name + ".h", 'w') as f:
0917 text = jroot_output_processor_h.format(processor_name=processor_name, dir_name=dir_name)
0918 f.write(text)
0919
0920
0921 def build_plugin_test(plugin_name, copy_catch_hpp=True, dir="."):
0922
0923 if copy_catch_hpp:
0924 files_to_copy = {"catch.hpp": {"sourcedir": "src/external",
0925 "installdir": "include/JANA/external",
0926 "destname": dir+"/catch.hpp"}}
0927 copy_from_source_dir(files_to_copy)
0928
0929 cmakelists_path = dir + "/" + "CMakeLists.txt"
0930 with open(cmakelists_path) as f:
0931 text = plugin_tests_cmakelists_txt.format(name=plugin_name)
0932 f.write(text)
0933
0934 integration_test_cc_path = dir + "/IntegrationTests.cc"
0935 with open(integration_test_cc_path) as f:
0936 text = plugin_integration_tests_cc.format(name=plugin_name)
0937 f.write(text)
0938
0939 tests_main_path = dir + "/TestsMain.cc"
0940 with open(tests_main_path) as f:
0941 text = plugin_tests_main_cc
0942 f.write(text)
0943
0944
0945 def build_jeventprocessor_test(processor_name, is_mini=True, copy_catch_hpp=True, dir="."):
0946
0947 if copy_catch_hpp:
0948 files_to_copy = {"catch.hpp": {"sourcedir": "src/external",
0949 "installdir": "include/JANA/external",
0950 "destname": dir+"/catch.hpp"}}
0951 copy_from_source_dir(files_to_copy)
0952
0953 cmakelists_path = dir + "/" + "CMakeLists.txt"
0954 with open(cmakelists_path) as f:
0955 text = plugin_tests_cmakelists_txt.format(name=name)
0956 f.write(text)
0957
0958 if is_mini:
0959 integration_test_cc_path = dir + "/IntegrationTests.cc"
0960 with open(integration_test_cc_path) as f:
0961 text = plugin_integration_tests_cc.format(name=processor_name)
0962 f.write(text)
0963 else:
0964 tests_main_path = dir + "/TestsMain.cc"
0965 with open(tests_main_path) as f:
0966 text = plugin_tests_main_cc
0967 f.write(text)
0968
0969
0970 def create_jeventprocessor_test(processor_name):
0971 """Create a JEventProcessor unit test skeleton in the current directory. Requires two arguments:
0972 processor_name: The name of the JEventProcessor under test
0973 """
0974 build_jeventprocessor_test()
0975
0976
0977 def create_jfactory(jobject_name, tag=''):
0978 """Create a JFactory code skeleton in the current directory. One required argument and one optional argument:
0979 jobject_name The name of the JObject this factory creates, e.g. "RecoTrack"
0980 [tag] Optional tag for the factory (defaults to empty string)
0981
0982 n.b. This will also automatically create a JObject header in the current
0983 directory if the file does not already exist. You may need to delete this
0984 manually if you already have this class defined elsewhere in the source tree.
0985 """
0986
0987 factory_name = f'JFactory_{jobject_name}'
0988 if tag != '' : factory_name += f'_{tag}'
0989
0990 print(f"Creating {factory_name}:public JFactoryT<{jobject_name}>")
0991 with open(factory_name + ".cc", 'w') as f:
0992 text = jfactory_template_cc.format(name=factory_name, jobject_name=jobject_name, tag=tag)
0993 f.write(text)
0994
0995 with open(factory_name + ".h", 'w') as f:
0996 text = jfactory_template_h.format(name=factory_name, jobject_name=jobject_name, tag=tag)
0997 f.write(text)
0998
0999
1000
1001
1002 jobject_header_filename = jobject_name + ".h"
1003 if not os.path.exists( jobject_header_filename ):
1004 create_jobject( jobject_name )
1005
1006
1007 def create_jfactory_test(factory_name, jobject_name):
1008 with open(factory_name + "Test.cc", 'w') as f:
1009 text = jfactory_test_cc.format(factory_name=factory_name, jobject_name=jobject_name);
1010 f.write(text)
1011
1012
1013 def create_executable(name):
1014 """Create a code skeleton for a project executable in the current directory. Requires one positional argument:
1015 name: The name of the executable, e.g. "escalate" or "halld_recon"
1016 """
1017 pass
1018
1019
1020 def create_plugin(name, is_standalone=True, is_mini=True, include_root=False, include_tests=False):
1021 """Create a code skeleton for a plugin in its own directory. Takes the following positional arguments:
1022 name The name of the plugin, e.g. "trk_eff" or "TrackingEfficiency"
1023 [is_standalone] Is this a new project, or are we inside the source tree of an existing CMake project? (default=True)
1024 [is_mini] Reduce boilerplate and put everything in a single file? (default=True)
1025 [include_root] Include a ROOT dependency and stubs for filling a ROOT histogram? (default=False)
1026
1027 Example: `jana_generate.py Plugin TrackingEfficiency 1 0 0`
1028 """
1029
1030 is_standalone = boolify(is_standalone, "is_standalone")
1031 is_mini = boolify(is_mini, "is_mini")
1032 include_root = boolify(include_root, "include_root")
1033 include_tests = boolify(include_tests, "include_tests")
1034
1035 os.mkdir(name)
1036 if not is_standalone:
1037 with open("CMakeLists.txt", 'a') as f:
1038 f.write("add_subdirectory("+name+")\n")
1039
1040
1041
1042 cmakelists = ""
1043 if include_root:
1044 extra_find_packages = "find_package(ROOT REQUIRED)"
1045 extra_includes = "${ROOT_INCLUDE_DIRS}"
1046 extra_libraries = "${ROOT_LIBRARIES}"
1047 else:
1048 extra_find_packages = ""
1049 extra_includes = ""
1050 extra_libraries = ""
1051
1052 if is_standalone:
1053 cmakelists += project_cmakelists_txt.format(name=name)
1054
1055 if not is_mini:
1056 with open(name + "/" + name + ".cc", 'w') as f:
1057 text = plugin_main.format(name=name)
1058 f.write(text)
1059
1060
1061
1062 if include_root and is_mini:
1063 cmakelists += mini_plugin_cmakelists_txt.format(name=name,
1064 extra_find_packages=extra_find_packages,
1065 extra_includes=extra_includes,
1066 extra_libraries=extra_libraries)
1067 with open(name + "/" + name + ".cc", 'w') as f:
1068 text = mini_plugin_cc.format(name=name)
1069 f.write(text)
1070
1071 elif include_root and not is_mini:
1072 with open(name + "/" + name + "Processor.h", 'w') as f:
1073 text = jroot_output_processor_h.format(processor_name=name+"Processor", dir_name=name)
1074 f.write(text)
1075
1076 with open(name + "/" + name + "Processor.cc", 'w') as f:
1077 text = jroot_output_processor_cc.format(processor_name=name+"Processor", dir_name=name)
1078 f.write(text)
1079
1080 cmakelists += plugin_cmakelists_txt.format(name=name,
1081 extra_find_packages=extra_find_packages,
1082 extra_includes=extra_includes,
1083 extra_libraries=extra_libraries)
1084
1085 elif not include_root and is_mini:
1086 cmakelists += mini_plugin_cmakelists_txt.format(name=name,
1087 extra_find_packages=extra_find_packages,
1088 extra_includes=extra_includes,
1089 extra_libraries=extra_libraries)
1090 with open(name + "/" + name + ".cc", 'w') as f:
1091 text = mini_plugin_cc_noroot.format(name=name)
1092 f.write(text)
1093
1094 else:
1095
1096 cmakelists += plugin_cmakelists_txt.format(name=name,
1097 extra_find_packages=extra_find_packages,
1098 extra_includes=extra_includes,
1099 extra_libraries=extra_libraries)
1100
1101 with open(name + "/" + name + "Processor.cc", 'w') as f:
1102 text = jeventprocessor_template_cc.format(name=name+"Processor")
1103 f.write(text)
1104
1105 with open(name + "/" + name + "Processor.h", 'w') as f:
1106 text = jeventprocessor_template_h.format(name=name+"Processor")
1107 f.write(text)
1108
1109 if include_tests:
1110 with open(name + "/" + name + "ProcessorTest.cc", 'w') as f:
1111 text = jeventprocessor_template_tests.format(name=name+"Processor")
1112 f.write(text)
1113
1114
1115
1116
1117
1118
1119 with open(name + "/CMakeLists.txt", 'w') as f:
1120 f.write(cmakelists)
1121
1122
1123 def create_project(name):
1124 """Create a code skeleton for a complete project in its own directory. Requires one argument:
1125 name: The name of the project, e.g. "escalate" or "halld_recon"
1126 """
1127 os.mkdir(name)
1128 os.mkdir(name + "/cmake")
1129 os.mkdir(name + "/external")
1130 os.mkdir(name + "/src")
1131 os.mkdir(name + "/src/libraries")
1132 os.mkdir(name + "/src/plugins")
1133 os.mkdir(name + "/src/programs")
1134 os.mkdir(name + "/src/programs/cli")
1135
1136
1137 with open(name + "/CMakeLists.txt", 'w') as f:
1138 text = project_cmakelists_txt.format(name=name)
1139 f.write(text)
1140
1141 with open(name + "/src/CMakeLists.txt", 'w') as f:
1142 text = project_src_cmakelists_txt
1143 f.write(text)
1144
1145
1146
1147
1148 with open(name + "/src/libraries/CMakeLists.txt", 'w') as f:
1149 f.write("")
1150
1151 with open(name + "/src/plugins/CMakeLists.txt", 'w') as f:
1152 f.write("\n")
1153
1154 with open(name + "/src/programs/CMakeLists.txt", 'w') as f:
1155 f.write("")
1156
1157 def print_usage():
1158 print("Usage: jana-generate.py [-h|--help] [type] [args...]")
1159 print(" type: " + ' '.join(dispatch_table.keys()))
1160
1161 def print_help():
1162 print("""
1163 jana-generate.py : Generate skeleton code template for various JANA code constructs.
1164
1165 Usage: jana-generate.py [-h|--help] [type] [args...]
1166
1167 This is used to generate a small piece of skeleton code that can then be easily
1168 edited to implement a specific class or plugin in JANA. The type argument specifies
1169 the type of construct to generate. Optional arguments vary depending on the type.
1170 The type argument should be one of:
1171 """)
1172 print('\n'.join(dispatch_table.keys()))
1173
1174 print('\n--------------------------------------------------------------------')
1175 print('Details:\n')
1176
1177 for (name,proc) in dispatch_table.items():
1178 print( name )
1179 print( proc.__doc__ )
1180
1181
1182
1183 if __name__ == '__main__':
1184
1185 if sys.version_info < (3, 6):
1186 print('Please upgrade your Python version to 3.6.0 or higher')
1187 sys.exit()
1188
1189
1190 dispatch_table = {'JObject': create_jobject,
1191 'JEventSource': create_jeventsource,
1192 'JEventProcessor': create_jeventprocessor,
1193 'RootEventProcessor': create_root_eventprocessor,
1194 'JEventProcessorTest': create_jeventprocessor_test,
1195 'JFactory': create_jfactory,
1196
1197
1198 'Plugin': create_plugin,
1199 'Project': create_project,
1200
1201 }
1202
1203
1204 if len(argv) < 2:
1205 print_usage()
1206 exit()
1207
1208
1209 if len(argv) == 2:
1210 if argv[1]=='-h' or argv[1]=='--help':
1211 print_help()
1212 exit()
1213
1214
1215 option = argv[1]
1216 if option in dispatch_table:
1217 try:
1218 dispatch_table[option](*argv[2:])
1219 except TypeError:
1220 print('\n'+dispatch_table[option].__doc__)
1221 else:
1222 print("Error: Invalid option!")
1223 print_usage()
1224 exit()
1225
1226