<commit_before>/**
 * @file
 * @brief Implementation of Geant4 deposition module
 * @remarks Based on code from Mathieu Benoit
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "DepositionGeant4Module.hpp"

#include <limits>
#include <string>
#include <utility>

#include <G4EmParameters.hh>
#include <G4HadronicProcessStore.hh>
#include <G4LogicalVolume.hh>
#include <G4PhysListFactory.hh>
#include <G4RadioactiveDecayPhysics.hh>
#include <G4RunManager.hh>
#include <G4StepLimiterPhysics.hh>
#include <G4UImanager.hh>
#include <G4UserLimits.hh>

#include "G4FieldManager.hh"
#include "G4TransportationManager.hh"
#include "G4UniformMagField.hh"

#include "core/config/exceptions.h"
#include "core/geometry/GeometryManager.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"
#include "objects/DepositedCharge.hpp"
#include "tools/ROOT.h"
#include "tools/geant4.h"

#include "GeneratorActionG4.hpp"
#include "SensitiveDetectorActionG4.hpp"
#include "SetTrackInfoUserHookG4.hpp"

#define G4_NUM_SEEDS 10

using namespace allpix;

/**
 * Includes the particle source point to the geometry using \ref GeometryManager::addPoint.
 */
DepositionGeant4Module::DepositionGeant4Module(Configuration& config, Messenger* messenger, GeometryManager* geo_manager)
    : Module(config), messenger_(messenger), geo_manager_(geo_manager), last_event_num_(1), run_manager_g4_(nullptr) {
    // Create user limits for maximum step length in the sensor
    user_limits_ = std::make_unique<G4UserLimits>(config_.get<double>("max_step_length", Units::get(1.0, "um")));

    // Set default physics list
    config_.setDefault("physics_list", "FTFP_BERT_LIV");

    config_.setDefault("source_type", "beam");
    config_.setDefault<bool>("output_plots", false);
    config_.setDefault<int>("output_plots_scale", Units::get(100, "ke"));

    // Set alias for support of old particle source definition
    config_.setAlias("source_position", "beam_position");
    config_.setAlias("source_energy", "beam_energy");
    config_.setAlias("source_energy_spread", "beam_energy_spread");

    // Add the particle source position to the geometry
    geo_manager_->addPoint(config_.get<ROOT::Math::XYZPoint>("source_position"));
}

/**
 * Module depends on \ref GeometryBuilderGeant4Module loaded first, because it owns the pointer to the Geant4 run manager.
 */
