Class: HQMF::Generator
- Inherits:
-
Object
- Object
- HQMF::Generator
- Defined in:
- lib/tpg/generation/generator.rb
Class Method Summary collapse
- .apply_field_defaults(data_criteria, time) ⇒ Object
-
.classify_entry(type) ⇒ Object
Map all patient api coded entry types from HQMF data criteria to Record sections.
-
.create_base_patient(initial_attributes = nil) ⇒ Object
Create a patient with trivial demographic information and no coded entries.
- .create_oid_dictionary(oids) ⇒ Object
-
.determine_measure_needs(measures) ⇒ Object
Takes an Array of meassures and builds a Hash keyed by NQF ID with the values being an Array of data criteria.
-
.finalize_patient(patient) ⇒ Object
Fill in any missing details that should be filled in on a patient.
-
.generate_qrda_patients(measure_needs, value_sets = nil) ⇒ Hash
Generate patients from lists of DataCriteria.
-
.parse_measure(measure_json) ⇒ Object
Parses a JSON representation of a measure from a Bonnie Bundle into an hqmf-parser ready format.
-
.select_unique_data_criteria(all_data_criteria) ⇒ Object
Select all unique data criteria from a list.
- .select_unique_oids(all_data_criteria) ⇒ Object
-
.select_valid_time_range(patient, data_criteria) ⇒ Object
Create a random time range for an entry to occur.
Class Method Details
.apply_field_defaults(data_criteria, time) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/tpg/generation/generator.rb', line 165 def self.apply_field_defaults(data_criteria, time) return nil if data_criteria.field_values.nil? # Some fields come in with no value or marked as AnyValue (i.e. any value is acceptable, there just must be one). If that's the case, we pick a default here. data_criteria.field_values.each do |name, field| if field.is_a? HQMF::AnyValue if ["ADMISSION_DATETIME", "START_DATETIME", "INCISION_DATETIME"].include? name data_criteria.field_values[name] = time.low elsif ["DISCHARGE_DATETIME", "STOP_DATETIME", "REMOVAL_DATETIME"].include? name data_criteria.field_values[name] = time.high elsif name == "REASON" # If we're not explicitly given a code (e.g. HQMF dictates there must be a reason but any is ok), we assign a random one (birth) data_criteria.field_values[name] = Coded.for_code_list("2.16.840.1.113883.3.117.1.7.1.70", "birth") elsif name == "ORDINAL" # If we're not explicitly given a code (e.g. HQMF dictates there must be a reason but any is ok), we assign it to be not principle data_criteria.field_values[name] = Coded.for_code_list("2.16.840.1.113883.3.117.2.7.1.14", "principle") end end end end |
.classify_entry(type) ⇒ Object
Map all patient api coded entry types from HQMF data criteria to Record sections.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/tpg/generation/generator.rb', line 226 def self.classify_entry(type) # The possible matches per patientAPI function can be found in hqmf-parser's README case type when :allProcedures "procedures" when :proceduresPerformed "procedures" when :procedureResults "procedures" when :laboratoryTests "vital_signs" when :allMedications "medications" when :activeDiagnoses "conditions" when :inactiveDiagnoses "conditions" when :resolvedDiagnoses "conditions" when :allProblems "conditions" when :allDevices "medical_equipment" else type.to_s end end |
.create_base_patient(initial_attributes = nil) ⇒ Object
Create a patient with trivial demographic information and no coded entries.
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/tpg/generation/generator.rb', line 45 def self.create_base_patient(initial_attributes = nil) patient = Record.new if initial_attributes.nil? patient = Randomizer.randomize_demographics(patient) else initial_attributes.each {|attribute, value| patient.send("#{attribute}=", value)} end patient end |
.create_oid_dictionary(oids) ⇒ Object
107 108 109 110 111 112 113 114 |
# File 'lib/tpg/generation/generator.rb', line 107 def self.create_oid_dictionary(oids) value_sets = [] HealthDataStandards::SVS::ValueSet.any_in(oid: oids).each do |value_set| code_sets = value_set.concepts value_sets << {"concepts" => code_sets, "oid" => value_set.oid} end value_sets end |
.determine_measure_needs(measures) ⇒ Object
Takes an Array of meassures and builds a Hash keyed by NQF ID with the values being an Array of data criteria.
190 191 192 193 194 195 196 197 |
# File 'lib/tpg/generation/generator.rb', line 190 def self.determine_measure_needs(measures) measure_needs = {} measures.each do |measure| measure_needs[measure.id] = measure.all_data_criteria end measure_needs end |
.finalize_patient(patient) ⇒ Object
Fill in any missing details that should be filled in on a patient. These include: age, gender, and first name.
61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/tpg/generation/generator.rb', line 61 def self.finalize_patient(patient) if patient.birthdate.nil? patient.birthdate = Randomizer.randomize_birthdate(patient) patient.birthdate = Time.now.to_i end if patient.gender.nil? patient.gender = "F" patient.first ||= Randomizer.randomize_first_name(patient.gender) end patient end |
.generate_qrda_patients(measure_needs, value_sets = nil) ⇒ Hash
Generate patients from lists of DataCriteria. This is originally created for QRDA Category 1 validation testing, i.e. a single patient will be generated per measure with an entry for every data criteria involved in the measure.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/tpg/generation/generator.rb', line 10 def self.generate_qrda_patients(measure_needs, value_sets=nil) return {} if measure_needs.nil? measure_patients = {} measure_needs.each do |measure, all_data_criteria| # Define a list of unique data criteria and matching value sets to create a patient for this measure. unique_data_criteria = select_unique_data_criteria(all_data_criteria) oids = select_unique_oids(all_data_criteria) value_sets = create_oid_dictionary(oids) if value_sets.nil? # Create a patient that includes an entry for every data criteria included in this measure. patient = Generator.create_base_patient unique_data_criteria.each do |data_criteria| # Ignore data criteria that are really just containers. next if data_criteria.derivation_operator.present? # Prepare and apply our parameters for modifying the patient based on the data criteria. time = select_valid_time_range(patient, data_criteria) apply_field_defaults(data_criteria, time) data_criteria.modify_patient(patient, time, value_sets) end # Add final data for the patient, e.g. that they were designed for the measure, possibly a birthdate, etc. patient.measure_ids ||= [] patient.measure_ids << measure patient.type = "qrda" measure_patients[measure] = Generator.finalize_patient(patient) end measure_patients end |
.parse_measure(measure_json) ⇒ Object
Parses a JSON representation of a measure from a Bonnie Bundle into an hqmf-parser ready format.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/tpg/generation/generator.rb', line 203 def self.parse_measure(measure_json) # HQMF Parser expects just a hash of ID => data_criteria, so translate to that format here. translated_data_criteria = {} measure_json["data_criteria"].each { |data_criteria| translated_data_criteria[data_criteria.keys.first] = data_criteria.values.first } measure_json["data_criteria"] = translated_data_criteria # HQMF::Documents have fields for hqmf_id and id, but not NQF ID. We'll store NQF_ID in ID. measure_json["id"] = measure_json["nqf_id"] measure_json["source_data_criteria"] = [] measure = HQMF::Document.from_json(measure_json) measure.all_data_criteria.each do |data_criteria| data_criteria.values ||= [] data_criteria.values << data_criteria.value if data_criteria.value && data_criteria.value.type != "ANYNonNull" end measure end |
.select_unique_data_criteria(all_data_criteria) ⇒ Object
Select all unique data criteria from a list. Category 1 validation is only checking for ability to access information so to minimize time we only want to include each kind of data once.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/tpg/generation/generator.rb', line 80 def self.select_unique_data_criteria(all_data_criteria) all_data_criteria.flatten! all_data_criteria.uniq! unique_data_criteria = [] all_data_criteria.each do |data_criteria| fields1 = data_criteria.field_values || {} index = unique_data_criteria.index {|dc| dc.code_list_id == data_criteria.code_list_id && dc.negation_code_list_id == data_criteria.negation_code_list_id && dc.status == data_criteria.status && dc.definition == data_criteria.definition} if index crit = unique_data_criteria[index] crit.field_values ||= {} crit.field_values.merge! data_criteria.field_values || {} else unique_data_criteria << data_criteria end end unique_data_criteria end |
.select_unique_oids(all_data_criteria) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/tpg/generation/generator.rb', line 120 def self.select_unique_oids(all_data_criteria) oids = [] all_data_criteria.each do |dc| oids << dc.code_list_id if dc.code_list_id.present? oids << dc.negation_code_list_id if dc.negation_code_list_id.present? oids << dc.value.code_list_id if dc.value.present? && dc.value.type == "CD" dc.field_values.each {|name, field| oids << field.code_list_id if field.present? && field.type == "CD"} if dc.field_values.present? end oids << "2.16.840.1.113883.3.117.1.7.1.70" oids << "2.16.840.1.113883.3.117.2.7.1.14" oids.flatten! oids.uniq! oids.compact end |
.select_valid_time_range(patient, data_criteria) ⇒ Object
Create a random time range for an entry to occur. It is guaranteed to be within the lifespan of the patient and will last no longer than a day.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/tpg/generation/generator.rb', line 143 def self.select_valid_time_range(patient, data_criteria) earliest_time = patient.birthdate latest_time = patient.deathdate # Make sure all ranges occur within the bounds of birth and death. If this data criteria is deciding one of those two, place this range outside of our 35 year range for entries. if data_criteria.property.present? if data_criteria.property == :birthtime earliest_time = HQMF::Randomizer.randomize_birthdate(patient) latest_time = earliest_time.advance(days: 1) elsif data_criteria.property == :expired earliest_time = Time.now latest_time = earliest_time.advance(days: 1) end end time = Randomizer.randomize_range(earliest_time, latest_time, {days: 1}) end |