Class: Measure
- Inherits:
-
Object
- Object
- Measure
- Includes:
- Mongoid::Attributes::Dynamic, Mongoid::Document, Mongoid::Timestamps
- Defined in:
- lib/models/measure.rb
Constant Summary collapse
- DEFAULT_EFFECTIVE_DATE =
Time.gm(2012,12,31,23,59).to_i
- MP_START_DATE =
Time.gm(2012,1,1,0,0).to_i
- TYPES =
["ep", "eh"]
- TYPE_MAP =
{ 'problem' => 'conditions', 'encounter' => 'encounters', 'labresults' => 'results', 'procedure' => 'procedures', 'medication' => 'medications', 'rx' => 'medications', 'demographics' => 'characteristic', 'derived' => 'derived' }
Class Method Summary collapse
-
.for_patient(record) ⇒ Object
Find the measures matching a patient.
Instance Method Summary collapse
- #all_data_criteria ⇒ Object
-
#as_hqmf_model ⇒ Object
Returns the hqmf-parser’s ruby implementation of an HQMF document.
- #as_javascript(population_index, check_crosswalk = false) ⇒ Object
- #calculate_complexity ⇒ Object
-
#clear_cached_js ⇒ Object
Clear any cached JavaScript, forcing it to be generated next time it’s requested.
-
#criteria_keys_by_population ⇒ Object
Return the list of all data criteria keys in this measure, indexed by population code.
- #data_criteria_complexity(criteria_reference, options = {}) ⇒ Object
-
#data_criteria_criteria_keys(criteria_reference) ⇒ Object
Given a data criteria, return the list of all data criteria keys referenced within, either through children criteria or temporal references; this includes the passed in criteria reference.
-
#diff(other) ⇒ Object
Compute a simplified diff hash for Complexity Dashboard usage; stored within measure.latest_diff.
- #extract_measure_logic ⇒ Object
-
#generate_js(options = {}) ⇒ Object
Generate and cache all the javascript for the measure, optionally clearing the cache first.
-
#map_fn(population_index, options = {}) ⇒ Object
Cache the generated JS code, with optional options to manipulate cached result.
- #measure_json(population_index = 0, check_crosswalk = false) ⇒ Object
-
#precondition_complexity(precondition) ⇒ Object
Measure Complexity Analysis ##############################.
-
#precondition_criteria_keys(precondition) ⇒ Object
Given a precondition, return the list of all data criteria keys referenced within.
- #set_continuous_variable ⇒ Object
- #value_sets ⇒ Object
Class Method Details
.for_patient(record) ⇒ Object
Find the measures matching a patient
85 86 87 |
# File 'lib/models/measure.rb', line 85 def self.for_patient(record) where user_id: record.user_id, hqmf_set_id: { '$in' => record.measure_ids } end |
Instance Method Details
#all_data_criteria ⇒ Object
129 130 131 |
# File 'lib/models/measure.rb', line 129 def all_data_criteria as_hqmf_model.all_data_criteria end |
#as_hqmf_model ⇒ Object
Returns the hqmf-parser’s ruby implementation of an HQMF document. Rebuild from population_criteria, data_criteria, and measure_period JSON
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/models/measure.rb', line 102 def as_hqmf_model json = { "id" => self.measure_id, "title" => self.title, "description" => self.description, "population_criteria" => self.population_criteria, "data_criteria" => self.data_criteria, "source_data_criteria" => self.source_data_criteria, "measure_period" => self.measure_period, "attributes" => self.measure_attributes, "populations" => self.populations, "hqmf_id" => self.hqmf_id, "hqmf_set_id" => self.hqmf_set_id, "hqmf_version_number" => self.hqmf_version_number, "cms_id" => self.cms_id } HQMF::Document.from_json(json) end |
#as_javascript(population_index, check_crosswalk = false) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/models/measure.rb', line 133 def as_javascript(population_index, check_crosswalk=false) = { value_sets: value_sets, episode_ids: episode_ids, continuous_variable: continuous_variable, force_sources: force_sources, custom_functions: custom_functions, check_crosswalk: check_crosswalk } HQMF2JS::Generator::Execution.logic(as_hqmf_model, population_index, ) end |
#calculate_complexity ⇒ Object
233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/models/measure.rb', line 233 def calculate_complexity self.complexity = { populations: [], variables: [] } self.population_criteria.each do |name, precondition| complexity = precondition_complexity(precondition) self.complexity[:populations] << { name: name, complexity: complexity } end self.source_data_criteria.each do |reference, criteria| next unless criteria['variable'] name = criteria['description'] complexity = data_criteria_complexity(reference, calculating_variable: true) self.complexity[:variables] << { name: name, complexity: complexity } end self.complexity end |
#clear_cached_js ⇒ Object
Clear any cached JavaScript, forcing it to be generated next time it’s requested
70 71 72 73 |
# File 'lib/models/measure.rb', line 70 def clear_cached_js self.map_fns.map! { nil } self.save end |
#criteria_keys_by_population ⇒ Object
Return the list of all data criteria keys in this measure, indexed by population code
180 181 182 183 184 185 186 |
# File 'lib/models/measure.rb', line 180 def criteria_keys_by_population criteria_keys_by_population = {} population_criteria.each do |name, precondition| criteria_keys_by_population[name] = precondition_criteria_keys(precondition).reject { |ck| ck == 'MeasurePeriod' } end criteria_keys_by_population end |
#data_criteria_complexity(criteria_reference, options = {}) ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/models/measure.rb', line 203 def data_criteria_complexity(criteria_reference, = {}) .reverse_merge! calculating_variable: false # We want to calculate the number of branching paths, which we can normally do by counting leaf nodes. # This is more complicated for data criteria because, in addition to direct children, the criteria can # also have temporal references, which can themselves branch. Our approach is to calculate an initial # number of leaf nodes through looking at direct children and then seeing if any additional leaves are # added through temporal references. A temporal reference that doesn't branch doesn't add a leaf node. # Finally, this reference may be a variable, in which case we consider this a leaf node *unless* we are # explicitly calculating the complexity of the variable itself if criteria = self.data_criteria[criteria_reference] complexity = if criteria['children_criteria'].present? && (!criteria['variable'] || [:calculating_variable]) criteria['children_criteria'].map { |c| data_criteria_complexity(c) }.sum else 1 end complexity + if criteria['temporal_references'].present? criteria['temporal_references'].map { |tr| data_criteria_complexity(tr['reference']) - 1 }.sum else 0 end else 1 end end |
#data_criteria_criteria_keys(criteria_reference) ⇒ Object
Given a data criteria, return the list of all data criteria keys referenced within, either through children criteria or temporal references; this includes the passed in criteria reference
155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/models/measure.rb', line 155 def data_criteria_criteria_keys(criteria_reference) criteria_keys = [criteria_reference] if criteria = self.data_criteria[criteria_reference] if criteria['children_criteria'].present? criteria_keys.concat(criteria['children_criteria'].map { |c| data_criteria_criteria_keys(c) }.flatten) end if criteria['temporal_references'].present? criteria_keys.concat(criteria['temporal_references'].map { |tr| data_criteria_criteria_keys(tr['reference']) }.flatten) end end criteria_keys end |
#diff(other) ⇒ Object
Compute a simplified diff hash for Complexity Dashboard usage; stored within measure.latest_diff
267 268 269 |
# File 'lib/models/measure.rb', line 267 def diff(other) HQMF::Measure::LogicExtractor.get_measure_logic_diff(self,other,true) end |
#extract_measure_logic ⇒ Object
254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/models/measure.rb', line 254 def extract_measure_logic self.measure_logic = [] # There are occasional issues extracting measure logic; while we want to fix them we also don't want logic # extraction issues to hold up loading or updating a measure begin self.measure_logic.concat HQMF::Measure::LogicExtractor.new().population_logic(self) rescue => e self.measure_logic << "Error parsing measure logic: #{e.}" end self.measure_logic end |
#generate_js(options = {}) ⇒ Object
Generate and cache all the javascript for the measure, optionally clearing the cache first
65 66 67 |
# File 'lib/models/measure.rb', line 65 def generate_js( = {}) populations.each_with_index { |p, idx| map_fn(idx, ) } end |
#map_fn(population_index, options = {}) ⇒ Object
Cache the generated JS code, with optional options to manipulate cached result
54 55 56 57 58 59 60 61 62 |
# File 'lib/models/measure.rb', line 54 def map_fn(population_index, = {}) .assert_valid_keys :clear_db_cache, :cache_result_in_db, :check_crosswalk # Defaults are: don't clear the cache, do cache the result in the DB, use user specified crosswalk setting .reverse_merge! clear_db_cache: false, cache_result_in_db: true, check_crosswalk: !!self.user.try(:crosswalk_enabled) self.map_fns[population_index] = nil if [:clear_db_cache] self.map_fns[population_index] ||= as_javascript(population_index, [:check_crosswalk]) save if changed? && [:cache_result_in_db] self.map_fns[population_index] end |
#measure_json(population_index = 0, check_crosswalk = false) ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/models/measure.rb', line 273 def measure_json(population_index=0,check_crosswalk=false) = { value_sets: value_sets, episode_ids: episode_ids, continuous_variable: continuous_variable, force_sources: force_sources, custom_functions: custom_functions, check_crosswalk: check_crosswalk } population_index ||= 0 json = { id: self.hqmf_id, nqf_id: self.measure_id, hqmf_id: self.hqmf_id, hqmf_set_id: self.hqmf_set_id, hqmf_version_number: self.hqmf_version_number, cms_id: self.cms_id, name: self.title, description: self.description, type: self.type, category: self.category, map_fn: HQMF2JS::Generator::Execution.measure_js(self.as_hqmf_model, population_index, ), continuous_variable: self.continuous_variable, episode_of_care: self.episode_of_care, hqmf_document: self.as_hqmf_model.to_json } if (self.populations.count > 1) sub_ids = ('a'..'az').to_a json[:sub_id] = sub_ids[population_index] population_title = self.populations[population_index]['title'] json[:subtitle] = population_title json[:short_subtitle] = population_title end if self.continuous_variable observation = self.population_criteria[self.populations[population_index][HQMF::PopulationCriteria::OBSERV]] json[:aggregator] = observation['aggregator'] end json[:oids] = self.value_sets.map{|value_set| value_set.oid}.uniq population_ids = {} HQMF::PopulationCriteria::ALL_POPULATION_CODES.each do |type| population_key = self.populations[population_index][type] population_criteria = self.population_criteria[population_key] if (population_criteria) population_ids[type] = population_criteria['hqmf_id'] end end stratification = self['populations'][population_index]['stratification'] if stratification population_ids['stratification'] = stratification end json[:population_ids] = population_ids json end |
#precondition_complexity(precondition) ⇒ Object
Measure Complexity Analysis ##############################
190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/models/measure.rb', line 190 def precondition_complexity(precondition) # We want to calculate the number of branching paths; we can do that by simply counting the leaf nodes. # Any children of this particular node can appear either through child preconditions or by reference to a # data criteria. ASSERTION: a precondition can never both have child preconditions and a data criteria. if precondition['preconditions'] && precondition['preconditions'].size > 0 precondition['preconditions'].map { |p| precondition_complexity(p) }.sum elsif precondition['reference'] data_criteria_complexity(precondition['reference']) else 1 end end |
#precondition_criteria_keys(precondition) ⇒ Object
Given a precondition, return the list of all data criteria keys referenced within
169 170 171 172 173 174 175 176 177 |
# File 'lib/models/measure.rb', line 169 def precondition_criteria_keys(precondition) if precondition['preconditions'] && precondition['preconditions'].size > 0 precondition['preconditions'].map { |p| precondition_criteria_keys(p) }.flatten elsif precondition['reference'] data_criteria_criteria_keys(precondition['reference']) else [] end end |
#set_continuous_variable ⇒ Object
146 147 148 149 |
# File 'lib/models/measure.rb', line 146 def set_continuous_variable self.continuous_variable = populations.map {|x| x.keys}.flatten.uniq.include? HQMF::PopulationCriteria::MSRPOPL true end |
#value_sets ⇒ Object
122 123 124 125 126 127 |
# File 'lib/models/measure.rb', line 122 def value_sets = { oid: value_set_oids } [:user_id] = user.id if user? @value_sets ||= HealthDataStandards::SVS::ValueSet.in() @value_sets end |