void DepositionGeant4Module::init() {
    // Load the G4 run manager (which is owned by the geometry builder)
    run_manager_g4_ = G4RunManager::GetRunManager();
    if(run_manager_g4_ == nullptr) {
        throw ModuleError("Cannot deposit charges using Geant4 without a Geant4 geometry builder");
    }

    // Suppress all output from G4
    SUPPRESS_STREAM(G4cout);

    // Get UI manager for sending commands
    G4UImanager* ui_g4 = G4UImanager::GetUIpointer();

    // Apply optional PAI model
    if(config_.get<bool>("enable_pai", false)) {
        LOG(TRACE) << "Enabling PAI model on all detectors";
        G4EmParameters::Instance();

        for(auto& detector : geo_manager_->getDetectors()) {
            // Get logical volume
            auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
            if(logical_volume == nullptr) {
                throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
            }
            // Create region
            G4Region* region = new G4Region(detector->getName() + "_sensor_region");
            region->AddRootLogicalVolume(logical_volume.get());

            auto pai_model = config_.get<std::string>("pai_model", "pai");
            auto lcase_model = pai_model;
            std::transform(lcase_model.begin(), lcase_model.end(), lcase_model.begin(), ::tolower);
            if(lcase_model == "pai") {
                pai_model = "PAI";
            } else if(lcase_model == "paiphoton") {
                pai_model = "PAIphoton";
            } else {
                throw InvalidValueError(config_, "pai_model", "model has to be either 'pai' or 'paiphoton'");
            }

            ui_g4->ApplyCommand("/process/em/AddPAIRegion all " + region->GetName() + " " + pai_model);
        }
    }

    // Find the physics list
    G4PhysListFactory physListFactory;
    G4VModularPhysicsList* physicsList = physListFactory.GetReferencePhysList(config_.get<std::string>("physics_list"));
    if(physicsList == nullptr) {
        std::string message = "specified physics list does not exists";
        std::vector<G4String> base_lists = physListFactory.AvailablePhysLists();
        message += " (available base lists are ";
        for(auto& base_list : base_lists) {
            message += base_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += " with optional suffixes for electromagnetic lists ";
        std::vector<G4String> em_lists = physListFactory.AvailablePhysListsEM();
        for(auto& em_list : em_lists) {
            if(em_list.empty()) {
                continue;
            }
            message += em_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += ")";

        throw InvalidValueError(config_, "physics_list", message);
    } else {
        LOG(INFO) << "Using G4 physics list \"" << config_.get<std::string>("physics_list") << "\"";
    }
    // Register a step limiter (uses the user limits defined earlier)
    physicsList->RegisterPhysics(new G4StepLimiterPhysics());

    // Register radioactive decay physics lists
    physicsList->RegisterPhysics(new G4RadioactiveDecayPhysics());

    // Set the range-cut off threshold for secondary production:
    double production_cut;
    if(config_.has("range_cut")) {
        production_cut = config_.get<double>("range_cut");
        LOG(INFO) << "Setting configured G4 production cut to " << Units::display(production_cut, {"mm", "um"});
    } else {
        // Define the production cut as one fifth of the minimum size (thickness, pitch) among the detectors
        double min_size = std::numeric_limits<double>::max();
        std::string min_detector;
        for(auto& detector : geo_manager_->getDetectors()) {
            auto model = detector->getModel();
            double prev_min_size = min_size;
            min_size =
                std::min({min_size, model->getPixelSize().x(), model->getPixelSize().y(), model->getSensorSize().z()});
            if(min_size != prev_min_size) {
                min_detector = detector->getName();
            }
        }
        production_cut = min_size / 5;
        LOG(INFO) << "Setting G4 production cut to " << Units::display(production_cut, {"mm", "um"})
                  << ", derived from properties of detector \"" << min_detector << "\"";
    }
    ui_g4->ApplyCommand("/run/setCut " + std::to_string(production_cut));

    // Initialize the physics list
    LOG(TRACE) << "Initializing physics processes";
    run_manager_g4_->SetUserInitialization(physicsList);
    run_manager_g4_->InitializePhysics();

    // Initialize the full run manager to ensure correct state flags
    run_manager_g4_->Initialize();

    // Build particle generator
    LOG(TRACE) << "Constructing particle source";
    auto generator = new GeneratorActionG4(config_);
    run_manager_g4_->SetUserAction(generator);

    track_info_manager_ = std::make_unique<TrackInfoManager>();

    // User hook to store additional information at track initialization and termination as well as custom track ids
    auto userTrackIDHook = new SetTrackInfoUserHookG4(track_info_manager_.get());
    run_manager_g4_->SetUserAction(userTrackIDHook);

    if(geo_manager_->hasMagneticField()) {
        MagneticFieldType magnetic_field_type_ = geo_manager_->getMagneticFieldType();

        if(magnetic_field_type_ == MagneticFieldType::CONSTANT) {
            ROOT::Math::XYZVector b_field = geo_manager_->getMagneticField(ROOT::Math::XYZPoint(0., 0., 0.));
            G4MagneticField* magField = new G4UniformMagField(G4ThreeVector(b_field.x(), b_field.y(), b_field.z()));
            G4FieldManager* globalFieldMgr = G4TransportationManager::GetTransportationManager()->GetFieldManager();
            globalFieldMgr->SetDetectorField(magField);
            globalFieldMgr->CreateChordFinder(magField);
        } else {
            throw ModuleError("Magnetic field enabled, but not constant. This can't be handled by this module yet.");
        }
    }

    // Get the creation energy for charge (default is silicon electron hole pair energy)
    auto charge_creation_energy = config_.get<double>("charge_creation_energy", Units::get(3.64, "eV"));
    auto fano_factor = config_.get<double>("fano_factor", 0.115);

    // Loop through all detectors and set the sensitive detector action that handles the particle passage
    bool useful_deposition = false;
    for(auto& detector : geo_manager_->getDetectors()) {
        // Do not add sensitive detector for detectors that have no listeners for the deposited charges
        // FIXME Probably the MCParticle has to be checked as well
        if(!messenger_->hasReceiver(this,
                                    std::make_shared<DepositedChargeMessage>(std::vector<DepositedCharge>(), detector))) {
            LOG(INFO) << "Not depositing charges in " << detector->getName()
                      << " because there is no listener for its output";
            continue;
        }
        useful_deposition = true;

        // Get model of the sensitive device
        auto sensitive_detector_action = new SensitiveDetectorActionG4(
            this, detector, messenger_, track_info_manager_.get(), charge_creation_energy, fano_factor, getRandomSeed());
        auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
        if(logical_volume == nullptr) {
            throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
        }

        // Apply the user limits to this element
        logical_volume->SetUserLimits(user_limits_.get());

        // Add the sensitive detector action
        logical_volume->SetSensitiveDetector(sensitive_detector_action);
        sensors_.push_back(sensitive_detector_action);

        // If requested, prepare output plots
        if(config_.get<bool>("output_plots")) {
            LOG(TRACE) << "Creating output plots";

            // Plot axis are in kilo electrons - convert from framework units!
            int maximum = static_cast<int>(Units::convert(config_.get<int>("output_plots_scale"), "ke"));
            int nbins = 5 * maximum;

            // Create histograms if needed
            std::string plot_name = "deposited_charge_" + sensitive_detector_action->getName();
            charge_per_event_[sensitive_detector_action->getName()] =
                new TH1D(plot_name.c_str(), "deposited charge per event;deposited charge [ke];events", nbins, 0, maximum);
        }
    }

    if(!useful_deposition) {
        LOG(ERROR) << "Not a single listener for deposited charges, module is useless!";
    }

    // Disable verbose messages from processes
    ui_g4->ApplyCommand("/process/verbose 0");
    ui_g4->ApplyCommand("/process/em/verbose 0");
    ui_g4->ApplyCommand("/process/eLoss/verbose 0");
    G4HadronicProcessStore::Instance()->SetVerbose(0);

    // Set the random seed for Geant4 generation
    // NOTE Assumes this is the only Geant4 module using random numbers
    std::string seed_command = "/random/setSeeds ";
    for(int i = 0; i < G4_NUM_SEEDS; ++i) {
        seed_command += std::to_string(static_cast<uint32_t>(getRandomSeed() % INT_MAX));
        if(i != G4_NUM_SEEDS - 1) {
            seed_command += " ";
        }
    }
    ui_g4->ApplyCommand(seed_command);

    // Release the output stream
    RELEASE_STREAM(G4cout);
}

void DepositionGeant4Module::run(unsigned int event_num) {
    // Suppress output stream if not in debugging mode
    IFLOG(DEBUG);
    else {
        SUPPRESS_STREAM(G4cout);
    }

    // Start a single event from the beam
    LOG(TRACE) << "Enabling beam";
    run_manager_g4_->BeamOn(static_cast<int>(config_.get<unsigned int>("number_of_particles", 1)));
    last_event_num_ = event_num;

    // Release the stream (if it was suspended)
    RELEASE_STREAM(G4cout);

    track_info_manager_->createMCTracks();

    // Dispatch the necessary messages
    for(auto& sensor : sensors_) {
        sensor->dispatchMessages();

        // Fill output plots if requested:
        if(config_.get<bool>("output_plots")) {
            double charge = static_cast<double>(Units::convert(sensor->getDepositedCharge(), "ke"));
            charge_per_event_[sensor->getName()]->Fill(charge);
        }
    }

    track_info_manager_->dispatchMessage(this, messenger_);
    track_info_manager_->resetTrackInfoManager();
}

void DepositionGeant4Module::finalize() {
    size_t total_charges = 0;
    for(auto& sensor : sensors_) {
        total_charges += sensor->getTotalDepositedCharge();
    }

    if(config_.get<bool>("output_plots")) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        for(auto& plot : charge_per_event_) {
            plot.second->Write();
        }
    }

    // Print summary or warns if module did not output any charges
    if(!sensors_.empty() && total_charges > 0 && last_event_num_ > 0) {
        size_t average_charge = total_charges / sensors_.size() / last_event_num_;
        LOG(INFO) << "Deposited total of " << total_charges << " charges in " << sensors_.size() << " sensor(s) (average of "
                  << average_charge << " per sensor for every event)";
    } else {
        LOG(WARNING) << "No charges deposited";
    }
}
<commit_msg>Prepare Geant4 seeds before the SensitiveDetector to keep seed order<commit_after>/**
 * @file
 * @brief Implementation of Geant4 deposition module
 * @remarks Based on code from Mathieu Benoit
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "DepositionGeant4Module.hpp"

#include <limits>
#include <string>
#include <utility>

#include <G4EmParameters.hh>
#include <G4HadronicProcessStore.hh>
#include <G4LogicalVolume.hh>
#include <G4PhysListFactory.hh>
#include <G4RadioactiveDecayPhysics.hh>
#include <G4RunManager.hh>
#include <G4StepLimiterPhysics.hh>
#include <G4UImanager.hh>
#include <G4UserLimits.hh>

#include "G4FieldManager.hh"
#include "G4TransportationManager.hh"
#include "G4UniformMagField.hh"

#include "core/config/exceptions.h"
#include "core/geometry/GeometryManager.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"
#include "objects/DepositedCharge.hpp"
#include "tools/ROOT.h"
#include "tools/geant4.h"

#include "GeneratorActionG4.hpp"
#include "SensitiveDetectorActionG4.hpp"
#include "SetTrackInfoUserHookG4.hpp"

#define G4_NUM_SEEDS 10

using namespace allpix;

/**
 * Includes the particle source point to the geometry using \ref GeometryManager::addPoint.
 */
DepositionGeant4Module::DepositionGeant4Module(Configuration& config, Messenger* messenger, GeometryManager* geo_manager)
    : Module(config), messenger_(messenger), geo_manager_(geo_manager), last_event_num_(1), run_manager_g4_(nullptr) {
    // Create user limits for maximum step length in the sensor
    user_limits_ = std::make_unique<G4UserLimits>(config_.get<double>("max_step_length", Units::get(1.0, "um")));

    // Set default physics list
    config_.setDefault("physics_list", "FTFP_BERT_LIV");

    config_.setDefault("source_type", "beam");
    config_.setDefault<bool>("output_plots", false);
    config_.setDefault<int>("output_plots_scale", Units::get(100, "ke"));

    // Set alias for support of old particle source definition
    config_.setAlias("source_position", "beam_position");
    config_.setAlias("source_energy", "beam_energy");
    config_.setAlias("source_energy_spread", "beam_energy_spread");

    // Add the particle source position to the geometry
    geo_manager_->addPoint(config_.get<ROOT::Math::XYZPoint>("source_position"));
}

/**
 * Module depends on \ref GeometryBuilderGeant4Module loaded first, because it owns the pointer to the Geant4 run manager.
 */
void DepositionGeant4Module::init() {
    // Load the G4 run manager (which is owned by the geometry builder)
    run_manager_g4_ = G4RunManager::GetRunManager();
    if(run_manager_g4_ == nullptr) {
        throw ModuleError("Cannot deposit charges using Geant4 without a Geant4 geometry builder");
    }

    // Suppress all output from G4
    SUPPRESS_STREAM(G4cout);

    // Get UI manager for sending commands
    G4UImanager* ui_g4 = G4UImanager::GetUIpointer();

    // Apply optional PAI model
    if(config_.get<bool>("enable_pai", false)) {
        LOG(TRACE) << "Enabling PAI model on all detectors";
        G4EmParameters::Instance();

        for(auto& detector : geo_manager_->getDetectors()) {
            // Get logical volume
            auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
            if(logical_volume == nullptr) {
                throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
            }
            // Create region
            G4Region* region = new G4Region(detector->getName() + "_sensor_region");
            region->AddRootLogicalVolume(logical_volume.get());

            auto pai_model = config_.get<std::string>("pai_model", "pai");
            auto lcase_model = pai_model;
            std::transform(lcase_model.begin(), lcase_model.end(), lcase_model.begin(), ::tolower);
            if(lcase_model == "pai") {
                pai_model = "PAI";
            } else if(lcase_model == "paiphoton") {
                pai_model = "PAIphoton";
            } else {
                throw InvalidValueError(config_, "pai_model", "model has to be either 'pai' or 'paiphoton'");
            }

            ui_g4->ApplyCommand("/process/em/AddPAIRegion all " + region->GetName() + " " + pai_model);
        }
    }

    // Find the physics list
    G4PhysListFactory physListFactory;
    G4VModularPhysicsList* physicsList = physListFactory.GetReferencePhysList(config_.get<std::string>("physics_list"));
    if(physicsList == nullptr) {
        std::string message = "specified physics list does not exists";
        std::vector<G4String> base_lists = physListFactory.AvailablePhysLists();
        message += " (available base lists are ";
        for(auto& base_list : base_lists) {
            message += base_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += " with optional suffixes for electromagnetic lists ";
        std::vector<G4String> em_lists = physListFactory.AvailablePhysListsEM();
        for(auto& em_list : em_lists) {
            if(em_list.empty()) {
                continue;
            }
            message += em_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += ")";

        throw InvalidValueError(config_, "physics_list", message);
    } else {
        LOG(INFO) << "Using G4 physics list \"" << config_.get<std::string>("physics_list") << "\"";
    }
    // Register a step limiter (uses the user limits defined earlier)
    physicsList->RegisterPhysics(new G4StepLimiterPhysics());

    // Register radioactive decay physics lists
    physicsList->RegisterPhysics(new G4RadioactiveDecayPhysics());

    // Set the range-cut off threshold for secondary production:
    double production_cut;
    if(config_.has("range_cut")) {
        production_cut = config_.get<double>("range_cut");
        LOG(INFO) << "Setting configured G4 production cut to " << Units::display(production_cut, {"mm", "um"});
    } else {
        // Define the production cut as one fifth of the minimum size (thickness, pitch) among the detectors
        double min_size = std::numeric_limits<double>::max();
        std::string min_detector;
        for(auto& detector : geo_manager_->getDetectors()) {
            auto model = detector->getModel();
            double prev_min_size = min_size;
            min_size =
                std::min({min_size, model->getPixelSize().x(), model->getPixelSize().y(), model->getSensorSize().z()});
            if(min_size != prev_min_size) {
                min_detector = detector->getName();
            }
        }
        production_cut = min_size / 5;
        LOG(INFO) << "Setting G4 production cut to " << Units::display(production_cut, {"mm", "um"})
                  << ", derived from properties of detector \"" << min_detector << "\"";
    }
    ui_g4->ApplyCommand("/run/setCut " + std::to_string(production_cut));

    // Initialize the physics list
    LOG(TRACE) << "Initializing physics processes";
    run_manager_g4_->SetUserInitialization(physicsList);
    run_manager_g4_->InitializePhysics();

    // Initialize the full run manager to ensure correct state flags
    run_manager_g4_->Initialize();

    // Build particle generator
    LOG(TRACE) << "Constructing particle source";
    auto generator = new GeneratorActionG4(config_);
    run_manager_g4_->SetUserAction(generator);

    track_info_manager_ = std::make_unique<TrackInfoManager>();

    // User hook to store additional information at track initialization and termination as well as custom track ids
    auto userTrackIDHook = new SetTrackInfoUserHookG4(track_info_manager_.get());
    run_manager_g4_->SetUserAction(userTrackIDHook);

    if(geo_manager_->hasMagneticField()) {
        MagneticFieldType magnetic_field_type_ = geo_manager_->getMagneticFieldType();

        if(magnetic_field_type_ == MagneticFieldType::CONSTANT) {
            ROOT::Math::XYZVector b_field = geo_manager_->getMagneticField(ROOT::Math::XYZPoint(0., 0., 0.));
            G4MagneticField* magField = new G4UniformMagField(G4ThreeVector(b_field.x(), b_field.y(), b_field.z()));
            G4FieldManager* globalFieldMgr = G4TransportationManager::GetTransportationManager()->GetFieldManager();
            globalFieldMgr->SetDetectorField(magField);
            globalFieldMgr->CreateChordFinder(magField);
        } else {
            throw ModuleError("Magnetic field enabled, but not constant. This can't be handled by this module yet.");
        }
    }

    // Get the creation energy for charge (default is silicon electron hole pair energy)
    auto charge_creation_energy = config_.get<double>("charge_creation_energy", Units::get(3.64, "eV"));
    auto fano_factor = config_.get<double>("fano_factor", 0.115);

    // Prepare seeds for Geant4:
    // NOTE Assumes this is the only Geant4 module using random numbers
    std::string seed_command = "/random/setSeeds ";
    for(int i = 0; i < G4_NUM_SEEDS; ++i) {
        seed_command += std::to_string(static_cast<uint32_t>(getRandomSeed() % INT_MAX));
        if(i != G4_NUM_SEEDS - 1) {
            seed_command += " ";
        }
    }

    // Loop through all detectors and set the sensitive detector action that handles the particle passage
    bool useful_deposition = false;
    for(auto& detector : geo_manager_->getDetectors()) {
        // Do not add sensitive detector for detectors that have no listeners for the deposited charges
        // FIXME Probably the MCParticle has to be checked as well
        if(!messenger_->hasReceiver(this,
                                    std::make_shared<DepositedChargeMessage>(std::vector<DepositedCharge>(), detector))) {
            LOG(INFO) << "Not depositing charges in " << detector->getName()
                      << " because there is no listener for its output";
            continue;
        }
        useful_deposition = true;

        // Get model of the sensitive device
        auto sensitive_detector_action = new SensitiveDetectorActionG4(
            this, detector, messenger_, track_info_manager_.get(), charge_creation_energy, fano_factor, getRandomSeed());
        auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
        if(logical_volume == nullptr) {
            throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
        }

        // Apply the user limits to this element
        logical_volume->SetUserLimits(user_limits_.get());

        // Add the sensitive detector action
        logical_volume->SetSensitiveDetector(sensitive_detector_action);
        sensors_.push_back(sensitive_detector_action);

        // If requested, prepare output plots
        if(config_.get<bool>("output_plots")) {
            LOG(TRACE) << "Creating output plots";

            // Plot axis are in kilo electrons - convert from framework units!
            int maximum = static_cast<int>(Units::convert(config_.get<int>("output_plots_scale"), "ke"));
            int nbins = 5 * maximum;

            // Create histograms if needed
            std::string plot_name = "deposited_charge_" + sensitive_detector_action->getName();
            charge_per_event_[sensitive_detector_action->getName()] =
                new TH1D(plot_name.c_str(), "deposited charge per event;deposited charge [ke];events", nbins, 0, maximum);
        }
    }

    if(!useful_deposition) {
        LOG(ERROR) << "Not a single listener for deposited charges, module is useless!";
    }

    // Disable verbose messages from processes
    ui_g4->ApplyCommand("/process/verbose 0");
    ui_g4->ApplyCommand("/process/em/verbose 0");
    ui_g4->ApplyCommand("/process/eLoss/verbose 0");
    G4HadronicProcessStore::Instance()->SetVerbose(0);

    // Set the random seed for Geant4 generation
    ui_g4->ApplyCommand(seed_command);

    // Release the output stream
    RELEASE_STREAM(G4cout);
}

void DepositionGeant4Module::run(unsigned int event_num) {
    // Suppress output stream if not in debugging mode
    IFLOG(DEBUG);
    else {
        SUPPRESS_STREAM(G4cout);
    }

    // Start a single event from the beam
    LOG(TRACE) << "Enabling beam";
    run_manager_g4_->BeamOn(static_cast<int>(config_.get<unsigned int>("number_of_particles", 1)));
    last_event_num_ = event_num;

    // Release the stream (if it was suspended)
    RELEASE_STREAM(G4cout);

    track_info_manager_->createMCTracks();

    // Dispatch the necessary messages
    for(auto& sensor : sensors_) {
        sensor->dispatchMessages();

        // Fill output plots if requested:
        if(config_.get<bool>("output_plots")) {
            double charge = static_cast<double>(Units::convert(sensor->getDepositedCharge(), "ke"));
            charge_per_event_[sensor->getName()]->Fill(charge);
        }
    }

    track_info_manager_->dispatchMessage(this, messenger_);
    track_info_manager_->resetTrackInfoManager();
}

void DepositionGeant4Module::finalize() {
    size_t total_charges = 0;
    for(auto& sensor : sensors_) {
        total_charges += sensor->getTotalDepositedCharge();
    }

    if(config_.get<bool>("output_plots")) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        for(auto& plot : charge_per_event_) {
            plot.second->Write();
        }
    }

    // Print summary or warns if module did not output any charges
    if(!sensors_.empty() && total_charges > 0 && last_event_num_ > 0) {
        size_t average_charge = total_charges / sensors_.size() / last_event_num_;
        LOG(INFO) << "Deposited total of " << total_charges << " charges in " << sensors_.size() << " sensor(s) (average of "
                  << average_charge << " per sensor for every event)";
    } else {
        LOG(WARNING) << "No charges deposited";
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __STOUT_OS_MKTEMP_HPP__
#define __STOUT_OS_MKTEMP_HPP__

#include <stdlib.h>
#include <string.h>

#include <string>

#include <stout/error.hpp>
#include <stout/try.hpp>

#ifdef __WINDOWS__
#include <stout/windows.hpp> // To be certain we're using the right `mkstemp`.
#endif // __WINDOWS__

#include <stout/os/close.hpp>
#include <stout/os/int_fd.hpp>

namespace os {

// Creates a temporary file using the specified path template. The
// template may be any path with _6_ `Xs' appended to it, for example
// /tmp/temp.XXXXXX. The trailing `Xs' are replaced with a unique
// alphanumeric combination.
inline Try<std::string> mktemp(const std::string& path = "/tmp/XXXXXX")
{
  char* temp = new char[path.size() + 1];
  ::memcpy(temp, path.c_str(), path.size() + 1);

  int_fd fd = ::mkstemp(temp);
  if (fd < 0) {
    delete[] temp;
    return ErrnoError();
  }

  // We ignore the return value of close(). This is because users
  // calling this function are interested in the return value of
  // mkstemp(). Also an unsuccessful close() doesn't affect the file.
  os::close(fd);

  std::string result(temp);
  delete[] temp;
  return result;
}

} // namespace os {

#endif // __STOUT_OS_MKTEMP_HPP__
<commit_msg>Stout: Made `os::mktemp` fully cross-platform.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __STOUT_OS_MKTEMP_HPP__
#define __STOUT_OS_MKTEMP_HPP__

#include <stdlib.h>
#include <string.h>

#include <string>

#include <stout/error.hpp>
#include <stout/path.hpp>
#include <stout/try.hpp>

#ifdef __WINDOWS__
#include <stout/windows.hpp> // To be certain we're using the right `mkstemp`.
#endif // __WINDOWS__

#include <stout/os/close.hpp>
#include <stout/os/int_fd.hpp>
#include <stout/os/temp.hpp>

namespace os {

// Creates a temporary file using the specified path template. The
// template may be any path with _6_ `Xs' appended to it, for example
// /tmp/temp.XXXXXX. The trailing `Xs' are replaced with a unique
// alphanumeric combination.
inline Try<std::string> mktemp(
    const std::string& path = path::join(os::temp(), "XXXXXX"))
{
  char* temp = new char[path.size() + 1];
  ::memcpy(temp, path.c_str(), path.size() + 1);

  int_fd fd = ::mkstemp(temp);
  if (fd < 0) {
    delete[] temp;
    return ErrnoError();
  }

  // We ignore the return value of close(). This is because users
  // calling this function are interested in the return value of
  // mkstemp(). Also an unsuccessful close() doesn't affect the file.
  os::close(fd);

  std::string result(temp);
  delete[] temp;
  return result;
}

} // namespace os {

#endif // __STOUT_OS_MKTEMP_HPP__
<|endoftext|>


<commit_before>#include "estimation/jet/jet_ekf.hh"
#include "estimation/jet/jet_rk4.hh"

#include "sophus.hh"

namespace estimation {
namespace jet_filter {

struct FiducialMeasurement {
  int fiducial_id = -1;
  SE3 fiducial_pose;
};

State dynamics(const State& x, const double h) {
  const Parameters z = {};
  return rk4_integrate(x, z, h);
}

class JetFilter {
  using Update = FilterStateUpdate<State>;
  using JetFilterState = FilterState<State>;

 public:
  JetFilter() : ekf_(dynamics) {
    const auto error_model = [](const State& x, const AccelMeasurement& z) -> jcc::Vec3 {
      const jcc::Vec3 g(0.0, 0.0, -9.81);
      const SE3 vehicle_from_sensor;

      const jcc::Vec3 expected_a_mpss = observe_accel(x.T_body_from_world, x.eps_dot,
                                                      x.eps_ddot, vehicle_from_sensor, g);
      const jcc::Vec3 error = expected_a_mpss - z.observed_acceleration;

      return error;
    };
    const ImuModel accel_model(error_model);
    // using ObservationFunction =
    // std::function<Update(const JetFilterState&, const AccelMeasurement&)>;
    imu_id_ = ekf_.add_model(accel_model);

    // fiducial_id_ = ekf_.add_model(fiducial_model);
  }

  void measure_imu(const AccelMeasurement& meas, const TimePoint& t) {
    ekf_.measure(meas, t, imu_id_);
  }

  // void measure_fiducial(const FiducialMeasurement& meas) {
  // ekf_.measure(meas, fiducial_id_);
  // }

  void free_run() {
    xp_.P.setZero();
    xp_ = ekf_.service_all_measurements(xp_);
  }

 private:
  void observe_imu() const;
  void observe_fiducial() const;

  // void handle(int i) {
  //   switch (i) {
  //     case 0:
  //       const FilterStateUpdate update = observe_imu(x, imu_measurements_.top());
  //       imu_measurements_.pop();
  //       break;
  //     case 1:
  //       const FilterStateUpdate update =
  //           observe_fiducial(x, fiducial_measurements_.top());
  //       fiducial_measurements_.pop();
  //       break;
  //   }
  // }

 private:
  JetEkf ekf_;

  JetFilterState xp_;

  int imu_id_ = -1;
  int fiducial_id_ = -1;
};

void go() {
  const jcc::Vec3 g(0.0, 0.0, 0.0);
  const SO3 r_vehicle_from_sensor;
  const jcc::Vec3 t_vehicle_from_sensor = jcc::Vec3(0.0, 0.0, 1.0);
  const SE3 vehicle_from_sensor = SE3(r_vehicle_from_sensor, t_vehicle_from_sensor);

  State x;
  // x.eps_dot = VecNd<6>::Ones();
  x.eps_dot[0] = 1.0;
  x.eps_dot[3] = 0.0;
  x.eps_dot[4] = 0.0;
  x.eps_dot[5] = 1.0;

  x.eps_ddot[2] = 0.0;
  x.eps_ddot[5] = 0.0;

  const auto res =
      observe_accel(x.T_body_from_world, x.eps_dot, x.eps_ddot, vehicle_from_sensor, g);
  std::cout << res.transpose() << std::endl;
  // JetFilter jf;
  //   AccelMeasurement meas;
  //   TimePoint start_time = {};
  //   for (int k = 0; k < 10; ++k) {
  //     const TimePoint obs_time = to_duration(k * 0.1) + start_time;
  //     jf.measure_imu(meas, obs_time);
  //   }
  //   jf.free_run();
}

}  // namespace jet_filter
}  // namespace estimation

int main() {
  estimation::jet_filter::go();
}<commit_msg>Allow access to filter state in jet filter<commit_after>#include "estimation/jet/jet_ekf.hh"
#include "estimation/jet/jet_rk4.hh"

#include "sophus.hh"

namespace estimation {
namespace jet_filter {

struct FiducialMeasurement {
  int fiducial_id = -1;
  SE3 fiducial_pose;
};

Parameters get_parameters() {
  const jcc::Vec3 g(0.0, 0.0, 0.0);
  const SE3 vehicle_from_sensor;
  Parameters p;
  p.T_sensor_from_body = vehicle_from_sensor;
  return p;
}

State dynamics(const State& x, const double h) {
  const Parameters p = get_parameters();
  return rk4_integrate(x, p, h);
}

jcc::Vec3 accel_error_model(const State& x, const AccelMeasurement& z) {
  const Parameters p = get_parameters();
  const jcc::Vec3 expected_a_mpss = observe_accel(x, p);
  const jcc::Vec3 error = z.observed_acceleration - expected_a_mpss;
  return error;
}

class JetFilter {
  using Update = FilterStateUpdate<State>;
  using JetFilterState = FilterState<State>;

 public:
  JetFilter(const JetFilterState& xp0) : xp_(xp0), ekf_(dynamics) {
    const ImuModel accel_model(accel_error_model);
    imu_id_ = ekf_.add_model(accel_model);

    // fiducial_id_ = ekf_.add_model(fiducial_model);
  }

  void measure_imu(const AccelMeasurement& meas, const TimePoint& t) {
    ekf_.measure(meas, t, imu_id_);
  }

  // void measure_fiducial(const FiducialMeasurement& meas) {
  // ekf_.measure(meas, fiducial_id_);
  // }

  void free_run() {
    xp_ = ekf_.service_all_measurements(xp_);
  }

  const JetFilterState& state() const {
    return xp_;
  }

 private:
  void observe_imu() const;
  void observe_fiducial() const;

 private:
  JetFilterState xp_;
  JetEkf ekf_;

  int imu_id_ = -1;
  int fiducial_id_ = -1;
};

void go() {
  // const Parameters p = get_parameters();
  // const SO3 r_vehicle_from_sensor;
  // const jcc::Vec3 t_vehicle_from_sensor = jcc::Vec3(0.0, 0.0, 1.0);
  // const SE3 vehicle_from_sensor = SE3(r_vehicle_from_sensor, t_vehicle_from_sensor);

  // State x;
  // x.eps_ddot[1] = 1.0;
  //

  FilterState<State> xp0;
  xp0.P.setIdentity();
  xp0.x.eps_ddot[0] = -0.9;

  JetFilter jf(xp0);
  AccelMeasurement meas;
  meas.observed_acceleration[0] = 2.0;

  // return;

  TimePoint start_time = {};
  for (int k = 0; k < 10; ++k) {
    const TimePoint obs_time = to_duration(k * 0.5) + start_time;
    jf.measure_imu(meas, obs_time);
    jf.free_run();

    const auto xp = jf.state();

    std::cout << "Modelled Error: " << accel_error_model(xp.x, meas).transpose()
              << std::endl;
    const auto res = observe_accel(xp.x, get_parameters());
    std::cout << "Expected Accel: " << res.transpose() << std::endl;
  }
}

}  // namespace jet_filter
}  // namespace estimation

int main() {
  estimation::jet_filter::go();
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 *
 * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "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 THE COPYRIGHT
 * OWNER OR CONTRIBUTORS 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.
 */

#include "config.h"

#include "core/inspector/WorkerInspectorController.h"

#include "InspectorBackendDispatcher.h"
#include "InspectorFrontend.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/InspectorConsoleAgent.h"
#include "core/inspector/InspectorFrontendChannel.h"
#include "core/inspector/InspectorHeapProfilerAgent.h"
#include "core/inspector/InspectorProfilerAgent.h"
#include "core/inspector/InspectorState.h"
#include "core/inspector/InspectorStateClient.h"
#include "core/inspector/InspectorTimelineAgent.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/inspector/WorkerConsoleAgent.h"
#include "core/inspector/WorkerDebuggerAgent.h"
#include "core/inspector/WorkerRuntimeAgent.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerReportingProxy.h"
#include "core/workers/WorkerThread.h"
#include "wtf/PassOwnPtr.h"

namespace WebCore {

namespace {

class PageInspectorProxy : public InspectorFrontendChannel {
    WTF_MAKE_FAST_ALLOCATED;
public:
    explicit PageInspectorProxy(WorkerGlobalScope* workerGlobalScope) : m_workerGlobalScope(workerGlobalScope) { }
    virtual ~PageInspectorProxy() { }
private:
    virtual bool sendMessageToFrontend(const String& message)
    {
        m_workerGlobalScope->thread()->workerReportingProxy().postMessageToPageInspector(message);
        return true;
    }
    WorkerGlobalScope* m_workerGlobalScope;
};

class WorkerStateClient : public InspectorStateClient {
    WTF_MAKE_FAST_ALLOCATED;
public:
    WorkerStateClient(WorkerGlobalScope* context) : m_workerGlobalScope(context) { }
    virtual ~WorkerStateClient() { }

private:
    virtual void updateInspectorStateCookie(const String& cookie)
    {
        m_workerGlobalScope->thread()->workerReportingProxy().updateInspectorStateCookie(cookie);
    }

    WorkerGlobalScope* m_workerGlobalScope;
};

}

WorkerInspectorController::WorkerInspectorController(WorkerGlobalScope* workerGlobalScope)
    : m_workerGlobalScope(workerGlobalScope)
    , m_stateClient(adoptPtr(new WorkerStateClient(workerGlobalScope)))
    , m_state(adoptPtr(new InspectorCompositeState(m_stateClient.get())))
    , m_instrumentingAgents(InstrumentingAgents::create())
    , m_injectedScriptManager(InjectedScriptManager::createForWorker())
    , m_debugServer(adoptPtr(new WorkerScriptDebugServer(workerGlobalScope, WorkerDebuggerAgent::debuggerTaskMode)))
{
    m_agents.append(WorkerRuntimeAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), m_debugServer.get(), workerGlobalScope));

    OwnPtr<InspectorTimelineAgent> timelineAgent = InspectorTimelineAgent::create(m_instrumentingAgents.get(), 0, 0, 0, 0, m_state.get(), InspectorTimelineAgent::WorkerInspector, 0);
    OwnPtr<InspectorConsoleAgent> consoleAgent = WorkerConsoleAgent::create(m_instrumentingAgents.get(), timelineAgent.get(), m_state.get(), m_injectedScriptManager.get());
    m_agents.append(WorkerDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_debugServer.get(), workerGlobalScope, m_injectedScriptManager.get()));

    m_agents.append(InspectorProfilerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), 0));
    m_agents.append(InspectorHeapProfilerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get()));
    m_agents.append(timelineAgent.release());
    m_agents.append(consoleAgent.release());

    m_injectedScriptManager->injectedScriptHost()->init(m_instrumentingAgents.get(), m_debugServer.get());
}

