Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dynamic risk factor mechanism #189

Merged
merged 7 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions example/France.Config.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@
"proxy": "ses",
"range": [-2.316299, 2.296689]
},
{
"name": "Carbohydrate",
"level": 0,
"proxy": "",
"range": [40.0, 400.0]
},
{
"name": "Sodium",
"level": 1,
Expand Down Expand Up @@ -91,7 +85,6 @@
"range": [13.88, 39.48983]
}
],
"dynamic_risk_factor": "",
"risk_factor_models": {
"static": "France.HLM.json",
"dynamic": "France.EBHLM.json"
Expand Down
36 changes: 4 additions & 32 deletions src/HealthGPS.Console/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,24 +210,6 @@ Configuration load_configuration(CommandOptions &options) {
}
}

if (!config.modelling.dynamic_risk_factor.empty()) {
auto found_dynamic_factor = false;
for (auto &factor : config.modelling.risk_factors) {
if (core::case_insensitive::equals(factor.name,
config.modelling.dynamic_risk_factor)) {
found_dynamic_factor = true;
break;
}
}

if (!found_dynamic_factor) {
fmt::print(
fg(fmt::color::red),
"\nInvalid configuration, dynamic risk factor: {} is not a risk factor.\n",
config.modelling.dynamic_risk_factor);
}
}

