#ifndef COMPONENT_INCLUDED_HH #define COMPONENT_INCLUDED_HH #include "stringutil.hh" #include "io_util.hh" #include "Table.hh" #include "rootutil.hh" //#include "ana/search/DetectorResponse.hh" #include "ana/search/DetResponse.hh" #include "ana/search/SearchEvent.hh" #include "ana/search/DataSet.hh" #include "TRandom.h" #include "TBaseClass.h" #include #include #include #include "TMath.h" #include "Math/GSLMinimizer.h" #include "Math/Minimizer.h" #include "Math/Factory.h" #include "Math/Functor.h" #include "Fit/FitConfig.h" #include "Parameter.hh" /*! A (data-taking) period */ struct Period { TTimeStamp start; TTimeStamp stop; Period( const TTimeStamp& start, const TTimeStamp& stop ) : start(start), stop(stop) {} Period( const TTimeStamp& start = TTimeStamp(2024,1,1,0,0,0) ) : start(start), stop( start.GetSec()+365*24*3600 ) {} double nsec() const { return stop.AsDouble() - start.AsDouble(); } double nyear() const { return nsec() / (365*24*3600); } bool contains( TTimeStamp& t ) const { return ( t > start) && ( t < stop ); } TTimeStamp random() const { double t1 = start.AsDouble(); double t2 = stop.AsDouble(); double t = gRandom->Uniform( t1, t2 ); return TTimeStamp( time_t( int(t) ) , (int) ( t - int(t) )*1e9 ); } }; /*! Base class for a signal-or-background component to the description of a dataset. Each Component can include as member-variable one or more Parameters. The Component class can (via ROOT RTTI) know about it's Parameters. */ struct Component { int component_id; //unique for each component unsigned ngen; //number of generated events string name; Period period; vector flavors; // all neutrino flavors this compoment will deal with vector channels; // all the channels this compoment should deal with // Declare your Parameters as members of each Component // Every component has -- presumably -- a norm(alization)... Parameter norm = { "number of events in component", 1000, 1e-5, 10000, 1 }; /* private parameters cache */ vector parameter_cache; /*! init is guarranteed to be called at least once before the first evaluation of the likelihood. This is so that the Component may do pre-computions */ virtual void init( DataSet& dset ) {} virtual void deinit() {} // reset whatever init did, so that we start with a clear event. virtual void update() =0; virtual double dN_dOmega_dlogE(SearchEvent &sev) { fatal("base dN_dOmega_dlogE called"); return 0; } virtual SearchEvent generate_event() { fatal("base class generate_event called"); } virtual void generate( DataSet &d, bool fluctuate_number_of_events = true ) { ngen = fluctuate_number_of_events? gRandom->Poisson( norm ) : norm ; for (unsigned i = 0 ; i < ngen ; i++) { auto ev = generate_event(); ev.index = d.data.size(); ev.source = component_id; if ( !ev.check_yourself_before_you_wreck_yourself() ) { print(ev.__str__() ); fatal("Component",name,"generated an invalid searchevent ") } d.data.push_back( ev ); } } virtual double Ntot() { return norm; } virtual int Ngen() { return ngen; } /*!Compute the integral over directions and energy. If things are correctly normalized, the result should be norm.value. The base class does it by stepping thourgh cos-zenith and log-energy. Derived classes (e.g. for point source) can implement more appropriate schemes. */ virtual double compute_integral() { double dcz = 0.01; double dloge = 0.01; double s = 0; for (double cz = -1; cz <= 1; cz += dcz ) { for ( double loge = 1; loge < 8 ; loge += dloge ) { static SearchEvent sev; sev.Eproxy = loge; sev.zenith = acos( cz ); sev.azimuth = 0; s += 2*pi*dN_dOmega_dlogE( sev ) * dcz * dloge; } } return s; } /*! return a list of all the parameters (members of type Parameter) of the component */ vector parameters() { vector r; for (auto dm : *(IsA()->GetListOfAllPublicDataMembers())) { if ( string(((TDataMember*) dm) -> GetTypeName ()) == "Parameter") { auto p = (Parameter *)( (char *) this + ((TDataMember *)dm)->GetOffset() ); p->name = dm->GetName(); p->component_name = ( (Component *) this)->name; r.push_back(p); } } return r; } /*! Get parameter by name */ Parameter *get_parameter(string name) { for ( auto p : parameters() ) if (p->name == name) return p; print ("no parameter with name", name); return nullptr; } /* check if parameters were updated externally and if yes, update the private cache */ bool CheckIfUpdated(){ vector public_parameters = parameters(); unsigned parsize = public_parameters.size(); if (parsize != parameter_cache.size()) { UpdateParameters(); return false; } else { for(unsigned ii = 0; ii < parsize; ii++) { if (public_parameters[ii]->value != parameter_cache[ii].value) { UpdateParameters(); return false; } } } return true; } /* update private parameters cache */ void UpdateParameters(){ parameter_cache.clear(); vector public_parameters = parameters(); for (auto paramptr : public_parameters) { parameter_cache.emplace_back(*paramptr); } } Component( string name_ = "" ) : name(name_) { static int counter = 0; counter++; component_id = counter; ngen = 0; } string __str__() const { return "Component " + string( IsA()->GetName() ) ; } Table table_parameters() { Table r("name","value","fit"); r.title = name; for (auto p : parameters() ) { r << p->name << p->value << p->fit; } return r; } void print_parameters() { cout << table_parameters() << endl; } // boilerplate -- repeat for every component virtual Component *clone() const = 0; // {fatal("base class clone called"); // return new Component(*this);} virtual ~Component() {} ClassDef( Component, 1) }; #endif