chemicalml 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +7 -1
- data/.rubocop.yml +23 -0
- data/CLAUDE.md +95 -40
- data/README.adoc +154 -26
- data/TODO.align/36-molecular-convention-coverage.md +46 -0
- data/TODO.align/37-compchem-convention-coverage.md +55 -0
- data/TODO.align/38-dictionary-convention-coverage.md +34 -0
- data/TODO.align/39-unit-dictionary-convention-coverage.md +33 -0
- data/TODO.align/40-unit-type-dictionary-convention-coverage.md +28 -0
- data/TODO.align/41-expand-canonical-model-layer.md +43 -0
- data/TODO.align/42-translator-wire-new-models.md +31 -0
- data/TODO.align/43-dictionary-model-no-to-h.md +39 -0
- data/TODO.align/44-schema3-only-and-schema24-module.md +44 -0
- data/TODO.align/45-documentation-and-final-verification.md +23 -0
- data/TODO.align/46-lattice-vector-content.md +24 -0
- data/TODO.align/47-molecule-crystal-spectra-property-lists.md +23 -0
- data/TODO.align/48-model-list-and-module-lists.md +21 -0
- data/TODO.align/49-more-chemistry-models.md +34 -0
- data/TODO.align/50-validation-report.md +29 -0
- data/TODO.align/51-convention-auto-detection.md +30 -0
- data/TODO.align/52-schema24-legacy-elements.md +28 -0
- data/TODO.align/53-round-trip-integration-specs.md +30 -0
- data/TODO.align/54-document-versioned-parser-shim.md +38 -0
- data/TODO.align/55-molecule-missing-attributes.md +20 -0
- data/TODO.align/56-geometry-models.md +24 -0
- data/TODO.align/57-compchem-models.md +26 -0
- data/TODO.align/58-remaining-models.md +24 -0
- data/TODO.align/59-wire-new-models-translator.md +18 -0
- data/TODO.align/60-docs-and-final-verification.md +19 -0
- data/TODO.align/61-parallel-array-attrs.md +54 -0
- data/TODO.align/62-per-element-attribute-gaps.md +49 -0
- data/TODO.align/63-universal-children-mixin.md +42 -0
- data/TODO.align/64-per-element-child-gaps.md +81 -0
- data/TODO.align/65-simple-unit-convention.md +40 -0
- data/TODO.align/66-schema24-legacy-children.md +32 -0
- data/TODO.align/67-final-verification.md +32 -0
- data/TODO.align/68-detection-coverage.md +33 -0
- data/TODO.align/69-json-yaml-roundtrip.md +27 -0
- data/TODO.align/70-iterative-walker.md +40 -0
- data/TODO.align/71-violation-value.md +25 -0
- data/TODO.align/72-close-child-gaps.md +66 -0
- data/TODO.align/73-schema24-parse-limitation.md +64 -0
- data/TODO.align/74-final-verification-round18.md +15 -0
- data/TODO.align/75-key-value-mappings.md +43 -0
- data/TODO.align/76-schema24-workaround.md +57 -0
- data/TODO.align/77-convention-coverage-matrix.md +31 -0
- data/TODO.align/78-fixture-audit.md +23 -0
- data/TODO.align/79-final-verification-round19.md +15 -0
- data/TODO.align/80-xsd-enum-constants.md +35 -0
- data/TODO.align/81-enum-validation-constraints.md +29 -0
- data/TODO.align/82-reference-resolver.md +33 -0
- data/TODO.align/83-toml-roundtrip.md +20 -0
- data/TODO.align/84-final-verification-round21.md +16 -0
- data/TODO.align/85-bond-distinct-atoms.md +25 -0
- data/TODO.align/86-references-should-resolve.md +20 -0
- data/TODO.align/87-cli-utility.md +26 -0
- data/TODO.align/88-diverse-fixtures.md +26 -0
- data/TODO.align/89-final-verification-round22.md +15 -0
- data/TODO.align/90-bond-stereo-completeness.md +31 -0
- data/TODO.align/91-atomparity-distinct.md +21 -0
- data/TODO.align/92-unit-dictionary-completeness.md +28 -0
- data/TODO.align/93-yard-docs.md +23 -0
- data/TODO.align/94-final-verification-round23.md +15 -0
- data/TODO.align/README.round17.md +28 -0
- data/TODO.align/README.round18.md +37 -0
- data/TODO.align/README.round19.md +40 -0
- data/TODO.align/README.round20.md +49 -0
- data/TODO.align/README.round21.md +35 -0
- data/TODO.align/README.round22.md +48 -0
- data/TODO.align/README.round23.md +46 -0
- data/TODO.align/README.round24.md +53 -0
- data/TODO.align/README.round25.md +66 -0
- data/TODO.align/README.round26.md +55 -0
- data/TODO.align/README.round27.md +51 -0
- data/TODO.align/README.round28.md +61 -0
- data/TODO.align/README.round29.md +64 -0
- data/TODO.align/README.round30.md +50 -0
- data/TODO.align/README.round31.md +54 -0
- data/TODO.align/README.round32.md +67 -0
- data/TODO.align/README.round33.md +62 -0
- data/TODO.align/README.round34.md +70 -0
- data/docs/constraints.md +161 -0
- data/docs/generate_constraint_docs.rb +44 -0
- data/exe/chemicalml +6 -0
- data/lib/chemicalml/cli/base.rb +68 -0
- data/lib/chemicalml/cli/command.rb +43 -0
- data/lib/chemicalml/cli/constraints_command.rb +27 -0
- data/lib/chemicalml/cli/conventions_command.rb +14 -0
- data/lib/chemicalml/cli/dictionaries_command.rb +14 -0
- data/lib/chemicalml/cli/elements_command.rb +17 -0
- data/lib/chemicalml/cli/enums_command.rb +17 -0
- data/lib/chemicalml/cli/info_command.rb +77 -0
- data/lib/chemicalml/cli/inspect_command.rb +39 -0
- data/lib/chemicalml/cli/validate_command.rb +54 -0
- data/lib/chemicalml/cli.rb +43 -0
- data/lib/chemicalml/cml/base/abundance.rb +21 -5
- data/lib/chemicalml/cml/base/action.rb +44 -6
- data/lib/chemicalml/cml/base/action_list.rb +44 -8
- data/lib/chemicalml/cml/base/alternative.rb +37 -0
- data/lib/chemicalml/cml/base/amount.rb +15 -5
- data/lib/chemicalml/cml/base/angle.rb +34 -7
- data/lib/chemicalml/cml/base/annotation.rb +38 -0
- data/lib/chemicalml/cml/base/any_cml.rb +12 -5
- data/lib/chemicalml/cml/base/appinfo.rb +40 -0
- data/lib/chemicalml/cml/base/arg.rb +80 -0
- data/lib/chemicalml/cml/base/array.rb +51 -8
- data/lib/chemicalml/cml/base/array_list.rb +15 -5
- data/lib/chemicalml/cml/base/atom.rb +93 -19
- data/lib/chemicalml/cml/base/atom_array.rb +77 -2
- data/lib/chemicalml/cml/base/atom_parity.rb +18 -2
- data/lib/chemicalml/cml/base/atom_set.rb +15 -5
- data/lib/chemicalml/cml/base/atom_type.rb +27 -7
- data/lib/chemicalml/cml/base/atom_type_list.rb +23 -7
- data/lib/chemicalml/cml/base/atomic_basis_function.rb +35 -11
- data/lib/chemicalml/cml/base/band.rb +22 -7
- data/lib/chemicalml/cml/base/band_list.rb +15 -7
- data/lib/chemicalml/cml/base/basis_set.rb +26 -7
- data/lib/chemicalml/cml/base/bond.rb +39 -7
- data/lib/chemicalml/cml/base/bond_array.rb +41 -2
- data/lib/chemicalml/cml/base/bond_set.rb +15 -5
- data/lib/chemicalml/cml/base/bond_stereo.rb +25 -4
- data/lib/chemicalml/cml/base/bond_type.rb +24 -7
- data/lib/chemicalml/cml/base/bond_type_list.rb +23 -7
- data/lib/chemicalml/cml/base/cell_parameter.rb +30 -8
- data/lib/chemicalml/cml/base/cml_module.rb +36 -11
- data/lib/chemicalml/cml/base/common_children.rb +35 -0
- data/lib/chemicalml/cml/base/complex_object.rb +37 -0
- data/lib/chemicalml/cml/base/condition_list.rb +28 -8
- data/lib/chemicalml/cml/base/crystal.rb +27 -9
- data/lib/chemicalml/cml/base/definition.rb +12 -5
- data/lib/chemicalml/cml/base/description.rb +15 -5
- data/lib/chemicalml/cml/base/dictionary.rb +30 -7
- data/lib/chemicalml/cml/base/dictionary_entry.rb +67 -8
- data/lib/chemicalml/cml/base/dimension.rb +31 -7
- data/lib/chemicalml/cml/base/document.rb +18 -8
- data/lib/chemicalml/cml/base/documentation.rb +12 -5
- data/lib/chemicalml/cml/base/eigen.rb +33 -7
- data/lib/chemicalml/cml/base/electron.rb +29 -9
- data/lib/chemicalml/cml/base/enumeration.rb +41 -0
- data/lib/chemicalml/cml/base/expression.rb +47 -0
- data/lib/chemicalml/cml/base/float.rb +52 -0
- data/lib/chemicalml/cml/base/float_array.rb +55 -0
- data/lib/chemicalml/cml/base/formula.rb +31 -10
- data/lib/chemicalml/cml/base/fragment.rb +33 -9
- data/lib/chemicalml/cml/base/fragment_list.rb +26 -7
- data/lib/chemicalml/cml/base/gradient.rb +19 -6
- data/lib/chemicalml/cml/base/identifier.rb +22 -4
- data/lib/chemicalml/cml/base/integer.rb +52 -0
- data/lib/chemicalml/cml/base/integer_array.rb +55 -0
- data/lib/chemicalml/cml/base/isotope.rb +29 -8
- data/lib/chemicalml/cml/base/isotope_list.rb +18 -7
- data/lib/chemicalml/cml/base/join.rb +28 -6
- data/lib/chemicalml/cml/base/kpoint.rb +17 -6
- data/lib/chemicalml/cml/base/kpoint_list.rb +15 -7
- data/lib/chemicalml/cml/base/label.rb +15 -5
- data/lib/chemicalml/cml/base/lattice.rb +36 -9
- data/lib/chemicalml/cml/base/lattice_vector.rb +17 -6
- data/lib/chemicalml/cml/base/length.rb +31 -7
- data/lib/chemicalml/cml/base/line3.rb +21 -5
- data/lib/chemicalml/cml/base/link.rb +51 -10
- data/lib/chemicalml/cml/base/list.rb +23 -9
- data/lib/chemicalml/cml/base/map.rb +38 -5
- data/lib/chemicalml/cml/base/matrix.rb +38 -9
- data/lib/chemicalml/cml/base/mechanism.rb +20 -7
- data/lib/chemicalml/cml/base/mechanism_component.rb +14 -6
- data/lib/chemicalml/cml/base/metadata.rb +20 -6
- data/lib/chemicalml/cml/base/metadata_list.rb +30 -5
- data/lib/chemicalml/cml/base/molecule.rb +95 -21
- data/lib/chemicalml/cml/base/molecule_list.rb +27 -7
- data/lib/chemicalml/cml/base/name.rb +11 -3
- data/lib/chemicalml/cml/base/object.rb +20 -6
- data/lib/chemicalml/cml/base/observation.rb +18 -5
- data/lib/chemicalml/cml/base/operator.rb +40 -0
- data/lib/chemicalml/cml/base/parameter.rb +38 -8
- data/lib/chemicalml/cml/base/parameter_list.rb +30 -5
- data/lib/chemicalml/cml/base/particle.rb +23 -6
- data/lib/chemicalml/cml/base/peak.rb +86 -11
- data/lib/chemicalml/cml/base/peak_group.rb +81 -7
- data/lib/chemicalml/cml/base/peak_list.rb +25 -8
- data/lib/chemicalml/cml/base/peak_structure.rb +47 -6
- data/lib/chemicalml/cml/base/plane3.rb +15 -5
- data/lib/chemicalml/cml/base/point3.rb +15 -5
- data/lib/chemicalml/cml/base/potential.rb +17 -6
- data/lib/chemicalml/cml/base/potential_form.rb +31 -6
- data/lib/chemicalml/cml/base/potential_list.rb +15 -7
- data/lib/chemicalml/cml/base/product.rb +53 -2
- data/lib/chemicalml/cml/base/product_list.rb +36 -2
- data/lib/chemicalml/cml/base/property.rb +32 -8
- data/lib/chemicalml/cml/base/property_list.rb +26 -5
- data/lib/chemicalml/cml/base/reactant.rb +53 -2
- data/lib/chemicalml/cml/base/reactant_list.rb +36 -2
- data/lib/chemicalml/cml/base/reaction.rb +82 -12
- data/lib/chemicalml/cml/base/reaction_list.rb +29 -2
- data/lib/chemicalml/cml/base/reaction_scheme.rb +48 -8
- data/lib/chemicalml/cml/base/reaction_step.rb +33 -9
- data/lib/chemicalml/cml/base/reaction_step_list.rb +34 -7
- data/lib/chemicalml/cml/base/reactive_centre.rb +31 -6
- data/lib/chemicalml/cml/base/region.rb +24 -5
- data/lib/chemicalml/cml/base/related_entry.rb +34 -0
- data/lib/chemicalml/cml/base/sample.rb +32 -5
- data/lib/chemicalml/cml/base/scalar.rb +41 -6
- data/lib/chemicalml/cml/base/spectator.rb +26 -5
- data/lib/chemicalml/cml/base/spectator_list.rb +20 -7
- data/lib/chemicalml/cml/base/spectrum.rb +63 -12
- data/lib/chemicalml/cml/base/spectrum_data.rb +20 -8
- data/lib/chemicalml/cml/base/spectrum_list.rb +30 -7
- data/lib/chemicalml/cml/base/sphere3.rb +15 -5
- data/lib/chemicalml/cml/base/stmml.rb +12 -5
- data/lib/chemicalml/cml/base/string.rb +40 -0
- data/lib/chemicalml/cml/base/string_array.rb +52 -0
- data/lib/chemicalml/cml/base/substance.rb +42 -8
- data/lib/chemicalml/cml/base/substance_list.rb +32 -7
- data/lib/chemicalml/cml/base/symmetry.rb +33 -7
- data/lib/chemicalml/cml/base/system.rb +23 -8
- data/lib/chemicalml/cml/base/table.rb +43 -8
- data/lib/chemicalml/cml/base/table_cell.rb +12 -5
- data/lib/chemicalml/cml/base/table_content.rb +20 -8
- data/lib/chemicalml/cml/base/table_header.rb +15 -7
- data/lib/chemicalml/cml/base/table_header_cell.rb +27 -5
- data/lib/chemicalml/cml/base/table_row.rb +15 -7
- data/lib/chemicalml/cml/base/table_row_list.rb +15 -7
- data/lib/chemicalml/cml/base/tcell.rb +43 -0
- data/lib/chemicalml/cml/base/torsion.rb +34 -7
- data/lib/chemicalml/cml/base/transform3.rb +12 -5
- data/lib/chemicalml/cml/base/transition_state.rb +23 -5
- data/lib/chemicalml/cml/base/trow.rb +48 -0
- data/lib/chemicalml/cml/base/unit.rb +45 -10
- data/lib/chemicalml/cml/base/unit_list.rb +40 -6
- data/lib/chemicalml/cml/base/unit_type.rb +32 -5
- data/lib/chemicalml/cml/base/unit_type_list.rb +34 -6
- data/lib/chemicalml/cml/base/vector3.rb +15 -5
- data/lib/chemicalml/cml/base/xaxis.rb +33 -7
- data/lib/chemicalml/cml/base/yaxis.rb +33 -7
- data/lib/chemicalml/cml/base/z_matrix.rb +26 -5
- data/lib/chemicalml/cml/base.rb +139 -121
- data/lib/chemicalml/cml/canonical_comparison.rb +54 -0
- data/lib/chemicalml/cml/elements.rb +168 -124
- data/lib/chemicalml/cml/enums.rb +55 -0
- data/lib/chemicalml/cml/namespace.rb +2 -3
- data/lib/chemicalml/cml/patterns.rb +33 -0
- data/lib/chemicalml/cml/reference_resolver.rb +137 -0
- data/lib/chemicalml/cml/role/alternative.rb +10 -0
- data/lib/chemicalml/cml/role/annotation.rb +10 -0
- data/lib/chemicalml/cml/role/appinfo.rb +10 -0
- data/lib/chemicalml/cml/role/arg.rb +10 -0
- data/lib/chemicalml/cml/role/cml_module.rb +2 -3
- data/lib/chemicalml/cml/role/complex_object.rb +10 -0
- data/lib/chemicalml/cml/role/enumeration.rb +10 -0
- data/lib/chemicalml/cml/role/expression.rb +10 -0
- data/lib/chemicalml/cml/role/float.rb +10 -0
- data/lib/chemicalml/cml/role/float_array.rb +10 -0
- data/lib/chemicalml/cml/role/integer.rb +10 -0
- data/lib/chemicalml/cml/role/integer_array.rb +10 -0
- data/lib/chemicalml/cml/role/operator.rb +10 -0
- data/lib/chemicalml/cml/role/related_entry.rb +10 -0
- data/lib/chemicalml/cml/role/string.rb +10 -0
- data/lib/chemicalml/cml/role/string_array.rb +10 -0
- data/lib/chemicalml/cml/role/tcell.rb +10 -0
- data/lib/chemicalml/cml/role/trow.rb +10 -0
- data/lib/chemicalml/cml/role.rb +138 -121
- data/lib/chemicalml/cml/schema24/alternative.rb +14 -0
- data/lib/chemicalml/cml/schema24/annotation.rb +15 -0
- data/lib/chemicalml/cml/schema24/appinfo.rb +15 -0
- data/lib/chemicalml/cml/schema24/arg.rb +14 -0
- data/lib/chemicalml/cml/schema24/cml_module.rb +18 -0
- data/lib/chemicalml/cml/schema24/complex_object.rb +14 -0
- data/lib/chemicalml/cml/schema24/configuration.rb +15 -2
- data/lib/chemicalml/cml/schema24/enumeration.rb +16 -0
- data/lib/chemicalml/cml/schema24/expression.rb +14 -0
- data/lib/chemicalml/cml/schema24/float.rb +14 -0
- data/lib/chemicalml/cml/schema24/float_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/integer.rb +14 -0
- data/lib/chemicalml/cml/schema24/integer_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/operator.rb +14 -0
- data/lib/chemicalml/cml/schema24/related_entry.rb +14 -0
- data/lib/chemicalml/cml/schema24/string.rb +14 -0
- data/lib/chemicalml/cml/schema24/string_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/tcell.rb +14 -0
- data/lib/chemicalml/cml/schema24/trow.rb +14 -0
- data/lib/chemicalml/cml/schema24.rb +154 -126
- data/lib/chemicalml/cml/schema3.rb +123 -123
- data/lib/chemicalml/cml/visitable.rb +77 -3
- data/lib/chemicalml/cml/wire_class_registry.rb +3 -3
- data/lib/chemicalml/cml.rb +164 -132
- data/lib/chemicalml/context_configuration.rb +12 -4
- data/lib/chemicalml/convention/base.rb +17 -3
- data/lib/chemicalml/convention/cascade/constraints/reaction_scheme_must_have_content.rb +33 -0
- data/lib/chemicalml/convention/cascade/constraints/reaction_step_list_must_contain_steps.rb +31 -0
- data/lib/chemicalml/convention/cascade/constraints/reaction_step_must_have_reaction_or_lists.rb +33 -0
- data/lib/chemicalml/convention/cascade/constraints/reactive_centre_atom_refs_should_be_present.rb +34 -0
- data/lib/chemicalml/convention/cascade/constraints.rb +18 -0
- data/lib/chemicalml/convention/cascade.rb +43 -0
- data/lib/chemicalml/convention/compchem/constraints/array_rules.rb +44 -0
- data/lib/chemicalml/convention/compchem/constraints/calculation_requires_finalization.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +5 -4
- data/lib/chemicalml/convention/compchem/constraints/environment_at_most_one_property_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_must_have_content.rb +44 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_must_not_contain_parameter.rb +27 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_must_have_content.rb +54 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_must_not_contain_property.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/job_list_module_must_have_id.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_environment.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_must_have_id.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +7 -9
- data/lib/chemicalml/convention/compchem/constraints/matrix_rules.rb +48 -0
- data/lib/chemicalml/convention/compchem/constraints/module_predicates.rb +50 -0
- data/lib/chemicalml/convention/compchem/constraints/scalar_units.rb +42 -0
- data/lib/chemicalml/convention/compchem/constraints.rb +40 -2
- data/lib/chemicalml/convention/compchem.rb +20 -2
- data/lib/chemicalml/convention/constraint.rb +68 -24
- data/lib/chemicalml/convention/coordinator.rb +90 -0
- data/lib/chemicalml/convention/detection.rb +39 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace.rb +29 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash.rb +32 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern.rb +33 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +4 -4
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_contain_definition.rb +29 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +6 -6
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_unit_type.rb +31 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_units_co_constraints.rb +44 -0
- data/lib/chemicalml/convention/dictionary/constraints.rb +14 -2
- data/lib/chemicalml/convention/dictionary.rb +8 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula.rb +41 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +18 -9
- data/lib/chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired.rb +6 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_element_type_should_be_in_periodic_table.rb +39 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_id_must_match_pattern.rb +7 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +3 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_element_type.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_id.rb +5 -4
- data/lib/chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom.rb +65 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_array_must_be_child_of_molecule.rb +37 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_atom_refs2_should_be_distinct.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_id_should_match_pattern.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_ids_unique_within_molecule.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_order.rb +5 -4
- data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +4 -3
- data/lib/chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref.rb +34 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_should_be_in_enum.rb +39 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_should_not_be_numeric.rb +3 -3
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct.rb +43 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4.rb +45 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref.rb +33 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_should_be_in_enum.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb +45 -0
- data/lib/chemicalml/convention/molecular/constraints/dict_ref_should_resolve.rb +59 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_atom_array_mutually_exclusive_with_children.rb +33 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children.rb +32 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_chirality_should_be_in_enum.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb +35 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_id_should_match_pattern.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_must_have_id.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/property_must_have_dict_ref.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb +58 -0
- data/lib/chemicalml/convention/molecular/constraints/references_should_resolve.rb +37 -0
- data/lib/chemicalml/convention/molecular/constraints/scalar_must_have_data_type.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints.rb +59 -13
- data/lib/chemicalml/convention/molecular.rb +25 -2
- data/lib/chemicalml/convention/registry.rb +95 -10
- data/lib/chemicalml/convention/simple_unit/constraints/root_must_be_unit_list.rb +24 -0
- data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_power.rb +32 -0
- data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_symbol.rb +31 -0
- data/lib/chemicalml/convention/simple_unit/constraints.rb +16 -0
- data/lib/chemicalml/convention/simple_unit.rb +37 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/peak_list_must_contain_peaks.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/peak_should_have_values.rb +34 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_content.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_convention.rb +32 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_format.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints.rb +20 -0
- data/lib/chemicalml/convention/spectroscopy.rb +41 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_contain_at_least_one_unit.rb +29 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_have_namespace.rb +36 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_contain_definition.rb +28 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_id.rb +28 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_multiplier_or_constant_to_si.rb +34 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_parent_si.rb +32 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_symbol_and_unit_type.rb +4 -4
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_title.rb +32 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_parent_si_should_resolve.rb +45 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_unit_type_should_resolve.rb +46 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints.rb +19 -1
- data/lib/chemicalml/convention/unit_dictionary.rb +11 -2
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_id_must_match_pattern.rb +31 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_contain_at_least_one_unit_type.rb +28 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_have_namespace.rb +35 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_contain_definition.rb +28 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +6 -6
- data/lib/chemicalml/convention/unit_type_dictionary/constraints.rb +9 -1
- data/lib/chemicalml/convention/unit_type_dictionary.rb +6 -2
- data/lib/chemicalml/convention/validation_report.rb +90 -0
- data/lib/chemicalml/convention/violation.rb +9 -3
- data/lib/chemicalml/convention.rb +49 -11
- data/lib/chemicalml/dictionary/entry.rb +6 -6
- data/lib/chemicalml/dictionary/enum.rb +1 -1
- data/lib/chemicalml/dictionary/link.rb +3 -3
- data/lib/chemicalml/dictionary/loader.rb +19 -19
- data/lib/chemicalml/dictionary/model.rb +5 -5
- data/lib/chemicalml/dictionary/registry.rb +9 -9
- data/lib/chemicalml/dictionary.rb +13 -9
- data/lib/chemicalml/logger.rb +47 -0
- data/lib/chemicalml/schema/definition.rb +2 -2
- data/lib/chemicalml/schema.rb +7 -7
- data/lib/chemicalml/version.rb +1 -1
- data/lib/chemicalml/versioned_parser.rb +28 -10
- data/lib/chemicalml.rb +79 -17
- data/lib/tasks/reference_fetch.rake +30 -31
- data/lib/tasks/scrape_fixtures.rake +23 -24
- metadata +235 -35
- data/lib/chemicalml/cml/child_mappings.rb +0 -168
- data/lib/chemicalml/cml/translator/value_translations.rb +0 -270
- data/lib/chemicalml/cml/translator.rb +0 -484
- data/lib/chemicalml/model/atom.rb +0 -64
- data/lib/chemicalml/model/atom_parity.rb +0 -21
- data/lib/chemicalml/model/bond.rb +0 -39
- data/lib/chemicalml/model/bond_stereo.rb +0 -29
- data/lib/chemicalml/model/cml_array.rb +0 -27
- data/lib/chemicalml/model/cml_module.rb +0 -45
- data/lib/chemicalml/model/document.rb +0 -29
- data/lib/chemicalml/model/formula.rb +0 -34
- data/lib/chemicalml/model/identifier.rb +0 -21
- data/lib/chemicalml/model/label.rb +0 -21
- data/lib/chemicalml/model/matrix.rb +0 -29
- data/lib/chemicalml/model/metadata.rb +0 -23
- data/lib/chemicalml/model/metadata_list.rb +0 -25
- data/lib/chemicalml/model/molecule.rb +0 -45
- data/lib/chemicalml/model/name.rb +0 -21
- data/lib/chemicalml/model/node.rb +0 -45
- data/lib/chemicalml/model/parameter.rb +0 -27
- data/lib/chemicalml/model/parameter_list.rb +0 -25
- data/lib/chemicalml/model/product.rb +0 -21
- data/lib/chemicalml/model/product_list.rb +0 -21
- data/lib/chemicalml/model/property.rb +0 -28
- data/lib/chemicalml/model/property_list.rb +0 -25
- data/lib/chemicalml/model/reactant.rb +0 -21
- data/lib/chemicalml/model/reactant_list.rb +0 -21
- data/lib/chemicalml/model/reaction.rb +0 -41
- data/lib/chemicalml/model/reaction_list.rb +0 -23
- data/lib/chemicalml/model/scalar.rb +0 -25
- data/lib/chemicalml/model/substance.rb +0 -25
- data/lib/chemicalml/model.rb +0 -40
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<bond>`'s `order` attribute SHOULD be one of the XSD
|
|
8
|
+
# orderType enum values: S/1/D/2/T/3/A/unknown/other.
|
|
9
|
+
# Warning severity — CML permits extension values via
|
|
10
|
+
# convention-specific dicts.
|
|
11
|
+
class BondOrderShouldBeInEnum < Chemicalml::Convention::Constraint::NodeConstraint
|
|
12
|
+
self.description = "A `<bond>`'s `order` attribute SHOULD be one of the XSD orderType enum values: S/1/D/2/T/3/A/unknown/other. Warning severity — CML permits extension values via"
|
|
13
|
+
include Chemicalml::Cml::Enums
|
|
14
|
+
|
|
15
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
16
|
+
|
|
17
|
+
def check_node(node, _path)
|
|
18
|
+
order = node.order.to_s
|
|
19
|
+
return [] if order.empty?
|
|
20
|
+
return [] if ORDER_VALUES.include?(order)
|
|
21
|
+
|
|
22
|
+
[violation(path: yield_path(node),
|
|
23
|
+
message: "bond #{node.id.inspect} order #{order.inspect} should be one of " \
|
|
24
|
+
"#{ORDER_VALUES.to_a.sort.inspect}",
|
|
25
|
+
severity: :warning,
|
|
26
|
+
value: order)]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def yield_path(node)
|
|
32
|
+
id = node.node_id
|
|
33
|
+
id ? "bond[#{id}]" : 'bond'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -5,17 +5,17 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class BondOrderShouldNotBeNumeric < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = "A <bond>'s order attribute SHOULD be one of S/D/T/Q/A or 'other' (numeric values are not recommended)."
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
8
10
|
VALID_ORDERS = %w[S D T Q A other].freeze
|
|
9
11
|
|
|
10
12
|
def check_node(node, path)
|
|
11
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Bond)
|
|
12
|
-
|
|
13
13
|
order = node.order.to_s
|
|
14
14
|
return [] if order.empty?
|
|
15
15
|
|
|
16
16
|
return [] if VALID_ORDERS.include?(order) || node.dict_ref.to_s.size.positive?
|
|
17
17
|
|
|
18
|
-
[violation(path: path.empty? ?
|
|
18
|
+
[violation(path: path.empty? ? 'bond' : path.join('/'),
|
|
19
19
|
message: "bond order #{order.inspect} is not recommended " \
|
|
20
20
|
"(use S/D/T/Q/A or 'other' with dictRef)",
|
|
21
21
|
severity: :warning)]
|
data/lib/chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<bondStereo>` with `atomRefs4` (used by C/T stereo)
|
|
8
|
+
# SHOULD reference four distinct atom ids. Duplicate ids make
|
|
9
|
+
# the stereo descriptor meaningless. Warning severity.
|
|
10
|
+
class BondStereoAtomRefs4ShouldBeDistinct < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = 'A `<bondStereo>` with `atomRefs4` (used by C/T stereo) SHOULD reference four distinct atom ids. Duplicate ids make the stereo descriptor meaningless. Warning severity.'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::BondStereo
|
|
13
|
+
|
|
14
|
+
def check_node(node, _path)
|
|
15
|
+
ids = parse_refs(node.atom_refs4)
|
|
16
|
+
return [] if ids.size < 2
|
|
17
|
+
return [] if ids.uniq.size == ids.size
|
|
18
|
+
|
|
19
|
+
duplicates = ids.group_by { |i| i }.select { |_, v| v.size > 1 }.keys
|
|
20
|
+
[violation(path: yield_path(node),
|
|
21
|
+
message: "bondStereo #{node.id.inspect} atomRefs4 should reference four distinct atoms; " \
|
|
22
|
+
"duplicate ids: #{duplicates.inspect}",
|
|
23
|
+
severity: :warning,
|
|
24
|
+
value: node.atom_refs4)]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def yield_path(node)
|
|
30
|
+
id = node.node_id
|
|
31
|
+
id ? "bondStereo[#{id}]" : 'bondStereo'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def parse_refs(value)
|
|
35
|
+
return [] if value.nil?
|
|
36
|
+
|
|
37
|
+
value.to_s.split(/\s+/).reject(&:empty?)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `<bondStereo>` value C (cis) or T
|
|
8
|
+
# (trans) MUST have `atomRefs4` and MUST NOT have `atomRefs2`.
|
|
9
|
+
class BondStereoCisTransMustHaveAtomRefs4 < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Molecular convention: `<bondStereo>` value C (cis) or T (trans) MUST have `atomRefs4` and MUST NOT have `atomRefs2`.'
|
|
11
|
+
applies_to Chemicalml::Cml::Role::BondStereo
|
|
12
|
+
CIS_TRANS_VALUES = %w[C T].freeze
|
|
13
|
+
|
|
14
|
+
def check_node(node, path)
|
|
15
|
+
value = node.content.to_s.upcase
|
|
16
|
+
return [] unless CIS_TRANS_VALUES.include?(value)
|
|
17
|
+
|
|
18
|
+
violations = []
|
|
19
|
+
if node.atom_refs4.to_s.strip.empty?
|
|
20
|
+
violations << violation(
|
|
21
|
+
path: (path + [describe(node)]).join('/'),
|
|
22
|
+
message: "bondStereo value #{value.inspect} must have atomRefs4 " \
|
|
23
|
+
'(four atom ids; two must match the parent bond)'
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
unless node.atom_refs2.to_s.strip.empty?
|
|
27
|
+
violations << violation(
|
|
28
|
+
path: (path + [describe(node)]).join('/'),
|
|
29
|
+
message: "bondStereo value #{value.inspect} must not have atomRefs2 " \
|
|
30
|
+
'(only W/H wedge/hatch values use atomRefs2)'
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
violations
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def bond_stereo?(node)
|
|
39
|
+
node.is_a?(Chemicalml::Cml::Role::BondStereo)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `<bondStereo>` with value `other`
|
|
8
|
+
# MUST have a `dictRef` pointing to the convention that
|
|
9
|
+
# defines the stereo semantics.
|
|
10
|
+
class BondStereoOtherMustHaveDictRef < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = 'Molecular convention: `<bondStereo>` with value `other` MUST have a `dictRef` pointing to the convention that defines the stereo semantics.'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::BondStereo
|
|
13
|
+
def check_node(node, path)
|
|
14
|
+
return [] unless node.content.to_s.downcase == 'other'
|
|
15
|
+
return [] unless node.dict_ref.to_s.empty?
|
|
16
|
+
|
|
17
|
+
[violation(
|
|
18
|
+
path: (path + [describe(node)]).join('/'),
|
|
19
|
+
message: "bondStereo value 'other' must have a dictRef " \
|
|
20
|
+
'identifying the convention that defines it'
|
|
21
|
+
)]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def bond_stereo?(node)
|
|
27
|
+
node.is_a?(Chemicalml::Cml::Role::BondStereo)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<bondStereo>`'s `value` attribute SHOULD be one of the
|
|
8
|
+
# XSD stereoType enum values: C/T/W/H/undefined/other.
|
|
9
|
+
# Warning severity.
|
|
10
|
+
class BondStereoShouldBeInEnum < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<bondStereo>`'s `value` attribute SHOULD be one of the XSD stereoType enum values: C/T/W/H/undefined/other. Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Enums
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::BondStereo
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
value = node.content.to_s
|
|
18
|
+
return [] if value.empty?
|
|
19
|
+
return [] if STEREO_VALUES.include?(value)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "bondStereo #{node.id.inspect} value #{value.inspect} should be one of " \
|
|
23
|
+
"#{STEREO_VALUES.to_a.sort.inspect}",
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: value)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "bondStereo[#{id}]" : 'bondStereo'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `<bondStereo>` value W (wedge) or H
|
|
8
|
+
# (hatch) MUST have `atomRefs2` and MUST NOT have `atomRefs4`.
|
|
9
|
+
class BondStereoWedgeHashMustHaveAtomRefs2 < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Molecular convention: `<bondStereo>` value W (wedge) or H (hatch) MUST have `atomRefs2` and MUST NOT have `atomRefs4`.'
|
|
11
|
+
applies_to Chemicalml::Cml::Role::BondStereo
|
|
12
|
+
WEDGE_HASH_VALUES = %w[W H].freeze
|
|
13
|
+
|
|
14
|
+
def check_node(node, path)
|
|
15
|
+
value = node.content.to_s.upcase
|
|
16
|
+
return [] unless WEDGE_HASH_VALUES.include?(value)
|
|
17
|
+
|
|
18
|
+
violations = []
|
|
19
|
+
if node.atom_refs2.to_s.strip.empty?
|
|
20
|
+
violations << violation(
|
|
21
|
+
path: (path + [describe(node)]).join('/'),
|
|
22
|
+
message: "bondStereo value #{value.inspect} must have atomRefs2 " \
|
|
23
|
+
'(first atom = sharp end, second = blunt end)'
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
unless node.atom_refs4.to_s.strip.empty?
|
|
27
|
+
violations << violation(
|
|
28
|
+
path: (path + [describe(node)]).join('/'),
|
|
29
|
+
message: "bondStereo value #{value.inspect} must not have atomRefs4 " \
|
|
30
|
+
'(only C/T cis-trans values use atomRefs4)'
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
violations
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def bond_stereo?(node)
|
|
39
|
+
node.is_a?(Chemicalml::Cml::Role::BondStereo)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Walks the document and warns on any element whose `dictRef`
|
|
8
|
+
# attribute cannot be resolved against the built-in
|
|
9
|
+
# dictionaries. Catches typos like `dictRef="cml:bpingpoint"`.
|
|
10
|
+
#
|
|
11
|
+
# DocumentConstraint — needs the whole tree, but the resolver
|
|
12
|
+
# works per-node so it's just a wrapper around the per-node
|
|
13
|
+
# check.
|
|
14
|
+
class DictRefShouldResolve < Chemicalml::Convention::Constraint::NodeConstraint
|
|
15
|
+
self.description = 'Walks the document and warns on any element whose `dictRef` attribute cannot be resolved against the built-in dictionaries. Catches typos like `dictRef="cml:bpingpoint"`.'
|
|
16
|
+
applies_to Chemicalml::Cml::Role::Atom,
|
|
17
|
+
Chemicalml::Cml::Role::Bond,
|
|
18
|
+
Chemicalml::Cml::Role::Molecule,
|
|
19
|
+
Chemicalml::Cml::Role::Property,
|
|
20
|
+
Chemicalml::Cml::Role::Scalar,
|
|
21
|
+
Chemicalml::Cml::Role::Array,
|
|
22
|
+
Chemicalml::Cml::Role::Matrix,
|
|
23
|
+
Chemicalml::Cml::Role::Name,
|
|
24
|
+
Chemicalml::Cml::Role::Label
|
|
25
|
+
|
|
26
|
+
def check_node(node, path)
|
|
27
|
+
dict_ref = node.dict_ref.to_s.strip
|
|
28
|
+
return [] if dict_ref.empty?
|
|
29
|
+
return [] if resolves?(dict_ref)
|
|
30
|
+
|
|
31
|
+
[violation(path: path_fingerprint(node, path),
|
|
32
|
+
message: "#{node.element_name} #{node_id_or_blank(node).inspect} " \
|
|
33
|
+
"dictRef #{dict_ref.inspect} does not resolve against any built-in dictionary",
|
|
34
|
+
severity: :warning,
|
|
35
|
+
value: dict_ref)]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def resolves?(dict_ref)
|
|
41
|
+
!Chemicalml::Dictionary::Registry.lookup(dict_ref).nil?
|
|
42
|
+
rescue StandardError
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def path_fingerprint(node, path)
|
|
47
|
+
base = path.empty? ? node.element_name : path.join('/')
|
|
48
|
+
id = node.node_id
|
|
49
|
+
id ? "#{base}[#{id}]" : base
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def node_id_or_blank(node)
|
|
53
|
+
node.node_id || ''
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: a `<molecule>` MAY hold an `atomArray`
|
|
8
|
+
# OR child `<molecule>` elements, but not both. The two are
|
|
9
|
+
# mutually exclusive ways of describing composition.
|
|
10
|
+
class MoleculeAtomArrayMutuallyExclusiveWithChildren < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = 'Molecular convention: a `<molecule>` MAY hold an `atomArray` OR child `<molecule>` elements, but not both. The two are mutually exclusive ways of describing composition.'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
13
|
+
def check_node(node, path)
|
|
14
|
+
return [] if node.atom_array.nil?
|
|
15
|
+
return [] if (node.molecules || []).empty?
|
|
16
|
+
|
|
17
|
+
[violation(
|
|
18
|
+
path: (path + [describe(node)]).join('/'),
|
|
19
|
+
message: "molecule #{node.id.inspect} has both an atomArray " \
|
|
20
|
+
'and child molecule elements — these are mutually exclusive'
|
|
21
|
+
)]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def molecule?(node)
|
|
27
|
+
node.is_a?(Chemicalml::Cml::Role::Molecule)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: a `<molecule>` MAY hold a `bondArray`
|
|
8
|
+
# OR child `<molecule>` elements, but not both.
|
|
9
|
+
class MoleculeBondArrayMutuallyExclusiveWithChildren < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Molecular convention: a `<molecule>` MAY hold a `bondArray` OR child `<molecule>` elements, but not both.'
|
|
11
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
12
|
+
def check_node(node, path)
|
|
13
|
+
return [] if node.bond_array.nil?
|
|
14
|
+
return [] if (node.molecules || []).empty?
|
|
15
|
+
|
|
16
|
+
[violation(
|
|
17
|
+
path: (path + [describe(node)]).join('/'),
|
|
18
|
+
message: "molecule #{node.id.inspect} has both a bondArray " \
|
|
19
|
+
'and child molecule elements — these are mutually exclusive'
|
|
20
|
+
)]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def molecule?(node)
|
|
26
|
+
node.is_a?(Chemicalml::Cml::Role::Molecule)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<molecule>`'s `chirality` attribute SHOULD be one of the
|
|
8
|
+
# XSD chiralityType enum values:
|
|
9
|
+
# enantiomer/racemate/unknown/other. Warning severity.
|
|
10
|
+
class MoleculeChiralityShouldBeInEnum < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<molecule>`'s `chirality` attribute SHOULD be one of the XSD chiralityType enum values: enantiomer/racemate/unknown/other. Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Enums
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
chirality = node.chirality.to_s
|
|
18
|
+
return [] if chirality.empty?
|
|
19
|
+
return [] if CHIRALITY_VALUES.include?(chirality)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "molecule #{node.id.inspect} chirality #{chirality.inspect} should be one of " \
|
|
23
|
+
"#{CHIRALITY_VALUES.to_a.sort.inspect}",
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: chirality)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "molecule[#{id}]" : 'molecule'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `count` MUST NOT appear on top-level
|
|
8
|
+
# molecules (direct children of `<cml>`). It is REQUIRED on
|
|
9
|
+
# molecules nested inside another `<molecule>`.
|
|
10
|
+
class MoleculeCountMustNotAppearOnTopLevel < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
11
|
+
self.description = 'Molecular convention: `count` MUST NOT appear on top-level molecules (direct children of `<cml>`). It is REQUIRED on molecules nested inside another `<molecule>`.'
|
|
12
|
+
def check(document)
|
|
13
|
+
violations = []
|
|
14
|
+
top_level_molecules(document).each do |mol, path|
|
|
15
|
+
next if mol.count.to_s.empty?
|
|
16
|
+
|
|
17
|
+
violations << violation(
|
|
18
|
+
path: (path + [describe(mol)]).join('/'),
|
|
19
|
+
message: "top-level molecule #{mol.id.inspect} must not have " \
|
|
20
|
+
'a count attribute (only nested molecules may carry count)'
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
violations
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def top_level_molecules(document)
|
|
29
|
+
(document.molecules || []).map { |m| [m, []] }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<molecule>`'s `id` attribute SHOULD match the XSD
|
|
8
|
+
# moleculeIDType pattern (letter/underscore start, alphanumeric
|
|
9
|
+
# body, optional namespace prefix). Warning severity.
|
|
10
|
+
class MoleculeIdShouldMatchPattern < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<molecule>`'s `id` attribute SHOULD match the XSD moleculeIDType pattern (letter/underscore start, alphanumeric body, optional namespace prefix). Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Patterns
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
id = node.id.to_s
|
|
18
|
+
return [] if id.empty?
|
|
19
|
+
return [] if id.match?(/\A#{MOLECULE_ID_PATTERN.source}\z/)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "molecule id #{id.inspect} should match the moleculeIDType pattern " \
|
|
23
|
+
'(letter start, alphanumeric body, optional prefix)',
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: id)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "molecule[#{id}]" : 'molecule'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -5,13 +5,13 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class MoleculeMustHaveId < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <molecule> in a molecular document MUST have an id attribute unique within document scope.'
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
8
10
|
def check_node(node, path)
|
|
9
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Molecule)
|
|
10
|
-
|
|
11
11
|
return [] unless node.id.to_s.empty?
|
|
12
12
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
13
|
+
[violation(path: path.empty? ? 'molecule' : path.join('/'),
|
|
14
|
+
message: 'molecule must have an id attribute')]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -5,13 +5,13 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class PropertyMustHaveDictRef < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <property> MUST have a dictRef attribute that identifies the property type via a dictionary entry.'
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Property
|
|
8
10
|
def check_node(node, path)
|
|
9
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Property)
|
|
10
|
-
|
|
11
11
|
return [] unless node.dict_ref.to_s.empty?
|
|
12
12
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
13
|
+
[violation(path: path.empty? ? 'property' : path.join('/'),
|
|
14
|
+
message: 'property must have a dictRef attribute')]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<property>` with a `dictRef` whose dictionary entry declares
|
|
8
|
+
# a `dataType` SHOULD have a child `<scalar>` whose `dataType`
|
|
9
|
+
# attribute matches. Catches inconsistencies like a property
|
|
10
|
+
# declaring `dictRef="cml:bp"` (boiling point, xsd:float) but
|
|
11
|
+
# carrying a `<scalar dataType="xsd:string">`.
|
|
12
|
+
#
|
|
13
|
+
# Warning severity — some dictionaries allow multiple dataTypes.
|
|
14
|
+
class PropertyScalarDataTypeMatchesDictionary < Chemicalml::Convention::Constraint::NodeConstraint
|
|
15
|
+
self.description = 'A `<property>` with a `dictRef` whose dictionary entry declares a `dataType` SHOULD have a child `<scalar>` whose `dataType` attribute matches. Catches inconsistencies like a property'
|
|
16
|
+
applies_to Chemicalml::Cml::Role::Property
|
|
17
|
+
|
|
18
|
+
def check_node(node, _path)
|
|
19
|
+
dict_ref = node.dict_ref.to_s
|
|
20
|
+
return [] if dict_ref.empty?
|
|
21
|
+
|
|
22
|
+
entry = lookup_entry(dict_ref)
|
|
23
|
+
return [] unless entry
|
|
24
|
+
|
|
25
|
+
expected_type = entry.data_type.to_s
|
|
26
|
+
return [] if expected_type.empty?
|
|
27
|
+
|
|
28
|
+
scalar = node.scalar
|
|
29
|
+
return [] unless scalar
|
|
30
|
+
|
|
31
|
+
actual_type = scalar.data_type.to_s
|
|
32
|
+
return [] if actual_type.empty?
|
|
33
|
+
return [] if actual_type == expected_type
|
|
34
|
+
|
|
35
|
+
[violation(path: yield_path(node),
|
|
36
|
+
message: "property #{node.id.inspect} dictRef #{dict_ref.inspect} " \
|
|
37
|
+
"expects dataType #{expected_type.inspect} but scalar has #{actual_type.inspect}",
|
|
38
|
+
severity: :warning,
|
|
39
|
+
value: { expected: expected_type, actual: actual_type }.freeze)]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def lookup_entry(dict_ref)
|
|
45
|
+
Chemicalml::Dictionary::Registry.lookup(dict_ref)
|
|
46
|
+
rescue StandardError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def yield_path(node)
|
|
51
|
+
id = node.node_id
|
|
52
|
+
id ? "property[#{id}]" : 'property'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Walks the document via `Cml::ReferenceResolver` and reports
|
|
8
|
+
# every bond whose `atomRefs2` references atoms that don't
|
|
9
|
+
# exist in the parent molecule. Warning severity — there are
|
|
10
|
+
# edge cases (inter-molecular bonds in transition states).
|
|
11
|
+
#
|
|
12
|
+
# DocumentConstraint because it needs the whole tree to
|
|
13
|
+
# resolve references.
|
|
14
|
+
class ReferencesShouldResolve < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
15
|
+
self.description = "Walks the document via `Cml::ReferenceResolver` and reports every bond whose `atomRefs2` references atoms that don't exist in the parent molecule. Warning severity — there are"
|
|
16
|
+
def check(document)
|
|
17
|
+
resolver = Chemicalml::Cml::ReferenceResolver.new(document)
|
|
18
|
+
resolver.unresolved_refs.map do |entry|
|
|
19
|
+
violation(path: describe(entry[:node]),
|
|
20
|
+
message: "bond #{entry[:node].id.inspect} #{entry[:attr]} references " \
|
|
21
|
+
"missing atoms: #{entry[:missing].inspect}",
|
|
22
|
+
severity: :warning,
|
|
23
|
+
value: entry[:missing])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def describe(node)
|
|
30
|
+
id = node.node_id
|
|
31
|
+
id ? "#{node.element_name}[#{id}]" : node.element_name
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -5,13 +5,13 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class ScalarMustHaveDataType < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <scalar> child of a <property> MUST have a dataType attribute (e.g. xsd:float, xsd:integer).'
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Scalar
|
|
8
10
|
def check_node(node, path)
|
|
9
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Scalar)
|
|
10
|
-
|
|
11
11
|
return [] unless node.data_type.to_s.empty?
|
|
12
12
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
13
|
+
[violation(path: path.empty? ? 'scalar' : path.join('/'),
|
|
14
|
+
message: 'scalar must have a dataType attribute')]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|