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,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `<atomArray>` MUST be a child of
|
|
8
|
+
# `<molecule>` or `<formula>`. Any other parent is invalid.
|
|
9
|
+
# Checked from the parent's perspective during the walk —
|
|
10
|
+
# when visiting a non-molecule/non-formula node, look for
|
|
11
|
+
# misplaced atomArray children.
|
|
12
|
+
class AtomArrayMustBeChildOfMoleculeOrFormula < Chemicalml::Convention::Constraint::NodeConstraint
|
|
13
|
+
self.description = "Molecular convention: `<atomArray>` MUST be a child of `<molecule>` or `<formula>`. Any other parent is invalid. Checked from the parent's perspective during the walk —"
|
|
14
|
+
def check_node(node, path)
|
|
15
|
+
return [] if allowed_parent?(node)
|
|
16
|
+
|
|
17
|
+
misplaced = node.wire_children.select { |c| atom_array?(c) }
|
|
18
|
+
misplaced.map do |child|
|
|
19
|
+
violation(
|
|
20
|
+
path: (path + [describe(node), describe(child)]).join('/'),
|
|
21
|
+
message: 'atomArray must be a child of molecule or formula, ' \
|
|
22
|
+
"but appears under #{node.element_name.inspect}"
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def allowed_parent?(node)
|
|
30
|
+
node.is_a?(Chemicalml::Cml::Role::Molecule) ||
|
|
31
|
+
node.is_a?(Chemicalml::Cml::Role::Formula)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def atom_array?(node)
|
|
35
|
+
node.is_a?(Chemicalml::Cml::Role::AtomArray)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -4,24 +4,33 @@ module Chemicalml
|
|
|
4
4
|
module Convention
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
|
-
# `atomArray` MUST contain at least one
|
|
8
|
-
#
|
|
7
|
+
# `atomArray` MUST contain at least one atom. The atoms can
|
|
8
|
+
# be in the child form (`<atom>` elements) or the parallel-array
|
|
9
|
+
# form (`atomID` attribute with whitespace-separated ids).
|
|
9
10
|
class AtomArrayMustContainAtoms < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = '`atomArray` MUST contain at least one atom. The atoms can be in the child form (`<atom>` elements) or the parallel-array form (`atomID` attribute with whitespace-separated ids).'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
10
13
|
def check_node(node, path)
|
|
11
|
-
return [] unless molecule?(node)
|
|
12
14
|
return [] unless node.atom_array
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
return []
|
|
16
|
+
aa = node.atom_array
|
|
17
|
+
return [] if has_child_atoms?(aa) || has_parallel_array_atoms?(aa)
|
|
16
18
|
|
|
17
|
-
[violation(path: path.empty? ?
|
|
18
|
-
message:
|
|
19
|
+
[violation(path: path.empty? ? 'molecule' : path.join('/'),
|
|
20
|
+
message: 'atomArray must contain at least one atom')]
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
private
|
|
22
24
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
+
def has_child_atoms?(atom_array)
|
|
26
|
+
!(atom_array.atoms || []).empty?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Parallel-array form is identified by a non-empty atomIDArray
|
|
30
|
+
# attribute — the XSD marks it as mandatory when atoms are
|
|
31
|
+
# encoded as parallel arrays.
|
|
32
|
+
def has_parallel_array_atoms?(atom_array)
|
|
33
|
+
!atom_array.atom_id_array.to_s.strip.empty?
|
|
25
34
|
end
|
|
26
35
|
end
|
|
27
36
|
end
|
|
@@ -5,23 +5,23 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class AtomCoordinatesMustBePaired < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = '<atom> 2D coordinates (x2, y2) must appear together; 3D coordinates (x3, y3, z3) must appear together.'
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Atom
|
|
8
10
|
def check_node(node, path)
|
|
9
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Atom)
|
|
10
|
-
|
|
11
11
|
violations = []
|
|
12
12
|
has_x2 = !node.x2.to_s.empty?
|
|
13
13
|
has_y2 = !node.y2.to_s.empty?
|
|
14
14
|
if has_x2 != has_y2
|
|
15
|
-
violations << violation(path: path.empty? ?
|
|
16
|
-
message:
|
|
15
|
+
violations << violation(path: path.empty? ? 'atom' : path.join('/'),
|
|
16
|
+
message: 'x2 and y2 must both be present or both absent')
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
has_x3 = !node.x3.to_s.empty?
|
|
20
20
|
has_y3 = !node.y3.to_s.empty?
|
|
21
21
|
has_z3 = !node.z3.to_s.empty?
|
|
22
22
|
if [has_x3, has_y3, has_z3].any? && ![has_x3, has_y3, has_z3].all?
|
|
23
|
-
violations << violation(path: path.empty? ?
|
|
24
|
-
message:
|
|
23
|
+
violations << violation(path: path.empty? ? 'atom' : path.join('/'),
|
|
24
|
+
message: 'x3, y3, and z3 must all be present together')
|
|
25
25
|
end
|
|
26
26
|
violations
|
|
27
27
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# An `<atom>`'s `elementType` attribute SHOULD be one of the
|
|
8
|
+
# XSD elementTypeType enum values (the periodic table plus
|
|
9
|
+
# the special "Du" dummy and "R" group placeholder). Warns
|
|
10
|
+
# on typos like "Carb" or "X".
|
|
11
|
+
class AtomElementTypeShouldBeInPeriodicTable < Chemicalml::Convention::Constraint::NodeConstraint
|
|
12
|
+
self.description = "An `<atom>`'s `elementType` attribute SHOULD be one of the XSD elementTypeType enum values (the periodic table plus the special \"Du\" dummy and \"R\" group placeholder). Warns"
|
|
13
|
+
include Chemicalml::Cml::Enums
|
|
14
|
+
|
|
15
|
+
applies_to Chemicalml::Cml::Role::Atom
|
|
16
|
+
|
|
17
|
+
def check_node(node, _path)
|
|
18
|
+
et = node.element_type.to_s.strip
|
|
19
|
+
return [] if et.empty?
|
|
20
|
+
return [] if ELEMENT_TYPE_VALUES.include?(et)
|
|
21
|
+
|
|
22
|
+
[violation(path: yield_path(node),
|
|
23
|
+
message: "atom #{node.id.inspect} elementType #{et.inspect} should be one of " \
|
|
24
|
+
"the periodic table symbols (e.g. C, H, O, Fe) — got #{et.inspect}",
|
|
25
|
+
severity: :warning,
|
|
26
|
+
value: et)]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def yield_path(node)
|
|
32
|
+
id = node.node_id
|
|
33
|
+
id ? "atom[#{id}]" : 'atom'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -5,19 +5,20 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class AtomIdMustMatchPattern < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
-
|
|
8
|
+
self.description = "An <atom>'s id attribute SHOULD start with a letter and contain only letters, digits, dot, hyphen, or underscore."
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Atom
|
|
10
|
+
ID_PATTERN = /\A[A-Za-z][A-Za-z0-9._-]*\z/
|
|
9
11
|
|
|
10
12
|
def check_node(node, path)
|
|
11
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Atom)
|
|
12
|
-
|
|
13
13
|
id = node.id.to_s
|
|
14
14
|
return [] if id.empty?
|
|
15
15
|
return [] if id.match?(ID_PATTERN)
|
|
16
16
|
|
|
17
|
-
[violation(path: path.empty? ?
|
|
17
|
+
[violation(path: path.empty? ? 'atom' : path.join('/'),
|
|
18
18
|
message: "atom id #{id.inspect} must start with a letter and " \
|
|
19
|
-
|
|
20
|
-
severity: :warning
|
|
19
|
+
'contain only letters, digits, dot, hyphen, or underscore',
|
|
20
|
+
severity: :warning,
|
|
21
|
+
value: id)]
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
end
|
|
@@ -7,6 +7,7 @@ module Chemicalml
|
|
|
7
7
|
# Atom ids MUST be unique within the eldest containing molecule
|
|
8
8
|
# per the molecular convention.
|
|
9
9
|
class AtomIdsUniqueWithinMolecule < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
10
|
+
self.description = 'Atom ids MUST be unique within the eldest containing molecule per the molecular convention.'
|
|
10
11
|
def check(document)
|
|
11
12
|
violations = []
|
|
12
13
|
walk_nodes(document) do |node, path|
|
|
@@ -16,7 +17,7 @@ module Chemicalml
|
|
|
16
17
|
duplicates = ids.group_by { |x| x }.select { |_, v| v.length > 1 }.keys
|
|
17
18
|
duplicates.each do |dup|
|
|
18
19
|
violations << violation(
|
|
19
|
-
path: path.empty? ? "molecule[#{node.id}]" : path.join(
|
|
20
|
+
path: path.empty? ? "molecule[#{node.id}]" : path.join('/'),
|
|
20
21
|
message: "duplicate atom id #{dup.inspect} within molecule #{node.id.inspect}"
|
|
21
22
|
)
|
|
22
23
|
end
|
|
@@ -33,7 +34,7 @@ module Chemicalml
|
|
|
33
34
|
def atom_ids_within(molecule)
|
|
34
35
|
return [] unless molecule.atom_array
|
|
35
36
|
|
|
36
|
-
(molecule.atom_array.atoms || []).map
|
|
37
|
+
(molecule.atom_array.atoms || []).map(&:id).compact
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
40
|
end
|
|
@@ -5,13 +5,13 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class AtomMustHaveElementType < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'An <atom> inside an atomArray in a molecule MUST have an elementType attribute.'
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Atom
|
|
8
10
|
def check_node(node, path)
|
|
9
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Atom)
|
|
10
|
-
|
|
11
11
|
return [] unless node.element_type.to_s.empty?
|
|
12
12
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
13
|
+
[violation(path: path.empty? ? 'atom' : path.join('/'),
|
|
14
|
+
message: 'atom must have an elementType attribute')]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -5,13 +5,14 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class AtomMustHaveId < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
applies_to Chemicalml::Cml::Role::Atom
|
|
9
|
+
self.description = 'An <atom> inside an atomArray in a molecule MUST have an id attribute.'
|
|
10
10
|
|
|
11
|
+
def check_node(node, path)
|
|
11
12
|
return [] unless node.id.to_s.empty?
|
|
12
13
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
14
|
+
[violation(path: path.empty? ? 'atom' : path.join('/'),
|
|
15
|
+
message: 'atom must have an id attribute')]
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
18
|
end
|
data/lib/chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# An `<atomParity>` element's `atomRefs4` attribute SHOULD
|
|
8
|
+
# reference four distinct atom ids around a chiral center.
|
|
9
|
+
# Duplicate ids make the parity descriptor meaningless.
|
|
10
|
+
# Warning severity.
|
|
11
|
+
class AtomParityAtomRefs4ShouldBeDistinct < Chemicalml::Convention::Constraint::NodeConstraint
|
|
12
|
+
self.description = "An `<atomParity>` element's `atomRefs4` attribute SHOULD reference four distinct atom ids around a chiral center. Duplicate ids make the parity descriptor meaningless."
|
|
13
|
+
applies_to Chemicalml::Cml::Role::AtomParity
|
|
14
|
+
|
|
15
|
+
def check_node(node, _path)
|
|
16
|
+
ids = parse_refs(node.atom_refs4)
|
|
17
|
+
return [] if ids.size < 2
|
|
18
|
+
return [] if ids.uniq.size == ids.size
|
|
19
|
+
|
|
20
|
+
duplicates = ids.group_by { |i| i }.select { |_, v| v.size > 1 }.keys
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "atomParity #{node.id.inspect} atomRefs4 should reference four distinct atoms; " \
|
|
23
|
+
"duplicate ids: #{duplicates.inspect}",
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: node.atom_refs4)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "atomParity[#{id}]" : 'atomParity'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse_refs(value)
|
|
36
|
+
return [] if value.nil?
|
|
37
|
+
|
|
38
|
+
value.to_s.split(/\s+/).reject(&:empty?)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
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 `<atomParity>` elements
|
|
8
|
+
# whose parent `<atom>`'s id does not appear in atomRefs4.
|
|
9
|
+
# The CML convention requires the parent atom to be one of
|
|
10
|
+
# the four references (otherwise the parity is meaningless).
|
|
11
|
+
#
|
|
12
|
+
# DocumentConstraint because it needs to walk the tree and
|
|
13
|
+
# track parent-child relationships.
|
|
14
|
+
class AtomParityShouldIncludeParentAtom < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
15
|
+
self.description = "Walks the document and warns on `<atomParity>` elements whose parent `<atom>`'s id does not appear in atomRefs4. The CML convention requires the parent atom to be one of"
|
|
16
|
+
def check(document)
|
|
17
|
+
violations = []
|
|
18
|
+
visit_with_parent(document, nil) do |node, parent|
|
|
19
|
+
next unless atom_parity?(node)
|
|
20
|
+
next unless atom?(parent)
|
|
21
|
+
|
|
22
|
+
refs = parse_refs(node.atom_refs4)
|
|
23
|
+
next if refs.empty?
|
|
24
|
+
next if refs.include?(parent.id)
|
|
25
|
+
|
|
26
|
+
violations << violation(
|
|
27
|
+
path: "atom[#{parent.id}]/atomParity",
|
|
28
|
+
message: "atomParity atomRefs4 #{refs.inspect} should include the parent atom id " \
|
|
29
|
+
"#{parent.id.inspect}",
|
|
30
|
+
severity: :warning,
|
|
31
|
+
value: node.atom_refs4
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
violations
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def visit_with_parent(node, parent, &block)
|
|
40
|
+
return unless node.is_a?(Lutaml::Model::Serializable)
|
|
41
|
+
|
|
42
|
+
block.call(node, parent)
|
|
43
|
+
return unless node.is_a?(Chemicalml::Cml::Visitable)
|
|
44
|
+
|
|
45
|
+
node.wire_children.each { |c| visit_with_parent(c, node, &block) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def atom_parity?(node)
|
|
49
|
+
node.is_a?(Chemicalml::Cml::Role::AtomParity)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def atom?(node)
|
|
53
|
+
node.is_a?(Chemicalml::Cml::Role::Atom)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def parse_refs(value)
|
|
57
|
+
return [] if value.nil?
|
|
58
|
+
|
|
59
|
+
value.to_s.split(/\s+/).reject(&:empty?)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `<bondArray>` MUST be a child of
|
|
8
|
+
# `<molecule>`. Any other parent is invalid.
|
|
9
|
+
class BondArrayMustBeChildOfMolecule < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Molecular convention: `<bondArray>` MUST be a child of `<molecule>`. Any other parent is invalid.'
|
|
11
|
+
def check_node(node, path)
|
|
12
|
+
return [] if molecule?(node)
|
|
13
|
+
|
|
14
|
+
misplaced = node.wire_children.select { |c| bond_array?(c) }
|
|
15
|
+
misplaced.map do |child|
|
|
16
|
+
violation(
|
|
17
|
+
path: (path + [describe(node), describe(child)]).join('/'),
|
|
18
|
+
message: 'bondArray must be a child of molecule, ' \
|
|
19
|
+
"but appears under #{node.element_name.inspect}"
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def molecule?(node)
|
|
27
|
+
node.is_a?(Chemicalml::Cml::Role::Molecule)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def bond_array?(node)
|
|
31
|
+
node.is_a?(Chemicalml::Cml::Role::BondArray)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<bond>`'s `atomRefs2` SHOULD reference two distinct atom
|
|
8
|
+
# ids. A self-bond (`a1 a1`) is chemically meaningless.
|
|
9
|
+
# Warning severity — there are edge cases in non-classical
|
|
10
|
+
# chemistry (e.g. agostic interactions).
|
|
11
|
+
class BondAtomRefs2ShouldBeDistinct < Chemicalml::Convention::Constraint::NodeConstraint
|
|
12
|
+
self.description = "A `<bond>`'s `atomRefs2` SHOULD reference two distinct atom ids. A self-bond (`a1 a1`) is chemically meaningless. Warning severity — there are edge cases in non-classical"
|
|
13
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
14
|
+
|
|
15
|
+
def check_node(node, _path)
|
|
16
|
+
ids = parse_refs(node.atom_refs2)
|
|
17
|
+
return [] if ids.size < 2
|
|
18
|
+
return [] if ids.uniq.size == ids.size
|
|
19
|
+
|
|
20
|
+
duplicates = ids.group_by { |i| i }.select { |_, v| v.size > 1 }.keys
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "bond #{node.id.inspect} atomRefs2 should reference two distinct atoms; " \
|
|
23
|
+
"duplicate ids: #{duplicates.inspect}",
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: node.atom_refs2)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "bond[#{id}]" : 'bond'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse_refs(value)
|
|
36
|
+
return [] if value.nil?
|
|
37
|
+
|
|
38
|
+
value.to_s.split(/\s+/).reject(&:empty?)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
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 `<bond>`'s `id` attribute SHOULD match the XSD idType
|
|
8
|
+
# pattern (letter start, alphanumeric body with dots/dashes).
|
|
9
|
+
# Warning severity.
|
|
10
|
+
class BondIdShouldMatchPattern < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<bond>`'s `id` attribute SHOULD match the XSD idType pattern (letter start, alphanumeric body with dots/dashes). Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Patterns
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
id = node.id.to_s
|
|
18
|
+
return [] if id.empty?
|
|
19
|
+
return [] if id.match?(/\A#{ID_PATTERN.source}\z/)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "bond id #{id.inspect} should match the idType pattern " \
|
|
23
|
+
'(letter start, alphanumeric body with . and -)',
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: id)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "bond[#{id}]" : 'bond'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: a `<bond>` `id` MUST be unique within
|
|
8
|
+
# the eldest containing molecule. Mirrors the existing
|
|
9
|
+
# `AtomIdsUniqueWithinMolecule` constraint for bonds.
|
|
10
|
+
class BondIdsUniqueWithinMolecule < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
11
|
+
self.description = 'Molecular convention: a `<bond>` `id` MUST be unique within the eldest containing molecule. Mirrors the existing `AtomIdsUniqueWithinMolecule` constraint for bonds.'
|
|
12
|
+
def check(document)
|
|
13
|
+
violations = []
|
|
14
|
+
walk_nodes(document) do |node, path|
|
|
15
|
+
next unless molecule?(node)
|
|
16
|
+
|
|
17
|
+
ids = bond_ids_within(node)
|
|
18
|
+
duplicates = ids.group_by { |x| x }.select { |_, v| v.length > 1 }.keys
|
|
19
|
+
duplicates.each do |dup|
|
|
20
|
+
violations << violation(
|
|
21
|
+
path: (path + [describe(node)]).join('/'),
|
|
22
|
+
message: "duplicate bond id #{dup.inspect} within molecule #{node.id.inspect}"
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
violations
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def molecule?(node)
|
|
32
|
+
node.is_a?(Chemicalml::Cml::Role::Molecule)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def bond_ids_within(molecule)
|
|
36
|
+
return [] unless molecule.bond_array
|
|
37
|
+
|
|
38
|
+
(molecule.bond_array.bonds || []).map(&:id).compact
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -5,13 +5,13 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class BondMustHaveAtomRefs2 < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <bond> MUST have an atomRefs2 attribute referencing two distinct atoms in the same molecule.'
|
|
9
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
8
10
|
def check_node(node, path)
|
|
9
|
-
return [] unless node.is_a?(Chemicalml::Cml::Role::Bond)
|
|
10
|
-
|
|
11
11
|
return [] unless node.atom_refs2.to_s.strip.empty?
|
|
12
12
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
13
|
+
[violation(path: path.empty? ? 'bond' : path.join('/'),
|
|
14
|
+
message: 'bond must have an atomRefs2 attribute')]
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -5,13 +5,14 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class BondMustHaveOrder < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
9
|
+
self.description = 'A <bond> MUST have an order attribute (S/D/T/A recommended).'
|
|
10
10
|
|
|
11
|
+
def check_node(node, path)
|
|
11
12
|
return [] unless node.order.to_s.strip.empty?
|
|
12
13
|
|
|
13
|
-
[violation(path: path.empty? ?
|
|
14
|
-
message:
|
|
14
|
+
[violation(path: path.empty? ? 'bond' : path.join('/'),
|
|
15
|
+
message: 'bond must have an order attribute')]
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
18
|
end
|
data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb
CHANGED
|
@@ -7,6 +7,7 @@ module Chemicalml
|
|
|
7
7
|
# Bonds MUST reference atoms within the same parent molecule
|
|
8
8
|
# per the molecular convention.
|
|
9
9
|
class BondMustReferenceAtomsInSameMolecule < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
10
|
+
self.description = 'Bonds MUST reference atoms within the same parent molecule per the molecular convention.'
|
|
10
11
|
def check(document)
|
|
11
12
|
violations = []
|
|
12
13
|
walk_nodes(document) do |node, path|
|
|
@@ -18,7 +19,7 @@ module Chemicalml
|
|
|
18
19
|
next if missing.empty?
|
|
19
20
|
|
|
20
21
|
violations << violation(
|
|
21
|
-
path: path.empty? ? "molecule[#{node.id}]" : path.join(
|
|
22
|
+
path: path.empty? ? "molecule[#{node.id}]" : path.join('/'),
|
|
22
23
|
message: "bond #{bond.id.inspect} references atoms not in the same molecule: #{missing.inspect}"
|
|
23
24
|
)
|
|
24
25
|
end
|
|
@@ -35,7 +36,7 @@ module Chemicalml
|
|
|
35
36
|
def atom_ids_within(molecule)
|
|
36
37
|
return [] unless molecule.atom_array
|
|
37
38
|
|
|
38
|
-
(molecule.atom_array.atoms || []).map
|
|
39
|
+
(molecule.atom_array.atoms || []).map(&:id)
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
def bonds_within(molecule)
|
|
@@ -45,7 +46,7 @@ module Chemicalml
|
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
def atom_refs_of(bond)
|
|
48
|
-
bond.atom_refs2.to_s.split
|
|
49
|
+
bond.atom_refs2.to_s.split
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Molecular convention: `<bond>` with `order="other"` MUST
|
|
8
|
+
# have a `dictRef` pointing to the dictionary that defines
|
|
9
|
+
# the order semantics. The warning-level "should not be
|
|
10
|
+
# numeric" rule is separate; this is the hard error.
|
|
11
|
+
class BondOrderOtherMustHaveDictRef < Chemicalml::Convention::Constraint::NodeConstraint
|
|
12
|
+
self.description = 'Molecular convention: `<bond>` with `order="other"` MUST have a `dictRef` pointing to the dictionary that defines the order semantics. The warning-level "should not be'
|
|
13
|
+
applies_to Chemicalml::Cml::Role::Bond
|
|
14
|
+
def check_node(node, path)
|
|
15
|
+
return [] unless node.order.to_s.downcase == 'other'
|
|
16
|
+
return [] unless node.dict_ref.to_s.empty?
|
|
17
|
+
|
|
18
|
+
[violation(
|
|
19
|
+
path: (path + [describe(node)]).join('/'),
|
|
20
|
+
message: "bond order 'other' must have a dictRef " \
|
|
21
|
+
'identifying the dictionary entry that defines it'
|
|
22
|
+
)]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def bond?(node)
|
|
28
|
+
node.is_a?(Chemicalml::Cml::Role::Bond)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|