class Measure

Constants

DEFAULT_EFFECTIVE_DATE
MP_START_DATE
TYPES
TYPE_MAP

Public Class Methods

for_patient(record) click to toggle source

Find the measures matching a patient

# 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

Public Instance Methods

all_data_criteria() click to toggle source
# File lib/models/measure.rb, line 129
def all_data_criteria
  as_hqmf_model.all_data_criteria
end
as_hqmf_model() click to toggle source

Returns the hqmf-parser's ruby implementation of an HQMF document. Rebuild from population_criteria, data_criteria, and measure_period JSON

# 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) click to toggle source
# File lib/models/measure.rb, line 133
def as_javascript(population_index, check_crosswalk=false)
  options = {
    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, options)
end
calculate_complexity() click to toggle source
# 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() click to toggle source

Clear any cached JavaScript, forcing it to be generated next time it's requested

# File lib/models/measure.rb, line 70
def clear_cached_js
  self.map_fns.map! { nil }
  self.save
end
criteria_keys_by_population() click to toggle source

Return the list of all data criteria keys in this measure, indexed by population code

# 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 = {}) click to toggle source
# File lib/models/measure.rb, line 203
def data_criteria_complexity(criteria_reference, options = {})
  options.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'] || options[: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) click to toggle source

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

# 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) click to toggle source

Compute a simplified diff hash for Complexity Dashboard usage; stored within measure.latest_diff

# File lib/models/measure.rb, line 267
def diff(other)
  HQMF::Measure::LogicExtractor.get_measure_logic_diff(self,other,true)
end
extract_measure_logic() click to toggle source
# 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.message}"
  end
  self.measure_logic
end
generate_js(options = {}) click to toggle source

Generate and cache all the javascript for the measure, optionally clearing the cache first

# File lib/models/measure.rb, line 65
def generate_js(options = {})
  populations.each_with_index { |p, idx| map_fn(idx, options) }
end
map_fn(population_index, options = {}) click to toggle source

Cache the generated JS code, with optional options to manipulate cached result

# File lib/models/measure.rb, line 54
def map_fn(population_index, options = {})
  options.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
  options.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 options[:clear_db_cache]
  self.map_fns[population_index] ||= as_javascript(population_index, options[:check_crosswalk])
  save if changed? && options[:cache_result_in_db]
  self.map_fns[population_index]
end
measure_json(population_index=0,check_crosswalk=false) click to toggle source
# File lib/models/measure.rb, line 273
def measure_json(population_index=0,check_crosswalk=false)
  options = {
    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, options),
        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) click to toggle source

Measure Complexity Analysis ##############################

# 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) click to toggle source

Given a precondition, return the list of all data criteria keys referenced within

# 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() click to toggle source
# 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() click to toggle source
# File lib/models/measure.rb, line 122
def value_sets
  options = { oid: value_set_oids }
  options[:user_id] = user.id if user?
  @value_sets ||= HealthDataStandards::SVS::ValueSet.in(options)
  @value_sets
end