89 : options_(options) {}
112 for (
const auto& finding : result.
findings) {
133 if (modality !=
"RTPLAN")
return false;
153 std::vector<validation_finding>& findings)
const {
165 std::vector<validation_finding>& findings)
const {
182 std::vector<validation_finding>& findings)
const {
191 if (modality !=
"RTPLAN") {
195 "Modality must be 'RTPLAN' for RT Plan, found: " + modality,
209 std::vector<validation_finding>& findings)
const {
213 "FrameOfReferenceUID", findings);
218 "PositionReferenceIndicator", findings);
224 std::vector<validation_finding>& findings)
const {
235 if (geometry !=
"PATIENT" && geometry !=
"TREATMENT_DEVICE") {
239 "Invalid RTPlanGeometry: " + geometry +
" (expected PATIENT or TREATMENT_DEVICE)",
254 if (intent !=
"CURATIVE" && intent !=
"PALLIATIVE" && intent !=
"PROPHYLACTIC" &&
255 intent !=
"VERIFICATION" && intent !=
"MACHINE_QA" && intent !=
"RESEARCH" &&
256 intent !=
"SERVICE") {
260 "Non-standard PlanIntent: " + intent,
272 "ReferencedStructureSetSequence not present - plan has no associated structures",
281 std::vector<validation_finding>& findings)
const {
286 "FractionGroupSequence", findings);
296 "NumberOfFractionsPlanned not specified in FractionGroupSequence",
305 std::vector<validation_finding>& findings)
const {
310 if (num_beams && *num_beams > 0) {
315 "BeamSequence required when NumberOfBeams > 0",
329 "TreatmentMachineName not specified",
337 if (beam_type !=
"STATIC" && beam_type !=
"DYNAMIC") {
341 "Non-standard BeamType: " + beam_type +
" (expected STATIC or DYNAMIC)",
350 if (radiation_type !=
"PHOTON" && radiation_type !=
"ELECTRON" &&
351 radiation_type !=
"NEUTRON" && radiation_type !=
"PROTON" &&
352 radiation_type !=
"ION") {
356 "Non-standard RadiationType: " + radiation_type,
366 std::vector<validation_finding>& findings)
const {
380 "SOPClassUID is not an RT Plan SOP Class: " + sop_class,
390 std::string_view
name,
391 std::vector<validation_finding>& findings)
const {
397 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
399 "RTPLAN-TYPE1-MISSING"
407 std::string(
"Type 1 attribute has empty value: ") +
418 std::string_view
name,
419 std::vector<validation_finding>& findings)
const {
425 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
427 "RTPLAN-TYPE2-MISSING"
437 : options_(options) {}
459 for (
const auto& finding : result.
findings) {
479 if (modality !=
"RTDOSE")
return false;
500 std::vector<validation_finding>& findings)
const {
512 std::vector<validation_finding>& findings)
const {
528 std::vector<validation_finding>& findings)
const {
536 if (modality !=
"RTDOSE") {
540 "Modality must be 'RTDOSE' for RT Dose, found: " + modality,
550 std::vector<validation_finding>& findings)
const {
554 "FrameOfReferenceUID", findings);
560 std::vector<validation_finding>& findings)
const {
572 if (units !=
"GY" && units !=
"RELATIVE") {
576 "Non-standard DoseUnits: " + units +
" (expected GY or RELATIVE)",
585 if (dose_type !=
"PHYSICAL" && dose_type !=
"EFFECTIVE" && dose_type !=
"ERROR") {
589 "Non-standard DoseType: " + dose_type,
598 if (summation !=
"PLAN" && summation !=
"MULTI_PLAN" && summation !=
"FRACTION" &&
599 summation !=
"BEAM" && summation !=
"BRACHY" && summation !=
"FRACTION_SESSION" &&
600 summation !=
"BEAM_SESSION" && summation !=
"BRACHY_SESSION" &&
601 summation !=
"CONTROL_POINT" && summation !=
"RECORD") {
605 "Non-standard DoseSummationType: " + summation,
616 "DoseGridScaling not present - dose values may not be properly scaled",
627 "ReferencedRTPlanSequence not present - dose has no associated plan reference",
641 std::vector<validation_finding>& findings)
const {
658 "PixelData not present - this may be a point dose or DVH-only object",
666 std::vector<validation_finding>& findings)
const {
679 "SOPClassUID is not RT Dose Storage: " + sop_class,
689 std::string_view
name,
690 std::vector<validation_finding>& findings)
const {
696 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
698 "RTDOSE-TYPE1-MISSING"
706 std::string(
"Type 1 attribute has empty value: ") +
717 std::string_view
name,
718 std::vector<validation_finding>& findings)
const {
724 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
726 "RTDOSE-TYPE2-MISSING"
733 std::vector<validation_finding>& findings)
const {
740 if (bits_allocated && bits_stored) {
741 if (*bits_stored > *bits_allocated) {
745 "BitsStored exceeds BitsAllocated",
751 if (bits_stored && high_bit) {
752 if (*high_bit != *bits_stored - 1) {
756 "HighBit should typically be BitsStored - 1",
764 if (num_frames && *num_frames > 1) {
769 "GridFrameOffsetVector recommended for multi-frame dose grids",
781 : options_(options) {}
806 for (
const auto& finding : result.
findings) {
826 if (modality !=
"RTSTRUCT")
return false;
846 std::vector<validation_finding>& findings)
const {
858 std::vector<validation_finding>& findings)
const {
874 std::vector<validation_finding>& findings)
const {
882 if (modality !=
"RTSTRUCT") {
886 "Modality must be 'RTSTRUCT' for RT Structure Set, found: " + modality,
896 std::vector<validation_finding>& findings)
const {
902 "StructureSetROISequence", findings);
917 "ReferencedFrameOfReferenceSequence not present - structures have no spatial reference",
926 std::vector<validation_finding>& findings)
const {
938 "ROIDisplayColor not present - ROIs will use default colors",
946 std::vector<validation_finding>& findings)
const {
951 "RTROIObservationsSequence", findings);
960 "RTROIInterpretedType not specified - ROI semantic meaning not defined",
969 std::vector<validation_finding>& findings)
const {
982 "SOPClassUID is not RT Structure Set Storage: " + sop_class,
992 std::string_view
name,
993 std::vector<validation_finding>& findings)
const {
999 std::string(
"Type 1 attribute missing: ") + std::string(
name) +
1001 "RTSTRUCT-TYPE1-MISSING"
1005 if (value.empty()) {
1006 findings.push_back({
1009 std::string(
"Type 1 attribute has empty value: ") +
1011 "RTSTRUCT-TYPE1-EMPTY"
1020 std::string_view
name,
1021 std::vector<validation_finding>& findings)
const {
1024 findings.push_back({
1027 std::string(
"Type 2 attribute missing: ") + std::string(
name) +
1029 "RTSTRUCT-TYPE2-MISSING"
1036 std::vector<validation_finding>& findings)
const {
1045 findings.push_back({
1048 "StructureSetROISequence present but ROIContourSequence missing - ROIs have no contours",
1059 : options_(options) {}
1063 std::string sop_class;
1072 return validator.
validate(dataset);
1077 return validator.
validate(dataset);
1082 return validator.
validate(dataset);
1089 if (modality ==
"RTPLAN") {
1091 return validator.
validate(dataset);
1093 if (modality ==
"RTDOSE") {
1095 return validator.
validate(dataset);
1097 if (modality ==
"RTSTRUCT") {
1099 return validator.
validate(dataset);
1109 "Unable to determine RT object type from SOPClassUID or Modality",
1139 return validator.
validate(dataset);
1144 return validator.
validate(dataset);
1149 return validator.
validate(dataset);
1154 return validator.
validate(dataset);
auto get_numeric(dicom_tag tag) const -> std::optional< T >
Get the numeric value of an element.
auto contains(dicom_tag tag) const noexcept -> bool
Check if the dataset contains an element with the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
auto to_string() const -> std::string
Convert to string representation.
Validator for RT Dose IODs.
void set_options(const rt_validation_options &options)
void validate_rt_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
rt_dose_iod_validator()=default
void check_type2_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
bool quick_check(const core::dicom_dataset &dataset) const
void validate_sop_common_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate(const core::dicom_dataset &dataset) const
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void validate_general_study_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
rt_validation_options options_
const rt_validation_options & options() const noexcept
void validate_frame_of_reference_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_image_pixel_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_rt_dose_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_dose_data_consistency(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_patient_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
Unified validator for all RT IODs.
validation_result validate(const core::dicom_dataset &dataset) const
Validate an RT dataset (auto-detects type)
const rt_validation_options & options() const noexcept
void set_options(const rt_validation_options &options)
rt_validation_options options_
rt_iod_validator()=default
bool quick_check(const core::dicom_dataset &dataset) const
Quick check if dataset has minimum required RT attributes.
Validator for RT Plan IODs.
void validate_rt_general_plan_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_type2_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void validate_sop_common_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_general_study_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
rt_validation_options options_
void validate_patient_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void validate_frame_of_reference_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
rt_plan_iod_validator()=default
const rt_validation_options & options() const noexcept
void validate_rt_fraction_scheme_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_rt_beams_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate(const core::dicom_dataset &dataset) const
bool quick_check(const core::dicom_dataset &dataset) const
void validate_rt_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void set_options(const rt_validation_options &options)
Validator for RT Structure Set IODs.
void validate_sop_common_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
rt_structure_set_iod_validator()=default
void set_options(const rt_validation_options &options)
void check_type1_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
rt_validation_options options_
void check_type2_attribute(const core::dicom_dataset &dataset, core::dicom_tag tag, std::string_view name, std::vector< validation_finding > &findings) const
void validate_structure_set_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_rt_series_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void check_roi_consistency(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_patient_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
bool quick_check(const core::dicom_dataset &dataset) const
void validate_roi_contour_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
void validate_general_study_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
const rt_validation_options & options() const noexcept
void validate_rt_roi_observations_module(const core::dicom_dataset &dataset, std::vector< validation_finding > &findings) const
validation_result validate(const core::dicom_dataset &dataset) const
Compile-time constants for commonly used DICOM tags.
constexpr std::string_view rt_structure_set_storage_uid
RT Structure Set Storage SOP Class UID.
constexpr std::string_view rt_ion_plan_storage_uid
RT Ion Plan Storage SOP Class UID.
constexpr std::string_view rt_dose_storage_uid
RT Dose Storage SOP Class UID.
bool is_rt_plan_sop_class(std::string_view uid) noexcept
Check if a SOP Class UID is an RT Plan type.
rt_plan_geometry
RT Plan Geometry.
rt_roi_interpreted_type
RT ROI Interpreted Type.
constexpr std::string_view rt_plan_storage_uid
RT Plan Storage SOP Class UID.
validation_result validate_rt_iod(const core::dicom_dataset &dataset)
Validate any RT dataset (auto-detects type) with default options.
bool is_valid_rt_dose_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid RT Dose.
bool is_valid_rt_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid RT object (any type)
validation_result validate_rt_plan_iod(const core::dicom_dataset &dataset)
Validate an RT Plan dataset with default options.
bool is_valid_rt_structure_set_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid RT Structure Set.
bool is_valid_rt_plan_dataset(const core::dicom_dataset &dataset)
Quick check if a dataset is a valid RT Plan.
@ warning
Non-critical - IOD may have issues.
@ info
Informational - suggestion for improvement.
@ error
Critical - IOD is non-compliant.
validation_result validate_rt_structure_set_iod(const core::dicom_dataset &dataset)
Validate an RT Structure Set dataset with default options.
validation_result validate_rt_dose_iod(const core::dicom_dataset &dataset)
Validate an RT Dose dataset with default options.
Radiation Therapy (RT) IOD Validators.
Radiation Therapy (RT) Storage SOP Classes.
Options for RT IOD validation.
bool check_type2
Check Type 2 (required, can be empty) attributes.
bool validate_rt_plan
Validate RT Plan specific attributes (beams, fractions)
bool validate_pixel_data
Validate pixel data consistency (for RT Dose and RT Image)
bool check_type1
Check Type 1 (required) attributes.
bool validate_references
Validate referenced objects (plans, images)
bool strict_mode
Strict mode - treat warnings as errors.
bool validate_rt_structure_set
Validate RT Structure Set specific attributes (ROIs, contours)
Result of IOD validation.
std::vector< validation_finding > findings
All findings during validation.
bool is_valid
Overall validation status.