WorkerInspectorController::~WorkerInspectorController()
{
    m_instrumentingAgents->reset();
    disconnectFrontend();
}

void WorkerInspectorController::connectFrontend()
{
    ASSERT(!m_frontend);
    m_state->unmute();
    m_frontendChannel = adoptPtr(new PageInspectorProxy(m_workerGlobalScope));
    m_frontend = adoptPtr(new InspectorFrontend(m_frontendChannel.get()));
    m_backendDispatcher = InspectorBackendDispatcher::create(m_frontendChannel.get());
    m_agents.registerInDispatcher(m_backendDispatcher.get());
    m_agents.setFrontend(m_frontend.get());
}

void WorkerInspectorController::disconnectFrontend()
{
    if (!m_frontend)
        return;
    m_backendDispatcher->clearFrontend();
    m_backendDispatcher.clear();
    // Destroying agents would change the state, but we don't want that.
    // Pre-disconnect state will be used to restore inspector agents.
    m_state->mute();
    m_agents.clearFrontend();
    m_frontend.clear();
    m_frontendChannel.clear();
}

void WorkerInspectorController::restoreInspectorStateFromCookie(const String& inspectorCookie)
{
    ASSERT(!m_frontend);
    connectFrontend();
    m_state->loadFromCookie(inspectorCookie);

    m_agents.restore();
}

