<commit_before>// -*- mode: c++; coding: utf-8 -*-
/*! @file tissue.cpp
    @brief Implementation of Tissue class
*/
#include "tissue.hpp"

#include <sfmt.hpp>
#include <wtl/prandom.hpp>
#include <wtl/iostr.hpp>
#include <wtl/debug.hpp>
#include <wtl/math.hpp>
#include <wtl/numeric.hpp>
#include <wtl/algorithm.hpp>
#include <wtl/genetic.hpp>

#include <boost/program_options.hpp>

#include <iostream>
#include <sstream>

namespace tumopp {

unsigned int Tissue::DIMENSIONS_;
std::string Tissue::COORDINATE_;
std::string Tissue::LOCAL_DENSITY_EFFECT_;
std::string Tissue::DISPLACEMENT_PATH_;
double Tissue::SIGMA_E_;
size_t Tissue::INITIAL_SIZE_;
size_t Tissue::RECORDING_EARLY_GROWTH_;
size_t Tissue::MUTATION_TIMING_;

//! Program options
/*! @ingroup params
    @return Program options description

    Command line option | Symbol         | Variable
    ------------------- | -------------- | -------------------------------
    `-D,--dimensions`   | -              | Tissue::DIMENSIONS_
    `-C,--coord`        | -              | Tissue::COORDINATE_
    `-L,--local`        | \f$E_2\f$      | Tissue::LOCAL_DENSITY_EFFECT_
    `-P,--path`         | -              | Tissue::DISPLACEMENT_PATH_
    `-g,--peripheral`   | \f$\sigma_E\f$ | Tissue::SIGMA_E_
    `-O,--origin`       | \f$N_0\f$      | Tissue::INITIAL_SIZE_
    `-R,--record`       | -              | Tissue::RECORDING_EARLY_GROWTH_
    `-U,--mutate`       | \f$N_\mu\f$    | Tissue::MUTATION_TIMING_
*/
boost::program_options::options_description Tissue::opt_description() {
    namespace po = boost::program_options;
    po::options_description desc{"Tissue"};
    desc.add_options()
        ("dimensions,D", po::value(&DIMENSIONS_)->default_value(3))
        ("coord,C", po::value(&COORDINATE_)->default_value("moore"))
        ("local,L", po::value(&LOCAL_DENSITY_EFFECT_)->default_value("const"))
        ("path,P", po::value(&DISPLACEMENT_PATH_)->default_value("default"))
        ("peripheral,g", po::value(&SIGMA_E_)->default_value(std::numeric_limits<double>::infinity()))
        ("origin,O", po::value(&INITIAL_SIZE_)->default_value(1))
        ("record,R", po::value(&RECORDING_EARLY_GROWTH_)->default_value(0))
        ("mutate,U", po::value(&MUTATION_TIMING_)->default_value(std::numeric_limits<size_t>::max()))
    ;
    return desc;
}

void Tissue::init() {HERE;
    tumor_.clear();
    queue_.clear();
    time_ = 0.0;
    id_tail_ = 0;
    (specimens_ = wtl::make_oss()) << header();
    (snapshots_ = wtl::make_oss()) << header();
    (drivers_ = wtl::make_oss()) << "id\ttype\tcoef\n";
    init_coord();
    init_insert_function();
    const auto initial_coords = coord_func_->sphere(INITIAL_SIZE_);
    const auto origin = std::make_shared<Cell>(initial_coords[0], ++id_tail_);
    tumor_.insert(origin);
    queue_push(origin);
    while (tumor_.size() < INITIAL_SIZE_) {
        for (const auto& mother: tumor_) {
            const auto daughter = std::make_shared<Cell>(*mother);
            mother->set_time_of_death(0.0);
            write(specimens_, *mother);
            mother->set_time_of_birth(0.0, ++id_tail_);
            daughter->set_time_of_birth(0.0, ++id_tail_);
            daughter->set_coord(initial_coords[tumor_.size()]);
            tumor_.insert(daughter);
            queue_push(daughter);
            if (tumor_.size() >= INITIAL_SIZE_) break;
        }
    }
    write(snapshots_);
}

void Tissue::init_coord() {HERE;
    std::unordered_map<std::string, std::unique_ptr<Coord>> swtch;
    swtch["neumann"] = std::make_unique<Neumann>(DIMENSIONS_);
    swtch["moore"] = std::make_unique<Moore>(DIMENSIONS_);
    swtch["hex"] = std::make_unique<Hexagonal>(DIMENSIONS_);
    try {
        coord_func_ = std::move(swtch.at(COORDINATE_));
    } catch (std::exception& e) {
        std::ostringstream oss;
        oss << std::endl << FILE_LINE_PRETTY
            << "\nInvalid value for -C (" << COORDINATE_ << "); choose from "
            << wtl::keys(swtch);
        throw std::runtime_error(oss.str());
    }
}

bool Tissue::grow(const size_t max_size, const double plateau_time) {HERE;
    init();
    bool success = false;
    double time_stopped = 0.0;
    const size_t max_time = static_cast<size_t>(std::log2(max_size) * 100);
    size_t i = 0;
    while (true) {
        if (tumor_.size() >= max_size && time_stopped == 0.0) {
            // only the first time that tumor_.size() has reached max_size
            success = true;
            time_stopped = time_;
            queue_.clear();
            for (auto& p: tumor_) {
                p->increase_death_rate();
                queue_push(p);
            }
        }
        if ((++i % 256U) == 0U) {DCERR("\r" << tumor_.size());}
        auto it = queue_.begin();
        time_ = it->first;
        if (time_stopped > 0.0 && time_ - time_stopped > plateau_time) {break;}
        if (time_ > max_time) {success = true; break;}
        const auto mother = it->second;
        queue_.erase(it);
        if (mother->next_event() == Event::birth) {
            const auto daughter = std::make_shared<Cell>(*mother);
            if (insert(daughter)) {
                mother->set_time_of_death(time_);
                write(specimens_, *mother);
                mother->set_time_of_death(0.0);
                mother->set_time_of_birth(time_, ++id_tail_);
                daughter->set_time_of_birth(time_, ++id_tail_);
                drivers_ << mother->mutate();
                drivers_ << daughter->mutate();
                if (tumor_.size() > MUTATION_TIMING_) {  // once
                    MUTATION_TIMING_ = std::numeric_limits<size_t>::max();
                    drivers_ << daughter->force_mutate();
                }
                queue_push(mother);
                queue_push(daughter);
            } else {
                queue_push(mother);
                continue;  // skip write()
            }
        } else if (mother->next_event() == Event::death) {
            mother->set_time_of_death(time_);
            write(specimens_, *mother);
            tumor_.erase(mother);
            if (tumor_.empty()) break;
        } else {
            migrate(mother);
            queue_push(mother);
        }
        if (tumor_.size() < RECORDING_EARLY_GROWTH_) {
            write(snapshots_);
        } else {
            RECORDING_EARLY_GROWTH_ = 0;  // prevent restart by cell death
        }
    }
    DCERR(std::endl);
    write(specimens_);
    return success;
}

void Tissue::queue_push(const std::shared_ptr<Cell>& x) {
    double dt = x->delta_time(positional_value(x->coord()));<commit_msg>Print correct tumor_.size() in the end<commit_after>// -*- mode: c++; coding: utf-8 -*-
/*! @file tissue.cpp
    @brief Implementation of Tissue class
*/
#include "tissue.hpp"

#include <sfmt.hpp>
#include <wtl/prandom.hpp>
#include <wtl/iostr.hpp>
#include <wtl/debug.hpp>
#include <wtl/math.hpp>
#include <wtl/numeric.hpp>
#include <wtl/algorithm.hpp>
#include <wtl/genetic.hpp>

#include <boost/program_options.hpp>

#include <iostream>
#include <sstream>

namespace tumopp {

unsigned int Tissue::DIMENSIONS_;
std::string Tissue::COORDINATE_;
std::string Tissue::LOCAL_DENSITY_EFFECT_;
std::string Tissue::DISPLACEMENT_PATH_;
double Tissue::SIGMA_E_;
size_t Tissue::INITIAL_SIZE_;
size_t Tissue::RECORDING_EARLY_GROWTH_;
size_t Tissue::MUTATION_TIMING_;

//! Program options
/*! @ingroup params
    @return Program options description

    Command line option | Symbol         | Variable
    ------------------- | -------------- | -------------------------------
    `-D,--dimensions`   | -              | Tissue::DIMENSIONS_
    `-C,--coord`        | -              | Tissue::COORDINATE_
    `-L,--local`        | \f$E_2\f$      | Tissue::LOCAL_DENSITY_EFFECT_
    `-P,--path`         | -              | Tissue::DISPLACEMENT_PATH_
    `-g,--peripheral`   | \f$\sigma_E\f$ | Tissue::SIGMA_E_
    `-O,--origin`       | \f$N_0\f$      | Tissue::INITIAL_SIZE_
    `-R,--record`       | -              | Tissue::RECORDING_EARLY_GROWTH_
    `-U,--mutate`       | \f$N_\mu\f$    | Tissue::MUTATION_TIMING_
*/
boost::program_options::options_description Tissue::opt_description() {
    namespace po = boost::program_options;
    po::options_description desc{"Tissue"};
    desc.add_options()
        ("dimensions,D", po::value(&DIMENSIONS_)->default_value(3))
        ("coord,C", po::value(&COORDINATE_)->default_value("moore"))
        ("local,L", po::value(&LOCAL_DENSITY_EFFECT_)->default_value("const"))
        ("path,P", po::value(&DISPLACEMENT_PATH_)->default_value("default"))
        ("peripheral,g", po::value(&SIGMA_E_)->default_value(std::numeric_limits<double>::infinity()))
        ("origin,O", po::value(&INITIAL_SIZE_)->default_value(1))
        ("record,R", po::value(&RECORDING_EARLY_GROWTH_)->default_value(0))
        ("mutate,U", po::value(&MUTATION_TIMING_)->default_value(std::numeric_limits<size_t>::max()))
    ;
    return desc;
}

void Tissue::init() {HERE;
    tumor_.clear();
    queue_.clear();
    time_ = 0.0;
    id_tail_ = 0;
    (specimens_ = wtl::make_oss()) << header();
    (snapshots_ = wtl::make_oss()) << header();
    (drivers_ = wtl::make_oss()) << "id\ttype\tcoef\n";
    init_coord();
    init_insert_function();
    const auto initial_coords = coord_func_->sphere(INITIAL_SIZE_);
    const auto origin = std::make_shared<Cell>(initial_coords[0], ++id_tail_);
    tumor_.insert(origin);
    queue_push(origin);
    while (tumor_.size() < INITIAL_SIZE_) {
        for (const auto& mother: tumor_) {
            const auto daughter = std::make_shared<Cell>(*mother);
            mother->set_time_of_death(0.0);
            write(specimens_, *mother);
            mother->set_time_of_birth(0.0, ++id_tail_);
            daughter->set_time_of_birth(0.0, ++id_tail_);
            daughter->set_coord(initial_coords[tumor_.size()]);
            tumor_.insert(daughter);
            queue_push(daughter);
            if (tumor_.size() >= INITIAL_SIZE_) break;
        }
    }
    write(snapshots_);
}

void Tissue::init_coord() {HERE;
    std::unordered_map<std::string, std::unique_ptr<Coord>> swtch;
    swtch["neumann"] = std::make_unique<Neumann>(DIMENSIONS_);
    swtch["moore"] = std::make_unique<Moore>(DIMENSIONS_);
    swtch["hex"] = std::make_unique<Hexagonal>(DIMENSIONS_);
    try {
        coord_func_ = std::move(swtch.at(COORDINATE_));
    } catch (std::exception& e) {
        std::ostringstream oss;
        oss << std::endl << FILE_LINE_PRETTY
            << "\nInvalid value for -C (" << COORDINATE_ << "); choose from "
            << wtl::keys(swtch);
        throw std::runtime_error(oss.str());
    }
}

bool Tissue::grow(const size_t max_size, const double plateau_time) {HERE;
    init();
    bool success = false;
    double time_stopped = 0.0;
    const size_t max_time = static_cast<size_t>(std::log2(max_size) * 100);
    size_t i = 0;
    while (true) {
        if (tumor_.size() >= max_size && time_stopped == 0.0) {
            // only the first time that tumor_.size() has reached max_size
            success = true;
            time_stopped = time_;
            queue_.clear();
            for (auto& p: tumor_) {
                p->increase_death_rate();
                queue_push(p);
            }
        }
        if ((++i % 256U) == 0U) {DCERR("\r" << tumor_.size());}
        auto it = queue_.begin();
        time_ = it->first;
        if (time_stopped > 0.0 && time_ - time_stopped > plateau_time) {break;}
        if (time_ > max_time) {success = true; break;}
        const auto mother = it->second;
        queue_.erase(it);
        if (mother->next_event() == Event::birth) {
            const auto daughter = std::make_shared<Cell>(*mother);
            if (insert(daughter)) {
                mother->set_time_of_death(time_);
                write(specimens_, *mother);
                mother->set_time_of_death(0.0);
                mother->set_time_of_birth(time_, ++id_tail_);
                daughter->set_time_of_birth(time_, ++id_tail_);
                drivers_ << mother->mutate();
                drivers_ << daughter->mutate();
                if (tumor_.size() > MUTATION_TIMING_) {  // once
                    MUTATION_TIMING_ = std::numeric_limits<size_t>::max();
                    drivers_ << daughter->force_mutate();
                }
                queue_push(mother);
                queue_push(daughter);
            } else {
                queue_push(mother);
                continue;  // skip write()
            }
        } else if (mother->next_event() == Event::death) {
            mother->set_time_of_death(time_);
            write(specimens_, *mother);
            tumor_.erase(mother);
            if (tumor_.empty()) break;
        } else {
            migrate(mother);
            queue_push(mother);
        }
        if (tumor_.size() < RECORDING_EARLY_GROWTH_) {
            write(snapshots_);
        } else {
            RECORDING_EARLY_GROWTH_ = 0;  // prevent restart by cell death
        }
    }
    DCERR("\r" << tumor_.size() << std::endl);
    write(specimens_);
    return success;
}

void Tissue::queue_push(const std::shared_ptr<Cell>& x) {
    double dt = x->delta_time(positional_value(x->coord()));
{'fraction_non_alphanumeric': 0.1638191714544905, 'fraction_numerical': 0.005140610825521621, 'mean_word_length': 2.4694466299501703, 'pattern_counts': {'":': 0, '<': 111, '<?xml version=': 0, '>': 119, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3547654', 'n_tokens_mistral': 4509, 'n_tokens_neox': 4296, 'n_words': 720}