// Run-time
opt["running"]["start_time"].get_to(config.start_time);
opt["running"]["stop_time"].get_to(config.stop_time);
Expand Down Expand Up @@ -353,21 +335,11 @@ ModelInput create_model_input(core::DataTable &input_table, core::Country countr

auto mapping = std::vector<MappingEntry>();
for (auto &item : config.modelling.risk_factors) {
if (core::case_insensitive::equals(item.name, config.modelling.dynamic_risk_factor)) {
if (item.range.empty()) {
mapping.emplace_back(
MappingEntry(item.name, item.level, core::Identifier{item.proxy}, true));
} else {
auto boundary = FactorRange{item.range[0], item.range[1]};
mapping.emplace_back(MappingEntry(item.name, item.level,
core::Identifier{item.proxy}, boundary, true));
}
} else if (!item.range.empty()) {
auto boundary = FactorRange{item.range[0], item.range[1]};
mapping.emplace_back(
MappingEntry{item.name, item.level, core::Identifier{item.proxy}, boundary});
if (item.range.empty()) {
mapping.emplace_back(item.name, item.level, item.proxy);
} else {
mapping.emplace_back(MappingEntry{item.name, item.level, core::Identifier{item.proxy}});
auto boundary = FactorRange{item.range[0], item.range[1]};
mapping.emplace_back(item.name, item.level, item.proxy, boundary);
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/HealthGPS.Console/jsonparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,12 @@ void from_json(const json &j, RiskFactorInfo &p) {

void to_json(json &j, const ModellingInfo &p) {
j = json{{"risk_factors", p.risk_factors},
{"dynamic_risk_factor", p.dynamic_risk_factor},
{"risk_factor_models", p.risk_factor_models},
{"baseline_adjustments", p.baseline_adjustment}};
}

void from_json(const json &j, ModellingInfo &p) {
j.at("risk_factors").get_to(p.risk_factors);
j.at("dynamic_risk_factor").get_to(p.dynamic_risk_factor);
j.at("risk_factor_models").get_to(p.risk_factor_models);
j.at("baseline_adjustments").get_to(p.baseline_adjustment);
}
Expand Down
3 changes: 1 addition & 2 deletions src/HealthGPS.Console/poco.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ struct BaselineInfo {

struct RiskFactorInfo {
std::string name;
short level{};
int level{};
std::string proxy;
std::vector<double> range;
};

struct ModellingInfo {
std::vector<RiskFactorInfo> risk_factors;
std::string dynamic_risk_factor;
std::unordered_map<std::string, std::string> risk_factor_models;
BaselineInfo baseline_adjustment;
};
Expand Down
2 changes: 1 addition & 1 deletion src/HealthGPS.Console/riskmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct HierarchicalModelInfo {

struct VariableInfo {
std::string name;
short level{};
int level{};
std::string factor;
};

Expand Down
12 changes: 6 additions & 6 deletions src/HealthGPS.Tests/HealthGPS.Test.cpp
jamesturner246 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ namespace fs = std::filesystem;

static std::vector<hgps::MappingEntry> create_mapping_entries() {
using namespace hgps;
return std::vector<MappingEntry>{MappingEntry("Year", 0, core::Identifier::empty(), true),
MappingEntry("Gender", 0, core::Identifier{"gender"}),
MappingEntry("Age", 0, core::Identifier{"age"}),
MappingEntry("SmokingStatus", 1),
MappingEntry("AlcoholConsumption", 1),
MappingEntry("BMI", 2)};
return {MappingEntry("Year", 0, core::Identifier::empty()),
MappingEntry("Gender", 0, core::Identifier{"gender"}),
MappingEntry("Age", 0, core::Identifier{"age"}),
MappingEntry("SmokingStatus", 1),
MappingEntry("AlcoholConsumption", 1),
MappingEntry("BMI", 2)};
}

void create_test_datatable(hgps::core::DataTable &data) {
Expand Down
54 changes: 6 additions & 48 deletions src/HealthGPS.Tests/HierarchicalMapping.Test.cpp
jamesturner246 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

static std::vector<hgps::MappingEntry> create_mapping_entries() {
using namespace hgps;
return std::vector<MappingEntry>{MappingEntry("Year", 0, core::Identifier::empty(), true),
MappingEntry("Gender", 0, core::Identifier{"gender"}),
MappingEntry("Age", 0, core::Identifier{"age"}),
MappingEntry("SmokingStatus", 1),
MappingEntry("AlcoholConsumption", 1),
MappingEntry("BMI", 2)};
return {MappingEntry("Year", 0, core::Identifier::empty()),
MappingEntry("Gender", 0, core::Identifier{"gender"}),
MappingEntry("Age", 0, core::Identifier{"age"}),
MappingEntry("SmokingStatus", 1),
MappingEntry("AlcoholConsumption", 1),
MappingEntry("BMI", 2)};
}

TEST(TestHealthGPS_Mapping, CreateEmpty) {
Expand Down Expand Up @@ -73,22 +73,6 @@ TEST(TestHealthGPS_Mapping, AccessByConstInterator) {
}
}

TEST(TestHealthGPS_Mapping, CanIdentifyDynamicFactor) {
using namespace hgps;

auto entries = create_mapping_entries();
auto mapping = HierarchicalMapping(std::move(entries));
auto dynamic_factor = core::Identifier{"year"};

for (auto &entry : mapping) {
if (entry.key() == dynamic_factor) {
ASSERT_TRUE(entry.is_dynamic_factor());
} else {
ASSERT_FALSE(entry.is_dynamic_factor());
}
}
}

TEST(TestHealthGPS_Mapping, AccessAllEntries) {
using namespace hgps;

Expand Down Expand Up @@ -129,17 +113,6 @@ TEST(TestHealthGPS_Mapping, AccessSingleEntryThrowForUnknowKey) {
}
}

TEST(TestHealthGPS_Mapping, AccessEntriesWithoutDynamicFactor) {
using namespace hgps;

auto entries = create_mapping_entries();
auto exp_size = entries.size() - 1u;
auto mapping = HierarchicalMapping(std::move(entries));
auto all_entries = mapping.entries_without_dynamic();

ASSERT_EQ(exp_size, all_entries.size());
}

TEST(TestHealthGPS_Mapping, AccessAllLevelEntries) {
using namespace hgps;

Expand All @@ -154,18 +127,3 @@ TEST(TestHealthGPS_Mapping, AccessAllLevelEntries) {
ASSERT_EQ(exp_size[1], level_1_entries.size());
ASSERT_EQ(exp_size[2], level_2_entries.size());
}

TEST(TestHealthGPS_Mapping, AccessLevelEntriesWithoutDynamicFactor) {
using namespace hgps;

auto entries = create_mapping_entries();
std::vector<int> exp_size = {2, 2, 1};
auto mapping = HierarchicalMapping(std::move(entries));
auto level_0_entries = mapping.at_level_without_dynamic(0);
auto level_1_entries = mapping.at_level_without_dynamic(1);
auto level_2_entries = mapping.at_level_without_dynamic(2);

ASSERT_EQ(exp_size[0], level_0_entries.size());
ASSERT_EQ(exp_size[1], level_1_entries.size());
ASSERT_EQ(exp_size[2], level_2_entries.size());
}
3 changes: 2 additions & 1 deletion src/HealthGPS/analysis_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ void AnalysisModule::initialise_output_channels(RuntimeContext &context) {
}

channels_.push_back("count");
for (auto &factor : context.mapping().entries_without_dynamic()) {
for (auto &factor : context.mapping().entries()) {
channels_.emplace_back(factor.key().to_string());
}

Expand Down Expand Up @@ -404,4 +404,5 @@ std::unique_ptr<AnalysisModule> build_analysis_module(Repository &repository,
config.settings().age_range(),
config.run().comorbidities);
}

} // namespace hgps
11 changes: 3 additions & 8 deletions src/HealthGPS/energy_balance_hierarchical_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ void EnergyBalanceHierarchicalModel::update_risk_factors(RuntimeContext &context
continue;
}

auto current_risk_factors =
get_current_risk_factors(context.mapping(), entity, context.time_now());
auto current_risk_factors = get_current_risk_factors(context.mapping(), entity);

// Model calibrated on previous year's age
auto model_age = static_cast<int>(entity.age - 1);
Expand Down Expand Up @@ -107,15 +106,11 @@ void EnergyBalanceHierarchicalModel::update_risk_factors_exposure(

std::map<core::Identifier, double>
EnergyBalanceHierarchicalModel::get_current_risk_factors(const HierarchicalMapping &mapping,
Person &entity, int time_year) const {
Person &entity) const {
auto entity_risk_factors = std::map<core::Identifier, double>();
entity_risk_factors.emplace(InterceptKey, entity.get_risk_factor_value(InterceptKey));
for (const auto &factor : mapping) {
if (factor.is_dynamic_factor()) {
entity_risk_factors.emplace(factor.key(), time_year - 1);
} else {
entity_risk_factors.emplace(factor.key(), entity.get_risk_factor_value(factor.key()));
}
entity_risk_factors.emplace(factor.key(), entity.get_risk_factor_value(factor.key()));
}

return entity_risk_factors;
Expand Down
3 changes: 1 addition & 2 deletions src/HealthGPS/energy_balance_hierarchical_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ class EnergyBalanceHierarchicalModel final : public HierarchicalLinearModel {
const std::map<core::Identifier, FactorDynamicEquation> &equations);

std::map<core::Identifier, double> get_current_risk_factors(const HierarchicalMapping &mapping,
Person &entity,
int time_year) const;
Person &entity) const;

double sample_normal_with_boundary(Random &random, double mean, double standard_deviation,
double boundary) const;
Expand Down
6 changes: 3 additions & 3 deletions src/HealthGPS/hierarchical_model_static.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void StaticHierarchicalLinearModel::generate_risk_factors(RuntimeContext &contex
if (level_factors_cache.contains(level)) {
level_factors = level_factors_cache.at(level);
} else {
level_factors = context.mapping().at_level_without_dynamic(level);
level_factors = context.mapping().at_level(level);
level_factors_cache.emplace(level, level_factors);
}

Expand All @@ -54,7 +54,7 @@ void StaticHierarchicalLinearModel::update_risk_factors(RuntimeContext &context)
if (level_factors_cache.contains(level)) {
level_factors = level_factors_cache.at(level);
} else {
level_factors = context.mapping().at_level_without_dynamic(level);
level_factors = context.mapping().at_level(level);
level_factors_cache.emplace(level, level_factors);
}

Expand Down Expand Up @@ -96,7 +96,7 @@ void StaticHierarchicalLinearModel::generate_for_entity(RuntimeContext &context,
auto determ_risk_factors = std::map<core::Identifier, double>();
determ_risk_factors.emplace(InterceptKey, entity.get_risk_factor_value(InterceptKey));
for (const auto &item : context.mapping()) {
if (item.level() < level && !item.is_dynamic_factor()) {
if (item.level() < level) {
determ_risk_factors.emplace(item.key(),
entity.get_risk_factor_value(item.entity_key()));
}
Expand Down
41 changes: 8 additions & 33 deletions src/HealthGPS/mapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,28 @@
#include <tuple>

namespace hgps {
hgps::MappingEntry::MappingEntry(std::string name, short level, core::Identifier entity_key,
FactorRange range, bool dynamic_factor)
: name_{name}, name_key_{core::Identifier{name}}, level_{level},
entity_key_{std::move(entity_key)}, range_{range}, dynamic_factor_{dynamic_factor} {}

MappingEntry::MappingEntry(std::string name, short level, core::Identifier entity_key,
bool dynamic_factor)
: MappingEntry(name, level, entity_key, FactorRange{}, dynamic_factor) {}

MappingEntry::MappingEntry(std::string name, short level, core::Identifier entity_key,
MappingEntry::MappingEntry(std::string name, int level, core::Identifier entity_key,
FactorRange range)
: MappingEntry(name, level, entity_key, range, false) {}
: name_{name}, name_key_{core::Identifier{name}}, level_{level},
entity_key_{std::move(entity_key)}, range_{range} {}

MappingEntry::MappingEntry(std::string name, short level, core::Identifier entity_key)
: MappingEntry(name, level, entity_key, FactorRange{}, false) {}
MappingEntry::MappingEntry(std::string name, int level, core::Identifier entity_key)
: MappingEntry(name, level, entity_key, FactorRange{}) {}

MappingEntry::MappingEntry(std::string name, short level)
: MappingEntry(name, level, core::Identifier::empty(), FactorRange{}, false) {}
MappingEntry::MappingEntry(std::string name, int level)
: MappingEntry(name, level, core::Identifier::empty(), FactorRange{}) {}

const std::string &MappingEntry::name() const noexcept { return name_; }

short MappingEntry::level() const noexcept { return level_; }
int MappingEntry::level() const noexcept { return level_; }

const core::Identifier &MappingEntry::entity_key() const noexcept {
return is_entity() ? entity_key_ : name_key_;
}

bool MappingEntry::is_entity() const noexcept { return !entity_key_.is_empty(); }

bool MappingEntry::is_dynamic_factor() const noexcept { return dynamic_factor_; }

const core::Identifier &MappingEntry::key() const noexcept { return name_key_; }

const FactorRange &MappingEntry::range() const noexcept { return range_; }
Expand Down Expand Up @@ -68,14 +59,6 @@ HierarchicalMapping::HierarchicalMapping(std::vector<MappingEntry> &&mapping)

const std::vector<MappingEntry> &HierarchicalMapping::entries() const noexcept { return mapping_; }

std::vector<MappingEntry> HierarchicalMapping::entries_without_dynamic() const noexcept {
std::vector<MappingEntry> result;
std::copy_if(mapping_.begin(), mapping_.end(), std::back_inserter(result),
[](const auto &elem) { return !elem.is_dynamic_factor(); });

return result;
}

std::size_t HierarchicalMapping::size() const noexcept { return mapping_.size(); }

int HierarchicalMapping::max_level() const noexcept {
Expand Down Expand Up @@ -105,12 +88,4 @@ std::vector<MappingEntry> HierarchicalMapping::at_level(int level) const noexcep
return result;
}

std::vector<MappingEntry> HierarchicalMapping::at_level_without_dynamic(int level) const noexcept {
std::vector<MappingEntry> result;
std::copy_if(
mapping_.cbegin(), mapping_.cend(), std::back_inserter(result),
[&level](const auto &elem) { return elem.level() == level && !elem.is_dynamic_factor(); });

return result;
}
} // namespace hgps
Loading