void WorkerInspectorController::dispatchMessageFromFrontend(const String& message)
{
    if (m_backendDispatcher)
        m_backendDispatcher->dispatch(message);
}

void WorkerInspectorController::resume()
{
    if (WorkerRuntimeAgent* runtimeAgent = m_instrumentingAgents->workerRuntimeAgent()) {
        ErrorString unused;
        runtimeAgent->run(&unused);
    }
}

}
<commit_msg>Inline consoleAgent variable in WorkerInspectorController constructor<commit_after>/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 *
 * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "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 THE COPYRIGHT
 * OWNER OR CONTRIBUTORS 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.
 */

#include "config.h"

#include "core/inspector/WorkerInspectorController.h"

#include "InspectorBackendDispatcher.h"
#include "InspectorFrontend.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/InspectorConsoleAgent.h"
#include "core/inspector/InspectorFrontendChannel.h"
#include "core/inspector/InspectorHeapProfilerAgent.h"
#include "core/inspector/InspectorProfilerAgent.h"
#include "core/inspector/InspectorState.h"
#include "core/inspector/InspectorStateClient.h"
#include "core/inspector/InspectorTimelineAgent.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/inspector/WorkerConsoleAgent.h"
#include "core/inspector/WorkerDebuggerAgent.h"
#include "core/inspector/WorkerRuntimeAgent.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerReportingProxy.h"
#include "core/workers/WorkerThread.h"
#include "wtf/PassOwnPtr.h"

namespace WebCore {

namespace {

class PageInspectorProxy : public InspectorFrontendChannel {
    WTF_MAKE_FAST_ALLOCATED;
public:
    explicit PageInspectorProxy(WorkerGlobalScope* workerGlobalScope) : m_workerGlobalScope(workerGlobalScope) { }
    virtual ~PageInspectorProxy() { }
private:
    virtual bool sendMessageToFrontend(const String& message)
    {
        m_workerGlobalScope->thread()->workerReportingProxy().postMessageToPageInspector(message);
        return true;
    }
    WorkerGlobalScope* m_workerGlobalScope;
};

class WorkerStateClient : public InspectorStateClient {
    WTF_MAKE_FAST_ALLOCATED;
public:
    WorkerStateClient(WorkerGlobalScope* context) : m_workerGlobalScope(context) { }
    virtual ~WorkerStateClient() { }

private:
    virtual void updateInspectorStateCookie(const String& cookie)
    {
        m_workerGlobalScope->thread()->workerReportingProxy().updateInspectorStateCookie(cookie);
    }

    WorkerGlobalScope* m_workerGlobalScope;
};

}

WorkerInspectorController::WorkerInspectorController(WorkerGlobalScope* workerGlobalScope)
    : m_workerGlobalScope(workerGlobalScope)
    , m_stateClient(adoptPtr(new WorkerStateClient(workerGlobalScope)))
    , m_state(adoptPtr(new InspectorCompositeState(m_stateClient.get())))
    , m_instrumentingAgents(InstrumentingAgents::create())
    , m_injectedScriptManager(InjectedScriptManager::createForWorker())
    , m_debugServer(adoptPtr(new WorkerScriptDebugServer(workerGlobalScope, WorkerDebuggerAgent::debuggerTaskMode)))
{
    m_agents.append(WorkerRuntimeAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), m_debugServer.get(), workerGlobalScope));

    OwnPtr<InspectorTimelineAgent> timelineAgent = InspectorTimelineAgent::create(m_instrumentingAgents.get(), 0, 0, 0, 0, m_state.get(), InspectorTimelineAgent::WorkerInspector, 0);
    m_agents.append(WorkerDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_debugServer.get(), workerGlobalScope, m_injectedScriptManager.get()));

    m_agents.append(InspectorProfilerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), 0));
    m_agents.append(InspectorHeapProfilerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get()));
    m_agents.append(WorkerConsoleAgent::create(m_instrumentingAgents.get(), timelineAgent.get(), m_state.get(), m_injectedScriptManager.get()));
    m_agents.append(timelineAgent.release());

    m_injectedScriptManager->injectedScriptHost()->init(m_instrumentingAgents.get(), m_debugServer.get());
}

WorkerInspectorController::~WorkerInspectorController()
{
    m_instrumentingAgents->reset();
    disconnectFrontend();
}

void WorkerInspectorController::connectFrontend()
{
    ASSERT(!m_frontend);
    m_state->unmute();
    m_frontendChannel = adoptPtr(new PageInspectorProxy(m_workerGlobalScope));
    m_frontend = adoptPtr(new InspectorFrontend(m_frontendChannel.get()));
    m_backendDispatcher = InspectorBackendDispatcher::create(m_frontendChannel.get());
    m_agents.registerInDispatcher(m_backendDispatcher.get());
    m_agents.setFrontend(m_frontend.get());
}

void WorkerInspectorController::disconnectFrontend()
{
    if (!m_frontend)
        return;
    m_backendDispatcher->clearFrontend();
    m_backendDispatcher.clear();
    // Destroying agents would change the state, but we don't want that.
    // Pre-disconnect state will be used to restore inspector agents.
    m_state->mute();
    m_agents.clearFrontend();
    m_frontend.clear();
    m_frontendChannel.clear();
}

void WorkerInspectorController::restoreInspectorStateFromCookie(const String& inspectorCookie)
{
    ASSERT(!m_frontend);
    connectFrontend();
    m_state->loadFromCookie(inspectorCookie);

    m_agents.restore();
}

void WorkerInspectorController::dispatchMessageFromFrontend(const String& message)
{
    if (m_backendDispatcher)
        m_backendDispatcher->dispatch(message);
}

void WorkerInspectorController::resume()
{
    if (WorkerRuntimeAgent* runtimeAgent = m_instrumentingAgents->workerRuntimeAgent()) {
        ErrorString unused;
        runtimeAgent->run(&unused);
    }
}

}
<|endoftext|>


<commit_before>// Copyright 2015 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <QSettings>
#include <QGuiApplication>
#include <QQuickView>
#include <QCommandLineParser>
#include <QDir>

#ifdef Q_OS_WIN
#include <Windows.h>
#endif

#include "MapQuickView.h"
#include "FeatureLayerSelection.h"
#include "ArcGISRuntimeEnvironment.h"

using namespace Esri::ArcGISRuntime;

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

#ifdef Q_OS_WIN
    // Force usage of OpenGL ES through ANGLE on Windows
    QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif

    // Register the map view for QML
    qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
    qmlRegisterType<FeatureLayerSelection>("Esri.Samples", 1, 0, "FeatureLayerSelectionSample");

    // Intialize application view
    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);

    // Add the import Path
    view.engine()->addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml"));

    // Set the source
    view.setSource(QUrl("qrc:/Samples/Features/FeatureLayerSelection/FeatureLayerSelection.qml"));

    view.show();

    return app.exec();
}

<commit_msg>add missing include<commit_after>// Copyright 2015 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <QSettings>
#include <QGuiApplication>
#include <QQuickView>
#include <QCommandLineParser>
#include <QDir>

#ifdef Q_OS_WIN
#include <Windows.h>
#endif

#include "MapQuickView.h"
#include "FeatureLayerSelection.h"
#include "ArcGISRuntimeEnvironment.h"
#include <QQmlEngine>

using namespace Esri::ArcGISRuntime;

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

#ifdef Q_OS_WIN
    // Force usage of OpenGL ES through ANGLE on Windows
    QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif

    // Register the map view for QML
    qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
    qmlRegisterType<FeatureLayerSelection>("Esri.Samples", 1, 0, "FeatureLayerSelectionSample");

    // Intialize application view
    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);

    // Add the import Path
    view.engine()->addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml"));

    // Set the source
    view.setSource(QUrl("qrc:/Samples/Features/FeatureLayerSelection/FeatureLayerSelection.qml"));

    view.show();

    return app.exec();
}

<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_MULTIPLY_LOG_HPP
#define STAN_MATH_REV_FUN_MULTIPLY_LOG_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/fun/log.hpp>
#include <stan/math/rev/fun/elt_multiply.hpp>
#include <stan/math/rev/fun/multiply.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/multiply_log.hpp>
#include <stan/math/prim/fun/is_any_nan.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
class multiply_log_vv_vari : public op_vv_vari {
 public:
  multiply_log_vv_vari(vari* avi, vari* bvi)
      : op_vv_vari(multiply_log(avi->val_, bvi->val_), avi, bvi) {}
  void chain() {
    using std::log;
    if (unlikely(is_any_nan(avi_->val_, bvi_->val_))) {
      avi_->adj_ = NOT_A_NUMBER;
      bvi_->adj_ = NOT_A_NUMBER;
    } else {
      avi_->adj_ += adj_ * log(bvi_->val_);
      bvi_->adj_ += adj_ * avi_->val_ / bvi_->val_;
    }
  }
};
class multiply_log_vd_vari : public op_vd_vari {
 public:
  multiply_log_vd_vari(vari* avi, double b)
      : op_vd_vari(multiply_log(avi->val_, b), avi, b) {}
  void chain() {
    using std::log;
    if (unlikely(is_any_nan(avi_->val_, bd_))) {
      avi_->adj_ = NOT_A_NUMBER;
    } else {
      avi_->adj_ += adj_ * log(bd_);
    }
  }
};
class multiply_log_dv_vari : public op_dv_vari {
 public:
  multiply_log_dv_vari(double a, vari* bvi)
      : op_dv_vari(multiply_log(a, bvi->val_), a, bvi) {}
  void chain() { bvi_->adj_ += adj_ * ad_ / bvi_->val_; }
};
}  // namespace internal

/**
 * Return the value of a*log(b).
 *
 * When both a and b are 0, the value returned is 0.
 * The partial derivative with respect to a is log(b).
 * The partial derivative with respect to b is a/b.
 *
 * @param a First variable.
 * @param b Second variable.
 * @return Value of a*log(b)
 */
inline var multiply_log(const var& a, const var& b) {
  return var(new internal::multiply_log_vv_vari(a.vi_, b.vi_));
}
/**
 * Return the value of a*log(b).
 *
 * When both a and b are 0, the value returned is 0.
 * The partial derivative with respect to a is log(b).
 *
 * @param a First variable.
 * @param b Second scalar.
 * @return Value of a*log(b)
 */
inline var multiply_log(const var& a, double b) {
  return var(new internal::multiply_log_vd_vari(a.vi_, b));
}
/**
 * Return the value of a*log(b).
 *
 * When both a and b are 0, the value returned is 0.
 * The partial derivative with respect to b is a/b.
 *
 * @param a First scalar.
 * @param b Second variable.
 * @return Value of a*log(b)
 */
inline var multiply_log(double a, const var& b) {
  if (a == 1.0) {
    return log(b);
  }
  return var(new internal::multiply_log_dv_vari(a, b.vi_));
}

/**
 * Return the elementwise product `a * log(b)`.
 *
 * Both `T1` and `T2` are matrices, and one of `T1` or `T2` must be a
 * `var_value`
 *
 * @tparam T1 Type of first argument
 * @tparam T2 Type of second argument
 * @param a First argument
 * @param b Second argument
 * @return elementwise product of `a` and `log(b)`
 */
template <typename T1, typename T2, require_all_matrix_t<T1, T2>* = nullptr,
          require_any_var_matrix_t<T1, T2>* = nullptr>
inline auto multiply_log(const T1& a, const T2& b) {
  if (!is_constant<T1>::value && !is_constant<T2>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(
        (arena_a.val().array() * arena_b.val().array().log()).matrix(),
        [arena_a, arena_b](const auto& res) mutable {
          arena_a.adj().array()
              += res.adj().array() * arena_b.val().array().log();
          arena_b.adj().array() += res.adj().array() * arena_a.val().array()
                                   / arena_b.val().array();
        });
  } else if (!is_constant<T1>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;
    auto arena_b_log = to_arena(value_of(b).array().log());

    return make_callback_var((arena_a.val().array() * arena_b_log).matrix(),
                             [arena_a, arena_b_log](const auto& res) mutable {
                               arena_a.adj().array()
                                   += res.adj().array() * arena_b_log;
                             });
  } else {
    auto arena_a = to_arena(value_of(a));
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(
        (arena_a.array() * arena_b.val().array().log()).matrix(),
        [arena_a, arena_b](const auto& res) mutable {
          arena_b.adj().array()
              += res.adj().array() * arena_a.array() / arena_b.val().array();
        });
  }
}

/**
 * Return the product `a * log(b)`.
 *
 * @tparam T1 Type of matrix argument
 * @tparam T2 Type of scalar argument
 * @param a Matrix argument
 * @param b Scalar argument
 * @return Product of `a` and `log(b)`
 */
template <typename T1, typename T2, require_var_matrix_t<T1>* = nullptr,
          require_stan_scalar_t<T2>* = nullptr>
inline auto multiply_log(const T1& a, const T2& b) {
  using std::log;

  if (!is_constant<T1>::value && !is_constant<T2>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;
    var arena_b = b;

    return make_callback_var(
        arena_a.val() * log(arena_b.val()),
        [arena_a, arena_b](const auto& res) mutable {
          arena_a.adj() += res.adj() * log(arena_b.val());
          arena_b.adj()
              += (res.adj().array() * arena_a.val().array() / arena_b.val())
                     .sum();
        });
  } else if (!is_constant<T1>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;

    return make_callback_var(arena_a.val() * log(value_of(b)),
                             [arena_a, b](const auto& res) mutable {
                               arena_a.adj() += res.adj() * log(value_of(b));
                             });
  } else {
    arena_t<promote_scalar_t<double, T1>> arena_a = value_of(a);
    var arena_b = b;

    return make_callback_var(
        arena_a * log(arena_b.val()),
        [arena_a, arena_b](const auto& res) mutable {
          arena_b.adj()
              += (res.adj().array() * arena_a.array() / arena_b.val()).sum();
        });
  }
}

/**
 * Return the product `a * log(b)`.
 *
 * @tparam T1 Type of scalar argument
 * @tparam T2 Type of matrix argument
 * @param a Scalar argument
 * @param b Matrix argument
 * @return Product of `a` and `log(b)`
 */
template <typename T1, typename T2, require_stan_scalar_t<T1>* = nullptr,
          require_var_matrix_t<T2>* = nullptr>
inline auto multiply_log(const T1& a, const T2& b) {
  if (!is_constant<T1>::value && !is_constant<T2>::value) {
    var arena_a = a;
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(
        (arena_a.val() * arena_b.val().array().log()).matrix(),
        [arena_a, arena_b](const auto& res) mutable {
          arena_a.adj()
              += (res.adj().array() * arena_b.val().array().log()).sum();
          arena_b.adj().array()
              += res.adj().array() * arena_a.val() / arena_b.val().array();
        });
  } else if (!is_constant<T1>::value) {
    var arena_a = a;
    auto arena_b_log = to_arena(value_of(b).array().log());

    return make_callback_var((arena_a.val() * arena_b_log).matrix(),
                             [arena_a, arena_b_log](const auto& res) mutable {
                               arena_a.adj()
                                   += (res.adj().array() * arena_b_log).sum();
                             });
  } else {
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(
        (value_of(a) * arena_b.val().array().log()).matrix(),
        [a, arena_b](const auto& res) mutable {
          arena_b.adj().array()
              += res.adj().array() * value_of(a) / arena_b.val().array();
        });
  }
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Added checks back to `multiply_log` (Issue #2101)<commit_after>#ifndef STAN_MATH_REV_FUN_MULTIPLY_LOG_HPP
#define STAN_MATH_REV_FUN_MULTIPLY_LOG_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/fun/log.hpp>
#include <stan/math/rev/fun/elt_multiply.hpp>
#include <stan/math/rev/fun/multiply.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/multiply_log.hpp>
#include <stan/math/prim/fun/is_any_nan.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
class multiply_log_vv_vari : public op_vv_vari {
 public:
  multiply_log_vv_vari(vari* avi, vari* bvi)
      : op_vv_vari(multiply_log(avi->val_, bvi->val_), avi, bvi) {}
  void chain() {
    using std::log;
    if (unlikely(is_any_nan(avi_->val_, bvi_->val_))) {
      avi_->adj_ = NOT_A_NUMBER;
      bvi_->adj_ = NOT_A_NUMBER;
    } else {
      avi_->adj_ += adj_ * log(bvi_->val_);
      if (bvi_->val_ == 0.0 && avi_->val_ == 0) {
        bvi_->adj_ += adj_ * INFTY;
      } else {
        bvi_->adj_ += adj_ * avi_->val_ / bvi_->val_;
      }
    }
  }
};
class multiply_log_vd_vari : public op_vd_vari {
 public:
  multiply_log_vd_vari(vari* avi, double b)
      : op_vd_vari(multiply_log(avi->val_, b), avi, b) {}
  void chain() {
    using std::log;
    if (unlikely(is_any_nan(avi_->val_, bd_))) {
      avi_->adj_ = NOT_A_NUMBER;
    } else {
      avi_->adj_ += adj_ * log(bd_);
    }
  }
};
class multiply_log_dv_vari : public op_dv_vari {
 public:
  multiply_log_dv_vari(double a, vari* bvi)
      : op_dv_vari(multiply_log(a, bvi->val_), a, bvi) {}
  void chain() {
    if (bvi_->val_ == 0.0 && ad_ == 0.0) {
      bvi_->adj_ += adj_ * INFTY;
    } else {
      bvi_->adj_ += adj_ * ad_ / bvi_->val_;
    }
  }
};
}  // namespace internal

/**
 * Return the value of a*log(b).
 *
 * When both a and b are 0, the value returned is 0.
 * The partial derivative with respect to a is log(b).
 * The partial derivative with respect to b is a/b.
 *
 * @param a First variable.
 * @param b Second variable.
 * @return Value of a*log(b)
 */
inline var multiply_log(const var& a, const var& b) {
  return var(new internal::multiply_log_vv_vari(a.vi_, b.vi_));
}
/**
 * Return the value of a*log(b).
 *
 * When both a and b are 0, the value returned is 0.
 * The partial derivative with respect to a is log(b).
 *
 * @param a First variable.
 * @param b Second scalar.
 * @return Value of a*log(b)
 */
inline var multiply_log(const var& a, double b) {
  return var(new internal::multiply_log_vd_vari(a.vi_, b));
}
/**
 * Return the value of a*log(b).
 *
 * When both a and b are 0, the value returned is 0.
 * The partial derivative with respect to b is a/b.
 *
 * @param a First scalar.
 * @param b Second variable.
 * @return Value of a*log(b)
 */
inline var multiply_log(double a, const var& b) {
  if (a == 1.0) {
    return log(b);
  }
  return var(new internal::multiply_log_dv_vari(a, b.vi_));
}

/**
 * Return the elementwise product `a * log(b)`.
 *
 * Both `T1` and `T2` are matrices, and one of `T1` or `T2` must be a
 * `var_value`
 *
 * @tparam T1 Type of first argument
 * @tparam T2 Type of second argument
 * @param a First argument
 * @param b Second argument
 * @return elementwise product of `a` and `log(b)`
 */
template <typename T1, typename T2, require_all_matrix_t<T1, T2>* = nullptr,
          require_any_var_matrix_t<T1, T2>* = nullptr>
inline auto multiply_log(const T1& a, const T2& b) {
  check_matching_dims("multiply_log", "a", a, "b", b);
  if (!is_constant<T1>::value && !is_constant<T2>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(multiply_log(arena_a.val(), arena_b.val()),
			     [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val().coeff(i, j), arena_b.val().coeff(i, j)))) {
				     arena_a.adj().coeffRef(i, j) = NOT_A_NUMBER;
				     arena_b.adj().coeffRef(i, j) = NOT_A_NUMBER;
				   } else {
				     arena_a.adj().coeffRef(i, j) += res.adj().coeff(i, j) * log(arena_b.val().coeff(i, j));
				     if (arena_b.val().coeff(i, j) == 0.0 && arena_a.val().coeff(i, j) == 0) {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * INFTY;
				     } else {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * arena_a.val().coeff(i, j) / arena_b.val().coeff(i, j);
				     }
				   }
				 }
			       }
			     });
  } else if (!is_constant<T1>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;
    auto arena_b = to_arena(value_of(b));

    return make_callback_var(multiply_log(arena_a.val(), arena_b),
                             [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val().coeff(i, j), arena_b.coeff(i, j)))) {
				     arena_a.adj().coeffRef(i, j) = NOT_A_NUMBER;
				   } else {
				     arena_a.adj().coeffRef(i, j) += res.adj().coeff(i, j) * log(arena_b.coeff(i, j));
				   }
				 }
			       }
                             });
  } else {
    auto arena_a = to_arena(value_of(a));
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(multiply_log(arena_a, arena_b.val()),
			     [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val().coeff(i, j), arena_b.val().coeff(i, j)))) {
				     arena_b.adj().coeffRef(i, j) = NOT_A_NUMBER;
				   } else {
				     if (arena_b.val().coeff(i, j) == 0.0 && arena_a.val().coeff(i, j) == 0) {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * INFTY;
				     } else {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * arena_a.coeff(i, j) / arena_b.val().coeff(i, j);
				     }
				   }
				 }
			       }
			     });
  }
}

/**
 * Return the product `a * log(b)`.
 *
 * @tparam T1 Type of matrix argument
 * @tparam T2 Type of scalar argument
 * @param a Matrix argument
 * @param b Scalar argument
 * @return Product of `a` and `log(b)`
 */
template <typename T1, typename T2, require_var_matrix_t<T1>* = nullptr,
          require_stan_scalar_t<T2>* = nullptr>
inline auto multiply_log(const T1& a, const T2& b) {
  using std::log;

  if (!is_constant<T1>::value && !is_constant<T2>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;
    var arena_b = b;

    return make_callback_var(multiply_log(arena_a.val(), arena_b.val()),
        [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val().coeff(i, j), arena_b.val()))) {
				     arena_a.adj().coeffRef(i, j) = NOT_A_NUMBER;
				     arena_b.adj() = NOT_A_NUMBER;
				   } else {
				     arena_a.adj().coeffRef(i, j) += res.adj().coeff(i, j) * log(arena_b.val());
				     if (arena_b.val() == 0.0 && arena_a.val().coeff(i, j) == 0) {
				       arena_b.adj() += res.adj().coeff(i, j) * INFTY;
				     } else {
				       arena_b.adj() += res.adj().coeff(i, j) * arena_a.val().coeff(i, j) / arena_b.val();
				     }
				   }
				 }
			       }
        });
  } else if (!is_constant<T1>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_a = a;

    return make_callback_var(multiply_log(arena_a.val(), value_of(b)),
                             [arena_a, b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val().coeff(i, j), value_of(b)))) {
				     arena_a.adj().coeffRef(i, j) = NOT_A_NUMBER;
				   } else {
				     arena_a.adj().coeffRef(i, j) += res.adj().coeff(i, j) * log(value_of(b));
				   }
				 }
			       }
                             });
  } else {
    arena_t<promote_scalar_t<double, T1>> arena_a = value_of(a);
    var arena_b = b;

    return make_callback_var(multiply_log(arena_a, arena_b.val()),
        [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val().coeff(i, j), arena_b.val()))) {
				     arena_b.adj() = NOT_A_NUMBER;
				   } else {
				     if (arena_b.val() == 0.0 && arena_a.val().coeff(i, j) == 0) {
				       arena_b.adj() += res.adj().coeff(i, j) * INFTY;
				     } else {
				       arena_b.adj() += res.adj().coeff(i, j) * arena_a.val().coeff(i, j) / arena_b.val();
				     }
				   }
				 }
			       }
        });
  }
}

/**
 * Return the product `a * log(b)`.
 *
 * @tparam T1 Type of scalar argument
 * @tparam T2 Type of matrix argument
 * @param a Scalar argument
 * @param b Matrix argument
 * @return Product of `a` and `log(b)`
 */
template <typename T1, typename T2, require_stan_scalar_t<T1>* = nullptr,
          require_var_matrix_t<T2>* = nullptr>
inline auto multiply_log(const T1& a, const T2& b) {
  if (!is_constant<T1>::value && !is_constant<T2>::value) {
    var arena_a = a;
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(multiply_log(arena_a.val(), arena_b.val()),
        [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val(), arena_b.val().coeff(i, j)))) {
				     arena_a.adj() = NOT_A_NUMBER;
				     arena_b.adj().coeffRef(i, j) = NOT_A_NUMBER;
				   } else {
				     arena_a.adj() += res.adj().coeff(i, j) * log(arena_b.val().coeff(i, j));
				     if (arena_b.val().coeff(i, j) == 0.0 && arena_a.val() == 0) {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * INFTY;
				     } else {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * arena_a.val() / arena_b.val().coeff(i, j);
				     }
				   }
				 }
			       }
        });
  } else if (!is_constant<T1>::value) {
    var arena_a = a;
    auto arena_b = to_arena(value_of(b));

    return make_callback_var(multiply_log(arena_a.val(), arena_b),
                             [arena_a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(arena_a.val(), arena_b.val().coeff(i, j)))) {
				     arena_a.adj() = NOT_A_NUMBER;
				   } else {
				     arena_a.adj() += res.adj().coeff(i, j) * log(arena_b.val().coeff(i, j));
				   }
				 }
			       }
			     });
  } else {
    arena_t<promote_scalar_t<var, T2>> arena_b = b;

    return make_callback_var(multiply_log(value_of(a), arena_b.val()),
        [a, arena_b](const auto& res) mutable {
			       for(Eigen::Index j = 0; j < res.adj().cols(); ++j) {
				 for(Eigen::Index i = 0; i < res.adj().rows(); ++i) {
				   if (unlikely(is_any_nan(value_of(a), arena_b.val().coeff(i, j)))) {
				     arena_b.adj().coeffRef(i, j) = NOT_A_NUMBER;
				   } else {
				     if (arena_b.val().coeff(i, j) == 0.0 && value_of(a) == 0) {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * INFTY;
				     } else {
				       arena_b.adj().coeffRef(i, j) += res.adj().coeff(i, j) * value_of(a) / arena_b.val().coeff(i, j);
				     }
				   }
				 }
			       }
        });
  }
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>