From 8d2f4d5abc5671cfc88ecbf607e978a42d11b75f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 01:11:35 +0000 Subject: [PATCH 1/6] V_zeta: implement Brainstorm I (subject_interaction spine + shape-typed observations) Adds schemas/V_zeta, the sandbox iteration implementing Brainstorm I from ndi-next-steps Summer 2026/1_Ingestion, superseding V_epsilon (Brainstorm E, retained on main as an archived reference). Full coverage set: the documents needed to express every existing V_delta document. Core Brainstorm-I model (vs V_epsilon): - One spine. subject_interaction (<- base) carries the whole identity/where/when payload: subject_id, time_reference_# (>=1), method (verb), variable (noun, required), target_structure (optional locus, Path T). observation / manipulation / annotation are empty direction markers; isa replaces a direction filter. subject_statement removed; subject_assertion re-rooted under base. - Off-class identity. The observation tier is named by DATA-TYPE (shape), not property: 12 dimensional scalar__observation leaves + a generic escape hatch replace E's ~20 property classes, and categorical_observation collapses to one concrete class. WHICH property rides on the `variable` term (the answer to E's EPM enumeration failure). The shared shape library (scalar_mass ... scalar_score, generic_scalar) is inherited by both the observation that reads a quantity and the manipulation that imposes it. - Shaped time. time_reference gains a `sampling` structure (point / grid / enumerated); per-sample times are derived from the shaped reference, so sample_time is retired from the scalar genera and regular grids are O(1). - dataseries_observation branch (timeseries_/imageseries_observation) retained as the observation-tier handle for acquired data, with the record/array channel model + dataseries_channel_map sidecar. Manipulation families, time_reference frames, dataseries/expression bodies, all infrastructure, and the five deprecated classes carry over from V_epsilon (design-neutral for I); the spine-owned target_structure is stripped where a family redeclared it. hartley_calc's long-standing malformed file record is fixed so the whole set passes meta-validation. 202 document classes (156 stable, 40 draft, 6 deprecated) + 3 meta. index.json and topics.json regenerated from disk; V_zeta_SPEC.md + V_zeta_notes.md document the deltas and the resolved open questions (Path T locus, method/variable, shaped time; both spine-shaping forks confirmed with the maintainer). New tests/test_vzeta.py enforces meta-schema validity, index<->disk agreement, superclass/dependency resolution, tier/maturity agreement, and spine composition. 515 tests pass (104 prior + 411 new). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015zjbvyLbSLMYz1uCizYwQh --- README.md | 2 + .../conversions/from_did_v1/_TEMPLATE.md | 92 + .../V_zeta/conversions/from_did_v1/_files.md | 71 + .../V_zeta/conversions/from_did_v1/_index.md | 76 + .../from_did_v1/_universal_renames.md | 325 +++ .../from_did_v1/contrast_sensitivity_calc.md | 75 + .../from_did_v1/contrast_tuning.md | 107 + .../from_did_v1/contrast_tuning_calc.md | 67 + .../conversions/from_did_v1/hartley_calc.md | 75 + .../hartley_reverse_correlation.md | 71 + .../conversions/from_did_v1/ontology_image.md | 173 ++ .../conversions/from_did_v1/ontology_label.md | 184 ++ .../from_did_v1/ontology_table_row.md | 113 + .../from_did_v1/oridirtuning_calc.md | 82 + .../orientation_direction_tuning.md | 116 + .../conversions/from_did_v1/probe_location.md | 164 ++ .../from_did_v1/reverse_correlation.md | 64 + .../from_did_v1/spatial_frequency_tuning.md | 104 + .../spatial_frequency_tuning_calc.md | 55 + .../conversions/from_did_v1/speed_tuning.md | 93 + .../from_did_v1/speed_tuning_calc.md | 55 + .../conversions/from_did_v1/subject_group.md | 42 + .../from_did_v1/temporal_frequency_tuning.md | 105 + .../temporal_frequency_tuning_calc.md | 55 + .../conversions/from_did_v1/treatment.md | 108 + .../conversions/from_did_v1/treatment_drug.md | 29 + .../from_did_v1/treatment_transfer.md | 27 + .../from_did_v1/virus_injection.md | 28 + schemas/V_zeta/deprecated/.gitkeep | 0 schemas/V_zeta/deprecated/projectvar.json | 96 + schemas/V_zeta/deprecated/subject_group.json | 52 + schemas/V_zeta/deprecated/treatment.json | 91 + schemas/V_zeta/deprecated/treatment_drug.json | 81 + .../V_zeta/deprecated/treatment_transfer.json | 120 + .../V_zeta/deprecated/virus_injection.json | 124 + schemas/V_zeta/draft/.gitkeep | 0 .../V_zeta/draft/dataseries_channel_map.json | 108 + schemas/V_zeta/draft/dataseries_data.json | 362 +++ .../V_zeta/draft/dataseries_observation.json | 272 ++ schemas/V_zeta/draft/dataseries_pyramid.json | 72 + .../V_zeta/draft/expression_matrix_data.json | 48 + .../expression_matrix_data_cellranger_h5.json | 15 + .../expression_matrix_data_counts_table.json | 15 + .../expression_matrix_data_dia_report.json | 15 + .../draft/expression_matrix_data_gef.json | 15 + .../draft/expression_matrix_data_gem.json | 15 + .../draft/expression_matrix_data_h5ad.json | 15 + .../draft/expression_matrix_data_imzml.json | 15 + .../draft/expression_matrix_data_loom.json | 15 + .../expression_matrix_data_maxquant.json | 15 + .../draft/expression_matrix_data_mtx.json | 15 + .../draft/expression_matrix_data_mzml.json | 15 + .../draft/expression_matrix_data_mztab.json | 15 + .../draft/expression_matrix_data_visium.json | 15 + .../V_zeta/draft/expression_observation.json | 106 + schemas/V_zeta/draft/imageseries_data.json | 16 + .../V_zeta/draft/imageseries_observation.json | 56 + schemas/V_zeta/draft/instrument.json | 76 + .../draft/reference_annotation_data.json | 23 + .../draft/reference_annotation_data_gff3.json | 15 + .../draft/reference_annotation_data_gtf.json | 15 + schemas/V_zeta/draft/reference_data.json | 184 ++ .../V_zeta/draft/reference_sequence_data.json | 16 + .../reference_sequence_data_fasta_genome.json | 15 + ...reference_sequence_data_fasta_protein.json | 15 + ...nce_sequence_data_fasta_transcriptome.json | 15 + schemas/V_zeta/draft/sequence_read_data.json | 67 + .../V_zeta/draft/sequence_read_data_bam.json | 28 + .../V_zeta/draft/sequence_read_data_cram.json | 28 + .../draft/sequence_read_data_fastq.json | 22 + .../draft/spatial_expression_observation.json | 63 + schemas/V_zeta/draft/timeseries_data.json | 16 + .../V_zeta/draft/timeseries_data_binary.json | 15 + schemas/V_zeta/draft/timeseries_data_csv.json | 15 + schemas/V_zeta/draft/timeseries_data_edf.json | 15 + .../V_zeta/draft/timeseries_observation.json | 115 + schemas/V_zeta/examples/.gitkeep | 0 ...scalar_temperature_observation_series.json | 32 + .../V_zeta/examples/utc_reference_grid.json | 27 + schemas/V_zeta/index.json | 2360 +++++++++++++++++ schemas/V_zeta/microschemas/_DESIGN.md | 409 +++ schemas/V_zeta/stable/CURIE_lookups_meta.json | 92 + schemas/V_zeta/stable/annotation.json | 16 + schemas/V_zeta/stable/app.json | 142 + schemas/V_zeta/stable/base.json | 78 + schemas/V_zeta/stable/bath.json | 55 + .../stable/binaryseries_parameters.json | 104 + schemas/V_zeta/stable/binnedspikeratevm.json | 70 + .../V_zeta/stable/biological_transfer.json | 62 + schemas/V_zeta/stable/calculator.json | 35 + .../stable/categorical_observation.json | 43 + .../stable/contrast_sensitivity_calc.json | 351 +++ schemas/V_zeta/stable/contrast_tuning.json | 698 +++++ .../V_zeta/stable/contrast_tuning_calc.json | 21 + .../V_zeta/stable/control_stimulus_ids.json | 105 + schemas/V_zeta/stable/daqmetadatareader.json | 66 + .../daqmetadatareader_epochdata_ingested.json | 25 + schemas/V_zeta/stable/daqreader.json | 31 + .../stable/daqreader_epochdata_ingested.json | 76 + .../daqreader_mfdaq_epochdata_ingested.json | 69 + schemas/V_zeta/stable/daqreader_ndr.json | 64 + schemas/V_zeta/stable/daqsystem.json | 44 + schemas/V_zeta/stable/dataset_remote.json | 61 + .../V_zeta/stable/dataset_session_info.json | 66 + schemas/V_zeta/stable/demo_ndi.json | 44 + schemas/V_zeta/stable/demo_ndi_mock.json | 44 + schemas/V_zeta/stable/derivation.json | 43 + schemas/V_zeta/stable/did_schema_meta.json | 326 +++ schemas/V_zeta/stable/directory.json | 114 + schemas/V_zeta/stable/distance_metadata.json | 132 + .../stable/electrode_offset_voltage.json | 53 + schemas/V_zeta/stable/element.json | 109 + schemas/V_zeta/stable/element_epoch.json | 340 +++ .../stable/environmental_manipulation.json | 50 + schemas/V_zeta/stable/ephys_zarr.json | 405 +++ .../stable/epoch_bounded_reference.json | 58 + .../stable/epoch_relative_reference.json | 121 + schemas/V_zeta/stable/epochclocktimes.json | 67 + .../V_zeta/stable/epochfiles_ingested.json | 67 + schemas/V_zeta/stable/epochid.json | 34 + .../stable/event_bounded_reference.json | 22 + .../stable/event_relative_reference.json | 65 + schemas/V_zeta/stable/filenavigator.json | 72 + schemas/V_zeta/stable/filter.json | 69 + schemas/V_zeta/stable/fitcurve.json | 82 + .../V_zeta/stable/frequency_manipulation.json | 18 + schemas/V_zeta/stable/generic_file.json | 73 + schemas/V_zeta/stable/generic_scalar.json | 73 + .../stable/generic_scalar_manipulation.json | 18 + .../stable/generic_scalar_observation.json | 18 + schemas/V_zeta/stable/group_assignment.json | 38 + schemas/V_zeta/stable/hartley_calc.json | 26 + .../stable/hartley_reverse_correlation.json | 261 ++ schemas/V_zeta/stable/image.json | 99 + schemas/V_zeta/stable/image_collection.json | 71 + schemas/V_zeta/stable/image_stack.json | 59 + .../V_zeta/stable/image_stack_parameters.json | 152 ++ schemas/V_zeta/stable/image_zarr.json | 251 ++ schemas/V_zeta/stable/injection.json | 150 ++ .../V_zeta/stable/interaction_purpose.json | 58 + schemas/V_zeta/stable/jrclust_clusters.json | 46 + schemas/V_zeta/stable/manipulation.json | 16 + schemas/V_zeta/stable/measurement.json | 54 + schemas/V_zeta/stable/metadata_editor.json | 30 + schemas/V_zeta/stable/mock.json | 29 + schemas/V_zeta/stable/ndi_reserved_keys.json | 46 + .../V_zeta/stable/neuron_extracellular.json | 125 + schemas/V_zeta/stable/ngrid.json | 97 + schemas/V_zeta/stable/observation.json | 16 + schemas/V_zeta/stable/oneepoch.json | 60 + schemas/V_zeta/stable/ontology_image.json | 41 + schemas/V_zeta/stable/ontology_label.json | 36 + schemas/V_zeta/stable/ontology_table_row.json | 79 + schemas/V_zeta/stable/openminds.json | 78 + schemas/V_zeta/stable/openminds_element.json | 25 + schemas/V_zeta/stable/openminds_stimulus.json | 28 + schemas/V_zeta/stable/openminds_subject.json | 25 + schemas/V_zeta/stable/oridirtuning_calc.json | 21 + .../stable/orientation_direction_tuning.json | 507 ++++ .../stable/pharmacological_manipulation.json | 72 + schemas/V_zeta/stable/placement.json | 38 + schemas/V_zeta/stable/position_metadata.json | 122 + .../V_zeta/stable/pressure_manipulation.json | 18 + schemas/V_zeta/stable/probe_geometry.json | 82 + schemas/V_zeta/stable/probe_location.json | 53 + .../stable/procedural_manipulation.json | 50 + schemas/V_zeta/stable/pyraview.json | 177 ++ .../V_zeta/stable/reverse_correlation.json | 62 + .../V_zeta/stable/scalar_concentration.json | 36 + .../scalar_concentration_observation.json | 18 + schemas/V_zeta/stable/scalar_count.json | 39 + .../stable/scalar_count_observation.json | 18 + schemas/V_zeta/stable/scalar_current.json | 36 + .../stable/scalar_current_observation.json | 18 + schemas/V_zeta/stable/scalar_duration.json | 36 + .../stable/scalar_duration_observation.json | 18 + schemas/V_zeta/stable/scalar_frequency.json | 36 + .../stable/scalar_frequency_observation.json | 18 + schemas/V_zeta/stable/scalar_length.json | 36 + .../stable/scalar_length_observation.json | 18 + .../V_zeta/stable/scalar_manipulation.json | 32 + schemas/V_zeta/stable/scalar_mass.json | 36 + .../stable/scalar_mass_observation.json | 18 + schemas/V_zeta/stable/scalar_observation.json | 16 + schemas/V_zeta/stable/scalar_pressure.json | 36 + .../stable/scalar_pressure_observation.json | 18 + schemas/V_zeta/stable/scalar_score.json | 41 + .../stable/scalar_score_observation.json | 18 + schemas/V_zeta/stable/scalar_temperature.json | 36 + .../scalar_temperature_observation.json | 18 + schemas/V_zeta/stable/scalar_voltage.json | 36 + .../stable/scalar_voltage_observation.json | 18 + schemas/V_zeta/stable/scalar_volume.json | 36 + .../stable/scalar_volume_observation.json | 18 + schemas/V_zeta/stable/session.json | 88 + schemas/V_zeta/stable/session_extent.json | 82 + .../V_zeta/stable/session_in_a_dataset.json | 156 ++ .../stable/session_relative_reference.json | 45 + schemas/V_zeta/stable/simple_calc.json | 54 + schemas/V_zeta/stable/site2channelmap.json | 53 + schemas/V_zeta/stable/sorting_parameters.json | 129 + .../stable/spatial_frequency_tuning.json | 939 +++++++ .../stable/spatial_frequency_tuning_calc.json | 21 + schemas/V_zeta/stable/speed_tuning.json | 722 +++++ schemas/V_zeta/stable/speed_tuning_calc.json | 21 + schemas/V_zeta/stable/spike_clusters.json | 60 + .../stable/spike_extraction_parameters.json | 77 + ...ke_extraction_parameters_modification.json | 54 + .../spike_interface_sorting_outputs.json | 85 + schemas/V_zeta/stable/spikewaves.json | 73 + schemas/V_zeta/stable/stimulus_approach.json | 75 + schemas/V_zeta/stable/stimulus_bath.json | 22 + .../V_zeta/stable/stimulus_manipulation.json | 22 + schemas/V_zeta/stable/stimulus_parameter.json | 68 + .../stable/stimulus_parameter_table.json | 65 + .../V_zeta/stable/stimulus_presentation.json | 78 + schemas/V_zeta/stable/stimulus_response.json | 64 + .../stable/stimulus_response_scalar.json | 55 + .../stimulus_response_scalar_parameters.json | 23 + ...ulus_response_scalar_parameters_basic.json | 105 + .../V_zeta/stable/stimulus_tuningcurve.json | 246 ++ schemas/V_zeta/stable/subject.json | 78 + schemas/V_zeta/stable/subject_assertion.json | 80 + .../V_zeta/stable/subject_interaction.json | 82 + schemas/V_zeta/stable/syncgraph.json | 39 + schemas/V_zeta/stable/syncrule.json | 45 + schemas/V_zeta/stable/syncrule_mapping.json | 251 ++ .../stable/temperature_manipulation.json | 18 + .../stable/temporal_frequency_tuning.json | 939 +++++++ .../temporal_frequency_tuning_calc.json | 21 + schemas/V_zeta/stable/time_reference.json | 106 + schemas/V_zeta/stable/tuning_fit.json | 16 + schemas/V_zeta/stable/tuningcurve_calc.json | 105 + schemas/V_zeta/stable/utc_reference.json | 42 + schemas/V_zeta/stable/valid_interval.json | 241 ++ .../stable/vmneuralresponseresiduals.json | 47 + .../stable/vmspikefilteringparameters.json | 51 + schemas/V_zeta/stable/vmspikefit.json | 72 + schemas/V_zeta/stable/vmspikesummary.json | 75 + schemas/V_zeta/stable/zarr.json | 553 ++++ schemas/V_zeta/topics.json | 392 +++ schemas/V_zeta_SPEC.md | 231 ++ schemas/V_zeta_notes.md | 126 + tests/test_vzeta.py | 153 ++ 244 files changed, 23981 insertions(+) create mode 100644 schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/_files.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/_index.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/_universal_renames.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/hartley_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/ontology_image.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/ontology_label.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/ontology_table_row.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/probe_location.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/speed_tuning.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/subject_group.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/treatment.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/treatment_drug.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md create mode 100644 schemas/V_zeta/conversions/from_did_v1/virus_injection.md create mode 100644 schemas/V_zeta/deprecated/.gitkeep create mode 100644 schemas/V_zeta/deprecated/projectvar.json create mode 100644 schemas/V_zeta/deprecated/subject_group.json create mode 100644 schemas/V_zeta/deprecated/treatment.json create mode 100644 schemas/V_zeta/deprecated/treatment_drug.json create mode 100644 schemas/V_zeta/deprecated/treatment_transfer.json create mode 100644 schemas/V_zeta/deprecated/virus_injection.json create mode 100644 schemas/V_zeta/draft/.gitkeep create mode 100644 schemas/V_zeta/draft/dataseries_channel_map.json create mode 100644 schemas/V_zeta/draft/dataseries_data.json create mode 100644 schemas/V_zeta/draft/dataseries_observation.json create mode 100644 schemas/V_zeta/draft/dataseries_pyramid.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_cellranger_h5.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_counts_table.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_dia_report.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_gef.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_gem.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_h5ad.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_imzml.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_loom.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_maxquant.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_mtx.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_mzml.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_mztab.json create mode 100644 schemas/V_zeta/draft/expression_matrix_data_visium.json create mode 100644 schemas/V_zeta/draft/expression_observation.json create mode 100644 schemas/V_zeta/draft/imageseries_data.json create mode 100644 schemas/V_zeta/draft/imageseries_observation.json create mode 100644 schemas/V_zeta/draft/instrument.json create mode 100644 schemas/V_zeta/draft/reference_annotation_data.json create mode 100644 schemas/V_zeta/draft/reference_annotation_data_gff3.json create mode 100644 schemas/V_zeta/draft/reference_annotation_data_gtf.json create mode 100644 schemas/V_zeta/draft/reference_data.json create mode 100644 schemas/V_zeta/draft/reference_sequence_data.json create mode 100644 schemas/V_zeta/draft/reference_sequence_data_fasta_genome.json create mode 100644 schemas/V_zeta/draft/reference_sequence_data_fasta_protein.json create mode 100644 schemas/V_zeta/draft/reference_sequence_data_fasta_transcriptome.json create mode 100644 schemas/V_zeta/draft/sequence_read_data.json create mode 100644 schemas/V_zeta/draft/sequence_read_data_bam.json create mode 100644 schemas/V_zeta/draft/sequence_read_data_cram.json create mode 100644 schemas/V_zeta/draft/sequence_read_data_fastq.json create mode 100644 schemas/V_zeta/draft/spatial_expression_observation.json create mode 100644 schemas/V_zeta/draft/timeseries_data.json create mode 100644 schemas/V_zeta/draft/timeseries_data_binary.json create mode 100644 schemas/V_zeta/draft/timeseries_data_csv.json create mode 100644 schemas/V_zeta/draft/timeseries_data_edf.json create mode 100644 schemas/V_zeta/draft/timeseries_observation.json create mode 100644 schemas/V_zeta/examples/.gitkeep create mode 100644 schemas/V_zeta/examples/scalar_temperature_observation_series.json create mode 100644 schemas/V_zeta/examples/utc_reference_grid.json create mode 100644 schemas/V_zeta/index.json create mode 100644 schemas/V_zeta/microschemas/_DESIGN.md create mode 100644 schemas/V_zeta/stable/CURIE_lookups_meta.json create mode 100644 schemas/V_zeta/stable/annotation.json create mode 100644 schemas/V_zeta/stable/app.json create mode 100644 schemas/V_zeta/stable/base.json create mode 100644 schemas/V_zeta/stable/bath.json create mode 100644 schemas/V_zeta/stable/binaryseries_parameters.json create mode 100644 schemas/V_zeta/stable/binnedspikeratevm.json create mode 100644 schemas/V_zeta/stable/biological_transfer.json create mode 100644 schemas/V_zeta/stable/calculator.json create mode 100644 schemas/V_zeta/stable/categorical_observation.json create mode 100644 schemas/V_zeta/stable/contrast_sensitivity_calc.json create mode 100644 schemas/V_zeta/stable/contrast_tuning.json create mode 100644 schemas/V_zeta/stable/contrast_tuning_calc.json create mode 100644 schemas/V_zeta/stable/control_stimulus_ids.json create mode 100644 schemas/V_zeta/stable/daqmetadatareader.json create mode 100644 schemas/V_zeta/stable/daqmetadatareader_epochdata_ingested.json create mode 100644 schemas/V_zeta/stable/daqreader.json create mode 100644 schemas/V_zeta/stable/daqreader_epochdata_ingested.json create mode 100644 schemas/V_zeta/stable/daqreader_mfdaq_epochdata_ingested.json create mode 100644 schemas/V_zeta/stable/daqreader_ndr.json create mode 100644 schemas/V_zeta/stable/daqsystem.json create mode 100644 schemas/V_zeta/stable/dataset_remote.json create mode 100644 schemas/V_zeta/stable/dataset_session_info.json create mode 100644 schemas/V_zeta/stable/demo_ndi.json create mode 100644 schemas/V_zeta/stable/demo_ndi_mock.json create mode 100644 schemas/V_zeta/stable/derivation.json create mode 100644 schemas/V_zeta/stable/did_schema_meta.json create mode 100644 schemas/V_zeta/stable/directory.json create mode 100644 schemas/V_zeta/stable/distance_metadata.json create mode 100644 schemas/V_zeta/stable/electrode_offset_voltage.json create mode 100644 schemas/V_zeta/stable/element.json create mode 100644 schemas/V_zeta/stable/element_epoch.json create mode 100644 schemas/V_zeta/stable/environmental_manipulation.json create mode 100644 schemas/V_zeta/stable/ephys_zarr.json create mode 100644 schemas/V_zeta/stable/epoch_bounded_reference.json create mode 100644 schemas/V_zeta/stable/epoch_relative_reference.json create mode 100644 schemas/V_zeta/stable/epochclocktimes.json create mode 100644 schemas/V_zeta/stable/epochfiles_ingested.json create mode 100644 schemas/V_zeta/stable/epochid.json create mode 100644 schemas/V_zeta/stable/event_bounded_reference.json create mode 100644 schemas/V_zeta/stable/event_relative_reference.json create mode 100644 schemas/V_zeta/stable/filenavigator.json create mode 100644 schemas/V_zeta/stable/filter.json create mode 100644 schemas/V_zeta/stable/fitcurve.json create mode 100644 schemas/V_zeta/stable/frequency_manipulation.json create mode 100644 schemas/V_zeta/stable/generic_file.json create mode 100644 schemas/V_zeta/stable/generic_scalar.json create mode 100644 schemas/V_zeta/stable/generic_scalar_manipulation.json create mode 100644 schemas/V_zeta/stable/generic_scalar_observation.json create mode 100644 schemas/V_zeta/stable/group_assignment.json create mode 100644 schemas/V_zeta/stable/hartley_calc.json create mode 100644 schemas/V_zeta/stable/hartley_reverse_correlation.json create mode 100644 schemas/V_zeta/stable/image.json create mode 100644 schemas/V_zeta/stable/image_collection.json create mode 100644 schemas/V_zeta/stable/image_stack.json create mode 100644 schemas/V_zeta/stable/image_stack_parameters.json create mode 100644 schemas/V_zeta/stable/image_zarr.json create mode 100644 schemas/V_zeta/stable/injection.json create mode 100644 schemas/V_zeta/stable/interaction_purpose.json create mode 100644 schemas/V_zeta/stable/jrclust_clusters.json create mode 100644 schemas/V_zeta/stable/manipulation.json create mode 100644 schemas/V_zeta/stable/measurement.json create mode 100644 schemas/V_zeta/stable/metadata_editor.json create mode 100644 schemas/V_zeta/stable/mock.json create mode 100644 schemas/V_zeta/stable/ndi_reserved_keys.json create mode 100644 schemas/V_zeta/stable/neuron_extracellular.json create mode 100644 schemas/V_zeta/stable/ngrid.json create mode 100644 schemas/V_zeta/stable/observation.json create mode 100644 schemas/V_zeta/stable/oneepoch.json create mode 100644 schemas/V_zeta/stable/ontology_image.json create mode 100644 schemas/V_zeta/stable/ontology_label.json create mode 100644 schemas/V_zeta/stable/ontology_table_row.json create mode 100644 schemas/V_zeta/stable/openminds.json create mode 100644 schemas/V_zeta/stable/openminds_element.json create mode 100644 schemas/V_zeta/stable/openminds_stimulus.json create mode 100644 schemas/V_zeta/stable/openminds_subject.json create mode 100644 schemas/V_zeta/stable/oridirtuning_calc.json create mode 100644 schemas/V_zeta/stable/orientation_direction_tuning.json create mode 100644 schemas/V_zeta/stable/pharmacological_manipulation.json create mode 100644 schemas/V_zeta/stable/placement.json create mode 100644 schemas/V_zeta/stable/position_metadata.json create mode 100644 schemas/V_zeta/stable/pressure_manipulation.json create mode 100644 schemas/V_zeta/stable/probe_geometry.json create mode 100644 schemas/V_zeta/stable/probe_location.json create mode 100644 schemas/V_zeta/stable/procedural_manipulation.json create mode 100644 schemas/V_zeta/stable/pyraview.json create mode 100644 schemas/V_zeta/stable/reverse_correlation.json create mode 100644 schemas/V_zeta/stable/scalar_concentration.json create mode 100644 schemas/V_zeta/stable/scalar_concentration_observation.json create mode 100644 schemas/V_zeta/stable/scalar_count.json create mode 100644 schemas/V_zeta/stable/scalar_count_observation.json create mode 100644 schemas/V_zeta/stable/scalar_current.json create mode 100644 schemas/V_zeta/stable/scalar_current_observation.json create mode 100644 schemas/V_zeta/stable/scalar_duration.json create mode 100644 schemas/V_zeta/stable/scalar_duration_observation.json create mode 100644 schemas/V_zeta/stable/scalar_frequency.json create mode 100644 schemas/V_zeta/stable/scalar_frequency_observation.json create mode 100644 schemas/V_zeta/stable/scalar_length.json create mode 100644 schemas/V_zeta/stable/scalar_length_observation.json create mode 100644 schemas/V_zeta/stable/scalar_manipulation.json create mode 100644 schemas/V_zeta/stable/scalar_mass.json create mode 100644 schemas/V_zeta/stable/scalar_mass_observation.json create mode 100644 schemas/V_zeta/stable/scalar_observation.json create mode 100644 schemas/V_zeta/stable/scalar_pressure.json create mode 100644 schemas/V_zeta/stable/scalar_pressure_observation.json create mode 100644 schemas/V_zeta/stable/scalar_score.json create mode 100644 schemas/V_zeta/stable/scalar_score_observation.json create mode 100644 schemas/V_zeta/stable/scalar_temperature.json create mode 100644 schemas/V_zeta/stable/scalar_temperature_observation.json create mode 100644 schemas/V_zeta/stable/scalar_voltage.json create mode 100644 schemas/V_zeta/stable/scalar_voltage_observation.json create mode 100644 schemas/V_zeta/stable/scalar_volume.json create mode 100644 schemas/V_zeta/stable/scalar_volume_observation.json create mode 100644 schemas/V_zeta/stable/session.json create mode 100644 schemas/V_zeta/stable/session_extent.json create mode 100644 schemas/V_zeta/stable/session_in_a_dataset.json create mode 100644 schemas/V_zeta/stable/session_relative_reference.json create mode 100644 schemas/V_zeta/stable/simple_calc.json create mode 100644 schemas/V_zeta/stable/site2channelmap.json create mode 100644 schemas/V_zeta/stable/sorting_parameters.json create mode 100644 schemas/V_zeta/stable/spatial_frequency_tuning.json create mode 100644 schemas/V_zeta/stable/spatial_frequency_tuning_calc.json create mode 100644 schemas/V_zeta/stable/speed_tuning.json create mode 100644 schemas/V_zeta/stable/speed_tuning_calc.json create mode 100644 schemas/V_zeta/stable/spike_clusters.json create mode 100644 schemas/V_zeta/stable/spike_extraction_parameters.json create mode 100644 schemas/V_zeta/stable/spike_extraction_parameters_modification.json create mode 100644 schemas/V_zeta/stable/spike_interface_sorting_outputs.json create mode 100644 schemas/V_zeta/stable/spikewaves.json create mode 100644 schemas/V_zeta/stable/stimulus_approach.json create mode 100644 schemas/V_zeta/stable/stimulus_bath.json create mode 100644 schemas/V_zeta/stable/stimulus_manipulation.json create mode 100644 schemas/V_zeta/stable/stimulus_parameter.json create mode 100644 schemas/V_zeta/stable/stimulus_parameter_table.json create mode 100644 schemas/V_zeta/stable/stimulus_presentation.json create mode 100644 schemas/V_zeta/stable/stimulus_response.json create mode 100644 schemas/V_zeta/stable/stimulus_response_scalar.json create mode 100644 schemas/V_zeta/stable/stimulus_response_scalar_parameters.json create mode 100644 schemas/V_zeta/stable/stimulus_response_scalar_parameters_basic.json create mode 100644 schemas/V_zeta/stable/stimulus_tuningcurve.json create mode 100644 schemas/V_zeta/stable/subject.json create mode 100644 schemas/V_zeta/stable/subject_assertion.json create mode 100644 schemas/V_zeta/stable/subject_interaction.json create mode 100644 schemas/V_zeta/stable/syncgraph.json create mode 100644 schemas/V_zeta/stable/syncrule.json create mode 100644 schemas/V_zeta/stable/syncrule_mapping.json create mode 100644 schemas/V_zeta/stable/temperature_manipulation.json create mode 100644 schemas/V_zeta/stable/temporal_frequency_tuning.json create mode 100644 schemas/V_zeta/stable/temporal_frequency_tuning_calc.json create mode 100644 schemas/V_zeta/stable/time_reference.json create mode 100644 schemas/V_zeta/stable/tuning_fit.json create mode 100644 schemas/V_zeta/stable/tuningcurve_calc.json create mode 100644 schemas/V_zeta/stable/utc_reference.json create mode 100644 schemas/V_zeta/stable/valid_interval.json create mode 100644 schemas/V_zeta/stable/vmneuralresponseresiduals.json create mode 100644 schemas/V_zeta/stable/vmspikefilteringparameters.json create mode 100644 schemas/V_zeta/stable/vmspikefit.json create mode 100644 schemas/V_zeta/stable/vmspikesummary.json create mode 100644 schemas/V_zeta/stable/zarr.json create mode 100644 schemas/V_zeta/topics.json create mode 100644 schemas/V_zeta_SPEC.md create mode 100644 schemas/V_zeta_notes.md create mode 100644 tests/test_vzeta.py diff --git a/README.md b/README.md index c5a648c..c49697e 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ Each field definition object contains: `name`, `type`, `blank_value`, `default_v See [schemas/V_alpha_SPEC.md](schemas/V_alpha_SPEC.md) for the V_alpha specification and [schemas/V_beta_SPEC.md](schemas/V_beta_SPEC.md) for the V_beta specification (V_alpha plus snake_case naming requirements). +The current sandbox iteration is **V_zeta** (see [schemas/V_zeta_SPEC.md](schemas/V_zeta_SPEC.md)), which implements **Brainstorm I** from the `ndi-next-steps` "Summer 2026 / 1_Ingestion" thread: a single `subject_interaction` spine (`subject_id`, a shaped `time_reference`, `method`, `variable`, `target_structure`), direction carried by the empty `observation` / `manipulation` classes, observation leaves named by data-type (shape) with identity on the `variable` ontology term, and the `dataseries_observation` branch. V_zeta supersedes V_epsilon (Brainstorm E, retained as an archived reference). Within each `V_*` directory, `index.json` is the resolution source of truth. + ## Directory layout Each document type is a directory under `schemas/` containing its schema definition: diff --git a/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md b/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md new file mode 100644 index 0000000..82bd776 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md @@ -0,0 +1,92 @@ +# Conversion: did_v1 → V_delta — `` + +> Copy this file to `.md` (one file per V_delta document type that +> has a `did_v1` analog) and fill in every section. Sections that genuinely do +> not apply should be retained with the text `N/A` so reviewers can see they +> were considered, not skipped. + +## Identity + +- **V_delta `class_name`:** `` +- **V_delta tier:** `stable` | `draft` | `deprecated` +- **V_delta schema path:** `schemas/V_delta//.json` +- **did_v1 source:** repo + path (or "synthesized from MATLAB class + `<...>`") +- **Status:** `drafted` | `reviewed` | `applied-in-tooling` | `frozen` + +## Summary + +One or two sentences. What is this document type, and what is the +high-level shape of the change between did_v1 and V_delta? If there is no +change, say so. + +## Field mapping + +Use one row per field. Cover every field in both the did_v1 source and the +V_delta target — including dropped fields (V_delta column blank) and new +fields (did_v1 column blank). + +| did_v1 field | V_delta field | Transformation | Notes | +|---|---|---|---| +| `` | `` | rename | | +| `` | `` | type change: `` → `` | Validation rules below | +| `` | — | dropped | Reason | +| — | `` | new field | Default value: `<...>` | +| `` | `` | identity | | + +## Transformations in detail + +For any row above whose transformation is non-trivial (type change, unit +conversion, structural reshape, value mapping), describe the rule here in +enough detail that a reader could implement it without consulting the +author. Cite the relevant spec section if applicable. + +## Default values for new fields + +If V_delta introduces required fields that did_v1 documents do not carry, +list the default each migrated document gets, and the reasoning. Distinguish +between "constant default" and "computed from other fields." + +## Worked example + +A minimal but realistic did_v1 document and the V_delta document it converts +to. These pairs double as unit-test fixtures — keep them small enough to +read by eye. + +### Before (did_v1) + +```json +{ + "document_class": { "class_name": "", "schema_version": "did_v1", ... }, + ... +} +``` + +### After (V_delta) + +```json +{ + "document_class": { "class_name": "", "class_version": "...", "schema_version": "V_delta", ... }, + ... +} +``` + +## File handling + +If this document type carries or references files (binary blobs, external +paths, hash-addressed content), describe how those are handled on migration. +For anything that follows the generic rules, link to `_files.md` instead of +restating them here. Document only the type-specific behavior. + +## Open questions + +Anything still undecided. Pose as concrete questions, not vague concerns. +Each question should be resolvable by a domain owner without needing to +re-read this whole doc. + +## Cross-references + +- Related document types whose conversions interact with this one: +- did_v1 source-of-truth path(s): +- V_delta schema file: +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/_files.md b/schemas/V_zeta/conversions/from_did_v1/_files.md new file mode 100644 index 0000000..50817af --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/_files.md @@ -0,0 +1,71 @@ +# File handling: did_v1 → V_delta + +> This is the **generalized** file-handling specification for the +> did_v1 → V_delta migration. Per-document-type conversion docs should +> link here for anything that follows these generic rules, and only +> document type-specific behavior locally. + +This file is a **skeleton**. Sections marked `TODO` need domain input +before the migration engine can be implemented. + +## Scope + +What counts as a "file" in this document? In DID terminology, any binary +blob, external path, or hash-addressed content that a document instance +references (rather than embeds inline). Examples to consider: + +- TODO: enumerate the file-reference fields that appear across did_v1 + document types (e.g., raw recording files, processed outputs, image + stacks, zarr archives). + +## did_v1 file-reference shape + +TODO: describe how did_v1 documents reference files today — field names, +path formats (absolute? relative? hash-addressed?), whether integrity is +verified, and what container/database layout assumptions exist. + +## V_delta file-reference shape + +TODO: describe the target file-reference shape under V_delta. Anchor +choices in `V_delta_SPEC.md` once finalized. + +## Migration rules + +For each migration scenario, specify the rule. Stubs follow. + +### Path rewriting + +TODO: when did_v1 paths are absolute and the V_delta layout requires +relative or hash-addressed paths, how are old paths translated? What +happens if the original file is no longer on disk? + +### Integrity verification + +TODO: does V_delta require a hash on file references? If so, how is it +computed during migration, and what happens on hash mismatch (fail, +warn, or annotate)? + +### Orphan files + +TODO: files that are on disk but no document references them, and +references that point at files no longer on disk. Specify the policy +for each. + +### Large file handling + +TODO: any size-based branching (e.g., inline vs. external) at the +V_delta layer. + +### Container/database boundaries + +TODO: when a document is migrated across databases (or out of one and +into a fresh V_delta container), how are file references rewritten? + +## Open questions + +- Are file references stored on the document instance itself, or on a + side index? +- Should the migration engine ever copy file content, or only update + references? +- What is the policy for files referenced by both a did_v1 document and + a V_delta document during a transitional period? diff --git a/schemas/V_zeta/conversions/from_did_v1/_index.md b/schemas/V_zeta/conversions/from_did_v1/_index.md new file mode 100644 index 0000000..88f3160 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/_index.md @@ -0,0 +1,76 @@ +# did_v1 → V_delta conversion index + +This file enumerates every V_delta document type that needs a conversion +doc from `did_v1`, and tracks its status. Update this index whenever a +new conversion doc is added or its status changes. + +The corresponding template is [`_TEMPLATE.md`](_TEMPLATE.md). The shared +file-handling rules are in [`_files.md`](_files.md). Cross-cutting renames +that apply to **every** did_v1 → V_delta migration (underscore-prefix +removal, snake_case, ontology-annotation reshape, superclass-reference +reshape, class-scoped property blocks, maturity-level enum) are in +[`_universal_renames.md`](_universal_renames.md). Per-class markdowns +assume those renames have been applied and document only the per-class +field-level changes on top. + +## Status legend + +- **none** — no conversion doc exists yet +- **drafted** — markdown exists, awaiting domain review +- **reviewed** — domain-reviewed, awaiting implementation +- **applied-in-tooling** — implemented in the migration engine in + `DID-matlab`, but not yet locked +- **frozen** — implemented, tested against real datasets, locked for + V_delta +- **no-conversion-needed** — explicitly marked as having no did_v1 + predecessor + +## Conversions + +| V_delta class_name | did_v1 source | Status | Doc | +|---|---|---|---| +| `contrast_tuning` | NDIcalc-vis-matlab `vision/contrast_tuning` | drafted | [contrast_tuning.md](contrast_tuning.md) | +| `contrast_tuning_calc` | NDIcalc-vis-matlab `calc/contrasttuning_calc` (renamed) | drafted | [contrast_tuning_calc.md](contrast_tuning_calc.md) | +| `contrast_sensitivity_calc` | NDIcalc-vis-matlab `calc/contrastsensitivity_calc` (renamed) | drafted | [contrast_sensitivity_calc.md](contrast_sensitivity_calc.md) | +| `spatial_frequency_tuning` | NDIcalc-vis-matlab `vision/spatial_frequency_tuning` | drafted | [spatial_frequency_tuning.md](spatial_frequency_tuning.md) | +| `spatial_frequency_tuning_calc` | NDIcalc-vis-matlab `calc/spatial_frequency_tuning_calc` | drafted | [spatial_frequency_tuning_calc.md](spatial_frequency_tuning_calc.md) | +| `temporal_frequency_tuning` | NDIcalc-vis-matlab `vision/temporal_frequency_tuning` | drafted | [temporal_frequency_tuning.md](temporal_frequency_tuning.md) | +| `temporal_frequency_tuning_calc` | NDIcalc-vis-matlab `calc/temporal_frequency_tuning_calc` | drafted | [temporal_frequency_tuning_calc.md](temporal_frequency_tuning_calc.md) | +| `speed_tuning` | NDIcalc-vis-matlab `vision/speed_tuning` | drafted | [speed_tuning.md](speed_tuning.md) | +| `speed_tuning_calc` | NDIcalc-vis-matlab `calc/speedtuning_calc` (renamed) | drafted | [speed_tuning_calc.md](speed_tuning_calc.md) | +| `orientation_direction_tuning` | NDIcalc-vis-matlab `stimulus/vision/oridir/orientation_direction_tuning` | drafted | [orientation_direction_tuning.md](orientation_direction_tuning.md) | +| `oridirtuning_calc` | NDIcalc-vis-matlab `calc/oridirtuning_calc` | drafted | [oridirtuning_calc.md](oridirtuning_calc.md) | +| `reverse_correlation` | NDIcalc-vis-matlab `neuro/reverse_correlation` | drafted | [reverse_correlation.md](reverse_correlation.md) | +| `hartley_reverse_correlation` | NDIcalc-vis-matlab `neuro/hartley_reverse_correlation` | drafted | [hartley_reverse_correlation.md](hartley_reverse_correlation.md) | +| `hartley_calc` | NDIcalc-vis-matlab `calc/hartley_calc` | drafted | [hartley_calc.md](hartley_calc.md) | +| `probe_location` | legacy NDI/DID `probe_location` (V_alpha shape) | drafted | [probe_location.md](probe_location.md) | +| `treatment` | legacy NDI/DID `treatment` (V_alpha shape) | drafted | [treatment.md](treatment.md) | +| `treatment` → manipulation tiers (Brainstorm E **split**) | legacy `treatment` → `injection`/`bath`/`procedural_manipulation`/`temperature_manipulation`/`environmental_manipulation` (+ out-of-tier) | drafted | [treatment.md](treatment.md) | +| `ontology_table_row` → observation tiers (Brainstorm E **split**, 1→N) | legacy `ontology_table_row` → scalar/categorical observation property classes (+ out-of-tier) | drafted | [ontology_table_row.md](ontology_table_row.md) | +| `subject_group` → `subject` (`is_group`) (Brainstorm E **fold**) | legacy `subject_group` → `subject` flagged `is_group` (+ `group_assignment` in NDI layer) | drafted | [subject_group.md](subject_group.md) | +| `treatment_drug` → `injection` (`kind: drug`) (Brainstorm E **fold**) | legacy `treatment_drug` → `injection` (mixture from `mixture_table`) | drafted | [treatment_drug.md](treatment_drug.md) | +| `virus_injection` → `injection` (`kind: virus`) (Brainstorm E **fold**) | legacy `virus_injection` → `injection` (virus+dilution in mixture) | drafted | [virus_injection.md](virus_injection.md) | +| `treatment_transfer` → `biological_transfer` (Brainstorm E **fold**) | legacy `treatment_transfer` → `biological_transfer` (recipient→subject, donor carried) | drafted | [treatment_transfer.md](treatment_transfer.md) | +| `ontology_image` | legacy NDI/DID `ontologyImage` (V_alpha shape) | drafted | [ontology_image.md](ontology_image.md) | +| `ontology_label` | legacy NDI/DID `ontologyLabel` (V_alpha shape) | drafted | [ontology_label.md](ontology_label.md) | + +## Notes + +- **Not migrated:** `stimloopsplitter_calc` (deprecated per domain owner + decision; not added to V_delta). +- **Already in V_delta from earlier set versions** (no `did_v1` conversion + added in this PR): `tuningcurve_calc`, `stimulus_tuningcurve`, `ngrid`. + These have no NDIcalc-vis-matlab v1 predecessor in `ndi_common/`; if any + need a separate `did_v1` source resurrected later, add their conversions + then. + +## Conventions + +- One conversion markdown per V_delta document type. If a V_delta class + has multiple did_v1 sources, document the merge in a single file + rather than splitting. +- If a V_delta class is genuinely new (no did_v1 ancestor), create + `_no_conversion_needed.md` with a one-line reason and add + the row with status `no-conversion-needed`. +- File-handling behavior that follows the generic rules in `_files.md` + should be linked, not restated. diff --git a/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md b/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md new file mode 100644 index 0000000..c3bed00 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md @@ -0,0 +1,325 @@ +# Universal renames: did_v1 → V_delta + +> These transformations apply to **every** did_v1 document and to +> **every** schema file as it is migrated to V_delta. Per-class +> conversion markdowns (under `conversions/from_did_v1/.md`) +> assume these renames have been applied and document only the +> per-class field-level changes on top. +> +> `_files.md` is a sibling document covering generic file-reference +> handling, which is a separate concern from these renames. + +For each rule below the arrow direction is `did_v1 → V_delta`. + +## 1. Underscore-prefix structural keys are unprefixed + +V_alpha-era schema files (`schemas/V_alpha/*.json`) decorated every +structural key with a leading underscore: `_classname`, +`_class_version`, `_maturity_level`, `_superclasses`, `_depends_on`, +`_file`, `_fields`, and inside each field-spec entry `_name`, +`_blank_value`, `_default_value`, `_mustBeNonEmpty`, `_mustBeScalar`, +`_mustNotHaveNaN`, `_queryable`, `_ontology`, `_documentation`, +`_constraints`. The leading underscore was a sigil to distinguish +DID structural keys from user payload. + +V_gamma dropped the sigil from every structural key and V_delta +inherits that convention. The rename is mechanical: + +| did_v1 (V_alpha) key | V_delta key | +|---|---| +| `_classname` | `class_name` *(also moved under `document_class`; see §3)* | +| `_class_version` | `class_version` *(also moved under `document_class`; see §3)* | +| `_maturity_level` | `maturity_level` *(also moved under `document_class`; see §3)* | +| `_superclasses` | `superclasses` *(also moved under `document_class`; see §3)* | +| `_depends_on` | `depends_on` | +| `_file` | `file` | +| `_fields` | `fields` | +| `_name` (inside `_fields[i]`) | `name` | +| `_blank_value` | `blank_value` | +| `_default_value` | `default_value` | +| `_mustBeNonEmpty` | `mustBeNonEmpty` | +| `_mustBeScalar` | `mustBeScalar` | +| `_mustNotHaveNaN` | `mustNotHaveNaN` | +| `_queryable` | `queryable` | +| `_ontology` | `ontology` | +| `_documentation` | `documentation` | +| `_constraints` | `constraints` | + +`type` was already unprefixed in V_alpha and is unchanged. + +In `_depends_on[i]` and `_file[i]` the same rule applies to inner keys +(`_name` → `name`, `_documentation` → `documentation`, +`_must_refer_to_document_class` → `must_refer_to_document_class`, +`_mustBeNonEmpty` → `mustBeNonEmpty`). + +## 2. `_classname` is now `document_class.class_name` + +Rule §1 strips the underscore prefix; this rule additionally relocates +the class-identity keys into a nested `document_class` block. The full +rewrite is: + +```text +did_v1 V_delta +------ ------- +"_classname": "x" → "document_class": { +"_class_version": "1.0.0" → "class_name": "x", +"_maturity_level": "..." → "class_version": "1.0.0", +"_superclasses": [ ... ] → "maturity_level": "stable", + "superclasses": [ ... ] + } +``` + +`depends_on`, `file`, and `fields` remain top-level — `document_class` +is for class-identity metadata only. This relocation was introduced in +V_gamma; see `V_gamma_notes.md` § "Class metadata under a top-level +`document_class` header" for the rationale. + +For the `maturity_level` value mapping, see §5. + +## 3. Snake_case for class names, field names, and filenames + +V_alpha allowed camelCase identifiers (e.g., `ontologyImage`, +`SpikeInterfaceSortingOutputs`, `ontologyName`). V_beta and later +require all class names, field names, and filenames to match +`^[a-z][a-z0-9_]*$`. The per-class conversion markdowns list any +identifier renames they trigger. Common cases inherited from V_beta: + +| did_v1 identifier | V_delta identifier | +|---|---| +| `ontologyImage` (class) | `ontology_image` | +| `ontologyLabel` (class) | `ontology_label` | +| `ontologyTableRow` (class) | `ontology_table_row` | +| `imageCollection` (class) | `image_collection` | +| `imageStack` (class) | `image_stack` | +| `imageStack_parameters` (class) | `image_stack_parameters` | +| `demoNDI` (class) | `demo_ndi` | +| `demoNDIMock` (class) | `demo_ndi_mock` | +| `SpikeInterfaceSortingOutputs` (class) | `spike_interface_sorting_outputs` | +| `ontologyName` (field) | `ontology_name` | +| `ontologyNodes` (field) | `ontology_nodes` | +| `dataType` (field) | `data_type` | +| `nativeRate` (field) | `native_rate` | +| `nativeStartTime` (field) | `native_start_time` | +| `decimationLevels` (field) | `decimation_levels` | +| `decimationSamplingRates` (field) | `decimation_sampling_rates` | +| `decimationStartTimes` (field) | `decimation_start_times` | +| `variableNames` (field) | `variable_names` | + +See `V_beta_notes.md` for the full V_alpha → V_beta rename table. +Filenames track the class name (one schema file per class, named +`.json`). + +## 4. Superclass references drop the schema-path token + +V_alpha entries in `_superclasses` were two-key objects whose second +key was a `$NDISCHEMAPATH`-prefixed path string: + +```json +{ "_classname": "base", "_schema": "$NDISCHEMAPATH/base/schema.json" } +``` + +V_gamma renamed the keys (§1) and dropped the `$NDISCHEMAPATH` prefix +convention while still permitting an explicit `schema` path key. +V_delta removes the `schema` key entirely: a superclass reference in a +**schema file** is `{"class_name": ""}` only. The validator +resolves the superclass by `class_name` through +`schemas/V_delta/index.json`. The meta-schema enforces this via +`additionalProperties: false` on superclass references. + +```text +did_v1 V_delta +{ "_classname": "base", { "class_name": "base" } + "_schema": "$NDISCHEMAPATH/base/schema.json" } +``` + +In **document instances**, the superclass-reference key set is +different — `class_name` plus `class_version` (a pinned snapshot of +the inheritance chain). That convention was set in V_gamma and is +unchanged in V_delta. See `V_gamma_SPEC.md` § "Schema-reference forms". + +## 5. `maturity_level` enum is `{stable, draft, deprecated}` + +V_alpha allowed `_maturity_level ∈ {"work_in_progress", "mature"}`. +V_delta replaces the vocabulary with `{stable, draft, deprecated}` +and additionally requires that the value match the tier-folder a +schema file lives in (`schemas/V_delta//`). + +Migration mapping for did_v1 documents and schemas carried into +V_delta: + +| did_v1 `_maturity_level` | V_delta `maturity_level` | +|---|---| +| `"mature"` | `"stable"` | +| `"work_in_progress"` | `"stable"` *(default placement; a separate domain-review pass may re-tier specific schemas to `draft` or `deprecated`)* | + +The meta-schema (`did_schema_meta.json`) enforces the V_delta enum. +See `V_delta_SPEC.md` § 3. + +## 6. Ontology annotation reshape (4-key → 2-key) + +In V_alpha, the field-level `_ontology` slot was a four-key object: + +```json +"_ontology": { + "_namespace": "iao", + "_term": "0000219", + "_name": "denotes", + "_uri": "http://purl.obolibrary.org/obo/IAO_0000219" +} +``` + +V_gamma collapsed this to a two-key CURIE-based shape: + +```json +"ontology": { + "node": "iao:0000219", + "name": "denotes" +} +``` + +V_delta inherits the V_gamma shape. The rewrite rule is: + + node = ":<_term>" + name = <_name> + +The `_uri` field is dropped; consumers reconstruct the URI through +`CURIE_lookups_meta.json`. `ontology: null` (annotation absent) is +still valid. + +The ontology-annotation reshape is a schema-file-syntax change — it +describes the *field*, not the documents validated against the field +— and so does **not** trigger a `class_version` bump. See +`V_gamma_notes.md` § "Annotation-shape change is not a version bump". + +## 7. Class-scoped property blocks (document instances) + +V_gamma re-established and V_delta inherits the **class-scoped +property block** wire shape for document instances. A document is +structured as: + +```text +{ + "document_class": { ... }, ← class-identity header + "depends_on": [ ... ], ← cross-document references + "": { ... }, ← one block per class in the + "": { ... }, inheritance chain, keyed by + ... the *declaring* class's name +} +``` + +Every field declared by class `X` lives inside the document's `"X": +{ ... }` block. Inherited fields are **not** copied into the +subclass's block: they stay in the block of the class that declared +them. A class with zero declared fields still contributes an empty +block `{}`. + +V_alpha already used class-scoped blocks (with a separate +`property_listname` knob); V_gamma collapsed that down so the block +key is the `class_name` verbatim. V_delta keeps the V_gamma form. + +Migration consequences: + +- Every did_v1 document is reshaped so its top-level keys are exactly + `document_class`, `depends_on`, and one block per class in + `{concrete class} ∪ {transitive superclasses}` (e.g., for a + `probe_location` document: `base` and `probe_location`). +- The `base`-class fields (`id`, `session_id`, `name`, `datestamp`) + live under the `base` block: paths `base.id`, `base.session_id`, + `base.name`, `base.datestamp`. Any did_v1 document that carried + these at the document's top level is rewritten into the `base` + block; documents that already carried them under `base` are + unchanged. +- The `property_listname` knob from V_alpha is removed; the block + key must equal the declaring class's `class_name` exactly. + +See `V_gamma_SPEC.md` § "JSON Format: Document Instances" for the +authoritative description. + +## 8. `class_version` semantics under V_delta sandbox + +V_delta is a sandbox set version (like V_gamma was); `class_version` +bumps are deferred until the V1 freeze. Schemas in +`schemas/V_delta/stable/` whose document shape differs from did_v1 +nonetheless declare `class_version: "1.0.0"`. The +non-triviality of the migration for those classes is captured in this +directory (one markdown per class) rather than in a version flag. + +This rule is purely V_delta-side bookkeeping; it imposes no +transformation on the did_v1 document being migrated. + +## 9. `depends_on(k).id` → `depends_on(k).document_id` + +Every did_v1 document carries cross-document references as an array of +two-key (sometimes three-key) entries: + +```json +"_depends_on": [ + { "_name": "probe_id", "_id": "aabb...", "_version": "..." }, + ... +] +``` + +After rule §1 strips the underscore prefix the keys are `name`, `id`, +and optionally `version`. V_delta renames `id` → `document_id` and +drops `version` entirely. The result on every V_delta document +instance is: + +```json +"depends_on": [ + { "name": "probe_id", "document_id": "aabb..." }, + ... +] +``` + +The rename motivation: `id` collided with the top-level +`base.id` field for the documents themselves; the earlier V_delta +draft used `value`, which avoided the collision but was uninformative +("a value of what?"). `document_id` says exactly what the field is — +a `did_uid` referring to another document — and the explicit +`document_` prefix disambiguates from any future id-shaped fields the +schema may add. + +`version` is dropped because V_delta does not support per-document +version branches; cross-document references resolve to whichever +version of the target document is current in the database. + +| did_v1 entry key | V_delta entry key | +|---|---| +| `id` | `document_id` | +| `version` | _(dropped)_ | +| `name` | `name` *(unchanged)* | + +The universal-rename pass in `did2.convert.universalRenames` +(`renameDependsOnEntries`) implements this rule. It also tolerates +the earlier V_delta-draft key `value` as a synonym for `id` so +already-migrated corpora convert forward to `document_id` on next +read. + +## 10. `schema_version` on every document + +Every V_delta document carries a `schema_version` string naming the +schema set under which it is interpreted. Established values: + +- `"V_delta"` — documents authored against V_delta +- `"did_v1"` — legacy documents still carrying the did_v1 shape, or + documents in a holding state during migration + +`schema_version` lives at `document_class.schema_version` (a sibling +of `class_name`, `class_version`, `superclasses`), not as a `base` +field. It identifies the overarching schema set, not a property of +any one class, so it isn't declared in any per-class `fields` array +and isn't validated by class-field validation. + +The migrator sets `body.document_class.schema_version = "V_delta"` +on every output document. It is the dispatcher short-circuit signal: +a document whose `document_class.schema_version` is already +`"V_delta"` is left untouched (modulo the structural padding in +`ensureClassBlocks`). + +## Cross-references + +- File-reference handling (generic): [`_files.md`](_files.md) +- Conversion index: [`_index.md`](_index.md) +- Conversion template: [`_TEMPLATE.md`](_TEMPLATE.md) +- V_delta differences from V_gamma: [`V_delta_SPEC.md`](../../V_delta_SPEC.md) +- V_alpha → V_gamma rename history: `V_beta_notes.md`, `V_gamma_notes.md` diff --git a/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md b/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md new file mode 100644 index 0000000..d962386 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md @@ -0,0 +1,75 @@ +# Conversion: did_v1 → V_delta — `contrast_sensitivity_calc` + +## Identity + +- **V_delta `class_name`:** `contrast_sensitivity_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/contrast_sensitivity_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/contrastsensitivity_calc_schema.json` + plus `ndi_common/database_documents/calc/contrastsensitivity_calc.json`. +- **Status:** `drafted` + +## Summary + +Calculator type that produces a per-spatial-frequency contrast sensitivity +profile by fitting a contrast response (RB, RBN, RBNS Naka-Rushton variants) +at each spatial frequency. Unlike the tuning calculators, this class +inherits only from `base` and carries its analysis outputs as its own +top-level fields rather than via a `*_tuning` result superclass. + +did_v1 name `contrastsensitivity_calc` is normalized to +`contrast_sensitivity_calc`. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `class_name: "contrastsensitivity_calc"` | `class_name: "contrast_sensitivity_calc"` | rename (snake-case) | +| (top-level) `depends_on: [element_id, stimulus_presentation_id, stimulus_response_scalar_id]` | top-level `depends_on` | identity | +| `contrastsensitivity_calc.input_parameters` | `contrast_sensitivity_calc.input_parameters` | empty struct → typed structure with empty `fields` | +| `contrastsensitivity_calc.depends_on` (internal struct with `element_id`) | (removed — already at top-level `depends_on`) | redundant in did_v1; dropped | +| `spatial_frequencies` | same | `matrix` | +| `sensitivity_{RB,RBN,RBNS}` | `sensitivity_{rb,rbn,rbns}` | snake-case; `matrix` | +| `relative_max_gain_{RB,RBN,RBNS}` | `relative_max_gain_{rb,rbn,rbns}` | same | +| `empirical_c50_{RB,RBN,RBNS}` | `empirical_c50_{rb,rbn,rbns}` | same | +| `saturation_index_{RB,RBN,RBNS}` | `saturation_index_{rb,rbn,rbns}` | same | +| `parameters_{RB,RBN,RBNS}` | `parameters_{rb,rbn,rbns}` | same | +| `fitless_interpolated_c50` | same | `matrix` | +| `is_modulated_response` | same | `boolean` (did_v1 stored as 0/1 double; promoted to boolean in V_delta) | +| `visual_response_p_bonferroni` | same | `matrix` | +| `response_varies_p_bonferroni` | same | `matrix` | +| `response_type` | same | `char` | + +## Transformations in detail + +- **Snake-case variant tags.** All `_RB` / `_RBN` / `_RBNS` suffixes are + lowercased to `_rb` / `_rbn` / `_rbns`. +- **Inheritance.** Despite producing contrast-sensitivity outputs, this + calc does NOT inherit from `contrast_tuning` in did_v1 — only from + `base`. V_delta preserves that choice. (Inheritance is confirmed `base`-only because this class aggregates across `contrast_tuning` documents rather than being a single one.) +- **`is_modulated_response` promoted to boolean.** did_v1 stored this as a numeric scalar (0/1 double). V_delta declares it `type: boolean`. Migration tools must convert `0` → `false` / `1` → `true`. + +## Default values for new fields + +None. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/contrastsensitivity_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/contrastsensitivity_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + + +- **TODO-domain:** ontology terms for sensitivity / gain / c50 fields. + +## Cross-references + +- Related result type: [`contrast_tuning.md`](contrast_tuning.md) +- Related calculator: [`contrast_tuning_calc.md`](contrast_tuning_calc.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md new file mode 100644 index 0000000..0b74e4d --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md @@ -0,0 +1,107 @@ +# Conversion: did_v1 → V_delta — `contrast_tuning` + +## Identity + +- **V_delta `class_name`:** `contrast_tuning` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/contrast_tuning.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/vision/contrast_tuning_schema.json` plus + the paired template + `ndi_common/database_documents/vision/contrast_tuning.json`. +- **Status:** `drafted` + +## Summary + +This is the **result type** for empirical and fit-derived contrast tuning +of a visual element. The class is independent of how the tuning was +computed; calculator types (e.g., `contrast_tuning_calc`) inherit from it. + +Conversion is primarily a structural reshaping: did_v1 declares every +top-level grouping as `type: "structure"` with no inner declarations, so +all field-level typing in V_delta is recovered from the paired db_doc +template (the schema file alone is insufficient). + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `contrast_tuning.properties.response_units` | `contrast_tuning.properties.response_units` | type `0` placeholder → `char` (per user decision) | +| `contrast_tuning.properties.response_type` | `contrast_tuning.properties.response_type` | identity (char) | +| `contrast_tuning.tuning_curve.contrast` | `contrast_tuning.tuning_curve.contrast` | scalar placeholder → `matrix` | +| `contrast_tuning.tuning_curve.{mean,stddev,stderr}` | same | scalar placeholders → `matrix` | +| `contrast_tuning.tuning_curve.individual` | same | empty struct in v1 → `matrix` (rows index sampled points along the tuning axis; columns index trials) | +| `contrast_tuning.tuning_curve.{control_stddev,control_stderr}` | same | scalar placeholder → `matrix` | +| `contrast_tuning.significance.{visual_response_anova_p,across_stimuli_anova_p}` | same | identity (double) | +| `contrast_tuning.fitless.interpolated_c50` | same | identity (double) | +| `contrast_tuning.fit.naka_rushton_RB_*` (9 fields) | `contrast_tuning.fit.naka_rushton_rb.*` | regrouped into nested struct + snake-cased; scalar metrics → `double`, array metrics → `matrix`; `sensitivity` is a 1x10 `matrix` (see below) | +| `contrast_tuning.fit.naka_rushton_RBN_*` | `contrast_tuning.fit.naka_rushton_rbn.*` | same | +| `contrast_tuning.fit.naka_rushton_RBNS_*` | `contrast_tuning.fit.naka_rushton_rbns.*` | same | +| (top-level) `depends_on: [element_id, stimulus_tuningcurve_id]` | top-level `depends_on` array | identity (named refs declared on the schema, document_id carried on document instances) | + +## Transformations in detail + +- **Naka-Rushton fit grouping.** did_v1 stores the three model variants + (RB, RBN, RBNS) as 27 sibling fields with `naka_rushton__` + names. V_delta groups them under a `fit` structure containing three + sub-structures `naka_rushton_rb`, `naka_rushton_rbn`, `naka_rushton_rbns`, + each carrying nine identically-named metrics. Migration is a name split + on the second underscore (after `naka_rushton_`). +- **Scalar metrics stored as 1-element arrays.** Several did_v1 fields + (e.g., `naka_rushton_RB_pref`, `_empirical_c50`, `_r2`, + `_relative_max_gain`, `_saturation_index`) appear as `[0]` in the + template. The conversion *unwraps* these to plain `double` scalars in + V_delta — the V_delta schema declares them as `type: double` / + `mustBeScalar: true`. Migration tools must extract `arr[0]` and verify + the array has exactly one element. +- **`sensitivity` is genuinely a vector, not a scalar.** The did_v1 + template stores `naka_rushton__sensitivity` as `[0]` like the + other scalar metrics, but the user-supplied field documentation + describes it as a 1x10 vector: for each i in 1..10, an inverse-threshold + sensitivity at i standard deviations of the control response. V_delta + declares `sensitivity` as `matrix` in all three Naka-Rushton + blocks (do **not** unwrap to scalar). Migration tools must preserve the + full vector rather than extracting `arr[0]`. +- **Snake-case.** Variant tags are lowercased (`RB` → `rb`). +- **RB-specific `saturation_index`.** The RB form has 2 free parameters + with no saturation-controlling term, so `saturation_index` is always 0 + under the RB fit. V_delta encodes that note in the field documentation + on `naka_rushton_rb.saturation_index`. + +## Default values for new fields + +V_delta does not introduce new required fields on this class beyond what +existed in did_v1. The global `schema_version` tag lives at +`document_class.schema_version` (see `_universal_renames.md` § 10) and is +set to `"V_delta"` by the dispatcher rather than the per-class migrator. + +## Worked example + +The before-and-after pair is large; rather than inline the entire document, +see: + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/contrast_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/contrast_tuning.json) +- **After (V_delta):** an example will be added to + `schemas/V_delta/examples/contrast_tuning_minimal.json` in a follow-up + PR once the migration engine produces one. + +## File handling + +This document type does not reference files. The generic file-handling +rules in [`_files.md`](_files.md) do not apply. + +## Open questions + + +- **TODO-domain:** ontology terms. Most field-level `ontology` slots are + `null` pending a sweep through the V_gamma CURIE registry. Candidate + CURIE families: `stato:` for statistical measures, `iao:` for data + items, `efo:` / `obi:` for stimulus parameters. + +## Cross-references + +- General file-handling rules: [`_files.md`](_files.md) +- Calculator that produces this result type: `contrast_tuning_calc` (see + [`contrast_tuning_calc.md`](contrast_tuning_calc.md)) +- Related contrast analysis: `contrast_sensitivity_calc` (see + [`contrast_sensitivity_calc.md`](contrast_sensitivity_calc.md)) diff --git a/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md new file mode 100644 index 0000000..a8ef6f8 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md @@ -0,0 +1,67 @@ +# Conversion: did_v1 → V_delta — `contrast_tuning_calc` + +## Identity + +- **V_delta `class_name`:** `contrast_tuning_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/contrast_tuning_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/contrasttuning_calc_schema.json` plus + `ndi_common/database_documents/calc/contrasttuning_calc.json`. +- **Status:** `drafted` + +## Summary + +A calculator type that computes a `contrast_tuning` result and stores the +calculator's own input parameters alongside the inherited result fields. + +The did_v1 name `contrasttuning_calc` is normalized to `contrast_tuning_calc` +in V_delta to match the snake-cased naming of the result type it inherits +from. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `document_class.class_name: "contrasttuning_calc"` | `document_class.class_name: "contrast_tuning_calc"` | rename (snake-case normalization) | +| `superclasses: [base, contrast_tuning]` | `superclasses: [base, contrast_tuning]` | identity (inherited fields stay in their declaring classes) | +| `contrasttuning_calc.input_parameters` | `contrast_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields`; calculators may extend in subclasses | +| `contrasttuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `contrast_tuning`) | the inner `depends_on` referenced `stimulus_tuningcurve_id` which is already declared on `contrast_tuning`. V_delta does not re-declare it. | + +## Transformations in detail + +- **Class name normalization.** `contrasttuning_calc` → `contrast_tuning_calc`. + Migration tools must rewrite `document_class.class_name` and the + enclosing block key in document instances. +- **Inherited dependency.** did_v1 redundantly listed `stimulus_tuningcurve_id` + as an internal `depends_on` entry even though the parent class already + declared it. V_delta drops the redundancy; the dependency exists + exactly once, on `contrast_tuning`. + +## Default values for new fields + +None — this class adds only `input_parameters`, which is an unconstrained +empty struct. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/contrasttuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/contrasttuning_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/` once + the migration engine produces one. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** what *should* `input_parameters` carry in practice? + The did_v1 template leaves it empty. Likely candidates: the + `response_type` choice (mean/peak/F1), windowing parameters, baseline + policy. Worth aligning with `contrast_sensitivity_calc.input_parameters` + if there is overlap. + +## Cross-references + +- Parent result type: [`contrast_tuning.md`](contrast_tuning.md) +- Related calculator: [`contrast_sensitivity_calc.md`](contrast_sensitivity_calc.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md b/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md new file mode 100644 index 0000000..f240fcc --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md @@ -0,0 +1,75 @@ +# Conversion: did_v1 → V_delta — `hartley_calc` + +## Identity + +- **V_delta `class_name`:** `hartley_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/hartley_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/hartley_calc_schema.json` plus + `ndi_common/database_documents/calc/hartley_calc.json`. +- **Status:** `drafted` + +## Summary + +Calculator type that computes a Hartley-basis reverse correlation. +Inherits from `base` and `hartley_reverse_correlation`. Unlike the +empty-`input_parameters` calc types in NDIcalc-vis-matlab, this one +has actual input parameters (time-lag grid `T`, spatial samplings) and +a file reference to the produced kernel. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `class_name: "hartley_calc"` | same | identity | +| `superclasses: [base, hartley_reverse_correlation]` | same | identity | +| (top-level) `files.file_list: ["hartley_results.ngrid"]` | top-level `file` array, one entry `name: "hartley_results.ngrid"` | structural rename: did_v1 `files.file_list` → V_delta top-level `file` | +| `hartley_calc.input_parameters.T` | `hartley_calc.input_parameters.t` | snake-case rename; type `matrix` | +| `hartley_calc.input_parameters.X_sampling` | `hartley_calc.input_parameters.x_sampling` | snake-case rename; `double` | +| `hartley_calc.input_parameters.Y_sampling` | `hartley_calc.input_parameters.y_sampling` | snake-case rename; `double` | +| `hartley_calc.depends_on` (internal struct with `element_id`, `stimulus_presentation_id`) | (removed — already inherited from `reverse_correlation`) | dependency redundancy dropped | + +## Transformations in detail + +- **`files.file_list` → top-level `file`.** did_v1 carries a class-block + `files.file_list` array; V_delta has a dedicated top-level `file` field + on schemas (file record objects with `name`, `mustBeNonEmpty`, + `documentation`). Migration must move and reshape this list. +- **Capital-letter inputs renamed.** `T` / `X_sampling` / `Y_sampling` + become `t` / `x_sampling` / `y_sampling` for snake-case compliance. +- **Inherited dependencies.** `element_id` and `stimulus_presentation_id` + are inherited via `reverse_correlation`; they are not re-declared on + `hartley_calc`. + +## Default values for new fields + +The did_v1 template carries `T: [0, 0.05, 0.10, 0.15, 0.20, 0.25]`, +`X_sampling: 1`, `Y_sampling: 1`. V_delta preserves these as +`default_value` on the respective fields. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/hartley_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/hartley_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +This class declares one file: `hartley_results.ngrid`. See +[`_files.md`](_files.md) for how `.ngrid` file paths and integrity hashes +are translated under migration; this class follows those generic rules +with no type-specific behavior. + +## Open questions + +- **TODO-domain:** confirm `hartley_results.ngrid` is the only file the + Hartley calculator produces, and that there are no auxiliary debug or + intermediate files that should be declared. +- **TODO-domain:** ontology terms for the input-parameter fields + (sampling intervals). + +## Cross-references + +- Parent: [`hartley_reverse_correlation.md`](hartley_reverse_correlation.md) +- Sibling: [`reverse_correlation.md`](reverse_correlation.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md b/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md new file mode 100644 index 0000000..a6a4015 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md @@ -0,0 +1,71 @@ +# Conversion: did_v1 → V_delta — `hartley_reverse_correlation` + +## Identity + +- **V_delta `class_name`:** `hartley_reverse_correlation` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/hartley_reverse_correlation.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/neuro/hartley_reverse_correlation_schema.json` + plus + `ndi_common/database_documents/neuro/hartley_reverse_correlation.json`. +- **Status:** `drafted` + +## Summary + +Reverse-correlation specialized for Hartley basis stimuli. Inherits from +`base` and `reverse_correlation`, adding stimulus-presentation metadata +(M, L_max, K_max, sf_max, fps, colors, on-screen rect), reconstruction +grids, and the spike-time / frame-time / Hartley-index arrays used to +compute the kernel. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `class_name: "hartley_reverse_correlation"` | same | identity | +| `superclasses: [base, reverse_correlation]` | same | identity | +| `hartley_reverse_correlation.stimulus_properties.{M,L_max,K_max,sf_max,fps}` | `stimulus_properties.{m,l_max,k_max,sf_max,fps}` | snake-case rename; scalar `double` | +| `hartley_reverse_correlation.stimulus_properties.{color_high,color_low,rect}` | same | `matrix` | +| `hartley_reverse_correlation.reconstruction_properties.{T_coords,X_coords,Y_coords}` | `reconstruction_properties.{t_coords,x_coords,y_coords}` | snake-case rename; `matrix` | +| `hartley_reverse_correlation.spiketimes` | same | `matrix` | +| `hartley_reverse_correlation.frameTimes` | `hartley_reverse_correlation.frame_times` | snake-case rename; `matrix` | +| `hartley_reverse_correlation.hartley_numbers` | same | `matrix` (integer-valued; integer subtype not introduced for V_delta) | + +## Transformations in detail + +- **Snake-case rename.** The did_v1 field `frameTimes` is renamed to `frame_times` to comply with the V_gamma SPEC's snake_case rule. The conversion engine should accept either spelling on read during the transition window. did_v1 `M`, `L_max`, `K_max`, `T_coords`, `X_coords`, `Y_coords` are similarly lowercased to `m`, `l_max`, `k_max`, `t_coords`, `x_coords`, `y_coords`. +- **`hartley_numbers` semantics.** Indexed in parallel with `frameTimes` + — each entry is the Hartley basis index of the frame presented at the + corresponding time. + +## Default values for new fields + +The did_v1 template carries non-empty defaults for several +`stimulus_properties` fields (e.g., `L_max: 20`, `fps: 10`, `rect: [0, 0, +800, 600]`). V_delta preserves those as the `default_value` of each +field. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/neuro/hartley_reverse_correlation.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/neuro/hartley_reverse_correlation.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No direct file references on this class. Inherited `ngrid` from +`reverse_correlation` carries the kernel data. See [`_files.md`](_files.md) +for generic rules. + +## Open questions + + + +- **TODO-domain:** ontology terms for `stimulus_properties` fields + (cycles per degree, frames per second, RGB color). + +## Cross-references + +- Parent: [`reverse_correlation.md`](reverse_correlation.md) +- Calculator: [`hartley_calc.md`](hartley_calc.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/ontology_image.md b/schemas/V_zeta/conversions/from_did_v1/ontology_image.md new file mode 100644 index 0000000..25aca7c --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/ontology_image.md @@ -0,0 +1,173 @@ +# Conversion: did_v1 → V_delta — `ontology_image` + +## Identity + +- **V_delta `class_name`:** `ontology_image` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/ontology_image.json` +- **did_v1 source:** legacy NDI/DID `ontologyImage` document type + (`_classname: "ontologyImage"` — camelCase). Schema-shape ancestor in + this repository is `schemas/V_alpha/ontologyImage.json`; + `schemas/V_beta/ontology_image.json` is the same shape after the + V_alpha → V_beta snake-case housekeeping + (`ontologyImage` → `ontology_image`). +- **Status:** `drafted` + +## Summary + +`ontology_image` carries a labelled image of an anatomical or +functional region (e.g., a brain-atlas slice for a given Allen CCF +region). did_v1 stored the ontology identity as a pair of `char` fields +(`ontology_name` + `ontology_region`); V_delta collapses them into a +single `region` field of `ontology_term` composite type. The image +file reference (`ontology_image_file`) is unchanged. + +## Field mapping + +Beyond these fields, the universal renames listed in +[`_universal_renames.md`](_universal_renames.md) apply (snake-case +classname `ontologyImage` → `ontology_image`, ontology-annotation +reshape, superclass-reference reshape, class-scoped property block +keyed by `ontology_image`). + +| did_v1 field | V_delta field | Transformation | Notes | +|---|---|---|---| +| `ontologyImage.ontology_name` (char) | `ontology_image.region.node` | composed into `ontology_term` | CURIE (e.g., `allen_ccf_v3:12345`). See "Transformations in detail". | +| `ontologyImage.ontology_region` (char) | `ontology_image.region.name` | composed into `ontology_term` | Human-readable label snapshot. | +| — | `ontology_image.region` (ontology_term) | new composite field | Created by composing the two did_v1 chars above. `mustBeNonEmpty: true`. | +| `_file[ontology_image_file]` | `file[ontology_image_file]` | identity (declaration); underscore-prefix stripped from the structural key | See [`_files.md`](_files.md) for the generic file-reference rules. | +| `depends_on[element_id]` | `depends_on[element_id]` | identity | | + +## Transformations in detail + +- **Collapse two coordinated chars into one `ontology_term`.** Same + pattern as `probe_location` and `treatment`. did_v1's `ontology_name` + (the ontology CURIE-or-name) and `ontology_region` (the + human-readable region label) merge into V_delta's `region` + composite: + + region = { + "node": , + "name": + } + + V_delta's schema declares this field `mustBeNonEmpty: true`. Migrated + documents that have empty inputs for either part fail validation + until the missing value is supplied — see "Open questions". + +- **Class name normalization.** `ontologyImage` (V_alpha) → + `ontology_image` (V_beta and later) is a snake-case rename. The + migrator rewrites `document_class.class_name` and the property-block + key. + +- **Document-instance shape.** V_delta uses class-scoped property + blocks; the `region` value lives at `ontology_image.region`. + +- **File reference.** The schema-level `_file` array (V_alpha) is + renamed `file` and its inner entries lose the underscore prefix + (`_name` → `name`, `_documentation` → `documentation`). The + `ontology_image_file` slot itself is unchanged. Per-document + file-reference values follow [`_files.md`](_files.md). + +## Default values for new fields + +V_delta introduces no required field on this class beyond what did_v1 +documents already supply, modulo the `mustBeNonEmpty: true` tightening +on `region` (which is a stricter validation of an existing input, not +a new field). + +## Worked example + +### Before (did_v1) + +```json +{ + "document_class": { + "class_name": "ontologyImage", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "base", "class_version": "1.0.0" } + ] + }, + "depends_on": [ + { "name": "element_id", "document_id": "" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "ccf_v1_slice_42", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "ontologyImage": { + "ontology_name": "allen_ccf_v3:12345", + "ontology_region": "primary visual cortex" + } +} +``` + +### After (V_delta) + +```json +{ + "document_class": { + "class_name": "ontology_image", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "base", "class_version": "1.0.0" } + ] + }, + "depends_on": [ + { "name": "element_id", "document_id": "" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "ccf_v1_slice_42", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "ontology_image": { + "region": { + "node": "allen_ccf_v3:12345", + "name": "primary visual cortex" + } + } +} +``` + +## File handling + +`ontology_image` carries one file slot, `ontology_image_file`, declared +at the schema level. The slot's name and semantics are unchanged +between did_v1 and V_delta; only the underscore-prefix stripping +applies to the surrounding structural keys. The per-document file +reference itself follows the generic rules in +[`_files.md`](_files.md). No `ontology_image`-specific file-handling +rules apply. + +## Open questions + +- **TODO-domain:** the V_delta schema requires `region` to be + non-empty. did_v1 made `ontology_region` optional (`_mustBeNonEmpty: + false`). Migrated documents that lack a region label cannot satisfy + the V_delta constraint as written. Options: (a) tighten by demoting + to `mustBeNonEmpty: false` to preserve migration completeness; (b) + populate `region.name` from a fallback (e.g., the resolved + CURIE-registry label for `region.node`) and emit a warning; (c) + reject such documents and ask the producer to supply the label. The + conversion-engine choice needs a domain decision before the V1 + freeze. +- **TODO-domain:** are did_v1 `ontology_name` values guaranteed to be + well-formed CURIEs (e.g., `allen_ccf_v3:12345`), or do some carry + just an ontology label such as `Allen CCF v3` with the numeric ID + on a different field? If the latter, see the parallel question in + [`probe_location.md`](probe_location.md). + +## Cross-references + +- General file-handling rules: [`_files.md`](_files.md) +- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) +- V_delta schema file: [`schemas/V_delta/stable/ontology_image.json`](../../stable/ontology_image.json) +- Sibling ontology-annotation type: [`ontology_label.md`](ontology_label.md) +- Same two-char-to-`ontology_term` pattern: + [`probe_location.md`](probe_location.md), + [`treatment.md`](treatment.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/ontology_label.md b/schemas/V_zeta/conversions/from_did_v1/ontology_label.md new file mode 100644 index 0000000..1df8ba0 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/ontology_label.md @@ -0,0 +1,184 @@ +# Conversion: did_v1 → V_delta — `ontology_label` + +## Identity + +- **V_delta `class_name`:** `ontology_label` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/ontology_label.json` +- **did_v1 source:** legacy NDI/DID `ontologyLabel` document type + (`_classname: "ontologyLabel"` — camelCase). Schema-shape ancestor in + this repository is `schemas/V_alpha/ontologyLabel.json`; + `schemas/V_beta/ontology_label.json` is the same shape after the + V_alpha → V_beta snake-case housekeeping + (`ontologyLabel` → `ontology_label`). +- **Status:** `drafted` + +## Summary + +`ontology_label` attaches an ontology-derived label to an element +(e.g., a brain-region label from Allen CCF). did_v1 stored three +coordinated fields — `ontology_name` (the source ontology), +`label` (the human-readable region name), and `label_id` (a numeric +id within that ontology). V_delta collapses these into a single +`term` field of `ontology_term` composite type, where the CURIE +`:` becomes the node and `label` becomes the +label snapshot. + +## Field mapping + +Beyond these fields, the universal renames listed in +[`_universal_renames.md`](_universal_renames.md) apply (snake-case +classname `ontologyLabel` → `ontology_label`, ontology-annotation +reshape, superclass-reference reshape, class-scoped property block +keyed by `ontology_label`). + +| did_v1 field | V_delta field | Transformation | Notes | +|---|---|---|---| +| `ontologyLabel.ontology_name` (char) | `ontology_label.term.node` (CURIE prefix) | composed into `ontology_term`; combined with `label_id` | See "Transformations in detail". | +| `ontologyLabel.label_id` (integer) | `ontology_label.term.node` (CURIE local part) | composed into `ontology_term`; combined with `ontology_name` | See "Transformations in detail". | +| `ontologyLabel.label` (char) | `ontology_label.term.name` | composed into `ontology_term` | Human-readable label snapshot. | +| — | `ontology_label.term` (ontology_term) | new composite field | Created by composing the three did_v1 fields above. `mustBeNonEmpty: true`. | +| `depends_on[element_id]` | `depends_on[element_id]` | identity | | + +## Transformations in detail + +- **Three-field collapse into one `ontology_term`.** Unlike + `probe_location` / `treatment` / `ontology_image`, which collapse two + did_v1 chars into a composite, `ontology_label` collapses three + fields (one char + one char + one integer). The migration rule is: + + term = { + "node": ":", + "name": + } + + The CURIE is built by concatenating the source-ontology name (the + CURIE prefix), a colon, and the string form of `label_id`. The + V_delta schema's `documentation` for `term` describes this layout + explicitly: "The CURIE prefix identifies the source ontology (e.g., + 'allen_ccf_v3'), the local part is the numeric ID (e.g., + 'allen_ccf_v3:12345'), and 'name' carries the human-readable label." + +- **CURIE prefix normalization.** did_v1's `ontology_name` is a + free-form string (e.g., `Allen CCF v3`). For V_delta the prefix must + match a registered CURIE prefix in `CURIE_lookups_meta.json` (or at + least follow that file's conventions). The migrator should + lower-case the prefix and replace spaces with underscores; the + resulting `Allen CCF v3` → `allen_ccf_v3`. The mapping is not + bijective in the general case (multiple did_v1 strings can map to + one CURIE prefix), so this is a one-way normalization step. See + "Open questions" for un-registrable cases. + +- **Class name normalization.** `ontologyLabel` (V_alpha) → + `ontology_label` (V_beta and later) is a snake-case rename. The + migrator rewrites `document_class.class_name` and the property-block + key. + +- **Document-instance shape.** V_delta uses class-scoped property + blocks; the `term` value lives at `ontology_label.term`. + +## Default values for new fields + +V_delta introduces no required field on this class beyond what did_v1 +documents already supply, modulo the `mustBeNonEmpty: true` tightening +on `term` (which is a stricter validation of an existing input, not a +new field). + +## Worked example + +### Before (did_v1) + +```json +{ + "document_class": { + "class_name": "ontologyLabel", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "base", "class_version": "1.0.0" } + ] + }, + "depends_on": [ + { "name": "element_id", "document_id": "" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "v1_label_for_element_x", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "ontologyLabel": { + "ontology_name": "Allen CCF v3", + "label": "primary visual cortex", + "label_id": 12345 + } +} +``` + +### After (V_delta) + +```json +{ + "document_class": { + "class_name": "ontology_label", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "base", "class_version": "1.0.0" } + ] + }, + "depends_on": [ + { "name": "element_id", "document_id": "" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "v1_label_for_element_x", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "ontology_label": { + "term": { + "node": "allen_ccf_v3:12345", + "name": "primary visual cortex" + } + } +} +``` + +## File handling + +This document type does not reference files. The generic file-handling +rules in [`_files.md`](_files.md) do not apply. + +## Open questions + +- **TODO-domain:** the V_delta `term.node` is documented as + ":". did_v1's `label_id` is declared `integer` + with `mustBeNonEmpty: false` and `_default_value: 0`. Documents that + carry the default `0` (or no `label_id`) cannot form a meaningful + CURIE local part. Options: (a) emit `:0` and rely on + consumers to recognize it as a placeholder; (b) reject the migration + and require the producer to supply a real id; (c) introduce a + side-channel for "label-only" ontology entries (no numeric id), + e.g., `:`. Decision pending. +- **TODO-domain:** for did_v1 `ontology_name` values that do not map + cleanly to a registered CURIE prefix (e.g., free-form lab-specific + labels), what should the migrator do — fail, emit a TODO-marked + CURIE, or write to a side-channel? Mirrors the open question in + [`ontology_image.md`](ontology_image.md). +- **TODO-domain:** the V_delta schema declares `term` as + `mustBeNonEmpty: true`. did_v1 made each of the three input fields + individually nullable. Whether to demote `term` to `mustBeNonEmpty: + false` to preserve migration completeness, or to enforce non-empty + and reject deficient sources, is the same question as in + [`ontology_image.md`](ontology_image.md). + +## Cross-references + +- General file-handling rules: [`_files.md`](_files.md) +- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) +- V_delta schema file: [`schemas/V_delta/stable/ontology_label.json`](../../stable/ontology_label.json) +- Sibling ontology-annotation type: [`ontology_image.md`](ontology_image.md) +- Same composite-collapse pattern (two-input variant): + [`probe_location.md`](probe_location.md), + [`treatment.md`](treatment.md) +- CURIE prefix registry (V_delta): + [`schemas/V_delta/stable/CURIE_lookups_meta.json`](../../stable/CURIE_lookups_meta.json) diff --git a/schemas/V_zeta/conversions/from_did_v1/ontology_table_row.md b/schemas/V_zeta/conversions/from_did_v1/ontology_table_row.md new file mode 100644 index 0000000..0fc2e8e --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/ontology_table_row.md @@ -0,0 +1,113 @@ +# Conversion: `ontology_table_row` → the Brainstorm-I observation tier + +**Status:** V_zeta (Brainstorm I) rewrite of the V_epsilon (Brainstorm E) split +spec. The 1→N shape is unchanged (one table row → N observation documents, one +per measured column); what changes is the **destination**: I names observation +leaves by **data-type (shape)**, not property, and carries the property on the +spine `variable` term. + +--- + +## The split, in the I model + +A `did_v1` `ontology_table_row` packs several measured facts about a subject +into one row. Each **column** becomes one observation document. The destination +**class** is chosen by the value's **shape** (the #59 axis test), and the +column's property term becomes the queryable `variable`: + +- a **scalar** measurement → the matching `scalar__observation` + (`scalar_mass_observation`, `scalar_temperature_observation`, …), value as the + typed composite; +- a **categorical** label → `categorical_observation`, value as a bound + `ontology_term`; +- a fact with **no usable value** (missing key, empty, `NaN`) → skipped; +- a value with no minted dimensional shape → the escape hatch + `generic_scalar_observation` (`{source_unit, source_value, approximate}`), + promoted to a dimensional leaf later. + +There is **no property class** anymore: a body-weight column and a brain-mass +column both become `scalar_mass_observation`, distinguished only by their +`variable` term. + +## Column → destination class (by shape, not property) + +| Column value shape | Destination class (`value` type) | Field mapping | +|---|---|---| +| Mass-dimensioned (body weight, brain/tumor mass) | `scalar_mass_observation` (`value : mass`) | term → `variable`; anatomy → `target_structure`; value+unit → `mass` composite | +| Length / distance | `scalar_length_observation` (`length`) | as above | +| Duration / age | `scalar_duration_observation` (`duration`) | | +| Volume | `scalar_volume_observation` (`volume`) | | +| Temperature | `scalar_temperature_observation` (`temperature`) | | +| Frequency (heart / respiration rate) | `scalar_frequency_observation` (`frequency`) | | +| Pressure (BP, IOP, partial pressure) | `scalar_pressure_observation` (`pressure`) | | +| Count (litter size, cell count, spike count) | `scalar_count_observation` (`count`) | | +| Score (body condition, behavioral) | `scalar_score_observation` (`score`) | | +| Concentration (glucose, cortisol, titer) | `scalar_concentration_observation` (`concentration`) | | +| Voltage (transcribed Vm) | `scalar_voltage_observation` (`voltage`) | | +| Current | `scalar_current_observation` (`current`) | | +| **Scalar with no dimensional shape** | `generic_scalar_observation` (`generic_scalar`) | value → `{source_unit, source_value, approximate}`; promote later | +| Categorical: any concept (developmental stage, health status, coat colour, estrous, behavioral label) | `categorical_observation` (`value : ontology_term`) | term → `value`; property → `variable` | + +## Field-by-field (all destinations) + +| `ontology_table_row` source | I destination | type | +|---|---|---| +| row subject | `subject_id` (spine dep, inherited) | dep → `subject` | +| — (verb) | `method` (spine) = measurement | `ontology_term` (optional) | +| row property term | `variable` (spine) | `ontology_term` (**required**) | +| row anatomy/structure, if any | `target_structure` (spine) | `ontology_term[]` (optional) | +| row value (+ unit) | `value` on the destination block | scalar: typed composite in the shape-mixin block (`scalar_mass`, …); categorical: bound `ontology_term` on `categorical_observation`'s block | +| row time | a `time_reference` dep (below) | dep → `time_reference` | + +The former `observation.measured_property` is gone — property identity is the +spine `variable`. Per-sample timing uses the shaped `time_reference` (§2 of +`V_zeta_SPEC.md`), not a `sample_time` array. + +## Timing anchor + +Each migrated observation must resolve a `time_reference`. When the source row +carries no device clock or wall-clock date, emit/link a +`session_relative_reference` (`relation = during`, → `session` via +`base.session_id`), exactly as the treatment split does. A shared row-level +anchor is reused across the N column-observations produced from one row +(1 → N+1 documents: N observations + 1 shared reference). + +## Worked example (one row → two observations) + +```jsonc +// column 1: body weight 24.3 g -> scalar_mass_observation +{ + "document_class": { "class_name": "scalar_mass_observation", "class_version": "1.0.0", + "superclasses": [ { "class_name": "scalar_observation" }, { "class_name": "scalar_mass" } ] }, + "depends_on": [ { "name": "subject_id", "value": "…" }, { "name": "time_reference_1", "value": "…" } ], + "subject_interaction": { + "method": { "node": "ncit:C41355", "name": "measurement" }, + "variable": { "node": "schema:weight", "name": "weight" }, + "target_structure": [] }, + "scalar_mass": { "value": [ { "kilograms": 0.0243, "source_unit": "g", "source_value": 24.3, "approximate": false } ] } +} + +// column 2: life stage = larval -> categorical_observation +{ + "document_class": { "class_name": "categorical_observation", "class_version": "2.0.0", + "superclasses": [ { "class_name": "observation" } ] }, + "depends_on": [ { "name": "subject_id", "value": "…" }, { "name": "time_reference_1", "value": "…" } ], + "subject_interaction": { + "method": { "node": "ncit:C41355", "name": "measurement" }, + "variable": { "node": "uberon:0000105", "name": "life cycle stage" }, + "target_structure": [] }, + "categorical_observation": { "value": { "node": "fbdv:00005336", "name": "larval stage" } } +} +``` + +## The dominant `did_v1` form and the migrator + +The dominant `ontology_table_row` layout is **parallel char fields** — +comma-separated `names`, `variable_names`, `ontology_nodes` plus a `data` struct +keyed by `variable_names`. One document is one table **row**; each **column** is +a measured property. The migrator splits it: column *i* → one observation with +`variable = ontology_nodes[i] + names[i]` and value `= data.(variable_names[i])`, +dispatched scalar-vs-categorical by the value type, and the destination scalar +class chosen by the value's dimension. Columns with no usable value are skipped; +an unrecognised layout falls back to migrating unchanged as an +`ontology_table_row` (the class carries over) rather than quarantining. diff --git a/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md new file mode 100644 index 0000000..eab50c6 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md @@ -0,0 +1,82 @@ +# Conversion: did_v1 → V_delta — `oridirtuning_calc` + +## Identity + +- **V_delta `class_name`:** `oridirtuning_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/oridirtuning_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/oridirtuning_calc_schema.json` plus + `ndi_common/database_documents/calc/oridirtuning_calc.json`. +- **Status:** `drafted` + +## Summary + +A calculator type that computes an `orientation_direction_tuning` result and +stores the calculator's own input parameters in the inherited +`calculator.input_parameters` slot. The V_delta name `oridirtuning_calc` +matches the did_v1 source — earlier V_delta drafts had renamed it to +`orientation_direction_tuning_calc` "to match the snake-cased naming of the +result type it inherits from", but that rename invented a class name that +does not appear in the NDI calculator hierarchy +(`ndi.calc.vis.oridir_tuning`), so the original name is restored. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `document_class.class_name: "oridirtuning_calc"` | `document_class.class_name: "oridirtuning_calc"` | identity | +| `superclasses: [base, orientation_direction_tuning]` | `superclasses: [base, orientation_direction_tuning, tuning_fit]` | added `tuning_fit` (and transitively `calculator` and `app`) so the calculator interface lives on the shared base, not on each subclass | +| `oridirtuning_calc.input_parameters` | `calculator.input_parameters` | moved up to the abstract `calculator` base (field is now inherited, not declared per-subclass) | +| `app.name`, `app.version` (top-level v1 block) | `app.app_name`, `app.app_version` (same block) | universal app-block field rename in did2.convert.universalRenames; the v1 source already carries the canonical NDI calculator class name in `app.name` (e.g., "ndi.calc.vis.oridir_tuning"), so V_delta does not need a separate `calculator_name` field | +| `oridirtuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `orientation_direction_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | + +## Transformations in detail + +- **Calculator base.** V_delta introduces a new abstract `calculator` class + whose superclasses are `base` and `app`. It declares one field + (`input_parameters`, structure, optional). The required calculator + identity comes from the inherited `app.app_name` -- there is no + `calculator.calculator_name` in V_delta, because that field would + duplicate `app.app_name`. Every `*_calc` schema inherits from + `calculator` (directly, or via the intermediate abstract `tuning_fit` + base when the calculator is a tuning fit). `oridirtuning_calc` + reaches `calculator` (and therefore `app`) through `tuning_fit`. +- **app block migration.** did_v1 calc documents already ship a top-level + `app` block whose `name` field holds the NDI calculator class identity + (e.g., `ndi.calc.vis.oridir_tuning`). V_delta renames `app.name -> + app.app_name` and `app.version -> app.app_version`; the rename is + applied universally by `did2.convert.universalRenames` to any + document carrying an `app` block, not just calc docs. The other app + fields (`url`, `os`, `os_version`, `interpreter`, `interpreter_version`) + match V_delta verbatim. +- **Inherited dependency.** did_v1 redundantly listed + `stimulus_tuningcurve_id` as an internal `depends_on` entry even though + the parent class `orientation_direction_tuning` already declared it. + V_delta drops the redundancy. + +## Default values for new fields + +| Field | Default | +|---|---| +| `app.app_name` | derived from v1 `app.name` (the universal rename); never defaulted by the migrator | +| `calculator.input_parameters` | `{}` if v1 had no `input_parameters` | + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/oridirtuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/oridirtuning_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** concrete shape of `input_parameters` when populated by + real calculators. + +## Cross-references + +- Parent result type: [`orientation_direction_tuning.md`](./orientation_direction_tuning.md) +- Calculator base: see `stable/calculator.json` and `stable/tuning_fit.json` diff --git a/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md b/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md new file mode 100644 index 0000000..b280743 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md @@ -0,0 +1,116 @@ +# Conversion: did_v1 → V_delta — `orientation_direction_tuning` + +## Identity + +- **V_delta `class_name`:** `orientation_direction_tuning` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/orientation_direction_tuning.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/stimulus/vision/oridir/orientation_direction_tuning_schema.json` + plus the paired template + `ndi_common/database_documents/stimulus/vision/oridir/orientation_direction_tuning.json`. +- **Status:** `drafted` + +## Summary + +This is the **result type** for empirical and fit-derived orientation / +direction tuning of a visual element. The class is independent of how the +tuning was computed; calculator types (e.g., +`oridirtuning_calc`) inherit from it. + +Conversion is primarily a structural reshaping: did_v1 declares every +top-level grouping (`properties`, `tuning_curve`, `significance`, `vector`, +`fit`) as `type: "structure"` with no inner declarations, so all +field-level typing in V_delta is recovered from the paired db_doc template +(the schema file alone is insufficient). + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `orientation_direction_tuning.properties.coordinates` | same | char placeholder → `char` with enum `{compass, cartesian}` | +| `orientation_direction_tuning.properties.response_units` | same | type `0` placeholder → `char` (per user decision) | +| `orientation_direction_tuning.properties.response_type` | same | identity (char) | +| `orientation_direction_tuning.tuning_curve.direction` | same | scalar placeholder → `matrix` (1xN direction angles in degrees) | +| `orientation_direction_tuning.tuning_curve.{mean,stddev,stderr}` | same | scalar placeholders → `matrix` | +| `orientation_direction_tuning.tuning_curve.individual` | same | empty struct in v1 → `matrix` (rows index directions; columns index trials) | +| `orientation_direction_tuning.tuning_curve.raw_individual` | same | empty struct in v1 → `matrix` (rows index directions; columns index trials; no blank subtraction / normalization) | +| `orientation_direction_tuning.tuning_curve.control_individual` | same | empty struct in v1 → `matrix` (per-trial control responses) | +| `orientation_direction_tuning.significance.{visual_response_anova_p,across_stimuli_anova_p}` | same | identity (double) | +| `orientation_direction_tuning.vector.{circular_variance,direction_circular_variance,hotelling2test,direction_hotelling2test,dot_direction_significance}` | same | identity (double); semantics documented per-field | +| `orientation_direction_tuning.vector.{orientation_preference,direction_preference}` | same | scalar placeholder → `double` (angle in degrees of the vector-sum preference) | +| `orientation_direction_tuning.fit.double_gaussian_parameters` | same | `[0]` placeholder → `matrix` (vector of length 5: `[Rsp Rp theta_pref sigma Rn]`) | +| `orientation_direction_tuning.fit.double_gaussian_fit_angles` | same | `[0]` placeholder → `matrix` (angle axis, typically 0:359) | +| `orientation_direction_tuning.fit.double_gaussian_fit_values` | same | `[0]` placeholder → `matrix` (fit values at each angle) | +| `orientation_direction_tuning.fit.orientation_preferred_orthogonal_ratio` | same | `[0]` 1-element array placeholder → scalar `double` | +| `orientation_direction_tuning.fit.direction_preferred_null_ratio` | same | `[0]` 1-element array placeholder → scalar `double` | +| `orientation_direction_tuning.fit.orientation_preferred_orthogonal_ratio_rectified` | same | `[0]` 1-element array placeholder → scalar `double` | +| `orientation_direction_tuning.fit.direction_preferred_null_ratio_rectified` | same | `[0]` 1-element array placeholder → scalar `double` | +| `orientation_direction_tuning.fit.orientation_angle_preference` | same | identity (double) | +| `orientation_direction_tuning.fit.direction_angle_preference` | same | identity (double) | +| `orientation_direction_tuning.fit.hwhh` | same | identity (double) | +| (top-level) `depends_on: [element_id, stimulus_tuningcurve_id]` | top-level `depends_on` array | identity (named refs declared on the schema, document_id carried on document instances) | + +## Transformations in detail + +- **`coordinates` enum.** did_v1 stores `coordinates` as a free-form + string placeholder. V_delta constrains it to the documented vocabulary + `{"compass", "cartesian"}`. Migration tools must lower-case any + legacy capitalisations. +- **Scalar metrics stored as 1-element arrays.** Four fit-derived ratio + fields appear as `[0]` in the did_v1 template: + `orientation_preferred_orthogonal_ratio`, + `direction_preferred_null_ratio`, + `orientation_preferred_orthogonal_ratio_rectified`, + `direction_preferred_null_ratio_rectified`. The conversion *unwraps* + these to plain `double` scalars in V_delta — the V_delta schema declares + them as `type: double` / `mustBeScalar: true`. Migration tools must + extract `arr[0]` and verify the array has exactly one element. +- **Vector-space preferences.** `vector.orientation_preference` and + `vector.direction_preference` are stored as scalar angles (in degrees) + giving the argument of the orientation- and direction-space vector + sums respectively. Tools that represent these as complex numbers + internally must convert to angle-in-degrees on output. +- **Trial-axis convention.** For the per-trial matrices (`individual`, + `raw_individual`, `control_individual`) V_delta documents the + row-vs-column convention explicitly: rows index sampled directions, + columns index trials. did_v1 did not commit to a layout. + +## Default values for new fields + +V_delta does not introduce new required fields on this class beyond what +existed in did_v1. The global `schema_version` tag lives at +`document_class.schema_version` (see `_universal_renames.md` § 10) and is +set to `"V_delta"` by the dispatcher rather than the per-class migrator. + +## Worked example + +The before-and-after pair is large; rather than inline the entire document, +see: + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/stimulus/vision/oridir/orientation_direction_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/stimulus/vision/oridir/orientation_direction_tuning.json) +- **After (V_delta):** an example will be added to + `schemas/V_delta/examples/orientation_direction_tuning_minimal.json` in a + follow-up PR once the migration engine produces one. + +## File handling + +This document type does not reference files. The generic file-handling +rules in [`_files.md`](_files.md) do not apply. + +## Open questions + +- **TODO-domain:** ontology terms. Most field-level `ontology` slots are + `null` pending a sweep through the V_gamma CURIE registry. Candidate + CURIE families: `stato:` for the ANOVA and Hotelling p-values, + `iao:` for data items, `efo:` / `obi:` for the stimulus-direction axis. +- **TODO-domain:** confirm whether `vector.orientation_preference` and + `vector.direction_preference` should be kept as scalar angles (current + V_delta choice) or expanded to a 2-element `[real, imag]` matrix to + preserve vector-sum magnitude alongside the angle. + +## Cross-references + +- General file-handling rules: [`_files.md`](_files.md) +- Calculator that produces this result type: `oridirtuning_calc` (see + [`oridirtuning_calc.md`](oridirtuning_calc.md)) diff --git a/schemas/V_zeta/conversions/from_did_v1/probe_location.md b/schemas/V_zeta/conversions/from_did_v1/probe_location.md new file mode 100644 index 0000000..2118402 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/probe_location.md @@ -0,0 +1,164 @@ +# Conversion: did_v1 → V_delta — `probe_location` + +## Identity + +- **V_delta `class_name`:** `probe_location` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/probe_location.json` +- **did_v1 source:** legacy NDI/DID `probe_location` document type + (`_classname: "probe_location"`). The schema-shape ancestor in this + repository is `schemas/V_alpha/probe_location.json`; the + `schemas/V_beta/probe_location.json` revision is the same shape with + only naming-convention housekeeping applied. +- **Status:** `drafted` + +## Summary + +`probe_location` records the anatomical or functional location at which a +probe is sampling. did_v1 carried this as a pair of coordinated `char` +fields (`ontology_name` + `name`); V_delta collapses them into a single +`location` field of the V_gamma-introduced `ontology_term` composite +type, which packages a CURIE node and a label snapshot under one key. + +## Field mapping + +One row per field across the V_alpha/V_beta-era shape and the V_delta +target. Beyond these fields, the universal renames listed in +[`_universal_renames.md`](_universal_renames.md) apply (snake-case +classname, ontology-annotation reshape, superclass-reference reshape, +class-scoped property block keyed by `probe_location`). + +| did_v1 field | V_delta field | Transformation | Notes | +|---|---|---|---| +| `probe_location.ontology_name` (char) | `probe_location.location.node` | composed into `ontology_term` | CURIE (e.g., `uberon:0002436`). See "Transformations in detail". | +| `probe_location.name` (char) | `probe_location.location.name` | composed into `ontology_term` | Human-readable label snapshot (e.g., `primary visual cortex`). | +| — | `probe_location.location` (ontology_term) | new composite field | Created by composing the two did_v1 chars above. | +| `depends_on[probe_id]` | `depends_on[probe_id]` | identity | Declared on the schema; the document_id travels with each document. | + +## Transformations in detail + +- **Collapse two coordinated chars into one `ontology_term`.** did_v1 + stored the ontology identifier and its human-readable label as two + separate `char` fields. V_delta declares a single `location` field of + type `ontology_term` (introduced in V_gamma — see `V_gamma_notes.md` + § "Class-version bumps (2.0.0)"). The composite value carries two + sub-keys: `node` (the CURIE) and `name` (the label snapshot). The + migration rule is: + + location = { + "node": , + "name": + } + + Both inputs are `char`; the output sub-fields are `char`. If either + input is empty, the corresponding sub-field is the empty string. + +- **CURIE normalization.** did_v1's `ontology_name` was a free-form + string; V_delta's `node` is a CURIE. If the did_v1 value already looks + like `:` (e.g., `uberon:0002436`), it carries over + verbatim. If it carries only a prefix name (e.g., `UBERON`) with the + term elsewhere, the migrator must reconstruct the CURIE. See "Open + questions" for the under-specified cases. + +- **Document-instance shape.** V_delta uses class-scoped property + blocks; the migrated `location` value lives under the + `probe_location` block at path `probe_location.location`. + +## Default values for new fields + +V_delta introduces no required field on this class that did_v1 documents +do not already supply. The global `schema_version` tag lives on every +document at `document_class.schema_version` (see `_universal_renames.md` +§10) and is set to `"V_delta"` by the dispatcher rather than the +per-class migrator. + +## Worked example + +### Before (did_v1) + +```json +{ + "document_class": { + "class_name": "probe_location", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "base", "class_version": "1.0.0" } + ] + }, + "depends_on": [ + { "name": "probe_id", "document_id": "aabb1122ccdd3344_aabb1122ccdd3344" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "left_hemisphere_probe_location", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "probe_location": { + "ontology_name": "uberon:0002436", + "name": "primary visual cortex" + } +} +``` + +### After (V_delta) + +```json +{ + "document_class": { + "class_name": "probe_location", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "base", "class_version": "1.0.0" } + ] + }, + "depends_on": [ + { "name": "probe_id", "document_id": "aabb1122ccdd3344_aabb1122ccdd3344" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "left_hemisphere_probe_location", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "probe_location": { + "location": { + "node": "uberon:0002436", + "name": "primary visual cortex" + } + } +} +``` + +## File handling + +This document type does not reference files. The generic file-handling +rules in [`_files.md`](_files.md) do not apply. + +## Open questions + +- **TODO-domain:** are did_v1 `ontology_name` values guaranteed to be + well-formed CURIEs (`:`) in every dataset in the wild, + or do some carry only a prefix string (e.g., `UBERON` with the term + on `name` or elsewhere)? If the latter, the migrator needs a + per-source rule to reconstruct the CURIE before populating + `location.node`. +- **TODO-domain:** should the CURIE prefix be lowercased on migration + (e.g., `UBERON:0002436` → `uberon:0002436`) to match the V_gamma + CURIE-registry convention? `CURIE_lookups_meta.json` uses lowercase + prefixes; the conservative behavior is to lowercase only the prefix + segment. +- **TODO-domain:** the `mustBeNonEmpty` for `location` is `false` in + the V_delta schema. If a did_v1 document has both inputs empty, the + migrator can emit an empty composite (`{"node": "", "name": ""}`), + or it can omit the field entirely. Confirm the preferred behavior. + +## Cross-references + +- General file-handling rules: [`_files.md`](_files.md) +- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) +- V_delta schema file: [`schemas/V_delta/stable/probe_location.json`](../../stable/probe_location.json) +- Related conversions that follow the same two-char-to-`ontology_term` + pattern: [`treatment.md`](treatment.md), + [`ontology_image.md`](ontology_image.md), + [`ontology_label.md`](ontology_label.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md b/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md new file mode 100644 index 0000000..abd9e61 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md @@ -0,0 +1,64 @@ +# Conversion: did_v1 → V_delta — `reverse_correlation` + +## Identity + +- **V_delta `class_name`:** `reverse_correlation` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/reverse_correlation.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/neuro/reverse_correlation_schema.json` plus + `ndi_common/database_documents/neuro/reverse_correlation.json`. +- **Status:** `drafted` + +## Summary + +Generic reverse-correlation result type. Inherits from `base` and `ngrid` +(an existing V_delta type) — the n-dimensional grid carries the +reverse-correlation kernel itself, and this class adds the metadata +describing the method and axis labels. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `class_name: "reverse_correlation"` | same | identity | +| `superclasses: [base, ngrid]` | same | identity | +| (top-level) `depends_on: [element_id, stimulus_presentation_id]` | top-level `depends_on` | identity | +| `reverse_correlation.method` | same | `char` (candidate for promotion to `ontology_term`) | +| `reverse_correlation.dimension_labels` | same | `char` (comma-separated axis names; consider splitting into a `matrix` in a follow-up) | + +## Transformations in detail + +- Minimal structural change. The class is a thin metadata layer over the + inherited `ngrid`; the kernel itself lives in the `ngrid` block. + +## Default values for new fields + +None. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/neuro/reverse_correlation.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/neuro/reverse_correlation.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No direct file references on this class; the inherited `ngrid` carries +the kernel data. See [`_files.md`](_files.md) for the generic rules that +govern how the inherited file references migrate. + +## Open questions + +- **TODO-domain:** is `dimension_labels` best kept as a comma-separated + `char` (preserves the v1 shape), promoted to `matrix` of axis + names, or constrained by enumeration? +- **TODO-domain:** controlled vocabulary for `method` — likely candidates + include `spike-triggered average`, `STC`, `MID`. Promote to + `ontology_term` once a CURIE is identified. + +## Cross-references + +- Inherited type: `ngrid` (existing V_delta type — not migrated by this + PR; conversion doc not required here) +- Specialization: [`hartley_reverse_correlation.md`](hartley_reverse_correlation.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md new file mode 100644 index 0000000..68f74f1 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md @@ -0,0 +1,104 @@ +# Conversion: did_v1 → V_delta — `spatial_frequency_tuning` + +## Identity + +- **V_delta `class_name`:** `spatial_frequency_tuning` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/spatial_frequency_tuning.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/vision/spatial_frequency_tuning_schema.json` plus + the paired template + `ndi_common/database_documents/vision/spatial_frequency_tuning.json`. +- **Status:** `drafted` + +## Summary + +Result type for empirical and fit-derived tuning along spatial +frequencies (cycles per degree). Independent of the calculator that +produced it; calculators (e.g., `spatial_frequency_tuning_calc`) inherit +from this class. + +Conversion is primarily a structural reshaping: did_v1 declares each +top-level grouping as an unconstrained `type: "structure"`, so all +field-level typing in V_delta is recovered from the paired db_doc +template. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `spatial_frequency_tuning.properties.{response_units,response_type}` | same | `char` types (response_units per user decision) | +| `spatial_frequency_tuning.tuning_curve.spatial_frequency` | same | scalar placeholder → `matrix` | +| `spatial_frequency_tuning.tuning_curve.{mean,stddev,stderr}` | same | scalar placeholder → `matrix` | +| `spatial_frequency_tuning.tuning_curve.individual` | same | empty struct in v1 → `matrix` (rows index spatial frequencies; columns index trials) | +| `spatial_frequency_tuning.tuning_curve.{control_stddev,control_stderr}` | same | scalar placeholder → `matrix` | +| `spatial_frequency_tuning.significance.{visual_response_anova_p,across_stimuli_anova_p}` | same | identity (double) | +| `spatial_frequency_tuning.fitless.{L50,Pref,H50,low_pass_index,high_pass_index,bandwidth}` | same (snake-cased) | identity (double); semantics documented per-field | +| `spatial_frequency_tuning.fit_dog` | same | nested struct; `parameters` is `matrix` (DoG `[b a1 b1 a2 b2]`), `values` / `fit` are `matrix`, scalar metrics `{r2, l50, pref, h50, bandwidth}` are `double` | +| `spatial_frequency_tuning.fit_movshon` | same | nested struct; Movshon 2005 fit `[k f fc B]` | +| `spatial_frequency_tuning.fit_movshon_c` | same | nested struct; Movshon 2005 fit with constant term `[k f fc B C]` | +| `spatial_frequency_tuning.fit_spline` | same | nested struct; no `parameters` field, no `r2` field (the spline is non-parametric) | +| `spatial_frequency_tuning.fit_sgauss` | same | nested struct; skewed-Gaussian fit | +| `spatial_frequency_tuning.abs` | same | mirror of all preceding blocks computed on the absolute value of responses; empty in did_v1 | +| (top-level) `depends_on: [element_id, stimulus_tuningcurve_id]` | top-level `depends_on` | identity | + +## Transformations in detail + +- **Snake-case everywhere.** did_v1 field names like `L50` / `Pref` / + `H50` / `R2` are lowercased to `l50` / `pref` / `h50` / `r2` to comply + with V_gamma's snake_case rule. +- **`values` and `fit` semantics, clarified.** In each fit block the + did_v1 template has two same-shape arrays named `values` and `fit`. + The user-supplied field documentation establishes the convention that + **`values` is the X axis** (the spatial frequencies at which the fit + is evaluated, used to draw a filled-in curve) and **`fit` is the Y + axis** (the response value of the fit at each X). An earlier draft of + this schema described them in the opposite sense; that has been + corrected. +- **Mixed scalar/array fields in did_v1 are normalized.** For example, + `fit_movshon.values` is declared as scalar `0` while `fit_dog.values` + is `[0]`; V_delta unifies these as `matrix` per user direction + ("double arrays for this"). +- **Per-fit parameter vectors are documented.** Each fit block's + `parameters` documentation now records the canonical parameter layout + (DoG `[b a1 b1 a2 b2]`, Movshon 2005 `[k f fc B]`, Movshon 2005 with + constant `[k f fc B C]`). +- **Fitless metrics carry semantic details.** `l50` / `pref` / `h50` + encode the behaviour at boundary conditions (-Inf / +Inf when the + half-max point is never crossed); `low_pass_index` and + `high_pass_index` document the rectification rule and the 0..1 / NaN + value range; `bandwidth` documents the `log2(h50 / l50)` definition + and the Inf propagation. +- **`abs` block** is a documented mirror of all preceding blocks, + recomputed on absolute-valued responses. Empty in did_v1; V_delta + retains it as an empty structure pending domain confirmation. + +## Default values for new fields + +None added by this PR. The global `schema_version` tag lives at +`document_class.schema_version` (see `_universal_renames.md` § 10) and +is set to `"V_delta"` by the dispatcher rather than the per-class +migrator. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/spatial_frequency_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/spatial_frequency_tuning.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** ontology terms for fit-parameter fields. +- **TODO-domain:** the `abs` block — concrete sub-field shape if and + when calculators start populating it. + +## Cross-references + +- Calculator that produces this result type: + [`spatial_frequency_tuning_calc.md`](./spatial_frequency_tuning_calc.md) +- Sibling result type with identical structure: + [`temporal_frequency_tuning.md`](./temporal_frequency_tuning.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md new file mode 100644 index 0000000..39d2f29 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md @@ -0,0 +1,55 @@ +# Conversion: did_v1 → V_delta — `spatial_frequency_tuning_calc` + +## Identity + +- **V_delta `class_name`:** `spatial_frequency_tuning_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/spatial_frequency_tuning_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/spatial_frequency_tuning_calc_schema.json` plus + `ndi_common/database_documents/calc/spatial_frequency_tuning_calc.json`. +- **Status:** `drafted` + +## Summary + +A calculator type that computes a `spatial_frequency_tuning` result and stores the +calculator's own input parameters alongside the inherited result fields. + The class name is already snake-cased and is kept unchanged. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `document_class.class_name: "spatial_frequency_tuning_calc"` | `document_class.class_name: "spatial_frequency_tuning_calc"` | identity | +| `superclasses: [base, spatial_frequency_tuning]` | `superclasses: [base, spatial_frequency_tuning]` | identity (inherited fields stay in their declaring classes) | +| `spatial_frequency_tuning_calc.input_parameters` | `spatial_frequency_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields` | +| `spatial_frequency_tuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `spatial_frequency_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | + +## Transformations in detail + +- **Inherited dependency.** did_v1 redundantly listed + `stimulus_tuningcurve_id` as an internal `depends_on` entry even though + the parent class `spatial_frequency_tuning` already declared it. V_delta drops the + redundancy. + +## Default values for new fields + +None. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/spatial_frequency_tuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/spatial_frequency_tuning_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** concrete shape of `input_parameters` when populated by + real calculators. + +## Cross-references + +- Parent result type: [`spatial_frequency_tuning.md`](./spatial_frequency_tuning.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md b/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md new file mode 100644 index 0000000..18e3de1 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md @@ -0,0 +1,93 @@ +# Conversion: did_v1 → V_delta — `speed_tuning` + +## Identity + +- **V_delta `class_name`:** `speed_tuning` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/speed_tuning.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/vision/speed_tuning_schema.json` plus + the paired template + `ndi_common/database_documents/vision/speed_tuning.json`. +- **Status:** `drafted` + +## Summary + +Result type for empirical and fit-derived tuning along (SF, TF) pairs in +the speed plane. Independent of the calculator that produced it; +calculators (e.g., `speed_tuning_calc`) inherit from this class. + +Conversion is primarily a structural reshaping: did_v1 declares each +top-level grouping as an unconstrained `type: "structure"`, so all +field-level typing in V_delta is recovered from the paired db_doc +template. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `speed_tuning.properties.{response_units,response_type}` | same | `char` types (response_units per user decision) | +| `speed_tuning.tuning_curve.{spatial_frequency,temporal_frequency}` | same | scalar placeholder → `matrix` (1xN sampled values) | +| `speed_tuning.tuning_curve.{mean,stddev,stderr}` | same | scalar placeholder → `matrix` | +| `speed_tuning.tuning_curve.individual` | same | empty struct in v1 → `matrix` (rows index sampled (SF, TF) points; columns index trials) | +| `speed_tuning.tuning_curve.raw_individual` | same | empty struct in v1 → `matrix` (no blank subtraction / normalization) | +| `speed_tuning.tuning_curve.control_individual` | same | empty struct in v1 → `matrix` (per-trial control responses) | +| `speed_tuning.significance.{visual_response_anova_p,across_stimuli_anova_p}` | same | identity (double) | +| `speed_tuning.fit.Priebe_fit_*` (9 fields) | `speed_tuning.fit.priebe_fit_*` | snake-case; scalar metrics → `double`, array metrics → `matrix`; `Priebe_fit_speed_tuning_index` (`[0]`) unwrapped to scalar `double` | +| `speed_tuning.fit_no_speed.*` | same (snake-cased) | same as `fit` plus `partial_r2` and `priebe_fit_nested_f_test_p_value` | +| `speed_tuning.fit_fullspeed.*` | same (snake-cased) | same as `fit_no_speed` | +| (top-level) `depends_on: [element_id, stimulus_tuningcurve_id]` | top-level `depends_on` | identity | + +## Transformations in detail + +- **Snake-case.** `Priebe_*` prefix is lowercased to `priebe_*`. +- **`speed_tuning_index` unwrapped.** did_v1 stores + `Priebe_fit_speed_tuning_index` as a 1-element array `[0]` in all three + fit blocks. The user-supplied documentation describes it as a singular + index ("Provides an index of the relationship between preferred speed + and spatial frequency"), so V_delta declares it as scalar `double` / + `mustBeScalar: true`. Migration tools must extract `arr[0]` and verify + the array has exactly one element. This is the same unwrap convention + applied to the scalar `[0]` placeholders in `contrast_tuning` and + `orientation_direction_tuning`. +- **Three fit families.** did_v1 stores three nested fit blocks + (`fit`, `fit_no_speed`, `fit_fullspeed`) with overlapping field sets. + `fit_no_speed` and `fit_fullspeed` add `partial_r2` and + `priebe_fit_nested_f_test_p_value` for the nested F-test comparison; + `fit` does not. V_delta preserves all three blocks and the + field-membership difference between them. +- **Trial-axis convention.** For the per-trial matrices (`individual`, + `raw_individual`, `control_individual`) V_delta documents the + row-vs-column convention explicitly: rows index sampled (SF, TF) points, + columns index trials. + +## Default values for new fields + +None added by this PR. The global `schema_version` tag lives at +`document_class.schema_version` (see `_universal_renames.md` § 10) and +is set to `"V_delta"` by the dispatcher rather than the per-class +migrator. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/speed_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/speed_tuning.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** ontology terms for fit-parameter fields. +- **TODO-domain:** the meaning and shape of the seven Priebe + parameters in `priebe_fit_parameters` should be documented (currently + the schema notes only the parameter count). + +## Cross-references + +- Calculator that produces this result type: + [`speed_tuning_calc.md`](./speed_tuning_calc.md) +- Sibling fit-block patterns: + [`contrast_tuning.md`](./contrast_tuning.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md new file mode 100644 index 0000000..1a715e1 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md @@ -0,0 +1,55 @@ +# Conversion: did_v1 → V_delta — `speed_tuning_calc` + +## Identity + +- **V_delta `class_name`:** `speed_tuning_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/speed_tuning_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/speedtuning_calc_schema.json` plus + `ndi_common/database_documents/calc/speedtuning_calc.json`. +- **Status:** `drafted` + +## Summary + +A calculator type that computes a `speed_tuning` result and stores the +calculator's own input parameters alongside the inherited result fields. + The did_v1 name `speedtuning_calc` is normalized to `speed_tuning_calc` to match the snake-cased naming of the result type it inherits from. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `document_class.class_name: "speedtuning_calc"` | `document_class.class_name: "speed_tuning_calc"` | rename (snake-case normalization) | +| `superclasses: [base, speed_tuning]` | `superclasses: [base, speed_tuning]` | identity (inherited fields stay in their declaring classes) | +| `speedtuning_calc.input_parameters` | `speed_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields` | +| `speedtuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `speed_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | + +## Transformations in detail + +- **Inherited dependency.** did_v1 redundantly listed + `stimulus_tuningcurve_id` as an internal `depends_on` entry even though + the parent class `speed_tuning` already declared it. V_delta drops the + redundancy. + +## Default values for new fields + +None. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/speedtuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/speedtuning_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** concrete shape of `input_parameters` when populated by + real calculators. + +## Cross-references + +- Parent result type: [`speed_tuning.md`](./speed_tuning.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/subject_group.md b/schemas/V_zeta/conversions/from_did_v1/subject_group.md new file mode 100644 index 0000000..e77f3df --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/subject_group.md @@ -0,0 +1,42 @@ +# `subject_group` → `subject` (`is_group: true`) [Brainstorm E] + +Status: **drafted** + +`subject_group` is **deprecated** in V_epsilon (see `V_epsilon_SPEC.md`, +"Deprecated / folded" table). A group of subjects is modeled as a +`subject` flagged `is_group: true`, and membership becomes +`group_assignment` events. + +## Mapping (per document, 1 → 1) + +| did_v1 `subject_group` | V_epsilon `subject` | Transformation | +|---|---|---| +| (class) `subject_group` | (class) `subject`, `is_group: true` | class fold | +| `subject_group.group_name` (optional; absent in v1 corpus) | `subject.local_identifier` | char copy | +| `subject_group.description` (optional) | `subject.description` | char copy | +| — | `subject.is_biological` | `false` (a group is not a biological individual) | +| `base.*` | `base.*` | carried unchanged (same document id) | + +The legacy `subject_group` document is an (essentially empty) marker; it +carries **no members** — membership is expressed by member subjects +referencing the group. So the per-document migration produces only the +group `subject`. + +## Membership → `group_assignment` (relational, NDI layer) + +In V_epsilon, member→group membership is event-sourced as `group_assignment` +annotations (member `subject_id` + `group_id`). **However, did_v1 does not +record group membership anywhere**: the `subject_group` body is empty and no +v1 document depends on a `subject_group` (verified across the did_v1 document +set). There is therefore **no v1 source to migrate into `group_assignment`** +— synthesizing edges would invent data. The migration is complete with the +group `subject` alone; `group_assignment` is a forward-looking class for +newly authored data, not a migration target. If a specific corpus turns out +to encode membership out-of-band (e.g., a lab-specific table), that becomes +a targeted, corpus-specific NDI-layer pass at that time. + +## Engine + +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to +`+did2/+convert/+migrators_e/subject_group.m`. A 1 → 1 fold; the default +`V_delta` target is unaffected (it keeps `subject_group` as-is). diff --git a/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md new file mode 100644 index 0000000..fb544bd --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md @@ -0,0 +1,105 @@ +# Conversion: did_v1 → V_delta — `temporal_frequency_tuning` + +## Identity + +- **V_delta `class_name`:** `temporal_frequency_tuning` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/temporal_frequency_tuning.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/vision/temporal_frequency_tuning_schema.json` plus + the paired template + `ndi_common/database_documents/vision/temporal_frequency_tuning.json`. +- **Status:** `drafted` + +## Summary + +Result type for empirical and fit-derived tuning along temporal +frequencies (cycles per second). Independent of the calculator that +produced it; calculators (e.g., `temporal_frequency_tuning_calc`) inherit +from this class. + +Conversion is primarily a structural reshaping: did_v1 declares each +top-level grouping as an unconstrained `type: "structure"`, so all +field-level typing in V_delta is recovered from the paired db_doc +template. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `temporal_frequency_tuning.properties.{response_units,response_type}` | same | `char` types (response_units per user decision) | +| `temporal_frequency_tuning.tuning_curve.temporal_frequency` | same | scalar placeholder → `matrix` | +| `temporal_frequency_tuning.tuning_curve.{mean,stddev,stderr}` | same | scalar placeholder → `matrix` | +| `temporal_frequency_tuning.tuning_curve.individual` | same | empty struct in v1 → `matrix` (rows index temporal frequencies; columns index trials) | +| `temporal_frequency_tuning.tuning_curve.{control_stddev,control_stderr}` | same | scalar placeholder → `matrix` | +| `temporal_frequency_tuning.significance.{visual_response_anova_p,across_stimuli_anova_p}` | same | identity (double) | +| `temporal_frequency_tuning.fitless.{L50,Pref,H50,low_pass_index,high_pass_index,bandwidth}` | same (snake-cased) | identity (double); semantics documented per-field | +| `temporal_frequency_tuning.fit_dog` | same | nested struct; `parameters` is `matrix` (DoG `[b a1 b1 a2 b2]`), `values` / `fit` are `matrix`, scalar metrics `{r2, l50, pref, h50, bandwidth}` are `double` | +| `temporal_frequency_tuning.fit_movshon` | same | nested struct; Movshon 2005 fit `[k f fc B]` | +| `temporal_frequency_tuning.fit_movshon_c` | same | nested struct; Movshon 2005 fit with constant term `[k f fc B C]` | +| `temporal_frequency_tuning.fit_spline` | same | nested struct; no `parameters` field, no `r2` field (the spline is non-parametric) | +| `temporal_frequency_tuning.fit_sgauss` | same | nested struct; skewed-Gaussian fit | +| `temporal_frequency_tuning.abs` | same | mirror of all preceding blocks computed on the absolute value of responses; empty in did_v1 | +| (top-level) `depends_on: [element_id, stimulus_tuningcurve_id]` | top-level `depends_on` | identity | + +## Transformations in detail + +- **Snake-case everywhere.** did_v1 field names like `L50` / `Pref` / + `H50` / `R2` are lowercased to `l50` / `pref` / `h50` / `r2` to comply + with V_gamma's snake_case rule. +- **`values` and `fit` semantics, clarified.** In each fit block the + did_v1 template has two same-shape arrays named `values` and `fit`. + The user-supplied field documentation establishes the convention that + **`values` is the X axis** (the temporal frequencies at which the fit + is evaluated, used to draw a filled-in curve) and **`fit` is the Y + axis** (the response value of the fit at each X). An earlier draft of + this schema described them in the opposite sense — and additionally + carried over the word "spatial" from the SF schema for the `fit` + docstring; that has been corrected. +- **Mixed scalar/array fields in did_v1 are normalized.** For example, + `fit_movshon.values` is declared as scalar `0` while `fit_dog.values` + is `[0]`; V_delta unifies these as `matrix` per user direction + ("double arrays for this"). +- **Per-fit parameter vectors are documented.** Each fit block's + `parameters` documentation now records the canonical parameter layout + (DoG `[b a1 b1 a2 b2]`, Movshon 2005 `[k f fc B]`, Movshon 2005 with + constant `[k f fc B C]`). +- **Fitless metrics carry semantic details.** `l50` / `pref` / `h50` + encode the behaviour at boundary conditions (-Inf / +Inf when the + half-max point is never crossed); `low_pass_index` and + `high_pass_index` document the rectification rule and the 0..1 / NaN + value range; `bandwidth` documents the `log2(h50 / l50)` definition + and the Inf propagation. +- **`abs` block** is a documented mirror of all preceding blocks, + recomputed on absolute-valued responses. Empty in did_v1; V_delta + retains it as an empty structure pending domain confirmation. + +## Default values for new fields + +None added by this PR. The global `schema_version` tag lives at +`document_class.schema_version` (see `_universal_renames.md` § 10) and +is set to `"V_delta"` by the dispatcher rather than the per-class +migrator. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/temporal_frequency_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/temporal_frequency_tuning.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** ontology terms for fit-parameter fields. +- **TODO-domain:** the `abs` block — concrete sub-field shape if and + when calculators start populating it. + +## Cross-references + +- Calculator that produces this result type: + [`temporal_frequency_tuning_calc.md`](./temporal_frequency_tuning_calc.md) +- Sibling result type with identical structure: + [`spatial_frequency_tuning.md`](./spatial_frequency_tuning.md) +- General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md new file mode 100644 index 0000000..5f932b6 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md @@ -0,0 +1,55 @@ +# Conversion: did_v1 → V_delta — `temporal_frequency_tuning_calc` + +## Identity + +- **V_delta `class_name`:** `temporal_frequency_tuning_calc` +- **V_delta tier:** `stable` +- **V_delta schema path:** `schemas/V_delta/stable/temporal_frequency_tuning_calc.json` +- **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — + `ndi_common/schema_documents/calc/temporal_frequency_tuning_calc_schema.json` plus + `ndi_common/database_documents/calc/temporal_frequency_tuning_calc.json`. +- **Status:** `drafted` + +## Summary + +A calculator type that computes a `temporal_frequency_tuning` result and stores the +calculator's own input parameters alongside the inherited result fields. + The class name is already snake-cased and is kept unchanged. + +## Field mapping + +| did_v1 location | V_delta location | Transformation | +|---|---|---| +| `document_class.class_name: "temporal_frequency_tuning_calc"` | `document_class.class_name: "temporal_frequency_tuning_calc"` | identity | +| `superclasses: [base, temporal_frequency_tuning]` | `superclasses: [base, temporal_frequency_tuning]` | identity (inherited fields stay in their declaring classes) | +| `temporal_frequency_tuning_calc.input_parameters` | `temporal_frequency_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields` | +| `temporal_frequency_tuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `temporal_frequency_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | + +## Transformations in detail + +- **Inherited dependency.** did_v1 redundantly listed + `stimulus_tuningcurve_id` as an internal `depends_on` entry even though + the parent class `temporal_frequency_tuning` already declared it. V_delta drops the + redundancy. + +## Default values for new fields + +None. + +## Worked example + +- **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/temporal_frequency_tuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/temporal_frequency_tuning_calc.json) +- **After (V_delta):** to be added under `schemas/V_delta/examples/`. + +## File handling + +No file references. See [`_files.md`](_files.md) for generic rules. + +## Open questions + +- **TODO-domain:** concrete shape of `input_parameters` when populated by + real calculators. + +## Cross-references + +- Parent result type: [`temporal_frequency_tuning.md`](./temporal_frequency_tuning.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment.md b/schemas/V_zeta/conversions/from_did_v1/treatment.md new file mode 100644 index 0000000..42f2d56 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/treatment.md @@ -0,0 +1,108 @@ +# Conversion: did_v1 → V_epsilon — `treatment` → manipulation tiers (Brainstorm E split) + +> **Supersedes the conservative class-preserving `treatment` → V_delta `treatment` conversion** (kept in git history). Under Brainstorm E the legacy `treatment` catch-all is **retired** and **split** across the manipulation tier (and, for non-manipulation rows, out of the tier entirely). This doc is the dispatch spec for that split. Companion: [`ontology_table_row.md`](ontology_table_row.md) (the observation-tier split). + +## Identity + +- **Target tier:** V_epsilon manipulation families (`schemas/V_epsilon/draft/`). +- **did_v1 source:** legacy NDI/DID `treatment` (`_classname: "treatment"`; shape ancestor `schemas/V_alpha/treatment.json`). Fields: `treatment.ontologyName` + `treatment.name` (ontology identity), `treatment.numeric_value` (matrix), `treatment.string_value` (char); `depends_on`: `subject_id`, `manipulation_id`, `protocol_id`. +- **Status:** `drafted` (dispatch table seeded from real corpora; per-term branch list finalized in discovery mode — see [Open questions](#open-questions)). +- **Cardinality:** **1 → 1** in the common case (one `treatment` → one manipulation document), **1 → 2** when a recognizable `numeric_value` spawns a companion `scalar_observation`. Genuinely-not-a-manipulation rows route **out of tier** (1 → 1 into observation/annotation/session metadata). + +## Summary + +A `treatment` row carries an ontology identity + an optional number + optional prose. Brainstorm E reads that identity and dispatches the row to the manipulation family whose **action** it names — substance delivery → `injection`/`bath`; physical operation on the body → `procedural_manipulation`; imposed typed quantity → a `scalar_manipulation` (e.g. `temperature_manipulation`); changed condition/regime → `environmental_manipulation` — with focal-vs-ambient and structure carried as **data** (`target_structure`), not as classes. Rows that are not manipulations at all (date of birth, experiment time) are routed out of the manipulation tier. + +## Dispatch table (on `treatment.ontologyName` branch) + +First match wins; resolved against the term's ontology branch, not a string match. + +| `ontologyName` branch | Destination class | Key field mapping | +|---|---|---| +| Drug / vehicle / virus / tracer / contrast **delivered by injection** (CHEBI drug branch; OBI injection) | **`injection`** (← `pharmacological_manipulation`) | identity → `mixture` agent; `numeric_value` (if volume) → `volume`; route/coords → curator backfill; `kind` ∈ {drug,virus,tracer,vehicle,contrast} | +| Substance applied **as a bath** | **`bath`** / **`stimulus_bath`** | identity → `mixture`; `location` from prose/backfill | +| Surgical / minor physical **operation on the body** (OBI/NCIT procedure branch — craniotomy, implant, lesion, eye-opening, ear-notch, perfusion) | **`procedural_manipulation`** | identity → `procedure`; structure → `target_structure`; prose → `notes` | +| **Heating / cooling** (thermal) | **`temperature_manipulation`** (← `scalar_manipulation`, `scalar_temperature`) | identity → `applied_property`; thermal `numeric_value` → `value` (typed temperature); focal site → `target_structure` (empty ⇒ ambient) | +| Other **imposed typed quantity** (applied pressure/force, field, frequency) | matching `scalar_manipulation` subclass (`pressure_manipulation`, …) or `generic_scalar_manipulation` | identity → `applied_property`; `numeric_value` → `value` | +| **Environmental / husbandry / behavioral regime** with no typed value (dark rearing, deprivation regime, social isolation, enrichment, light cycle, diet/water restriction, training) | **`environmental_manipulation`** | identity → `factor`; structure (lateralized) → `target_structure`; prose → `notes`; duration → bounded `time_reference` | +| **Not a manipulation** (`Treatment: Date of birth`, `Treatment: Non-survival experiment time`, …) | **out of tier** → `age_observation`/`categorical_observation` (DOB) or session metadata/annotation | per [`ontology_table_row.md`](ontology_table_row.md) routing | +| Empty / unresolvable `ontologyName` | **curator review queue** (default routing **off**) | flagged, never silently forced into a residual family | + +### Edge cases captured from real corpora + +- **`string_value` carrying an ontology target, not prose** (the `Dab` treeshrew optogenetic-tetanus rows: `ontologyName = EMPTY:0000074`, `name = "…Target Location"`, `string_value = UBERON CURIE`). Route `string_value` → **`target_structure`** (as `ontology_term`), strip the "Target Location" role-suffix from the procedure/action name, register an NDIC term for the `EMPTY:` placeholder (curator backfill until then). Detection rule: `name` ends in "Target Location" **and/or** `string_value` matches a CURIE pattern. +- **`numeric_value` → companion observation.** A recognizable typed quantity that is *measured*, not the manipulation's own payload (e.g. a training-exposure duration), becomes a companion `scalar_observation` sharing `subject_id` + `time_reference`. Unrecognizable numbers are **flagged, never silently kept** (the `numeric_value` grab-bag is exactly what E retires). + +## Common field mapping (all manipulation destinations) + +| did_v1 field | V_epsilon field | Transformation | +|---|---|---| +| `treatment.ontologyName` + `treatment.name` | the family identity slot (`procedure` / `factor` / `applied_property`; or `mixture` agent) | collapse the two chars into one `ontology_term` (same merge rule as `probe_location`), then place per the dispatch table | +| `treatment.numeric_value` | typed `value` **or** companion `scalar_observation` **or** flagged | per dispatch; thermal/pressure/etc. → typed `value`; measured quantity → companion; else flag | +| `treatment.string_value` | `notes` (prose) **or** `target_structure` (Dab case) | default prose → `notes`; CURIE/Target-Location → `target_structure` | +| `depends_on[subject_id]` | inherited `subject_id` | identity | +| — | inherited `time_reference_#` | **emits a `session_relative_reference`** document (`relation: during`, `depends_on session_id → session` from `base.session_id`) and points `time_reference_1` at it. v1 treatment rows have no epoch and (often) no UTC date, so the honest anchor is ordinal-against-the-session; `during` is the universal fallback (the act happened within the session), `at_end_of` reserved for known-terminal cases. Makes the migration **1 → 2**. | +| `depends_on[manipulation_id]` | — | **dropped** (stale in v1) | +| `depends_on[protocol_id]` | — | **dropped + flagged** for the tier-level `protocol_id` commonality (issue #8 Option C / #10) | + +## Default values for new fields + +- `target_structure`: `[]` (empty ⇒ whole-subject/ambient) unless recoverable. +- `kind` (injection): inferred from the agent branch where possible; else curator backfill. +- `time_reference_#`: synthesized; required, so the migrator must produce at least one (a point-in-time reference anchored to the session) and flag for widening. + +## Worked example — thermal `treatment` → `temperature_manipulation` + +### Before (did_v1) +```json +{ + "document_class": { "class_name": "treatment", "class_version": "1.0.0", + "superclasses": [ { "class_name": "base", "class_version": "1.0.0" } ] }, + "depends_on": [ + { "name": "subject_id", "document_id": "aabb1122ccdd3344_aabb1122ccdd3344" }, + { "name": "manipulation_id", "document_id": "" }, + { "name": "protocol_id", "document_id": "ccdd_protocol" } + ], + "base": { "id": "aabb1122ccdd3344_1122334455667788", "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "v1_cooling", "datestamp": "2024-06-01T12:00:00.000Z" }, + "treatment": { "ontologyName": "ndic:0000nnnn", "name": "focal cortical cooling", + "numeric_value": [12.0], "string_value": "Peltier, V1" } +} +``` + +### After (V_epsilon) +```json +{ + "document_class": { "class_name": "temperature_manipulation", "class_version": "1.0.0", + "superclasses": [ { "class_name": "scalar_manipulation" }, { "class_name": "scalar_temperature" } ] }, + "depends_on": [ + { "name": "subject_id", "value": "aabb1122ccdd3344_aabb1122ccdd3344" }, + { "name": "time_reference_1", "value": "aabb1122ccdd3344_synthesized" } + ], + "base": { "id": "aabb1122ccdd3344_1122334455667788", "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "v1_cooling", "datestamp": "2024-06-01T12:00:00.000Z" }, + "scalar_manipulation": { + "applied_property": { "node": "ndic:0000nnnn", "name": "focal cortical cooling" }, + "target_structure": [ { "node": "uberon:0002436", "name": "primary visual cortex" } ], + "notes": "Peltier, V1" + }, + "scalar_temperature": { "value": { "celsius": 12.0, "source_unit": "°C", "source_value": 12.0, "approximate": false } } +} +``` +(`target_structure` here was recovered from `string_value`; `protocol_id`/`manipulation_id` dropped; `time_reference` synthesized.) + +## File handling + +`treatment` references no files. [`_files.md`](_files.md) does not apply. + +## Open questions + +- **Per-term branch list.** The dispatch table is branch-level; the concrete `ontologyName` → destination mapping per corpus is finalized in **discovery mode** (run the corpus through the converter, read the quarantine/review report, extend the branch list). Report-only before any rewrite. +- **`time_reference` synthesis fidelity.** What session/epoch anchor each corpus exposes; bounded vs point default per family. +- **`protocol_id` carryover.** Dropped now; belongs to the tier-level commonality decision (#8 Option C / #10). + +## Cross-references + +- Observation-tier split: [`ontology_table_row.md`](ontology_table_row.md) +- Universal renames: [`_universal_renames.md`](_universal_renames.md) +- Design sources (ndi-next-steps): `Procedural_Manipulation_Proposal.md`, `Environmental_Manipulation_Proposal.md`, `Scalar_Manipulation_Proposal.md`, `Injection_Proposal.md`, `Bath_Proposal.md`, `20260615/Brainstorm_E_Class_Catalog.md` §4. diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md b/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md new file mode 100644 index 0000000..13ef0d8 --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md @@ -0,0 +1,29 @@ +# `treatment_drug` → `injection` (`kind: "drug"`) [Brainstorm E] + +Status: **drafted** + +`treatment_drug` is **deprecated** in V_epsilon and folds into `injection` +(a `pharmacological_manipulation`). + +## Mapping (per document, 1 → 2) + +| did_v1 `treatment_drug` | V_epsilon | Transformation | +|---|---|---| +| (class) `treatment_drug` | (class) `injection`, `injection.kind = "drug"` | class fold | +| `mixture_table` (CSV) | `pharmacological_manipulation.mixture[]` (`{chemical, amount}`) | best-effort CSV parse; ≥1 record (blank if unparseable) | +| `location_ontologyNode` / `location_name` | `injection.target_structure[]` | ontology_term | +| `administration_*` times | (timing) | ordinal `session_relative_reference` (`during`) for now; UTC/event refinement is a follow-up | +| `subject_id` | `subject_id` | carried | +| `base.*` | `base.*` | carried (same id) | + +The second emitted document is the shared `session_relative_reference` +anchor (`subject_interaction` requires a `time_reference`). + +`injection.volume` / `injection.route` are required but absent in v1; they +are emitted as blank composites (curator-fillable). Branch/field mapping is +a **heuristic seed**, finalised in discovery mode. + +## Engine +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to +`+did2/+convert/+migrators_e/treatment_drug.m`. Default `V_delta` target is +unaffected. diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md new file mode 100644 index 0000000..418386b --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md @@ -0,0 +1,27 @@ +# `treatment_transfer` → `biological_transfer` [Brainstorm E] + +Status: **drafted** + +`treatment_transfer` is **deprecated** in V_epsilon and folds into +`biological_transfer` (a `procedural_manipulation`). + +## Mapping (per document, 1 → 2) + +| did_v1 `treatment_transfer` | V_epsilon | Transformation | +|---|---|---| +| (class) `treatment_transfer` | (class) `biological_transfer` | class fold | +| `recipient_id` (depends_on) | `subject_id` | the recipient is the subject | +| `donor_id` (depends_on) | `biological_transfer` donor dependency (`donor_id`) | carried | +| `entity_ontologyNode` / `entity_name` | `biological_transfer.entity` | ontology_term | +| `method_ontologyNode` / `method_name` | `procedural_manipulation.procedure` | ontology_term | +| `method_name` | `biological_transfer.kind` | char (fallback `"transfer"`) | +| `timestamp` / `clocktype` | (timing) | ordinal `session_relative_reference` (`during`) for now; UTC/event refinement is a follow-up | +| `base.*` | `base.*` | carried (same id) | + +The second emitted document is the shared `session_relative_reference` +anchor (`subject_interaction` requires a `time_reference`). + +## Engine +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to +`+did2/+convert/+migrators_e/treatment_transfer.m`. Default `V_delta` +target is unaffected. diff --git a/schemas/V_zeta/conversions/from_did_v1/virus_injection.md b/schemas/V_zeta/conversions/from_did_v1/virus_injection.md new file mode 100644 index 0000000..c7b95dd --- /dev/null +++ b/schemas/V_zeta/conversions/from_did_v1/virus_injection.md @@ -0,0 +1,28 @@ +# `virus_injection` → `injection` (`kind: "virus"`) [Brainstorm E] + +Status: **drafted** + +`virus_injection` is **deprecated** in V_epsilon and folds into `injection` +(a `pharmacological_manipulation`). Serotype/identity ride in the mixture +ontology term; dilution rides in its concentration amount. + +## Mapping (per document, 1 → 2) + +| did_v1 `virus_injection` | V_epsilon | Transformation | +|---|---|---| +| (class) `virus_injection` | (class) `injection`, `injection.kind = "virus"` | class fold | +| `virus_OntologyName` / `virus_name` | `mixture[1].chemical` | ontology_term | +| `dilution` | `mixture[1].amount` | concentration (`source_value`, `source_unit="dilution"`) | +| `diluent_OntologyName` / `diluent_name` | `mixture[2].chemical` (if named) | ontology_term | +| `virusLocation_OntologyName` / `virusLocation_name` | `injection.target_structure[]` | ontology_term | +| `virus_AdministrationDate` / `virus_AdministrationPND` | (timing) | ordinal `session_relative_reference` (`during`) for now; UTC/developmental refinement is a follow-up | +| `subject_id` | `subject_id` | carried | +| `base.*` | `base.*` | carried (same id) | + +The second emitted document is the shared `session_relative_reference` +anchor. `injection.volume` / `route` are emitted blank (curator-fillable). + +## Engine +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to +`+did2/+convert/+migrators_e/virus_injection.m`. Default `V_delta` target +is unaffected. diff --git a/schemas/V_zeta/deprecated/.gitkeep b/schemas/V_zeta/deprecated/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/schemas/V_zeta/deprecated/projectvar.json b/schemas/V_zeta/deprecated/projectvar.json new file mode 100644 index 0000000..ffc5648 --- /dev/null +++ b/schemas/V_zeta/deprecated/projectvar.json @@ -0,0 +1,96 @@ +{ + "document_class": { + "class_name": "projectvar", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "deprecated" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this project variable is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "project", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the project.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "user", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The user who created this project variable.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "lab", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The lab or group associated with this project variable.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "description", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "A free-text description of the project variable.", + "constraints": { + "maxLength": 1024 + } + }, + { + "name": "data", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The data payload of the project variable, stored as a string.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/deprecated/subject_group.json b/schemas/V_zeta/deprecated/subject_group.json new file mode 100644 index 0000000..96080c2 --- /dev/null +++ b/schemas/V_zeta/deprecated/subject_group.json @@ -0,0 +1,52 @@ +{ + "document_class": { + "class_name": "subject_group", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "deprecated" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "group_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:name", + "name": "name" + }, + "documentation": "Optional human-readable name for this subject group (e.g., 'control', 'treatment'). v1 docs did not carry a name and migrate with this field absent; new documents may populate it for ad-hoc labeling. Candidate for promotion to ontology_term once a study-arm vocabulary (e.g., NCIT 'Study Arm' branch) is registered.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "description", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:description", + "name": "description" + }, + "documentation": "Optional free-text description of this subject group.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/deprecated/treatment.json b/schemas/V_zeta/deprecated/treatment.json new file mode 100644 index 0000000..672b0c4 --- /dev/null +++ b/schemas/V_zeta/deprecated/treatment.json @@ -0,0 +1,91 @@ +{ + "document_class": { + "class_name": "treatment", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "deprecated" + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the subject that received this treatment.", + "must_refer_to_document_class": "" + }, + { + "name": "manipulation_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the manipulation associated with this treatment.", + "must_refer_to_document_class": "" + }, + { + "name": "protocol_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the protocol associated with this treatment.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "ontology_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology identifier of the treatment (e.g., 'EMPTY:0000074'). v1 ships this as a flat char field alongside `name`.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Human-readable name for the treatment. Paired with `ontology_name`.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "numeric_value", + "type": "matrix", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The numeric value associated with the treatment.", + "constraints": {} + }, + { + "name": "string_value", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The character string value associated with the treatment.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/deprecated/treatment_drug.json b/schemas/V_zeta/deprecated/treatment_drug.json new file mode 100644 index 0000000..b72e86c --- /dev/null +++ b/schemas/V_zeta/deprecated/treatment_drug.json @@ -0,0 +1,81 @@ +{ + "document_class": { + "class_name": "treatment_drug", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "deprecated" + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the subject that received this drug treatment.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "drug_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the drug administered.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "dose", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The dose of the drug administered.", + "constraints": {} + }, + { + "name": "dose_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The units of the dose (e.g., 'mg/kg', 'uL', 'mM').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "route", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The route of administration (e.g., 'ip', 'iv', 'sc', 'oral', 'topical').", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/deprecated/treatment_transfer.json b/schemas/V_zeta/deprecated/treatment_transfer.json new file mode 100644 index 0000000..0bedb20 --- /dev/null +++ b/schemas/V_zeta/deprecated/treatment_transfer.json @@ -0,0 +1,120 @@ +{ + "document_class": { + "class_name": "treatment_transfer", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "deprecated" + }, + "depends_on": [ + { + "name": "recipient_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the subject that received the transferred entity.", + "must_refer_to_document_class": "" + }, + { + "name": "donor_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the subject from which the entity was transferred, if applicable.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "timestamp", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The time that the transfer occurred, specified as a datenum (if global clock) or in seconds (if local clock).", + "constraints": { + "min": -10000000, + "max": 10000000 + } + }, + { + "name": "clocktype", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The clock type of the timestamp. Use a global clock if available.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "entity_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The human-readable name of the entity that was transferred (e.g., 'blood' or 'medium'). Paired with `entity_ontology_node`.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "entity_ontology_node", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology node identifier of the entity that was transferred, as a CURIE (e.g., 'EMPTY:0000002', 'UBERON:3373'). Paired with `entity_name`.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "method_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The human-readable name of the method used to transfer the entity (e.g., 'blood transfusion' or 'titanium pick'). Paired with `method_ontology_node`.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "method_ontology_node", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology node identifier of the transfer method, as a CURIE (e.g., 'EMPTY:0000002', 'UBERON:3373'). Paired with `method_name`.", + "constraints": { + "maxLength": 128 + } + } + ] +} diff --git a/schemas/V_zeta/deprecated/virus_injection.json b/schemas/V_zeta/deprecated/virus_injection.json new file mode 100644 index 0000000..91de21b --- /dev/null +++ b/schemas/V_zeta/deprecated/virus_injection.json @@ -0,0 +1,124 @@ +{ + "document_class": { + "class_name": "virus_injection", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "deprecated" + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the subject that received this virus injection.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "virus_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the virus construct (e.g., 'AAV2-CaMKII-GCaMP6f').", + "constraints": { + "maxLength": 512 + } + }, + { + "name": "serotype", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The serotype of the viral vector (e.g., 'AAV2', 'AAV9', 'lentivirus').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "titer", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The titer of the virus in titer_units.", + "constraints": {} + }, + { + "name": "titer_units", + "type": "char", + "blank_value": "", + "default_value": "gc/mL", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The units for the titer (e.g., 'gc/mL', 'vg/mL').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "volume", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The volume injected in volume_units.", + "constraints": {} + }, + { + "name": "volume_units", + "type": "char", + "blank_value": "", + "default_value": "nL", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The units for the injected volume (e.g., 'nL', 'uL').", + "constraints": { + "maxLength": 16 + } + }, + { + "name": "injection_site", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The anatomical location of the injection site.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/draft/.gitkeep b/schemas/V_zeta/draft/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/schemas/V_zeta/draft/dataseries_channel_map.json b/schemas/V_zeta/draft/dataseries_channel_map.json new file mode 100644 index 0000000..835e1c2 --- /dev/null +++ b/schemas/V_zeta/draft/dataseries_channel_map.json @@ -0,0 +1,108 @@ +{ + "document_class": { + "class_name": "dataseries_channel_map", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "draft" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The element this channel map describes (default; stable per rig, covers all epochs). Provide this OR element_epoch_id.", + "must_refer_to_document_class": "element" + }, + { + "name": "element_epoch_id", + "mustBeNonEmpty": false, + "documentation": "A specific element_epoch this channel map overrides. Provide this OR element_id.", + "must_refer_to_document_class": "element_epoch" + } + ], + "file": [], + "fields": [ + { + "name": "channels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-slot channel meaning keyed by channel index. Absent slots are count-only/nameless. Newest-wins per index.", + "constraints": {}, + "fields": [ + { + "name": "slot", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Channel index/slot this meaning applies to.", + "constraints": {} + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Human-readable channel name.", + "constraints": {} + }, + { + "name": "measured_quantity", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical/biological quantity the channel measures.", + "constraints": {} + }, + { + "name": "quantity_relationship", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Relationship of stored signal to the measured quantity.", + "constraints": { + "enum": [ + "calibrated", + "proportional", + "unknown" + ] + } + } + ] + } + ] +} diff --git a/schemas/V_zeta/draft/dataseries_data.json b/schemas/V_zeta/draft/dataseries_data.json new file mode 100644 index 0000000..7647bdc --- /dev/null +++ b/schemas/V_zeta/draft/dataseries_data.json @@ -0,0 +1,362 @@ +{ + "document_class": { + "class_name": "dataseries_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [ + { + "name": "dataseries_binary_data", + "documentation": "The bulk samples/pixels payload (opaque blob; format pinned by subtype's storage block)." + } + ], + "fields": [ + { + "name": "axes", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sampled/index dimensions of the series. Each axis describes one grid dimension (time, space, section, wavelength, index, ...).", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis name (e.g. 'time', 'x', 'y', 'z', 'section').", + "constraints": {} + }, + { + "name": "kind", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis kind (time | space_x | space_y | space_z | section | index | wavelength | ...).", + "constraints": {} + }, + { + "name": "length", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of samples/pixels along this axis. Use -1 or 0 for open/unbounded.", + "constraints": {} + }, + { + "name": "regularity", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Whether the axis is regularly sampled.", + "constraints": { + "enum": [ + "regular", + "irregular" + ] + } + }, + { + "name": "spacing", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sample interval when the axis is regular.", + "constraints": {} + }, + { + "name": "unit", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Unit of the axis coordinate (e.g. second, micrometer).", + "constraints": {} + }, + { + "name": "sample_rate", + "type": "frequency", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sampling rate for a regular time axis (= 1/spacing).", + "constraints": {} + } + ] + }, + { + "name": "channels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Value vector recorded at each grid point. Each channel describes one component of the stored signal.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Channel name/identity (required for heterogeneous record channels, optional for homogeneous array bundles).", + "constraints": {} + }, + { + "name": "native_unit", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Unit of the stored signal (volt | microvolt | digital_count | arbitrary_unit | dimensionless | ...).", + "constraints": {} + }, + { + "name": "gain", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Scale factor: native = (stored - offset) * gain.", + "constraints": {} + }, + { + "name": "offset", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Offset applied before gain.", + "constraints": {} + }, + { + "name": "measured_quantity", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical quantity the channel measures (may be empty when unknown).", + "constraints": {} + }, + { + "name": "quantity_relationship", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Relationship of stored signal to the physical quantity.", + "constraints": { + "enum": [ + "calibrated", + "proportional", + "unknown" + ] + } + }, + { + "name": "bad", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "True if the channel is known to be bad.", + "constraints": {} + } + ] + }, + { + "name": "storage", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical storage descriptor for the bulk samples/pixels.", + "constraints": {}, + "fields": [ + { + "name": "format", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical encoding (vhsb | zarr | ome_ngff | csv | binary | ...).", + "constraints": {} + }, + { + "name": "chunk_shape", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-axis chunk sizes enabling partial/ROI reads.", + "constraints": {} + }, + { + "name": "codec", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Compression/filter pipeline (e.g. blosc/zstd).", + "constraints": {} + } + ] + }, + { + "name": "storage_mode", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Whether the bulk bytes are attached in the database or referenced externally.", + "constraints": { + "enum": [ + "attached", + "by_reference" + ] + } + }, + { + "name": "content_hash", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Content hash of the bulk data; natural dedup key.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/draft/dataseries_observation.json b/schemas/V_zeta/draft/dataseries_observation.json new file mode 100644 index 0000000..e9351bf --- /dev/null +++ b/schemas/V_zeta/draft/dataseries_observation.json @@ -0,0 +1,272 @@ +{ + "document_class": { + "class_name": "dataseries_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "observation" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "axes", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sampled/index dimensions of the series. Each axis describes one grid dimension (time, space, section, wavelength, index, ...).", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis name (e.g. 'time', 'x', 'y', 'z', 'section').", + "constraints": {} + }, + { + "name": "kind", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis kind (time | space_x | space_y | space_z | section | index | wavelength | ...).", + "constraints": {} + }, + { + "name": "length", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of samples/pixels along this axis. Use -1 or 0 for open/unbounded.", + "constraints": {} + }, + { + "name": "regularity", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Whether the axis is regularly sampled.", + "constraints": { + "enum": [ + "regular", + "irregular" + ] + } + }, + { + "name": "spacing", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sample interval when the axis is regular.", + "constraints": {} + }, + { + "name": "unit", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Unit of the axis coordinate (e.g. second, micrometer).", + "constraints": {} + }, + { + "name": "sample_rate", + "type": "frequency", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sampling rate for a regular time axis (= 1/spacing).", + "constraints": {} + } + ] + }, + { + "name": "channels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Value vector recorded at each grid point. Each channel describes one component of the stored signal.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Channel name/identity (required for heterogeneous record channels, optional for homogeneous array bundles).", + "constraints": {} + }, + { + "name": "native_unit", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Unit of the stored signal (volt | microvolt | digital_count | arbitrary_unit | dimensionless | ...).", + "constraints": {} + }, + { + "name": "gain", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Scale factor: native = (stored - offset) * gain.", + "constraints": {} + }, + { + "name": "offset", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Offset applied before gain.", + "constraints": {} + }, + { + "name": "measured_quantity", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical quantity the channel measures (may be empty when unknown).", + "constraints": {} + }, + { + "name": "quantity_relationship", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Relationship of stored signal to the physical quantity.", + "constraints": { + "enum": [ + "calibrated", + "proportional", + "unknown" + ] + } + }, + { + "name": "bad", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "True if the channel is known to be bad.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/draft/dataseries_pyramid.json b/schemas/V_zeta/draft/dataseries_pyramid.json new file mode 100644 index 0000000..65b7e7b --- /dev/null +++ b/schemas/V_zeta/draft/dataseries_pyramid.json @@ -0,0 +1,72 @@ +{ + "document_class": { + "class_name": "dataseries_pyramid", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "draft" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The element whose epoch data this pyramid accelerates.", + "must_refer_to_document_class": "element" + } + ], + "file": [ + { + "name": "pyramid_level_files", + "documentation": "Per-level downsampled locator files (derived .vhsb or native pointers)." + } + ], + "fields": [ + { + "name": "representation_levels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Disposable multiresolution read-acceleration levels. Nothing depends_on this document.", + "constraints": {}, + "fields": [ + { + "name": "representation", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Representation name (e.g. broadband | LFP | MUA).", + "constraints": {} + }, + { + "name": "levels", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-level descriptors {factor, summary, source, file}.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data.json b/schemas/V_zeta/draft/expression_matrix_data.json new file mode 100644 index 0000000..7ed39f0 --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data.json @@ -0,0 +1,48 @@ +{ + "document_class": { + "class_name": "expression_matrix_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [ + { + "name": "expression_matrix_file", + "documentation": "The expression matrix payload; format pinned by subtype." + } + ], + "fields": [ + { + "name": "feature_count", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of features (genes/proteins) along the feature axis.", + "constraints": {} + }, + { + "name": "observation_count", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of observations (samples/cells/spots).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_cellranger_h5.json b/schemas/V_zeta/draft/expression_matrix_data_cellranger_h5.json new file mode 100644 index 0000000..5a54fd5 --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_cellranger_h5.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_cellranger_h5", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_counts_table.json b/schemas/V_zeta/draft/expression_matrix_data_counts_table.json new file mode 100644 index 0000000..e50e2e1 --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_counts_table.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_counts_table", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_dia_report.json b/schemas/V_zeta/draft/expression_matrix_data_dia_report.json new file mode 100644 index 0000000..1a51cf4 --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_dia_report.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_dia_report", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_gef.json b/schemas/V_zeta/draft/expression_matrix_data_gef.json new file mode 100644 index 0000000..05470bc --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_gef.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_gef", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_gem.json b/schemas/V_zeta/draft/expression_matrix_data_gem.json new file mode 100644 index 0000000..0332b6f --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_gem.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_gem", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_h5ad.json b/schemas/V_zeta/draft/expression_matrix_data_h5ad.json new file mode 100644 index 0000000..98608ae --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_h5ad.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_h5ad", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_imzml.json b/schemas/V_zeta/draft/expression_matrix_data_imzml.json new file mode 100644 index 0000000..656800d --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_imzml.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_imzml", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_loom.json b/schemas/V_zeta/draft/expression_matrix_data_loom.json new file mode 100644 index 0000000..57c094e --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_loom.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_loom", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_maxquant.json b/schemas/V_zeta/draft/expression_matrix_data_maxquant.json new file mode 100644 index 0000000..cbd1387 --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_maxquant.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_maxquant", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_mtx.json b/schemas/V_zeta/draft/expression_matrix_data_mtx.json new file mode 100644 index 0000000..c7120de --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_mtx.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_mtx", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_mzml.json b/schemas/V_zeta/draft/expression_matrix_data_mzml.json new file mode 100644 index 0000000..85de1ab --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_mzml.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_mzml", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_mztab.json b/schemas/V_zeta/draft/expression_matrix_data_mztab.json new file mode 100644 index 0000000..655e52a --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_mztab.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_mztab", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_matrix_data_visium.json b/schemas/V_zeta/draft/expression_matrix_data_visium.json new file mode 100644 index 0000000..eeb4b51 --- /dev/null +++ b/schemas/V_zeta/draft/expression_matrix_data_visium.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "expression_matrix_data_visium", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_matrix_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/expression_observation.json b/schemas/V_zeta/draft/expression_observation.json new file mode 100644 index 0000000..e77a99f --- /dev/null +++ b/schemas/V_zeta/draft/expression_observation.json @@ -0,0 +1,106 @@ +{ + "document_class": { + "class_name": "expression_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "observation" + } + ], + "maturity_level": "draft" + }, + "depends_on": [ + { + "name": "data_id", + "mustBeNonEmpty": true, + "documentation": "The expression matrix body-of-record.", + "must_refer_to_document_class": "expression_matrix_data" + } + ], + "file": [], + "fields": [ + { + "name": "analyte", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Molecular class profiled (transcriptome | proteome | ...).", + "constraints": {} + }, + { + "name": "feature_id_type", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Feature-axis namespace (Ensembl | gene symbol | UniProt | ...).", + "constraints": {} + }, + { + "name": "n_features", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of features (genes/proteins).", + "constraints": {} + }, + { + "name": "n_observations", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of samples/cells/locations.", + "constraints": {} + }, + { + "name": "normalization", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Normalization applied (raw_counts | tpm | cpm | log1p | lfq | ...).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/draft/imageseries_data.json b/schemas/V_zeta/draft/imageseries_data.json new file mode 100644 index 0000000..d279425 --- /dev/null +++ b/schemas/V_zeta/draft/imageseries_data.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "imageseries_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "dataseries_data" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/imageseries_observation.json b/schemas/V_zeta/draft/imageseries_observation.json new file mode 100644 index 0000000..4ce9d30 --- /dev/null +++ b/schemas/V_zeta/draft/imageseries_observation.json @@ -0,0 +1,56 @@ +{ + "document_class": { + "class_name": "imageseries_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "dataseries_observation" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "kind", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Imaging modality facet.", + "constraints": {} + }, + { + "name": "acquisition_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "How the image series was acquired.", + "constraints": { + "enum": [ + "manual", + "device_export", + "daq", + "simulation", + "derived" + ] + } + } + ] +} diff --git a/schemas/V_zeta/draft/instrument.json b/schemas/V_zeta/draft/instrument.json new file mode 100644 index 0000000..3f056d7 --- /dev/null +++ b/schemas/V_zeta/draft/instrument.json @@ -0,0 +1,76 @@ +{ + "document_class": { + "class_name": "instrument", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "instrument_type", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The kind of device/observer (ontology branch naming device/observer kinds).", + "constraints": {} + }, + { + "name": "global_identifier", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Cross-subject identity handle (UDI / RRID / serial).", + "constraints": {}, + "fields": [ + { + "name": "scheme", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Identifier scheme (UDI | RRID | serial | ...).", + "constraints": {} + }, + { + "name": "value", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Identifier value within the scheme.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/draft/reference_annotation_data.json b/schemas/V_zeta/draft/reference_annotation_data.json new file mode 100644 index 0000000..e8134f1 --- /dev/null +++ b/schemas/V_zeta/draft/reference_annotation_data.json @@ -0,0 +1,23 @@ +{ + "document_class": { + "class_name": "reference_annotation_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_data" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [ + { + "name": "annotates", + "mustBeNonEmpty": false, + "documentation": "The reference sequence this annotation describes.", + "must_refer_to_document_class": "reference_sequence_data" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/reference_annotation_data_gff3.json b/schemas/V_zeta/draft/reference_annotation_data_gff3.json new file mode 100644 index 0000000..e6e67d5 --- /dev/null +++ b/schemas/V_zeta/draft/reference_annotation_data_gff3.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "reference_annotation_data_gff3", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_annotation_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/reference_annotation_data_gtf.json b/schemas/V_zeta/draft/reference_annotation_data_gtf.json new file mode 100644 index 0000000..2a29e15 --- /dev/null +++ b/schemas/V_zeta/draft/reference_annotation_data_gtf.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "reference_annotation_data_gtf", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_annotation_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/reference_data.json b/schemas/V_zeta/draft/reference_data.json new file mode 100644 index 0000000..e7d17b5 --- /dev/null +++ b/schemas/V_zeta/draft/reference_data.json @@ -0,0 +1,184 @@ +{ + "document_class": { + "class_name": "reference_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [ + { + "name": "reference_file", + "documentation": "The reference payload (sequence or annotation); format pinned by subtype." + } + ], + "fields": [ + { + "name": "species", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Organism the assembly describes (NCBITaxon).", + "constraints": { + "binding": { + "root": "NCBITaxon:1", + "expansion": "descendants", + "strength": "preferred", + "source": "ontology" + } + } + }, + { + "name": "assembly", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Assembly identity.", + "constraints": {}, + "fields": [ + { + "name": "accession", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "INSDC/NCBI accession (e.g. GCF_011764305.1).", + "constraints": {} + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Assembly name (e.g. MusPutFur1.0).", + "constraints": {} + }, + { + "name": "source", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Assembly source.", + "constraints": { + "enum": [ + "NCBI", + "Ensembl", + "GENCODE", + "lab-derived" + ] + } + } + ] + }, + { + "name": "version", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Version/revision label within a lineage.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "series_id", + "type": "did_uid", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The lineage this revision belongs to.", + "constraints": {} + }, + { + "name": "feature_id_type", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Namespace the feature IDs are drawn from.", + "constraints": {} + }, + { + "name": "source_uri", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Where a stock external resource is published.", + "constraints": { + "maxLength": 1024 + } + }, + { + "name": "content_hash", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Dedup key and exact-version anchor.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/draft/reference_sequence_data.json b/schemas/V_zeta/draft/reference_sequence_data.json new file mode 100644 index 0000000..7012a36 --- /dev/null +++ b/schemas/V_zeta/draft/reference_sequence_data.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "reference_sequence_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_data" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/reference_sequence_data_fasta_genome.json b/schemas/V_zeta/draft/reference_sequence_data_fasta_genome.json new file mode 100644 index 0000000..7ab89d5 --- /dev/null +++ b/schemas/V_zeta/draft/reference_sequence_data_fasta_genome.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "reference_sequence_data_fasta_genome", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_sequence_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/reference_sequence_data_fasta_protein.json b/schemas/V_zeta/draft/reference_sequence_data_fasta_protein.json new file mode 100644 index 0000000..83c0737 --- /dev/null +++ b/schemas/V_zeta/draft/reference_sequence_data_fasta_protein.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "reference_sequence_data_fasta_protein", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_sequence_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/reference_sequence_data_fasta_transcriptome.json b/schemas/V_zeta/draft/reference_sequence_data_fasta_transcriptome.json new file mode 100644 index 0000000..bff40c9 --- /dev/null +++ b/schemas/V_zeta/draft/reference_sequence_data_fasta_transcriptome.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "reference_sequence_data_fasta_transcriptome", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "reference_sequence_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/sequence_read_data.json b/schemas/V_zeta/draft/sequence_read_data.json new file mode 100644 index 0000000..d227660 --- /dev/null +++ b/schemas/V_zeta/draft/sequence_read_data.json @@ -0,0 +1,67 @@ +{ + "document_class": { + "class_name": "sequence_read_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [ + { + "name": "sequence_read_file", + "documentation": "The sequence-read payload; format pinned by subtype." + } + ], + "fields": [ + { + "name": "species", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Organism (NCBITaxon), consistent with the source specimen.", + "constraints": {} + }, + { + "name": "read_count", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of reads.", + "constraints": {} + }, + { + "name": "content_hash", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Dedup key.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/draft/sequence_read_data_bam.json b/schemas/V_zeta/draft/sequence_read_data_bam.json new file mode 100644 index 0000000..44bb990 --- /dev/null +++ b/schemas/V_zeta/draft/sequence_read_data_bam.json @@ -0,0 +1,28 @@ +{ + "document_class": { + "class_name": "sequence_read_data_bam", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "sequence_read_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [ + { + "name": "aligned_to", + "mustBeNonEmpty": false, + "documentation": "The reference sequence these reads are aligned to.", + "must_refer_to_document_class": "reference_sequence_data" + }, + { + "name": "reads_from", + "mustBeNonEmpty": false, + "documentation": "The specimen subject these reads were obtained from.", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/sequence_read_data_cram.json b/schemas/V_zeta/draft/sequence_read_data_cram.json new file mode 100644 index 0000000..cf1914c --- /dev/null +++ b/schemas/V_zeta/draft/sequence_read_data_cram.json @@ -0,0 +1,28 @@ +{ + "document_class": { + "class_name": "sequence_read_data_cram", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "sequence_read_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [ + { + "name": "aligned_to", + "mustBeNonEmpty": false, + "documentation": "The reference sequence these reads are aligned to.", + "must_refer_to_document_class": "reference_sequence_data" + }, + { + "name": "reads_from", + "mustBeNonEmpty": false, + "documentation": "The specimen subject these reads were obtained from.", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/sequence_read_data_fastq.json b/schemas/V_zeta/draft/sequence_read_data_fastq.json new file mode 100644 index 0000000..6ad114a --- /dev/null +++ b/schemas/V_zeta/draft/sequence_read_data_fastq.json @@ -0,0 +1,22 @@ +{ + "document_class": { + "class_name": "sequence_read_data_fastq", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "sequence_read_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [ + { + "name": "reads_from", + "mustBeNonEmpty": false, + "documentation": "The specimen subject these reads were obtained from.", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/spatial_expression_observation.json b/schemas/V_zeta/draft/spatial_expression_observation.json new file mode 100644 index 0000000..588f553 --- /dev/null +++ b/schemas/V_zeta/draft/spatial_expression_observation.json @@ -0,0 +1,63 @@ +{ + "document_class": { + "class_name": "spatial_expression_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "expression_observation" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "coordinate_registration", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Maps the file's internal spatial frame to subject/anatomy/atlas.", + "constraints": {}, + "fields": [ + { + "name": "reference_frame", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The frame the spatial coordinates are registered to.", + "constraints": {} + }, + { + "name": "transform", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Affine/orientation transform into the reference frame.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/draft/timeseries_data.json b/schemas/V_zeta/draft/timeseries_data.json new file mode 100644 index 0000000..6e100a1 --- /dev/null +++ b/schemas/V_zeta/draft/timeseries_data.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "timeseries_data", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "dataseries_data" + } + ], + "maturity_level": "draft", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/timeseries_data_binary.json b/schemas/V_zeta/draft/timeseries_data_binary.json new file mode 100644 index 0000000..be291bd --- /dev/null +++ b/schemas/V_zeta/draft/timeseries_data_binary.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "timeseries_data_binary", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "timeseries_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/timeseries_data_csv.json b/schemas/V_zeta/draft/timeseries_data_csv.json new file mode 100644 index 0000000..5153903 --- /dev/null +++ b/schemas/V_zeta/draft/timeseries_data_csv.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "timeseries_data_csv", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "timeseries_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/timeseries_data_edf.json b/schemas/V_zeta/draft/timeseries_data_edf.json new file mode 100644 index 0000000..606b373 --- /dev/null +++ b/schemas/V_zeta/draft/timeseries_data_edf.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "timeseries_data_edf", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "timeseries_data" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/draft/timeseries_observation.json b/schemas/V_zeta/draft/timeseries_observation.json new file mode 100644 index 0000000..cc78799 --- /dev/null +++ b/schemas/V_zeta/draft/timeseries_observation.json @@ -0,0 +1,115 @@ +{ + "document_class": { + "class_name": "timeseries_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "dataseries_observation" + } + ], + "maturity_level": "draft" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "kind", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Modality facet (electrophysiology | imaging | behavior | physiology | clinical | environmental | ...).", + "constraints": {} + }, + { + "name": "acquisition_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "How the series was acquired.", + "constraints": { + "enum": [ + "manual", + "device_export", + "daq", + "simulation", + "derived" + ] + } + }, + { + "name": "temporal_extent", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Temporal extent of the series.", + "constraints": { + "enum": [ + "bounded", + "open_start", + "open_end", + "unbounded" + ] + } + }, + { + "name": "regularity", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Whether samples are regularly spaced.", + "constraints": { + "enum": [ + "regular", + "irregular" + ] + } + }, + { + "name": "sample_rate", + "type": "frequency", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sampling rate of the series.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/examples/.gitkeep b/schemas/V_zeta/examples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/schemas/V_zeta/examples/scalar_temperature_observation_series.json b/schemas/V_zeta/examples/scalar_temperature_observation_series.json new file mode 100644 index 0000000..0310424 --- /dev/null +++ b/schemas/V_zeta/examples/scalar_temperature_observation_series.json @@ -0,0 +1,32 @@ +{ + "document_class": { + "class_name": "scalar_temperature_observation", + "class_version": "1.0.0", + "superclasses": [ + { "class_name": "scalar_observation" }, + { "class_name": "scalar_temperature" } + ] + }, + "depends_on": [ + { "name": "subject_id", "value": "aabb1122ccdd3344_aabb1122ccdd3344" }, + { "name": "time_reference_1", "value": "aabb1122ccdd3344_1100220033004400" } + ], + "base": { + "id": "aabb1122ccdd3344_1122334455667788", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "mouse042_cooling_curve", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "subject_interaction": { + "method": { "node": "ncit:C41355", "name": "measurement" }, + "variable": { "node": "ncit:C174446", "name": "core body temperature" }, + "target_structure": [] + }, + "scalar_temperature": { + "value": [ + { "celsius": 37.1, "source_unit": "°C", "source_value": 37.1, "approximate": false }, + { "celsius": 36.4, "source_unit": "°C", "source_value": 36.4, "approximate": false }, + { "celsius": 35.0, "source_unit": "°C", "source_value": 35.0, "approximate": false } + ] + } +} diff --git a/schemas/V_zeta/examples/utc_reference_grid.json b/schemas/V_zeta/examples/utc_reference_grid.json new file mode 100644 index 0000000..db1ffb9 --- /dev/null +++ b/schemas/V_zeta/examples/utc_reference_grid.json @@ -0,0 +1,27 @@ +{ + "document_class": { + "class_name": "utc_reference", + "class_version": "2.0.0", + "superclasses": [ { "class_name": "time_reference" } ] + }, + "depends_on": [], + "base": { + "id": "aabb1122ccdd3344_1100220033004400", + "session_id": "aabb1122ccdd3344_9900aabbccddeeff", + "name": "mouse042_cooling_curve_clock", + "datestamp": "2024-06-01T12:00:00.000Z" + }, + "time_reference": { + "is_approximate": false, + "sampling": { + "kind": "grid", + "sample_rate": { "hertz": 0.0016667, "source_unit": "1/min", "source_value": 0.1, "approximate": false }, + "n": 3, + "offsets": [] + } + }, + "utc_reference": { + "start": "2024-06-01T12:00:00.000Z", + "end": "" + } +} diff --git a/schemas/V_zeta/index.json b/schemas/V_zeta/index.json new file mode 100644 index 0000000..503c508 --- /dev/null +++ b/schemas/V_zeta/index.json @@ -0,0 +1,2360 @@ +{ + "set_version": "V_zeta", + "schema_version_value": "V_zeta", + "based_on": "V_delta", + "tiers": [ + "stable", + "draft", + "deprecated" + ], + "legacy_schema_version_values": [ + "did_v1", + "V_delta" + ], + "notes": "Source of truth for class_name uniqueness and tier placement. V_zeta implements Brainstorm I (ndi-next-steps Summer 2026/1_Ingestion): a single subject_interaction spine (subject_id, shaped time_reference, method, variable, target_structure), direction as the empty observation/manipulation classes, observation leaves named by DATA-TYPE (shape) with identity carried on the `variable` ontology term, a shaped time_reference (point/grid/enumerated; no sample_time), Path T target_structure for locus, and the dataseries_observation branch. Supersedes V_epsilon (Brainstorm E).", + "schemas": [ + { + "class_name": "CURIE_lookups_meta", + "tier": "stable", + "class_version": null, + "maturity_level": null, + "superclasses": [], + "path": "schemas/V_zeta/stable/CURIE_lookups_meta.json", + "is_meta": true + }, + { + "class_name": "did_schema_meta", + "tier": "stable", + "class_version": null, + "maturity_level": null, + "superclasses": [], + "path": "schemas/V_zeta/stable/did_schema_meta.json", + "is_meta": true + }, + { + "class_name": "ndi_reserved_keys", + "tier": "stable", + "class_version": null, + "maturity_level": null, + "superclasses": [], + "path": "schemas/V_zeta/stable/ndi_reserved_keys.json", + "is_meta": true + }, + { + "class_name": "annotation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "subject_interaction" + ], + "path": "schemas/V_zeta/stable/annotation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "app", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/app.json", + "is_meta": false + }, + { + "class_name": "base", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [], + "path": "schemas/V_zeta/stable/base.json", + "is_meta": false + }, + { + "class_name": "bath", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "pharmacological_manipulation" + ], + "path": "schemas/V_zeta/stable/bath.json", + "is_meta": false + }, + { + "class_name": "binaryseries_parameters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/binaryseries_parameters.json", + "is_meta": false + }, + { + "class_name": "binnedspikeratevm", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/binnedspikeratevm.json", + "is_meta": false + }, + { + "class_name": "biological_transfer", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "procedural_manipulation" + ], + "path": "schemas/V_zeta/stable/biological_transfer.json", + "is_meta": false + }, + { + "class_name": "calculator", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "app" + ], + "path": "schemas/V_zeta/stable/calculator.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "categorical_observation", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "observation" + ], + "path": "schemas/V_zeta/stable/categorical_observation.json", + "is_meta": false + }, + { + "class_name": "contrast_sensitivity_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "calculator" + ], + "path": "schemas/V_zeta/stable/contrast_sensitivity_calc.json", + "is_meta": false + }, + { + "class_name": "contrast_tuning", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/contrast_tuning.json", + "is_meta": false + }, + { + "class_name": "contrast_tuning_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "contrast_tuning", + "tuning_fit" + ], + "path": "schemas/V_zeta/stable/contrast_tuning_calc.json", + "is_meta": false + }, + { + "class_name": "control_stimulus_ids", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "app" + ], + "path": "schemas/V_zeta/stable/control_stimulus_ids.json", + "is_meta": false + }, + { + "class_name": "daqmetadatareader", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/daqmetadatareader.json", + "is_meta": false + }, + { + "class_name": "daqmetadatareader_epochdata_ingested", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "epochid" + ], + "path": "schemas/V_zeta/stable/daqmetadatareader_epochdata_ingested.json", + "is_meta": false + }, + { + "class_name": "daqreader", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/daqreader.json", + "is_meta": false + }, + { + "class_name": "daqreader_epochdata_ingested", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/daqreader_epochdata_ingested.json", + "is_meta": false + }, + { + "class_name": "daqreader_mfdaq_epochdata_ingested", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "daqreader_epochdata_ingested", + "epochid" + ], + "path": "schemas/V_zeta/stable/daqreader_mfdaq_epochdata_ingested.json", + "is_meta": false + }, + { + "class_name": "daqreader_ndr", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "daqreader" + ], + "path": "schemas/V_zeta/stable/daqreader_ndr.json", + "is_meta": false + }, + { + "class_name": "daqsystem", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/daqsystem.json", + "is_meta": false + }, + { + "class_name": "dataseries_channel_map", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/draft/dataseries_channel_map.json", + "is_meta": false + }, + { + "class_name": "dataseries_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/draft/dataseries_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "dataseries_observation", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "observation" + ], + "path": "schemas/V_zeta/draft/dataseries_observation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "dataseries_pyramid", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base", + "epochid" + ], + "path": "schemas/V_zeta/draft/dataseries_pyramid.json", + "is_meta": false + }, + { + "class_name": "dataset_remote", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/dataset_remote.json", + "is_meta": false + }, + { + "class_name": "dataset_session_info", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/dataset_session_info.json", + "is_meta": false + }, + { + "class_name": "demo_ndi", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/demo_ndi.json", + "is_meta": false + }, + { + "class_name": "demo_ndi_mock", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/demo_ndi_mock.json", + "is_meta": false + }, + { + "class_name": "derivation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/derivation.json", + "is_meta": false + }, + { + "class_name": "directory", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/directory.json", + "is_meta": false + }, + { + "class_name": "distance_metadata", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/distance_metadata.json", + "is_meta": false + }, + { + "class_name": "electrode_offset_voltage", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/electrode_offset_voltage.json", + "is_meta": false + }, + { + "class_name": "element", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/element.json", + "is_meta": false + }, + { + "class_name": "element_epoch", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "epochid" + ], + "path": "schemas/V_zeta/stable/element_epoch.json", + "is_meta": false + }, + { + "class_name": "environmental_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/environmental_manipulation.json", + "is_meta": false + }, + { + "class_name": "ephys_zarr", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "zarr" + ], + "path": "schemas/V_zeta/stable/ephys_zarr.json", + "is_meta": false + }, + { + "class_name": "epoch_bounded_reference", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "time_reference", + "epochid" + ], + "path": "schemas/V_zeta/stable/epoch_bounded_reference.json", + "is_meta": false + }, + { + "class_name": "epoch_relative_reference", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "time_reference", + "epochid" + ], + "path": "schemas/V_zeta/stable/epoch_relative_reference.json", + "is_meta": false + }, + { + "class_name": "epochclocktimes", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "epochid" + ], + "path": "schemas/V_zeta/stable/epochclocktimes.json", + "is_meta": false + }, + { + "class_name": "epochfiles_ingested", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/epochfiles_ingested.json", + "is_meta": false + }, + { + "class_name": "epochid", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/epochid.json", + "is_meta": false + }, + { + "class_name": "event_bounded_reference", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "time_reference" + ], + "path": "schemas/V_zeta/stable/event_bounded_reference.json", + "is_meta": false + }, + { + "class_name": "event_relative_reference", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "time_reference" + ], + "path": "schemas/V_zeta/stable/event_relative_reference.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "expression_matrix_data_cellranger_h5", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_cellranger_h5.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_counts_table", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_counts_table.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_dia_report", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_dia_report.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_gef", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_gef.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_gem", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_gem.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_h5ad", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_h5ad.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_imzml", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_imzml.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_loom", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_loom.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_maxquant", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_maxquant.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_mtx", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_mtx.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_mzml", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_mzml.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_mztab", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_mztab.json", + "is_meta": false + }, + { + "class_name": "expression_matrix_data_visium", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_matrix_data" + ], + "path": "schemas/V_zeta/draft/expression_matrix_data_visium.json", + "is_meta": false + }, + { + "class_name": "expression_observation", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "observation" + ], + "path": "schemas/V_zeta/draft/expression_observation.json", + "is_meta": false + }, + { + "class_name": "filenavigator", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/filenavigator.json", + "is_meta": false + }, + { + "class_name": "filter", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/filter.json", + "is_meta": false + }, + { + "class_name": "fitcurve", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/fitcurve.json", + "is_meta": false + }, + { + "class_name": "frequency_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_manipulation", + "scalar_frequency" + ], + "path": "schemas/V_zeta/stable/frequency_manipulation.json", + "is_meta": false + }, + { + "class_name": "generic_file", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/generic_file.json", + "is_meta": false + }, + { + "class_name": "generic_scalar", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/generic_scalar.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "generic_scalar_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_manipulation", + "generic_scalar" + ], + "path": "schemas/V_zeta/stable/generic_scalar_manipulation.json", + "is_meta": false + }, + { + "class_name": "generic_scalar_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "generic_scalar" + ], + "path": "schemas/V_zeta/stable/generic_scalar_observation.json", + "is_meta": false + }, + { + "class_name": "group_assignment", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "annotation" + ], + "path": "schemas/V_zeta/stable/group_assignment.json", + "is_meta": false + }, + { + "class_name": "hartley_calc", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "hartley_reverse_correlation", + "calculator" + ], + "path": "schemas/V_zeta/stable/hartley_calc.json", + "is_meta": false + }, + { + "class_name": "hartley_reverse_correlation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "reverse_correlation" + ], + "path": "schemas/V_zeta/stable/hartley_reverse_correlation.json", + "is_meta": false + }, + { + "class_name": "image", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/image.json", + "is_meta": false + }, + { + "class_name": "image_collection", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/image_collection.json", + "is_meta": false + }, + { + "class_name": "image_stack", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "image_stack_parameters" + ], + "path": "schemas/V_zeta/stable/image_stack.json", + "is_meta": false + }, + { + "class_name": "image_stack_parameters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/image_stack_parameters.json", + "is_meta": false + }, + { + "class_name": "image_zarr", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "zarr" + ], + "path": "schemas/V_zeta/stable/image_zarr.json", + "is_meta": false + }, + { + "class_name": "imageseries_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "dataseries_data" + ], + "path": "schemas/V_zeta/draft/imageseries_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "imageseries_observation", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "dataseries_observation" + ], + "path": "schemas/V_zeta/draft/imageseries_observation.json", + "is_meta": false + }, + { + "class_name": "injection", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "pharmacological_manipulation" + ], + "path": "schemas/V_zeta/stable/injection.json", + "is_meta": false + }, + { + "class_name": "instrument", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/draft/instrument.json", + "is_meta": false + }, + { + "class_name": "interaction_purpose", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/interaction_purpose.json", + "is_meta": false + }, + { + "class_name": "jrclust_clusters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "app" + ], + "path": "schemas/V_zeta/stable/jrclust_clusters.json", + "is_meta": false + }, + { + "class_name": "manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "subject_interaction" + ], + "path": "schemas/V_zeta/stable/manipulation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "measurement", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "epochid" + ], + "path": "schemas/V_zeta/stable/measurement.json", + "is_meta": false + }, + { + "class_name": "metadata_editor", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/metadata_editor.json", + "is_meta": false + }, + { + "class_name": "mock", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/mock.json", + "is_meta": false + }, + { + "class_name": "neuron_extracellular", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "app" + ], + "path": "schemas/V_zeta/stable/neuron_extracellular.json", + "is_meta": false + }, + { + "class_name": "ngrid", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/ngrid.json", + "is_meta": false + }, + { + "class_name": "observation", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "subject_interaction" + ], + "path": "schemas/V_zeta/stable/observation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "oneepoch", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "epochid" + ], + "path": "schemas/V_zeta/stable/oneepoch.json", + "is_meta": false + }, + { + "class_name": "ontology_image", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/ontology_image.json", + "is_meta": false + }, + { + "class_name": "ontology_label", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/ontology_label.json", + "is_meta": false + }, + { + "class_name": "ontology_table_row", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/ontology_table_row.json", + "is_meta": false + }, + { + "class_name": "openminds", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/openminds.json", + "is_meta": false + }, + { + "class_name": "openminds_element", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "openminds" + ], + "path": "schemas/V_zeta/stable/openminds_element.json", + "is_meta": false + }, + { + "class_name": "openminds_stimulus", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "openminds", + "epochid" + ], + "path": "schemas/V_zeta/stable/openminds_stimulus.json", + "is_meta": false + }, + { + "class_name": "openminds_subject", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "openminds" + ], + "path": "schemas/V_zeta/stable/openminds_subject.json", + "is_meta": false + }, + { + "class_name": "oridirtuning_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "orientation_direction_tuning", + "tuning_fit" + ], + "path": "schemas/V_zeta/stable/oridirtuning_calc.json", + "is_meta": false + }, + { + "class_name": "orientation_direction_tuning", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/orientation_direction_tuning.json", + "is_meta": false + }, + { + "class_name": "pharmacological_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/pharmacological_manipulation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "placement", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/placement.json", + "is_meta": false + }, + { + "class_name": "position_metadata", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/position_metadata.json", + "is_meta": false + }, + { + "class_name": "pressure_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_manipulation", + "scalar_pressure" + ], + "path": "schemas/V_zeta/stable/pressure_manipulation.json", + "is_meta": false + }, + { + "class_name": "probe_geometry", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/probe_geometry.json", + "is_meta": false + }, + { + "class_name": "probe_location", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/probe_location.json", + "is_meta": false + }, + { + "class_name": "procedural_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/procedural_manipulation.json", + "is_meta": false + }, + { + "class_name": "projectvar", + "tier": "deprecated", + "class_version": "1.0.0", + "maturity_level": "deprecated", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/deprecated/projectvar.json", + "is_meta": false + }, + { + "class_name": "pyraview", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "epochclocktimes", + "filter", + "base", + "epochid" + ], + "path": "schemas/V_zeta/stable/pyraview.json", + "is_meta": false + }, + { + "class_name": "reference_annotation_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_data" + ], + "path": "schemas/V_zeta/draft/reference_annotation_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "reference_annotation_data_gff3", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_annotation_data" + ], + "path": "schemas/V_zeta/draft/reference_annotation_data_gff3.json", + "is_meta": false + }, + { + "class_name": "reference_annotation_data_gtf", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_annotation_data" + ], + "path": "schemas/V_zeta/draft/reference_annotation_data_gtf.json", + "is_meta": false + }, + { + "class_name": "reference_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/draft/reference_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "reference_sequence_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_data" + ], + "path": "schemas/V_zeta/draft/reference_sequence_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "reference_sequence_data_fasta_genome", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_sequence_data" + ], + "path": "schemas/V_zeta/draft/reference_sequence_data_fasta_genome.json", + "is_meta": false + }, + { + "class_name": "reference_sequence_data_fasta_protein", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_sequence_data" + ], + "path": "schemas/V_zeta/draft/reference_sequence_data_fasta_protein.json", + "is_meta": false + }, + { + "class_name": "reference_sequence_data_fasta_transcriptome", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "reference_sequence_data" + ], + "path": "schemas/V_zeta/draft/reference_sequence_data_fasta_transcriptome.json", + "is_meta": false + }, + { + "class_name": "reverse_correlation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "ngrid" + ], + "path": "schemas/V_zeta/stable/reverse_correlation.json", + "is_meta": false + }, + { + "class_name": "scalar_concentration", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_concentration.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_concentration_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_concentration" + ], + "path": "schemas/V_zeta/stable/scalar_concentration_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_count", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_count.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_count_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_count" + ], + "path": "schemas/V_zeta/stable/scalar_count_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_current", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_current.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_current_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_current" + ], + "path": "schemas/V_zeta/stable/scalar_current_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_duration", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_duration.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_duration_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_duration" + ], + "path": "schemas/V_zeta/stable/scalar_duration_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_frequency", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_frequency.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_frequency_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_frequency" + ], + "path": "schemas/V_zeta/stable/scalar_frequency_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_length", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_length.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_length_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_length" + ], + "path": "schemas/V_zeta/stable/scalar_length_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_manipulation", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/scalar_manipulation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_mass", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_mass.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_mass_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_mass" + ], + "path": "schemas/V_zeta/stable/scalar_mass_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_observation", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "observation" + ], + "path": "schemas/V_zeta/stable/scalar_observation.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_pressure", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_pressure.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_pressure_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_pressure" + ], + "path": "schemas/V_zeta/stable/scalar_pressure_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_score", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_score.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_score_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_score" + ], + "path": "schemas/V_zeta/stable/scalar_score_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_temperature", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_temperature.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_temperature_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_temperature" + ], + "path": "schemas/V_zeta/stable/scalar_temperature_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_voltage", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_voltage.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_voltage_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_voltage" + ], + "path": "schemas/V_zeta/stable/scalar_voltage_observation.json", + "is_meta": false + }, + { + "class_name": "scalar_volume", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/scalar_volume.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "scalar_volume_observation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_observation", + "scalar_volume" + ], + "path": "schemas/V_zeta/stable/scalar_volume_observation.json", + "is_meta": false + }, + { + "class_name": "sequence_read_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/draft/sequence_read_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "sequence_read_data_bam", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "sequence_read_data" + ], + "path": "schemas/V_zeta/draft/sequence_read_data_bam.json", + "is_meta": false + }, + { + "class_name": "sequence_read_data_cram", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "sequence_read_data" + ], + "path": "schemas/V_zeta/draft/sequence_read_data_cram.json", + "is_meta": false + }, + { + "class_name": "sequence_read_data_fastq", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "sequence_read_data" + ], + "path": "schemas/V_zeta/draft/sequence_read_data_fastq.json", + "is_meta": false + }, + { + "class_name": "session", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/session.json", + "is_meta": false + }, + { + "class_name": "session_extent", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/session_extent.json", + "is_meta": false + }, + { + "class_name": "session_in_a_dataset", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/session_in_a_dataset.json", + "is_meta": false + }, + { + "class_name": "session_relative_reference", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "time_reference" + ], + "path": "schemas/V_zeta/stable/session_relative_reference.json", + "is_meta": false + }, + { + "class_name": "simple_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "calculator" + ], + "path": "schemas/V_zeta/stable/simple_calc.json", + "is_meta": false + }, + { + "class_name": "site2channelmap", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/site2channelmap.json", + "is_meta": false + }, + { + "class_name": "sorting_parameters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/sorting_parameters.json", + "is_meta": false + }, + { + "class_name": "spatial_expression_observation", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "expression_observation" + ], + "path": "schemas/V_zeta/draft/spatial_expression_observation.json", + "is_meta": false + }, + { + "class_name": "spatial_frequency_tuning", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/spatial_frequency_tuning.json", + "is_meta": false + }, + { + "class_name": "spatial_frequency_tuning_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "spatial_frequency_tuning", + "tuning_fit" + ], + "path": "schemas/V_zeta/stable/spatial_frequency_tuning_calc.json", + "is_meta": false + }, + { + "class_name": "speed_tuning", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/speed_tuning.json", + "is_meta": false + }, + { + "class_name": "speed_tuning_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "speed_tuning", + "tuning_fit" + ], + "path": "schemas/V_zeta/stable/speed_tuning_calc.json", + "is_meta": false + }, + { + "class_name": "spike_clusters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/spike_clusters.json", + "is_meta": false + }, + { + "class_name": "spike_extraction_parameters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/spike_extraction_parameters.json", + "is_meta": false + }, + { + "class_name": "spike_extraction_parameters_modification", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/spike_extraction_parameters_modification.json", + "is_meta": false + }, + { + "class_name": "spike_interface_sorting_outputs", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/spike_interface_sorting_outputs.json", + "is_meta": false + }, + { + "class_name": "spikewaves", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/spikewaves.json", + "is_meta": false + }, + { + "class_name": "stimulus_approach", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/stimulus_approach.json", + "is_meta": false + }, + { + "class_name": "stimulus_bath", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "bath" + ], + "path": "schemas/V_zeta/stable/stimulus_bath.json", + "is_meta": false + }, + { + "class_name": "stimulus_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/stimulus_manipulation.json", + "is_meta": false + }, + { + "class_name": "stimulus_parameter", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/stimulus_parameter.json", + "is_meta": false + }, + { + "class_name": "stimulus_parameter_table", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/stimulus_parameter_table.json", + "is_meta": false + }, + { + "class_name": "stimulus_presentation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "app", + "epochid" + ], + "path": "schemas/V_zeta/stable/stimulus_presentation.json", + "is_meta": false + }, + { + "class_name": "stimulus_response", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/stimulus_response.json", + "is_meta": false + }, + { + "class_name": "stimulus_response_scalar", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "stimulus_response" + ], + "path": "schemas/V_zeta/stable/stimulus_response_scalar.json", + "is_meta": false + }, + { + "class_name": "stimulus_response_scalar_parameters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/stimulus_response_scalar_parameters.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "stimulus_response_scalar_parameters_basic", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "stimulus_response_scalar_parameters" + ], + "path": "schemas/V_zeta/stable/stimulus_response_scalar_parameters_basic.json", + "is_meta": false + }, + { + "class_name": "stimulus_tuningcurve", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/stimulus_tuningcurve.json", + "is_meta": false + }, + { + "class_name": "subject", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/subject.json", + "is_meta": false + }, + { + "class_name": "subject_assertion", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/subject_assertion.json", + "is_meta": false + }, + { + "class_name": "subject_group", + "tier": "deprecated", + "class_version": "1.0.0", + "maturity_level": "deprecated", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/deprecated/subject_group.json", + "is_meta": false + }, + { + "class_name": "subject_interaction", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/subject_interaction.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "syncgraph", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/syncgraph.json", + "is_meta": false + }, + { + "class_name": "syncrule", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/syncrule.json", + "is_meta": false + }, + { + "class_name": "syncrule_mapping", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/syncrule_mapping.json", + "is_meta": false + }, + { + "class_name": "temperature_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "scalar_manipulation", + "scalar_temperature" + ], + "path": "schemas/V_zeta/stable/temperature_manipulation.json", + "is_meta": false + }, + { + "class_name": "temporal_frequency_tuning", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/temporal_frequency_tuning.json", + "is_meta": false + }, + { + "class_name": "temporal_frequency_tuning_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "temporal_frequency_tuning", + "tuning_fit" + ], + "path": "schemas/V_zeta/stable/temporal_frequency_tuning_calc.json", + "is_meta": false + }, + { + "class_name": "time_reference", + "tier": "stable", + "class_version": "2.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/time_reference.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "timeseries_data", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "dataseries_data" + ], + "path": "schemas/V_zeta/draft/timeseries_data.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "timeseries_data_binary", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "timeseries_data" + ], + "path": "schemas/V_zeta/draft/timeseries_data_binary.json", + "is_meta": false + }, + { + "class_name": "timeseries_data_csv", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "timeseries_data" + ], + "path": "schemas/V_zeta/draft/timeseries_data_csv.json", + "is_meta": false + }, + { + "class_name": "timeseries_data_edf", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "timeseries_data" + ], + "path": "schemas/V_zeta/draft/timeseries_data_edf.json", + "is_meta": false + }, + { + "class_name": "timeseries_observation", + "tier": "draft", + "class_version": "1.0.0", + "maturity_level": "draft", + "superclasses": [ + "dataseries_observation" + ], + "path": "schemas/V_zeta/draft/timeseries_observation.json", + "is_meta": false + }, + { + "class_name": "treatment", + "tier": "deprecated", + "class_version": "1.0.0", + "maturity_level": "deprecated", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/deprecated/treatment.json", + "is_meta": false + }, + { + "class_name": "treatment_drug", + "tier": "deprecated", + "class_version": "1.0.0", + "maturity_level": "deprecated", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/deprecated/treatment_drug.json", + "is_meta": false + }, + { + "class_name": "treatment_transfer", + "tier": "deprecated", + "class_version": "1.0.0", + "maturity_level": "deprecated", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/deprecated/treatment_transfer.json", + "is_meta": false + }, + { + "class_name": "tuning_fit", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "calculator" + ], + "path": "schemas/V_zeta/stable/tuning_fit.json", + "abstract": true, + "is_meta": false + }, + { + "class_name": "tuningcurve_calc", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "calculator", + "stimulus_tuningcurve" + ], + "path": "schemas/V_zeta/stable/tuningcurve_calc.json", + "is_meta": false + }, + { + "class_name": "utc_reference", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "time_reference" + ], + "path": "schemas/V_zeta/stable/utc_reference.json", + "is_meta": false + }, + { + "class_name": "valid_interval", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/valid_interval.json", + "is_meta": false + }, + { + "class_name": "virus_injection", + "tier": "deprecated", + "class_version": "1.0.0", + "maturity_level": "deprecated", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/deprecated/virus_injection.json", + "is_meta": false + }, + { + "class_name": "vmneuralresponseresiduals", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/vmneuralresponseresiduals.json", + "is_meta": false + }, + { + "class_name": "vmspikefilteringparameters", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/vmspikefilteringparameters.json", + "is_meta": false + }, + { + "class_name": "vmspikefit", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/vmspikefit.json", + "is_meta": false + }, + { + "class_name": "vmspikesummary", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/vmspikesummary.json", + "is_meta": false + }, + { + "class_name": "zarr", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base" + ], + "path": "schemas/V_zeta/stable/zarr.json", + "abstract": true, + "is_meta": false + } + ] +} diff --git a/schemas/V_zeta/microschemas/_DESIGN.md b/schemas/V_zeta/microschemas/_DESIGN.md new file mode 100644 index 0000000..437bb04 --- /dev/null +++ b/schemas/V_zeta/microschemas/_DESIGN.md @@ -0,0 +1,409 @@ +# Microschemas — Design (V_delta) + +> **Status:** design proposal, not implemented. This document describes +> the intended shape of the microschema mechanism for V_delta. No +> meta-schema changes, no validator changes, and no actual microschemas +> have been added in this commit. The design is reviewable on its own; +> implementation will land in follow-up PRs. + +## Purpose + +V_delta has document classes that act as **registries for open-ended +variants** — most prominently `treatment` and `measurement`. Each variant +(a drug dose, a virus injection, a behavioral protocol, etc.) has its +own structured parameters, but the variants share a common identity +("this is a treatment"). Modeling every variant as its own document +class creates class explosion and pushes new variant authors through a +heavy schema-change workflow for what should be a small, frequent +operation. + +Microschemas are the V_delta mechanism for this. A microschema is a +named, versioned schema fragment that describes the shape of a specific +field's body on a host document class, selected at validation time by +the value of a *discriminator field* on the document instance. + +## Non-goals + +- **Microschemas are not document classes.** They cannot be instantiated + on their own, do not have a `document_class` header, do not + participate in superclass inheritance, and cannot appear in + `index.json`'s `schemas` section. +- **Microschemas are not a replacement for inheritance.** Calculator + variants where each kind is distinct code should remain class-per-kind + with their own schemas. Microschemas are for cases where variants + share identity but vary in body shape. +- **Microschemas are not URL-resolvable.** All microschemas in V_delta + resolve from local paths (central registry + optional local overlay). + Network-fetched schemas are out of scope. + +## File layout + +``` +schemas/V_delta/ +├── stable/ ← document classes +├── draft/ +├── deprecated/ +├── examples/ +├── conversions/ +├── microschemas/ +│ ├── _DESIGN.md ← this file +│ ├── treatment/ ← namespace per host class +│ │ ├── stable/ +│ │ │ ├── drug.json +│ │ │ ├── virus_injection.json +│ │ │ └── stimulus_bath.json +│ │ ├── draft/ +│ │ │ └── optogenetic_silencing.json +│ │ └── deprecated/ +│ └── measurement/ +│ ├── stable/ +│ │ └── ... +│ └── draft/ +└── index.json +``` + +**Conventions:** + +- One directory per host class, named by the host class's `class_name`. +- Inside each host directory, the same `stable / draft / deprecated` + tier folders used elsewhere in V_delta. +- Filename stem equals the *discriminator value* (`drug.json` registers + the microschema for `treatment_kind: "drug"`). +- Reserved tier-folder names (`stable`, `draft`, `deprecated`) may not + be used as discriminator values. +- A discriminator value may live in at most one tier folder for a given + host class. Promoting `draft/` → `stable/` is a file move. + +## Microschema file format + +A microschema is a JSON **fragment**, not a full class schema. It has +two top-level keys: `microschema` (metadata) and `fields` (body shape). + +```json +{ + "microschema": { + "host_class": "treatment", + "discriminator_value": "drug", + "version": "1.0.0", + "maturity_level": "stable" + }, + "fields": [ + { + "name": "drug_name", + "type": "ontology_term", + "blank_value": { "node": "", "name": "" }, + "default_value": { "node": "", "name": "" }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Identity of the administered substance, expressed as an ontology term.", + "constraints": {} + }, + { + "name": "dose", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Numeric dose administered, in dose_units.", + "constraints": {} + }, + { + "name": "dose_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Units of dose (e.g., 'mg/kg', 'µM').", + "constraints": { "maxLength": 64 } + }, + { + "name": "route", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Route of administration (e.g., 'IP', 'IV', 'topical').", + "constraints": { "maxLength": 64 } + } + ] +} +``` + +**Rules:** + +- `microschema.host_class` must match the parent directory name. +- `microschema.discriminator_value` must match the filename stem. +- `microschema.maturity_level` must match the tier folder (`stable` / + `draft` / `deprecated`). +- `microschema.version` is semver. Like class_version, it tracks the + microschema's own evolution. +- `fields` follows the same field-definition shape used in regular + document class schemas (typed, with `blank_value`, `default_value`, + etc.). Microschemas may use any type V_delta supports, including + named composites and nested structures. +- Microschemas **may not** declare `superclasses`, `depends_on`, + `file`, `directory`, or any other top-level keys reserved for + document classes. + +## Host class linking + +A document class becomes a microschema host by declaring two fields with +specific `constraints`: + +- A **discriminator field** (typically `char`) whose value names the + microschema. +- A **body field** of type `structure` whose contents are validated by + the selected microschema. + +Example: `treatment.json` after host-conversion (sketch): + +```jsonc +{ + "document_class": { + "class_name": "treatment", + "class_version": "2.0.0", + "superclasses": [ { "class_name": "base" } ], + "maturity_level": "stable" + }, + "depends_on": [ + { "name": "subject_id", "mustBeNonEmpty": true, + "documentation": "...", "must_refer_to_document_class": "subject" } + ], + "file": [], + "fields": [ + { + "name": "treatment_kind", + "type": "char", + "documentation": "Discriminator. Names a microschema under microschemas/treatment//.json.", + "constraints": { + "maxLength": 64, + "microschema_discriminator_for": "treatment.parameters" + } + }, + { + "name": "parameters", + "type": "structure", + "documentation": "Kind-specific parameters; shape determined by treatment_kind.", + "constraints": { + "microschema_registry": "treatment", + "microschema_keyed_by": "treatment_kind" + } + } + ] +} +``` + +**Constraint keys (new in V_delta meta-schema):** + +- On the discriminator field: `microschema_discriminator_for` — + value is the dotted path of the body field this discriminator selects + for. Advisory, not required for resolution; documentation aid. +- On the body field: `microschema_registry` (string, required) — the + host-class-name namespace under `microschemas/`. Usually equals the + document class's own `class_name`, but doesn't have to. +- On the body field: `microschema_keyed_by` (string, required) — the + name of the discriminator field, relative to the same class block as + the body field. + +## Resolution rules + +When validating a document instance: + +1. Find the body field on a class in the inheritance chain that has + `microschema_registry` and `microschema_keyed_by` constraints. +2. Read the value of the field named by `microschema_keyed_by` from the + same class block on the document instance. Call this `D`. +3. Locate a microschema for `/` by checking, in order: + a. The **local overlay** (see "Local overlay" below). + b. The **central registry** at + `schemas/V_delta/microschemas///.json` for any + tier folder in which it exists. +4. If exactly one microschema is found, validate the body field's value + against the microschema's `fields`. +5. If **both** local overlay and central registry define `/`, + the validator **MUST** raise an error. There is no precedence rule; + the conflict is treated as authored ambiguity and refuses to validate + until the user resolves it by removing one definition. +6. If **neither** defines `/`, the validator **MUST** raise + an error (strict policy; see below). + +A microschema may appear in only one tier folder within the central +registry (CI-enforced — see "CI checks" below). + +## Validation policy: strict (closed-set) + +Documents whose discriminator value has no registered microschema in +either the local overlay or the central registry **fail validation**. +This is a deliberate choice: + +- It prevents documents from being authored with parameter bodies that + no one ever specified. +- It surfaces the need to register a new variant *before* documents + accumulate. +- It makes the registry the source of truth for "what kinds of + treatments exist." + +The relief valve for "I want to experiment locally without a central +PR" is the local overlay, not policy relaxation. + +## Local overlay + +Authors and labs may extend the registry without committing to the +central repository by configuring a **local overlay directory**. + +**Configuration:** an environment variable `DID_LOCAL_MICROSCHEMA_PATH` +points to a directory whose layout mirrors `schemas/V_delta/microschemas/` +under that root: + +``` +$DID_LOCAL_MICROSCHEMA_PATH/ +├── treatment/ +│ └── my_weird_optogenetic_protocol.json ← no tier folder; overlay is flat per host +└── measurement/ + └── ... +``` + +Notes: + +- The overlay does **not** use tier folders. Overlay microschemas have + no tier concept; they are unreviewed personal/lab extensions. +- Overlay files must still conform to the microschema file format and + rules (the `microschema.maturity_level` field on an overlay file is + ignored). +- Overlay shadowing of a central microschema is **not allowed**: if a + discriminator value exists in both the overlay and the central + registry (any tier), validation errors out. The user must remove one. +- CI runs do not have an overlay path. Production data is therefore + always validated against the central registry alone. + +**Detection at load time:** when the validator initializes, it should +log (at INFO or higher) every overlay microschema it picks up, so users +have visibility into which non-central definitions are in play. + +## Contribution funnel + +Three levels of commitment, with matching review burden: + +| Level | Where | Review | Visibility | +|---|---|---|---| +| **Personal/local** | `$DID_LOCAL_MICROSCHEMA_PATH//.json` | None | Author's machine only | +| **Draft (shared)** | `microschemas//draft/.json` | Light: correct format, CI passes, no obvious problems | Anyone using did-schema | +| **Stable (canonical)** | `microschemas//stable/.json` | Full: domain review, naming, ontology terms, field-level validation rules | Anyone using did-schema | + +Promotion `draft/` → `stable/` is a file move plus an updated +`microschema.maturity_level` value, gated on stable-level review. + +## CI checks + +The following invariants are enforced by CI on `did-schema`: + +1. **Filename ↔ metadata agreement.** For every microschema file, + `microschema.host_class` matches the parent host directory and + `microschema.discriminator_value` matches the filename stem. +2. **Tier ↔ metadata agreement.** `microschema.maturity_level` matches + the tier folder it lives in. +3. **Tier uniqueness.** Within a host class, no discriminator value + appears in more than one tier folder. +4. **Reserved-name protection.** `stable` / `draft` / `deprecated` are + not used as discriminator values. +5. **Host-class existence.** Every `microschemas//` corresponds to + a document class that exists in `schemas/V_delta/stable/.json` + (or draft/deprecated) AND that class declares a body field with a + matching `microschema_registry`. +6. **No microschema declares document-class-only keys** + (`document_class`, `superclasses`, `depends_on`, `file`, + `directory`). +7. **Index agreement.** Every microschema file is listed in + `index.json`'s `microschemas` section, and vice versa. + +## `index.json` extension + +The V_delta index gains a top-level `microschemas` array, parallel to +`schemas`: + +```jsonc +{ + "set_version": "V_delta", + "schemas": [ /* document classes */ ], + "microschemas": [ + { + "host_class": "treatment", + "discriminator_value": "drug", + "tier": "stable", + "version": "1.0.0", + "path": "schemas/V_delta/microschemas/treatment/stable/drug.json" + } + ] +} +``` + +## Open questions + +These are not blocking the design but should be settled before or during +implementation: + +1. **Versioning interaction.** What happens when a microschema is + version-bumped (1.0.0 → 1.1.0)? Documents in the wild reference the + discriminator value but don't pin a microschema version. Options: + (a) only one version of a microschema can be live at a time + (simplest); (b) microschemas keep all versions on disk and documents + pin via a separate field. I'd default to (a) for V_delta. + +2. **Inheritance interaction.** If `treatment` is a host and a subclass + `treatment_drug` inherits from it, does `treatment_drug` have its own + microschema registry, or does it share `treatment`'s? My read: it + shares, because the body field is declared on `treatment`. Subclass + document instances still consult `microschemas/treatment/...`. A + subclass could declare *its own* body field with its own + `microschema_registry` if it wants a separate registry, but that's + probably rare. + +3. **What stops a calculator from using microschemas instead of + per-class declarations?** Nothing technically — `calculator`-style + discrimination would work. But the convention should be: use + microschemas for *open registries* (treatments, measurements), use + per-class declarations for *closed kinds* (calculators, where each + kind is distinct code). Worth stating in V_delta_SPEC.md so the + right tool is reached for. + +4. **Validator behavior for unknown registry.** If a body field + declares `microschema_registry: "foobar"` and there's no + `microschemas/foobar/` directory, is that a load-time error or a + silent no-op? I'd say load-time error, caught by CI check (5). + +5. **Overlay path security.** Should the validator refuse to follow + symlinks in the overlay path? Or warn? Out of scope for the schema + model but relevant for consumer tooling. + +## Out of scope for this design + +- The implementation of the meta-schema extensions (new `constraints` + keys, new top-level `microschemas` index section). +- The validator rule implementing the resolution algorithm. +- Migration of the existing `treatment`, `treatment_drug`, + `stimulus_bath`, `virus_injection`, `measurement`, etc. classes to the + new model. That is its own PR with its own review. +- The DID-matlab side: loader updates, document-instance validation + against the resolved microschema, examples authoring. + +## Status + +Design only — no microschemas added, no host classes converted, no +meta-schema changes, no CI checks implemented. Discussion is the +deliverable for this commit. Convert classes and add microschemas in +subsequent PRs once this design is reviewed. diff --git a/schemas/V_zeta/stable/CURIE_lookups_meta.json b/schemas/V_zeta/stable/CURIE_lookups_meta.json new file mode 100644 index 0000000..f4e2d27 --- /dev/null +++ b/schemas/V_zeta/stable/CURIE_lookups_meta.json @@ -0,0 +1,92 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://did-schema.example.org/meta/CURIE_lookups_meta.json", + "title": "CURIE Registry for DID/NDI V_gamma", + "description": "Registry mapping CURIE prefixes (used in ontology_term.node values and in field-level ontology.node annotations) to their authoritative URI base and metadata. Consumer tooling uses this file to expand a CURIE such as 'uberon:0002436' into the full URI 'http://purl.obolibrary.org/obo/UBERON_0002436'. Prefixes are matched case-insensitively; by convention prefixes are written in lowercase inside documents and annotations.", + "format_version": "1.0.3", + "prefixes": { + "iao": { + "label": "Information Artifact Ontology", + "uri_base": "http://purl.obolibrary.org/obo/IAO_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "OBO Foundry ontology for information entities. Expansion rule: 'iao:NNNNNNN' -> 'http://purl.obolibrary.org/obo/IAO_NNNNNNN'." + }, + "uberon": { + "label": "Uber-anatomy Ontology", + "uri_base": "http://purl.obolibrary.org/obo/UBERON_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "Multi-species anatomy ontology." + }, + "pato": { + "label": "Phenotype And Trait Ontology", + "uri_base": "http://purl.obolibrary.org/obo/PATO_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "Ontology of phenotypic qualities." + }, + "emapa": { + "label": "Mouse Developmental Anatomy Ontology (abstract)", + "uri_base": "http://purl.obolibrary.org/obo/EMAPA_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "Anatomical ontology for the developing mouse." + }, + "ncit": { + "label": "NCI Thesaurus", + "uri_base": "http://purl.obolibrary.org/obo/NCIT_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "Controlled vocabulary for biomedical concepts. An OBO-style mirror is available at the given base; the canonical browser lives at https://ncit.nci.nih.gov/ncitbrowser/." + }, + "stato": { + "label": "Statistical Methods Ontology", + "uri_base": "http://purl.obolibrary.org/obo/STATO_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "OBO Foundry ontology of statistical methods, distributions, variables, and spread/variation metrics. Site: https://stato-ontology.org/." + }, + "obi": { + "label": "Ontology for Biomedical Investigations", + "uri_base": "http://purl.obolibrary.org/obo/OBI_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "OBO Foundry ontology of biological and clinical investigations. Used here for mid-level concepts (e.g., 'independent variable' OBI:0000750) that STATO imports rather than re-defining." + }, + "schema": { + "label": "Schema.org", + "uri_base": "https://schema.org/", + "uri_style": "direct", + "approximate": false, + "documentation": "General-purpose linked-data vocabulary. CURIE local part is the term name (e.g., 'schema:name' -> 'https://schema.org/name')." + }, + "allen_ccf_v3": { + "label": "Allen Mouse Brain Common Coordinate Framework v3", + "uri_base": "", + "uri_style": "local", + "approximate": false, + "documentation": "Identifiers are integer region IDs from the Allen CCF v3 structure graph. No canonical web URI is defined here; consumers should resolve via the Allen SDK or equivalent." + }, + "empty": { + "label": "Empty Ontology (Experimental Measurements, Purposes, and Treatments)", + "uri_base": "https://raw.githubusercontent.com/Waltham-Data-Science/empty-ontology/main/empty-base.owl#EMPTY_", + "uri_style": "obo_underscore", + "approximate": false, + "documentation": "Empty Ontology by Waltham Data Science — https://github.com/Waltham-Data-Science/empty-ontology. Term IDs are numeric (e.g., 'empty:0000001'). No PURL is in use yet; the canonical artefact is the GitHub-raw OWL file 'empty-base.owl' on the main branch, and CURIEs expand to a fragment within that file (matching the EMPTY_ prefix used inside the OWL). Consumer tooling (e.g., ndi-ontology-matlab) fetches the full OWL and searches by ID/label rather than dereferencing per-term URIs." + }, + "placeholder": { + "label": "Placeholder namespace for example and in-progress data", + "uri_base": "", + "uri_style": "local", + "approximate": true, + "documentation": "Reserved placeholder for documentation examples and for values that have not yet been mapped to a real ontology. Values are not expected to resolve. Flagged approximate so tooling can warn. Distinct from the 'empty' prefix (registered above), which points at the real Empty Ontology." + } + }, + "uri_styles": { + "obo_underscore": "Concatenate uri_base with the CURIE local part verbatim; underscore-separated form (e.g., 'http://purl.obolibrary.org/obo/UBERON_0002436').", + "direct": "Concatenate uri_base with the CURIE local part verbatim (e.g., 'https://schema.org/name').", + "local": "No URI expansion; the CURIE is the authoritative identifier and the uri_base is empty." + }, + "documentation": "This file is advisory, not enforced structurally by the meta-schema. It is consumed by tooling that needs to expand CURIEs to URIs, warn on unknown prefixes, or flag approximate namespaces. To add a prefix: add an entry under prefixes with all four metadata keys, bump format_version at least PATCH, and update V_gamma_SPEC.md's 'CURIE Registry' section." +} diff --git a/schemas/V_zeta/stable/annotation.json b/schemas/V_zeta/stable/annotation.json new file mode 100644 index 0000000..9fd130c --- /dev/null +++ b/schemas/V_zeta/stable/annotation.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "annotation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "subject_interaction" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/app.json b/schemas/V_zeta/stable/app.json new file mode 100644 index 0000000..2780404 --- /dev/null +++ b/schemas/V_zeta/stable/app.json @@ -0,0 +1,142 @@ +{ + "document_class": { + "class_name": "app", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "app_name", + "type": "char", + "blank_value": "", + "default_value": "ndi.app", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:name", + "name": "name" + }, + "documentation": "The name of the application.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "app_version", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:softwareVersion", + "name": "softwareVersion" + }, + "documentation": "The version of the app (often a Git commit identifier).", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "url", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:url", + "name": "url" + }, + "documentation": "The home page URL of the application.", + "constraints": { + "maxLength": 1024 + } + }, + { + "name": "os", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:operatingSystem", + "name": "operatingSystem" + }, + "documentation": "The operating system that ran the application.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "os_version", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:softwareVersion", + "name": "softwareVersion" + }, + "documentation": "The operating system version.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "interpreter", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:runtimePlatform", + "name": "runtimePlatform" + }, + "documentation": "The name of the interpreter (e.g., 'Matlab', 'python3').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "interpreter_version", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:softwareVersion", + "name": "softwareVersion" + }, + "documentation": "The version of the interpreter.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/base.json b/schemas/V_zeta/stable/base.json new file mode 100644 index 0000000..a9a1547 --- /dev/null +++ b/schemas/V_zeta/stable/base.json @@ -0,0 +1,78 @@ +{ + "document_class": { + "class_name": "base", + "class_version": "1.0.0", + "superclasses": [], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "id", + "type": "did_uid", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "Unique identifier for this document instance.", + "constraints": {} + }, + { + "name": "session_id", + "type": "did_uid", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "ncit:C169028", + "name": "Study Unique Identifier" + }, + "documentation": "Unique identifier of the session this document belongs to.", + "constraints": {} + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:name", + "name": "name" + }, + "documentation": "Human-readable name for this document.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "datestamp", + "type": "timestamp", + "blank_value": "", + "default_value": "2018-12-05T18:36:47.241Z", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:dateCreated", + "name": "dateCreated" + }, + "documentation": "UTC timestamp of document creation in ISO 8601 format.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/bath.json b/schemas/V_zeta/stable/bath.json new file mode 100644 index 0000000..fbb4750 --- /dev/null +++ b/schemas/V_zeta/stable/bath.json @@ -0,0 +1,55 @@ +{ + "document_class": { + "class_name": "bath", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "pharmacological_manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "kind", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Coarse purpose bucket.", + "constraints": { + "enum": [ + "drug", + "vehicle", + "wash", + "tracer" + ] + } + }, + { + "name": "location", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Type of chamber/vessel the bath was applied in (Petri dish, perfusion chamber, ...).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/binaryseries_parameters.json b/schemas/V_zeta/stable/binaryseries_parameters.json new file mode 100644 index 0000000..45c4430 --- /dev/null +++ b/schemas/V_zeta/stable/binaryseries_parameters.json @@ -0,0 +1,104 @@ +{ + "document_class": { + "class_name": "binaryseries_parameters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this binary series is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "double", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "ncit:C42645", + "name": "Data Type" + }, + "documentation": "The numeric data type of the binary series (e.g., 'double', 'single', 'int16', 'uint8').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "sample_rate", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "pato:0000044", + "name": "frequency" + }, + "documentation": "The sampling rate in samples per second (Hz).", + "constraints": {} + }, + { + "name": "num_channels", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "ncit:C25463", + "name": "Count" + }, + "documentation": "The number of channels in the binary series.", + "constraints": {} + }, + { + "name": "byte_order", + "type": "char", + "blank_value": "", + "default_value": "little-endian", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "ncit:C181701", + "name": "Byte Order" + }, + "documentation": "Byte order of the binary data ('little-endian' or 'big-endian').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "header_bytes", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "The number of header bytes to skip before reading binary data.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/binnedspikeratevm.json b/schemas/V_zeta/stable/binnedspikeratevm.json new file mode 100644 index 0000000..4b20266 --- /dev/null +++ b/schemas/V_zeta/stable/binnedspikeratevm.json @@ -0,0 +1,70 @@ +{ + "document_class": { + "class_name": "binnedspikeratevm", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the neuron element this binned spike rate was computed from.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "binnedspikeratevm_file", + "documentation": "The file containing binned spike rate and Vm data." + } + ], + "fields": [ + { + "name": "bin_size", + "type": "duration", + "blank_value": null, + "default_value": { + "seconds": 0.001, + "approximate": false, + "source_unit": "millisecond", + "source_value": 1.0 + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The width of each bin used to compute the binned spike rate, expressed as a duration.", + "constraints": { + "minimum": 0, + "allowed_units": [ + "nanosecond", + "microsecond", + "millisecond", + "second" + ] + } + }, + { + "name": "num_bins", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": { + "node": "ncit:C25463", + "name": "Count" + }, + "documentation": "The total number of bins.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/biological_transfer.json b/schemas/V_zeta/stable/biological_transfer.json new file mode 100644 index 0000000..2bd88f8 --- /dev/null +++ b/schemas/V_zeta/stable/biological_transfer.json @@ -0,0 +1,62 @@ +{ + "document_class": { + "class_name": "biological_transfer", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "procedural_manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "donor_id", + "mustBeNonEmpty": false, + "documentation": "The donor subject, when there is one. Optional (donorless transfers like cultured cells are real).", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [ + { + "name": "entity", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The biological material transferred (UBERON/CL/NDIC).", + "constraints": {} + }, + { + "name": "kind", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Coarse material bucket.", + "constraints": { + "enum": [ + "blood", + "cells", + "tissue_graft", + "lysate" + ] + } + } + ] +} diff --git a/schemas/V_zeta/stable/calculator.json b/schemas/V_zeta/stable/calculator.json new file mode 100644 index 0000000..291e138 --- /dev/null +++ b/schemas/V_zeta/stable/calculator.json @@ -0,0 +1,35 @@ +{ + "document_class": { + "class_name": "calculator", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "app" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "input_parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "placement": "concrete_class", + "documentation": "Calculator-specific input parameters. The concrete shape is determined by the calculator named in the inherited app.app_name field; the abstract calculator base does not constrain the contents. Placement is `concrete_class`: this field lives in the property block of the concrete calculator subclass (e.g., `simple_calc.input_parameters`, `tuningcurve_calc.input_parameters`), not in a `calculator` block, and the abstract `calculator` class contributes no property block to instance bodies. See V_gamma_SPEC.md \"Field placement\" under \"Field Definition Object\".", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/categorical_observation.json b/schemas/V_zeta/stable/categorical_observation.json new file mode 100644 index 0000000..f4481d2 --- /dev/null +++ b/schemas/V_zeta/stable/categorical_observation.json @@ -0,0 +1,43 @@ +{ + "document_class": { + "class_name": "categorical_observation", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "observation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The observed concept as a bound term (developmental stage, health status, behavioral phenotype, coat colour). One concept per document; the property observed is the spine `variable`, and the admissible root is a binding-registry nudge keyed on variable.", + "constraints": { + "binding": { + "keyed_by": "variable", + "expansion": "descendants", + "node_kind": "class", + "strength": "preferred", + "source": "ontology" + } + } + } + ] +} diff --git a/schemas/V_zeta/stable/contrast_sensitivity_calc.json b/schemas/V_zeta/stable/contrast_sensitivity_calc.json new file mode 100644 index 0000000..c1065cf --- /dev/null +++ b/schemas/V_zeta/stable/contrast_sensitivity_calc.json @@ -0,0 +1,351 @@ +{ + "document_class": { + "class_name": "contrast_sensitivity_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "calculator" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element whose contrast sensitivity is described.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_presentation that drove the responses.", + "must_refer_to_document_class": "stimulus_presentation" + }, + { + "name": "stimulus_response_scalar_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_response_scalar from which sensitivity was computed.", + "must_refer_to_document_class": "stimulus_response_scalar" + } + ], + "file": [], + "fields": [ + { + "name": "spatial_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Spatial frequencies (cycles per degree) at which contrast sensitivity is reported. One element per per-frequency value below.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "sensitivity_rb", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency contrast sensitivity derived from a Naka-Rushton RB fit at that frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "sensitivity_rbn", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency contrast sensitivity derived from a Naka-Rushton RBN fit at that frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "sensitivity_rbns", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency contrast sensitivity derived from a Naka-Rushton RBNS fit at that frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "relative_max_gain_rb", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency relative maximum gain from the RB fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "relative_max_gain_rbn", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency relative maximum gain from the RBN fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "relative_max_gain_rbns", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency relative maximum gain from the RBNS fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "empirical_c50_rb", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency empirical c50 from the RB fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "empirical_c50_rbn", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency empirical c50 from the RBN fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "empirical_c50_rbns", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency empirical c50 from the RBNS fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "saturation_index_rb", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency saturation index from the RB fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "saturation_index_rbn", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency saturation index from the RBN fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "saturation_index_rbns", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency saturation index from the RBNS fit.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "parameters_rb", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency fitted parameters from the RB model (one parameter set per frequency).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "parameters_rbn", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency fitted parameters from the RBN model.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "parameters_rbns", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency fitted parameters from the RBNS model.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fitless_interpolated_c50", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency interpolated c50 derived from the empirical curve (no model fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "is_modulated_response", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Indicates whether responses were treated as modulated (F1) rather than mean (F0).", + "constraints": {} + }, + { + "name": "visual_response_p_bonferroni", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency Bonferroni-corrected p-values for the visual-response ANOVA.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "response_varies_p_bonferroni", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-frequency Bonferroni-corrected p-values for the response-varies-across-contrasts ANOVA.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reduction applied per trial to produce each response value.", + "constraints": { + "maxLength": 64 + } + } + ] +} \ No newline at end of file diff --git a/schemas/V_zeta/stable/contrast_tuning.json b/schemas/V_zeta/stable/contrast_tuning.json new file mode 100644 index 0000000..95b5937 --- /dev/null +++ b/schemas/V_zeta/stable/contrast_tuning.json @@ -0,0 +1,698 @@ +{ + "document_class": { + "class_name": "contrast_tuning", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element whose contrast tuning is described.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_tuningcurve_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_tuningcurve from which this contrast tuning was derived.", + "must_refer_to_document_class": "stimulus_tuningcurve" + } + ], + "file": [], + "fields": [ + { + "name": "properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Bookkeeping properties describing how response values were measured and reported.", + "constraints": {}, + "fields": [ + { + "name": "response_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Units of the response values (e.g., 'spikes/s', 'dF/F').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "mean", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reduction applied to each stimulus presentation to yield a per-trial response (e.g., 'mean', 'peak', 'F1').", + "constraints": { + "maxLength": 64 + } + } + ] + }, + { + "name": "tuning_curve", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The empirical contrast tuning curve and per-point summary statistics.", + "constraints": {}, + "fields": [ + { + "name": "contrast", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The set of contrast values (1xN vector, 0-1 fraction) sampled along the tuning curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean response at each contrast, in response_units (1xN vector).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the responses at each contrast.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean response at each contrast.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Individual per-trial response values for each contrast. Rows index sampled contrasts; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the control-group response values at each contrast point.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean of the control-group response values at each contrast point.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "significance", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "ANOVA-derived significance metrics for the tuning curve.", + "constraints": {}, + "fields": [ + { + "name": "visual_response_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA across visual stimuli and the blank (control) stimulus. Indicates whether there is any evidence of visual responsiveness.", + "constraints": {} + }, + { + "name": "across_stimuli_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA across the visual stimuli. Indicates whether there is any evidence of differences in mean responses across the sampled contrasts.", + "constraints": {} + } + ] + }, + { + "name": "fitless", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fit-free summary measures derived directly from the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "interpolated_c50", + "type": "double", + "blank_value": 0, + "default_value": 0.5, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The contrast that produces half of the maximum response value, found by linear interpolation of the empirical (unfitted) responses.", + "constraints": {} + } + ] + }, + { + "name": "fit", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Naka-Rushton fits to the empirical contrast response curve. Three variants are stored, with progressively richer parameter vectors: RB ([Rm, C50], 2 parameters), RBN ([Rm, C50, N], 3 parameters, adds the saturation exponent N), and RBNS ([Rm, C50, N, S], 4 parameters, adds the asymptotic saturation S).", + "constraints": {}, + "fields": [ + { + "name": "naka_rushton_rb", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Two-parameter Naka-Rushton fit with parameter vector [Rm, C50]: Rm is the maximum response and C50 is the contrast at half-Rm.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector [Rm, C50] for the 2-parameter Naka-Rushton function.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "contrast", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of contrast values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted response values at each contrast in the contrast field.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The contrast with the maximum response under the fit.", + "constraints": {} + }, + { + "name": "empirical_c50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Empirical fit contrast that gives 50% of the response to 100% contrast. This generally differs from the C50 parameter of the fit, because the maximum response is not usually at 100% contrast.", + "constraints": {} + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The fit r^2 value.", + "constraints": {} + }, + { + "name": "relative_max_gain", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Relative maximum gain: the maximum slope of the fit when the maximum response is normalized to 1.", + "constraints": {} + }, + { + "name": "saturation_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Saturation index (R(Cmax) - R(1)) / (R(Cmax) - R(0)). Always 0 for the 2-parameter (RB) version.", + "constraints": {} + }, + { + "name": "sensitivity", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Contrast sensitivity vector (1x10): for each i in 1..10, sensitivity = 1/Cthreshold where R(Cthreshold) is the first response value greater than i standard deviations of the control response. If the standard deviation of the control response is 0, it is recalculated assuming the response is 1 unit per trial.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "naka_rushton_rbn", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Three-parameter Naka-Rushton fit with parameter vector [Rm, C50, N]: RB plus the saturation exponent N. Sub-field shape mirrors naka_rushton_rb.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector [Rm, C50, N] for the 3-parameter Naka-Rushton function.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "contrast", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of contrast values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted response values at each contrast in the contrast field.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The contrast with the maximum response under the fit.", + "constraints": {} + }, + { + "name": "empirical_c50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Empirical fit contrast that gives 50% of the response to 100% contrast. This generally differs from the C50 parameter of the fit, because the maximum response is not usually at 100% contrast.", + "constraints": {} + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The fit r^2 value.", + "constraints": {} + }, + { + "name": "relative_max_gain", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Relative maximum gain: the maximum slope of the fit when the maximum response is normalized to 1.", + "constraints": {} + }, + { + "name": "saturation_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Saturation index (R(Cmax) - R(1)) / (R(Cmax) - R(0)).", + "constraints": {} + }, + { + "name": "sensitivity", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Contrast sensitivity vector (1x10): for each i in 1..10, sensitivity = 1/Cthreshold where R(Cthreshold) is the first response value greater than i standard deviations of the control response. If the standard deviation of the control response is 0, it is recalculated assuming the response is 1 unit per trial.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "naka_rushton_rbns", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Four-parameter Naka-Rushton fit with parameter vector [Rm, C50, N, S]: RBN plus the asymptotic-saturation term S. Sub-field shape mirrors naka_rushton_rb.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector [Rm, C50, N, S] for the 4-parameter Naka-Rushton-with-saturation function.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "contrast", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of contrast values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted response values at each contrast in the contrast field.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The contrast with the maximum response under the fit.", + "constraints": {} + }, + { + "name": "empirical_c50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Empirical fit contrast that gives 50% of the response to 100% contrast. This generally differs from the C50 parameter of the fit, because the maximum response is not usually at 100% contrast.", + "constraints": {} + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The fit r^2 value.", + "constraints": {} + }, + { + "name": "relative_max_gain", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Relative maximum gain: the maximum slope of the fit when the maximum response is normalized to 1.", + "constraints": {} + }, + { + "name": "saturation_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Saturation index (R(Cmax) - R(1)) / (R(Cmax) - R(0)).", + "constraints": {} + }, + { + "name": "sensitivity", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Contrast sensitivity vector (1x10): for each i in 1..10, sensitivity = 1/Cthreshold where R(Cthreshold) is the first response value greater than i standard deviations of the control response. If the standard deviation of the control response is 0, it is recalculated assuming the response is 1 unit per trial.", + "constraints": { + "element_type": "double" + } + } + ] + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/contrast_tuning_calc.json b/schemas/V_zeta/stable/contrast_tuning_calc.json new file mode 100644 index 0000000..b703b73 --- /dev/null +++ b/schemas/V_zeta/stable/contrast_tuning_calc.json @@ -0,0 +1,21 @@ +{ + "document_class": { + "class_name": "contrast_tuning_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "contrast_tuning" + }, + { + "class_name": "tuning_fit" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} \ No newline at end of file diff --git a/schemas/V_zeta/stable/control_stimulus_ids.json b/schemas/V_zeta/stable/control_stimulus_ids.json new file mode 100644 index 0000000..5f54048 --- /dev/null +++ b/schemas/V_zeta/stable/control_stimulus_ids.json @@ -0,0 +1,105 @@ +{ + "document_class": { + "class_name": "control_stimulus_ids", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "app" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": false, + "documentation": "Optional pointer to the stimulus_presentation document these control IDs annotate.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "control_stimulus_ids", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Integer identifier(s) of the stimulus condition(s) that serve as the control reference for the linked stimulus_presentation. v1 sometimes ships NaN when no control was recorded; sometimes a scalar; sometimes an array.", + "constraints": {} + }, + { + "name": "control_stimulus_id_method", + "type": "structure", + "blank_value": { + "method": "", + "controlid": "", + "controlid_value": 0 + }, + "default_value": { + "method": "", + "controlid": "", + "controlid_value": 0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "How the control_stimulus_ids were derived. v1 uniformly ships a 3-field struct: method (e.g., 'pseudorandom'), controlid (e.g., 'isblank'), and controlid_value (numeric tag, e.g., 1).", + "constraints": {}, + "fields": [ + { + "name": "method", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Name of the algorithm used to identify which stimuli are controls (e.g., 'pseudorandom', 'explicit_list').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "controlid", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Name of the per-stimulus key that flags control trials (e.g., 'isblank').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "controlid_value", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Value of `controlid` that marks a trial as a control (e.g., 1).", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/daqmetadatareader.json b/schemas/V_zeta/stable/daqmetadatareader.json new file mode 100644 index 0000000..f7df719 --- /dev/null +++ b/schemas/V_zeta/stable/daqmetadatareader.json @@ -0,0 +1,66 @@ +{ + "document_class": { + "class_name": "daqmetadatareader", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "daqsystem_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the DAQ system this metadata reader is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "ndi_daqmetadatareader_class", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the metadata reader implementation.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "metadata_names", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Comma-separated list of metadata field names this reader can extract (e.g., 'sample_rate,num_channels,device_name').", + "constraints": {} + }, + { + "name": "tab_separated_file_parameter", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional 'lazy hook' field: if the metadata for each epoch is a tab-separated file, the base ndi.daq.metadatareader uses this field to identify the per-epoch file without requiring a subclass. Preserved as a v1 → V_delta pass-through; new code should prefer a dedicated subclass (e.g., daqmetadatareader_tsv) when one exists.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/stable/daqmetadatareader_epochdata_ingested.json b/schemas/V_zeta/stable/daqmetadatareader_epochdata_ingested.json new file mode 100644 index 0000000..c6e4762 --- /dev/null +++ b/schemas/V_zeta/stable/daqmetadatareader_epochdata_ingested.json @@ -0,0 +1,25 @@ +{ + "document_class": { + "class_name": "daqmetadatareader_epochdata_ingested", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "daqmetadatareader_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the DAQ metadata reader whose epoch data has been ingested.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/daqreader.json b/schemas/V_zeta/stable/daqreader.json new file mode 100644 index 0000000..35b23a7 --- /dev/null +++ b/schemas/V_zeta/stable/daqreader.json @@ -0,0 +1,31 @@ +{ + "document_class": { + "class_name": "daqreader", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "ndi_daqreader_class", + "type": "char", + "blank_value": "", + "default_value": "ndi_daqreader", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the DAQ reader implementation.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/daqreader_epochdata_ingested.json b/schemas/V_zeta/stable/daqreader_epochdata_ingested.json new file mode 100644 index 0000000..21ba839 --- /dev/null +++ b/schemas/V_zeta/stable/daqreader_epochdata_ingested.json @@ -0,0 +1,76 @@ +{ + "document_class": { + "class_name": "daqreader_epochdata_ingested", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "daqreader_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the DAQ reader whose epoch data has been ingested.", + "must_refer_to_document_class": "" + }, + { + "name": "epochid", + "mustBeNonEmpty": true, + "documentation": "The document ID of the epoch whose data was ingested.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "epochtable", + "type": "structure", + "blank_value": { + "epochclock": [], + "t0_t1": [] + }, + "default_value": { + "epochclock": [], + "t0_t1": [] + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Captured epoch-table snapshot for the ingested epoch. v1 ships {epochclock: [], t0_t1: [t0, t1]} — clock identifier(s) and the corresponding start/stop time pair, both in the units of that clock.", + "constraints": {}, + "fields": [ + { + "name": "epochclock", + "type": "string", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Cell array of clock identifier strings (e.g., {'dev_local_time'}) that index the t0_t1 row(s).", + "constraints": {} + }, + { + "name": "t0_t1", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Two-element [t0, t1] start/stop time pair in the units of the matching epochclock entry.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/daqreader_mfdaq_epochdata_ingested.json b/schemas/V_zeta/stable/daqreader_mfdaq_epochdata_ingested.json new file mode 100644 index 0000000..e441450 --- /dev/null +++ b/schemas/V_zeta/stable/daqreader_mfdaq_epochdata_ingested.json @@ -0,0 +1,69 @@ +{ + "document_class": { + "class_name": "daqreader_mfdaq_epochdata_ingested", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "daqreader_epochdata_ingested" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "parameters", + "type": "structure", + "blank_value": { + "sample_analog_segment": 0.0, + "sample_digital_segment": 0.0 + }, + "default_value": { + "sample_analog_segment": 0.0, + "sample_digital_segment": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reader-specific parameters captured at the time the epoch was ingested. The two sub-fields seen in the v1 corpora are sample-count cutoffs the MFDAQ reader used to slice the source recording.", + "constraints": {}, + "fields": [ + { + "name": "sample_analog_segment", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Maximum sample count per analog segment used during ingestion.", + "constraints": {} + }, + { + "name": "sample_digital_segment", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Maximum sample count per digital segment used during ingestion.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/daqreader_ndr.json b/schemas/V_zeta/stable/daqreader_ndr.json new file mode 100644 index 0000000..0296af9 --- /dev/null +++ b/schemas/V_zeta/stable/daqreader_ndr.json @@ -0,0 +1,64 @@ +{ + "document_class": { + "class_name": "daqreader_ndr", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "daqreader" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "ndi_daqreader_ndr_class", + "type": "char", + "blank_value": "", + "default_value": "ndi.daq.reader.mfdaq.ndr", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The NDI reader class that implements this NDR-backed daqreader.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "ndr_reader_string", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The NDR file type this reader handles (e.g., 'SpikeGadgets', 'Intan', 'CED').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "file_extension", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The file extension associated with this reader (e.g., '.rec', '.rhd', '.smr').", + "constraints": { + "maxLength": 32 + } + } + ] +} diff --git a/schemas/V_zeta/stable/daqsystem.json b/schemas/V_zeta/stable/daqsystem.json new file mode 100644 index 0000000..ecabadf --- /dev/null +++ b/schemas/V_zeta/stable/daqsystem.json @@ -0,0 +1,44 @@ +{ + "document_class": { + "class_name": "daqsystem", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "filenavigator_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the file navigator used by this DAQ system.", + "must_refer_to_document_class": "" + }, + { + "name": "daqreader_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the DAQ reader used by this DAQ system.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "ndi_daqsystem_class", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the DAQ system implementation.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/dataset_remote.json b/schemas/V_zeta/stable/dataset_remote.json new file mode 100644 index 0000000..55d7a48 --- /dev/null +++ b/schemas/V_zeta/stable/dataset_remote.json @@ -0,0 +1,61 @@ +{ + "document_class": { + "class_name": "dataset_remote", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "remote_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type of remote storage (e.g., 's3', 'http', 'globus', 'git').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "dataset_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The dataset identifier at the remote location.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "organization_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Organization identifier at the remote service (e.g., the lab or owning group whose namespace the dataset lives under).", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/dataset_session_info.json b/schemas/V_zeta/stable/dataset_session_info.json new file mode 100644 index 0000000..c4b8931 --- /dev/null +++ b/schemas/V_zeta/stable/dataset_session_info.json @@ -0,0 +1,66 @@ +{ + "document_class": { + "class_name": "dataset_session_info", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "session_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the session this info describes.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "dataset_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The identifier of the dataset this session belongs to.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "session_index", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The zero-based index of this session within the dataset.", + "constraints": {} + }, + { + "name": "reference_path", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The file-system path or reference for this session's data.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/stable/demo_ndi.json b/schemas/V_zeta/stable/demo_ndi.json new file mode 100644 index 0000000..ffa0fae --- /dev/null +++ b/schemas/V_zeta/stable/demo_ndi.json @@ -0,0 +1,44 @@ +{ + "document_class": { + "class_name": "demo_ndi", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "demo_param1", + "type": "double", + "blank_value": 0.0, + "default_value": 1.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A demonstration numeric parameter.", + "constraints": {} + }, + { + "name": "demo_param2", + "type": "char", + "blank_value": "", + "default_value": "hello", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A demonstration string parameter.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/demo_ndi_mock.json b/schemas/V_zeta/stable/demo_ndi_mock.json new file mode 100644 index 0000000..084725d --- /dev/null +++ b/schemas/V_zeta/stable/demo_ndi_mock.json @@ -0,0 +1,44 @@ +{ + "document_class": { + "class_name": "demo_ndi_mock", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "mock_value", + "type": "double", + "blank_value": 0.0, + "default_value": 42.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A mock numeric value for testing purposes.", + "constraints": {} + }, + { + "name": "mock_label", + "type": "char", + "blank_value": "", + "default_value": "mock", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A mock string label for testing purposes.", + "constraints": { + "maxLength": 128 + } + } + ] +} diff --git a/schemas/V_zeta/stable/derivation.json b/schemas/V_zeta/stable/derivation.json new file mode 100644 index 0000000..175337b --- /dev/null +++ b/schemas/V_zeta/stable/derivation.json @@ -0,0 +1,43 @@ +{ + "document_class": { + "class_name": "derivation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "source_subject_id_#", + "mustBeNonEmpty": true, + "documentation": "The source subject(s) from which the derived subject (subject_id) was produced.", + "must_refer_to_document_class": "subject", + "multiple": true + } + ], + "file": [], + "fields": [ + { + "name": "derivation_method", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "How the derivation happened (surgical_dissection | cell_culture_passage | biological_pooling | biological_reproduction | ...).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/did_schema_meta.json b/schemas/V_zeta/stable/did_schema_meta.json new file mode 100644 index 0000000..7431b8b --- /dev/null +++ b/schemas/V_zeta/stable/did_schema_meta.json @@ -0,0 +1,326 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://did-schema.example.org/V_delta/did_schema_meta.json", + "title": "DID/NDI Schema Meta-Schema (V_delta)", + "description": "Validates the structure of DID/NDI schema files for V_delta. V_delta introduces named composite types 'duration', 'ontology_term', 'volume', 'mass', 'length', 'voltage', 'current', 'frequency', 'concentration', 'temperature', 'pressure', 'count', and 'score', and a redesigned field-level 'ontology' annotation shape with keys 'node' (CURIE) and 'name' (label); the CURIE prefix is resolved against CURIE_lookups_meta.json. The nine single-canonical typed-quantity composites ('duration', 'volume', 'mass', 'length', 'voltage', 'current', 'frequency', 'temperature', 'pressure') share the same sub-field layout (a canonical-unit double, 'approximate' boolean, 'source_unit' char, 'source_value' double); only the canonical sub-field name and the allowed source units differ. The canonicals are SI base units except for 'temperature' (canonical 'celsius' rather than the SI Kelvin because °C is the curator-natural unit for biological temperature; allowed source units include °C / C / Celsius / K / Kelvin / °F / F / Fahrenheit) and 'pressure' (canonical 'mmhg' rather than the SI pascal because mmHg is the curator-natural unit for biological pressure — blood pressure, intraocular pressure, partial pressures; allowed source units include mmHg / torr / kPa / Pa / cmH2O / bar / mbar / psi / atm). 'concentration' breaks the single-canonical pattern because concentration units do not collapse to a single canonical (mass/volume cannot be converted to molar without molecular weight, and vice versa); instead it offers multiple OPTIONAL canonical sub-fields ('molar', 'grams_per_liter', 'mass_fraction', 'volume_fraction', 'particles_per_liter') and the migrator populates whichever the source unit is computable into, alongside the same 'approximate' / 'source_unit' / 'source_value' triple. The 'particles_per_liter' canonical covers count-per-volume entries (viral titer in vg/mL, gc/mL, vp/mL, TU/mL, IU/mL, pfu/mL, TCID50/mL and equivalents — multiply by 1000 to go from per-mL to per-liter); the kind-of-particle distinction (genome vs physical-particle vs functional unit) is not collapsed by the canonical and remains carried by 'source_unit'. 'count' is the typed composite for discrete-count quantities (sub-fields: value: integer, unit: ontology_term identifying what is counted such as cells / individuals / spikes / events, approximate: boolean); the integer does not normalize across units because counts have no dimensional scaling — the unit is semantic, not dimensional, and the composite exists so validators and queries can identify count-style quantities as a group. 'score' is the typed composite for scale-based assessment values (sub-fields: value: double, scale: ontology_term identifying the scoring rubric such as Murine Body Condition Score, scale_min: double, scale_max: double, approximate: boolean); double rather than integer allows half-integer increments. NAMING CONVENTION: V_delta drops the V_beta underscore prefix on NDI-extension keys. Every reserved key \u2014 JSON Schema vocabulary or NDI extension \u2014 is used without an underscore prefix; the authoritative enumeration of NDI-reserved names lives in ndi_reserved_keys.json and is enforced by this meta-schema. Schema authors must not reuse a reserved name as their own data field name.", + "type": "object", + "required": [ + "document_class", + "depends_on", + "fields" + ], + "additionalProperties": false, + "properties": { + "document_class": { + "$ref": "#/$defs/document_class_header" + }, + "depends_on": { + "type": "array", + "items": { + "$ref": "#/$defs/dependency_object" + }, + "description": "Array of dependency objects. Top-level (not under document_class) because dependency declarations attach to the class but dependency values in document instances are cross-document and are kept at the top level of the instance for query convenience." + }, + "file": { + "type": "array", + "items": { + "$ref": "#/$defs/file_record" + }, + "description": "Array of file record objects. Optional \u2014 omit for document types that have no associated files." + }, + "directory": { + "type": "array", + "items": { + "$ref": "#/$defs/directory_record" + }, + "description": "Array of directory record objects. Optional \u2014 omit for document types that have no associated directories." + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/$defs/field_definition" + }, + "description": "Array of field definition objects." + } + }, + "$defs": { + "document_class_header": { + "type": "object", + "required": [ + "class_name", + "class_version", + "superclasses", + "maturity_level" + ], + "additionalProperties": false, + "properties": { + "class_name": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "description": "Unique name of the document type." + }, + "class_version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$", + "description": "Semantic version string MAJOR.MINOR.PATCH." + }, + "superclasses": { + "type": "array", + "items": { + "$ref": "#/$defs/superclass_reference" + }, + "description": "Array of superclass reference objects (class_name + schema path)." + }, + "maturity_level": { + "type": "string", + "enum": [ + "stable", + "draft", + "deprecated" + ], + "description": "Maturity level of this schema. Must agree with the schema's tier folder (stable/draft/deprecated) under schemas/V_delta/." + }, + "abstract": { + "type": "boolean", + "description": "If true, no document may have document_class.class_name equal to this class \u2014 only concrete subclasses may be instantiated. Default false when omitted. Does not affect inheritance, field flattening, or isa query matching." + } + } + }, + "superclass_reference": { + "type": "object", + "required": [ + "class_name" + ], + "additionalProperties": false, + "properties": { + "class_name": { + "type": "string", + "description": "Name of the parent class. Path-based resolution is removed in V_delta; consumer tooling resolves superclass schemas by class_name via schemas/V_delta/index.json." + } + } + }, + "dependency_object": { + "type": "object", + "required": [ + "name", + "mustBeNonEmpty", + "documentation", + "must_refer_to_document_class" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Role name of the dependency. The '#' character is a numeric placeholder: a name such as 'syncrule_id_#' matches any runtime name of the form 'syncrule_id_1', 'syncrule_id_2', etc. When '#' appears, 'multiple' must be true." + }, + "mustBeNonEmpty": { + "type": "boolean", + "description": "Whether the dependency value must be non-empty at validation time." + }, + "multiple": { + "type": "boolean", + "description": "If true, the document may carry zero or more instances of this dependency at runtime, distinguished by substituting a positive integer for the '#' placeholder in 'name' (e.g., a 'name' of 'syncrule_id_#' yields runtime keys 'syncrule_id_1', 'syncrule_id_2', etc.). The '#' placeholder is required in 'name' whenever 'multiple' is true. Omit or set to false for exactly-one dependencies, in which case 'name' must not contain '#'." + }, + "documentation": { + "type": "string", + "description": "Human-readable description." + }, + "must_refer_to_document_class": { + "type": "string", + "pattern": "^$|^[a-zA-Z][a-zA-Z0-9_]*(,[a-zA-Z][a-zA-Z0-9_]*)*$", + "description": "Comma-separated enumerated list of class_name values that the referenced document may belong to. Empty string means no constraint on the referenced document class." + } + } + }, + "file_record": { + "type": "object", + "required": [ + "name", + "documentation" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Identifier for this file record." + }, + "documentation": { + "type": "string", + "description": "Description of the file's contents." + } + } + }, + "directory_record": { + "type": "object", + "required": [ + "name", + "documentation" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Identifier for this directory record. Must not collide with any file record name on the same schema." + }, + "documentation": { + "type": "string", + "description": "Description of the directory's contents." + } + } + }, + "ontology_object": { + "type": "object", + "required": [ + "node", + "name" + ], + "additionalProperties": false, + "properties": { + "node": { + "type": "string", + "description": "CURIE identifier of the form 'prefix:local', where 'prefix' is a key in CURIE_lookups_meta.json (e.g., 'iao:0000578')." + }, + "name": { + "type": "string", + "description": "Human-readable label of the ontology term (e.g., 'centrally registered identifier')." + } + } + }, + "field_definition": { + "type": "object", + "required": [ + "name", + "type", + "blank_value", + "default_value", + "mustBeNonEmpty", + "mustBeScalar", + "mustNotHaveNaN", + "queryable", + "ontology", + "documentation", + "constraints" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "description": "Field name." + }, + "type": { + "type": "string", + "enum": [ + "did_uid", + "char", + "string", + "integer", + "double", + "matrix", + "timestamp", + "boolean", + "structure", + "duration", + "ontology_term", + "volume", + "mass", + "length", + "voltage", + "current", + "frequency", + "concentration", + "temperature", + "pressure", + "count", + "score" + ], + "description": "Data type of the field. Uses the standard JSON Schema keyword 'type'; values are NDI-specific." + }, + "blank_value": { + "description": "Value in a freshly constructed blank document. May fail validation." + }, + "default_value": { + "description": "Legitimate fallback value. Must pass validation." + }, + "mustBeNonEmpty": { + "type": "boolean", + "description": "Value may not be null, empty string, empty array, or empty object at validation time." + }, + "mustBeScalar": { + "type": "boolean", + "description": "Value must be a single element (not array/matrix). Domain-specific to MATLAB/scientific computing; has no JSON Schema equivalent." + }, + "mustNotHaveNaN": { + "type": "boolean", + "description": "No NaN values permitted. Domain-specific; NaN is not valid JSON but can appear in MATLAB/HDF5 data." + }, + "queryable": { + "type": "boolean", + "description": "Whether this field is indexed in the database." + }, + "ontology": { + "oneOf": [ + { + "$ref": "#/$defs/ontology_object" + }, + { + "type": "null" + } + ], + "description": "Ontology node, or null." + }, + "documentation": { + "type": "string", + "description": "Human-readable description of the field." + }, + "constraints": { + "type": "object", + "description": "Standard JSON Schema validation keywords constraining this field's value (e.g., minLength, minimum, maximum, pattern, enum). Use {} for unconstrained. JSON Schema validators can apply these keywords directly to field values." + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/$defs/field_definition" + }, + "description": "Nested field definitions for structure type fields." + }, + "discriminator": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "description": "Optional, only meaningful for type: 'structure'. Names a sub-field within fields whose value tags discriminated-union element variants. The discriminator sub-field is conventionally a char field with an enum constraint. The meta-schema does not enforce variant-specific required-field rules; consumer tooling and per-schema documentation define those." + }, + "placement": { + "type": "string", + "enum": [ + "declaring_class", + "concrete_class" + ], + "description": "Optional per-field opt-in to placement on the concrete subclass's block instead of the declaring class's block on document instances. Default when omitted is 'declaring_class', which matches the V_gamma per-class block default. Setting 'concrete_class' is only meaningful on a field declared by an abstract class (document_class.abstract: true); a concrete class's field with 'placement: concrete_class' is a schema error. See V_gamma_SPEC.md 'Field placement' under 'Field Definition Object'. Collisions are a hard error reported at class-cache build time: (a) two ancestors that both place the same field name into the concrete-class block, or (b) any class in the chain (abstract or concrete) that declares a field whose name matches a placement: concrete_class declaration on any ancestor." + } + }, + "if": { + "properties": { + "type": { + "const": "structure" + } + } + }, + "then": { + "required": [ + "name", + "type", + "blank_value", + "default_value", + "mustBeNonEmpty", + "mustBeScalar", + "mustNotHaveNaN", + "queryable", + "ontology", + "documentation", + "constraints", + "fields" + ] + } + } + } +} diff --git a/schemas/V_zeta/stable/directory.json b/schemas/V_zeta/stable/directory.json new file mode 100644 index 0000000..9ebabc9 --- /dev/null +++ b/schemas/V_zeta/stable/directory.json @@ -0,0 +1,114 @@ +{ + "document_class": { + "class_name": "directory", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "parent_doc_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the parent document that owns this directory. For subdirectories, this is still the root owning document (not the parent directory), enabling a single query to retrieve the entire directory tree for a document.", + "must_refer_to_document_class": "" + }, + { + "name": "parent_directory_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the parent directory document. Empty for top-level directories (those directly attached to the owning document's directory slot). Non-empty for subdirectories.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "manifest_file", + "documentation": "A file listing the contents of this directory. The format is specified by the manifest_format field. The manifest is internal infrastructure and is not accessible via open_binary_file; use get_directory_manifest instead. Files listed in the manifest are accessible via open_binary_file(directory_doc_id, filename)." + } + ], + "fields": [ + { + "name": "dirname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The directory name (e.g., 'raw_data/', 'metadata/'). This is the actual name of the directory, which may differ from the directory_role.", + "constraints": { + "maxLength": 512 + } + }, + { + "name": "directory_role", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the directory slot this directory fills on the parent document's schema. Non-empty for top-level directories (e.g., 'raw_data' matching a directory entry on the parent). Empty for subdirectories, which are not bound to a schema slot.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "num_entries", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of file entries in this directory's manifest (not counting subdirectories, which are separate directory documents).", + "constraints": { + "minimum": 0 + } + }, + { + "name": "manifest_format", + "type": "char", + "blank_value": "", + "default_value": "jsonlines", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The format of the manifest file. 'jsonlines' is one JSON object per line with keys filename, size, checksum_sha256 (no per-entry URIs; the directory's files all live under the same store as the directory document). 'jsonlines_uri' is the same plus an optional per-entry 'uri' field; entries without 'uri' are resolved against the directory's base_uri. 'kerchunk_parquet' is a Parquet file of kerchunk-style {key, uri, offset, length} references, used for mixed-source virtual aggregations (reserved for future use). 'zarr_implicit' means no manifest file is present; consumer tooling derives chunk paths from the owning zarr document's recipe (shape, chunks, dimension_separator) plus base_uri, and the manifest_file attachment may be empty.", + "constraints": { + "enum": [ + "jsonlines", + "jsonlines_uri", + "kerchunk_parquet", + "zarr_implicit" + ] + } + }, + { + "name": "base_uri", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional URI prefix used as the resolution root for files in this directory. Examples: 's3://bucket/light_sheet_001/', 'https://data.example.org/img42/', or empty when files are local relative to the document's storage. Required when manifest_format is 'zarr_implicit' (since the consumer must construct chunk URIs from base_uri plus the zarr recipe). Optional when manifest_format is 'jsonlines_uri' (used as the default for entries that omit their own 'uri'). Ignored when manifest_format is 'jsonlines'. Credentials are never included in base_uri; they are supplied by the consumer environment.", + "constraints": { + "maxLength": 2048 + } + } + ] +} diff --git a/schemas/V_zeta/stable/distance_metadata.json b/schemas/V_zeta/stable/distance_metadata.json new file mode 100644 index 0000000..01f581e --- /dev/null +++ b/schemas/V_zeta/stable/distance_metadata.json @@ -0,0 +1,132 @@ +{ + "document_class": { + "class_name": "distance_metadata", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element whose endpoints' distance is described by this metadata.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "endpoints", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Array of per-endpoint records describing the entities whose pairwise distance is being measured. v1 stored exactly two endpoints labelled 'A' and 'B'; V_delta keeps those labels explicit on each record's `label` field but generalises the container to an array so future N-endpoint distance schemes can reuse the same shape. Each endpoint carries: an ontology classification (`measurement`), a set of integer indices and document-id strings identifying which items at the linked element the endpoint covers, and an optional numeric-values vector. v1's `ontologyStringValues_X` (comma-separated did_uid list) becomes `string_ids` as a string array; v1's `integerIDs_X` (scalar or array) becomes `integer_ids` as a matrix.", + "constraints": {}, + "fields": [ + { + "name": "label", + "type": "char", + "blank_value": "", + "default_value": "A", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-endpoint identifier preserved verbatim from v1 (e.g., 'A', 'B'). Consumers can filter by label without resolving the ontology classification.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "measurement", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology term classifying what kind of entity this endpoint refers to (e.g., a probe contact, a stimulation site). `node` is the v1 `ontologyNode_X` CURIE verbatim; `name` is resolved via ndi.ontology.lookup at conversion time.", + "constraints": {} + }, + { + "name": "integer_ids", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Per-endpoint integer indices (e.g., contact numbers, item indices). v1 stored this as a scalar or array of integers; V_delta keeps it as a flat matrix of integers.", + "constraints": { + "element_type": "integer" + } + }, + { + "name": "string_ids", + "type": "string", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-endpoint document-id strings identifying the items the endpoint covers. v1 stored this as a single comma-separated did_uid string; V_delta represents it as a string array (one entry per id). Indexed in parallel with `integer_ids` when both are populated.", + "constraints": {} + }, + { + "name": "numeric_values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Optional per-endpoint numeric values (often empty in v1 corpora; reserved for calibrations or per-item measurements that the endpoint definition needs to carry inline).", + "constraints": {} + } + ] + }, + { + "name": "units", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology term naming the measurement unit for the distance (e.g., 'micrometer'). Resolved via ndi.ontology.lookup.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/electrode_offset_voltage.json b/schemas/V_zeta/stable/electrode_offset_voltage.json new file mode 100644 index 0000000..da83160 --- /dev/null +++ b/schemas/V_zeta/stable/electrode_offset_voltage.json @@ -0,0 +1,53 @@ +{ + "document_class": { + "class_name": "electrode_offset_voltage", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "probe_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the probe this offset voltage data belongs to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "offset_voltages", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Array of DC offset voltage values, one per electrode channel, in voltage_units. Length must match the number of channels on the probe.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "voltage_units", + "type": "char", + "blank_value": "", + "default_value": "V", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The units of the offset voltage values (e.g., 'V', 'mV', 'uV').", + "constraints": { + "maxLength": 16 + } + } + ] +} diff --git a/schemas/V_zeta/stable/element.json b/schemas/V_zeta/stable/element.json new file mode 100644 index 0000000..eae7fd1 --- /dev/null +++ b/schemas/V_zeta/stable/element.json @@ -0,0 +1,109 @@ +{ + "document_class": { + "class_name": "element", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "underlying_element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the underlying element, if this element derives from another.", + "must_refer_to_document_class": "" + }, + { + "name": "subject_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the subject associated with this element.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "ndi_element_class", + "type": "char", + "blank_value": "", + "default_value": "ndi_element", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the NDI element class that is stored.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:name", + "name": "name" + }, + "documentation": "The name of the element. Elements are uniquely defined by name, reference, and type.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "reference", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The reference number of the element.", + "constraints": { + "min": 0, + "max": 100000 + } + }, + { + "name": "type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type of the element. Common probe types are defined in probetype2object.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "direct", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Does this element directly feed data from an underlying element? 0 for no, 1 for yes.", + "constraints": { + "min": 0, + "max": 1 + } + } + ] +} diff --git a/schemas/V_zeta/stable/element_epoch.json b/schemas/V_zeta/stable/element_epoch.json new file mode 100644 index 0000000..9107a88 --- /dev/null +++ b/schemas/V_zeta/stable/element_epoch.json @@ -0,0 +1,340 @@ +{ + "document_class": { + "class_name": "element_epoch", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element associated with this epoch.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "clocks", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Array-of-records: one entry per clock reference frame in which this element's epoch is timed. Each entry carries the clock identifier (`name`) and the start/stop times (`t0`, `t1`) in that clock's units. The single-clock case (most v1 documents) is a 1-element array; v1 documents that recorded the same epoch in multiple clocks (e.g., 'dev_local_time' + 'exp_global_time') become multi-element arrays. Comma-separated v1 `epoch_clock` strings split on `,` to populate clocks[i].name; v1's N\u00d72 `t0_t1` splits row-wise to populate clocks[i].t0 and clocks[i].t1.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "dev_local_time", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Clock identifier (e.g., 'dev_local_time', 'utc', 'exp_global_time').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "t0", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Start time of this epoch in the units of the clock named in this record.", + "constraints": {} + }, + { + "name": "t1", + "type": "double", + "blank_value": 1.0, + "default_value": 1.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Stop time of this epoch in the units of the clock named in this record.", + "constraints": {} + } + ] + }, + { + "name": "axes", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional self-describing sampled/index dimensions of this epoch's data (V_epsilon dataseries header). Each axis describes one grid dimension.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis name (e.g. 'time', 'x', 'y').", + "constraints": {} + }, + { + "name": "kind", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis kind (time | space_x | space_y | space_z | section | index | wavelength | ...).", + "constraints": {} + }, + { + "name": "length", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of samples/pixels along this axis. Use -1 or 0 for open/unbounded.", + "constraints": {} + }, + { + "name": "regularity", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Whether the axis is regularly sampled.", + "constraints": { + "enum": [ + "regular", + "irregular" + ] + } + }, + { + "name": "spacing", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sample interval when regular.", + "constraints": {} + }, + { + "name": "unit", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Unit of the axis coordinate.", + "constraints": {} + }, + { + "name": "sample_rate", + "type": "frequency", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sampling rate for a regular time axis.", + "constraints": {} + } + ] + }, + { + "name": "channels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional intrinsic channel descriptors (count, native unit, storage relationship). Channel meaning lives in a dataseries_channel_map sidecar.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Channel name/identity (optional for homogeneous array bundles).", + "constraints": {} + }, + { + "name": "native_unit", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Unit of the stored signal (volt | microvolt | digital_count | arbitrary_unit | dimensionless | ...).", + "constraints": {} + }, + { + "name": "gain", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Scale factor: native = (stored - offset) * gain.", + "constraints": {} + }, + { + "name": "offset", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Offset applied before gain.", + "constraints": {} + } + ] + }, + { + "name": "storage", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical storage descriptor for the epoch's bulk data.", + "constraints": {}, + "fields": [ + { + "name": "format", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical encoding (vhsb | zarr | ome_ngff | ...).", + "constraints": {} + }, + { + "name": "chunk_shape", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-axis chunk sizes enabling partial/ROI reads.", + "constraints": {} + }, + { + "name": "codec", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Compression/filter pipeline.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/environmental_manipulation.json b/schemas/V_zeta/stable/environmental_manipulation.json new file mode 100644 index 0000000..7fe17ca --- /dev/null +++ b/schemas/V_zeta/stable/environmental_manipulation.json @@ -0,0 +1,50 @@ +{ + "document_class": { + "class_name": "environmental_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "factor", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The environmental factor/regime (dark rearing, deprivation, enrichment, restriction, training, ...).", + "constraints": {} + }, + { + "name": "notes", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", + "constraints": { + "maxLength": 4096 + } + } + ] +} diff --git a/schemas/V_zeta/stable/ephys_zarr.json b/schemas/V_zeta/stable/ephys_zarr.json new file mode 100644 index 0000000..186717a --- /dev/null +++ b/schemas/V_zeta/stable/ephys_zarr.json @@ -0,0 +1,405 @@ +{ + "document_class": { + "class_name": "ephys_zarr", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "zarr" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "probe_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the probe geometry document whose channels this recording samples. Required: an ephys recording is only meaningful in the context of a specific probe.", + "must_refer_to_document_class": "" + }, + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the NDI element this recording is associated with (e.g., a specific tetrode, shank, or probe segment). Optional; matches the image_zarr convention.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "sample_rate", + "type": "frequency", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "pato:0000044", + "name": "frequency" + }, + "documentation": "Acquisition sampling rate in hertz. Denormalised from the time axis: equals 1 / (multiscales[0].datasets[0].scale at the time axis index) when axes[time].unit is 'second' (and divided appropriately for other time units). Carries the original unit and value in source_unit / source_value so writers can preserve their natural unit; queries against sample_rate.hertz are the canonical form.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "num_samples", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "ncit:C25463", + "name": "Count" + }, + "documentation": "Number of samples along the time axis of the native array. Denormalised from shape at the time axis index. Used as the canonical 'how long is this recording' scalar for indexing and length queries.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "num_channels", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "ncit:C25463", + "name": "Count" + }, + "documentation": "Number of recording channels. Denormalised from shape at the channel axis index. Equal to the length of the channels array.", + "constraints": { + "minimum": 1 + } + }, + { + "name": "recording_duration", + "type": "duration", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Total recording duration, equal to num_samples / sample_rate. Denormalised so that 'find recordings longer than 10 minutes' is one direct query against recording_duration.seconds. Null when num_samples or sample_rate is not yet known.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "sample0_timeref", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "NDI time reference for sample 0 of the native array. Five sub-fields (matching the timeref_struct pattern used by valid_interval) place the first sample on a specific clock anchored to a specific epoch of a specific epochset, with a seconds offset within that epoch. This is the canonical way to express 'when did this recording start' in NDI's temporal vocabulary, and lets the time of sample 0 participate in sync graphs and cross-clock translation without any special-case handling on the consumer side.", + "constraints": {}, + "fields": [ + { + "name": "referent_epochsetname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Name of the ndi.epoch.epochset object (e.g., device name, probe name, element name) that provides the time reference for sample 0.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "referent_classname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Class name of the referent epochset object (e.g., 'element', 'probe', 'device').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "clocktypestring", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "String identifier of the ndi.time.clocktype used for sample 0. Valid values: 'dev_local_time', 'dev_global_time', 'utc', 'approx_utc', 'exp_global_time', 'no_time'.", + "constraints": { + "maxLength": 64, + "enum": [ + "dev_local_time", + "dev_global_time", + "utc", + "approx_utc", + "exp_global_time", + "no_time" + ] + } + }, + { + "name": "epoch", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The epochid of the epoch in the referent epochset that provides the time origin for sample 0.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "time", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Time offset (in seconds) within the reference epoch that corresponds to sample 0.", + "constraints": {} + } + ] + }, + { + "name": "channels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-channel acquisition records, parallel-indexed to the channel axis of the native array. Each element describes one recording channel: which physical probe contact it sampled, its gain/offset to convert stored values to physical voltage, and any quality flag.", + "constraints": {}, + "fields": [ + { + "name": "contact_id", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "One-based logical channel number on the referenced probe, matching NDI's 1-based indexing of probe_geometry.channel_positions (contact 1 is row 1 of channel_positions, contact 2 is row 2, etc.). Identifies which physical electrode contact this recording channel was wired to.", + "constraints": { + "minimum": 1 + } + }, + { + "name": "contact_label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Human-readable channel label (e.g., 'ch001', 'CSC1', 'shank0_ch7'). Free-form string; empty when the writer did not record one.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "gain", + "type": "double", + "blank_value": 1.0, + "default_value": 1.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Multiplier applied to convert stored values to physical voltage in voltage_unit: physical = (stored - offset) * gain. For raw int16 ADC data, this is typically the per-step voltage of the ADC range (e.g., 0.195 microvolts/step for an Intan headstage at default range). For data already stored in physical units, gain is 1.0.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "offset", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Additive offset subtracted from stored values before gain is applied: physical = (stored - offset) * gain. Typically 0 for ADC-derived data; non-zero when the writer applied a baseline shift before storage.", + "constraints": {} + }, + { + "name": "voltage_unit", + "type": "char", + "blank_value": "", + "default_value": "microvolt", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "pato:0001463", + "name": "electrical potential" + }, + "documentation": "Physical unit of (stored - offset) * gain. Almost always 'microvolt' for extracellular ephys; 'millivolt' for intracellular or LFP; 'volt' for raw bench signals.", + "constraints": { + "enum": [ + "microvolt", + "millivolt", + "volt" + ] + } + }, + { + "name": "bad_channel", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "True when this channel is known-bad (broken contact, excessive noise, saturated) and should be excluded from analysis. False by default.", + "constraints": {} + } + ] + }, + { + "name": "filter_history", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ordered list of filters applied to the signal before storage. Empty when the signal is stored raw (no filtering). Each entry describes one filter stage; the order reflects the order of application.", + "constraints": {}, + "fields": [ + { + "name": "filter_type", + "type": "char", + "blank_value": "", + "default_value": "highpass", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Class of filter response. 'highpass' passes frequencies above cutoff_low. 'lowpass' passes frequencies below cutoff_high. 'bandpass' passes frequencies between cutoff_low and cutoff_high. 'bandstop' rejects frequencies between cutoff_low and cutoff_high. 'notch' is a narrow bandstop (single-frequency rejection, e.g. 50/60 Hz line noise).", + "constraints": { + "enum": [ + "highpass", + "lowpass", + "bandpass", + "bandstop", + "notch" + ] + } + }, + { + "name": "filter_family", + "type": "char", + "blank_value": "", + "default_value": "butterworth", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Filter design family. 'butterworth' for flat passband. 'chebyshev1' / 'chebyshev2' for sharper rolloff with passband / stopband ripple. 'bessel' for linear phase. 'fir' for finite-impulse-response designs. 'iir_other' for unspecified IIR designs (writer's filter description was incomplete).", + "constraints": { + "enum": [ + "butterworth", + "chebyshev1", + "chebyshev2", + "bessel", + "fir", + "iir_other" + ] + } + }, + { + "name": "order", + "type": "integer", + "blank_value": 0, + "default_value": 2, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Filter order. For IIR filters, the number of poles; for FIR filters, the number of taps minus one. 0 when the writer did not record an order.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "cutoff_low", + "type": "frequency", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Lower-band cutoff frequency. For 'highpass': the single cutoff. For 'bandpass' / 'bandstop' / 'notch': the lower edge of the passband / stopband / notched region. Null for 'lowpass' filters (which have only an upper cutoff).", + "constraints": { + "minimum": 0 + } + }, + { + "name": "cutoff_high", + "type": "frequency", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Upper-band cutoff frequency. For 'lowpass': the single cutoff. For 'bandpass' / 'bandstop' / 'notch': the upper edge of the passband / stopband / notched region. Null for 'highpass' filters (which have only a lower cutoff).", + "constraints": { + "minimum": 0 + } + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/epoch_bounded_reference.json b/schemas/V_zeta/stable/epoch_bounded_reference.json new file mode 100644 index 0000000..ff8cf4a --- /dev/null +++ b/schemas/V_zeta/stable/epoch_bounded_reference.json @@ -0,0 +1,58 @@ +{ + "document_class": { + "class_name": "epoch_bounded_reference", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "time_reference" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The element whose epoch defines this reference's extent.", + "must_refer_to_document_class": "element" + } + ], + "file": [], + "fields": [ + { + "name": "epoch_clock", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Which device clock defines the epoch's extent (NDI-matlab clocktype set).", + "constraints": { + "binding": { + "root": "did_clocktype", + "expansion": "value_set", + "values": [ + "utc", + "dev_local_time", + "dev_global_time", + "exp_global_time", + "approx_utc", + "approx_exp_global_time", + "approx_dev_global_time", + "no_time", + "inherited" + ], + "strength": "required", + "source": "value_set" + }, + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/epoch_relative_reference.json b/schemas/V_zeta/stable/epoch_relative_reference.json new file mode 100644 index 0000000..e26efbb --- /dev/null +++ b/schemas/V_zeta/stable/epoch_relative_reference.json @@ -0,0 +1,121 @@ +{ + "document_class": { + "class_name": "epoch_relative_reference", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "time_reference" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The element whose epoch this reference is expressed against.", + "must_refer_to_document_class": "element" + } + ], + "file": [], + "fields": [ + { + "name": "epoch_clock", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Which device clock the offsets are expressed in (NDI-matlab clocktype set).", + "constraints": { + "binding": { + "root": "did_clocktype", + "expansion": "value_set", + "values": [ + "utc", + "dev_local_time", + "dev_global_time", + "exp_global_time", + "approx_utc", + "approx_exp_global_time", + "approx_dev_global_time", + "no_time", + "inherited" + ], + "strength": "required", + "source": "value_set" + }, + "maxLength": 64 + } + }, + { + "name": "t0", + "type": "duration", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Curator's reference origin within the epoch_clock (commonly 0; e.g. stimulus onset).", + "constraints": {} + }, + { + "name": "start", + "type": "duration", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Offset from t0.", + "constraints": {} + }, + { + "name": "end", + "type": "duration", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Offset from t0; present means an interval.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/epochclocktimes.json b/schemas/V_zeta/stable/epochclocktimes.json new file mode 100644 index 0000000..8a4b2ca --- /dev/null +++ b/schemas/V_zeta/stable/epochclocktimes.json @@ -0,0 +1,67 @@ +{ + "document_class": { + "class_name": "epochclocktimes", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element associated with this epoch clock time record.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "epoch_clock", + "type": "char", + "blank_value": "", + "default_value": "dev_local_time", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The clock type for this epoch (e.g., 'dev_local_time', 'utc', 'exp_global_time').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "t0", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "The start time of this epoch in the units of epoch_clock.", + "constraints": {} + }, + { + "name": "t1", + "type": "double", + "blank_value": 1.0, + "default_value": 1.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "The stop time of this epoch in the units of epoch_clock.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/epochfiles_ingested.json b/schemas/V_zeta/stable/epochfiles_ingested.json new file mode 100644 index 0000000..2c6bf57 --- /dev/null +++ b/schemas/V_zeta/stable/epochfiles_ingested.json @@ -0,0 +1,67 @@ +{ + "document_class": { + "class_name": "epochfiles_ingested", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "epochid", + "mustBeNonEmpty": true, + "documentation": "The document ID of the epoch whose files were ingested.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "epoch_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "Epoch identifier within the owning session (e.g., 't00001'). v1-faithful inline copy of the epoch's local name; the document-id link to the epoch lives in `depends_on[epochid]`.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "files", + "type": "string", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "List of file references ingested for this epoch. Entries are either NDI-scheme URIs (e.g., 'epochid://t00001') or absolute filesystem paths to the source files. Length varies per epoch (3-6 entries seen in the discovery corpora).", + "constraints": {} + }, + { + "name": "epochprobemap", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Tab-separated epoch-probe-map text describing the probe configuration at ingest time. Free-form pass-through from v1; structure is `name\\treference\\ttype\\tdevicestring\\tsubjectstring\\n\\n...`.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/epochid.json b/schemas/V_zeta/stable/epochid.json new file mode 100644 index 0000000..7bb9d3d --- /dev/null +++ b/schemas/V_zeta/stable/epochid.json @@ -0,0 +1,34 @@ +{ + "document_class": { + "class_name": "epochid", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "epochid", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "The epoch identifier that this document refers to.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/event_bounded_reference.json b/schemas/V_zeta/stable/event_bounded_reference.json new file mode 100644 index 0000000..9f8bf1f --- /dev/null +++ b/schemas/V_zeta/stable/event_bounded_reference.json @@ -0,0 +1,22 @@ +{ + "document_class": { + "class_name": "event_bounded_reference", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "time_reference" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "bounding_event", + "mustBeNonEmpty": true, + "documentation": "The interaction event whose extent bounds this reference. Must have interval extent.", + "must_refer_to_document_class": "subject_interaction" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/event_relative_reference.json b/schemas/V_zeta/stable/event_relative_reference.json new file mode 100644 index 0000000..9f44a8b --- /dev/null +++ b/schemas/V_zeta/stable/event_relative_reference.json @@ -0,0 +1,65 @@ +{ + "document_class": { + "class_name": "event_relative_reference", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "time_reference" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "reference_event", + "mustBeNonEmpty": true, + "documentation": "The interaction event that the offsets are measured from.", + "must_refer_to_document_class": "subject_interaction" + } + ], + "file": [], + "fields": [ + { + "name": "start", + "type": "duration", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Signed offset from the reference event (e.g. +25 days, -2 days).", + "constraints": {} + }, + { + "name": "end", + "type": "duration", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Signed offset from the reference event; present means an interval.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/filenavigator.json b/schemas/V_zeta/stable/filenavigator.json new file mode 100644 index 0000000..f5c4468 --- /dev/null +++ b/schemas/V_zeta/stable/filenavigator.json @@ -0,0 +1,72 @@ +{ + "document_class": { + "class_name": "filenavigator", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "ndi_filenavigator_class", + "type": "char", + "blank_value": "", + "default_value": "ndi_filenavigator", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the file navigator implementation.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "fileparameters", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Parameters that describe how to navigate the file system for epoch data.", + "constraints": {} + }, + { + "name": "epochprobemap_class", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The class name of the epoch-to-probe mapping implementation.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "epochprobemap_fileparameters", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "File parameters for the epoch-to-probe mapping.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/filter.json b/schemas/V_zeta/stable/filter.json new file mode 100644 index 0000000..94b9073 --- /dev/null +++ b/schemas/V_zeta/stable/filter.json @@ -0,0 +1,69 @@ +{ + "document_class": { + "class_name": "filter", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A user label.", + "constraints": {} + }, + { + "name": "filter_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The filter type: 'bandpass', 'low', 'high', 'none'.", + "constraints": {} + }, + { + "name": "algorithm", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The filter algorithm: 'chebyshev_1', 'chebyshev_2', 'butterworth', 'bessel', 'elliptic', 'none'.", + "constraints": {} + }, + { + "name": "parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A structure containing filter parameters: sampleFrequency, order, filterFrequency, passbandRipple, stopbandAttenuation.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/fitcurve.json b/schemas/V_zeta/stable/fitcurve.json new file mode 100644 index 0000000..5e2f4eb --- /dev/null +++ b/schemas/V_zeta/stable/fitcurve.json @@ -0,0 +1,82 @@ +{ + "document_class": { + "class_name": "fitcurve", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this fit curve is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "fit_function", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name or formula of the fitting function (e.g., 'gaussian', 'sigmoid', 'polynomial').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "fit_parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Structure of fitted parameter values keyed by parameter name. Keys and value types depend on fit_function (e.g., for 'gaussian': {mean, sigma, amplitude, offset}).", + "constraints": { + "dynamic_keys_from": "fit_function" + }, + "fields": [] + }, + { + "name": "goodness_of_fit", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "A goodness-of-fit statistic (e.g., R-squared value).", + "constraints": {} + }, + { + "name": "goodness_of_fit_type", + "type": "char", + "blank_value": "", + "default_value": "r_squared", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type of goodness-of-fit measure (e.g., 'r_squared', 'rmse', 'chi_squared').", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/frequency_manipulation.json b/schemas/V_zeta/stable/frequency_manipulation.json new file mode 100644 index 0000000..03afc8b --- /dev/null +++ b/schemas/V_zeta/stable/frequency_manipulation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "frequency_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_manipulation" + }, + { + "class_name": "scalar_frequency" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/generic_file.json b/schemas/V_zeta/stable/generic_file.json new file mode 100644 index 0000000..75f9ce9 --- /dev/null +++ b/schemas/V_zeta/stable/generic_file.json @@ -0,0 +1,73 @@ +{ + "document_class": { + "class_name": "generic_file", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this file is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "data_file", + "documentation": "The generic data file." + } + ], + "fields": [ + { + "name": "filename", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The original filename of the data file.", + "constraints": { + "maxLength": 512 + } + }, + { + "name": "mimetype", + "type": "char", + "blank_value": "", + "default_value": "application/octet-stream", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The MIME type of the data file.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "description", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "A free-text description of the file contents.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/stable/generic_scalar.json b/schemas/V_zeta/stable/generic_scalar.json new file mode 100644 index 0000000..99db89a --- /dev/null +++ b/schemas/V_zeta/stable/generic_scalar.json @@ -0,0 +1,73 @@ +{ + "document_class": { + "class_name": "generic_scalar", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "structure", + "blank_value": [], + "default_value": [ + {} + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Escape-hatch scalar value (shape-library mixin): source_unit/source_value only, no canonical. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {}, + "fields": [ + { + "name": "source_unit", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Source unit as recorded.", + "constraints": {} + }, + { + "name": "source_value", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Source value as recorded.", + "constraints": {} + }, + { + "name": "approximate", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "True if the value is a rough estimate.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/generic_scalar_manipulation.json b/schemas/V_zeta/stable/generic_scalar_manipulation.json new file mode 100644 index 0000000..75e39d7 --- /dev/null +++ b/schemas/V_zeta/stable/generic_scalar_manipulation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "generic_scalar_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_manipulation" + }, + { + "class_name": "generic_scalar" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/generic_scalar_observation.json b/schemas/V_zeta/stable/generic_scalar_observation.json new file mode 100644 index 0000000..3a51bd5 --- /dev/null +++ b/schemas/V_zeta/stable/generic_scalar_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "generic_scalar_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "generic_scalar" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/group_assignment.json b/schemas/V_zeta/stable/group_assignment.json new file mode 100644 index 0000000..42a3e2d --- /dev/null +++ b/schemas/V_zeta/stable/group_assignment.json @@ -0,0 +1,38 @@ +{ + "document_class": { + "class_name": "group_assignment", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "annotation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "group_id", + "mustBeNonEmpty": true, + "documentation": "The group the subject is assigned to. A subject with is_group: true.", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [ + { + "name": "batch_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional grouping handle linking assignments minted as one curatorial act.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/hartley_calc.json b/schemas/V_zeta/stable/hartley_calc.json new file mode 100644 index 0000000..45396cf --- /dev/null +++ b/schemas/V_zeta/stable/hartley_calc.json @@ -0,0 +1,26 @@ +{ + "document_class": { + "class_name": "hartley_calc", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "hartley_reverse_correlation" + }, + { + "class_name": "calculator" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [ + { + "name": "hartley_results.ngrid", + "documentation": "N-dimensional grid (ngrid) file holding the reverse-correlation kernel computed by this calculator." + } + ], + "fields": [] +} diff --git a/schemas/V_zeta/stable/hartley_reverse_correlation.json b/schemas/V_zeta/stable/hartley_reverse_correlation.json new file mode 100644 index 0000000..b9f007f --- /dev/null +++ b/schemas/V_zeta/stable/hartley_reverse_correlation.json @@ -0,0 +1,261 @@ +{ + "document_class": { + "class_name": "hartley_reverse_correlation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "reverse_correlation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "stimulus_properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Hartley basis stimulus parameters used to generate the displayed images.", + "constraints": {}, + "fields": [ + { + "name": "m", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of spatial samples per Hartley basis image (M x M grid).", + "constraints": {} + }, + { + "name": "l_max", + "type": "double", + "blank_value": 0, + "default_value": 20, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Maximum Hartley index in the L (horizontal) dimension.", + "constraints": {} + }, + { + "name": "k_max", + "type": "double", + "blank_value": 0, + "default_value": 20, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Maximum Hartley index in the K (vertical) dimension.", + "constraints": {} + }, + { + "name": "sf_max", + "type": "double", + "blank_value": 0, + "default_value": 2, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Maximum spatial frequency represented in the Hartley basis (cycles per degree).", + "constraints": {} + }, + { + "name": "fps", + "type": "double", + "blank_value": 0, + "default_value": 10, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Frames-per-second rate at which Hartley basis images were presented.", + "constraints": {} + }, + { + "name": "color_high", + "type": "matrix", + "blank_value": [], + "default_value": [ + 255, + 255, + 255 + ], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "RGB triple for the 'high' (positive-coefficient) Hartley basis pixel value (0-255 per channel).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "color_low", + "type": "matrix", + "blank_value": [], + "default_value": [ + 0, + 0, + 0 + ], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "RGB triple for the 'low' (negative-coefficient) Hartley basis pixel value (0-255 per channel).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "rect", + "type": "matrix", + "blank_value": [], + "default_value": [ + 0, + 0, + 800, + 600 + ], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "On-screen rectangle in which Hartley basis images were drawn, [x_left, y_top, x_right, y_bottom] in pixels.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "reconstruction_properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Coordinate grids at which the reverse-correlation kernel was reconstructed.", + "constraints": {}, + "fields": [ + { + "name": "t_coords", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Array of time-axis coordinates (seconds) at which the reverse-correlation kernel was reconstructed.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "x_coords", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Array of X-axis spatial coordinates at which the reverse-correlation kernel was reconstructed.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "y_coords", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Array of Y-axis spatial coordinates at which the reverse-correlation kernel was reconstructed.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "spiketimes", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Spike times (seconds, in the element's local clock) used as the trigger events for the reverse correlation.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "frame_times", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Times (seconds) at which each Hartley basis frame was presented. Indexed in parallel with hartley_numbers.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "hartley_numbers", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Hartley basis stimulus parameters: parallel-indexed arrays (one entry per presented frame) describing the basis-function coefficients. Concrete subfields used by NDIcalc-vis-matlab include `S` (sign), `KXV` (horizontal index), `KYV` (vertical index), and `ORDER` (presentation order). All arrays are the same length; indexed in parallel with frame_times.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/image.json b/schemas/V_zeta/stable/image.json new file mode 100644 index 0000000..91587d1 --- /dev/null +++ b/schemas/V_zeta/stable/image.json @@ -0,0 +1,99 @@ +{ + "document_class": { + "class_name": "image", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this image is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "image_file", + "documentation": "The image file (e.g., PNG, TIFF, JPEG)." + } + ], + "fields": [ + { + "name": "image_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type or modality of the image (e.g., 'brightfield', 'fluorescence', 'confocal').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "image_format", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The file format of the image (e.g., 'png', 'tiff', 'jpeg').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "x_resolution", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The x-axis resolution (pixels per unit).", + "constraints": {} + }, + { + "name": "y_resolution", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The y-axis resolution (pixels per unit).", + "constraints": {} + }, + { + "name": "resolution_units", + "type": "char", + "blank_value": "", + "default_value": "um", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The units for x_resolution and y_resolution (e.g., 'um', 'mm').", + "constraints": { + "maxLength": 32 + } + } + ] +} diff --git a/schemas/V_zeta/stable/image_collection.json b/schemas/V_zeta/stable/image_collection.json new file mode 100644 index 0000000..c9f9f4b --- /dev/null +++ b/schemas/V_zeta/stable/image_collection.json @@ -0,0 +1,71 @@ +{ + "document_class": { + "class_name": "image_collection", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this image collection is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "collection_file", + "documentation": "The file containing the image collection data." + } + ], + "fields": [ + { + "name": "num_images", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of images in the collection.", + "constraints": {} + }, + { + "name": "image_format", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The file format of images in the collection (e.g., 'png', 'tiff').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "description", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "A free-text description of this image collection.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/stable/image_stack.json b/schemas/V_zeta/stable/image_stack.json new file mode 100644 index 0000000..e992d56 --- /dev/null +++ b/schemas/V_zeta/stable/image_stack.json @@ -0,0 +1,59 @@ +{ + "document_class": { + "class_name": "image_stack", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "image_stack_parameters" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this image stack is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "imagestack_file", + "documentation": "The file containing the image stack data." + } + ], + "fields": [ + { + "name": "label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Free-text label or caption describing the image stack (e.g., 'An image of fluorescently labeled bacterial patches that has been processed to ...').", + "constraints": {} + }, + { + "name": "format_ontology", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology CURIE describing the image format / content type (e.g., 'NCIT:C70631' for a particular imaging modality). v1 corpora ship the CURIE directly as a char; consumers resolve via ndi.ontology.lookup when a human-readable name is needed.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/image_stack_parameters.json b/schemas/V_zeta/stable/image_stack_parameters.json new file mode 100644 index 0000000..ffbbaea --- /dev/null +++ b/schemas/V_zeta/stable/image_stack_parameters.json @@ -0,0 +1,152 @@ +{ + "document_class": { + "class_name": "image_stack_parameters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "imagestack_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the image stack these parameters describe.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "dimension_order", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "String encoding the spatial dimension order of the stack, one character per axis (e.g., 'YX' for a 2-D height-by-width image, 'ZYX' or 'TZYX' for higher-dimensional stacks).", + "constraints": { + "maxLength": 16 + } + }, + { + "name": "dimension_labels", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Comma-separated human-readable labels for each axis (e.g., 'height,width', 'depth,height,width'). One label per character in dimension_order.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "dimension_size", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Pixel/sample count along each axis. Length equals number of characters in dimension_order (e.g., [2208, 2752] for a 'YX' stack).", + "constraints": { + "element_type": "integer" + } + }, + { + "name": "dimension_scale", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Physical scale per axis (e.g., 94.89 micrometers per Y pixel). Same length as dimension_size; units captured in dimension_scale_units.", + "constraints": {} + }, + { + "name": "dimension_scale_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Comma-separated unit names for each axis (e.g., 'micrometer,micrometer', 'micrometer,micrometer,micrometer').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The numeric data type of pixel values (e.g., 'uint16', 'single', 'double').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "data_limits", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "2-element [min, max] range of valid pixel values for the declared data_type (e.g., [0, 65535] for uint16).", + "constraints": {} + }, + { + "name": "timestamp", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Acquisition timestamp of this image stack in the units of clocktype.", + "constraints": {} + }, + { + "name": "clocktype", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Clock identifier in whose units `timestamp` is expressed (e.g., 'exp_global_time', 'dev_local_time'). Same vocabulary as the epochclocktimes/element_epoch clock names.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/image_zarr.json b/schemas/V_zeta/stable/image_zarr.json new file mode 100644 index 0000000..06bc81b --- /dev/null +++ b/schemas/V_zeta/stable/image_zarr.json @@ -0,0 +1,251 @@ +{ + "document_class": { + "class_name": "image_zarr", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "zarr" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this image is associated with. Optional, since some image_zarr documents (e.g., raw acquisitions not yet bound to an experimental element) may not have an element at write time.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "omero_channels", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-channel rendering metadata in OMERO/OME-Zarr style. One element per imaging channel, ordered to match the channel axis of the native array. May be empty when the writer did not record OMERO metadata (channel labels/colors are then unknown). Most writers populate at least 'label' and 'active'; 'color', 'family', 'coefficient', and 'window' are commonly absent.", + "constraints": {}, + "fields": [ + { + "name": "label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Human-readable channel name (e.g., 'GFP', 'DAPI', 'ch0', 'ch1'). Free-form string; writers conventionally use short identifiers.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "color", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "RGB rendering color as a six-character hex string without leading '#' (e.g., 'FF0000' for red, '00FF00' for green). Empty when the writer did not record a color.", + "constraints": { + "pattern": "^$|^[0-9A-Fa-f]{6}$" + } + }, + { + "name": "active", + "type": "boolean", + "blank_value": true, + "default_value": true, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Whether this channel is shown by default in OMERO/napari rendering. True if absent in the source writer.", + "constraints": {} + }, + { + "name": "family", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Color-map family (e.g., 'linear', 'log', 'polynomial'). Empty when the writer did not record one.", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "coefficient", + "type": "double", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Family-specific shaping parameter (typically gamma for 'linear' / 'polynomial'). Null when not recorded.", + "constraints": {} + }, + { + "name": "window", + "type": "structure", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Display window for this channel. 'min' and 'max' are the full data range; 'start' and 'end' are the initial display range (mapped to the rendered color ramp's endpoints). Null when not recorded.", + "constraints": {}, + "fields": [ + { + "name": "min", + "type": "double", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Full data range minimum for this channel.", + "constraints": {} + }, + { + "name": "max", + "type": "double", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Full data range maximum for this channel.", + "constraints": {} + }, + { + "name": "start", + "type": "double", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Initial display-window minimum for this channel.", + "constraints": {} + }, + { + "name": "end", + "type": "double", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Initial display-window maximum for this channel.", + "constraints": {} + } + ] + } + ] + }, + { + "name": "num_channels", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of imaging channels. Denormalised for cheap querying ('find all multi-channel images'). Derivable from the native shape and the position of the channel axis; 0 when there is no channel axis. Consumer tooling populates this at ingest from the discovered channel axis.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "num_timepoints", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of timepoints in the native array. Denormalised for cheap querying ('find time-lapse images with more than N frames'). 0 when there is no time axis (e.g., a single 3D volume). Consumer tooling populates this at ingest from the discovered time axis.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "pixel_size_x", + "type": "length", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Physical pixel size along the x axis at the native level, as a length composite (canonical: meters). Denormalised from multiscales[0].datasets[0].scale and axes[*].unit so the typical query 'find images with sub-micrometer x resolution' is one operator. Null when there is no x axis or when the writer did not record a scale.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "pixel_size_y", + "type": "length", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Physical pixel size along the y axis at the native level. Same conventions as pixel_size_x.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "pixel_size_z", + "type": "length", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Physical pixel size along the z axis at the native level. Null for 2D images. Same conventions as pixel_size_x.", + "constraints": { + "minimum": 0 + } + } + ] +} diff --git a/schemas/V_zeta/stable/injection.json b/schemas/V_zeta/stable/injection.json new file mode 100644 index 0000000..f53d937 --- /dev/null +++ b/schemas/V_zeta/stable/injection.json @@ -0,0 +1,150 @@ +{ + "document_class": { + "class_name": "injection", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "pharmacological_manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "kind", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Coarse purpose bucket.", + "constraints": { + "enum": [ + "drug", + "virus", + "tracer", + "vehicle", + "contrast" + ] + } + }, + { + "name": "volume", + "type": "volume", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Total volume delivered at this site by this event.", + "constraints": {} + }, + { + "name": "route", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Route of administration (IP/IV/IM/SC/oral/intracortical/...; NCIT Route of Administration branch).", + "constraints": {} + }, + { + "name": "coordinates", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Stereotaxic coordinates (optional).", + "constraints": {}, + "fields": [ + { + "name": "ap", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Anterior-posterior coordinate.", + "constraints": {} + }, + { + "name": "ml", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Medial-lateral coordinate.", + "constraints": {} + }, + { + "name": "dv", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Dorsal-ventral coordinate.", + "constraints": {} + }, + { + "name": "reference_frame", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reference frame for the coordinates (e.g. bregma).", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/interaction_purpose.json b/schemas/V_zeta/stable/interaction_purpose.json new file mode 100644 index 0000000..a9cd1da --- /dev/null +++ b/schemas/V_zeta/stable/interaction_purpose.json @@ -0,0 +1,58 @@ +{ + "document_class": { + "class_name": "interaction_purpose", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "interaction_id_#", + "mustBeNonEmpty": true, + "documentation": "The interaction(s) this purpose applies to.", + "must_refer_to_document_class": "subject_interaction", + "multiple": true + } + ], + "file": [], + "fields": [ + { + "name": "purpose", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The ontology-based 'why' of the interaction(s).", + "constraints": {} + }, + { + "name": "comment", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Curator free-text note (genuinely new info, not a denormalized ontology description).", + "constraints": { + "maxLength": 2048 + } + } + ] +} diff --git a/schemas/V_zeta/stable/jrclust_clusters.json b/schemas/V_zeta/stable/jrclust_clusters.json new file mode 100644 index 0000000..cdba834 --- /dev/null +++ b/schemas/V_zeta/stable/jrclust_clusters.json @@ -0,0 +1,46 @@ +{ + "document_class": { + "class_name": "jrclust_clusters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "app" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) this JRCLUST sorting output is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "jrclust_output_file", + "documentation": "The JRCLUST output file containing cluster data." + } + ], + "fields": [ + { + "name": "res_mat_md5_checksum", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "MD5 checksum of the JRCLUST *_res.mat results file, recorded at ingestion so downstream consumers can detect resort/reanalysis.", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/manipulation.json b/schemas/V_zeta/stable/manipulation.json new file mode 100644 index 0000000..0022442 --- /dev/null +++ b/schemas/V_zeta/stable/manipulation.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "subject_interaction" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/measurement.json b/schemas/V_zeta/stable/measurement.json new file mode 100644 index 0000000..cc84f3e --- /dev/null +++ b/schemas/V_zeta/stable/measurement.json @@ -0,0 +1,54 @@ +{ + "document_class": { + "class_name": "measurement", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element this measurement belongs to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "measurement_class", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the measurement type (e.g., 'ndi_timeseries_measurement').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "parameters", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Measurement parameters, serialised as a JSON string.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/metadata_editor.json b/schemas/V_zeta/stable/metadata_editor.json new file mode 100644 index 0000000..2c44cc9 --- /dev/null +++ b/schemas/V_zeta/stable/metadata_editor.json @@ -0,0 +1,30 @@ +{ + "document_class": { + "class_name": "metadata_editor", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "metadata_structure", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Arbitrary key/value metadata describing the dataset this document was authored against. v1 documents in the Soph corpus carry dataset-level descriptors here (VersionIdentifier, License, DataType, and others). The shape is intentionally open: keys and inner structure depend on the editor and the dataset.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/mock.json b/schemas/V_zeta/stable/mock.json new file mode 100644 index 0000000..2da6442 --- /dev/null +++ b/schemas/V_zeta/stable/mock.json @@ -0,0 +1,29 @@ +{ + "document_class": { + "class_name": "mock", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "ismock", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A parameter that denotes the document as a mock document.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/ndi_reserved_keys.json b/schemas/V_zeta/stable/ndi_reserved_keys.json new file mode 100644 index 0000000..acceb7a --- /dev/null +++ b/schemas/V_zeta/stable/ndi_reserved_keys.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://did-schema.example.org/V_gamma/ndi_reserved_keys.json", + "title": "NDI Reserved Keys (V_gamma)", + "description": "Authoritative list of property names reserved by the NDI/DID schema system in V_gamma. Two lists are provided: `schema_file_keys` for names that appear in a class schema file (e.g. base.json, probe_location.json), and `document_instance_keys` for names that appear in an NDI document instance on disk. Schema authors MUST NOT use any reserved name as their own data field name (i.e., as a `name` inside a `fields` entry). This manifest is the discoverable surface for the reserved vocabulary; the meta-schema (did_schema_meta.json) is the enforcement surface. The CURIE registry file (CURIE_lookups_meta.json) has its own separate vocabulary and is out of scope here.", + "schema_file_keys": [ + { "name": "document_class", "context": "top-level", "description": "Class-identity header. Sub-keys: class_name, class_version, superclasses. Restored from the V_alpha NDI-matlab layout." }, + { "name": "class_name", "context": "inside document_class and inside document_class.superclasses entries", "description": "snake_case identifier of a class." }, + { "name": "class_version", "context": "inside document_class", "description": "Semantic version of the schema (MAJOR.MINOR.PATCH)." }, + { "name": "superclasses", "context": "inside document_class", "description": "Array of superclass reference objects." }, + { "name": "schema", "context": "inside document_class.superclasses entries", "description": "Path or token-substituted path to the superclass schema file." }, + { "name": "maturity_level", "context": "inside document_class", "description": "\"work_in_progress\" or \"mature\"." }, + { "name": "abstract", "context": "inside document_class", "description": "If true, this class cannot be instantiated directly; only concrete subclasses may be. Optional; defaults to false when omitted." }, + { "name": "depends_on", "context": "top-level", "description": "Array of dependency-declaration objects." }, + { "name": "file", "context": "top-level", "description": "Array of file-record objects." }, + { "name": "directory", "context": "top-level", "description": "Array of directory-record objects." }, + { "name": "fields", "context": "top-level (and recursive inside structure-typed fields)", "description": "Array of field-definition objects." }, + { "name": "name", "context": "inside depends_on / file / directory / fields / ontology entries", "description": "Identifier of the entry (snake_case)." }, + { "name": "documentation", "context": "inside depends_on / file / directory / fields entries", "description": "Human-readable description." }, + { "name": "multiple", "context": "inside depends_on entries", "description": "Enables numbered-dependency expansion (name_#)." }, + { "name": "must_refer_to_document_class", "context": "inside depends_on entries", "description": "Class-name constraint on the referenced document; empty string means any class." }, + { "name": "mustBeNonEmpty", "context": "inside depends_on and fields entries", "description": "Value must be non-empty (per-type semantics defined in the SPEC)." }, + { "name": "mustBeScalar", "context": "inside fields entries", "description": "Value must be a single element (not array/matrix)." }, + { "name": "mustNotHaveNaN", "context": "inside fields entries", "description": "No NaN values permitted." }, + { "name": "blank_value", "context": "inside fields entries", "description": "Value carried by a freshly constructed blank document. May fail validation." }, + { "name": "default_value", "context": "inside fields entries", "description": "Legitimate default value. Must pass validation." }, + { "name": "queryable", "context": "inside fields entries", "description": "Whether the field is indexed for did.query / ndi.query." }, + { "name": "ontology", "context": "inside fields entries", "description": "CURIE-based annotation of what the field itself denotes. Null permitted." }, + { "name": "node", "context": "inside an ontology annotation object", "description": "CURIE identifier (prefix:local) of the ontology term." }, + { "name": "constraints", "context": "inside fields entries", "description": "Type-specific constraint keywords; `{}` if unconstrained." }, + { "name": "discriminator", "context": "inside fields entries of type \"structure\"", "description": "Names the variant-tagging sub-field for discriminated unions." } + ], + "document_instance_keys": [ + { "name": "document_class", "context": "top-level", "description": "Class-identity header (sub-keys: class_name, class_version, superclasses)." }, + { "name": "class_name", "context": "inside document_class and inside document_class.superclasses entries", "description": "Concrete-class or superclass identifier." }, + { "name": "class_version", "context": "inside document_class and inside document_class.superclasses entries", "description": "Semantic version at write time." }, + { "name": "superclasses", "context": "inside document_class", "description": "Snapshot of the inheritance chain at write time." }, + { "name": "depends_on", "context": "top-level", "description": "Array of dependency-id objects." }, + { "name": "name", "context": "inside depends_on entries", "description": "Role name matching a dependency declaration (after numbered-dependency expansion)." }, + { "name": "document_id", "context": "inside depends_on entries", "description": "DID UID of the referenced document. Renamed from V_alpha's `id` and the earlier V_delta draft `value`: the field is always a did_uid string referring to another document, and the explicit name signals that." } + ], + "notes": [ + "Property-block keys in a document instance equal the `class_name` of a class in the document's inheritance chain. These are reserved by virtue of being class names; they are not enumerated here because they are not fixed strings.", + "Sub-field names inside named composite types (e.g. `seconds`, `source_unit`, `node`, `name` inside `duration` / `ontology_term`) are NOT reserved keys in the sense of this manifest. They are data field names fixed by the type's specification." + ] +} diff --git a/schemas/V_zeta/stable/neuron_extracellular.json b/schemas/V_zeta/stable/neuron_extracellular.json new file mode 100644 index 0000000..2186be2 --- /dev/null +++ b/schemas/V_zeta/stable/neuron_extracellular.json @@ -0,0 +1,125 @@ +{ + "document_class": { + "class_name": "neuron_extracellular", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "app" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) this neuron was recorded from.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "cluster_index", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "The cluster index assigned to this neuron by a spike sorter.", + "constraints": {} + }, + { + "name": "number_of_channels", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of recording channels contributing to this unit's waveform (e.g., the tetrode/probe channel count).", + "constraints": {} + }, + { + "name": "number_of_samples_per_channel", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of time samples per channel in mean_waveform / waveform_sample_times.", + "constraints": {} + }, + { + "name": "mean_waveform", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean spike-waveform matrix shaped (number_of_samples_per_channel x number_of_channels) -- samples down rows, channels across columns. Recorded in the original A/D units of the source data.", + "constraints": {} + }, + { + "name": "waveform_sample_times", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Time stamp of each sample in mean_waveform (seconds, in the element's local clock); length equals number_of_samples_per_channel.", + "constraints": {} + }, + { + "name": "quality_label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "placeholder:spike_sorting_quality_label", + "name": "spike-sorting quality label" + }, + "documentation": "Human-readable spike-sorting quality label (e.g., 'good', 'multi', 'noise'). Candidate for promotion to ontology_term once a controlled vocabulary (e.g., a spike-sorting quality branch in NIFSTD) is registered.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "quality_number", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Numeric spike-sorting quality grade (e.g., 1-4) paired with quality_label. Sorter-specific scale.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/ngrid.json b/schemas/V_zeta/stable/ngrid.json new file mode 100644 index 0000000..30a38b0 --- /dev/null +++ b/schemas/V_zeta/stable/ngrid.json @@ -0,0 +1,97 @@ +{ + "document_class": { + "class_name": "ngrid", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this N-dimensional grid is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "ngrid_file", + "documentation": "The N-dimensional grid data file." + } + ], + "fields": [ + { + "name": "ndims", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": { + "node": "iao:0000027", + "name": "data item" + }, + "documentation": "The number of dimensions of the grid.", + "constraints": {} + }, + { + "name": "dim_sizes", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": { + "node": "iao:0000027", + "name": "data item" + }, + "documentation": "The size of each dimension as an array of positive integers, one entry per dimension. Length must equal ndims.", + "constraints": { + "element_type": "integer", + "min_value": 1 + } + }, + { + "name": "dim_labels", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "iao:0000300", + "name": "textual entity" + }, + "documentation": "Comma-separated labels for each dimension (e.g., 'time,channel,trial'). Number of entries must equal ndims.", + "constraints": {} + }, + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "double", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000098", + "name": "denotator type" + }, + "documentation": "The numeric data type of the grid values (e.g., 'double', 'single', 'int16').", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/observation.json b/schemas/V_zeta/stable/observation.json new file mode 100644 index 0000000..89f5902 --- /dev/null +++ b/schemas/V_zeta/stable/observation.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "observation", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "subject_interaction" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/oneepoch.json b/schemas/V_zeta/stable/oneepoch.json new file mode 100644 index 0000000..7a467eb --- /dev/null +++ b/schemas/V_zeta/stable/oneepoch.json @@ -0,0 +1,60 @@ +{ + "document_class": { + "class_name": "oneepoch", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "epoch_clock", + "type": "char", + "blank_value": "", + "default_value": "dev_local_time", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The clock type for this single epoch.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "t0", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Start time of the single epoch.", + "constraints": {} + }, + { + "name": "t1", + "type": "double", + "blank_value": 1.0, + "default_value": 1.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Stop time of the single epoch.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/ontology_image.json b/schemas/V_zeta/stable/ontology_image.json new file mode 100644 index 0000000..2dff9a4 --- /dev/null +++ b/schemas/V_zeta/stable/ontology_image.json @@ -0,0 +1,41 @@ +{ + "document_class": { + "class_name": "ontology_image", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this ontology image is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "ontology_image_file", + "documentation": "The ontology image file." + } + ], + "fields": [ + { + "name": "region", + "type": "ontology_term", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The brain region or structure this image depicts, as an ontology term (e.g., 'allen_ccf_v3:12345').", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/ontology_label.json b/schemas/V_zeta/stable/ontology_label.json new file mode 100644 index 0000000..50bec7b --- /dev/null +++ b/schemas/V_zeta/stable/ontology_label.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "ontology_label", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this ontology label is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "term", + "type": "ontology_term", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The ontology term labelling this element. The CURIE prefix identifies the source ontology (e.g., 'allen_ccf_v3'), the local part is the numeric ID (e.g., 'allen_ccf_v3:12345'), and 'name' carries the human-readable label.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/ontology_table_row.json b/schemas/V_zeta/stable/ontology_table_row.json new file mode 100644 index 0000000..f3982aa --- /dev/null +++ b/schemas/V_zeta/stable/ontology_table_row.json @@ -0,0 +1,79 @@ +{ + "document_class": { + "class_name": "ontology_table_row", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The document ID of the element this ontology table row is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "names", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Comma-separated human-readable labels for each column in the table row. The number of entries must match variable_names and ontology_nodes.", + "constraints": {} + }, + { + "name": "variable_names", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Comma-separated variable names that serve as the keys in the data structure. The number of entries must match names and ontology_nodes.", + "constraints": {} + }, + { + "name": "ontology_nodes", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Comma-separated ontology node identifiers (e.g., 'EMPTY:0000103') for each column. The number of entries must match names and variable_names.", + "constraints": {} + }, + { + "name": "data", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "A structure whose keys are the entries of variable_names and whose values are the data for this table row. Values may be strings, numbers, or NaN. Requires a special evaluator: the keys must match the comma-separated entries in variable_names exactly, and the counts of names, variable_names, and ontology_nodes must all agree.", + "constraints": { + "dynamic_keys_from": "variable_names", + "requires_evaluator": true + }, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/openminds.json b/schemas/V_zeta/stable/openminds.json new file mode 100644 index 0000000..0c1891f --- /dev/null +++ b/schemas/V_zeta/stable/openminds.json @@ -0,0 +1,78 @@ +{ + "document_class": { + "class_name": "openminds", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "openminds_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Full openMINDS type IRI identifying which openMINDS schema this document carries (e.g., 'https://openminds.om-i.org/types/GeneticStrainType').", + "constraints": { + "maxLength": 1024 + } + }, + { + "name": "matlab_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Fully-qualified MATLAB class name of the corresponding openMINDS object (e.g., 'openminds.controlledterms.GeneticStrainType'). Paired with openminds_type for tooling that needs to reconstitute the MATLAB object.", + "constraints": { + "maxLength": 512 + } + }, + { + "name": "openminds_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "openMINDS instance IRI (e.g., 'https://openminds.om-i.org/instances/geneticStrainType/wildtype'). Identifies a particular openMINDS object instance rather than its type.", + "constraints": { + "maxLength": 1024 + } + }, + { + "name": "fields", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Open-shape struct carrying the openMINDS object's payload fields. Keys are openMINDS-type-specific (e.g., GeneticStrainType uses {definition, description, interlexIdentifier, knowledgeSpaceLink, name}); V_delta does not constrain them so each openMINDS type can contribute its own.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/openminds_element.json b/schemas/V_zeta/stable/openminds_element.json new file mode 100644 index 0000000..dd903b4 --- /dev/null +++ b/schemas/V_zeta/stable/openminds_element.json @@ -0,0 +1,25 @@ +{ + "document_class": { + "class_name": "openminds_element", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "openminds" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element this openMINDS metadata describes.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/openminds_stimulus.json b/schemas/V_zeta/stable/openminds_stimulus.json new file mode 100644 index 0000000..c791cfb --- /dev/null +++ b/schemas/V_zeta/stable/openminds_stimulus.json @@ -0,0 +1,28 @@ +{ + "document_class": { + "class_name": "openminds_stimulus", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "openminds" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus this openMINDS metadata describes.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/openminds_subject.json b/schemas/V_zeta/stable/openminds_subject.json new file mode 100644 index 0000000..5efdaf5 --- /dev/null +++ b/schemas/V_zeta/stable/openminds_subject.json @@ -0,0 +1,25 @@ +{ + "document_class": { + "class_name": "openminds_subject", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "openminds" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the subject this openMINDS metadata describes.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/oridirtuning_calc.json b/schemas/V_zeta/stable/oridirtuning_calc.json new file mode 100644 index 0000000..dcf5710 --- /dev/null +++ b/schemas/V_zeta/stable/oridirtuning_calc.json @@ -0,0 +1,21 @@ +{ + "document_class": { + "class_name": "oridirtuning_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "orientation_direction_tuning" + }, + { + "class_name": "tuning_fit" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} \ No newline at end of file diff --git a/schemas/V_zeta/stable/orientation_direction_tuning.json b/schemas/V_zeta/stable/orientation_direction_tuning.json new file mode 100644 index 0000000..42c5e75 --- /dev/null +++ b/schemas/V_zeta/stable/orientation_direction_tuning.json @@ -0,0 +1,507 @@ +{ + "document_class": { + "class_name": "orientation_direction_tuning", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element whose orientation/direction tuning is described.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_tuningcurve_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_tuningcurve from which this orientation/direction tuning was derived.", + "must_refer_to_document_class": "stimulus_tuningcurve" + } + ], + "file": [], + "fields": [ + { + "name": "properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Bookkeeping properties describing how the orientation/direction responses were measured and reported.", + "constraints": {}, + "fields": [ + { + "name": "coordinates", + "type": "char", + "blank_value": "", + "default_value": "compass", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The orientation/direction coordinate basis. One of 'compass' (0 deg = up, angles increase clockwise) or 'cartesian' (0 deg = right, angles increase counter-clockwise).", + "constraints": { + "enum": ["compass", "cartesian"] + } + }, + { + "name": "response_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Units of the response values (e.g., 'spikes/s', 'dF/F').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "mean", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reduction applied to each stimulus presentation to yield a per-trial response (e.g., 'mean', 'peak', 'F1').", + "constraints": { + "maxLength": 64 + } + } + ] + }, + { + "name": "tuning_curve", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The empirical orientation/direction tuning curve and per-direction summary statistics.", + "constraints": {}, + "fields": [ + { + "name": "direction", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The set of direction angles tested, in degrees (1xN vector).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean response to each direction. Responses may be normalized or control-subtracted.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the response to each direction.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean of the response to each direction.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Individual per-trial response values for each direction. Responses may be normalized or control-subtracted. Rows index directions; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "raw_individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Unprocessed per-trial response values for each direction (no blank subtraction or normalization). Rows index directions; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-trial response values to the control stimulus (e.g., a blank screen with the same duration as the stimuli).", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "significance", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "ANOVA-derived significance metrics for the tuning curve.", + "constraints": {}, + "fields": [ + { + "name": "visual_response_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values between the raw (stimulus) and control groups.", + "constraints": {} + }, + { + "name": "across_stimuli_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values generated by different stimuli (tuning vs. flat).", + "constraints": {} + } + ] + }, + { + "name": "vector", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Vector-based summary measures of orientation and direction selectivity derived from the empirical tuning curve via circular statistics.", + "constraints": {}, + "fields": [ + { + "name": "circular_variance", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Classic circular variance in orientation space, related to selectivity and tuning width.", + "constraints": {} + }, + { + "name": "direction_circular_variance", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Circular variance computed in direction space; related to selectivity and tuning width and differs from the classic orientation-space definition.", + "constraints": {} + }, + { + "name": "hotelling2test", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of Hotelling's T-squared test of whether the orientation vectors and [0,0] are different.", + "constraints": {} + }, + { + "name": "orientation_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The orientation with the highest response in orientation vector space, in degrees.", + "constraints": {} + }, + { + "name": "direction_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The direction with the highest response in direction vector space, in degrees.", + "constraints": {} + }, + { + "name": "direction_hotelling2test", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of Hotelling's T-squared test on the direction vector (insensitive in practice).", + "constraints": {} + }, + { + "name": "dot_direction_significance", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the 'direction dot product test' which uses both orientation and direction vectors to assess the direction selectivity of a cell (Mazurek et al. 2014).", + "constraints": {} + } + ] + }, + { + "name": "fit", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Double-Gaussian fit to the empirical tuning curve and the scalar metrics derived from it.", + "constraints": {}, + "fields": [ + { + "name": "double_gaussian_parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector for the double-Gaussian function: [Rsp Rp theta_pref sigma Rn].", + "constraints": { + "element_type": "double" + } + }, + { + "name": "double_gaussian_fit_angles", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Angle axis (in degrees) at which the fit function was evaluated (typically 0:359).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "double_gaussian_fit_values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Value of the response fit at each angle in double_gaussian_fit_angles.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "orientation_preferred_orthogonal_ratio", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ratio of the fit response at the preferred orientation to the response at the orthogonal orientation (90 degrees away).", + "constraints": {} + }, + { + "name": "direction_preferred_null_ratio", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ratio of the fit response at the preferred direction to the response at the null direction (180 degrees away).", + "constraints": {} + }, + { + "name": "orientation_preferred_orthogonal_ratio_rectified", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "orientation_preferred_orthogonal_ratio computed with each response rectified at 0 (no negative values even after blank subtraction).", + "constraints": {} + }, + { + "name": "direction_preferred_null_ratio_rectified", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "direction_preferred_null_ratio computed with each response rectified at 0 (no negative values even after blank subtraction).", + "constraints": {} + }, + { + "name": "orientation_angle_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Stimulus orientation angle (degrees) that evokes the maximum response under the fit.", + "constraints": {} + }, + { + "name": "direction_angle_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Stimulus direction angle (degrees) that evokes the maximum response under the fit.", + "constraints": {} + }, + { + "name": "hwhh", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Half-width at half-height of the fit (degrees): the angular distance from the preferred direction at which the response is half of the maximum.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/pharmacological_manipulation.json b/schemas/V_zeta/stable/pharmacological_manipulation.json new file mode 100644 index 0000000..4996796 --- /dev/null +++ b/schemas/V_zeta/stable/pharmacological_manipulation.json @@ -0,0 +1,72 @@ +{ + "document_class": { + "class_name": "pharmacological_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "mixture", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Array of per-chemical records describing the administered mixture. Each record carries the chemical identity as an ontology_term and the amount as a concentration composite.", + "constraints": {}, + "fields": [ + { + "name": "chemical", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology term identifying this chemical species.", + "constraints": {} + }, + { + "name": "amount", + "type": "concentration", + "blank_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "default_value": { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Concentration of this chemical in the mixture (canonical sub-fields plus source_unit/source_value).", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/placement.json b/schemas/V_zeta/stable/placement.json new file mode 100644 index 0000000..f34db83 --- /dev/null +++ b/schemas/V_zeta/stable/placement.json @@ -0,0 +1,38 @@ +{ + "document_class": { + "class_name": "placement", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "container_id", + "mustBeNonEmpty": true, + "documentation": "The container (plate/chamber/cage) the subject is placed in. Itself a subject.", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [ + { + "name": "batch_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional grouping handle linking placements minted as one curatorial act.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/position_metadata.json b/schemas/V_zeta/stable/position_metadata.json new file mode 100644 index 0000000..774ca50 --- /dev/null +++ b/schemas/V_zeta/stable/position_metadata.json @@ -0,0 +1,122 @@ +{ + "document_class": { + "class_name": "position_metadata", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element whose position is described by this metadata.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "measurement", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:location", + "name": "location" + }, + "documentation": "Ontology term classifying what kind of position is recorded by the linked element (e.g., a midpoint position, an anatomical landmark, a probe tip). The `node` is the v1 `ontologyNode` CURIE verbatim; `name` is resolved via ndi.ontology.lookup at conversion time.", + "constraints": {} + }, + { + "name": "units", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology term naming the measurement unit for the position values (e.g., 'micrometer'). Resolved via ndi.ontology.lookup.", + "constraints": {} + }, + { + "name": "dimensions", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Array of per-axis records describing each spatial dimension of the position measurement. v1 stored dimensions as a comma-separated CURIE list with implicit positional ordering; V_delta makes the ordering explicit via the `axis` field while preserving the ontology classification. The migrator labels axes as `axis_1`, `axis_2`, ... by default; an explicit `x`/`y`/`z` convention can be applied per-document where the spatial mapping is known.", + "constraints": {}, + "fields": [ + { + "name": "axis", + "type": "char", + "blank_value": "", + "default_value": "axis_1", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-record axis identifier. Defaults to positional labels (`axis_1`, `axis_2`, ...); consumers may rewrite to a spatial convention (e.g., `x`, `y`, `z`) when known.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "node", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology CURIE classifying this axis (e.g., a directional or anatomical-axis ontology node).", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Human-readable label resolved from `node` via ndi.ontology.lookup at conversion time. Empty when the lookup is unavailable.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/pressure_manipulation.json b/schemas/V_zeta/stable/pressure_manipulation.json new file mode 100644 index 0000000..27f878c --- /dev/null +++ b/schemas/V_zeta/stable/pressure_manipulation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "pressure_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_manipulation" + }, + { + "class_name": "scalar_pressure" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/probe_geometry.json b/schemas/V_zeta/stable/probe_geometry.json new file mode 100644 index 0000000..4b29ae7 --- /dev/null +++ b/schemas/V_zeta/stable/probe_geometry.json @@ -0,0 +1,82 @@ +{ + "document_class": { + "class_name": "probe_geometry", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "probe_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the probe whose geometry is described.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "num_channels", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The total number of channels on the probe.", + "constraints": {} + }, + { + "name": "channel_positions", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Nx2 matrix of channel positions in position_units, where N equals num_channels. Each row is [x, y] giving the spatial location of that channel on the probe.", + "constraints": { + "element_type": "double", + "shape": "Nx2" + } + }, + { + "name": "position_units", + "type": "char", + "blank_value": "", + "default_value": "um", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The units for channel positions (e.g., 'um', 'mm').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "probe_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type or model of the probe (e.g., 'Neuropixels 1.0', 'tetrode').", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/probe_location.json b/schemas/V_zeta/stable/probe_location.json new file mode 100644 index 0000000..478b7e5 --- /dev/null +++ b/schemas/V_zeta/stable/probe_location.json @@ -0,0 +1,53 @@ +{ + "document_class": { + "class_name": "probe_location", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "probe_id", + "mustBeNonEmpty": true, + "documentation": "The unique ID of the probe document this location is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "ontology_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ontology identifier of the probe's anatomical/functional location (e.g., 'UBERON:0002436', 'UBERON:0001880'). v1 ships this as a flat char field alongside `name`.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Human-readable name for the location (e.g., 'primary visual cortex', 'bed nucleus of stria terminalis (BNST)'). Paired with `ontology_name`.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/procedural_manipulation.json b/schemas/V_zeta/stable/procedural_manipulation.json new file mode 100644 index 0000000..16e66a0 --- /dev/null +++ b/schemas/V_zeta/stable/procedural_manipulation.json @@ -0,0 +1,50 @@ +{ + "document_class": { + "class_name": "procedural_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "procedure", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The procedure performed (OBI/NCIT surgery & procedure branches; NDIC fallback).", + "constraints": {} + }, + { + "name": "notes", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", + "constraints": { + "maxLength": 4096 + } + } + ] +} diff --git a/schemas/V_zeta/stable/pyraview.json b/schemas/V_zeta/stable/pyraview.json new file mode 100644 index 0000000..dcffbc2 --- /dev/null +++ b/schemas/V_zeta/stable/pyraview.json @@ -0,0 +1,177 @@ +{ + "document_class": { + "class_name": "pyraview", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "epochclocktimes" + }, + { + "class_name": "filter" + }, + { + "class_name": "base" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element this pyraview is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "level1.bin", + "documentation": "Binary data for decimation level 1." + }, + { + "name": "level2.bin", + "documentation": "Binary data for decimation level 2." + }, + { + "name": "level3.bin", + "documentation": "Binary data for decimation level 3." + }, + { + "name": "level4.bin", + "documentation": "Binary data for decimation level 4." + }, + { + "name": "level5.bin", + "documentation": "Binary data for decimation level 5." + }, + { + "name": "level6.bin", + "documentation": "Binary data for decimation level 6." + }, + { + "name": "level7.bin", + "documentation": "Binary data for decimation level 7." + }, + { + "name": "level8.bin", + "documentation": "Binary data for decimation level 8." + }, + { + "name": "level9.bin", + "documentation": "Binary data for decimation level 9." + }, + { + "name": "level10.bin", + "documentation": "Binary data for decimation level 10." + } + ], + "fields": [ + { + "name": "label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A string label.", + "constraints": {} + }, + { + "name": "native_rate", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Native sampling rate.", + "constraints": {} + }, + { + "name": "native_start_time", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Native start time (t0).", + "constraints": {} + }, + { + "name": "channels", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Number of channels in the probe.", + "constraints": {} + }, + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Data type: 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'single', 'double'.", + "constraints": {} + }, + { + "name": "decimation_levels", + "type": "matrix", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Vector of decimation levels (integers).", + "constraints": {} + }, + { + "name": "decimation_sampling_rates", + "type": "matrix", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Vector of decimation sampling rates (doubles).", + "constraints": {} + }, + { + "name": "decimation_start_times", + "type": "matrix", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Vector of decimation start times (doubles).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/reverse_correlation.json b/schemas/V_zeta/stable/reverse_correlation.json new file mode 100644 index 0000000..59ae1b4 --- /dev/null +++ b/schemas/V_zeta/stable/reverse_correlation.json @@ -0,0 +1,62 @@ +{ + "document_class": { + "class_name": "reverse_correlation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "ngrid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element this reverse correlation was computed for.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_presentation that drove the responses.", + "must_refer_to_document_class": "stimulus_presentation" + } + ], + "file": [], + "fields": [ + { + "name": "method", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Name of the reverse-correlation method used (e.g., 'spike-triggered average', 'STC'). Candidate for promotion to ontology_term.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "dimension_labels", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Comma-separated names for the axes of the reverse-correlation kernel inherited from ngrid (e.g., 'Time, X, Y').", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_concentration.json b/schemas/V_zeta/stable/scalar_concentration.json new file mode 100644 index 0000000..b9c11b3 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_concentration.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_concentration", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "concentration", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed concentration value (shape-library mixin). Identity classes that read or impose a concentration inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_concentration_observation.json b/schemas/V_zeta/stable/scalar_concentration_observation.json new file mode 100644 index 0000000..2b29ae0 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_concentration_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_concentration_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_concentration" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_count.json b/schemas/V_zeta/stable/scalar_count.json new file mode 100644 index 0000000..75e55e9 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_count.json @@ -0,0 +1,39 @@ +{ + "document_class": { + "class_name": "scalar_count", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "count", + "blank_value": [], + "default_value": [ + { + "value": 0, + "unit": { + "node": "", + "name": "" + }, + "approximate": false + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed count value (shape-library mixin); value.unit names what is counted. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_count_observation.json b/schemas/V_zeta/stable/scalar_count_observation.json new file mode 100644 index 0000000..981d1ee --- /dev/null +++ b/schemas/V_zeta/stable/scalar_count_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_count_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_count" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_current.json b/schemas/V_zeta/stable/scalar_current.json new file mode 100644 index 0000000..efac657 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_current.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_current", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "current", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed current value (shape-library mixin). Identity classes that read or impose a current inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_current_observation.json b/schemas/V_zeta/stable/scalar_current_observation.json new file mode 100644 index 0000000..eff39f4 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_current_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_current_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_current" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_duration.json b/schemas/V_zeta/stable/scalar_duration.json new file mode 100644 index 0000000..b0ce590 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_duration.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_duration", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "duration", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed duration value (shape-library mixin). Identity classes that read or impose a duration inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_duration_observation.json b/schemas/V_zeta/stable/scalar_duration_observation.json new file mode 100644 index 0000000..4dfa8ba --- /dev/null +++ b/schemas/V_zeta/stable/scalar_duration_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_duration_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_duration" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_frequency.json b/schemas/V_zeta/stable/scalar_frequency.json new file mode 100644 index 0000000..80749a3 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_frequency.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_frequency", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "frequency", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed frequency value (shape-library mixin). Identity classes that read or impose a frequency inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_frequency_observation.json b/schemas/V_zeta/stable/scalar_frequency_observation.json new file mode 100644 index 0000000..00084f5 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_frequency_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_frequency_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_frequency" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_length.json b/schemas/V_zeta/stable/scalar_length.json new file mode 100644 index 0000000..8267c96 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_length.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_length", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "length", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed length value (shape-library mixin). Identity classes that read or impose a length inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_length_observation.json b/schemas/V_zeta/stable/scalar_length_observation.json new file mode 100644 index 0000000..8c8cf65 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_length_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_length_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_length" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_manipulation.json b/schemas/V_zeta/stable/scalar_manipulation.json new file mode 100644 index 0000000..2da6736 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_manipulation.json @@ -0,0 +1,32 @@ +{ + "document_class": { + "class_name": "scalar_manipulation", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "notes", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", + "constraints": { + "maxLength": 4096 + } + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_mass.json b/schemas/V_zeta/stable/scalar_mass.json new file mode 100644 index 0000000..9788ed1 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_mass.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_mass", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "mass", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed mass value (shape-library mixin). Identity classes that read or impose a mass inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_mass_observation.json b/schemas/V_zeta/stable/scalar_mass_observation.json new file mode 100644 index 0000000..447c7cf --- /dev/null +++ b/schemas/V_zeta/stable/scalar_mass_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_mass_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_mass" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_observation.json b/schemas/V_zeta/stable/scalar_observation.json new file mode 100644 index 0000000..4a62b9e --- /dev/null +++ b/schemas/V_zeta/stable/scalar_observation.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "scalar_observation", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "observation" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_pressure.json b/schemas/V_zeta/stable/scalar_pressure.json new file mode 100644 index 0000000..c98f8a9 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_pressure.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_pressure", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "pressure", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed pressure value (shape-library mixin). Identity classes that read or impose a pressure inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_pressure_observation.json b/schemas/V_zeta/stable/scalar_pressure_observation.json new file mode 100644 index 0000000..f172e2f --- /dev/null +++ b/schemas/V_zeta/stable/scalar_pressure_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_pressure_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_pressure" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_score.json b/schemas/V_zeta/stable/scalar_score.json new file mode 100644 index 0000000..872c4f5 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_score.json @@ -0,0 +1,41 @@ +{ + "document_class": { + "class_name": "scalar_score", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "score", + "blank_value": [], + "default_value": [ + { + "value": 0.0, + "scale": { + "node": "", + "name": "" + }, + "scale_min": 0.0, + "scale_max": 0.0, + "approximate": false + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed score value (shape-library mixin); value.scale names the rubric. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_score_observation.json b/schemas/V_zeta/stable/scalar_score_observation.json new file mode 100644 index 0000000..aaa4a8b --- /dev/null +++ b/schemas/V_zeta/stable/scalar_score_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_score_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_score" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_temperature.json b/schemas/V_zeta/stable/scalar_temperature.json new file mode 100644 index 0000000..c93b9e5 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_temperature.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_temperature", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "temperature", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed temperature value (shape-library mixin). Identity classes that read or impose a temperature inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_temperature_observation.json b/schemas/V_zeta/stable/scalar_temperature_observation.json new file mode 100644 index 0000000..46fe829 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_temperature_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_temperature_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_temperature" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_voltage.json b/schemas/V_zeta/stable/scalar_voltage.json new file mode 100644 index 0000000..24b99ab --- /dev/null +++ b/schemas/V_zeta/stable/scalar_voltage.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_voltage", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "voltage", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed voltage value (shape-library mixin). Identity classes that read or impose a voltage inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_voltage_observation.json b/schemas/V_zeta/stable/scalar_voltage_observation.json new file mode 100644 index 0000000..14b593b --- /dev/null +++ b/schemas/V_zeta/stable/scalar_voltage_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_voltage_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_voltage" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/scalar_volume.json b/schemas/V_zeta/stable/scalar_volume.json new file mode 100644 index 0000000..8bed815 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_volume.json @@ -0,0 +1,36 @@ +{ + "document_class": { + "class_name": "scalar_volume", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "value", + "type": "volume", + "blank_value": [], + "default_value": [ + { + "approximate": false, + "source_unit": "", + "source_value": 0.0 + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "A typed volume value (shape-library mixin). Identity classes that read or impose a volume inherit this `value`. Series-as-cardinality (Brainstorm I): an ARRAY of the composite; a single reading is the length-1 case. Per-sample timing is DERIVED from the anchoring time_reference's shaped `sampling` (no sample_time).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/scalar_volume_observation.json b/schemas/V_zeta/stable/scalar_volume_observation.json new file mode 100644 index 0000000..0332fe5 --- /dev/null +++ b/schemas/V_zeta/stable/scalar_volume_observation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "scalar_volume_observation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_observation" + }, + { + "class_name": "scalar_volume" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/session.json b/schemas/V_zeta/stable/session.json new file mode 100644 index 0000000..c5ec4bc --- /dev/null +++ b/schemas/V_zeta/stable/session.json @@ -0,0 +1,88 @@ +{ + "document_class": { + "class_name": "session", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "reference", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "ncit:C169028", + "name": "Study Unique Identifier" + }, + "documentation": "A unique reference string for this experimental session.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000219", + "name": "denotes" + }, + "documentation": "The session type (e.g., 'acute', 'chronic'). The field denotes a value drawn from a session-type vocabulary; candidate for promotion to ontology_term.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "date", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "schema:startDate", + "name": "startDate" + }, + "documentation": "The date of the session in ISO 8601 format (YYYY-MM-DD).", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "purpose", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:description", + "name": "description" + }, + "documentation": "A free-text description of the purpose of this session.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/stable/session_extent.json b/schemas/V_zeta/stable/session_extent.json new file mode 100644 index 0000000..23a84de --- /dev/null +++ b/schemas/V_zeta/stable/session_extent.json @@ -0,0 +1,82 @@ +{ + "document_class": { + "class_name": "session_extent", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "session_id", + "mustBeNonEmpty": true, + "documentation": "The session whose temporal extent this record declares.", + "must_refer_to_document_class": "session" + } + ], + "file": [], + "fields": [ + { + "name": "start", + "type": "timestamp", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "UTC start of the session (optional; at least one of start/end must be present).", + "constraints": {} + }, + { + "name": "end", + "type": "timestamp", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "UTC end of the session (optional; at least one of start/end must be present).", + "constraints": {} + }, + { + "name": "grounding", + "type": "char", + "blank_value": "declared", + "default_value": "declared", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "How the extent was determined. 'declared' = curator-asserted (e.g. daq-less session); the others are derived/recomputable from the session's evidence.", + "constraints": { + "enum": [ + "declared", + "epoch_derived", + "reference_derived", + "developmental" + ] + } + }, + { + "name": "is_approximate", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Binary precision tier for the declared/derived bounds.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/session_in_a_dataset.json b/schemas/V_zeta/stable/session_in_a_dataset.json new file mode 100644 index 0000000..c737a5c --- /dev/null +++ b/schemas/V_zeta/stable/session_in_a_dataset.json @@ -0,0 +1,156 @@ +{ + "document_class": { + "class_name": "session_in_a_dataset", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "session_id", + "type": "did_uid", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "Document ID of the session referenced by this record. Note: this is the *referenced* session, not the dataset's session (which lives on base.session_id and serves as the dataset identifier).", + "constraints": {} + }, + { + "name": "session_reference", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Human-readable label for the session (e.g., a recording date string like '2008-05-22').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "is_linked", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "1 if the session is linked into the dataset (i.e., its underlying directory or remote is currently reachable); 0 if it is only referenced by metadata.", + "constraints": { + "min": 0, + "max": 1 + } + }, + { + "name": "session_creator", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Fully-qualified name of the NDI session class that produced this session (e.g., 'ndi.session.dir', 'ndi.session.cloud'). Used together with session_creator_input1..6 to reconstitute the session object.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "session_creator_input1", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "First positional argument passed to session_creator when reconstituting the session.", + "constraints": {} + }, + { + "name": "session_creator_input2", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Second positional argument passed to session_creator when reconstituting the session.", + "constraints": {} + }, + { + "name": "session_creator_input3", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Third positional argument passed to session_creator when reconstituting the session.", + "constraints": {} + }, + { + "name": "session_creator_input4", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fourth positional argument passed to session_creator when reconstituting the session.", + "constraints": {} + }, + { + "name": "session_creator_input5", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fifth positional argument passed to session_creator when reconstituting the session.", + "constraints": {} + }, + { + "name": "session_creator_input6", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Sixth positional argument passed to session_creator when reconstituting the session.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/session_relative_reference.json b/schemas/V_zeta/stable/session_relative_reference.json new file mode 100644 index 0000000..5da709d --- /dev/null +++ b/schemas/V_zeta/stable/session_relative_reference.json @@ -0,0 +1,45 @@ +{ + "document_class": { + "class_name": "session_relative_reference", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "time_reference" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "session_id", + "mustBeNonEmpty": true, + "documentation": "The session this reference is ordinally relative to.", + "must_refer_to_document_class": "session" + } + ], + "file": [], + "fields": [ + { + "name": "relation", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ordinal relation of the interaction to the session, with no metric offset (the case where there is neither a device clock nor a wall-clock date).", + "constraints": { + "enum": [ + "before", + "after", + "at_start_of", + "at_end_of", + "concurrent_with", + "during" + ] + } + } + ] +} diff --git a/schemas/V_zeta/stable/simple_calc.json b/schemas/V_zeta/stable/simple_calc.json new file mode 100644 index 0000000..21569e2 --- /dev/null +++ b/schemas/V_zeta/stable/simple_calc.json @@ -0,0 +1,54 @@ +{ + "document_class": { + "class_name": "simple_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "calculator" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element this calculation is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "result_value", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The scalar result value of the calculation.", + "constraints": {} + }, + { + "name": "result_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The units of the result value.", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/site2channelmap.json b/schemas/V_zeta/stable/site2channelmap.json new file mode 100644 index 0000000..d250da5 --- /dev/null +++ b/schemas/V_zeta/stable/site2channelmap.json @@ -0,0 +1,53 @@ +{ + "document_class": { + "class_name": "site2channelmap", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "probe_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the probe this channel map belongs to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "site_to_channel", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Structure mapping probe site identifiers (keys, as strings) to zero-based DAQ channel indices (values, integers). Number of entries equals num_sites.", + "constraints": { + "dynamic_keys": true, + "value_type": "integer" + }, + "fields": [] + }, + { + "name": "num_sites", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of recording sites in this mapping.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/sorting_parameters.json b/schemas/V_zeta/stable/sorting_parameters.json new file mode 100644 index 0000000..593809e --- /dev/null +++ b/schemas/V_zeta/stable/sorting_parameters.json @@ -0,0 +1,129 @@ +{ + "document_class": { + "class_name": "sorting_parameters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) these sorting parameters apply to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "sorter_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the spike sorting algorithm.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "graphical_mode", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Whether to use a graphical presentation during sorting (0 = no, 1 = yes).", + "constraints": { + "min": 0, + "max": 1 + } + }, + { + "name": "num_pca_features", + "type": "integer", + "blank_value": 10, + "default_value": 10, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of principal component features to use in clustering.", + "constraints": { + "min": 1 + } + }, + { + "name": "interpolation", + "type": "integer", + "blank_value": 3, + "default_value": 3, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Interpolation factor for spike waveforms. Waveforms are upsampled by this integer factor to provide extra resolution during alignment and clustering (e.g., 3 means 3x upsampling). Set to 1 for no interpolation.", + "constraints": { + "min": 1 + } + }, + { + "name": "min_clusters", + "type": "integer", + "blank_value": 3, + "default_value": 3, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Minimum number of clusters (units) to produce.", + "constraints": { + "min": 1 + } + }, + { + "name": "max_clusters", + "type": "integer", + "blank_value": 10, + "default_value": 10, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Maximum number of clusters (units) to produce. Must be >= min_clusters.", + "constraints": { + "min": 1 + } + }, + { + "name": "num_start", + "type": "integer", + "blank_value": 5, + "default_value": 5, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Initial number of clusters to seed the clustering algorithm with.", + "constraints": { + "min": 1 + } + } + ] +} diff --git a/schemas/V_zeta/stable/spatial_frequency_tuning.json b/schemas/V_zeta/stable/spatial_frequency_tuning.json new file mode 100644 index 0000000..7366a3d --- /dev/null +++ b/schemas/V_zeta/stable/spatial_frequency_tuning.json @@ -0,0 +1,939 @@ +{ + "document_class": { + "class_name": "spatial_frequency_tuning", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element whose spatial frequency tuning is described.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_tuningcurve_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_tuningcurve from which this tuning was derived.", + "must_refer_to_document_class": "stimulus_tuningcurve" + } + ], + "file": [], + "fields": [ + { + "name": "properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Bookkeeping properties describing how response values were measured and reported.", + "constraints": {}, + "fields": [ + { + "name": "response_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Units of the response values (e.g., 'spikes/s', 'dF/F').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "mean", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reduction applied to each stimulus presentation to yield a per-trial response (e.g., 'mean', 'F1').", + "constraints": { + "maxLength": 64 + } + } + ] + }, + { + "name": "tuning_curve", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Empirical spatial-frequency tuning curve and per-point summary statistics.", + "constraints": {}, + "fields": [ + { + "name": "spatial_frequency", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The set of spatial frequencies tested, in cycles per degree (1xN vector).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean response to each spatial frequency. Responses may be normalized and are usually control-subtracted.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the response to each spatial frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean of the response to each spatial frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Individual per-trial response values for each spatial frequency. Responses may be normalized and are usually control-subtracted. Rows index spatial frequencies; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the control-group response values at each spatial frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean of the control-group response values at each spatial frequency.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "significance", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "ANOVA-derived significance metrics for the tuning curve.", + "constraints": {}, + "fields": [ + { + "name": "visual_response_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values between the raw (stimulus) and control groups.", + "constraints": {} + }, + { + "name": "across_stimuli_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values generated by different stimuli (across the sampled spatial frequencies).", + "constraints": {} + } + ] + }, + { + "name": "fitless", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fit-free summary measures derived directly from the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency below the peak where the empirical (unfitted) response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency at which the empirical (unfitted) peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency above the peak where the empirical (unfitted) response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "low_pass_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Response at the lowest tested spatial frequency divided by the response at the peak spatial frequency. Responses are rectified to be non-negative; possible values are in 0..1 or NaN (if 0/0).", + "constraints": {} + }, + { + "name": "high_pass_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Response at the highest tested spatial frequency divided by the response at the peak spatial frequency. Responses are rectified to be non-negative; possible values are in 0..1 or NaN (if 0/0).", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_dog", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Difference-of-Gaussians fit to the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Difference-of-Gaussians fit parameters [b a1 b1 a2 b2] (see vis.frequency.dog_fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The spatial frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each spatial frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_movshon", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit to the empirical curve (4 free parameters).", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit parameters [k f fc B] (see vis.frequency.movshon2005_fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The spatial frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each spatial frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_movshon_c", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit with an additional constant term (5 free parameters).", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit parameters with a constant term [k f fc B C] (see vis.frequency.movshon2005_fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The spatial frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each spatial frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_spline", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Smoothing-spline fit to the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The spatial frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each spatial frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency below the peak where the spline response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency at which the spline peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency above the peak where the spline response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the spline: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_gausslog", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Skewed-Gaussian fit to the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector for the skewed-Gaussian function.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The spatial frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each spatial frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The spatial frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "abs", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mirror of all preceding blocks (tuning_curve, significance, fitless, fit_dog, fit_movshon, fit_movshon_c, fit_spline, fit_gausslog) recomputed on the absolute value of the responses. Empty in NDIcalc-vis-matlab v1; sub-fields to be populated as the calc implementation matures.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/spatial_frequency_tuning_calc.json b/schemas/V_zeta/stable/spatial_frequency_tuning_calc.json new file mode 100644 index 0000000..9440bac --- /dev/null +++ b/schemas/V_zeta/stable/spatial_frequency_tuning_calc.json @@ -0,0 +1,21 @@ +{ + "document_class": { + "class_name": "spatial_frequency_tuning_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "spatial_frequency_tuning" + }, + { + "class_name": "tuning_fit" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} \ No newline at end of file diff --git a/schemas/V_zeta/stable/speed_tuning.json b/schemas/V_zeta/stable/speed_tuning.json new file mode 100644 index 0000000..d80acd3 --- /dev/null +++ b/schemas/V_zeta/stable/speed_tuning.json @@ -0,0 +1,722 @@ +{ + "document_class": { + "class_name": "speed_tuning", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element whose speed tuning is described.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_tuningcurve_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_tuningcurve from which this speed tuning was derived.", + "must_refer_to_document_class": "stimulus_tuningcurve" + } + ], + "file": [], + "fields": [ + { + "name": "properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Bookkeeping properties describing how response values were measured and reported.", + "constraints": {}, + "fields": [ + { + "name": "response_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Units of the response values (e.g., 'spikes/s', 'dF/F').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "mean", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reduction applied to each stimulus presentation to yield a per-trial response (e.g., 'mean', 'peak', 'F1').", + "constraints": { + "maxLength": 64 + } + } + ] + }, + { + "name": "tuning_curve", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The empirical speed tuning curve in the (spatial frequency, temporal frequency) plane and per-point summary statistics.", + "constraints": {}, + "fields": [ + { + "name": "spatial_frequency", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The set of spatial frequency values (cycles per degree) sampled along the speed tuning curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "temporal_frequency", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The set of temporal frequency values (cycles per second) sampled along the speed tuning curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean response at each sampled (spatial frequency, temporal frequency) point, in response_units.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the responses at each sampled (spatial frequency, temporal frequency) point.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean response at each sampled (spatial frequency, temporal frequency) point.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Individual per-trial response values. Responses may be normalized or control-subtracted. Rows index sampled (SF, TF) points; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "raw_individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Unprocessed per-trial response values (no blank subtraction or normalization). Rows index sampled (SF, TF) points; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-trial response values to the control stimulus (e.g., a blank screen with the same duration as the stimuli). Rows index sampled (SF, TF) points; columns index trials.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "significance", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "ANOVA-derived significance metrics for the speed tuning curve.", + "constraints": {}, + "fields": [ + { + "name": "visual_response_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values between the raw (stimulus) and control groups.", + "constraints": {} + }, + { + "name": "across_stimuli_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values generated by different stimuli (tuning vs. flat).", + "constraints": {} + } + ] + }, + { + "name": "fit", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Priebe-style joint spatial-frequency / temporal-frequency fit to the empirical surface, using a modified two-dimensional Gaussian function with seven free parameters.", + "constraints": {}, + "fields": [ + { + "name": "priebe_fit_parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector for the Priebe modified two-dimensional Gaussian (seven free parameters).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_spatial_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of spatial frequency values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_temporal_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of temporal frequency values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted response values at each (spatial frequency, temporal frequency) point in priebe_fit_spatial_frequencies x priebe_fit_temporal_frequencies.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_speed_tuning_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Index describing the relationship between preferred speed and spatial frequency under the fit (Priebe et al.).", + "constraints": {} + }, + { + "name": "priebe_fit_spatial_frequency_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Spatial frequency, averaged across temporal frequencies, at which the neuron optimally responds under the fit.", + "constraints": {} + }, + { + "name": "priebe_fit_temporal_frequency_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Temporal frequency, averaged across spatial frequencies, at which the neuron optimally responds under the fit.", + "constraints": {} + }, + { + "name": "sse", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sum of squared errors of the fit.", + "constraints": {} + }, + { + "name": "r_squared", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Coefficient of determination (R^2) of the fit.", + "constraints": {} + } + ] + }, + { + "name": "fit_no_speed", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Priebe fit constrained to no speed tuning (nested null model for the F-test against the full fit). Sub-field shape mirrors the fit block.", + "constraints": {}, + "fields": [ + { + "name": "priebe_fit_parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted Priebe parameter vector under the no-speed constraint.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_spatial_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of spatial frequency values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_temporal_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of temporal frequency values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted response values under the no-speed-tuning constraint.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_speed_tuning_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Speed-tuning index under the no-speed-tuning constraint.", + "constraints": {} + }, + { + "name": "priebe_fit_spatial_frequency_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Spatial frequency, averaged across temporal frequencies, at which the neuron optimally responds under the fit.", + "constraints": {} + }, + { + "name": "priebe_fit_temporal_frequency_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Temporal frequency, averaged across spatial frequencies, at which the neuron optimally responds under the fit.", + "constraints": {} + }, + { + "name": "sse", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sum of squared errors of the fit.", + "constraints": {} + }, + { + "name": "r_squared", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Coefficient of determination (R^2) of the fit.", + "constraints": {} + }, + { + "name": "partial_r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Partial R^2 of the speed-tuning component, relative to the no-speed fit.", + "constraints": {} + }, + { + "name": "priebe_fit_nested_f_test_p_value", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value from the nested F-test comparing the no-speed-tuning and full-speed-tuning fits.", + "constraints": {} + } + ] + }, + { + "name": "fit_fullspeed", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Priebe fit with a fully-free speed-tuning component (alternative model for the F-test against fit_no_speed). Sub-field shape mirrors the fit block.", + "constraints": {}, + "fields": [ + { + "name": "priebe_fit_parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector for the Priebe modified two-dimensional Gaussian (seven free parameters) with full speed-tuning freedom.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_spatial_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of spatial frequency values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_temporal_frequencies", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The range of temporal frequency values at which the fit was evaluated.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted response values under the full-speed-tuning model.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "priebe_fit_speed_tuning_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Speed-tuning index under the full-speed-tuning model.", + "constraints": {} + }, + { + "name": "priebe_fit_spatial_frequency_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Spatial frequency, averaged across temporal frequencies, at which the neuron optimally responds under the fit.", + "constraints": {} + }, + { + "name": "priebe_fit_temporal_frequency_preference", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Temporal frequency, averaged across spatial frequencies, at which the neuron optimally responds under the fit.", + "constraints": {} + }, + { + "name": "sse", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Sum of squared errors of the fit.", + "constraints": {} + }, + { + "name": "r_squared", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Coefficient of determination (R^2) of the fit.", + "constraints": {} + }, + { + "name": "partial_r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Partial R^2 of the speed-tuning component, relative to the no-speed fit.", + "constraints": {} + }, + { + "name": "priebe_fit_nested_f_test_p_value", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value from the nested F-test against fit_no_speed.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/speed_tuning_calc.json b/schemas/V_zeta/stable/speed_tuning_calc.json new file mode 100644 index 0000000..3119b63 --- /dev/null +++ b/schemas/V_zeta/stable/speed_tuning_calc.json @@ -0,0 +1,21 @@ +{ + "document_class": { + "class_name": "speed_tuning_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "speed_tuning" + }, + { + "class_name": "tuning_fit" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} \ No newline at end of file diff --git a/schemas/V_zeta/stable/spike_clusters.json b/schemas/V_zeta/stable/spike_clusters.json new file mode 100644 index 0000000..e8137c8 --- /dev/null +++ b/schemas/V_zeta/stable/spike_clusters.json @@ -0,0 +1,60 @@ +{ + "document_class": { + "class_name": "spike_clusters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) this sorting output is associated with.", + "must_refer_to_document_class": "" + }, + { + "name": "sorting_parameters_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the sorting parameters used.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "clusters_file", + "documentation": "The file containing the spike cluster assignments." + } + ], + "fields": [ + { + "name": "num_clusters", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of clusters (units) identified.", + "constraints": {} + }, + { + "name": "num_spikes", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The total number of spikes that were sorted.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/spike_extraction_parameters.json b/schemas/V_zeta/stable/spike_extraction_parameters.json new file mode 100644 index 0000000..41b203b --- /dev/null +++ b/schemas/V_zeta/stable/spike_extraction_parameters.json @@ -0,0 +1,77 @@ +{ + "document_class": { + "class_name": "spike_extraction_parameters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) these extraction parameters apply to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "threshold", + "type": "double", + "blank_value": 0.0, + "default_value": -4.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The threshold value used for spike detection (in multiples of standard deviation or absolute voltage).", + "constraints": {} + }, + { + "name": "threshold_type", + "type": "char", + "blank_value": "", + "default_value": "std", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type of threshold ('std' for standard deviation multiples, 'absolute' for voltage).", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "filter_low", + "type": "double", + "blank_value": 0.0, + "default_value": 300.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The low-pass cutoff frequency of the bandpass filter in Hz.", + "constraints": {} + }, + { + "name": "filter_high", + "type": "double", + "blank_value": 0.0, + "default_value": 6000.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The high-pass cutoff frequency of the bandpass filter in Hz.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/spike_extraction_parameters_modification.json b/schemas/V_zeta/stable/spike_extraction_parameters_modification.json new file mode 100644 index 0000000..f02c362 --- /dev/null +++ b/schemas/V_zeta/stable/spike_extraction_parameters_modification.json @@ -0,0 +1,54 @@ +{ + "document_class": { + "class_name": "spike_extraction_parameters_modification", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "spike_extraction_parameters_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the spike_extraction_parameters being modified.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "modified_fields", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Structure whose keys are the names of the modified spike_extraction_parameters fields and whose values are the new values assigned to them. Dynamic keys: one entry per modified field.", + "constraints": { + "dynamic_keys": true + }, + "fields": [] + }, + { + "name": "modification_reason", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "A free-text reason for the parameter modification.", + "constraints": { + "maxLength": 1024 + } + } + ] +} diff --git a/schemas/V_zeta/stable/spike_interface_sorting_outputs.json b/schemas/V_zeta/stable/spike_interface_sorting_outputs.json new file mode 100644 index 0000000..ac4b21d --- /dev/null +++ b/schemas/V_zeta/stable/spike_interface_sorting_outputs.json @@ -0,0 +1,85 @@ +{ + "document_class": { + "class_name": "spike_interface_sorting_outputs", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) this sorting output is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "sorting_output_file", + "documentation": "The SpikeInterface sorting output file." + } + ], + "fields": [ + { + "name": "sorter_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the spike sorter used (e.g., 'kilosort2', 'mountainsort4').", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "num_units", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of units (clusters) found by the sorter.", + "constraints": {} + }, + { + "name": "sample_rate", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The sampling rate in Hz of the recording that was sorted.", + "constraints": {} + }, + { + "name": "sorter_parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Structure of the parameters used to run the sorter. Keys and value types are specific to the algorithm named in sorter_name (e.g., for 'kilosort2': {detect_threshold, projection_threshold, ...}).", + "constraints": { + "dynamic_keys_from": "sorter_name" + }, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/spikewaves.json b/schemas/V_zeta/stable/spikewaves.json new file mode 100644 index 0000000..68f0bb4 --- /dev/null +++ b/schemas/V_zeta/stable/spikewaves.json @@ -0,0 +1,73 @@ +{ + "document_class": { + "class_name": "spikewaves", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., probe) from which spikes were extracted.", + "must_refer_to_document_class": "" + }, + { + "name": "spike_extraction_parameters_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the extraction parameters used.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "spikewaves_file", + "documentation": "The file containing the spike waveform data." + } + ], + "fields": [ + { + "name": "num_spikes", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of spike waveforms extracted.", + "constraints": {} + }, + { + "name": "samples_per_spike", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "The number of samples per spike waveform.", + "constraints": {} + }, + { + "name": "sample_rate", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The sampling rate in Hz used during extraction.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_approach.json b/schemas/V_zeta/stable/stimulus_approach.json new file mode 100644 index 0000000..016b1fb --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_approach.json @@ -0,0 +1,75 @@ +{ + "document_class": { + "class_name": "stimulus_approach", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The subject receiving stimulation. Held directly for 0-hop subject search.", + "must_refer_to_document_class": "subject" + }, + { + "name": "stimulator_id", + "mustBeNonEmpty": true, + "documentation": "The stimulator apparatus; with epoch_id forms the self-contained epoch key.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The parameter body of the stimulus presentation.", + "must_refer_to_document_class": "stimulus_presentation" + }, + { + "name": "stimulus_manipulation_id", + "mustBeNonEmpty": true, + "documentation": "The subject-linked stimulus_manipulation event node.", + "must_refer_to_document_class": "stimulus_manipulation" + } + ], + "file": [], + "fields": [ + { + "name": "epoch_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Mirrors stimulus_presentation.epochid; with stimulator_id identifies the epoch at 0 hops.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "condition", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The out-of-band condition present during the epoch (e.g. 'left eye occluded'). One condition per document.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_bath.json b/schemas/V_zeta/stable/stimulus_bath.json new file mode 100644 index 0000000..56d2f0c --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_bath.json @@ -0,0 +1,22 @@ +{ + "document_class": { + "class_name": "stimulus_bath", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "bath" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_element_id", + "mustBeNonEmpty": true, + "documentation": "The stimulator element delivering during the bath.", + "must_refer_to_document_class": "element" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/stimulus_manipulation.json b/schemas/V_zeta/stable/stimulus_manipulation.json new file mode 100644 index 0000000..c9a0410 --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_manipulation.json @@ -0,0 +1,22 @@ +{ + "document_class": { + "class_name": "stimulus_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The stimulus_presentation body-of-record this event is generated from.", + "must_refer_to_document_class": "stimulus_presentation" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/stimulus_parameter.json b/schemas/V_zeta/stable/stimulus_parameter.json new file mode 100644 index 0000000..3e41042 --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_parameter.json @@ -0,0 +1,68 @@ +{ + "document_class": { + "class_name": "stimulus_parameter", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus presentation this parameter belongs to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "parameter_name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the stimulus parameter (e.g., 'angle', 'spatial_frequency').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "parameter_values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Array of numeric parameter values used across stimulus presentations, in parameter_units. One value per unique stimulus condition.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "parameter_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The units of the parameter values (e.g., 'degrees', 'cpd', 'Hz').", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_parameter_table.json b/schemas/V_zeta/stable/stimulus_parameter_table.json new file mode 100644 index 0000000..12a09fa --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_parameter_table.json @@ -0,0 +1,65 @@ +{ + "document_class": { + "class_name": "stimulus_parameter_table", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus presentation this parameter table belongs to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "parameter_names", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Comma-separated list of parameter names (column headers) in the table (e.g., 'angle,spatial_frequency,contrast'). Number of entries determines the number of columns in table_data.", + "constraints": {} + }, + { + "name": "table_data", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "2D matrix of numeric parameter values with shape (num_stimuli x num_parameters), where num_parameters equals the number of entries in parameter_names.", + "constraints": { + "element_type": "double", + "shape": "num_stimuli x num_parameters" + } + }, + { + "name": "num_stimuli", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The number of stimulus conditions (rows) in the table.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_presentation.json b/schemas/V_zeta/stable/stimulus_presentation.json new file mode 100644 index 0000000..f4e84e5 --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_presentation.json @@ -0,0 +1,78 @@ +{ + "document_class": { + "class_name": "stimulus_presentation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "app" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element associated with this stimulus presentation.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "presentation_order", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": { + "node": "placeholder:stimulus_presentation_order", + "name": "stimulus presentation order" + }, + "documentation": "Stimulus presentation index/order. v1 commonly ships a scalar 1; consumers that need a per-trial array fill it as a 1-based integer vector whose length equals the number of trials.", + "constraints": {} + }, + { + "name": "stimuli", + "type": "structure", + "blank_value": { + "parameters": {} + }, + "default_value": { + "parameters": {} + }, + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Stimulus configuration(s) captured at presentation time. v1 ships this as either a scalar struct (one stimulus configuration) or a struct array (one entry per presented stimulus, e.g., a 225-element array for a Hartley basis). The sole sub-field that all v1 corpora ship is `parameters`, an open-shape struct whose keys depend on the stimulus type (Hartley basis, sparse-noise grid, oriented gratings, etc.) and on the generating library version. V_delta does not constrain inner field names because each stimulus type contributes its own; the validator only verifies that `stimuli` is itself a struct (or struct array). Consumers that need to interpret specific parameter values should branch on the stimulus class context (e.g., the linked `app.app_name`) before reading.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Stimulus-type-specific parameter object. Open-shape: keys and value types depend on the stimulus generator. v1 corpora include Hartley-basis (rect, windowShape, M, K_absmax, randState, ...), sparse-noise (BG, value, random, repeat, pixSize, randState, ...), and many other variants.", + "constraints": {}, + "fields": [] + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_response.json b/schemas/V_zeta/stable/stimulus_response.json new file mode 100644 index 0000000..530e8ad --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_response.json @@ -0,0 +1,64 @@ +{ + "document_class": { + "class_name": "stimulus_response", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_presentation_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus presentation.", + "must_refer_to_document_class": "" + }, + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element (e.g., neuron) whose response was measured.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "response_file", + "documentation": "The file containing the stimulus response data." + } + ], + "fields": [ + { + "name": "stimulator_epochid", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Epoch identifier on the stimulator element whose presentation produced this response (e.g., 't00002'). Mirrors the v1 stimulus_response field.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "element_epochid", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Epoch identifier on the responding element (the element_id this document depends on) that aligns with the stimulator epoch above.", + "constraints": { + "maxLength": 64 + } + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_response_scalar.json b/schemas/V_zeta/stable/stimulus_response_scalar.json new file mode 100644 index 0000000..9a3d638 --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_response_scalar.json @@ -0,0 +1,55 @@ +{ + "document_class": { + "class_name": "stimulus_response_scalar", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "stimulus_response" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_response_id", + "mustBeNonEmpty": false, + "documentation": "Optional pointer to the underlying stimulus_response document.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "How the per-trial scalar response was reduced from the source signal (e.g., 'mean', 'peak', 'frequency'). v1 ships this directly on the stimulus_response_scalar block; declared here so per-class queries see it without joining to the parent.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "responses", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-trial scalar responses. v1 ships this as a struct with sub-fields {stimid (integer), response_real, response_imaginary, control_response_real, control_response_imaginary}; V_delta keeps the open-shape convention so callers can add bookkeeping fields without a schema bump.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_response_scalar_parameters.json b/schemas/V_zeta/stable/stimulus_response_scalar_parameters.json new file mode 100644 index 0000000..05db9eb --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_response_scalar_parameters.json @@ -0,0 +1,23 @@ +{ + "document_class": { + "class_name": "stimulus_response_scalar_parameters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [ + { + "name": "stimulus_response_scalar_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_response_scalar these parameters describe.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/stimulus_response_scalar_parameters_basic.json b/schemas/V_zeta/stable/stimulus_response_scalar_parameters_basic.json new file mode 100644 index 0000000..aa189ca --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_response_scalar_parameters_basic.json @@ -0,0 +1,105 @@ +{ + "document_class": { + "class_name": "stimulus_response_scalar_parameters_basic", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "stimulus_response_scalar_parameters" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "temporalfreqfunc", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Fully-qualified NDI function name that produced the temporal-frequency component of the scalar response (e.g., 'ndi.fun.stimulustemporalfrequency'). Identifies the analysis routine.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "freq_response", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "1 if this scalar response is a frequency-domain measurement, 0 otherwise. v1 corpora ship integer flags here.", + "constraints": { + "min": 0, + "max": 1 + } + }, + { + "name": "prestimulus_time", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Optional pre-stimulus baseline window. v1 ships either an empty array (no baseline subtraction) or a [start, stop] pair in seconds before stimulus onset.", + "constraints": {} + }, + { + "name": "prestimulus_normalization", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Optional normalization vector applied during the prestimulus baseline computation. v1 commonly ships an empty array; populated when a non-trivial baseline scheme is in use.", + "constraints": {} + }, + { + "name": "isspike", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "1 if the source signal is a spike train (analysed at spiketrain_dt resolution), 0 if it is a continuous signal.", + "constraints": { + "min": 0, + "max": 1 + } + }, + { + "name": "spiketrain_dt", + "type": "double", + "blank_value": 0.0, + "default_value": 0.001, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Time step (seconds) at which a spike train is discretised before computing the scalar response (e.g., 0.001 for 1 ms bins). Only meaningful when isspike == 1.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/stimulus_tuningcurve.json b/schemas/V_zeta/stable/stimulus_tuningcurve.json new file mode 100644 index 0000000..281e9ff --- /dev/null +++ b/schemas/V_zeta/stable/stimulus_tuningcurve.json @@ -0,0 +1,246 @@ +{ + "document_class": { + "class_name": "stimulus_tuningcurve", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_response_scalar_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_response_scalar this tuning curve was derived from.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "independent_variable_label", + "type": "string", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "obi:0000750", + "name": "independent variable" + }, + "documentation": "String label(s) for the independent variable(s) the tuning curve was computed across. v1 ships this as a 1-element list whose single entry is a comma-separated list of variable names when more than one variable was crossed (e.g., 'spatial_frequency,temporal_frequency'). V_delta keeps it as a string array; callers split the comma-separated form themselves if needed.", + "constraints": {} + }, + { + "name": "independent_variable_value", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Matrix of independent-variable values, one row per stimulus condition. Shape is (N_stimuli x N_independent_variables). For a single-variable tuning curve each row is length 1; for the 2D case (e.g., spatial-by-temporal frequency) each row is length 2.", + "constraints": {} + }, + { + "name": "stimid", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Integer stimulus identifiers (1-based) for each row of independent_variable_value. Length equals number of stimulus conditions.", + "constraints": { + "element_type": "integer" + } + }, + { + "name": "response_mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "ncit:C53319", + "name": "Arithmetic Mean" + }, + "documentation": "Per-stimulus mean of the scalar responses (length equals number of stimuli).", + "constraints": {} + }, + { + "name": "response_stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-stimulus standard deviation of the scalar responses.", + "constraints": {} + }, + { + "name": "response_stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "stato:0000037", + "name": "standard error of the mean" + }, + "documentation": "Per-stimulus standard error of the mean (length equals number of stimuli).", + "constraints": {} + }, + { + "name": "response_units", + "type": "string", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Units of the scalar response values. v1 often ships an empty array; populated when the source recording's units are known.", + "constraints": {} + }, + { + "name": "individual_responses_real", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Real component of each individual trial response. Shape (N_trials x N_stimuli). Paired with individual_responses_imaginary for complex-valued responses; for real-valued responses individual_responses_imaginary is zero or absent.", + "constraints": {} + }, + { + "name": "individual_responses_imaginary", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Imaginary component of each individual trial response. Same shape as individual_responses_real.", + "constraints": {} + }, + { + "name": "stimulus_presentation_number", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Per-trial, per-stimulus index of the original stimulus presentation. Shape (N_trials x N_stimuli). Lets callers map an individual_responses_real[t,s] back to the original stimulus_presentation document. Cells may be NaN where the corresponding trial slot held no presentation (v1 corpora use NaN as the missing-trial sentinel).", + "constraints": { + "element_type": "integer" + } + }, + { + "name": "control_stimid", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Stimulus identifiers for the control (blank/baseline) condition(s). Often empty when no control was recorded.", + "constraints": { + "element_type": "integer" + } + }, + { + "name": "control_response_mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean response on the control condition(s). Same length as response_mean (typically broadcasts a single control value across stimuli).", + "constraints": {} + }, + { + "name": "control_response_stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the response on the control condition(s).", + "constraints": {} + }, + { + "name": "control_response_stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean for the response on the control condition(s).", + "constraints": {} + }, + { + "name": "control_individual_responses_real", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Real component of individual trial responses on the control condition(s). Same shape conventions as individual_responses_real.", + "constraints": {} + }, + { + "name": "control_individual_responses_imaginary", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Imaginary component of individual trial responses on the control condition(s).", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/subject.json b/schemas/V_zeta/stable/subject.json new file mode 100644 index 0000000..7b3fef9 --- /dev/null +++ b/schemas/V_zeta/stable/subject.json @@ -0,0 +1,78 @@ +{ + "document_class": { + "class_name": "subject", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "local_identifier", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": { + "node": "iao:0000578", + "name": "centrally registered identifier" + }, + "documentation": "A globally unique identifier meaningful to a local group (e.g., 'mouse123@vhlab.org').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "description", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": { + "node": "schema:description", + "name": "description" + }, + "documentation": "A free-text description of the subject.", + "constraints": { + "maxLength": 1024 + } + }, + { + "name": "is_biological", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "True if the subject is the kind of thing for which biological metadata (species, strain, sex, developmental stage) is expected. Curation-expectation flag, not an ontological claim.", + "constraints": {} + }, + { + "name": "is_group", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "True if the subject represents a collection treated as plural (a group of one is still a group). Membership is recorded via group_assignment events, not enumerated here.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/subject_assertion.json b/schemas/V_zeta/stable/subject_assertion.json new file mode 100644 index 0000000..b48e9e1 --- /dev/null +++ b/schemas/V_zeta/stable/subject_assertion.json @@ -0,0 +1,80 @@ +{ + "document_class": { + "class_name": "subject_assertion", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The subject this timeless assertion is about.", + "must_refer_to_document_class": "subject" + } + ], + "file": [], + "fields": [ + { + "name": "asserted_property", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Semantic identity of the asserted, timeless property (e.g. species, strain, sex, genotype).", + "constraints": {} + }, + { + "name": "value", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The asserted value as a bound concept (e.g. an NCBITaxon species term). Typed/date values are a follow-up.", + "constraints": {} + }, + { + "name": "source", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Provenance/authority of the assertion (e.g. curator, vendor, openMINDS record). Optional.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/subject_interaction.json b/schemas/V_zeta/stable/subject_interaction.json new file mode 100644 index 0000000..a9444b4 --- /dev/null +++ b/schemas/V_zeta/stable/subject_interaction.json @@ -0,0 +1,82 @@ +{ + "document_class": { + "class_name": "subject_interaction", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [ + { + "name": "subject_id", + "mustBeNonEmpty": true, + "documentation": "The subject this interaction is about \u2014 the whole specimen whose property was measured or that was acted on (objective annotation rule).", + "must_refer_to_document_class": "subject" + }, + { + "name": "time_reference_#", + "mustBeNonEmpty": true, + "documentation": "When the interaction happened, as one or more time_reference documents (Brainstorm I \u00a71.2: the reference is SHAPED like the data \u2014 point / grid / enumerated \u2014 so per-sample times are derived, not stored).", + "must_refer_to_document_class": "time_reference", + "multiple": true + } + ], + "file": [], + "fields": [ + { + "name": "method", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The verb: what was done (measure, inject, heat, lesion, stimulate). Half of the (method, variable) identity pair (Brainstorm I \u00a71.1, settled). Optional at the schema level because on the observation tier the verb is nearly always 'measurement'; the binding registry is the soft correctness check.", + "constraints": {} + }, + { + "name": "variable", + "type": "ontology_term", + "blank_value": { + "node": "", + "name": "" + }, + "default_value": { + "node": "", + "name": "" + }, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The noun: what the interaction is about \u2014 the quantity observed or the entity/factor applied (temperature, body weight, a drug). The queryable fine identity; correctness of variable vs the value's shape is a binding-registry nudge, not a class weld (Brainstorm I, the EPM lesson).", + "constraints": {} + }, + { + "name": "target_structure", + "type": "ontology_term", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional locus on the subject: the anatomical structure(s) the act was about, as an ontology term or list (Path T, Locus_Encoding_Paths_Summary #69). Empty for whole-subject records; the subject stays the whole specimen.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/syncgraph.json b/schemas/V_zeta/stable/syncgraph.json new file mode 100644 index 0000000..1c6bd98 --- /dev/null +++ b/schemas/V_zeta/stable/syncgraph.json @@ -0,0 +1,39 @@ +{ + "document_class": { + "class_name": "syncgraph", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "syncrule_id_#", + "mustBeNonEmpty": true, + "multiple": true, + "documentation": "The document ID of a synchronisation rule participating in this sync graph. Each instance is named 'syncrule_id_1', 'syncrule_id_2', etc. A sync graph may reference any number of sync rules.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "ndi_syncgraph_class", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the synchronisation graph implementation.", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/syncrule.json b/schemas/V_zeta/stable/syncrule.json new file mode 100644 index 0000000..095f06d --- /dev/null +++ b/schemas/V_zeta/stable/syncrule.json @@ -0,0 +1,45 @@ +{ + "document_class": { + "class_name": "syncrule", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "ndi_syncrule_class", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The class name of the synchronisation rule implementation.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Synchronisation rule parameters. Keys and value types are specific to the sync rule implementation named in ndi_syncrule_class.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/syncrule_mapping.json b/schemas/V_zeta/stable/syncrule_mapping.json new file mode 100644 index 0000000..49ce6fc --- /dev/null +++ b/schemas/V_zeta/stable/syncrule_mapping.json @@ -0,0 +1,251 @@ +{ + "document_class": { + "class_name": "syncrule_mapping", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "syncrule_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the sync rule this mapping was computed from.", + "must_refer_to_document_class": "" + }, + { + "name": "epochid", + "mustBeNonEmpty": true, + "documentation": "The document ID of the epoch this mapping was computed for.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "cost", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Numeric cost / score of this mapping (lower is typically better). v1 ships an integer; V_delta uses `double` to admit fractional costs from future rules.", + "constraints": {} + }, + { + "name": "mapping", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Numeric mapping vector relating the two endpoints in clock space. v1 ships a 2-element numeric vector (int or float depending on the rule); V_delta keeps the shape open as a matrix.", + "constraints": {} + }, + { + "name": "epochnode_a", + "type": "structure", + "blank_value": { + "epoch_clock": "", + "epoch_id": "", + "epoch_session_id": "", + "epochprobemap": "", + "objectclass": "" + }, + "default_value": { + "epoch_clock": "", + "epoch_id": "", + "epoch_session_id": "", + "epochprobemap": "", + "objectclass": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "First endpoint of the mapping. Identifies the source epoch in clock space. Preserved verbatim from v1; the same shape applies to epochnode_b.", + "constraints": {}, + "fields": [ + { + "name": "epoch_clock", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Clock identifier for this endpoint (e.g., 'dev_local_time').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "epoch_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Epoch identifier within the endpoint's session (e.g., 't00001').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "epoch_session_id", + "type": "did_uid", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Document id of the session this endpoint's epoch lives in.", + "constraints": {} + }, + { + "name": "epochprobemap", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Tab-separated epoch-probe-map text describing the probe configuration at this endpoint. Free-form pass-through from v1.", + "constraints": {} + }, + { + "name": "objectclass", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Fully-qualified NDI epochprobemap class name (e.g., 'ndi.epoch.epochprobemap_daqsystem').", + "constraints": { + "maxLength": 256 + } + } + ] + }, + { + "name": "epochnode_b", + "type": "structure", + "blank_value": { + "epoch_clock": "", + "epoch_id": "", + "epoch_session_id": "", + "epochprobemap": "", + "objectclass": "" + }, + "default_value": { + "epoch_clock": "", + "epoch_id": "", + "epoch_session_id": "", + "epochprobemap": "", + "objectclass": "" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Second endpoint of the mapping. Same shape as epochnode_a.", + "constraints": {}, + "fields": [ + { + "name": "epoch_clock", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Clock identifier for this endpoint.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "epoch_id", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Epoch identifier within the endpoint's session.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "epoch_session_id", + "type": "did_uid", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Document id of the session this endpoint's epoch lives in.", + "constraints": {} + }, + { + "name": "epochprobemap", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Tab-separated epoch-probe-map text. Free-form pass-through from v1.", + "constraints": {} + }, + { + "name": "objectclass", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Fully-qualified NDI epochprobemap class name.", + "constraints": { + "maxLength": 256 + } + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/temperature_manipulation.json b/schemas/V_zeta/stable/temperature_manipulation.json new file mode 100644 index 0000000..df0374e --- /dev/null +++ b/schemas/V_zeta/stable/temperature_manipulation.json @@ -0,0 +1,18 @@ +{ + "document_class": { + "class_name": "temperature_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "scalar_manipulation" + }, + { + "class_name": "scalar_temperature" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/temporal_frequency_tuning.json b/schemas/V_zeta/stable/temporal_frequency_tuning.json new file mode 100644 index 0000000..abc8e06 --- /dev/null +++ b/schemas/V_zeta/stable/temporal_frequency_tuning.json @@ -0,0 +1,939 @@ +{ + "document_class": { + "class_name": "temporal_frequency_tuning", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the ndi.element whose temporal frequency tuning is described.", + "must_refer_to_document_class": "element" + }, + { + "name": "stimulus_tuningcurve_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the stimulus_tuningcurve from which this tuning was derived.", + "must_refer_to_document_class": "stimulus_tuningcurve" + } + ], + "file": [], + "fields": [ + { + "name": "properties", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Bookkeeping properties describing how response values were measured and reported.", + "constraints": {}, + "fields": [ + { + "name": "response_units", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Units of the response values (e.g., 'spikes/s', 'dF/F').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "response_type", + "type": "char", + "blank_value": "", + "default_value": "mean", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Reduction applied to each stimulus presentation to yield a per-trial response (e.g., 'mean', 'F1').", + "constraints": { + "maxLength": 64 + } + } + ] + }, + { + "name": "tuning_curve", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Empirical temporal-frequency tuning curve and per-point summary statistics.", + "constraints": {}, + "fields": [ + { + "name": "temporal_frequency", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The set of temporal frequencies tested, in cycles per second (1xN vector).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "mean", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mean response to each temporal frequency. Responses may be normalized and are usually control-subtracted.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the response to each temporal frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean of the response to each temporal frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "individual", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Individual per-trial response values for each temporal frequency. Responses may be normalized and are usually control-subtracted. Rows index temporal frequencies; columns index trials.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_stddev", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard deviation of the control-group response values at each temporal frequency.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "control_stderr", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Standard error of the mean of the control-group response values at each temporal frequency.", + "constraints": { + "element_type": "double" + } + } + ] + }, + { + "name": "significance", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "ANOVA-derived significance metrics for the tuning curve.", + "constraints": {}, + "fields": [ + { + "name": "visual_response_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values between the raw (stimulus) and control groups.", + "constraints": {} + }, + { + "name": "across_stimuli_anova_p", + "type": "double", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "p-value of the ANOVA relating the mean response values generated by different stimuli (across the sampled temporal frequencies).", + "constraints": {} + } + ] + }, + { + "name": "fitless", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fit-free summary measures derived directly from the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency below the peak where the empirical (unfitted) response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency at which the empirical (unfitted) peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency above the peak where the empirical (unfitted) response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "low_pass_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Response at the lowest tested temporal frequency divided by the response at the peak temporal frequency. Responses are rectified to be non-negative; possible values are in 0..1 or NaN (if 0/0).", + "constraints": {} + }, + { + "name": "high_pass_index", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Response at the highest tested temporal frequency divided by the response at the peak temporal frequency. Responses are rectified to be non-negative; possible values are in 0..1 or NaN (if 0/0).", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_dog", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Difference-of-Gaussians fit to the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Difference-of-Gaussians fit parameters [b a1 b1 a2 b2] (see vis.frequency.dog_fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The temporal frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each temporal frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_movshon", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit to the empirical curve (4 free parameters).", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit parameters [k f fc B] (see vis.frequency.movshon2005_fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The temporal frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each temporal frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_movshon_c", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit with an additional constant term (5 free parameters).", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Movshon 2005 fit parameters with a constant term [k f fc B C] (see vis.frequency.movshon2005_fit).", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The temporal frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each temporal frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_spline", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Smoothing-spline fit to the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The temporal frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each temporal frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency below the peak where the spline response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency at which the spline peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency above the peak where the spline response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the spline: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "fit_gausslog", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Skewed-Gaussian fit to the empirical curve.", + "constraints": {}, + "fields": [ + { + "name": "parameters", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Fitted parameter vector for the skewed-Gaussian function.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The temporal frequencies used to calculate a filled-in fit response curve.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "fit", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Response of the fit at each temporal frequency in values above.", + "constraints": { + "element_type": "double" + } + }, + { + "name": "r2", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The uncorrected r^2 value between the responses and the fit.", + "constraints": {} + }, + { + "name": "l50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency below the peak where the fit response drops below half the maximum, if any; -Inf if no such point exists.", + "constraints": {} + }, + { + "name": "pref", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency at which the fit peak response occurs.", + "constraints": {} + }, + { + "name": "h50", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The temporal frequency above the peak where the fit response drops below half the maximum, if any; +Inf if no such point exists.", + "constraints": {} + }, + { + "name": "bandwidth", + "type": "double", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Bandwidth between l50 and h50 in octaves under the fit: log2(h50 / l50). Inf if either l50 or h50 is +/-Inf.", + "constraints": {} + } + ] + }, + { + "name": "abs", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Mirror of all preceding blocks (tuning_curve, significance, fitless, fit_dog, fit_movshon, fit_movshon_c, fit_spline, fit_gausslog) recomputed on the absolute value of the responses. Empty in NDIcalc-vis-matlab v1; sub-fields to be populated as the calc implementation matures.", + "constraints": {}, + "fields": [] + } + ] +} diff --git a/schemas/V_zeta/stable/temporal_frequency_tuning_calc.json b/schemas/V_zeta/stable/temporal_frequency_tuning_calc.json new file mode 100644 index 0000000..d5f662b --- /dev/null +++ b/schemas/V_zeta/stable/temporal_frequency_tuning_calc.json @@ -0,0 +1,21 @@ +{ + "document_class": { + "class_name": "temporal_frequency_tuning_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "temporal_frequency_tuning" + }, + { + "class_name": "tuning_fit" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} \ No newline at end of file diff --git a/schemas/V_zeta/stable/time_reference.json b/schemas/V_zeta/stable/time_reference.json new file mode 100644 index 0000000..5eddfee --- /dev/null +++ b/schemas/V_zeta/stable/time_reference.json @@ -0,0 +1,106 @@ +{ + "document_class": { + "class_name": "time_reference", + "class_version": "2.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "is_approximate", + "type": "boolean", + "blank_value": false, + "default_value": false, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Binary precision tier. False ~ precise (within 0.1 ms); True ~ approximate (within ~5 s).", + "constraints": {} + }, + { + "name": "sampling", + "type": "structure", + "blank_value": {}, + "default_value": { + "kind": "point" + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Shape of the sample layout along time (Brainstorm I \u00a71.2). 'point': a single moment at the anchor (the scalar case). 'grid': a regular series \u2014 sample i occurs at the anchor + i / sample_rate, i in 0..n-1 (O(1); a week of samples is three numbers). 'enumerated': an irregular series \u2014 per-sample offsets from the anchor. Replaces the retired sample_time array; the anchoring instant (t0) is supplied by the concrete reference-frame subclass. len(value) must match the sampling extent (a consumer/tooling check).", + "constraints": {}, + "discriminator": "kind", + "fields": [ + { + "name": "kind", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "point | grid | enumerated.", + "constraints": { + "enum": [ + "point", + "grid", + "enumerated" + ] + } + }, + { + "name": "sample_rate", + "type": "frequency", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Grid only: samples per second (regular spacing).", + "constraints": {} + }, + { + "name": "n", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Grid only: number of samples.", + "constraints": {} + }, + { + "name": "offsets", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Enumerated only: per-sample time offsets from the anchor, in seconds, element-aligned with the value array.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/tuning_fit.json b/schemas/V_zeta/stable/tuning_fit.json new file mode 100644 index 0000000..dcaf327 --- /dev/null +++ b/schemas/V_zeta/stable/tuning_fit.json @@ -0,0 +1,16 @@ +{ + "document_class": { + "class_name": "tuning_fit", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "calculator" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/tuningcurve_calc.json b/schemas/V_zeta/stable/tuningcurve_calc.json new file mode 100644 index 0000000..ede266b --- /dev/null +++ b/schemas/V_zeta/stable/tuningcurve_calc.json @@ -0,0 +1,105 @@ +{ + "document_class": { + "class_name": "tuningcurve_calc", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "calculator" + }, + { + "class_name": "stimulus_tuningcurve" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "stimulus_tuningcurve_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the tuning curve this calculation was performed on.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "result_data", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Structure containing the tuning curve calculation results. Keys and value types are specific to the calculator named in calculator.calculator_name (e.g., preferred direction, tuning width, modulation index).", + "constraints": { + "dynamic_keys_from": "calculator_name" + }, + "fields": [] + }, + { + "name": "log", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Free-text log entry summarising the tuning-curve calculation (e.g., 'angle best value is 135.', 'sFrequency = 0.04'). Captured verbatim from v1 documents that carried a `log` field.", + "constraints": {} + }, + { + "name": "stim_property_list", + "type": "structure", + "blank_value": { + "names": [], + "values": [] + }, + "default_value": { + "names": [], + "values": [] + }, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Stimulus-property name/value pairs that conditioned this tuning-curve calculation. v1 stored this as `{names: [, ...], values: }`; V_delta preserves the same shape. `names` is the list of independent stimulus parameter names selected for the curve (most commonly a single name such as 'sFrequency'); `values` is the corresponding value(s).", + "constraints": {}, + "fields": [ + { + "name": "names", + "type": "string", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Array of stimulus parameter names (e.g., {'sFrequency', 'tFrequency'}). Empty array when no stimulus property was held; v1 most often ships a 1-element array.", + "constraints": {} + }, + { + "name": "values", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Numeric value(s) paralleling `names`. v1 ships either a scalar (when names is 1-element) or an empty array.", + "constraints": {} + } + ] + } + ] +} diff --git a/schemas/V_zeta/stable/utc_reference.json b/schemas/V_zeta/stable/utc_reference.json new file mode 100644 index 0000000..b1401b3 --- /dev/null +++ b/schemas/V_zeta/stable/utc_reference.json @@ -0,0 +1,42 @@ +{ + "document_class": { + "class_name": "utc_reference", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "time_reference" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [ + { + "name": "start", + "type": "timestamp", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Absolute wall-clock start.", + "constraints": {} + }, + { + "name": "end", + "type": "timestamp", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Absolute wall-clock end. Absent means an instant; present means an interval.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/valid_interval.json b/schemas/V_zeta/stable/valid_interval.json new file mode 100644 index 0000000..5b4532e --- /dev/null +++ b/schemas/V_zeta/stable/valid_interval.json @@ -0,0 +1,241 @@ +{ + "document_class": { + "class_name": "valid_interval", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the element whose valid interval is marked.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "timeref_structt0", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Time reference for the start of the interval (t0). Specifies the epoch and clock against which t0 is measured.", + "constraints": {}, + "fields": [ + { + "name": "referent_epochsetname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The name of the ndi.epoch.epochset object (e.g., device name, probe name, element name) that provides the time reference.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "referent_classname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The class name of the referent epochset object (e.g., 'element', 'probe', 'device').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "clocktypestring", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "String identifier of the ndi.time.clocktype used for this reference. Valid values: 'dev_local_time', 'dev_global_time', 'utc', 'approx_utc', 'exp_global_time', 'no_time'.", + "constraints": { + "maxLength": 64, + "enum": [ + "dev_local_time", + "dev_global_time", + "utc", + "approx_utc", + "exp_global_time", + "no_time" + ] + } + }, + { + "name": "epoch", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The epochid of the epoch in the referent epochset that provides the time origin.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "time", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The time offset (in seconds) within the reference epoch that serves as the origin for t0.", + "constraints": {} + } + ] + }, + { + "name": "t0", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Start time of the valid interval in seconds, measured relative to the origin defined by timeref_structt0.", + "constraints": {} + }, + { + "name": "timeref_structt1", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Time reference for the end of the interval (t1). Specifies the epoch and clock against which t1 is measured.", + "constraints": {}, + "fields": [ + { + "name": "referent_epochsetname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The name of the ndi.epoch.epochset object (e.g., device name, probe name, element name) that provides the time reference.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "referent_classname", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The class name of the referent epochset object (e.g., 'element', 'probe', 'device').", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "clocktypestring", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "String identifier of the ndi.time.clocktype used for this reference. Valid values: 'dev_local_time', 'dev_global_time', 'utc', 'approx_utc', 'exp_global_time', 'no_time'.", + "constraints": { + "maxLength": 64, + "enum": [ + "dev_local_time", + "dev_global_time", + "utc", + "approx_utc", + "exp_global_time", + "no_time" + ] + } + }, + { + "name": "epoch", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The epochid of the epoch in the referent epochset that provides the time origin.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "time", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The time offset (in seconds) within the reference epoch that serves as the origin for t1.", + "constraints": {} + } + ] + }, + { + "name": "t1", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "End time of the valid interval in seconds, measured relative to the origin defined by timeref_structt1. Must be >= t0 when both references are the same clock.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/vmneuralresponseresiduals.json b/schemas/V_zeta/stable/vmneuralresponseresiduals.json new file mode 100644 index 0000000..535b227 --- /dev/null +++ b/schemas/V_zeta/stable/vmneuralresponseresiduals.json @@ -0,0 +1,47 @@ +{ + "document_class": { + "class_name": "vmneuralresponseresiduals", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the neuron element this residuals analysis is associated with.", + "must_refer_to_document_class": "" + }, + { + "name": "vmspikefit_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the Vm-spike fit this residual analysis was computed from.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "residuals_file", + "documentation": "The file containing the neural response residual data." + } + ], + "fields": [ + { + "name": "mean_residual", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The mean residual of the Vm-to-firing-rate fit.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/vmspikefilteringparameters.json b/schemas/V_zeta/stable/vmspikefilteringparameters.json new file mode 100644 index 0000000..c2ddea0 --- /dev/null +++ b/schemas/V_zeta/stable/vmspikefilteringparameters.json @@ -0,0 +1,51 @@ +{ + "document_class": { + "class_name": "vmspikefilteringparameters", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the neuron element these filtering parameters apply to.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "filter_type", + "type": "char", + "blank_value": "", + "default_value": "median", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The type of spike filtering applied to the Vm signal (e.g., 'median', 'interpolation').", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "filter_window", + "type": "double", + "blank_value": 0.0, + "default_value": 0.001, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The time window in seconds used for spike filtering.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/vmspikefit.json b/schemas/V_zeta/stable/vmspikefit.json new file mode 100644 index 0000000..e62ecea --- /dev/null +++ b/schemas/V_zeta/stable/vmspikefit.json @@ -0,0 +1,72 @@ +{ + "document_class": { + "class_name": "vmspikefit", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the neuron element this Vm-spike fit is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [ + { + "name": "vmspikefit_file", + "documentation": "The file containing the Vm-to-spike-rate fit data." + } + ], + "fields": [ + { + "name": "fit_function", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The name of the function used to fit Vm to firing rate (e.g., 'threshold_linear', 'rectified_power').", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "fit_parameters", + "type": "structure", + "blank_value": {}, + "default_value": {}, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Structure of fitted parameter values keyed by parameter name. Keys and value types depend on fit_function (e.g., for 'threshold_linear': {threshold, slope}; for 'rectified_power': {threshold, slope, exponent}).", + "constraints": { + "dynamic_keys_from": "fit_function" + }, + "fields": [] + }, + { + "name": "r_squared", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "R-squared goodness-of-fit value.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/vmspikesummary.json b/schemas/V_zeta/stable/vmspikesummary.json new file mode 100644 index 0000000..58b6662 --- /dev/null +++ b/schemas/V_zeta/stable/vmspikesummary.json @@ -0,0 +1,75 @@ +{ + "document_class": { + "class_name": "vmspikesummary", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable" + }, + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": true, + "documentation": "The document ID of the neuron element this summary is associated with.", + "must_refer_to_document_class": "" + } + ], + "file": [], + "fields": [ + { + "name": "mean_vm", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The mean membrane potential (Vm) in mV.", + "constraints": {} + }, + { + "name": "mean_firing_rate", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The mean firing rate in Hz.", + "constraints": {} + }, + { + "name": "num_spikes", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The total number of spikes detected.", + "constraints": {} + }, + { + "name": "recording_duration", + "type": "double", + "blank_value": 0.0, + "default_value": 0.0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "The total recording duration in seconds.", + "constraints": {} + } + ] +} diff --git a/schemas/V_zeta/stable/zarr.json b/schemas/V_zeta/stable/zarr.json new file mode 100644 index 0000000..ce63d10 --- /dev/null +++ b/schemas/V_zeta/stable/zarr.json @@ -0,0 +1,553 @@ +{ + "document_class": { + "class_name": "zarr", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + } + ], + "maturity_level": "stable", + "abstract": true + }, + "depends_on": [], + "file": [], + "directory": [ + { + "name": "store", + "documentation": "The zarr store: a directory tree (or remote URI tree) containing the group's .zgroup/.zattrs (v2) or zarr.json (v3) sidecars plus per-array .zarray/zarr.json and chunk binary files. May be local or remote (S3, HTTP); the directory document's manifest_format determines how chunk paths are enumerated." + } + ], + "fields": [ + { + "name": "zarr_format", + "type": "char", + "blank_value": "", + "default_value": "3", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The zarr format version the writer declared for the arrays in this store. '2' for the historical .zarray layout (single 'compressor' object, dtype like '' big, '|' native). In v3 it is codecs[bytes].configuration.endian. Validator should check consistency with any 'bytes' entry in 'codecs'.", + "constraints": { + "enum": [ + "little", + "big", + "native" + ] + } + }, + { + "name": "shape", + "type": "matrix", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Per-dimension size of the native (level 0) array as an Nx1 column vector of integers; row count equals num_dimensions. Whole-vector equality queries are supported but rarely useful; concrete subclasses typically denormalise frequently-queried sizes (pixels_x, num_samples) into their own scalar fields.", + "constraints": { + "cols": 1, + "element_type": "integer", + "minimum": 1 + } + }, + { + "name": "chunks", + "type": "matrix", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Per-dimension chunk size of the native (level 0) array as an Nx1 column vector of integers; the chunk count along dimension i is ceil(shape[i] / chunks[i]). In v2 this is the top-level chunks field. In v3 it is chunk_grid.configuration.chunk_shape (when chunk_grid.name is 'regular' \u2014 the only grid type currently defined by the spec).", + "constraints": { + "cols": 1, + "element_type": "integer", + "minimum": 1 + } + }, + { + "name": "chunk_order", + "type": "char", + "blank_value": "", + "default_value": "C", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Byte order of elements within a chunk: 'C' for row-major (last axis fastest), 'F' for column-major (first axis fastest). v2 records this as the top-level 'order' field. v3 is implicitly 'C' (the spec does not carry an order field), so v3 documents always set 'C'.", + "constraints": { + "enum": [ + "C", + "F" + ] + } + }, + { + "name": "fill_value", + "type": "char", + "blank_value": "", + "default_value": "0", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Value returned for missing chunks, stored as a stringified scalar to accommodate the full range that zarr permits: integers ('0', '-1'), floats ('0.0', '3.14'), special floats ('NaN', 'Infinity', '-Infinity'), and booleans ('true', 'false'). Consumer tooling parses the string according to dtype. Numeric comparison queries are not supported on this field; equality queries are.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "num_dimensions", + "type": "integer", + "blank_value": 0, + "default_value": 1, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of dimensions of the native (level 0) array. Equal to the length of shape and chunks. Denormalised for cheap querying ('find all 5D zarrs').", + "constraints": { + "minimum": 1 + } + }, + { + "name": "num_elements", + "type": "double", + "blank_value": 0.0, + "default_value": 1.0, + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Total number of elements in the native (level 0) array (product of shape). Stored as double rather than integer because lightsheet and EM volumes routinely exceed 2^31 elements. Denormalised for cheap querying ('find all zarrs with > 1e10 elements').", + "constraints": { + "minimum": 1 + } + }, + { + "name": "codecs", + "type": "structure", + "blank_value": [], + "default_value": [ + { + "name": "bytes", + "endian": "little", + "level": null, + "checksum": null, + "inner_codec": "", + "shuffle": null, + "blocksize": null + } + ], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ordered codec pipeline applied to chunks. v3 stores carry their codecs[] array directly. v2 stores have either no compressor (empty codecs array) or one compressor object that consumer tooling normalises to a single-element codecs array. The discriminator 'name' selects which sub-fields are meaningful per entry: 'bytes' uses 'endian'; 'blosc' uses 'level', 'inner_codec', 'shuffle', 'blocksize'; 'gzip' and 'zlib' use 'level'; 'zstd' uses 'level' and 'checksum'; 'lz4' uses no parameters. Other codec names (e.g., 'transpose', 'sharding_indexed', 'crc32c') are permitted but their parameters are not currently surfaced as queryable sub-fields; round-trip support for those is the responsibility of consumer tooling.", + "constraints": {}, + "discriminator": "name", + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "bytes", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Codec name. Selects which other sub-fields of this codec entry are meaningful.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "endian", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Byte order for the 'bytes' codec. Empty string when this entry is not a 'bytes' codec. Must equal the document-level 'endianness' field when populated.", + "constraints": { + "enum": [ + "", + "little", + "big", + "native" + ] + } + }, + { + "name": "level", + "type": "integer", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Compression level. Codec-specific: 1-9 for gzip/zlib, 0-9 for blosc, 1-22 for zstd. Null when this entry's codec does not take a level.", + "constraints": { + "minimum": 0 + } + }, + { + "name": "checksum", + "type": "boolean", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Whether the codec appends an integrity checksum to each compressed chunk. Used by zstd. Null when this entry's codec does not have a checksum option.", + "constraints": {} + }, + { + "name": "inner_codec", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Inner codec used by blosc (its 'cname' parameter): typically 'lz4', 'zstd', 'blosclz', 'snappy'. Empty for non-blosc codecs.", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "shuffle", + "type": "integer", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Pre-compression shuffle filter for blosc: 0 = none, 1 = byte shuffle, 2 = bit shuffle. Null for non-blosc codecs.", + "constraints": { + "enum": [ + null, + 0, + 1, + 2 + ] + } + }, + { + "name": "blocksize", + "type": "integer", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Blosc internal block size in bytes. 0 means blosc chooses automatically. Null for non-blosc codecs.", + "constraints": { + "minimum": 0 + } + } + ] + }, + { + "name": "multiscales", + "type": "structure", + "blank_value": [], + "default_value": [ + { + "name": "default", + "downsampling_type": "none", + "metadata_json": "", + "axes": [], + "datasets": [ + { + "path": "0", + "scale": null, + "translation": null + } + ] + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "One or more multiscale pyramid groups within the store. Each pyramid is a list of arrays at progressively coarser resolution sharing one set of axes and one downsampling method. A single store can carry several parallel pyramids (e.g., a 'mean' pyramid for averaged previews and a 'max' pyramid for max-projection previews) that share the same level-0 native array. Non-pyramidal arrays have one multiscales entry with one datasets entry at path '0'.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "default", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Identifier for this pyramid within the store. Examples: 'mean', 'max', 'default'. Free-form string; OME-Zarr writers conventionally use it to disambiguate parallel pyramids.", + "constraints": { + "maxLength": 128 + } + }, + { + "name": "downsampling_type", + "type": "char", + "blank_value": "", + "default_value": "none", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Name of the algorithm used to produce coarser levels of this pyramid from the native array. OME-Zarr maps this to the multiscales[i].type field. Domain-specific allowed values: image-domain pyramids typically use 'mean', 'gaussian', 'max', 'peak', 'nearest', 'mode'; ephys-domain pyramids typically use 'minmax_envelope', 'decimate', 'rms', 'mean'. 'none' for non-pyramidal data.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "metadata_json", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Free-form per-pyramid algorithm provenance, stored as a stringified JSON object. OME-Zarr writers fill this with information like {'method': 'dask.array.coarsen(np.mean, ...)', 'version': '...'}. Not queryable as a structured field; retained only for round-trip fidelity.", + "constraints": { + "maxLength": 4096 + } + }, + { + "name": "axes", + "type": "structure", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Per-axis records ordered to match the corresponding dataset shape. Each element describes one dimension (its label, type, and physical unit). May be empty for non-OME-Zarr stores; OME-Zarr writers always populate it.", + "constraints": {}, + "fields": [ + { + "name": "name", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Axis label as the writer recorded it. Examples: 't', 'c', 'z', 'y', 'x', 'time', 'channel'. Free-form string; OME-Zarr typically uses single letters.", + "constraints": { + "maxLength": 64 + } + }, + { + "name": "type", + "type": "char", + "blank_value": "", + "default_value": "space", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Semantic class of this axis. OME-Zarr defines 'space', 'time', 'channel'; the schema also permits 'frequency' (e.g., spectrograms) and 'other' (writer-defined) for non-OME-Zarr stores.", + "constraints": { + "enum": [ + "space", + "time", + "channel", + "frequency", + "other" + ] + } + }, + { + "name": "unit", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Physical unit of this axis, written as a UDUNITS-2 string (e.g., 'micrometer', 'millisecond', 'hertz'). Empty for axes of type 'channel' (which has no physical unit) and for axes of type 'other' when no unit applies. The set of valid units depends on the axis type; the schema does not enforce that correlation structurally.", + "constraints": { + "maxLength": 64 + } + } + ] + }, + { + "name": "datasets", + "type": "structure", + "blank_value": [], + "default_value": [ + { + "path": "0", + "scale": null, + "translation": null + } + ], + "mustBeNonEmpty": true, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Ordered list of pyramid levels for this multiscale group. Element 0 is the native (full-resolution) array; subsequent elements are progressively coarser. Each entry names a path within the store and the physical-coordinate transform from index space to world space at that level. A non-pyramidal multiscales entry has exactly one datasets element with path '0'.", + "constraints": {}, + "fields": [ + { + "name": "path", + "type": "char", + "blank_value": "", + "default_value": "0", + "mustBeNonEmpty": true, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Path of this level's array within the zarr group, relative to the group root. Examples: '0' for the shared native array; 'mean/1' or 'max/2' for per-pyramid pyramid levels.", + "constraints": { + "maxLength": 256 + } + }, + { + "name": "scale", + "type": "matrix", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Per-axis scale coefficient that takes index coordinates to physical coordinates at this level, as an Nx1 column vector. For an axis with unit 'micrometer', a scale of 4 means each index step is 4 micrometers. Length equals num_dimensions; entry order matches the multiscales group's axes. OME-Zarr stores this as the 'scale' transform in coordinateTransformations. Null when no scale is declared.", + "constraints": { + "cols": 1, + "element_type": "double", + "minimum": 0 + } + }, + { + "name": "translation", + "type": "matrix", + "blank_value": null, + "default_value": null, + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": false, + "ontology": null, + "documentation": "Per-axis translation offset that shifts physical coordinates at this level, applied after the scale, as an Nx1 column vector in the same physical units as 'scale'. Length equals num_dimensions; entry order matches the multiscales group's axes. OME-Zarr stores this as an optional 'translation' transform following the 'scale' entry in coordinateTransformations. Null when no translation is declared (the common case for writers that align all levels to the origin).", + "constraints": { + "cols": 1, + "element_type": "double" + } + } + ] + } + ] + } + ] +} diff --git a/schemas/V_zeta/topics.json b/schemas/V_zeta/topics.json new file mode 100644 index 0000000..6d766f8 --- /dev/null +++ b/schemas/V_zeta/topics.json @@ -0,0 +1,392 @@ +{ + "set_version": "V_zeta", + "notes": "Topic tree for human navigation in the viewer. Independent of the class/superclass hierarchy and of any schema semantics; intended only to group related schemas by subject area, mirroring the directory layout used by the original NDI-matlab document_data tree. Editing this file does not affect schema validation or document classes. Classes not listed below appear under 'Uncategorized' in the viewer. The top-level 'classes' array holds classes that should appear as bare leaves at the root (no folder); 'topics' holds folder categories. Entries at each level are alphabetized, except that 'base' is pinned as the first top-level entry and 'meta' is pinned as the second.", + "classes": [ + "base" + ], + "topics": [ + { + "name": "meta", + "description": "Meta-schemas and reserved-keyword registries that describe the schema framework itself.", + "classes": [ + "CURIE_lookups_meta", + "did_schema_meta", + "ndi_reserved_keys" + ] + }, + { + "name": "annotations", + "description": "Annotation families: curatorial classifications such as group membership.", + "classes": [ + "group_assignment", + "interaction_purpose" + ] + }, + { + "name": "apps", + "description": "Application-specific documents and demos.", + "classes": [ + "app", + "demo_ndi", + "demo_ndi_mock", + "mock", + "pyraview" + ], + "children": [ + { + "name": "markgarbage", + "description": "Valid-interval annotations from the markgarbage app.", + "classes": [ + "valid_interval" + ] + }, + { + "name": "vhlab_voltage2firingrate", + "description": "Vm-to-firing-rate fitting and residuals (vhlab voltage2firingrate app).", + "classes": [ + "vmneuralresponseresiduals", + "vmspikefilteringparameters", + "vmspikefit", + "vmspikesummary" + ] + } + ] + }, + { + "name": "calculators", + "description": "Derived-quantity calculator documents (_calc). Most pair with a stimulus-response schema in stimulus/.", + "classes": [ + "calculator", + "contrast_sensitivity_calc", + "contrast_tuning_calc", + "hartley_calc", + "oridirtuning_calc", + "simple_calc", + "spatial_frequency_tuning_calc", + "speed_tuning_calc", + "temporal_frequency_tuning_calc", + "tuning_fit", + "tuningcurve_calc" + ] + }, + { + "name": "daq", + "description": "Data acquisition systems, readers, file navigation, sync, and epoch bookkeeping.", + "classes": [ + "daqmetadatareader", + "daqmetadatareader_epochdata_ingested", + "daqreader", + "daqreader_epochdata_ingested", + "daqreader_mfdaq_epochdata_ingested", + "daqreader_ndr", + "daqsystem", + "epochclocktimes", + "epochfiles_ingested", + "epochid", + "filenavigator", + "oneepoch", + "syncgraph", + "syncrule", + "syncrule_mapping" + ] + }, + { + "name": "data", + "description": "Generic data containers: time series, grids, images, fits, measurements, and generic file/directory wrappers.", + "classes": [ + "binaryseries_parameters", + "binnedspikeratevm", + "directory", + "distance_metadata", + "ephys_zarr", + "filter", + "fitcurve", + "generic_file", + "image", + "image_collection", + "image_stack", + "image_stack_parameters", + "image_zarr", + "measurement", + "ngrid", + "ontology_table_row", + "position_metadata", + "zarr" + ] + }, + { + "name": "dataseries_bodies", + "description": "Body-of-record documents carrying dataseries and expression/reference payloads.", + "classes": [ + "dataseries_data", + "timeseries_data", + "imageseries_data", + "timeseries_data_csv", + "timeseries_data_binary", + "timeseries_data_edf", + "dataseries_channel_map", + "dataseries_pyramid", + "instrument", + "expression_matrix_data", + "expression_matrix_data_h5ad", + "expression_matrix_data_mtx", + "expression_matrix_data_cellranger_h5", + "expression_matrix_data_loom", + "expression_matrix_data_counts_table", + "expression_matrix_data_gef", + "expression_matrix_data_gem", + "expression_matrix_data_visium", + "expression_matrix_data_mzml", + "expression_matrix_data_mztab", + "expression_matrix_data_maxquant", + "expression_matrix_data_dia_report", + "expression_matrix_data_imzml", + "reference_data", + "reference_sequence_data", + "reference_sequence_data_fasta_genome", + "reference_sequence_data_fasta_transcriptome", + "reference_sequence_data_fasta_protein", + "reference_annotation_data", + "reference_annotation_data_gtf", + "reference_annotation_data_gff3", + "sequence_read_data", + "sequence_read_data_bam", + "sequence_read_data_cram", + "sequence_read_data_fastq" + ] + }, + { + "name": "deprecated", + "description": "Classes deprecated in V_epsilon, retained for migration of legacy instances.", + "classes": [ + "projectvar", + "subject_group", + "treatment", + "treatment_drug", + "treatment_transfer", + "virus_injection" + ] + }, + { + "name": "element", + "description": "Logical recorded elements (channels, neurons) and their epoch data.", + "classes": [ + "element", + "element_epoch", + "neuron_extracellular" + ] + }, + { + "name": "manipulations", + "description": "Manipulation families: scalar, procedural, pharmacological, environmental, stimulus, placement, and derivation events.", + "classes": [ + "scalar_manipulation", + "temperature_manipulation", + "pressure_manipulation", + "frequency_manipulation", + "generic_scalar_manipulation", + "procedural_manipulation", + "biological_transfer", + "environmental_manipulation", + "pharmacological_manipulation", + "injection", + "bath", + "stimulus_manipulation", + "placement", + "derivation" + ] + }, + { + "name": "metadata", + "description": "External-ontology bindings (openMINDS, ontology lookups) and metadata editing.", + "classes": [ + "metadata_editor", + "ontology_image", + "ontology_label", + "openminds", + "openminds_element", + "openminds_stimulus", + "openminds_subject" + ] + }, + { + "name": "shape_library", + "description": "Brainstorm E shared shape library: typed value-composite mixin classes. Identity classes (observations by property, scalar manipulations by action) inherit one of these as a superclass to acquire their typed `value` field.", + "classes": [ + "categorical_observation", + "dataseries_observation", + "expression_observation", + "generic_scalar", + "generic_scalar_observation", + "imageseries_observation", + "scalar_concentration", + "scalar_concentration_observation", + "scalar_count", + "scalar_count_observation", + "scalar_current", + "scalar_current_observation", + "scalar_duration", + "scalar_duration_observation", + "scalar_frequency", + "scalar_frequency_observation", + "scalar_length", + "scalar_length_observation", + "scalar_mass", + "scalar_mass_observation", + "scalar_observation", + "scalar_pressure", + "scalar_pressure_observation", + "scalar_score", + "scalar_score_observation", + "scalar_temperature", + "scalar_temperature_observation", + "scalar_voltage", + "scalar_voltage_observation", + "scalar_volume", + "scalar_volume_observation", + "spatial_expression_observation", + "timeseries_observation" + ] + }, + { + "name": "observations", + "description": "Observation families (Brainstorm E): scalar observations named by property, categorical observations named by property, dataseries/image/expression measurements of subjects.", + "classes": [ + "observation", + "scalar_observation", + "generic_scalar_observation", + "categorical_observation", + "dataseries_observation", + "timeseries_observation", + "imageseries_observation", + "expression_observation", + "spatial_expression_observation" + ] + }, + { + "name": "probe", + "description": "Probe geometry, electrode mapping, and physical placement.", + "classes": [ + "electrode_offset_voltage", + "probe_geometry", + "probe_location", + "site2channelmap" + ] + }, + { + "name": "session", + "description": "Sessions, datasets, and project-scope variables.", + "classes": [ + "dataset_remote", + "dataset_session_info", + "projectvar", + "session", + "session_in_a_dataset", + "session_extent" + ] + }, + { + "name": "sorting", + "description": "Spike extraction, sorting, clusters, and waveforms.", + "classes": [ + "jrclust_clusters", + "sorting_parameters", + "spike_clusters", + "spike_extraction_parameters", + "spike_extraction_parameters_modification", + "spike_interface_sorting_outputs", + "spikewaves" + ] + }, + { + "name": "stimulus", + "description": "Stimulus descriptions, presentations, and stimulus-locked responses.", + "classes": [ + "control_stimulus_ids", + "reverse_correlation", + "stimulus_approach", + "stimulus_bath", + "stimulus_parameter", + "stimulus_parameter_table", + "stimulus_presentation", + "stimulus_response", + "stimulus_response_scalar", + "stimulus_response_scalar_parameters", + "stimulus_response_scalar_parameters_basic", + "stimulus_tuningcurve" + ], + "children": [ + { + "name": "visual", + "description": "Visual-stimulus tuning curves and reverse correlation.", + "classes": [ + "contrast_tuning", + "hartley_reverse_correlation", + "orientation_direction_tuning", + "spatial_frequency_tuning", + "speed_tuning", + "temporal_frequency_tuning" + ] + } + ] + }, + { + "name": "subject", + "description": "Subjects, subject groups, treatments, and interventions.", + "classes": [ + "subject", + "subject_group", + "treatment", + "treatment_drug", + "virus_injection" + ] + }, + { + "name": "subject_statement", + "description": "Timeless documented claims about a subject (Subject_Statement_Decision): the abstract subject_statement supertype and the concrete subject_assertion (asserted_property + value + source).", + "classes": [ + "subject_assertion" + ] + }, + { + "name": "subject_interaction", + "description": "The unified subject_interaction spine and its observation/manipulation/annotation tiers.", + "classes": [ + "subject_interaction", + "observation", + "manipulation", + "annotation" + ] + }, + { + "name": "time_reference", + "description": "Time reference documents that locate interactions in time.", + "classes": [ + "time_reference", + "utc_reference", + "event_relative_reference", + "epoch_relative_reference", + "epoch_bounded_reference", + "event_bounded_reference", + "session_relative_reference" + ] + }, + { + "name": "unfiled_vzeta", + "description": "Classes added/renamed in V_zeta not yet hand-placed in the topic tree.", + "classes": [ + "contrast_tuning", + "hartley_reverse_correlation", + "orientation_direction_tuning", + "spatial_frequency_tuning", + "speed_tuning", + "temporal_frequency_tuning", + "valid_interval", + "vmneuralresponseresiduals", + "vmspikefilteringparameters", + "vmspikefit", + "vmspikesummary" + ] + } + ] +} diff --git a/schemas/V_zeta_SPEC.md b/schemas/V_zeta_SPEC.md new file mode 100644 index 0000000..b136cf3 --- /dev/null +++ b/schemas/V_zeta_SPEC.md @@ -0,0 +1,231 @@ +# V_zeta_SPEC.md — DID/NDI Document Schema Format (V_zeta) + +## Purpose + +V_zeta is the next sandbox iteration of the DID/NDI schema set. It implements +**Brainstorm I**, the current direction of the `ndi-next-steps` +"Summer 2026 / 1_Ingestion" design thread (issue #69). Like every prior +sandbox (V_gamma → V_delta → V_epsilon), V_zeta is iterated against real +curation corpora until ready to be promoted to a stable `V1`. + +This document specifies the **differences** from V_delta. For everything not +listed here — the tiered directory layout (`stable/` / `draft/` / +`deprecated/` / `examples/` / `conversions/`), `index.json` as the resolution +source of truth, resolution-by-`class_name`, the `maturity_level` vocabulary, +the `document_class.schema_version` set-version tag, and the field/dependency +object shapes — the V_delta specification (`V_delta_SPEC.md`) remains +authoritative. The meta-schema (`did_schema_meta.json`) is **unchanged**: +every V_zeta class validates against it with no new field types, constraint +keys, or header keys. (The one advisory exception is the `binding` block, +carried inside the open `constraints` object; the meta-schema does not enforce +it.) + +## Relationship to V_epsilon (Brainstorm E) + +**V_zeta supersedes V_epsilon.** V_epsilon implemented Brainstorm **E** +(identity-named observation tiers — a `..._observation` class per measured +*property*). On main, V_epsilon is preserved as an archived reference, and the +merge that landed it records the reason: *"Brainstorm E is superseded by +Brainstorm I."* + +Brainstorm I keeps almost all of V_epsilon's design-neutral machinery — the +infrastructure classes, the manipulation families, the `time_reference` +reference frames, the dataseries/expression bodies, and the scalar/categorical +shape library — and V_zeta reuses those verbatim. What it **rebuilds** is the +observation tier, the spine, and the timing model, per §§1–4 below. V_zeta +therefore begins as a copy of V_epsilon's content with the Brainstorm-I deltas +applied, but its *design lineage* traces to V_delta (`based_on: "V_delta"`); +the E-specific observation classes are removed, not carried. + +--- + +## Source of the redesign + +The anchoring document is +`ndi-next-steps/Summer 2026/1_Ingestion/20260615/Brainstorm_I_Tour_and_Comparison.md` +(with `Brainstorm_I_slides.html`). Brainstorm I is stated there as **"Brainstorm +H plus three field-level changes and two restorations."** Supporting decisions +come from `Observations_Manipulations_overview.md` (the shared skeleton), +`Scalar_Dataseries_Boundary_Decision.md` (#59, the shape test), +`Channel_Model_and_Daqless_Element_Decision.md` (the record/array channel +model), `Temporal_Scope_Proposal.md` (`time_reference`), and the 2026-07-03 +`Locus_Encoding_Paths_Summary.md` / `Choosing_the_Subject_Guide.md` (the locus +fork). Where those proposals leave a choice open, V_zeta resolves it with a +documented default (see §9); the defaults are revisitable while V_zeta is a +sandbox. + +--- + +## Differences from V_delta + +### 1. One spine: `subject_interaction` (rewritten, `stable/`) + +Brainstorm I collapses the observation/manipulation asymmetry to **one shared +skeleton**. Every timed record is a `subject_interaction`, and the whole +identity/where/when payload lives on the spine: + +``` +subject_interaction (abstract, isa base) + subject_id → subject the whole specimen measured or acted on + time_reference_# → time_reference WHEN — a SHAPED reference (§2), one or more, ≥1 + method { node, name } the verb: what was done (measure, inject, heat) [optional] + variable { node, name } the noun: what it is about (temperature, a drug) [required] + target_structure { node, name }[] (optional) the locus on the subject (§3, Path T) +``` + +- **Direction is two empty classes.** `observation` and `manipulation` (and the + carried-over `annotation`) extend `subject_interaction` and **add no fields** — + membership carries direction, and `isa observation` replaces a `direction` + filter. `observation`'s former `measured_property`/`target_structure` fields + are gone (folded into the spine's `variable`/`target_structure`). +- **Identity is off the class.** V_zeta keeps H's `(method, variable)` ontology + pair (settled in Brainstorm I) rather than E's per-property classes or the + proposals' `measured_property`/`applied_action`. `variable` is the queryable + fine identity; correctness of variable-vs-value-shape is a **binding-registry + nudge**, not a class weld — this is the direct answer to E's enumeration + failure (the EPM assay mints ~40 property columns; they all land in one + shape/data-type leaf, with the fine identity on `variable`). +- `subject_statement` (V_epsilon's abstract shared parent) is **removed**; + `subject_interaction` is-a `base` directly. `subject_assertion` (timeless + facts — species/strain/sex/genotype) is re-rooted under `base` and owns its + own `subject_id`. + +### 2. Timing is a SHAPED reference; `sample_time` is retired (§2) + +Brainstorm I removes H's parallel `sample_time` array and carries the timing in +`time_reference`, **whose shape matches the value's shape**. `time_reference` +gains an optional `sampling` structure (discriminator `kind`): + +| data shape | `sampling` | note | +|---|---|---| +| scalar (1) | `{ kind: point }` | one moment at the anchor | +| regular series (N) | `{ kind: grid, sample_rate, n }` | O(1) — never grows with N | +| irregular series (N) | `{ kind: enumerated, offsets[] }` | explicit per-sample offsets | + +The anchoring instant (t0) is supplied by the concrete reference-frame subclass +(`utc_reference.start`, `epoch_relative_reference.t0`, …); the time of sample +*i* is **derived** (`anchor + i/sample_rate` for a grid), never stored beside +the value. Two payoffs the proposal calls out: **same-sample search holds** +(value and time share an index by construction — the false positives of the +independent `[*]` arrays cannot arise), and **regular grids are three numbers, +not N**. `sample_time` is dropped from the `scalar_observation` / +`scalar_manipulation` genera. + +The `time_reference` reference *frames* are unchanged from V_epsilon: +`utc_reference`, `epoch_relative_reference`, `epoch_bounded_reference`, +`event_relative_reference`, `event_bounded_reference`, +`session_relative_reference` (+ `session_extent`). + +### 3. Locus: the `target_structure` field — Path T (§3) + +V_zeta records *which part of a subject* an interaction is about with an +optional `target_structure` ontology term (a list) on the spine; the subject +stays the **whole specimen** (`mouse_042`, not `V1_of_mouse_042`). This is +**Path T** of `Locus_Encoding_Paths_Summary.md`, chosen over Path S +(subject-as-part) as the pragmatic default: it is near the decided model and +needs no standing find-or-create/dedup service under random subject UIDs. The +accepted trade-off is the region/slice wall and no per-locus biography; the +objective annotation rule and the imaging-FOV convention from +`Choosing_the_Subject_Guide.md` govern curation. `target_structure` is a **list** +(bilateral/multi-structure); the multi-structure-image rule is FOV-container + +derived observations. + +### 4. Observation leaves named by DATA-TYPE (shape), not property (§4) + +The core Brainstorm-I change to the observation tier. The shape/data-type is the +class; the property is the `variable` term. + +- **Scalar tier.** `scalar_observation` (abstract, ← `observation`) is a bare + `isa` umbrella. Concrete leaves are named by their **dimensional composite** + and acquire their typed `value` from the shared shape library (a second + superclass): `scalar_mass_observation`, `scalar_length_observation`, + `scalar_duration_observation`, `scalar_volume_observation`, + `scalar_temperature_observation`, `scalar_pressure_observation`, + `scalar_frequency_observation`, `scalar_voltage_observation`, + `scalar_current_observation`, `scalar_concentration_observation`, + `scalar_count_observation`, `scalar_score_observation`, plus the escape hatch + `generic_scalar_observation`. (E's ~20 property leaves — `body_weight_`, + `core_temperature_`, … — are removed; a body-weight reading is now + `scalar_mass_observation` with `variable = {body weight}`.) The **same** shape + class is shared with the manipulation that imposes it + (`scalar_temperature` ← both `scalar_temperature_observation` and + `temperature_manipulation`), so `value` is defined once and + `isa scalar_temperature` sweeps both tiers. +- **Series-as-cardinality (kept, retimed).** Each shape mixin's `value` is an + ARRAY of its composite; a single reading is the length-1 case, a curve is + length N of the *same* class. Per-sample timing is the shaped `time_reference` + (§2), not `sample_time`. +- **Categorical tier.** `categorical_observation` is now a single **concrete** + class (E's abstract genus + per-property leaves + `categorical_concept` + placement machinery are removed): one `ontology_term` `value`, one concept per + document, admissible root a binding nudge keyed on `variable`. +- **Dataseries tier (restored).** `dataseries_observation` (abstract, + ← `observation`; `axes[]` + `channels[]` header) → `timeseries_observation` + (ordering axes → traces) and `imageseries_observation` (≥2 spatial axes → + images/movies). A dataseries observation is a light event-graph handle + (`depends_on element_id → element`) whose native-unit samples live in + `element_epoch`; its payoff is subject-wide discovery in one query + (`isa timeseries_observation` + `subject_id = X`). The record/array channel + model and the newest-wins `dataseries_channel_map` sidecar carry over from the + channel-model decision. `expression_observation` / `spatial_expression_observation` + (omics endpoints) carry over. + +### 5. Manipulation, annotation, and event classes (carried, retargeted) + +The manipulation families are already action/shape-named in H/I and carry over +unchanged except that the spine-owned `target_structure` field is stripped from +those that declared it (it is now inherited): `scalar_manipulation` → +`temperature_manipulation` / `pressure_manipulation` / `frequency_manipulation` +/ `generic_scalar_manipulation`; `procedural_manipulation` → `biological_transfer`; +`environmental_manipulation`; `pharmacological_manipulation` → `injection` / +`bath` (+ `stimulus_bath`); `stimulus_manipulation`. Event-sourced relations +`placement`, `derivation`, `group_assignment`, and the standalone +`interaction_purpose` / `instrument` / re-scoped `stimulus_approach` carry over. + +### 6. Preserved infrastructure + +All non-interaction infrastructure is preserved verbatim from the canonical set: +`base`, `session`/`dataset_*`, `subject` (with `is_biological`/`is_group` +facets), `element`/`element_epoch`/`epoch*`, `daqsystem`/`daqreader*`, +`probe_location`/`probe_geometry`/`site2channelmap`, the `stimulus_*` family and +tuning/response calculators, `openminds*`, `ontology_*`, `zarr`/`image*`, etc. + +### 7. Deprecations + +`treatment`, `treatment_drug`, `treatment_transfer`, `virus_injection`, and +`subject_group` remain in `deprecated/` (replaced as in V_epsilon: +treatment-family → the manipulation tiers; `virus_injection`/`treatment_drug` → +`injection`; `treatment_transfer` → `biological_transfer`; `subject_group` → +`subject(is_group)` + `group_assignment`). Conversion notes are in +`conversions/`. + +### 8. Carryover cleanup + +`hartley_calc`'s `file` record (a long-standing defect copied through V_delta → +V_epsilon: field-definition keys on a file record) is stripped to `name` + +`documentation` so the whole V_zeta set passes meta-validation (v2.0.0). + +--- + +## 9. Resolved open questions + +| # | question (source) | V_zeta default | +|---|---|---| +| 1 | Locus encoding — Path S vs Path T (#69) | **Path T** — `target_structure` field; subject is the whole specimen. | +| 2 | `target` vs `target_structure` | **`target_structure`** (Brainstorm I recommendation; corpus's existing name; a list). | +| 3 | identity field names | **`method` / `variable`** (settled in Brainstorm I). | +| 4 | observation identity placement | **off-class** — shape/data-type is the class, property on `variable` (the EPM lesson). | +| 5 | in-document series timing | **shaped `time_reference`** (`sampling`: point/grid/enumerated); `sample_time` retired. | +| 6 | scalar vs dataseries boundary (#59) | **one axis test** — sampled metric axis ⇒ dataseries; else scalar (composite) or categorical; no third class. | +| 7 | `method` requiredness on observations | **optional** at the schema level (verb ≈ "measurement"); `variable` required. | + +Counts: **202 document classes** (156 `stable`, 40 `draft`, 6 `deprecated`) + +3 meta files. + +## Promotion to V1 + +Same procedure as V_delta: copy `schemas/V_zeta/` to `schemas/V1/`, freeze it, +replace the `"V_zeta"` value in `schema_version`/`index.json`, and tag. Before +promotion the `draft/` families (the genomics/omics + file-backed dataseries +data-format classes) are expected to be exercised against real corpora and +re-tiered to `stable/`. diff --git a/schemas/V_zeta_notes.md b/schemas/V_zeta_notes.md new file mode 100644 index 0000000..8672b8f --- /dev/null +++ b/schemas/V_zeta_notes.md @@ -0,0 +1,126 @@ +# V_zeta schemas + +The `V_zeta/` directory is the working set-version directory for the sandbox +iteration that implements **Brainstorm I**. Like V_epsilon before it, V_zeta is +a sandbox: contents are expected to change in place, and consumers should not +pin to V_zeta as a stable target. The set will be copied to `schemas/V1/` and +frozen when ready (see `V_zeta_SPEC.md` § "Promotion to V1"). + +This notes file tracks V_zeta's status, the decisions taken where the source +proposals were open, and the open follow-ups. + +## What V_zeta changes versus V_epsilon + +V_epsilon implemented Brainstorm **E** (an observation class per measured +*property*). The merge that landed V_epsilon on main records that **Brainstorm E +is superseded by Brainstorm I**; V_epsilon is kept as an archived reference. +V_zeta is the Brainstorm-I implementation. + +Brainstorm I is *"Brainstorm H plus three field-level changes and two +restorations."* Concretely, versus V_epsilon: + +1. **One spine.** The whole identity/where/when payload moves onto + `subject_interaction` (← `base`): `subject_id`, `time_reference_#`, `method`, + `variable`, `target_structure`. `observation` / `manipulation` / `annotation` + become empty direction markers. `subject_statement` is removed; + `subject_assertion` is re-rooted under `base`. +2. **Off-class identity.** The observation tier is named by **data-type + (shape)**, not property: 12 dimensional `scalar__observation` leaves + + `generic_scalar_observation` replace E's ~20 property leaves, and + `categorical_observation` collapses to one concrete class. The property rides + on the `variable` term. This is the direct answer to E's enumeration failure + (the EPM dilemma). +3. **Shaped time.** `time_reference` gains a `sampling` structure + (point/grid/enumerated); `sample_time` is retired from the scalar genera. +4. **Path T locus.** `target_structure` is restored as a spine field. +5. **Dataseries branch** (`dataseries_observation` → `timeseries_` / + `imageseries_observation`) is retained from the E draft as the observation-tier + handle for acquired data. + +The manipulation families, `time_reference` reference frames, dataseries/ +expression bodies, the scalar/categorical shape library, all infrastructure, and +the five deprecated classes carry over from V_epsilon (design-neutral for I). + +## Initial state + +- V_zeta content began as a verbatim copy of V_epsilon, then the Brainstorm-I + transform (above) was applied. +- **202 document classes**: 156 `stable`, 40 `draft`, 6 `deprecated`, + 3 meta. + `index.json` `set_version`/`schema_version_value` = `"V_zeta"`; `based_on` = + `"V_delta"`; `legacy_schema_version_values` = `["did_v1", "V_delta"]`. +- 23 Brainstorm-E classes removed (the property-named observation leaves, + `categorical_concept`, `subject_statement`); 13 shape-typed scalar observation + leaves authored; `categorical_observation` made concrete; `time_reference` + `sampling` added; spine rewritten; `target_structure` / `sample_time` / + `expression.method` stripped where they duplicated the spine. +- Every schema validates against `did_schema_meta.json`; `index.json` agrees + with disk (tier/maturity/path); every superclass and `must_refer_to_document_class` + resolves; the spine composes onto every interaction leaf; no + `placement:concrete_class` collisions. Enforced by `tests/test_vzeta.py` + (411 parametrized cases) and validated by the full suite (515 tests pass). + +## Decisions taken where the source proposals were open + +Brainstorm I is explicitly provisional and leaves several load-bearing choices +open. V_zeta resolves each with a documented default (see `V_zeta_SPEC.md` §9), +confirmed with the maintainer for the two spine-shaping forks: + +- **Locus: Path T (`target_structure` field), not Path S (subject-as-part).** + Confirmed. Near the decided model; no standing find-or-create/dedup service + required under random subject UIDs. Trade-off accepted: the region/slice wall + and no per-locus biography. +- **Scope: the full coverage set** — spine + shaped time + scalar/categorical/ + dataseries observation leaves + manipulation families + preserved + infrastructure + deprecations, sufficient to express every existing V_delta + document. Confirmed. +- **Identity: keep `method` / `variable`** (settled in Brainstorm I), off-class, + with a soft binding-registry nudge rather than a class weld. +- **`method` optional at the schema level** (the verb is nearly always + "measurement" on the observation tier); `variable` required. +- **`annotation` kept as a third direction** for curatorial/relational events + (`group_assignment`). Brainstorm I foregrounds observation/manipulation + symmetry but does not preclude it; it is carried from V_epsilon. + +## Provisional / still open (from Brainstorm I) + +These are flagged open in `Brainstorm_I_Tour_and_Comparison.md` §1.7 and are +revisitable while V_zeta is a sandbox: + +- **The subject-vs-target rule** (the ex-vivo case) and single-vs-nested + `target_structure` multiplicity. V_zeta uses a list; the multi-structure-image + rule (FOV container + derived observations) is a curation convention, not a + schema constraint. +- **The in-document (scalar/small series) vs `element_epoch` boundary**, and the + document-size cap that enforces it. The scalar/dataseries axis test (#59) + decides the *class*; the size cap that routes a small vs large series is a + tooling policy, not encoded here. +- **The axis split** — time in `time_reference.sampling` vs all axes in the + dataseries header. V_zeta puts the time axis in `sampling` and the spatial/ + other axes + channel model in the dataseries header (I's provisional + reconciliation). +- **`stimulus_approach` v2 write-time invariants** — documented in the proposal, + enforced by tooling, not the schema. + +## Not implemented in this pass (open follow-ups, separate PRs) + +- **Binding registry as a meta-file.** V_zeta carries `binding` blocks inline + (advisory, in `constraints`) on `variable`-keyed / `categorical_observation.value` + fields; the registry meta-file + `value_set` class are not added. +- **`dataSeriesType` registry** (a `probetype2object`-style type→template) and + per-element channel-identity materialization — registry/tooling artifacts. +- **Conversion docs.** The `conversions/` tree carries over from V_epsilon + (treatment split, `virus_injection`/`treatment_drug` → `injection`, + `treatment_transfer` → `biological_transfer`, `subject_group` folds). A + `from_v_epsilon/` (or `from_v_delta/`) path documenting the E→I observation-tier + remap (property leaf → shape leaf + `variable`; `measured_property` → `variable`; + `sample_time` → `sampling`) should be added. +- **NDI-matlab / DID-matlab consumer tooling** — resolve V_zeta via `index.json`; + emit the shaped `time_reference`; write the record/array channel model + + `dataseries_channel_map`; the E→I observation migrator. + +## Carried-over cleanup + +`hartley_calc`'s malformed `file` record (field-definition keys on a file +record, present identically in V_delta and V_epsilon) is fixed in V_zeta +(stripped to `name` + `documentation`, v2.0.0), so the whole set passes +meta-validation with no carryover defect. diff --git a/tests/test_vzeta.py b/tests/test_vzeta.py new file mode 100644 index 0000000..8dacece --- /dev/null +++ b/tests/test_vzeta.py @@ -0,0 +1,153 @@ +"""V_zeta (Brainstorm I) schema-set integrity tests. + +V_zeta is not in conftest's SCHEMA_VERSIONS parametrization (that covers the +V_beta / V_gamma wire-shape matrix). These tests validate the V_zeta set on +its own terms: every schema file passes the meta-schema, index.json agrees +with disk, superclass and dependency references resolve, tier folder matches +maturity_level, and the Brainstorm-I spine composes onto its leaves. +""" +import glob +import json +import os + +import jsonschema +import pytest + +REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +VZETA = os.path.join(REPO_ROOT, "schemas", "V_zeta") +TIERS = ["stable", "draft", "deprecated"] +META_FILES = {"did_schema_meta.json", "CURIE_lookups_meta.json", "ndi_reserved_keys.json"} + + +def _load(path): + with open(path) as f: + return json.load(f) + + +META = _load(os.path.join(VZETA, "stable", "did_schema_meta.json")) +INDEX = _load(os.path.join(VZETA, "index.json")) + + +def _doc_files(): + out = [] + for tier in TIERS: + for p in sorted(glob.glob(os.path.join(VZETA, tier, "*.json"))): + if os.path.basename(p) not in META_FILES: + out.append((tier, p)) + return out + + +def _records(): + recs = {} + for tier, p in _doc_files(): + d = _load(p) + recs[d["document_class"]["class_name"]] = (tier, d) + return recs + + +DOC_FILES = _doc_files() +RECORDS = _records() + + +@pytest.mark.parametrize("tier,path", DOC_FILES, ids=[os.path.basename(p) for _, p in DOC_FILES]) +def test_file_passes_meta_schema(tier, path): + jsonschema.validate(instance=_load(path), schema=META) + + +@pytest.mark.parametrize("tier,path", DOC_FILES, ids=[os.path.basename(p) for _, p in DOC_FILES]) +def test_filename_matches_class_and_tier(tier, path): + d = _load(path) + dc = d["document_class"] + assert dc["class_name"] + ".json" == os.path.basename(path) + assert dc["maturity_level"] == tier, f"{dc['class_name']} maturity != {tier}/ folder" + + +def test_index_agrees_with_disk(): + on_disk = set(RECORDS) | {f[:-5] for f in META_FILES} + in_index = {e["class_name"] for e in INDEX["schemas"]} + assert on_disk == in_index, f"index/disk drift: {on_disk ^ in_index}" + assert INDEX["set_version"] == "V_zeta" + + +def test_superclasses_resolve(): + names = set(RECORDS) + for name, (_, d) in RECORDS.items(): + for s in d["document_class"]["superclasses"]: + assert s["class_name"] in names, f"{name} -> missing superclass {s['class_name']}" + + +def test_dependencies_resolve(): + names = set(RECORDS) + for name, (_, d) in RECORDS.items(): + for dep in d.get("depends_on", []): + for tok in [t for t in dep["must_refer_to_document_class"].split(",") if t]: + assert tok in names, f"{name}.{dep['name']} -> missing class {tok}" + + +def _chain(name): + out = [name] + for s in RECORDS[name][1]["document_class"]["superclasses"]: + out += _chain(s["class_name"]) + return out + + +def _flat_field_types(name): + types = {} + for c in reversed(_chain(name)): + for f in RECORDS[c][1].get("fields", []): + types[f["name"]] = f["type"] + return types + + +def _flat_dep_names(name): + deps = set() + for c in _chain(name): + for dep in RECORDS[c][1].get("depends_on", []): + deps.add(dep["name"]) + return deps + + +def test_spine_composes_onto_every_interaction(): + """Every subject_interaction leaf inherits the Brainstorm-I skeleton.""" + for name in RECORDS: + if "subject_interaction" not in _chain(name): + continue + ft = _flat_field_types(name) + deps = _flat_dep_names(name) + assert "subject_id" in deps, f"{name} missing subject_id" + assert "time_reference_#" in deps, f"{name} missing time_reference" + assert ft.get("method") == "ontology_term", f"{name} missing spine method" + assert ft.get("variable") == "ontology_term", f"{name} missing spine variable" + assert ft.get("target_structure") == "ontology_term", f"{name} missing target_structure" + + +def test_shape_typed_scalar_leaves_present(): + """Brainstorm I names observation leaves by data-type (shape), not property.""" + for dim, vtype in { + "mass": "mass", "length": "length", "duration": "duration", + "volume": "volume", "temperature": "temperature", "pressure": "pressure", + "frequency": "frequency", "voltage": "voltage", "current": "current", + "concentration": "concentration", "count": "count", "score": "score", + }.items(): + leaf = f"scalar_{dim}_observation" + assert leaf in RECORDS, f"missing {leaf}" + assert _flat_field_types(leaf).get("value") == vtype + assert "observation" in _chain(leaf) + + +def test_no_brainstorm_e_property_leaves(): + """The E property-named observation tier is gone (superseded by I).""" + for gone in ["body_weight_observation", "core_temperature_observation", + "developmental_stage_observation", "categorical_concept", + "subject_statement"]: + assert gone not in RECORDS, f"{gone} should not exist in V_zeta" + + +def test_sample_time_retired(): + """Series timing lives in the shaped time_reference, not a sample_time array.""" + for name in ["scalar_observation", "scalar_manipulation"]: + ft = _flat_field_types(name) + assert "sample_time" not in ft, f"{name} still declares sample_time" + tr = RECORDS["time_reference"][1] + sampling = [f for f in tr["fields"] if f["name"] == "sampling"] + assert sampling and sampling[0]["type"] == "structure" From 83829a6f136fb4efd24e9d07cd37e98759416dbc Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 13:12:31 +0000 Subject: [PATCH 2/6] V_zeta: retarget from_did_v1 conversions to Brainstorm I; did_v1 is the only production source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The production document set is did_v1 (our first version); V_alpha..V_epsilon were sandbox iterations that never shipped, so conversions/from_did_v1/ is the sole conversion tree and there is nothing to migrate from the intermediate sandboxes. - index.json: legacy_schema_version_values -> ["did_v1"] (was ["did_v1", "V_delta"]); notes clarify did_v1 is the only production/legacy version. - Retarget the whole from_did_v1 tree from V_epsilon (Brainstorm E) to V_zeta (Brainstorm I): version labels, schema paths (families are stable/ in V_zeta), and the target model in prose. - treatment.md: fix the schema-level bug — thermal identity mapped to the retired scalar_manipulation.applied_property; in the I model identity is the spine `variable` and the verb is the spine `method`. Reworked the worked example accordingly (identity/verb/target_structure on the subject_interaction block; value as a typed array; scalar_manipulation carries only `notes`). - ontology_table_row.md (previous commit) already rewritten for the shape-typed observation tier; _index.md and the format/template docs (_universal_renames, _files, _TEMPLATE) retargeted to V_zeta, preserving the true V_alpha/beta/gamma format lineage. - V_zeta_notes.md: correct the conversion follow-up (no from_v_epsilon path; from_did_v1 only) and the legacy-value note. 515 tests pass; full set still validates against the meta-schema. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015zjbvyLbSLMYz1uCizYwQh --- .../conversions/from_did_v1/_TEMPLATE.md | 26 +++---- .../V_zeta/conversions/from_did_v1/_files.md | 20 +++--- .../V_zeta/conversions/from_did_v1/_index.md | 31 ++++---- .../from_did_v1/_universal_renames.md | 70 +++++++++---------- .../from_did_v1/contrast_sensitivity_calc.md | 18 ++--- .../from_did_v1/contrast_tuning.md | 28 ++++---- .../from_did_v1/contrast_tuning_calc.md | 18 ++--- .../conversions/from_did_v1/hartley_calc.md | 18 ++--- .../hartley_reverse_correlation.md | 16 ++--- .../conversions/from_did_v1/ontology_image.md | 32 ++++----- .../conversions/from_did_v1/ontology_label.md | 34 ++++----- .../from_did_v1/oridirtuning_calc.md | 30 ++++---- .../orientation_direction_tuning.md | 28 ++++---- .../conversions/from_did_v1/probe_location.md | 32 ++++----- .../from_did_v1/reverse_correlation.md | 16 ++--- .../from_did_v1/spatial_frequency_tuning.md | 20 +++--- .../spatial_frequency_tuning_calc.md | 16 ++--- .../conversions/from_did_v1/speed_tuning.md | 22 +++--- .../from_did_v1/speed_tuning_calc.md | 16 ++--- .../conversions/from_did_v1/subject_group.md | 12 ++-- .../from_did_v1/temporal_frequency_tuning.md | 20 +++--- .../temporal_frequency_tuning_calc.md | 16 ++--- .../conversions/from_did_v1/treatment.md | 64 +++++++++-------- .../conversions/from_did_v1/treatment_drug.md | 10 +-- .../from_did_v1/treatment_transfer.md | 10 +-- .../from_did_v1/virus_injection.md | 10 +-- schemas/V_zeta_notes.md | 23 ++++-- 27 files changed, 334 insertions(+), 322 deletions(-) diff --git a/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md b/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md index 82bd776..01cc50c 100644 --- a/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md +++ b/schemas/V_zeta/conversions/from_did_v1/_TEMPLATE.md @@ -1,15 +1,15 @@ -# Conversion: did_v1 → V_delta — `` +# Conversion: did_v1 → V_zeta — `` -> Copy this file to `.md` (one file per V_delta document type that +> Copy this file to `.md` (one file per V_zeta document type that > has a `did_v1` analog) and fill in every section. Sections that genuinely do > not apply should be retained with the text `N/A` so reviewers can see they > were considered, not skipped. ## Identity -- **V_delta `class_name`:** `` -- **V_delta tier:** `stable` | `draft` | `deprecated` -- **V_delta schema path:** `schemas/V_delta//.json` +- **V_zeta `class_name`:** `` +- **V_zeta tier:** `stable` | `draft` | `deprecated` +- **V_zeta schema path:** `schemas/V_zeta//.json` - **did_v1 source:** repo + path (or "synthesized from MATLAB class `<...>`") - **Status:** `drafted` | `reviewed` | `applied-in-tooling` | `frozen` @@ -17,16 +17,16 @@ ## Summary One or two sentences. What is this document type, and what is the -high-level shape of the change between did_v1 and V_delta? If there is no +high-level shape of the change between did_v1 and V_zeta? If there is no change, say so. ## Field mapping Use one row per field. Cover every field in both the did_v1 source and the -V_delta target — including dropped fields (V_delta column blank) and new +V_zeta target — including dropped fields (V_zeta column blank) and new fields (did_v1 column blank). -| did_v1 field | V_delta field | Transformation | Notes | +| did_v1 field | V_zeta field | Transformation | Notes | |---|---|---|---| | `` | `` | rename | | | `` | `` | type change: `` → `` | Validation rules below | @@ -43,13 +43,13 @@ author. Cite the relevant spec section if applicable. ## Default values for new fields -If V_delta introduces required fields that did_v1 documents do not carry, +If V_zeta introduces required fields that did_v1 documents do not carry, list the default each migrated document gets, and the reasoning. Distinguish between "constant default" and "computed from other fields." ## Worked example -A minimal but realistic did_v1 document and the V_delta document it converts +A minimal but realistic did_v1 document and the V_zeta document it converts to. These pairs double as unit-test fixtures — keep them small enough to read by eye. @@ -62,11 +62,11 @@ read by eye. } ``` -### After (V_delta) +### After (V_zeta) ```json { - "document_class": { "class_name": "", "class_version": "...", "schema_version": "V_delta", ... }, + "document_class": { "class_name": "", "class_version": "...", "schema_version": "V_zeta", ... }, ... } ``` @@ -88,5 +88,5 @@ re-read this whole doc. - Related document types whose conversions interact with this one: - did_v1 source-of-truth path(s): -- V_delta schema file: +- V_zeta schema file: - General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/_files.md b/schemas/V_zeta/conversions/from_did_v1/_files.md index 50817af..be530e5 100644 --- a/schemas/V_zeta/conversions/from_did_v1/_files.md +++ b/schemas/V_zeta/conversions/from_did_v1/_files.md @@ -1,7 +1,7 @@ -# File handling: did_v1 → V_delta +# File handling: did_v1 → V_zeta > This is the **generalized** file-handling specification for the -> did_v1 → V_delta migration. Per-document-type conversion docs should +> did_v1 → V_zeta migration. Per-document-type conversion docs should > link here for anything that follows these generic rules, and only > document type-specific behavior locally. @@ -24,10 +24,10 @@ TODO: describe how did_v1 documents reference files today — field names, path formats (absolute? relative? hash-addressed?), whether integrity is verified, and what container/database layout assumptions exist. -## V_delta file-reference shape +## V_zeta file-reference shape -TODO: describe the target file-reference shape under V_delta. Anchor -choices in `V_delta_SPEC.md` once finalized. +TODO: describe the target file-reference shape under V_zeta. Anchor +choices in `V_zeta_SPEC.md` once finalized. ## Migration rules @@ -35,13 +35,13 @@ For each migration scenario, specify the rule. Stubs follow. ### Path rewriting -TODO: when did_v1 paths are absolute and the V_delta layout requires +TODO: when did_v1 paths are absolute and the V_zeta layout requires relative or hash-addressed paths, how are old paths translated? What happens if the original file is no longer on disk? ### Integrity verification -TODO: does V_delta require a hash on file references? If so, how is it +TODO: does V_zeta require a hash on file references? If so, how is it computed during migration, and what happens on hash mismatch (fail, warn, or annotate)? @@ -54,12 +54,12 @@ for each. ### Large file handling TODO: any size-based branching (e.g., inline vs. external) at the -V_delta layer. +V_zeta layer. ### Container/database boundaries TODO: when a document is migrated across databases (or out of one and -into a fresh V_delta container), how are file references rewritten? +into a fresh V_zeta container), how are file references rewritten? ## Open questions @@ -68,4 +68,4 @@ into a fresh V_delta container), how are file references rewritten? - Should the migration engine ever copy file content, or only update references? - What is the policy for files referenced by both a did_v1 document and - a V_delta document during a transitional period? + a V_zeta document during a transitional period? diff --git a/schemas/V_zeta/conversions/from_did_v1/_index.md b/schemas/V_zeta/conversions/from_did_v1/_index.md index 88f3160..a56a1b3 100644 --- a/schemas/V_zeta/conversions/from_did_v1/_index.md +++ b/schemas/V_zeta/conversions/from_did_v1/_index.md @@ -1,12 +1,12 @@ -# did_v1 → V_delta conversion index +# did_v1 → V_zeta conversion index -This file enumerates every V_delta document type that needs a conversion +This file enumerates every V_zeta document type that needs a conversion doc from `did_v1`, and tracks its status. Update this index whenever a new conversion doc is added or its status changes. The corresponding template is [`_TEMPLATE.md`](_TEMPLATE.md). The shared file-handling rules are in [`_files.md`](_files.md). Cross-cutting renames -that apply to **every** did_v1 → V_delta migration (underscore-prefix +that apply to **every** did_v1 → V_zeta migration (underscore-prefix removal, snake_case, ontology-annotation reshape, superclass-reference reshape, class-scoped property blocks, maturity-level enum) are in [`_universal_renames.md`](_universal_renames.md). Per-class markdowns @@ -21,13 +21,13 @@ field-level changes on top. - **applied-in-tooling** — implemented in the migration engine in `DID-matlab`, but not yet locked - **frozen** — implemented, tested against real datasets, locked for - V_delta + V_zeta - **no-conversion-needed** — explicitly marked as having no did_v1 predecessor ## Conversions -| V_delta class_name | did_v1 source | Status | Doc | +| V_zeta class_name | did_v1 source | Status | Doc | |---|---|---|---| | `contrast_tuning` | NDIcalc-vis-matlab `vision/contrast_tuning` | drafted | [contrast_tuning.md](contrast_tuning.md) | | `contrast_tuning_calc` | NDIcalc-vis-matlab `calc/contrasttuning_calc` (renamed) | drafted | [contrast_tuning_calc.md](contrast_tuning_calc.md) | @@ -44,21 +44,20 @@ field-level changes on top. | `hartley_reverse_correlation` | NDIcalc-vis-matlab `neuro/hartley_reverse_correlation` | drafted | [hartley_reverse_correlation.md](hartley_reverse_correlation.md) | | `hartley_calc` | NDIcalc-vis-matlab `calc/hartley_calc` | drafted | [hartley_calc.md](hartley_calc.md) | | `probe_location` | legacy NDI/DID `probe_location` (V_alpha shape) | drafted | [probe_location.md](probe_location.md) | -| `treatment` | legacy NDI/DID `treatment` (V_alpha shape) | drafted | [treatment.md](treatment.md) | -| `treatment` → manipulation tiers (Brainstorm E **split**) | legacy `treatment` → `injection`/`bath`/`procedural_manipulation`/`temperature_manipulation`/`environmental_manipulation` (+ out-of-tier) | drafted | [treatment.md](treatment.md) | -| `ontology_table_row` → observation tiers (Brainstorm E **split**, 1→N) | legacy `ontology_table_row` → scalar/categorical observation property classes (+ out-of-tier) | drafted | [ontology_table_row.md](ontology_table_row.md) | -| `subject_group` → `subject` (`is_group`) (Brainstorm E **fold**) | legacy `subject_group` → `subject` flagged `is_group` (+ `group_assignment` in NDI layer) | drafted | [subject_group.md](subject_group.md) | -| `treatment_drug` → `injection` (`kind: drug`) (Brainstorm E **fold**) | legacy `treatment_drug` → `injection` (mixture from `mixture_table`) | drafted | [treatment_drug.md](treatment_drug.md) | -| `virus_injection` → `injection` (`kind: virus`) (Brainstorm E **fold**) | legacy `virus_injection` → `injection` (virus+dilution in mixture) | drafted | [virus_injection.md](virus_injection.md) | -| `treatment_transfer` → `biological_transfer` (Brainstorm E **fold**) | legacy `treatment_transfer` → `biological_transfer` (recipient→subject, donor carried) | drafted | [treatment_transfer.md](treatment_transfer.md) | +| `treatment` → manipulation tiers (Brainstorm I **split**) | legacy `treatment` → `injection`/`bath`/`procedural_manipulation`/`temperature_manipulation`/`environmental_manipulation` (+ out-of-tier) | drafted | [treatment.md](treatment.md) | +| `ontology_table_row` → observation tiers (Brainstorm I **split**, 1→N) | legacy `ontology_table_row` → shape-typed scalar/categorical observation classes (+ out-of-tier) | drafted | [ontology_table_row.md](ontology_table_row.md) | +| `subject_group` → `subject` (`is_group`) (Brainstorm I **fold**) | legacy `subject_group` → `subject` flagged `is_group` (+ `group_assignment` in NDI layer) | drafted | [subject_group.md](subject_group.md) | +| `treatment_drug` → `injection` (`kind: drug`) (Brainstorm I **fold**) | legacy `treatment_drug` → `injection` (mixture from `mixture_table`) | drafted | [treatment_drug.md](treatment_drug.md) | +| `virus_injection` → `injection` (`kind: virus`) (Brainstorm I **fold**) | legacy `virus_injection` → `injection` (virus+dilution in mixture) | drafted | [virus_injection.md](virus_injection.md) | +| `treatment_transfer` → `biological_transfer` (Brainstorm I **fold**) | legacy `treatment_transfer` → `biological_transfer` (recipient→subject, donor carried) | drafted | [treatment_transfer.md](treatment_transfer.md) | | `ontology_image` | legacy NDI/DID `ontologyImage` (V_alpha shape) | drafted | [ontology_image.md](ontology_image.md) | | `ontology_label` | legacy NDI/DID `ontologyLabel` (V_alpha shape) | drafted | [ontology_label.md](ontology_label.md) | ## Notes - **Not migrated:** `stimloopsplitter_calc` (deprecated per domain owner - decision; not added to V_delta). -- **Already in V_delta from earlier set versions** (no `did_v1` conversion + decision; not added to V_zeta). +- **Already in V_zeta from earlier set versions** (no `did_v1` conversion added in this PR): `tuningcurve_calc`, `stimulus_tuningcurve`, `ngrid`. These have no NDIcalc-vis-matlab v1 predecessor in `ndi_common/`; if any need a separate `did_v1` source resurrected later, add their conversions @@ -66,10 +65,10 @@ field-level changes on top. ## Conventions -- One conversion markdown per V_delta document type. If a V_delta class +- One conversion markdown per V_zeta document type. If a V_zeta class has multiple did_v1 sources, document the merge in a single file rather than splitting. -- If a V_delta class is genuinely new (no did_v1 ancestor), create +- If a V_zeta class is genuinely new (no did_v1 ancestor), create `_no_conversion_needed.md` with a one-line reason and add the row with status `no-conversion-needed`. - File-handling behavior that follows the generic rules in `_files.md` diff --git a/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md b/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md index c3bed00..f5ae4a8 100644 --- a/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md +++ b/schemas/V_zeta/conversions/from_did_v1/_universal_renames.md @@ -1,7 +1,7 @@ -# Universal renames: did_v1 → V_delta +# Universal renames: did_v1 → V_zeta > These transformations apply to **every** did_v1 document and to -> **every** schema file as it is migrated to V_delta. Per-class +> **every** schema file as it is migrated to V_zeta. Per-class > conversion markdowns (under `conversions/from_did_v1/.md`) > assume these renames have been applied and document only the > per-class field-level changes on top. @@ -9,7 +9,7 @@ > `_files.md` is a sibling document covering generic file-reference > handling, which is a separate concern from these renames. -For each rule below the arrow direction is `did_v1 → V_delta`. +For each rule below the arrow direction is `did_v1 → V_zeta`. ## 1. Underscore-prefix structural keys are unprefixed @@ -22,10 +22,10 @@ structural key with a leading underscore: `_classname`, `_constraints`. The leading underscore was a sigil to distinguish DID structural keys from user payload. -V_gamma dropped the sigil from every structural key and V_delta +V_gamma dropped the sigil from every structural key and V_zeta inherits that convention. The rename is mechanical: -| did_v1 (V_alpha) key | V_delta key | +| did_v1 (V_alpha) key | V_zeta key | |---|---| | `_classname` | `class_name` *(also moved under `document_class`; see §3)* | | `_class_version` | `class_version` *(also moved under `document_class`; see §3)* | @@ -59,7 +59,7 @@ the class-identity keys into a nested `document_class` block. The full rewrite is: ```text -did_v1 V_delta +did_v1 V_zeta ------ ------- "_classname": "x" → "document_class": { "_class_version": "1.0.0" → "class_name": "x", @@ -84,7 +84,7 @@ require all class names, field names, and filenames to match `^[a-z][a-z0-9_]*$`. The per-class conversion markdowns list any identifier renames they trigger. Common cases inherited from V_beta: -| did_v1 identifier | V_delta identifier | +| did_v1 identifier | V_zeta identifier | |---|---| | `ontologyImage` (class) | `ontology_image` | | `ontologyLabel` (class) | `ontology_label` | @@ -120,14 +120,14 @@ key was a `$NDISCHEMAPATH`-prefixed path string: V_gamma renamed the keys (§1) and dropped the `$NDISCHEMAPATH` prefix convention while still permitting an explicit `schema` path key. -V_delta removes the `schema` key entirely: a superclass reference in a +V_zeta removes the `schema` key entirely: a superclass reference in a **schema file** is `{"class_name": ""}` only. The validator resolves the superclass by `class_name` through -`schemas/V_delta/index.json`. The meta-schema enforces this via +`schemas/V_zeta/index.json`. The meta-schema enforces this via `additionalProperties: false` on superclass references. ```text -did_v1 V_delta +did_v1 V_zeta { "_classname": "base", { "class_name": "base" } "_schema": "$NDISCHEMAPATH/base/schema.json" } ``` @@ -135,25 +135,25 @@ did_v1 V_delta In **document instances**, the superclass-reference key set is different — `class_name` plus `class_version` (a pinned snapshot of the inheritance chain). That convention was set in V_gamma and is -unchanged in V_delta. See `V_gamma_SPEC.md` § "Schema-reference forms". +unchanged in V_zeta. See `V_gamma_SPEC.md` § "Schema-reference forms". ## 5. `maturity_level` enum is `{stable, draft, deprecated}` V_alpha allowed `_maturity_level ∈ {"work_in_progress", "mature"}`. -V_delta replaces the vocabulary with `{stable, draft, deprecated}` +V_zeta replaces the vocabulary with `{stable, draft, deprecated}` and additionally requires that the value match the tier-folder a -schema file lives in (`schemas/V_delta//`). +schema file lives in (`schemas/V_zeta//`). Migration mapping for did_v1 documents and schemas carried into -V_delta: +V_zeta: -| did_v1 `_maturity_level` | V_delta `maturity_level` | +| did_v1 `_maturity_level` | V_zeta `maturity_level` | |---|---| | `"mature"` | `"stable"` | | `"work_in_progress"` | `"stable"` *(default placement; a separate domain-review pass may re-tier specific schemas to `draft` or `deprecated`)* | -The meta-schema (`did_schema_meta.json`) enforces the V_delta enum. -See `V_delta_SPEC.md` § 3. +The meta-schema (`did_schema_meta.json`) enforces the V_zeta enum. +See `V_zeta_SPEC.md` § 3. ## 6. Ontology annotation reshape (4-key → 2-key) @@ -177,7 +177,7 @@ V_gamma collapsed this to a two-key CURIE-based shape: } ``` -V_delta inherits the V_gamma shape. The rewrite rule is: +V_zeta inherits the V_gamma shape. The rewrite rule is: node = ":<_term>" name = <_name> @@ -193,7 +193,7 @@ describes the *field*, not the documents validated against the field ## 7. Class-scoped property blocks (document instances) -V_gamma re-established and V_delta inherits the **class-scoped +V_gamma re-established and V_zeta inherits the **class-scoped property block** wire shape for document instances. A document is structured as: @@ -215,7 +215,7 @@ block `{}`. V_alpha already used class-scoped blocks (with a separate `property_listname` knob); V_gamma collapsed that down so the block -key is the `class_name` verbatim. V_delta keeps the V_gamma form. +key is the `class_name` verbatim. V_zeta keeps the V_gamma form. Migration consequences: @@ -235,16 +235,16 @@ Migration consequences: See `V_gamma_SPEC.md` § "JSON Format: Document Instances" for the authoritative description. -## 8. `class_version` semantics under V_delta sandbox +## 8. `class_version` semantics under V_zeta sandbox -V_delta is a sandbox set version (like V_gamma was); `class_version` +V_zeta is a sandbox set version (like V_gamma was); `class_version` bumps are deferred until the V1 freeze. Schemas in -`schemas/V_delta/stable/` whose document shape differs from did_v1 +`schemas/V_zeta/stable/` whose document shape differs from did_v1 nonetheless declare `class_version: "1.0.0"`. The non-triviality of the migration for those classes is captured in this directory (one markdown per class) rather than in a version flag. -This rule is purely V_delta-side bookkeeping; it imposes no +This rule is purely V_zeta-side bookkeeping; it imposes no transformation on the did_v1 document being migrated. ## 9. `depends_on(k).id` → `depends_on(k).document_id` @@ -260,8 +260,8 @@ two-key (sometimes three-key) entries: ``` After rule §1 strips the underscore prefix the keys are `name`, `id`, -and optionally `version`. V_delta renames `id` → `document_id` and -drops `version` entirely. The result on every V_delta document +and optionally `version`. V_zeta renames `id` → `document_id` and +drops `version` entirely. The result on every V_zeta document instance is: ```json @@ -272,18 +272,18 @@ instance is: ``` The rename motivation: `id` collided with the top-level -`base.id` field for the documents themselves; the earlier V_delta +`base.id` field for the documents themselves; the earlier V_zeta draft used `value`, which avoided the collision but was uninformative ("a value of what?"). `document_id` says exactly what the field is — a `did_uid` referring to another document — and the explicit `document_` prefix disambiguates from any future id-shaped fields the schema may add. -`version` is dropped because V_delta does not support per-document +`version` is dropped because V_zeta does not support per-document version branches; cross-document references resolve to whichever version of the target document is current in the database. -| did_v1 entry key | V_delta entry key | +| did_v1 entry key | V_zeta entry key | |---|---| | `id` | `document_id` | | `version` | _(dropped)_ | @@ -291,16 +291,16 @@ version of the target document is current in the database. The universal-rename pass in `did2.convert.universalRenames` (`renameDependsOnEntries`) implements this rule. It also tolerates -the earlier V_delta-draft key `value` as a synonym for `id` so +the earlier V_zeta-draft key `value` as a synonym for `id` so already-migrated corpora convert forward to `document_id` on next read. ## 10. `schema_version` on every document -Every V_delta document carries a `schema_version` string naming the +Every V_zeta document carries a `schema_version` string naming the schema set under which it is interpreted. Established values: -- `"V_delta"` — documents authored against V_delta +- `"V_zeta"` — documents authored against V_zeta - `"did_v1"` — legacy documents still carrying the did_v1 shape, or documents in a holding state during migration @@ -310,10 +310,10 @@ field. It identifies the overarching schema set, not a property of any one class, so it isn't declared in any per-class `fields` array and isn't validated by class-field validation. -The migrator sets `body.document_class.schema_version = "V_delta"` +The migrator sets `body.document_class.schema_version = "V_zeta"` on every output document. It is the dispatcher short-circuit signal: a document whose `document_class.schema_version` is already -`"V_delta"` is left untouched (modulo the structural padding in +`"V_zeta"` is left untouched (modulo the structural padding in `ensureClassBlocks`). ## Cross-references @@ -321,5 +321,5 @@ a document whose `document_class.schema_version` is already - File-reference handling (generic): [`_files.md`](_files.md) - Conversion index: [`_index.md`](_index.md) - Conversion template: [`_TEMPLATE.md`](_TEMPLATE.md) -- V_delta differences from V_gamma: [`V_delta_SPEC.md`](../../V_delta_SPEC.md) +- V_zeta differences from V_gamma: [`V_zeta_SPEC.md`](../../V_zeta_SPEC.md) - V_alpha → V_gamma rename history: `V_beta_notes.md`, `V_gamma_notes.md` diff --git a/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md b/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md index d962386..9c47355 100644 --- a/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/contrast_sensitivity_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `contrast_sensitivity_calc` +# Conversion: did_v1 → V_zeta — `contrast_sensitivity_calc` ## Identity -- **V_delta `class_name`:** `contrast_sensitivity_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/contrast_sensitivity_calc.json` +- **V_zeta `class_name`:** `contrast_sensitivity_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/contrast_sensitivity_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/contrastsensitivity_calc_schema.json` plus `ndi_common/database_documents/calc/contrastsensitivity_calc.json`. @@ -23,7 +23,7 @@ did_v1 name `contrastsensitivity_calc` is normalized to ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `class_name: "contrastsensitivity_calc"` | `class_name: "contrast_sensitivity_calc"` | rename (snake-case) | | (top-level) `depends_on: [element_id, stimulus_presentation_id, stimulus_response_scalar_id]` | top-level `depends_on` | identity | @@ -36,7 +36,7 @@ did_v1 name `contrastsensitivity_calc` is normalized to | `saturation_index_{RB,RBN,RBNS}` | `saturation_index_{rb,rbn,rbns}` | same | | `parameters_{RB,RBN,RBNS}` | `parameters_{rb,rbn,rbns}` | same | | `fitless_interpolated_c50` | same | `matrix` | -| `is_modulated_response` | same | `boolean` (did_v1 stored as 0/1 double; promoted to boolean in V_delta) | +| `is_modulated_response` | same | `boolean` (did_v1 stored as 0/1 double; promoted to boolean in V_zeta) | | `visual_response_p_bonferroni` | same | `matrix` | | `response_varies_p_bonferroni` | same | `matrix` | | `response_type` | same | `char` | @@ -47,8 +47,8 @@ did_v1 name `contrastsensitivity_calc` is normalized to lowercased to `_rb` / `_rbn` / `_rbns`. - **Inheritance.** Despite producing contrast-sensitivity outputs, this calc does NOT inherit from `contrast_tuning` in did_v1 — only from - `base`. V_delta preserves that choice. (Inheritance is confirmed `base`-only because this class aggregates across `contrast_tuning` documents rather than being a single one.) -- **`is_modulated_response` promoted to boolean.** did_v1 stored this as a numeric scalar (0/1 double). V_delta declares it `type: boolean`. Migration tools must convert `0` → `false` / `1` → `true`. + `base`. V_zeta preserves that choice. (Inheritance is confirmed `base`-only because this class aggregates across `contrast_tuning` documents rather than being a single one.) +- **`is_modulated_response` promoted to boolean.** did_v1 stored this as a numeric scalar (0/1 double). V_zeta declares it `type: boolean`. Migration tools must convert `0` → `false` / `1` → `true`. ## Default values for new fields @@ -57,7 +57,7 @@ None. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/contrastsensitivity_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/contrastsensitivity_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md index 0b74e4d..45f18d3 100644 --- a/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md +++ b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `contrast_tuning` +# Conversion: did_v1 → V_zeta — `contrast_tuning` ## Identity -- **V_delta `class_name`:** `contrast_tuning` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/contrast_tuning.json` +- **V_zeta `class_name`:** `contrast_tuning` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/contrast_tuning.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/vision/contrast_tuning_schema.json` plus the paired template @@ -19,12 +19,12 @@ computed; calculator types (e.g., `contrast_tuning_calc`) inherit from it. Conversion is primarily a structural reshaping: did_v1 declares every top-level grouping as `type: "structure"` with no inner declarations, so -all field-level typing in V_delta is recovered from the paired db_doc +all field-level typing in V_zeta is recovered from the paired db_doc template (the schema file alone is insufficient). ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `contrast_tuning.properties.response_units` | `contrast_tuning.properties.response_units` | type `0` placeholder → `char` (per user decision) | | `contrast_tuning.properties.response_type` | `contrast_tuning.properties.response_type` | identity (char) | @@ -43,7 +43,7 @@ template (the schema file alone is insufficient). - **Naka-Rushton fit grouping.** did_v1 stores the three model variants (RB, RBN, RBNS) as 27 sibling fields with `naka_rushton__` - names. V_delta groups them under a `fit` structure containing three + names. V_zeta groups them under a `fit` structure containing three sub-structures `naka_rushton_rb`, `naka_rushton_rbn`, `naka_rushton_rbns`, each carrying nine identically-named metrics. Migration is a name split on the second underscore (after `naka_rushton_`). @@ -51,29 +51,29 @@ template (the schema file alone is insufficient). (e.g., `naka_rushton_RB_pref`, `_empirical_c50`, `_r2`, `_relative_max_gain`, `_saturation_index`) appear as `[0]` in the template. The conversion *unwraps* these to plain `double` scalars in - V_delta — the V_delta schema declares them as `type: double` / + V_zeta — the V_zeta schema declares them as `type: double` / `mustBeScalar: true`. Migration tools must extract `arr[0]` and verify the array has exactly one element. - **`sensitivity` is genuinely a vector, not a scalar.** The did_v1 template stores `naka_rushton__sensitivity` as `[0]` like the other scalar metrics, but the user-supplied field documentation describes it as a 1x10 vector: for each i in 1..10, an inverse-threshold - sensitivity at i standard deviations of the control response. V_delta + sensitivity at i standard deviations of the control response. V_zeta declares `sensitivity` as `matrix` in all three Naka-Rushton blocks (do **not** unwrap to scalar). Migration tools must preserve the full vector rather than extracting `arr[0]`. - **Snake-case.** Variant tags are lowercased (`RB` → `rb`). - **RB-specific `saturation_index`.** The RB form has 2 free parameters with no saturation-controlling term, so `saturation_index` is always 0 - under the RB fit. V_delta encodes that note in the field documentation + under the RB fit. V_zeta encodes that note in the field documentation on `naka_rushton_rb.saturation_index`. ## Default values for new fields -V_delta does not introduce new required fields on this class beyond what +V_zeta does not introduce new required fields on this class beyond what existed in did_v1. The global `schema_version` tag lives at `document_class.schema_version` (see `_universal_renames.md` § 10) and is -set to `"V_delta"` by the dispatcher rather than the per-class migrator. +set to `"V_zeta"` by the dispatcher rather than the per-class migrator. ## Worked example @@ -81,8 +81,8 @@ The before-and-after pair is large; rather than inline the entire document, see: - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/contrast_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/contrast_tuning.json) -- **After (V_delta):** an example will be added to - `schemas/V_delta/examples/contrast_tuning_minimal.json` in a follow-up +- **After (V_zeta):** an example will be added to + `schemas/V_zeta/examples/contrast_tuning_minimal.json` in a follow-up PR once the migration engine produces one. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md index a8ef6f8..e1f9793 100644 --- a/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/contrast_tuning_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `contrast_tuning_calc` +# Conversion: did_v1 → V_zeta — `contrast_tuning_calc` ## Identity -- **V_delta `class_name`:** `contrast_tuning_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/contrast_tuning_calc.json` +- **V_zeta `class_name`:** `contrast_tuning_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/contrast_tuning_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/contrasttuning_calc_schema.json` plus `ndi_common/database_documents/calc/contrasttuning_calc.json`. @@ -16,17 +16,17 @@ A calculator type that computes a `contrast_tuning` result and stores the calculator's own input parameters alongside the inherited result fields. The did_v1 name `contrasttuning_calc` is normalized to `contrast_tuning_calc` -in V_delta to match the snake-cased naming of the result type it inherits +in V_zeta to match the snake-cased naming of the result type it inherits from. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `document_class.class_name: "contrasttuning_calc"` | `document_class.class_name: "contrast_tuning_calc"` | rename (snake-case normalization) | | `superclasses: [base, contrast_tuning]` | `superclasses: [base, contrast_tuning]` | identity (inherited fields stay in their declaring classes) | | `contrasttuning_calc.input_parameters` | `contrast_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields`; calculators may extend in subclasses | -| `contrasttuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `contrast_tuning`) | the inner `depends_on` referenced `stimulus_tuningcurve_id` which is already declared on `contrast_tuning`. V_delta does not re-declare it. | +| `contrasttuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `contrast_tuning`) | the inner `depends_on` referenced `stimulus_tuningcurve_id` which is already declared on `contrast_tuning`. V_zeta does not re-declare it. | ## Transformations in detail @@ -35,7 +35,7 @@ from. enclosing block key in document instances. - **Inherited dependency.** did_v1 redundantly listed `stimulus_tuningcurve_id` as an internal `depends_on` entry even though the parent class already - declared it. V_delta drops the redundancy; the dependency exists + declared it. V_zeta drops the redundancy; the dependency exists exactly once, on `contrast_tuning`. ## Default values for new fields @@ -46,7 +46,7 @@ empty struct. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/contrasttuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/contrasttuning_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/` once +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/` once the migration engine produces one. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md b/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md index f240fcc..aad25da 100644 --- a/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/hartley_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `hartley_calc` +# Conversion: did_v1 → V_zeta — `hartley_calc` ## Identity -- **V_delta `class_name`:** `hartley_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/hartley_calc.json` +- **V_zeta `class_name`:** `hartley_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/hartley_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/hartley_calc_schema.json` plus `ndi_common/database_documents/calc/hartley_calc.json`. @@ -20,11 +20,11 @@ a file reference to the produced kernel. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `class_name: "hartley_calc"` | same | identity | | `superclasses: [base, hartley_reverse_correlation]` | same | identity | -| (top-level) `files.file_list: ["hartley_results.ngrid"]` | top-level `file` array, one entry `name: "hartley_results.ngrid"` | structural rename: did_v1 `files.file_list` → V_delta top-level `file` | +| (top-level) `files.file_list: ["hartley_results.ngrid"]` | top-level `file` array, one entry `name: "hartley_results.ngrid"` | structural rename: did_v1 `files.file_list` → V_zeta top-level `file` | | `hartley_calc.input_parameters.T` | `hartley_calc.input_parameters.t` | snake-case rename; type `matrix` | | `hartley_calc.input_parameters.X_sampling` | `hartley_calc.input_parameters.x_sampling` | snake-case rename; `double` | | `hartley_calc.input_parameters.Y_sampling` | `hartley_calc.input_parameters.y_sampling` | snake-case rename; `double` | @@ -33,7 +33,7 @@ a file reference to the produced kernel. ## Transformations in detail - **`files.file_list` → top-level `file`.** did_v1 carries a class-block - `files.file_list` array; V_delta has a dedicated top-level `file` field + `files.file_list` array; V_zeta has a dedicated top-level `file` field on schemas (file record objects with `name`, `mustBeNonEmpty`, `documentation`). Migration must move and reshape this list. - **Capital-letter inputs renamed.** `T` / `X_sampling` / `Y_sampling` @@ -45,13 +45,13 @@ a file reference to the produced kernel. ## Default values for new fields The did_v1 template carries `T: [0, 0.05, 0.10, 0.15, 0.20, 0.25]`, -`X_sampling: 1`, `Y_sampling: 1`. V_delta preserves these as +`X_sampling: 1`, `Y_sampling: 1`. V_zeta preserves these as `default_value` on the respective fields. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/hartley_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/hartley_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md b/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md index a6a4015..959b358 100644 --- a/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md +++ b/schemas/V_zeta/conversions/from_did_v1/hartley_reverse_correlation.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `hartley_reverse_correlation` +# Conversion: did_v1 → V_zeta — `hartley_reverse_correlation` ## Identity -- **V_delta `class_name`:** `hartley_reverse_correlation` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/hartley_reverse_correlation.json` +- **V_zeta `class_name`:** `hartley_reverse_correlation` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/hartley_reverse_correlation.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/neuro/hartley_reverse_correlation_schema.json` plus @@ -21,7 +21,7 @@ compute the kernel. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `class_name: "hartley_reverse_correlation"` | same | identity | | `superclasses: [base, reverse_correlation]` | same | identity | @@ -30,7 +30,7 @@ compute the kernel. | `hartley_reverse_correlation.reconstruction_properties.{T_coords,X_coords,Y_coords}` | `reconstruction_properties.{t_coords,x_coords,y_coords}` | snake-case rename; `matrix` | | `hartley_reverse_correlation.spiketimes` | same | `matrix` | | `hartley_reverse_correlation.frameTimes` | `hartley_reverse_correlation.frame_times` | snake-case rename; `matrix` | -| `hartley_reverse_correlation.hartley_numbers` | same | `matrix` (integer-valued; integer subtype not introduced for V_delta) | +| `hartley_reverse_correlation.hartley_numbers` | same | `matrix` (integer-valued; integer subtype not introduced for V_zeta) | ## Transformations in detail @@ -43,13 +43,13 @@ compute the kernel. The did_v1 template carries non-empty defaults for several `stimulus_properties` fields (e.g., `L_max: 20`, `fps: 10`, `rect: [0, 0, -800, 600]`). V_delta preserves those as the `default_value` of each +800, 600]`). V_zeta preserves those as the `default_value` of each field. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/neuro/hartley_reverse_correlation.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/neuro/hartley_reverse_correlation.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/ontology_image.md b/schemas/V_zeta/conversions/from_did_v1/ontology_image.md index 25aca7c..a3c8055 100644 --- a/schemas/V_zeta/conversions/from_did_v1/ontology_image.md +++ b/schemas/V_zeta/conversions/from_did_v1/ontology_image.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `ontology_image` +# Conversion: did_v1 → V_zeta — `ontology_image` ## Identity -- **V_delta `class_name`:** `ontology_image` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/ontology_image.json` +- **V_zeta `class_name`:** `ontology_image` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/ontology_image.json` - **did_v1 source:** legacy NDI/DID `ontologyImage` document type (`_classname: "ontologyImage"` — camelCase). Schema-shape ancestor in this repository is `schemas/V_alpha/ontologyImage.json`; @@ -18,7 +18,7 @@ `ontology_image` carries a labelled image of an anatomical or functional region (e.g., a brain-atlas slice for a given Allen CCF region). did_v1 stored the ontology identity as a pair of `char` fields -(`ontology_name` + `ontology_region`); V_delta collapses them into a +(`ontology_name` + `ontology_region`); V_zeta collapses them into a single `region` field of `ontology_term` composite type. The image file reference (`ontology_image_file`) is unchanged. @@ -30,7 +30,7 @@ classname `ontologyImage` → `ontology_image`, ontology-annotation reshape, superclass-reference reshape, class-scoped property block keyed by `ontology_image`). -| did_v1 field | V_delta field | Transformation | Notes | +| did_v1 field | V_zeta field | Transformation | Notes | |---|---|---|---| | `ontologyImage.ontology_name` (char) | `ontology_image.region.node` | composed into `ontology_term` | CURIE (e.g., `allen_ccf_v3:12345`). See "Transformations in detail". | | `ontologyImage.ontology_region` (char) | `ontology_image.region.name` | composed into `ontology_term` | Human-readable label snapshot. | @@ -43,7 +43,7 @@ keyed by `ontology_image`). - **Collapse two coordinated chars into one `ontology_term`.** Same pattern as `probe_location` and `treatment`. did_v1's `ontology_name` (the ontology CURIE-or-name) and `ontology_region` (the - human-readable region label) merge into V_delta's `region` + human-readable region label) merge into V_zeta's `region` composite: region = { @@ -51,7 +51,7 @@ keyed by `ontology_image`). "name": } - V_delta's schema declares this field `mustBeNonEmpty: true`. Migrated + V_zeta's schema declares this field `mustBeNonEmpty: true`. Migrated documents that have empty inputs for either part fail validation until the missing value is supplied — see "Open questions". @@ -60,7 +60,7 @@ keyed by `ontology_image`). migrator rewrites `document_class.class_name` and the property-block key. -- **Document-instance shape.** V_delta uses class-scoped property +- **Document-instance shape.** V_zeta uses class-scoped property blocks; the `region` value lives at `ontology_image.region`. - **File reference.** The schema-level `_file` array (V_alpha) is @@ -71,7 +71,7 @@ keyed by `ontology_image`). ## Default values for new fields -V_delta introduces no required field on this class beyond what did_v1 +V_zeta introduces no required field on this class beyond what did_v1 documents already supply, modulo the `mustBeNonEmpty: true` tightening on `region` (which is a stricter validation of an existing input, not a new field). @@ -105,7 +105,7 @@ a new field). } ``` -### After (V_delta) +### After (V_zeta) ```json { @@ -138,7 +138,7 @@ a new field). `ontology_image` carries one file slot, `ontology_image_file`, declared at the schema level. The slot's name and semantics are unchanged -between did_v1 and V_delta; only the underscore-prefix stripping +between did_v1 and V_zeta; only the underscore-prefix stripping applies to the surrounding structural keys. The per-document file reference itself follows the generic rules in [`_files.md`](_files.md). No `ontology_image`-specific file-handling @@ -146,10 +146,10 @@ rules apply. ## Open questions -- **TODO-domain:** the V_delta schema requires `region` to be +- **TODO-domain:** the V_zeta schema requires `region` to be non-empty. did_v1 made `ontology_region` optional (`_mustBeNonEmpty: false`). Migrated documents that lack a region label cannot satisfy - the V_delta constraint as written. Options: (a) tighten by demoting + the V_zeta constraint as written. Options: (a) tighten by demoting to `mustBeNonEmpty: false` to preserve migration completeness; (b) populate `region.name` from a fallback (e.g., the resolved CURIE-registry label for `region.node`) and emit a warning; (c) @@ -165,8 +165,8 @@ rules apply. ## Cross-references - General file-handling rules: [`_files.md`](_files.md) -- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) -- V_delta schema file: [`schemas/V_delta/stable/ontology_image.json`](../../stable/ontology_image.json) +- Universal did_v1 → V_zeta renames: [`_universal_renames.md`](_universal_renames.md) +- V_zeta schema file: [`schemas/V_zeta/stable/ontology_image.json`](../../stable/ontology_image.json) - Sibling ontology-annotation type: [`ontology_label.md`](ontology_label.md) - Same two-char-to-`ontology_term` pattern: [`probe_location.md`](probe_location.md), diff --git a/schemas/V_zeta/conversions/from_did_v1/ontology_label.md b/schemas/V_zeta/conversions/from_did_v1/ontology_label.md index 1df8ba0..9d087af 100644 --- a/schemas/V_zeta/conversions/from_did_v1/ontology_label.md +++ b/schemas/V_zeta/conversions/from_did_v1/ontology_label.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `ontology_label` +# Conversion: did_v1 → V_zeta — `ontology_label` ## Identity -- **V_delta `class_name`:** `ontology_label` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/ontology_label.json` +- **V_zeta `class_name`:** `ontology_label` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/ontology_label.json` - **did_v1 source:** legacy NDI/DID `ontologyLabel` document type (`_classname: "ontologyLabel"` — camelCase). Schema-shape ancestor in this repository is `schemas/V_alpha/ontologyLabel.json`; @@ -19,7 +19,7 @@ (e.g., a brain-region label from Allen CCF). did_v1 stored three coordinated fields — `ontology_name` (the source ontology), `label` (the human-readable region name), and `label_id` (a numeric -id within that ontology). V_delta collapses these into a single +id within that ontology). V_zeta collapses these into a single `term` field of `ontology_term` composite type, where the CURIE `:` becomes the node and `label` becomes the label snapshot. @@ -32,7 +32,7 @@ classname `ontologyLabel` → `ontology_label`, ontology-annotation reshape, superclass-reference reshape, class-scoped property block keyed by `ontology_label`). -| did_v1 field | V_delta field | Transformation | Notes | +| did_v1 field | V_zeta field | Transformation | Notes | |---|---|---|---| | `ontologyLabel.ontology_name` (char) | `ontology_label.term.node` (CURIE prefix) | composed into `ontology_term`; combined with `label_id` | See "Transformations in detail". | | `ontologyLabel.label_id` (integer) | `ontology_label.term.node` (CURIE local part) | composed into `ontology_term`; combined with `ontology_name` | See "Transformations in detail". | @@ -54,13 +54,13 @@ keyed by `ontology_label`). The CURIE is built by concatenating the source-ontology name (the CURIE prefix), a colon, and the string form of `label_id`. The - V_delta schema's `documentation` for `term` describes this layout + V_zeta schema's `documentation` for `term` describes this layout explicitly: "The CURIE prefix identifies the source ontology (e.g., 'allen_ccf_v3'), the local part is the numeric ID (e.g., 'allen_ccf_v3:12345'), and 'name' carries the human-readable label." - **CURIE prefix normalization.** did_v1's `ontology_name` is a - free-form string (e.g., `Allen CCF v3`). For V_delta the prefix must + free-form string (e.g., `Allen CCF v3`). For V_zeta the prefix must match a registered CURIE prefix in `CURIE_lookups_meta.json` (or at least follow that file's conventions). The migrator should lower-case the prefix and replace spaces with underscores; the @@ -74,12 +74,12 @@ keyed by `ontology_label`). migrator rewrites `document_class.class_name` and the property-block key. -- **Document-instance shape.** V_delta uses class-scoped property +- **Document-instance shape.** V_zeta uses class-scoped property blocks; the `term` value lives at `ontology_label.term`. ## Default values for new fields -V_delta introduces no required field on this class beyond what did_v1 +V_zeta introduces no required field on this class beyond what did_v1 documents already supply, modulo the `mustBeNonEmpty: true` tightening on `term` (which is a stricter validation of an existing input, not a new field). @@ -114,7 +114,7 @@ new field). } ``` -### After (V_delta) +### After (V_zeta) ```json { @@ -150,7 +150,7 @@ rules in [`_files.md`](_files.md) do not apply. ## Open questions -- **TODO-domain:** the V_delta `term.node` is documented as +- **TODO-domain:** the V_zeta `term.node` is documented as ":". did_v1's `label_id` is declared `integer` with `mustBeNonEmpty: false` and `_default_value: 0`. Documents that carry the default `0` (or no `label_id`) cannot form a meaningful @@ -164,7 +164,7 @@ rules in [`_files.md`](_files.md) do not apply. labels), what should the migrator do — fail, emit a TODO-marked CURIE, or write to a side-channel? Mirrors the open question in [`ontology_image.md`](ontology_image.md). -- **TODO-domain:** the V_delta schema declares `term` as +- **TODO-domain:** the V_zeta schema declares `term` as `mustBeNonEmpty: true`. did_v1 made each of the three input fields individually nullable. Whether to demote `term` to `mustBeNonEmpty: false` to preserve migration completeness, or to enforce non-empty @@ -174,11 +174,11 @@ rules in [`_files.md`](_files.md) do not apply. ## Cross-references - General file-handling rules: [`_files.md`](_files.md) -- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) -- V_delta schema file: [`schemas/V_delta/stable/ontology_label.json`](../../stable/ontology_label.json) +- Universal did_v1 → V_zeta renames: [`_universal_renames.md`](_universal_renames.md) +- V_zeta schema file: [`schemas/V_zeta/stable/ontology_label.json`](../../stable/ontology_label.json) - Sibling ontology-annotation type: [`ontology_image.md`](ontology_image.md) - Same composite-collapse pattern (two-input variant): [`probe_location.md`](probe_location.md), [`treatment.md`](treatment.md) -- CURIE prefix registry (V_delta): - [`schemas/V_delta/stable/CURIE_lookups_meta.json`](../../stable/CURIE_lookups_meta.json) +- CURIE prefix registry (V_zeta): + [`schemas/V_zeta/stable/CURIE_lookups_meta.json`](../../stable/CURIE_lookups_meta.json) diff --git a/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md index eab50c6..48a7a3f 100644 --- a/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/oridirtuning_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `oridirtuning_calc` +# Conversion: did_v1 → V_zeta — `oridirtuning_calc` ## Identity -- **V_delta `class_name`:** `oridirtuning_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/oridirtuning_calc.json` +- **V_zeta `class_name`:** `oridirtuning_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/oridirtuning_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/oridirtuning_calc_schema.json` plus `ndi_common/database_documents/calc/oridirtuning_calc.json`. @@ -14,8 +14,8 @@ A calculator type that computes an `orientation_direction_tuning` result and stores the calculator's own input parameters in the inherited -`calculator.input_parameters` slot. The V_delta name `oridirtuning_calc` -matches the did_v1 source — earlier V_delta drafts had renamed it to +`calculator.input_parameters` slot. The V_zeta name `oridirtuning_calc` +matches the did_v1 source — earlier V_zeta drafts had renamed it to `orientation_direction_tuning_calc` "to match the snake-cased naming of the result type it inherits from", but that rename invented a class name that does not appear in the NDI calculator hierarchy @@ -23,37 +23,37 @@ does not appear in the NDI calculator hierarchy ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `document_class.class_name: "oridirtuning_calc"` | `document_class.class_name: "oridirtuning_calc"` | identity | | `superclasses: [base, orientation_direction_tuning]` | `superclasses: [base, orientation_direction_tuning, tuning_fit]` | added `tuning_fit` (and transitively `calculator` and `app`) so the calculator interface lives on the shared base, not on each subclass | | `oridirtuning_calc.input_parameters` | `calculator.input_parameters` | moved up to the abstract `calculator` base (field is now inherited, not declared per-subclass) | -| `app.name`, `app.version` (top-level v1 block) | `app.app_name`, `app.app_version` (same block) | universal app-block field rename in did2.convert.universalRenames; the v1 source already carries the canonical NDI calculator class name in `app.name` (e.g., "ndi.calc.vis.oridir_tuning"), so V_delta does not need a separate `calculator_name` field | -| `oridirtuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `orientation_direction_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | +| `app.name`, `app.version` (top-level v1 block) | `app.app_name`, `app.app_version` (same block) | universal app-block field rename in did2.convert.universalRenames; the v1 source already carries the canonical NDI calculator class name in `app.name` (e.g., "ndi.calc.vis.oridir_tuning"), so V_zeta does not need a separate `calculator_name` field | +| `oridirtuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `orientation_direction_tuning`) | redundant in did_v1; V_zeta does not re-declare an already-inherited dependency | ## Transformations in detail -- **Calculator base.** V_delta introduces a new abstract `calculator` class +- **Calculator base.** V_zeta introduces a new abstract `calculator` class whose superclasses are `base` and `app`. It declares one field (`input_parameters`, structure, optional). The required calculator identity comes from the inherited `app.app_name` -- there is no - `calculator.calculator_name` in V_delta, because that field would + `calculator.calculator_name` in V_zeta, because that field would duplicate `app.app_name`. Every `*_calc` schema inherits from `calculator` (directly, or via the intermediate abstract `tuning_fit` base when the calculator is a tuning fit). `oridirtuning_calc` reaches `calculator` (and therefore `app`) through `tuning_fit`. - **app block migration.** did_v1 calc documents already ship a top-level `app` block whose `name` field holds the NDI calculator class identity - (e.g., `ndi.calc.vis.oridir_tuning`). V_delta renames `app.name -> + (e.g., `ndi.calc.vis.oridir_tuning`). V_zeta renames `app.name -> app.app_name` and `app.version -> app.app_version`; the rename is applied universally by `did2.convert.universalRenames` to any document carrying an `app` block, not just calc docs. The other app fields (`url`, `os`, `os_version`, `interpreter`, `interpreter_version`) - match V_delta verbatim. + match V_zeta verbatim. - **Inherited dependency.** did_v1 redundantly listed `stimulus_tuningcurve_id` as an internal `depends_on` entry even though the parent class `orientation_direction_tuning` already declared it. - V_delta drops the redundancy. + V_zeta drops the redundancy. ## Default values for new fields @@ -65,7 +65,7 @@ does not appear in the NDI calculator hierarchy ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/oridirtuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/oridirtuning_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md b/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md index b280743..bfb2961 100644 --- a/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md +++ b/schemas/V_zeta/conversions/from_did_v1/orientation_direction_tuning.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `orientation_direction_tuning` +# Conversion: did_v1 → V_zeta — `orientation_direction_tuning` ## Identity -- **V_delta `class_name`:** `orientation_direction_tuning` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/orientation_direction_tuning.json` +- **V_zeta `class_name`:** `orientation_direction_tuning` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/orientation_direction_tuning.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/stimulus/vision/oridir/orientation_direction_tuning_schema.json` plus the paired template @@ -21,12 +21,12 @@ tuning was computed; calculator types (e.g., Conversion is primarily a structural reshaping: did_v1 declares every top-level grouping (`properties`, `tuning_curve`, `significance`, `vector`, `fit`) as `type: "structure"` with no inner declarations, so all -field-level typing in V_delta is recovered from the paired db_doc template +field-level typing in V_zeta is recovered from the paired db_doc template (the schema file alone is insufficient). ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `orientation_direction_tuning.properties.coordinates` | same | char placeholder → `char` with enum `{compass, cartesian}` | | `orientation_direction_tuning.properties.response_units` | same | type `0` placeholder → `char` (per user decision) | @@ -54,7 +54,7 @@ field-level typing in V_delta is recovered from the paired db_doc template ## Transformations in detail - **`coordinates` enum.** did_v1 stores `coordinates` as a free-form - string placeholder. V_delta constrains it to the documented vocabulary + string placeholder. V_zeta constrains it to the documented vocabulary `{"compass", "cartesian"}`. Migration tools must lower-case any legacy capitalisations. - **Scalar metrics stored as 1-element arrays.** Four fit-derived ratio @@ -63,7 +63,7 @@ field-level typing in V_delta is recovered from the paired db_doc template `direction_preferred_null_ratio`, `orientation_preferred_orthogonal_ratio_rectified`, `direction_preferred_null_ratio_rectified`. The conversion *unwraps* - these to plain `double` scalars in V_delta — the V_delta schema declares + these to plain `double` scalars in V_zeta — the V_zeta schema declares them as `type: double` / `mustBeScalar: true`. Migration tools must extract `arr[0]` and verify the array has exactly one element. - **Vector-space preferences.** `vector.orientation_preference` and @@ -72,16 +72,16 @@ field-level typing in V_delta is recovered from the paired db_doc template sums respectively. Tools that represent these as complex numbers internally must convert to angle-in-degrees on output. - **Trial-axis convention.** For the per-trial matrices (`individual`, - `raw_individual`, `control_individual`) V_delta documents the + `raw_individual`, `control_individual`) V_zeta documents the row-vs-column convention explicitly: rows index sampled directions, columns index trials. did_v1 did not commit to a layout. ## Default values for new fields -V_delta does not introduce new required fields on this class beyond what +V_zeta does not introduce new required fields on this class beyond what existed in did_v1. The global `schema_version` tag lives at `document_class.schema_version` (see `_universal_renames.md` § 10) and is -set to `"V_delta"` by the dispatcher rather than the per-class migrator. +set to `"V_zeta"` by the dispatcher rather than the per-class migrator. ## Worked example @@ -89,8 +89,8 @@ The before-and-after pair is large; rather than inline the entire document, see: - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/stimulus/vision/oridir/orientation_direction_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/stimulus/vision/oridir/orientation_direction_tuning.json) -- **After (V_delta):** an example will be added to - `schemas/V_delta/examples/orientation_direction_tuning_minimal.json` in a +- **After (V_zeta):** an example will be added to + `schemas/V_zeta/examples/orientation_direction_tuning_minimal.json` in a follow-up PR once the migration engine produces one. ## File handling @@ -106,7 +106,7 @@ rules in [`_files.md`](_files.md) do not apply. `iao:` for data items, `efo:` / `obi:` for the stimulus-direction axis. - **TODO-domain:** confirm whether `vector.orientation_preference` and `vector.direction_preference` should be kept as scalar angles (current - V_delta choice) or expanded to a 2-element `[real, imag]` matrix to + V_zeta choice) or expanded to a 2-element `[real, imag]` matrix to preserve vector-sum magnitude alongside the angle. ## Cross-references diff --git a/schemas/V_zeta/conversions/from_did_v1/probe_location.md b/schemas/V_zeta/conversions/from_did_v1/probe_location.md index 2118402..2c9066f 100644 --- a/schemas/V_zeta/conversions/from_did_v1/probe_location.md +++ b/schemas/V_zeta/conversions/from_did_v1/probe_location.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `probe_location` +# Conversion: did_v1 → V_zeta — `probe_location` ## Identity -- **V_delta `class_name`:** `probe_location` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/probe_location.json` +- **V_zeta `class_name`:** `probe_location` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/probe_location.json` - **did_v1 source:** legacy NDI/DID `probe_location` document type (`_classname: "probe_location"`). The schema-shape ancestor in this repository is `schemas/V_alpha/probe_location.json`; the @@ -16,19 +16,19 @@ `probe_location` records the anatomical or functional location at which a probe is sampling. did_v1 carried this as a pair of coordinated `char` -fields (`ontology_name` + `name`); V_delta collapses them into a single +fields (`ontology_name` + `name`); V_zeta collapses them into a single `location` field of the V_gamma-introduced `ontology_term` composite type, which packages a CURIE node and a label snapshot under one key. ## Field mapping -One row per field across the V_alpha/V_beta-era shape and the V_delta +One row per field across the V_alpha/V_beta-era shape and the V_zeta target. Beyond these fields, the universal renames listed in [`_universal_renames.md`](_universal_renames.md) apply (snake-case classname, ontology-annotation reshape, superclass-reference reshape, class-scoped property block keyed by `probe_location`). -| did_v1 field | V_delta field | Transformation | Notes | +| did_v1 field | V_zeta field | Transformation | Notes | |---|---|---|---| | `probe_location.ontology_name` (char) | `probe_location.location.node` | composed into `ontology_term` | CURIE (e.g., `uberon:0002436`). See "Transformations in detail". | | `probe_location.name` (char) | `probe_location.location.name` | composed into `ontology_term` | Human-readable label snapshot (e.g., `primary visual cortex`). | @@ -39,7 +39,7 @@ class-scoped property block keyed by `probe_location`). - **Collapse two coordinated chars into one `ontology_term`.** did_v1 stored the ontology identifier and its human-readable label as two - separate `char` fields. V_delta declares a single `location` field of + separate `char` fields. V_zeta declares a single `location` field of type `ontology_term` (introduced in V_gamma — see `V_gamma_notes.md` § "Class-version bumps (2.0.0)"). The composite value carries two sub-keys: `node` (the CURIE) and `name` (the label snapshot). The @@ -54,22 +54,22 @@ class-scoped property block keyed by `probe_location`). input is empty, the corresponding sub-field is the empty string. - **CURIE normalization.** did_v1's `ontology_name` was a free-form - string; V_delta's `node` is a CURIE. If the did_v1 value already looks + string; V_zeta's `node` is a CURIE. If the did_v1 value already looks like `:` (e.g., `uberon:0002436`), it carries over verbatim. If it carries only a prefix name (e.g., `UBERON`) with the term elsewhere, the migrator must reconstruct the CURIE. See "Open questions" for the under-specified cases. -- **Document-instance shape.** V_delta uses class-scoped property +- **Document-instance shape.** V_zeta uses class-scoped property blocks; the migrated `location` value lives under the `probe_location` block at path `probe_location.location`. ## Default values for new fields -V_delta introduces no required field on this class that did_v1 documents +V_zeta introduces no required field on this class that did_v1 documents do not already supply. The global `schema_version` tag lives on every document at `document_class.schema_version` (see `_universal_renames.md` -§10) and is set to `"V_delta"` by the dispatcher rather than the +§10) and is set to `"V_zeta"` by the dispatcher rather than the per-class migrator. ## Worked example @@ -101,7 +101,7 @@ per-class migrator. } ``` -### After (V_delta) +### After (V_zeta) ```json { @@ -149,15 +149,15 @@ rules in [`_files.md`](_files.md) do not apply. prefixes; the conservative behavior is to lowercase only the prefix segment. - **TODO-domain:** the `mustBeNonEmpty` for `location` is `false` in - the V_delta schema. If a did_v1 document has both inputs empty, the + the V_zeta schema. If a did_v1 document has both inputs empty, the migrator can emit an empty composite (`{"node": "", "name": ""}`), or it can omit the field entirely. Confirm the preferred behavior. ## Cross-references - General file-handling rules: [`_files.md`](_files.md) -- Universal did_v1 → V_delta renames: [`_universal_renames.md`](_universal_renames.md) -- V_delta schema file: [`schemas/V_delta/stable/probe_location.json`](../../stable/probe_location.json) +- Universal did_v1 → V_zeta renames: [`_universal_renames.md`](_universal_renames.md) +- V_zeta schema file: [`schemas/V_zeta/stable/probe_location.json`](../../stable/probe_location.json) - Related conversions that follow the same two-char-to-`ontology_term` pattern: [`treatment.md`](treatment.md), [`ontology_image.md`](ontology_image.md), diff --git a/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md b/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md index abd9e61..5cabb6c 100644 --- a/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md +++ b/schemas/V_zeta/conversions/from_did_v1/reverse_correlation.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `reverse_correlation` +# Conversion: did_v1 → V_zeta — `reverse_correlation` ## Identity -- **V_delta `class_name`:** `reverse_correlation` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/reverse_correlation.json` +- **V_zeta `class_name`:** `reverse_correlation` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/reverse_correlation.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/neuro/reverse_correlation_schema.json` plus `ndi_common/database_documents/neuro/reverse_correlation.json`. @@ -13,13 +13,13 @@ ## Summary Generic reverse-correlation result type. Inherits from `base` and `ngrid` -(an existing V_delta type) — the n-dimensional grid carries the +(an existing V_zeta type) — the n-dimensional grid carries the reverse-correlation kernel itself, and this class adds the metadata describing the method and axis labels. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `class_name: "reverse_correlation"` | same | identity | | `superclasses: [base, ngrid]` | same | identity | @@ -39,7 +39,7 @@ None. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/neuro/reverse_correlation.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/neuro/reverse_correlation.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling @@ -58,7 +58,7 @@ govern how the inherited file references migrate. ## Cross-references -- Inherited type: `ngrid` (existing V_delta type — not migrated by this +- Inherited type: `ngrid` (existing V_zeta type — not migrated by this PR; conversion doc not required here) - Specialization: [`hartley_reverse_correlation.md`](hartley_reverse_correlation.md) - General file-handling rules: [`_files.md`](_files.md) diff --git a/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md index 68f74f1..dec686c 100644 --- a/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md +++ b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `spatial_frequency_tuning` +# Conversion: did_v1 → V_zeta — `spatial_frequency_tuning` ## Identity -- **V_delta `class_name`:** `spatial_frequency_tuning` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/spatial_frequency_tuning.json` +- **V_zeta `class_name`:** `spatial_frequency_tuning` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/spatial_frequency_tuning.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/vision/spatial_frequency_tuning_schema.json` plus the paired template @@ -20,12 +20,12 @@ from this class. Conversion is primarily a structural reshaping: did_v1 declares each top-level grouping as an unconstrained `type: "structure"`, so all -field-level typing in V_delta is recovered from the paired db_doc +field-level typing in V_zeta is recovered from the paired db_doc template. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `spatial_frequency_tuning.properties.{response_units,response_type}` | same | `char` types (response_units per user decision) | | `spatial_frequency_tuning.tuning_curve.spatial_frequency` | same | scalar placeholder → `matrix` | @@ -57,7 +57,7 @@ template. corrected. - **Mixed scalar/array fields in did_v1 are normalized.** For example, `fit_movshon.values` is declared as scalar `0` while `fit_dog.values` - is `[0]`; V_delta unifies these as `matrix` per user direction + is `[0]`; V_zeta unifies these as `matrix` per user direction ("double arrays for this"). - **Per-fit parameter vectors are documented.** Each fit block's `parameters` documentation now records the canonical parameter layout @@ -70,20 +70,20 @@ template. value range; `bandwidth` documents the `log2(h50 / l50)` definition and the Inf propagation. - **`abs` block** is a documented mirror of all preceding blocks, - recomputed on absolute-valued responses. Empty in did_v1; V_delta + recomputed on absolute-valued responses. Empty in did_v1; V_zeta retains it as an empty structure pending domain confirmation. ## Default values for new fields None added by this PR. The global `schema_version` tag lives at `document_class.schema_version` (see `_universal_renames.md` § 10) and -is set to `"V_delta"` by the dispatcher rather than the per-class +is set to `"V_zeta"` by the dispatcher rather than the per-class migrator. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/spatial_frequency_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/spatial_frequency_tuning.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md index 39d2f29..d5a87c7 100644 --- a/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/spatial_frequency_tuning_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `spatial_frequency_tuning_calc` +# Conversion: did_v1 → V_zeta — `spatial_frequency_tuning_calc` ## Identity -- **V_delta `class_name`:** `spatial_frequency_tuning_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/spatial_frequency_tuning_calc.json` +- **V_zeta `class_name`:** `spatial_frequency_tuning_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/spatial_frequency_tuning_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/spatial_frequency_tuning_calc_schema.json` plus `ndi_common/database_documents/calc/spatial_frequency_tuning_calc.json`. @@ -18,18 +18,18 @@ calculator's own input parameters alongside the inherited result fields. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `document_class.class_name: "spatial_frequency_tuning_calc"` | `document_class.class_name: "spatial_frequency_tuning_calc"` | identity | | `superclasses: [base, spatial_frequency_tuning]` | `superclasses: [base, spatial_frequency_tuning]` | identity (inherited fields stay in their declaring classes) | | `spatial_frequency_tuning_calc.input_parameters` | `spatial_frequency_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields` | -| `spatial_frequency_tuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `spatial_frequency_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | +| `spatial_frequency_tuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `spatial_frequency_tuning`) | redundant in did_v1; V_zeta does not re-declare an already-inherited dependency | ## Transformations in detail - **Inherited dependency.** did_v1 redundantly listed `stimulus_tuningcurve_id` as an internal `depends_on` entry even though - the parent class `spatial_frequency_tuning` already declared it. V_delta drops the + the parent class `spatial_frequency_tuning` already declared it. V_zeta drops the redundancy. ## Default values for new fields @@ -39,7 +39,7 @@ None. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/spatial_frequency_tuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/spatial_frequency_tuning_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md b/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md index 18e3de1..863fce2 100644 --- a/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md +++ b/schemas/V_zeta/conversions/from_did_v1/speed_tuning.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `speed_tuning` +# Conversion: did_v1 → V_zeta — `speed_tuning` ## Identity -- **V_delta `class_name`:** `speed_tuning` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/speed_tuning.json` +- **V_zeta `class_name`:** `speed_tuning` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/speed_tuning.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/vision/speed_tuning_schema.json` plus the paired template @@ -19,12 +19,12 @@ calculators (e.g., `speed_tuning_calc`) inherit from this class. Conversion is primarily a structural reshaping: did_v1 declares each top-level grouping as an unconstrained `type: "structure"`, so all -field-level typing in V_delta is recovered from the paired db_doc +field-level typing in V_zeta is recovered from the paired db_doc template. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `speed_tuning.properties.{response_units,response_type}` | same | `char` types (response_units per user decision) | | `speed_tuning.tuning_curve.{spatial_frequency,temporal_frequency}` | same | scalar placeholder → `matrix` (1xN sampled values) | @@ -45,7 +45,7 @@ template. `Priebe_fit_speed_tuning_index` as a 1-element array `[0]` in all three fit blocks. The user-supplied documentation describes it as a singular index ("Provides an index of the relationship between preferred speed - and spatial frequency"), so V_delta declares it as scalar `double` / + and spatial frequency"), so V_zeta declares it as scalar `double` / `mustBeScalar: true`. Migration tools must extract `arr[0]` and verify the array has exactly one element. This is the same unwrap convention applied to the scalar `[0]` placeholders in `contrast_tuning` and @@ -54,10 +54,10 @@ template. (`fit`, `fit_no_speed`, `fit_fullspeed`) with overlapping field sets. `fit_no_speed` and `fit_fullspeed` add `partial_r2` and `priebe_fit_nested_f_test_p_value` for the nested F-test comparison; - `fit` does not. V_delta preserves all three blocks and the + `fit` does not. V_zeta preserves all three blocks and the field-membership difference between them. - **Trial-axis convention.** For the per-trial matrices (`individual`, - `raw_individual`, `control_individual`) V_delta documents the + `raw_individual`, `control_individual`) V_zeta documents the row-vs-column convention explicitly: rows index sampled (SF, TF) points, columns index trials. @@ -65,13 +65,13 @@ template. None added by this PR. The global `schema_version` tag lives at `document_class.schema_version` (see `_universal_renames.md` § 10) and -is set to `"V_delta"` by the dispatcher rather than the per-class +is set to `"V_zeta"` by the dispatcher rather than the per-class migrator. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/speed_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/speed_tuning.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md index 1a715e1..240b623 100644 --- a/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/speed_tuning_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `speed_tuning_calc` +# Conversion: did_v1 → V_zeta — `speed_tuning_calc` ## Identity -- **V_delta `class_name`:** `speed_tuning_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/speed_tuning_calc.json` +- **V_zeta `class_name`:** `speed_tuning_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/speed_tuning_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/speedtuning_calc_schema.json` plus `ndi_common/database_documents/calc/speedtuning_calc.json`. @@ -18,18 +18,18 @@ calculator's own input parameters alongside the inherited result fields. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `document_class.class_name: "speedtuning_calc"` | `document_class.class_name: "speed_tuning_calc"` | rename (snake-case normalization) | | `superclasses: [base, speed_tuning]` | `superclasses: [base, speed_tuning]` | identity (inherited fields stay in their declaring classes) | | `speedtuning_calc.input_parameters` | `speed_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields` | -| `speedtuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `speed_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | +| `speedtuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `speed_tuning`) | redundant in did_v1; V_zeta does not re-declare an already-inherited dependency | ## Transformations in detail - **Inherited dependency.** did_v1 redundantly listed `stimulus_tuningcurve_id` as an internal `depends_on` entry even though - the parent class `speed_tuning` already declared it. V_delta drops the + the parent class `speed_tuning` already declared it. V_zeta drops the redundancy. ## Default values for new fields @@ -39,7 +39,7 @@ None. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/speedtuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/speedtuning_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/subject_group.md b/schemas/V_zeta/conversions/from_did_v1/subject_group.md index e77f3df..d91233f 100644 --- a/schemas/V_zeta/conversions/from_did_v1/subject_group.md +++ b/schemas/V_zeta/conversions/from_did_v1/subject_group.md @@ -1,15 +1,15 @@ -# `subject_group` → `subject` (`is_group: true`) [Brainstorm E] +# `subject_group` → `subject` (`is_group: true`) [Brainstorm I] Status: **drafted** -`subject_group` is **deprecated** in V_epsilon (see `V_epsilon_SPEC.md`, +`subject_group` is **deprecated** in V_zeta (see `V_zeta_SPEC.md`, "Deprecated / folded" table). A group of subjects is modeled as a `subject` flagged `is_group: true`, and membership becomes `group_assignment` events. ## Mapping (per document, 1 → 1) -| did_v1 `subject_group` | V_epsilon `subject` | Transformation | +| did_v1 `subject_group` | V_zeta `subject` | Transformation | |---|---|---| | (class) `subject_group` | (class) `subject`, `is_group: true` | class fold | | `subject_group.group_name` (optional; absent in v1 corpus) | `subject.local_identifier` | char copy | @@ -24,7 +24,7 @@ group `subject`. ## Membership → `group_assignment` (relational, NDI layer) -In V_epsilon, member→group membership is event-sourced as `group_assignment` +In V_zeta, member→group membership is event-sourced as `group_assignment` annotations (member `subject_id` + `group_id`). **However, did_v1 does not record group membership anywhere**: the `subject_group` body is empty and no v1 document depends on a `subject_group` (verified across the did_v1 document @@ -37,6 +37,6 @@ a targeted, corpus-specific NDI-layer pass at that time. ## Engine -Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_zeta'` to `+did2/+convert/+migrators_e/subject_group.m`. A 1 → 1 fold; the default -`V_delta` target is unaffected (it keeps `subject_group` as-is). +`V_zeta` target is unaffected (it keeps `subject_group` as-is). diff --git a/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md index fb544bd..878495e 100644 --- a/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md +++ b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `temporal_frequency_tuning` +# Conversion: did_v1 → V_zeta — `temporal_frequency_tuning` ## Identity -- **V_delta `class_name`:** `temporal_frequency_tuning` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/temporal_frequency_tuning.json` +- **V_zeta `class_name`:** `temporal_frequency_tuning` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/temporal_frequency_tuning.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/vision/temporal_frequency_tuning_schema.json` plus the paired template @@ -20,12 +20,12 @@ from this class. Conversion is primarily a structural reshaping: did_v1 declares each top-level grouping as an unconstrained `type: "structure"`, so all -field-level typing in V_delta is recovered from the paired db_doc +field-level typing in V_zeta is recovered from the paired db_doc template. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `temporal_frequency_tuning.properties.{response_units,response_type}` | same | `char` types (response_units per user decision) | | `temporal_frequency_tuning.tuning_curve.temporal_frequency` | same | scalar placeholder → `matrix` | @@ -58,7 +58,7 @@ template. docstring; that has been corrected. - **Mixed scalar/array fields in did_v1 are normalized.** For example, `fit_movshon.values` is declared as scalar `0` while `fit_dog.values` - is `[0]`; V_delta unifies these as `matrix` per user direction + is `[0]`; V_zeta unifies these as `matrix` per user direction ("double arrays for this"). - **Per-fit parameter vectors are documented.** Each fit block's `parameters` documentation now records the canonical parameter layout @@ -71,20 +71,20 @@ template. value range; `bandwidth` documents the `log2(h50 / l50)` definition and the Inf propagation. - **`abs` block** is a documented mirror of all preceding blocks, - recomputed on absolute-valued responses. Empty in did_v1; V_delta + recomputed on absolute-valued responses. Empty in did_v1; V_zeta retains it as an empty structure pending domain confirmation. ## Default values for new fields None added by this PR. The global `schema_version` tag lives at `document_class.schema_version` (see `_universal_renames.md` § 10) and -is set to `"V_delta"` by the dispatcher rather than the per-class +is set to `"V_zeta"` by the dispatcher rather than the per-class migrator. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/vision/temporal_frequency_tuning.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/vision/temporal_frequency_tuning.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md index 5f932b6..f508fa2 100644 --- a/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md +++ b/schemas/V_zeta/conversions/from_did_v1/temporal_frequency_tuning_calc.md @@ -1,10 +1,10 @@ -# Conversion: did_v1 → V_delta — `temporal_frequency_tuning_calc` +# Conversion: did_v1 → V_zeta — `temporal_frequency_tuning_calc` ## Identity -- **V_delta `class_name`:** `temporal_frequency_tuning_calc` -- **V_delta tier:** `stable` -- **V_delta schema path:** `schemas/V_delta/stable/temporal_frequency_tuning_calc.json` +- **V_zeta `class_name`:** `temporal_frequency_tuning_calc` +- **V_zeta tier:** `stable` +- **V_zeta schema path:** `schemas/V_zeta/stable/temporal_frequency_tuning_calc.json` - **did_v1 source:** `VH-Lab/NDIcalc-vis-matlab` — `ndi_common/schema_documents/calc/temporal_frequency_tuning_calc_schema.json` plus `ndi_common/database_documents/calc/temporal_frequency_tuning_calc.json`. @@ -18,18 +18,18 @@ calculator's own input parameters alongside the inherited result fields. ## Field mapping -| did_v1 location | V_delta location | Transformation | +| did_v1 location | V_zeta location | Transformation | |---|---|---| | `document_class.class_name: "temporal_frequency_tuning_calc"` | `document_class.class_name: "temporal_frequency_tuning_calc"` | identity | | `superclasses: [base, temporal_frequency_tuning]` | `superclasses: [base, temporal_frequency_tuning]` | identity (inherited fields stay in their declaring classes) | | `temporal_frequency_tuning_calc.input_parameters` | `temporal_frequency_tuning_calc.input_parameters` | empty struct → `type: structure` with empty `fields` | -| `temporal_frequency_tuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `temporal_frequency_tuning`) | redundant in did_v1; V_delta does not re-declare an already-inherited dependency | +| `temporal_frequency_tuning_calc.depends_on` (internal struct with `stimulus_tuningcurve_id`) | (removed — inherited from `temporal_frequency_tuning`) | redundant in did_v1; V_zeta does not re-declare an already-inherited dependency | ## Transformations in detail - **Inherited dependency.** did_v1 redundantly listed `stimulus_tuningcurve_id` as an internal `depends_on` entry even though - the parent class `temporal_frequency_tuning` already declared it. V_delta drops the + the parent class `temporal_frequency_tuning` already declared it. V_zeta drops the redundancy. ## Default values for new fields @@ -39,7 +39,7 @@ None. ## Worked example - **Before (did_v1):** [`NDIcalc-vis-matlab/ndi_common/database_documents/calc/temporal_frequency_tuning_calc.json`](https://github.com/VH-Lab/NDIcalc-vis-matlab/blob/main/ndi_common/database_documents/calc/temporal_frequency_tuning_calc.json) -- **After (V_delta):** to be added under `schemas/V_delta/examples/`. +- **After (V_zeta):** to be added under `schemas/V_zeta/examples/`. ## File handling diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment.md b/schemas/V_zeta/conversions/from_did_v1/treatment.md index 42f2d56..ce3bacc 100644 --- a/schemas/V_zeta/conversions/from_did_v1/treatment.md +++ b/schemas/V_zeta/conversions/from_did_v1/treatment.md @@ -1,17 +1,17 @@ -# Conversion: did_v1 → V_epsilon — `treatment` → manipulation tiers (Brainstorm E split) +# Conversion: did_v1 → V_zeta — `treatment` → manipulation tiers (Brainstorm I split) -> **Supersedes the conservative class-preserving `treatment` → V_delta `treatment` conversion** (kept in git history). Under Brainstorm E the legacy `treatment` catch-all is **retired** and **split** across the manipulation tier (and, for non-manipulation rows, out of the tier entirely). This doc is the dispatch spec for that split. Companion: [`ontology_table_row.md`](ontology_table_row.md) (the observation-tier split). +> **Supersedes the conservative class-preserving `treatment` → `treatment` conversion** (kept in git history). Under Brainstorm I the legacy `treatment` catch-all is **retired** and **split** across the manipulation tier (and, for non-manipulation rows, out of the tier entirely). This doc is the dispatch spec for that split. Companion: [`ontology_table_row.md`](ontology_table_row.md) (the observation-tier split). ## Identity -- **Target tier:** V_epsilon manipulation families (`schemas/V_epsilon/draft/`). -- **did_v1 source:** legacy NDI/DID `treatment` (`_classname: "treatment"`; shape ancestor `schemas/V_alpha/treatment.json`). Fields: `treatment.ontologyName` + `treatment.name` (ontology identity), `treatment.numeric_value` (matrix), `treatment.string_value` (char); `depends_on`: `subject_id`, `manipulation_id`, `protocol_id`. +- **Target tier:** V_zeta manipulation families (`schemas/V_zeta/stable/`). +- **did_v1 source:** legacy NDI/DID `treatment` (`_classname: "treatment"`; shape ancestor `schemas/V_alpha/treatment.json`, used here only to document the did_v1 field shape). Fields: `treatment.ontologyName` + `treatment.name` (ontology identity), `treatment.numeric_value` (matrix), `treatment.string_value` (char); `depends_on`: `subject_id`, `manipulation_id`, `protocol_id`. - **Status:** `drafted` (dispatch table seeded from real corpora; per-term branch list finalized in discovery mode — see [Open questions](#open-questions)). -- **Cardinality:** **1 → 1** in the common case (one `treatment` → one manipulation document), **1 → 2** when a recognizable `numeric_value` spawns a companion `scalar_observation`. Genuinely-not-a-manipulation rows route **out of tier** (1 → 1 into observation/annotation/session metadata). +- **Cardinality:** **1 → 1** in the common case (one `treatment` → one manipulation document), **1 → 2** when a recognizable `numeric_value` spawns a companion shape-typed observation. Genuinely-not-a-manipulation rows route **out of tier** (1 → 1 into observation/annotation/session metadata). ## Summary -A `treatment` row carries an ontology identity + an optional number + optional prose. Brainstorm E reads that identity and dispatches the row to the manipulation family whose **action** it names — substance delivery → `injection`/`bath`; physical operation on the body → `procedural_manipulation`; imposed typed quantity → a `scalar_manipulation` (e.g. `temperature_manipulation`); changed condition/regime → `environmental_manipulation` — with focal-vs-ambient and structure carried as **data** (`target_structure`), not as classes. Rows that are not manipulations at all (date of birth, experiment time) are routed out of the manipulation tier. +A `treatment` row carries an ontology identity + an optional number + optional prose. Brainstorm I reads that identity and dispatches the row to the manipulation family whose **action** it names — substance delivery → `injection`/`bath`; physical operation on the body → `procedural_manipulation`; imposed typed quantity → a `scalar_manipulation` (e.g. `temperature_manipulation`); changed condition/regime → `environmental_manipulation`. In the I model the identity itself lands on the **spine** `variable` term (the queryable "what"), the verb on the spine `method`; focal-vs-ambient structure is the spine `target_structure`; and the value/agent is the family's typed data. Rows that are not manipulations at all (date of birth, experiment time) are routed out of the manipulation tier. ## Dispatch table (on `treatment.ontologyName` branch) @@ -19,37 +19,39 @@ First match wins; resolved against the term's ontology branch, not a string matc | `ontologyName` branch | Destination class | Key field mapping | |---|---|---| -| Drug / vehicle / virus / tracer / contrast **delivered by injection** (CHEBI drug branch; OBI injection) | **`injection`** (← `pharmacological_manipulation`) | identity → `mixture` agent; `numeric_value` (if volume) → `volume`; route/coords → curator backfill; `kind` ∈ {drug,virus,tracer,vehicle,contrast} | -| Substance applied **as a bath** | **`bath`** / **`stimulus_bath`** | identity → `mixture`; `location` from prose/backfill | -| Surgical / minor physical **operation on the body** (OBI/NCIT procedure branch — craniotomy, implant, lesion, eye-opening, ear-notch, perfusion) | **`procedural_manipulation`** | identity → `procedure`; structure → `target_structure`; prose → `notes` | -| **Heating / cooling** (thermal) | **`temperature_manipulation`** (← `scalar_manipulation`, `scalar_temperature`) | identity → `applied_property`; thermal `numeric_value` → `value` (typed temperature); focal site → `target_structure` (empty ⇒ ambient) | -| Other **imposed typed quantity** (applied pressure/force, field, frequency) | matching `scalar_manipulation` subclass (`pressure_manipulation`, …) or `generic_scalar_manipulation` | identity → `applied_property`; `numeric_value` → `value` | -| **Environmental / husbandry / behavioral regime** with no typed value (dark rearing, deprivation regime, social isolation, enrichment, light cycle, diet/water restriction, training) | **`environmental_manipulation`** | identity → `factor`; structure (lateralized) → `target_structure`; prose → `notes`; duration → bounded `time_reference` | -| **Not a manipulation** (`Treatment: Date of birth`, `Treatment: Non-survival experiment time`, …) | **out of tier** → `age_observation`/`categorical_observation` (DOB) or session metadata/annotation | per [`ontology_table_row.md`](ontology_table_row.md) routing | +| Drug / vehicle / virus / tracer / contrast **delivered by injection** (CHEBI drug branch; OBI injection) | **`injection`** (← `pharmacological_manipulation`) | identity → spine `variable`; agent → `mixture`; `numeric_value` (if volume) → `volume`; route/coords → curator backfill; `kind` ∈ {drug,virus,tracer,vehicle,contrast} | +| Substance applied **as a bath** | **`bath`** / **`stimulus_bath`** | identity → spine `variable`; agent → `mixture`; `location` from prose/backfill | +| Surgical / minor physical **operation on the body** (OBI/NCIT procedure branch — craniotomy, implant, lesion, eye-opening, ear-notch, perfusion) | **`procedural_manipulation`** | identity → spine `variable` (mirrored in the family `procedure` slot); structure → spine `target_structure`; prose → `notes` | +| **Heating / cooling** (thermal) | **`temperature_manipulation`** (← `scalar_manipulation`, `scalar_temperature`) | identity → spine `variable`; verb → spine `method`; thermal `numeric_value` → `value` (typed temperature array); focal site → spine `target_structure` (empty ⇒ ambient) | +| Other **imposed typed quantity** (applied pressure/force, field, frequency) | matching `scalar_manipulation` subclass (`pressure_manipulation`, …) or `generic_scalar_manipulation` | identity → spine `variable`; `numeric_value` → `value` | +| **Environmental / husbandry / behavioral regime** with no typed value (dark rearing, deprivation regime, social isolation, enrichment, light cycle, diet/water restriction, training) | **`environmental_manipulation`** | identity → spine `variable` (mirrored in the family `factor` slot); structure (lateralized) → spine `target_structure`; prose → `notes`; duration → bounded `time_reference` | +| **Not a manipulation** (`Treatment: Date of birth`, `Treatment: Non-survival experiment time`, …) | **out of tier** → `scalar_duration_observation`/`categorical_observation` (DOB/age) or session metadata/annotation | per [`ontology_table_row.md`](ontology_table_row.md) routing | | Empty / unresolvable `ontologyName` | **curator review queue** (default routing **off**) | flagged, never silently forced into a residual family | ### Edge cases captured from real corpora -- **`string_value` carrying an ontology target, not prose** (the `Dab` treeshrew optogenetic-tetanus rows: `ontologyName = EMPTY:0000074`, `name = "…Target Location"`, `string_value = UBERON CURIE`). Route `string_value` → **`target_structure`** (as `ontology_term`), strip the "Target Location" role-suffix from the procedure/action name, register an NDIC term for the `EMPTY:` placeholder (curator backfill until then). Detection rule: `name` ends in "Target Location" **and/or** `string_value` matches a CURIE pattern. -- **`numeric_value` → companion observation.** A recognizable typed quantity that is *measured*, not the manipulation's own payload (e.g. a training-exposure duration), becomes a companion `scalar_observation` sharing `subject_id` + `time_reference`. Unrecognizable numbers are **flagged, never silently kept** (the `numeric_value` grab-bag is exactly what E retires). +- **`string_value` carrying an ontology target, not prose** (the `Dab` treeshrew optogenetic-tetanus rows: `ontologyName = EMPTY:0000074`, `name = "…Target Location"`, `string_value = UBERON CURIE`). Route `string_value` → **spine `target_structure`** (as `ontology_term`), strip the "Target Location" role-suffix from the action name, register an NDIC term for the `EMPTY:` placeholder (curator backfill until then). Detection rule: `name` ends in "Target Location" **and/or** `string_value` matches a CURIE pattern. +- **`numeric_value` → companion observation.** A recognizable typed quantity that is *measured*, not the manipulation's own payload (e.g. a training-exposure duration), becomes a companion shape-typed observation (`scalar_duration_observation`, …) sharing `subject_id` + `time_reference`, with the property on its `variable`. Unrecognizable numbers are **flagged, never silently kept** (the `numeric_value` grab-bag is exactly what I retires). ## Common field mapping (all manipulation destinations) -| did_v1 field | V_epsilon field | Transformation | +| did_v1 field | V_zeta destination | Transformation | |---|---|---| -| `treatment.ontologyName` + `treatment.name` | the family identity slot (`procedure` / `factor` / `applied_property`; or `mixture` agent) | collapse the two chars into one `ontology_term` (same merge rule as `probe_location`), then place per the dispatch table | -| `treatment.numeric_value` | typed `value` **or** companion `scalar_observation` **or** flagged | per dispatch; thermal/pressure/etc. → typed `value`; measured quantity → companion; else flag | -| `treatment.string_value` | `notes` (prose) **or** `target_structure` (Dab case) | default prose → `notes`; CURIE/Target-Location → `target_structure` | -| `depends_on[subject_id]` | inherited `subject_id` | identity | -| — | inherited `time_reference_#` | **emits a `session_relative_reference`** document (`relation: during`, `depends_on session_id → session` from `base.session_id`) and points `time_reference_1` at it. v1 treatment rows have no epoch and (often) no UTC date, so the honest anchor is ordinal-against-the-session; `during` is the universal fallback (the act happened within the session), `at_end_of` reserved for known-terminal cases. Makes the migration **1 → 2**. | +| `treatment.ontologyName` + `treatment.name` | spine **`variable`** (the queryable identity), + the family's structured slot where one exists (`procedure` for procedural, `factor` for environmental, `mixture` agent for injection/bath) | collapse the two chars into one `ontology_term` (same merge rule as `probe_location`), place on `variable`, and mirror into the family slot per the dispatch table | +| — (the verb) | spine **`method`** | the action verb (apply, inject, heat, lesion); optional, defaulted from the family | +| `treatment.numeric_value` | typed `value` **or** companion observation **or** flagged | per dispatch; thermal/pressure/etc. → typed `value` (an array); measured quantity → companion; else flag | +| `treatment.string_value` | `notes` (prose) **or** spine `target_structure` (Dab case) | default prose → `notes`; CURIE/Target-Location → `target_structure` | +| `depends_on[subject_id]` | inherited spine `subject_id` | identity | +| — | inherited spine `time_reference_#` | **emits a `session_relative_reference`** document (`relation: during`, `depends_on session_id → session` from `base.session_id`) and points `time_reference_1` at it. v1 treatment rows have no epoch and (often) no UTC date, so the honest anchor is ordinal-against-the-session; `during` is the universal fallback, `at_end_of` reserved for known-terminal cases. Makes the migration **1 → 2**. | | `depends_on[manipulation_id]` | — | **dropped** (stale in v1) | | `depends_on[protocol_id]` | — | **dropped + flagged** for the tier-level `protocol_id` commonality (issue #8 Option C / #10) | ## Default values for new fields - `target_structure`: `[]` (empty ⇒ whole-subject/ambient) unless recoverable. +- `variable`: required — the migrator must resolve the collapsed `ontologyName`+`name` term; unresolvable ⇒ review queue. - `kind` (injection): inferred from the agent branch where possible; else curator backfill. -- `time_reference_#`: synthesized; required, so the migrator must produce at least one (a point-in-time reference anchored to the session) and flag for widening. +- `time_reference_#`: synthesized; required, so the migrator must produce at least one (a session-relative reference anchored to the session) and flag for widening. ## Worked example — thermal `treatment` → `temperature_manipulation` @@ -70,7 +72,7 @@ First match wins; resolved against the term's ontology branch, not a string matc } ``` -### After (V_epsilon) +### After (V_zeta) ```json { "document_class": { "class_name": "temperature_manipulation", "class_version": "1.0.0", @@ -81,15 +83,16 @@ First match wins; resolved against the term's ontology branch, not a string matc ], "base": { "id": "aabb1122ccdd3344_1122334455667788", "session_id": "aabb1122ccdd3344_9900aabbccddeeff", "name": "v1_cooling", "datestamp": "2024-06-01T12:00:00.000Z" }, - "scalar_manipulation": { - "applied_property": { "node": "ndic:0000nnnn", "name": "focal cortical cooling" }, - "target_structure": [ { "node": "uberon:0002436", "name": "primary visual cortex" } ], - "notes": "Peltier, V1" + "subject_interaction": { + "method": { "node": "ncit:C60658", "name": "cooling" }, + "variable": { "node": "ndic:0000nnnn", "name": "focal cortical cooling" }, + "target_structure": [ { "node": "uberon:0002436", "name": "primary visual cortex" } ] }, - "scalar_temperature": { "value": { "celsius": 12.0, "source_unit": "°C", "source_value": 12.0, "approximate": false } } + "scalar_manipulation": { "notes": "Peltier, V1" }, + "scalar_temperature": { "value": [ { "celsius": 12.0, "source_unit": "°C", "source_value": 12.0, "approximate": false } ] } } ``` -(`target_structure` here was recovered from `string_value`; `protocol_id`/`manipulation_id` dropped; `time_reference` synthesized.) +(identity → spine `variable`; verb → spine `method`; `target_structure` recovered from `string_value` onto the spine; `applied_property` no longer exists — it is the spine `variable` in the I model; `value` is an array; `protocol_id`/`manipulation_id` dropped; `time_reference` synthesized.) ## File handling @@ -100,9 +103,10 @@ First match wins; resolved against the term's ontology branch, not a string matc - **Per-term branch list.** The dispatch table is branch-level; the concrete `ontologyName` → destination mapping per corpus is finalized in **discovery mode** (run the corpus through the converter, read the quarantine/review report, extend the branch list). Report-only before any rewrite. - **`time_reference` synthesis fidelity.** What session/epoch anchor each corpus exposes; bounded vs point default per family. - **`protocol_id` carryover.** Dropped now; belongs to the tier-level commonality decision (#8 Option C / #10). +- **Family identity slots.** `procedure` / `factor` currently mirror the spine `variable` on the procedural/environmental families; whether to keep them as structured detail or drop them in favour of `variable` alone is an open V_zeta schema question (identity is off-class in Brainstorm I). ## Cross-references - Observation-tier split: [`ontology_table_row.md`](ontology_table_row.md) - Universal renames: [`_universal_renames.md`](_universal_renames.md) -- Design sources (ndi-next-steps): `Procedural_Manipulation_Proposal.md`, `Environmental_Manipulation_Proposal.md`, `Scalar_Manipulation_Proposal.md`, `Injection_Proposal.md`, `Bath_Proposal.md`, `20260615/Brainstorm_E_Class_Catalog.md` §4. +- Design sources (ndi-next-steps): `Procedural_Manipulation_Proposal.md`, `Environmental_Manipulation_Proposal.md`, `Scalar_Manipulation_Proposal.md`, `Injection_Proposal.md`, `Bath_Proposal.md`, `20260615/Brainstorm_I_Tour_and_Comparison.md`. diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md b/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md index 13ef0d8..d3ee52a 100644 --- a/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md +++ b/schemas/V_zeta/conversions/from_did_v1/treatment_drug.md @@ -1,13 +1,13 @@ -# `treatment_drug` → `injection` (`kind: "drug"`) [Brainstorm E] +# `treatment_drug` → `injection` (`kind: "drug"`) [Brainstorm I] Status: **drafted** -`treatment_drug` is **deprecated** in V_epsilon and folds into `injection` +`treatment_drug` is **deprecated** in V_zeta and folds into `injection` (a `pharmacological_manipulation`). ## Mapping (per document, 1 → 2) -| did_v1 `treatment_drug` | V_epsilon | Transformation | +| did_v1 `treatment_drug` | V_zeta | Transformation | |---|---|---| | (class) `treatment_drug` | (class) `injection`, `injection.kind = "drug"` | class fold | | `mixture_table` (CSV) | `pharmacological_manipulation.mixture[]` (`{chemical, amount}`) | best-effort CSV parse; ≥1 record (blank if unparseable) | @@ -24,6 +24,6 @@ are emitted as blank composites (curator-fillable). Branch/field mapping is a **heuristic seed**, finalised in discovery mode. ## Engine -Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to -`+did2/+convert/+migrators_e/treatment_drug.m`. Default `V_delta` target is +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_zeta'` to +`+did2/+convert/+migrators_e/treatment_drug.m`. Default `V_zeta` target is unaffected. diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md index 418386b..367506d 100644 --- a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md +++ b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md @@ -1,13 +1,13 @@ -# `treatment_transfer` → `biological_transfer` [Brainstorm E] +# `treatment_transfer` → `biological_transfer` [Brainstorm I] Status: **drafted** -`treatment_transfer` is **deprecated** in V_epsilon and folds into +`treatment_transfer` is **deprecated** in V_zeta and folds into `biological_transfer` (a `procedural_manipulation`). ## Mapping (per document, 1 → 2) -| did_v1 `treatment_transfer` | V_epsilon | Transformation | +| did_v1 `treatment_transfer` | V_zeta | Transformation | |---|---|---| | (class) `treatment_transfer` | (class) `biological_transfer` | class fold | | `recipient_id` (depends_on) | `subject_id` | the recipient is the subject | @@ -22,6 +22,6 @@ The second emitted document is the shared `session_relative_reference` anchor (`subject_interaction` requires a `time_reference`). ## Engine -Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to -`+did2/+convert/+migrators_e/treatment_transfer.m`. Default `V_delta` +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_zeta'` to +`+did2/+convert/+migrators_e/treatment_transfer.m`. Default `V_zeta` target is unaffected. diff --git a/schemas/V_zeta/conversions/from_did_v1/virus_injection.md b/schemas/V_zeta/conversions/from_did_v1/virus_injection.md index c7b95dd..ed1b56f 100644 --- a/schemas/V_zeta/conversions/from_did_v1/virus_injection.md +++ b/schemas/V_zeta/conversions/from_did_v1/virus_injection.md @@ -1,14 +1,14 @@ -# `virus_injection` → `injection` (`kind: "virus"`) [Brainstorm E] +# `virus_injection` → `injection` (`kind: "virus"`) [Brainstorm I] Status: **drafted** -`virus_injection` is **deprecated** in V_epsilon and folds into `injection` +`virus_injection` is **deprecated** in V_zeta and folds into `injection` (a `pharmacological_manipulation`). Serotype/identity ride in the mixture ontology term; dilution rides in its concentration amount. ## Mapping (per document, 1 → 2) -| did_v1 `virus_injection` | V_epsilon | Transformation | +| did_v1 `virus_injection` | V_zeta | Transformation | |---|---|---| | (class) `virus_injection` | (class) `injection`, `injection.kind = "virus"` | class fold | | `virus_OntologyName` / `virus_name` | `mixture[1].chemical` | ontology_term | @@ -23,6 +23,6 @@ The second emitted document is the shared `session_relative_reference` anchor. `injection.volume` / `route` are emitted blank (curator-fillable). ## Engine -Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_epsilon'` to -`+did2/+convert/+migrators_e/virus_injection.m`. Default `V_delta` target +Routed by `did2.convert.v1_to_v2` under `TargetVersion='V_zeta'` to +`+did2/+convert/+migrators_e/virus_injection.m`. Default `V_zeta` target is unaffected. diff --git a/schemas/V_zeta_notes.md b/schemas/V_zeta_notes.md index 8672b8f..e44dc6e 100644 --- a/schemas/V_zeta_notes.md +++ b/schemas/V_zeta_notes.md @@ -47,7 +47,10 @@ the five deprecated classes carry over from V_epsilon (design-neutral for I). transform (above) was applied. - **202 document classes**: 156 `stable`, 40 `draft`, 6 `deprecated`, + 3 meta. `index.json` `set_version`/`schema_version_value` = `"V_zeta"`; `based_on` = - `"V_delta"`; `legacy_schema_version_values` = `["did_v1", "V_delta"]`. + `"V_delta"` (the format/content ancestor V_zeta's files were copied from); + `legacy_schema_version_values` = `["did_v1"]` — did_v1 is the only production + document version, so it is the sole migration source (V_alpha..V_epsilon never + shipped). - 23 Brainstorm-E classes removed (the property-named observation leaves, `categorical_concept`, `subject_statement`); 13 shape-typed scalar observation leaves authored; `categorical_observation` made concrete; `time_reference` @@ -108,12 +111,18 @@ revisitable while V_zeta is a sandbox: fields; the registry meta-file + `value_set` class are not added. - **`dataSeriesType` registry** (a `probetype2object`-style type→template) and per-element channel-identity materialization — registry/tooling artifacts. -- **Conversion docs.** The `conversions/` tree carries over from V_epsilon - (treatment split, `virus_injection`/`treatment_drug` → `injection`, - `treatment_transfer` → `biological_transfer`, `subject_group` folds). A - `from_v_epsilon/` (or `from_v_delta/`) path documenting the E→I observation-tier - remap (property leaf → shape leaf + `variable`; `measured_property` → `variable`; - `sample_time` → `sampling`) should be added. +- **Conversion docs.** The only production document version is **`did_v1`** (our + first version); V_alpha..V_epsilon were sandbox iterations that never shipped, + so there is nothing to migrate *from* them — `conversions/from_did_v1/` is the + sole conversion tree. It has been **retargeted from V_epsilon (Brainstorm E) to + V_zeta (Brainstorm I)**: the `treatment` split and the `ontology_table_row` + 1→N split now target the shape-typed observation tier + the `(method, variable)` + spine (property leaf → shape leaf + `variable`; the retired `measured_property`/ + `applied_property` → spine `variable`; `sample_time` → the shaped `time_reference`), + and the four folds (`treatment_drug`/`virus_injection` → `injection`, + `treatment_transfer` → `biological_transfer`, `subject_group` → `subject(is_group)`) + target the V_zeta classes. Remaining: finalize each corpus's per-term dispatch in + discovery mode; the migrator itself lands in DID-matlab. - **NDI-matlab / DID-matlab consumer tooling** — resolve V_zeta via `index.json`; emit the shaped `time_reference`; write the record/array channel model + `dataseries_channel_map`; the E→I observation migrator. From a0881152eeda2a398cb844ccdacb4af60afb6463 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 13:28:14 +0000 Subject: [PATCH 3/6] V_zeta: remove pure-identity procedural_/environmental_manipulation; add generic_manipulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Brainstorm I a manipulation is a class only when it adds STRUCTURE (a typed value, a dependency, or an invariant) — identity rides on the spine `variable`. procedural_manipulation and environmental_manipulation carried only an ontology identity field (procedure/factor) + notes, i.e. no distinct structure, so they are pure-identity classes the framework forbids (the manipulation-side mirror of the EPM property-class problem on the observation tier). - Delete procedural_manipulation and environmental_manipulation. - Add generic_manipulation (concrete, <- manipulation): the escape-hatch leaf for payload-free acts (surgical/physical procedures, environmental/husbandry regimes, behavioral training). No typed value; the act is named by the spine `variable`, its ontology branch carrying the coarse kind. Manipulation-side analog of generic_scalar_observation. - Move the shared `notes` prose up to the abstract `manipulation` base so every manipulation inherits it (removed the duplicate from scalar_manipulation). - Re-parent biological_transfer onto `manipulation` (it earns its class via the donor_id dependency). Docs/tests updated: V_zeta_SPEC.md §5 rewritten around "classes earn their place by structure"; treatment.md / treatment_transfer.md / _index.md route procedures and regimes to generic_manipulation and drop the removed classes; V_zeta_notes.md change-list gains the manipulation-tier point; test_vzeta.py asserts the two classes are gone, generic_manipulation is a concrete manipulation leaf, biological_transfer re-parents with donor_id, and notes is inherited. index.json + topics.json regenerated (topics generation made idempotent; the tuning/vm classes V_epsilon left uncategorized are now filed). 201 document classes (155 stable, 40 draft, 6 deprecated) + 3 meta. 514 tests pass; full set validates against the meta-schema. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015zjbvyLbSLMYz1uCizYwQh --- .../V_zeta/conversions/from_did_v1/_index.md | 2 +- .../conversions/from_did_v1/treatment.md | 10 +- .../from_did_v1/treatment_transfer.md | 5 +- schemas/V_zeta/index.json | 41 ++-- .../V_zeta/stable/biological_transfer.json | 4 +- .../stable/environmental_manipulation.json | 50 ----- .../V_zeta/stable/generic_manipulation.json | 15 ++ schemas/V_zeta/stable/manipulation.json | 20 +- .../stable/procedural_manipulation.json | 50 ----- .../V_zeta/stable/scalar_manipulation.json | 20 +- schemas/V_zeta/topics.json | 196 ++++++++++-------- schemas/V_zeta_SPEC.md | 41 +++- schemas/V_zeta_notes.md | 23 +- tests/test_vzeta.py | 18 ++ 14 files changed, 236 insertions(+), 259 deletions(-) delete mode 100644 schemas/V_zeta/stable/environmental_manipulation.json create mode 100644 schemas/V_zeta/stable/generic_manipulation.json delete mode 100644 schemas/V_zeta/stable/procedural_manipulation.json diff --git a/schemas/V_zeta/conversions/from_did_v1/_index.md b/schemas/V_zeta/conversions/from_did_v1/_index.md index a56a1b3..5b0df9b 100644 --- a/schemas/V_zeta/conversions/from_did_v1/_index.md +++ b/schemas/V_zeta/conversions/from_did_v1/_index.md @@ -44,7 +44,7 @@ field-level changes on top. | `hartley_reverse_correlation` | NDIcalc-vis-matlab `neuro/hartley_reverse_correlation` | drafted | [hartley_reverse_correlation.md](hartley_reverse_correlation.md) | | `hartley_calc` | NDIcalc-vis-matlab `calc/hartley_calc` | drafted | [hartley_calc.md](hartley_calc.md) | | `probe_location` | legacy NDI/DID `probe_location` (V_alpha shape) | drafted | [probe_location.md](probe_location.md) | -| `treatment` → manipulation tiers (Brainstorm I **split**) | legacy `treatment` → `injection`/`bath`/`procedural_manipulation`/`temperature_manipulation`/`environmental_manipulation` (+ out-of-tier) | drafted | [treatment.md](treatment.md) | +| `treatment` → manipulation tiers (Brainstorm I **split**) | legacy `treatment` → `injection`/`bath`/`temperature_manipulation` (typed) / `generic_manipulation` (procedures & regimes) (+ out-of-tier) | drafted | [treatment.md](treatment.md) | | `ontology_table_row` → observation tiers (Brainstorm I **split**, 1→N) | legacy `ontology_table_row` → shape-typed scalar/categorical observation classes (+ out-of-tier) | drafted | [ontology_table_row.md](ontology_table_row.md) | | `subject_group` → `subject` (`is_group`) (Brainstorm I **fold**) | legacy `subject_group` → `subject` flagged `is_group` (+ `group_assignment` in NDI layer) | drafted | [subject_group.md](subject_group.md) | | `treatment_drug` → `injection` (`kind: drug`) (Brainstorm I **fold**) | legacy `treatment_drug` → `injection` (mixture from `mixture_table`) | drafted | [treatment_drug.md](treatment_drug.md) | diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment.md b/schemas/V_zeta/conversions/from_did_v1/treatment.md index ce3bacc..d1b2cc7 100644 --- a/schemas/V_zeta/conversions/from_did_v1/treatment.md +++ b/schemas/V_zeta/conversions/from_did_v1/treatment.md @@ -11,7 +11,7 @@ ## Summary -A `treatment` row carries an ontology identity + an optional number + optional prose. Brainstorm I reads that identity and dispatches the row to the manipulation family whose **action** it names — substance delivery → `injection`/`bath`; physical operation on the body → `procedural_manipulation`; imposed typed quantity → a `scalar_manipulation` (e.g. `temperature_manipulation`); changed condition/regime → `environmental_manipulation`. In the I model the identity itself lands on the **spine** `variable` term (the queryable "what"), the verb on the spine `method`; focal-vs-ambient structure is the spine `target_structure`; and the value/agent is the family's typed data. Rows that are not manipulations at all (date of birth, experiment time) are routed out of the manipulation tier. +A `treatment` row carries an ontology identity + an optional number + optional prose. Brainstorm I reads that identity and dispatches the row by the **structure** its data needs — substance delivery → `injection`/`bath`; imposed typed quantity → a `scalar_manipulation` (e.g. `temperature_manipulation`); a payload-free physical procedure or an environmental/husbandry regime → **`generic_manipulation`** (no structural class of its own — a procedure and a regime differ only in identity, which the framework keeps off the class). In the I model the identity always lands on the **spine** `variable` term (the queryable "what"), the verb on the spine `method`; focal-vs-ambient structure is the spine `target_structure`; and the value/agent is the family's typed data. Rows that are not manipulations at all (date of birth, experiment time) are routed out of the manipulation tier. ## Dispatch table (on `treatment.ontologyName` branch) @@ -21,10 +21,10 @@ First match wins; resolved against the term's ontology branch, not a string matc |---|---|---| | Drug / vehicle / virus / tracer / contrast **delivered by injection** (CHEBI drug branch; OBI injection) | **`injection`** (← `pharmacological_manipulation`) | identity → spine `variable`; agent → `mixture`; `numeric_value` (if volume) → `volume`; route/coords → curator backfill; `kind` ∈ {drug,virus,tracer,vehicle,contrast} | | Substance applied **as a bath** | **`bath`** / **`stimulus_bath`** | identity → spine `variable`; agent → `mixture`; `location` from prose/backfill | -| Surgical / minor physical **operation on the body** (OBI/NCIT procedure branch — craniotomy, implant, lesion, eye-opening, ear-notch, perfusion) | **`procedural_manipulation`** | identity → spine `variable` (mirrored in the family `procedure` slot); structure → spine `target_structure`; prose → `notes` | +| Surgical / minor physical **operation on the body** (OBI/NCIT procedure branch — craniotomy, implant, lesion, eye-opening, ear-notch, perfusion) | **`generic_manipulation`** | identity → spine `variable`; structure → spine `target_structure`; prose → inherited `notes` | | **Heating / cooling** (thermal) | **`temperature_manipulation`** (← `scalar_manipulation`, `scalar_temperature`) | identity → spine `variable`; verb → spine `method`; thermal `numeric_value` → `value` (typed temperature array); focal site → spine `target_structure` (empty ⇒ ambient) | | Other **imposed typed quantity** (applied pressure/force, field, frequency) | matching `scalar_manipulation` subclass (`pressure_manipulation`, …) or `generic_scalar_manipulation` | identity → spine `variable`; `numeric_value` → `value` | -| **Environmental / husbandry / behavioral regime** with no typed value (dark rearing, deprivation regime, social isolation, enrichment, light cycle, diet/water restriction, training) | **`environmental_manipulation`** | identity → spine `variable` (mirrored in the family `factor` slot); structure (lateralized) → spine `target_structure`; prose → `notes`; duration → bounded `time_reference` | +| **Environmental / husbandry / behavioral regime** with no typed value (dark rearing, deprivation regime, social isolation, enrichment, light cycle, diet/water restriction, training) | **`generic_manipulation`** | identity → spine `variable`; structure (lateralized) → spine `target_structure`; prose → inherited `notes`; duration → bounded `time_reference` | | **Not a manipulation** (`Treatment: Date of birth`, `Treatment: Non-survival experiment time`, …) | **out of tier** → `scalar_duration_observation`/`categorical_observation` (DOB/age) or session metadata/annotation | per [`ontology_table_row.md`](ontology_table_row.md) routing | | Empty / unresolvable `ontologyName` | **curator review queue** (default routing **off**) | flagged, never silently forced into a residual family | @@ -37,7 +37,7 @@ First match wins; resolved against the term's ontology branch, not a string matc | did_v1 field | V_zeta destination | Transformation | |---|---|---| -| `treatment.ontologyName` + `treatment.name` | spine **`variable`** (the queryable identity), + the family's structured slot where one exists (`procedure` for procedural, `factor` for environmental, `mixture` agent for injection/bath) | collapse the two chars into one `ontology_term` (same merge rule as `probe_location`), place on `variable`, and mirror into the family slot per the dispatch table | +| `treatment.ontologyName` + `treatment.name` | spine **`variable`** (the queryable identity); the `mixture` agent for injection/bath | collapse the two chars into one `ontology_term` (same merge rule as `probe_location`) and place on `variable`; for injection/bath the agent term also seeds `mixture` | | — (the verb) | spine **`method`** | the action verb (apply, inject, heat, lesion); optional, defaulted from the family | | `treatment.numeric_value` | typed `value` **or** companion observation **or** flagged | per dispatch; thermal/pressure/etc. → typed `value` (an array); measured quantity → companion; else flag | | `treatment.string_value` | `notes` (prose) **or** spine `target_structure` (Dab case) | default prose → `notes`; CURIE/Target-Location → `target_structure` | @@ -103,7 +103,7 @@ First match wins; resolved against the term's ontology branch, not a string matc - **Per-term branch list.** The dispatch table is branch-level; the concrete `ontologyName` → destination mapping per corpus is finalized in **discovery mode** (run the corpus through the converter, read the quarantine/review report, extend the branch list). Report-only before any rewrite. - **`time_reference` synthesis fidelity.** What session/epoch anchor each corpus exposes; bounded vs point default per family. - **`protocol_id` carryover.** Dropped now; belongs to the tier-level commonality decision (#8 Option C / #10). -- **Family identity slots.** `procedure` / `factor` currently mirror the spine `variable` on the procedural/environmental families; whether to keep them as structured detail or drop them in favour of `variable` alone is an open V_zeta schema question (identity is off-class in Brainstorm I). +- **`generic_manipulation` coarse kind.** Procedures and environmental regimes both land in `generic_manipulation`, distinguished only by the `variable` ontology branch. Whether a coarse queryable `kind` facet (procedure vs regime vs husbandry) is worth adding — vs. relying on `variable`'s branch — is open; the default is to rely on the branch (no facet). ## Cross-references diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md index 367506d..ec60c0a 100644 --- a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md +++ b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md @@ -3,7 +3,8 @@ Status: **drafted** `treatment_transfer` is **deprecated** in V_zeta and folds into -`biological_transfer` (a `procedural_manipulation`). +`biological_transfer` (a `manipulation` that earns its class via the +`donor_id` dependency). ## Mapping (per document, 1 → 2) @@ -13,7 +14,7 @@ Status: **drafted** | `recipient_id` (depends_on) | `subject_id` | the recipient is the subject | | `donor_id` (depends_on) | `biological_transfer` donor dependency (`donor_id`) | carried | | `entity_ontologyNode` / `entity_name` | `biological_transfer.entity` | ontology_term | -| `method_ontologyNode` / `method_name` | `procedural_manipulation.procedure` | ontology_term | +| `method_ontologyNode` / `method_name` | spine `variable` (the transfer act) / spine `method` | ontology_term | | `method_name` | `biological_transfer.kind` | char (fallback `"transfer"`) | | `timestamp` / `clocktype` | (timing) | ordinal `session_relative_reference` (`during`) for now; UTC/event refinement is a follow-up | | `base.*` | `base.*` | carried (same id) | diff --git a/schemas/V_zeta/index.json b/schemas/V_zeta/index.json index 503c508..ca9af0f 100644 --- a/schemas/V_zeta/index.json +++ b/schemas/V_zeta/index.json @@ -108,10 +108,10 @@ { "class_name": "biological_transfer", "tier": "stable", - "class_version": "1.0.0", + "class_version": "2.0.0", "maturity_level": "stable", "superclasses": [ - "procedural_manipulation" + "manipulation" ], "path": "schemas/V_zeta/stable/biological_transfer.json", "is_meta": false @@ -427,17 +427,6 @@ "path": "schemas/V_zeta/stable/element_epoch.json", "is_meta": false }, - { - "class_name": "environmental_manipulation", - "tier": "stable", - "class_version": "1.0.0", - "maturity_level": "stable", - "superclasses": [ - "manipulation" - ], - "path": "schemas/V_zeta/stable/environmental_manipulation.json", - "is_meta": false - }, { "class_name": "ephys_zarr", "tier": "stable", @@ -751,6 +740,17 @@ "path": "schemas/V_zeta/stable/generic_file.json", "is_meta": false }, + { + "class_name": "generic_manipulation", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "manipulation" + ], + "path": "schemas/V_zeta/stable/generic_manipulation.json", + "is_meta": false + }, { "class_name": "generic_scalar", "tier": "stable", @@ -950,7 +950,7 @@ { "class_name": "manipulation", "tier": "stable", - "class_version": "1.0.0", + "class_version": "2.0.0", "maturity_level": "stable", "superclasses": [ "subject_interaction" @@ -1213,17 +1213,6 @@ "path": "schemas/V_zeta/stable/probe_location.json", "is_meta": false }, - { - "class_name": "procedural_manipulation", - "tier": "stable", - "class_version": "1.0.0", - "maturity_level": "stable", - "superclasses": [ - "manipulation" - ], - "path": "schemas/V_zeta/stable/procedural_manipulation.json", - "is_meta": false - }, { "class_name": "projectvar", "tier": "deprecated", @@ -1499,7 +1488,7 @@ { "class_name": "scalar_manipulation", "tier": "stable", - "class_version": "2.0.0", + "class_version": "3.0.0", "maturity_level": "stable", "superclasses": [ "manipulation" diff --git a/schemas/V_zeta/stable/biological_transfer.json b/schemas/V_zeta/stable/biological_transfer.json index 2bd88f8..756019e 100644 --- a/schemas/V_zeta/stable/biological_transfer.json +++ b/schemas/V_zeta/stable/biological_transfer.json @@ -1,10 +1,10 @@ { "document_class": { "class_name": "biological_transfer", - "class_version": "1.0.0", + "class_version": "2.0.0", "superclasses": [ { - "class_name": "procedural_manipulation" + "class_name": "manipulation" } ], "maturity_level": "stable" diff --git a/schemas/V_zeta/stable/environmental_manipulation.json b/schemas/V_zeta/stable/environmental_manipulation.json deleted file mode 100644 index 7fe17ca..0000000 --- a/schemas/V_zeta/stable/environmental_manipulation.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "document_class": { - "class_name": "environmental_manipulation", - "class_version": "1.0.0", - "superclasses": [ - { - "class_name": "manipulation" - } - ], - "maturity_level": "stable" - }, - "depends_on": [], - "file": [], - "fields": [ - { - "name": "factor", - "type": "ontology_term", - "blank_value": { - "node": "", - "name": "" - }, - "default_value": { - "node": "", - "name": "" - }, - "mustBeNonEmpty": true, - "mustBeScalar": true, - "mustNotHaveNaN": false, - "queryable": true, - "ontology": null, - "documentation": "The environmental factor/regime (dark rearing, deprivation, enrichment, restriction, training, ...).", - "constraints": {} - }, - { - "name": "notes", - "type": "char", - "blank_value": "", - "default_value": "", - "mustBeNonEmpty": false, - "mustBeScalar": true, - "mustNotHaveNaN": false, - "queryable": false, - "ontology": null, - "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", - "constraints": { - "maxLength": 4096 - } - } - ] -} diff --git a/schemas/V_zeta/stable/generic_manipulation.json b/schemas/V_zeta/stable/generic_manipulation.json new file mode 100644 index 0000000..3605cda --- /dev/null +++ b/schemas/V_zeta/stable/generic_manipulation.json @@ -0,0 +1,15 @@ +{ + "document_class": { + "class_name": "generic_manipulation", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "manipulation" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [], + "fields": [] +} diff --git a/schemas/V_zeta/stable/manipulation.json b/schemas/V_zeta/stable/manipulation.json index 0022442..be71ce4 100644 --- a/schemas/V_zeta/stable/manipulation.json +++ b/schemas/V_zeta/stable/manipulation.json @@ -1,7 +1,7 @@ { "document_class": { "class_name": "manipulation", - "class_version": "1.0.0", + "class_version": "2.0.0", "superclasses": [ { "class_name": "subject_interaction" @@ -12,5 +12,21 @@ }, "depends_on": [], "file": [], - "fields": [] + "fields": [ + { + "name": "notes", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", + "constraints": { + "maxLength": 4096 + } + } + ] } diff --git a/schemas/V_zeta/stable/procedural_manipulation.json b/schemas/V_zeta/stable/procedural_manipulation.json deleted file mode 100644 index 16e66a0..0000000 --- a/schemas/V_zeta/stable/procedural_manipulation.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "document_class": { - "class_name": "procedural_manipulation", - "class_version": "1.0.0", - "superclasses": [ - { - "class_name": "manipulation" - } - ], - "maturity_level": "stable" - }, - "depends_on": [], - "file": [], - "fields": [ - { - "name": "procedure", - "type": "ontology_term", - "blank_value": { - "node": "", - "name": "" - }, - "default_value": { - "node": "", - "name": "" - }, - "mustBeNonEmpty": true, - "mustBeScalar": true, - "mustNotHaveNaN": false, - "queryable": true, - "ontology": null, - "documentation": "The procedure performed (OBI/NCIT surgery & procedure branches; NDIC fallback).", - "constraints": {} - }, - { - "name": "notes", - "type": "char", - "blank_value": "", - "default_value": "", - "mustBeNonEmpty": false, - "mustBeScalar": true, - "mustNotHaveNaN": false, - "queryable": false, - "ontology": null, - "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", - "constraints": { - "maxLength": 4096 - } - } - ] -} diff --git a/schemas/V_zeta/stable/scalar_manipulation.json b/schemas/V_zeta/stable/scalar_manipulation.json index 2da6736..90d3104 100644 --- a/schemas/V_zeta/stable/scalar_manipulation.json +++ b/schemas/V_zeta/stable/scalar_manipulation.json @@ -1,7 +1,7 @@ { "document_class": { "class_name": "scalar_manipulation", - "class_version": "2.0.0", + "class_version": "3.0.0", "superclasses": [ { "class_name": "manipulation" @@ -12,21 +12,5 @@ }, "depends_on": [], "file": [], - "fields": [ - { - "name": "notes", - "type": "char", - "blank_value": "", - "default_value": "", - "mustBeNonEmpty": false, - "mustBeScalar": true, - "mustNotHaveNaN": false, - "queryable": false, - "ontology": null, - "documentation": "Irreducible human prose describing this event. Documentation, not queryable structured data.", - "constraints": { - "maxLength": 4096 - } - } - ] + "fields": [] } diff --git a/schemas/V_zeta/topics.json b/schemas/V_zeta/topics.json index 6d766f8..7b33dbe 100644 --- a/schemas/V_zeta/topics.json +++ b/schemas/V_zeta/topics.json @@ -12,7 +12,8 @@ "CURIE_lookups_meta", "did_schema_meta", "ndi_reserved_keys" - ] + ], + "topics": [] }, { "name": "annotations", @@ -20,7 +21,8 @@ "classes": [ "group_assignment", "interaction_purpose" - ] + ], + "topics": [] }, { "name": "apps", @@ -50,7 +52,8 @@ "vmspikesummary" ] } - ] + ], + "topics": [] }, { "name": "calculators", @@ -67,7 +70,8 @@ "temporal_frequency_tuning_calc", "tuning_fit", "tuningcurve_calc" - ] + ], + "topics": [] }, { "name": "daq", @@ -88,7 +92,8 @@ "syncgraph", "syncrule", "syncrule_mapping" - ] + ], + "topics": [] }, { "name": "data", @@ -111,49 +116,52 @@ "ngrid", "ontology_table_row", "position_metadata", + "valid_interval", "zarr" - ] + ], + "topics": [] }, { "name": "dataseries_bodies", "description": "Body-of-record documents carrying dataseries and expression/reference payloads.", "classes": [ - "dataseries_data", - "timeseries_data", - "imageseries_data", - "timeseries_data_csv", - "timeseries_data_binary", - "timeseries_data_edf", "dataseries_channel_map", + "dataseries_data", "dataseries_pyramid", - "instrument", "expression_matrix_data", - "expression_matrix_data_h5ad", - "expression_matrix_data_mtx", "expression_matrix_data_cellranger_h5", - "expression_matrix_data_loom", "expression_matrix_data_counts_table", + "expression_matrix_data_dia_report", "expression_matrix_data_gef", "expression_matrix_data_gem", - "expression_matrix_data_visium", + "expression_matrix_data_h5ad", + "expression_matrix_data_imzml", + "expression_matrix_data_loom", + "expression_matrix_data_maxquant", + "expression_matrix_data_mtx", "expression_matrix_data_mzml", "expression_matrix_data_mztab", - "expression_matrix_data_maxquant", - "expression_matrix_data_dia_report", - "expression_matrix_data_imzml", + "expression_matrix_data_visium", + "imageseries_data", + "instrument", + "reference_annotation_data", + "reference_annotation_data_gff3", + "reference_annotation_data_gtf", "reference_data", "reference_sequence_data", "reference_sequence_data_fasta_genome", - "reference_sequence_data_fasta_transcriptome", "reference_sequence_data_fasta_protein", - "reference_annotation_data", - "reference_annotation_data_gtf", - "reference_annotation_data_gff3", + "reference_sequence_data_fasta_transcriptome", "sequence_read_data", "sequence_read_data_bam", "sequence_read_data_cram", - "sequence_read_data_fastq" - ] + "sequence_read_data_fastq", + "timeseries_data", + "timeseries_data_binary", + "timeseries_data_csv", + "timeseries_data_edf" + ], + "topics": [] }, { "name": "deprecated", @@ -165,7 +173,8 @@ "treatment_drug", "treatment_transfer", "virus_injection" - ] + ], + "topics": [] }, { "name": "element", @@ -174,27 +183,28 @@ "element", "element_epoch", "neuron_extracellular" - ] + ], + "topics": [] }, { "name": "manipulations", "description": "Manipulation families: scalar, procedural, pharmacological, environmental, stimulus, placement, and derivation events.", "classes": [ - "scalar_manipulation", - "temperature_manipulation", - "pressure_manipulation", + "bath", + "biological_transfer", + "derivation", "frequency_manipulation", + "generic_manipulation", "generic_scalar_manipulation", - "procedural_manipulation", - "biological_transfer", - "environmental_manipulation", - "pharmacological_manipulation", "injection", - "bath", - "stimulus_manipulation", + "pharmacological_manipulation", "placement", - "derivation" - ] + "pressure_manipulation", + "scalar_manipulation", + "stimulus_manipulation", + "temperature_manipulation" + ], + "topics": [] }, { "name": "metadata", @@ -207,7 +217,8 @@ "openminds_element", "openminds_stimulus", "openminds_subject" - ] + ], + "topics": [] }, { "name": "shape_library", @@ -246,22 +257,36 @@ "scalar_volume_observation", "spatial_expression_observation", "timeseries_observation" - ] + ], + "topics": [] }, { "name": "observations", "description": "Observation families (Brainstorm E): scalar observations named by property, categorical observations named by property, dataseries/image/expression measurements of subjects.", "classes": [ - "observation", - "scalar_observation", - "generic_scalar_observation", "categorical_observation", "dataseries_observation", - "timeseries_observation", - "imageseries_observation", "expression_observation", - "spatial_expression_observation" - ] + "generic_scalar_observation", + "imageseries_observation", + "observation", + "scalar_concentration_observation", + "scalar_count_observation", + "scalar_current_observation", + "scalar_duration_observation", + "scalar_frequency_observation", + "scalar_length_observation", + "scalar_mass_observation", + "scalar_observation", + "scalar_pressure_observation", + "scalar_score_observation", + "scalar_temperature_observation", + "scalar_voltage_observation", + "scalar_volume_observation", + "spatial_expression_observation", + "timeseries_observation" + ], + "topics": [] }, { "name": "probe", @@ -271,7 +296,8 @@ "probe_geometry", "probe_location", "site2channelmap" - ] + ], + "topics": [] }, { "name": "session", @@ -281,9 +307,10 @@ "dataset_session_info", "projectvar", "session", - "session_in_a_dataset", - "session_extent" - ] + "session_extent", + "session_in_a_dataset" + ], + "topics": [] }, { "name": "sorting", @@ -295,15 +322,25 @@ "spike_extraction_parameters", "spike_extraction_parameters_modification", "spike_interface_sorting_outputs", - "spikewaves" - ] + "spikewaves", + "vmneuralresponseresiduals", + "vmspikefilteringparameters", + "vmspikefit", + "vmspikesummary" + ], + "topics": [] }, { "name": "stimulus", "description": "Stimulus descriptions, presentations, and stimulus-locked responses.", "classes": [ + "contrast_tuning", "control_stimulus_ids", + "hartley_reverse_correlation", + "orientation_direction_tuning", "reverse_correlation", + "spatial_frequency_tuning", + "speed_tuning", "stimulus_approach", "stimulus_bath", "stimulus_parameter", @@ -313,7 +350,8 @@ "stimulus_response_scalar", "stimulus_response_scalar_parameters", "stimulus_response_scalar_parameters_basic", - "stimulus_tuningcurve" + "stimulus_tuningcurve", + "temporal_frequency_tuning" ], "children": [ { @@ -328,7 +366,8 @@ "temporal_frequency_tuning" ] } - ] + ], + "topics": [] }, { "name": "subject", @@ -339,54 +378,41 @@ "treatment", "treatment_drug", "virus_injection" - ] + ], + "topics": [] }, { "name": "subject_statement", "description": "Timeless documented claims about a subject (Subject_Statement_Decision): the abstract subject_statement supertype and the concrete subject_assertion (asserted_property + value + source).", "classes": [ "subject_assertion" - ] + ], + "topics": [] }, { "name": "subject_interaction", "description": "The unified subject_interaction spine and its observation/manipulation/annotation tiers.", "classes": [ - "subject_interaction", - "observation", + "annotation", "manipulation", - "annotation" - ] + "observation", + "subject_interaction" + ], + "topics": [] }, { "name": "time_reference", "description": "Time reference documents that locate interactions in time.", "classes": [ - "time_reference", - "utc_reference", - "event_relative_reference", - "epoch_relative_reference", "epoch_bounded_reference", + "epoch_relative_reference", "event_bounded_reference", - "session_relative_reference" - ] - }, - { - "name": "unfiled_vzeta", - "description": "Classes added/renamed in V_zeta not yet hand-placed in the topic tree.", - "classes": [ - "contrast_tuning", - "hartley_reverse_correlation", - "orientation_direction_tuning", - "spatial_frequency_tuning", - "speed_tuning", - "temporal_frequency_tuning", - "valid_interval", - "vmneuralresponseresiduals", - "vmspikefilteringparameters", - "vmspikefit", - "vmspikesummary" - ] + "event_relative_reference", + "session_relative_reference", + "time_reference", + "utc_reference" + ], + "topics": [] } ] } diff --git a/schemas/V_zeta_SPEC.md b/schemas/V_zeta_SPEC.md index b136cf3..21ca526 100644 --- a/schemas/V_zeta_SPEC.md +++ b/schemas/V_zeta_SPEC.md @@ -170,17 +170,36 @@ class; the property is the `variable` term. channel-model decision. `expression_observation` / `spatial_expression_observation` (omics endpoints) carry over. -### 5. Manipulation, annotation, and event classes (carried, retargeted) - -The manipulation families are already action/shape-named in H/I and carry over -unchanged except that the spine-owned `target_structure` field is stripped from -those that declared it (it is now inherited): `scalar_manipulation` → -`temperature_manipulation` / `pressure_manipulation` / `frequency_manipulation` -/ `generic_scalar_manipulation`; `procedural_manipulation` → `biological_transfer`; -`environmental_manipulation`; `pharmacological_manipulation` → `injection` / -`bath` (+ `stimulus_bath`); `stimulus_manipulation`. Event-sourced relations -`placement`, `derivation`, `group_assignment`, and the standalone -`interaction_purpose` / `instrument` / re-scoped `stimulus_approach` carry over. +### 5. Manipulation tier — classes earn their place by STRUCTURE + +Symmetric with the observation tier: a manipulation is a class only when it adds +**structure** (a typed value, a dependency, or an invariant), never for identity +alone — the identity is the spine `variable` term. The abstract `manipulation` +direction class hosts a shared `notes` prose field; concrete leaves: + +- `scalar_manipulation` (abstract) → `temperature_manipulation` / + `pressure_manipulation` / `frequency_manipulation` / + `generic_scalar_manipulation` — impose a **typed value**. +- `pharmacological_manipulation` (abstract) → `injection` / `bath` + (+ `stimulus_bath`) — carry a `mixture` + delivery structure. +- `biological_transfer` — earns its class via the `donor_id` **dependency** + (re-parented directly onto `manipulation`). +- `stimulus_manipulation` — a `stimulus_presentation_id` dependency. +- `generic_manipulation` (concrete) — the escape-hatch leaf for payload-free + acts: surgical/physical procedures, environmental/husbandry regimes, + behavioral training. No typed value, no extra structure; the specific act is + the spine `variable`, its ontology branch (OBI/NCIT procedure vs husbandry) + carrying the coarse kind. This is the manipulation-side analog of + `generic_scalar_observation`. + +**`procedural_manipulation` and `environmental_manipulation` do NOT exist** — +they were pure-identity classes (only an ontology `procedure`/`factor` + `notes`, +no distinct structure), which the framework forbids; they fold into +`generic_manipulation` with the act named by `variable`. The spine-owned +`target_structure` is stripped from every family that declared it (now +inherited). Event-sourced relations `placement`, `derivation`, +`group_assignment` (← `annotation`), and the standalone `interaction_purpose` / +`instrument` / re-scoped `stimulus_approach` carry over. ### 6. Preserved infrastructure diff --git a/schemas/V_zeta_notes.md b/schemas/V_zeta_notes.md index e44dc6e..3968ea4 100644 --- a/schemas/V_zeta_notes.md +++ b/schemas/V_zeta_notes.md @@ -36,16 +36,26 @@ restorations."* Concretely, versus V_epsilon: 5. **Dataseries branch** (`dataseries_observation` → `timeseries_` / `imageseries_observation`) is retained from the E draft as the observation-tier handle for acquired data. - -The manipulation families, `time_reference` reference frames, dataseries/ -expression bodies, the scalar/categorical shape library, all infrastructure, and -the five deprecated classes carry over from V_epsilon (design-neutral for I). +6. **Manipulation tier by structure, not identity.** The same off-class rule is + applied to manipulations: a class exists only when it adds structure (a typed + value, a dependency, an invariant). The pure-identity `procedural_manipulation` + and `environmental_manipulation` (only an ontology `procedure`/`factor` + prose) + are **removed** and fold into a new concrete `generic_manipulation` + escape-hatch leaf (the manipulation-side analog of `generic_scalar_observation`); + the act is named by the spine `variable`. Shared `notes` prose moves up to the + abstract `manipulation` base; `biological_transfer` re-parents onto + `manipulation` (it earns its class via the `donor_id` dependency). + +The typed manipulation families (`injection`/`bath`/`scalar_manipulation` tier), +`time_reference` reference frames, dataseries/expression bodies, the +scalar/categorical shape library, all infrastructure, and the five deprecated +classes carry over from V_epsilon (design-neutral for I). ## Initial state - V_zeta content began as a verbatim copy of V_epsilon, then the Brainstorm-I transform (above) was applied. -- **202 document classes**: 156 `stable`, 40 `draft`, 6 `deprecated`, + 3 meta. +- **201 document classes**: 155 `stable`, 40 `draft`, 6 `deprecated`, + 3 meta. `index.json` `set_version`/`schema_version_value` = `"V_zeta"`; `based_on` = `"V_delta"` (the format/content ancestor V_zeta's files were copied from); `legacy_schema_version_values` = `["did_v1"]` — did_v1 is the only production @@ -59,8 +69,7 @@ the five deprecated classes carry over from V_epsilon (design-neutral for I). - Every schema validates against `did_schema_meta.json`; `index.json` agrees with disk (tier/maturity/path); every superclass and `must_refer_to_document_class` resolves; the spine composes onto every interaction leaf; no - `placement:concrete_class` collisions. Enforced by `tests/test_vzeta.py` - (411 parametrized cases) and validated by the full suite (515 tests pass). + `placement:concrete_class` collisions. Enforced by `tests/test_vzeta.py` and validated by the full suite (515 tests pass). ## Decisions taken where the source proposals were open diff --git a/tests/test_vzeta.py b/tests/test_vzeta.py index 8dacece..b8e6682 100644 --- a/tests/test_vzeta.py +++ b/tests/test_vzeta.py @@ -143,6 +143,24 @@ def test_no_brainstorm_e_property_leaves(): assert gone not in RECORDS, f"{gone} should not exist in V_zeta" +def test_no_pure_identity_manipulation_classes(): + """A manipulation is a class only when it adds STRUCTURE; the pure-identity + procedural_/environmental_manipulation classes fold into generic_manipulation.""" + for gone in ["procedural_manipulation", "environmental_manipulation"]: + assert gone not in RECORDS, f"{gone} is pure-identity; must not exist" + # the payload-free escape hatch exists and is a concrete manipulation leaf + assert "generic_manipulation" in RECORDS + assert "manipulation" in _chain("generic_manipulation") + assert RECORDS["generic_manipulation"][1]["document_class"].get("abstract") is not True + # biological_transfer earns its class via donor_id and re-parents onto manipulation + assert RECORDS["biological_transfer"][1]["document_class"]["superclasses"] == \ + [{"class_name": "manipulation"}] + assert "donor_id" in _flat_dep_names("biological_transfer") + # shared prose lives on the abstract manipulation base (inherited by all leaves) + assert _flat_field_types("generic_manipulation").get("notes") == "char" + assert _flat_field_types("injection").get("notes") == "char" + + def test_sample_time_retired(): """Series timing lives in the shaped time_reference, not a sample_time array.""" for name in ["scalar_observation", "scalar_manipulation"]: From 51d3fa573d5be0a9f35816d00f9c721d3a00ba57 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 13:31:51 +0000 Subject: [PATCH 4/6] V_zeta: drop biological_transfer.entity (identity is the spine variable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The transferred material was carried in biological_transfer.entity, which duplicated the spine `variable` (the noun/identity). Remove it: biological_transfer is now `donor_id` (dependency) + `kind` (coarse bucket) — the structure that earns its class — with the specific material named by the spine `variable`. Updates the treatment_transfer conversion mapping (entity term -> variable). class_version 3.0.0. 514 tests pass; full set validates. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015zjbvyLbSLMYz1uCizYwQh --- .../from_did_v1/treatment_transfer.md | 2 +- schemas/V_zeta/index.json | 2 +- .../V_zeta/stable/biological_transfer.json | 21 +------------------ 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md index ec60c0a..5bc7b1b 100644 --- a/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md +++ b/schemas/V_zeta/conversions/from_did_v1/treatment_transfer.md @@ -13,7 +13,7 @@ Status: **drafted** | (class) `treatment_transfer` | (class) `biological_transfer` | class fold | | `recipient_id` (depends_on) | `subject_id` | the recipient is the subject | | `donor_id` (depends_on) | `biological_transfer` donor dependency (`donor_id`) | carried | -| `entity_ontologyNode` / `entity_name` | `biological_transfer.entity` | ontology_term | +| `entity_ontologyNode` / `entity_name` | spine `variable` (the transferred material) | ontology_term | | `method_ontologyNode` / `method_name` | spine `variable` (the transfer act) / spine `method` | ontology_term | | `method_name` | `biological_transfer.kind` | char (fallback `"transfer"`) | | `timestamp` / `clocktype` | (timing) | ordinal `session_relative_reference` (`during`) for now; UTC/event refinement is a follow-up | diff --git a/schemas/V_zeta/index.json b/schemas/V_zeta/index.json index ca9af0f..946b921 100644 --- a/schemas/V_zeta/index.json +++ b/schemas/V_zeta/index.json @@ -108,7 +108,7 @@ { "class_name": "biological_transfer", "tier": "stable", - "class_version": "2.0.0", + "class_version": "3.0.0", "maturity_level": "stable", "superclasses": [ "manipulation" diff --git a/schemas/V_zeta/stable/biological_transfer.json b/schemas/V_zeta/stable/biological_transfer.json index 756019e..3fa97c7 100644 --- a/schemas/V_zeta/stable/biological_transfer.json +++ b/schemas/V_zeta/stable/biological_transfer.json @@ -1,7 +1,7 @@ { "document_class": { "class_name": "biological_transfer", - "class_version": "2.0.0", + "class_version": "3.0.0", "superclasses": [ { "class_name": "manipulation" @@ -19,25 +19,6 @@ ], "file": [], "fields": [ - { - "name": "entity", - "type": "ontology_term", - "blank_value": { - "node": "", - "name": "" - }, - "default_value": { - "node": "", - "name": "" - }, - "mustBeNonEmpty": true, - "mustBeScalar": true, - "mustNotHaveNaN": false, - "queryable": true, - "ontology": null, - "documentation": "The biological material transferred (UBERON/CL/NDIC).", - "constraints": {} - }, { "name": "kind", "type": "char", From 32e9fded99a80dc8a9c7f47863a0f3247d1ebb88 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 19:57:11 +0000 Subject: [PATCH 5/6] V_zeta: add optional element_id to subject_interaction; drop redundant session_id edge Two Brainstorm-I spine refinements: 1. element_id (individuated referent). subject_interaction gains an optional element_id -> element dependency, all the way up on the abstract spine so every observation/manipulation leaf inherits it. It names the specific element that is part of the subject (an ndi.neuron, a probe, a derived signal) when that entity has its own document identity and is neither a subject_group nor an anatomy term -- the case target_structure (a KIND of place) cannot address. Completes the spine referent set: subject_id (whole specimen) / target_structure (ontological kind of locus) / element_id (which specific one). Optional; identity stays off the class (the EPM lesson). 2. session_relative_reference declares no session_id edge. Session identity rides on base.session_id (every document carries it), so the ordinal anchor needs no session_id dependency. The edge was redundant with base and produced only discovery-mode reference-integrity orphans -- the migrators synthesize thousands of these anchors and the session document is absent from a corpus dump, so each dangled (~41k JH, ~8k Dab). The real ndi.migrate.local path is unaffected (it referenced the session via base the same way). SPEC (new S3.1), notes, and tests updated; V_zeta suite green (412). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015zjbvyLbSLMYz1uCizYwQh --- .../stable/session_relative_reference.json | 9 +---- .../V_zeta/stable/subject_interaction.json | 7 ++++ schemas/V_zeta_SPEC.md | 34 +++++++++++++++++++ schemas/V_zeta_notes.md | 22 ++++++++++++ tests/test_vzeta.py | 27 +++++++++++++++ 5 files changed, 91 insertions(+), 8 deletions(-) diff --git a/schemas/V_zeta/stable/session_relative_reference.json b/schemas/V_zeta/stable/session_relative_reference.json index 5da709d..7937f75 100644 --- a/schemas/V_zeta/stable/session_relative_reference.json +++ b/schemas/V_zeta/stable/session_relative_reference.json @@ -9,14 +9,7 @@ ], "maturity_level": "stable" }, - "depends_on": [ - { - "name": "session_id", - "mustBeNonEmpty": true, - "documentation": "The session this reference is ordinally relative to.", - "must_refer_to_document_class": "session" - } - ], + "depends_on": [], "file": [], "fields": [ { diff --git a/schemas/V_zeta/stable/subject_interaction.json b/schemas/V_zeta/stable/subject_interaction.json index a9444b4..8e0735d 100644 --- a/schemas/V_zeta/stable/subject_interaction.json +++ b/schemas/V_zeta/stable/subject_interaction.json @@ -23,6 +23,13 @@ "documentation": "When the interaction happened, as one or more time_reference documents (Brainstorm I \u00a71.2: the reference is SHAPED like the data \u2014 point / grid / enumerated \u2014 so per-sample times are derived, not stored).", "must_refer_to_document_class": "time_reference", "multiple": true + }, + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "Optional individuated referent: the specific element (an ndi element document \u2014 e.g. an ndi.neuron or a probe) that is part of the subject and that this interaction concerns, when that entity has its own document identity and is neither a subject_group nor reducible to an anatomical ontology term. Completes the referent set on the spine: subject_id is the whole specimen (mandatory objective anchor), target_structure is the ontological KIND of locus (a place), and element_id is THIS specific individuated part / derived entity (which one). Empty for whole-subject records. Since an element already carries its own subject_id, element_id.subject == subject_id is a soft binding-registry invariant, not a class weld (identity stays OFF the class \u2014 the EPM lesson).", + "must_refer_to_document_class": "element", + "multiple": false } ], "file": [], diff --git a/schemas/V_zeta_SPEC.md b/schemas/V_zeta_SPEC.md index 21ca526..da1f1b0 100644 --- a/schemas/V_zeta_SPEC.md +++ b/schemas/V_zeta_SPEC.md @@ -71,6 +71,8 @@ subject_interaction (abstract, isa base) method { node, name } the verb: what was done (measure, inject, heat) [optional] variable { node, name } the noun: what it is about (temperature, a drug) [required] target_structure { node, name }[] (optional) the locus on the subject (§3, Path T) + element_id → element (optional) the specific individuated part / + derived entity this is about (§3.1) ``` - **Direction is two empty classes.** `observation` and `manipulation` (and the @@ -130,6 +132,38 @@ objective annotation rule and the imaging-FOV convention from (bilateral/multi-structure); the multi-structure-image rule is FOV-container + derived observations. +### 3.1 The individuated referent: optional `element_id` on the spine + +`target_structure` names the *ontological KIND* of locus (a place — "CA1", +"layer 5 pyramidal"). It cannot point at a **specific individuated entity that is +part of the subject** and has its own document identity but is neither a +`subject_group` nor reducible to an anatomy term — the canonical case being an +`ndi` element (an `ndi.neuron`, a probe, a derived signal). "Neuron #47 that I +recorded from" is a *thing*, not a *place*, and Path T had no slot for it. + +V_zeta adds an **optional `element_id → element`** dependency on the spine, +completing the referent set every `subject_interaction` can express: + +| slot | question it answers | type | +|---|---|---| +| `subject_id` | the whole specimen (mandatory objective anchor) | ref → `subject` | +| `target_structure` | the ontological KIND of locus ("a place") | ontology_term[] | +| `element_id` | THIS specific individuated part / derived entity ("which one") | ref → `element` | + +The three are orthogonal and co-occur (an interaction may name a specimen, an +anatomy term, *and* the exact element). `element_id` is **optional** — whole-subject +records (a bath, a body weight) leave it empty — and `subject_id` stays mandatory, +so "everything about subject X" queries are unchanged. Identity stays **off the +class** (the EPM lesson): this is a reference edge, not a `neuron_observation` +subclass. Since an `element` already carries its own `subject_id`, the invariant +`element_id.subject == subject_id` is a **binding-registry nudge**, not a class +weld. The restored dataseries event-graph handle (§4, `depends_on element_id → +element`) is this same spine edge; its "the handle must point at an element" +requiredness is a per-leaf / binding-registry concern layered on the optional +spine slot. (Migrators do not yet populate `element_id`; preserving source +element references from element-scoped `did_v1` observations is a deliberate +per-migrator follow-up.) + ### 4. Observation leaves named by DATA-TYPE (shape), not property (§4) The core Brainstorm-I change to the observation tier. The shape/data-type is the diff --git a/schemas/V_zeta_notes.md b/schemas/V_zeta_notes.md index 3968ea4..7efa69a 100644 --- a/schemas/V_zeta_notes.md +++ b/schemas/V_zeta_notes.md @@ -45,6 +45,15 @@ restorations."* Concretely, versus V_epsilon: the act is named by the spine `variable`. Shared `notes` prose moves up to the abstract `manipulation` base; `biological_transfer` re-parents onto `manipulation` (it earns its class via the `donor_id` dependency). +7. **Individuated referent on the spine.** `subject_interaction` gains an + **optional** `element_id → element` dependency (SPEC §3.1): the specific + element that is part of the subject (an `ndi.neuron`, a probe, a derived + signal) that an interaction is about, when that entity has its own document + identity and is neither a `subject_group` nor an anatomy term. Completes the + spine referent set — `subject_id` (whole specimen) / `target_structure` + (ontological KIND of locus) / `element_id` (which specific one). Optional; + identity stays off the class. (Added after the initial build, per maintainer + feedback on element-scoped observations; migrators don't populate it yet.) The typed manipulation families (`injection`/`bath`/`scalar_manipulation` tier), `time_reference` reference frames, dataseries/expression bodies, the @@ -92,6 +101,19 @@ confirmed with the maintainer for the two spine-shaping forks: - **`annotation` kept as a third direction** for curatorial/relational events (`group_assignment`). Brainstorm I foregrounds observation/manipulation symmetry but does not preclude it; it is carried from V_epsilon. +- **Optional `element_id` on the spine** (individuated referent, §3.1) — + confirmed with the maintainer for element-scoped observations that Path T's + ontology `target_structure` cannot address. +- **`session_relative_reference` declares no `session_id` edge.** Session + identity rides on `base.session_id` (every DID document carries it), so the + ordinal fallback anchor needs no `session_id` dependency. The edge was + redundant with `base` and produced only discovery-mode reference-integrity + orphans — the migrators synthesize thousands of these anchors (one per + timeless treatment / ontology_table_row / resolved bath), and the `session` + document is not part of a corpus dump, so every one dangled (~41k on JH, ~8k + on Dab). Dropping the edge removes the orphans at the source; the real + `ndi.migrate.local` path is unaffected (it referenced the session the same way + via `base`). ## Provisional / still open (from Brainstorm I) diff --git a/tests/test_vzeta.py b/tests/test_vzeta.py index b8e6682..dccad40 100644 --- a/tests/test_vzeta.py +++ b/tests/test_vzeta.py @@ -121,6 +121,33 @@ def test_spine_composes_onto_every_interaction(): assert ft.get("target_structure") == "ontology_term", f"{name} missing target_structure" +def test_element_id_is_optional_individuated_referent_on_spine(): + """Brainstorm I completes the referent set on the spine: subject_id is the + whole specimen, target_structure the ontological KIND of locus, and + element_id the specific individuated part / derived entity (an ndi element + that is part of the subject but is neither a group nor an anatomical + ontology term). It is an OPTIONAL dependency, not a class -- identity stays + OFF the class (the EPM lesson).""" + deps = {d["name"]: d for d in RECORDS["subject_interaction"][1]["depends_on"]} + assert "element_id" in deps, "subject_interaction must offer element_id" + assert deps["element_id"]["mustBeNonEmpty"] is False, "element_id must be optional" + assert deps["element_id"]["must_refer_to_document_class"] == "element" + assert deps["element_id"].get("multiple", False) is False, "element_id is single" + # every interaction leaf (observation and manipulation) inherits it + for name in RECORDS: + if "subject_interaction" in _chain(name): + assert "element_id" in _flat_dep_names(name), f"{name} missing element_id" + + +def test_session_relative_reference_has_no_redundant_session_edge(): + """session_id rides on base.session_id (every DID document carries it), so + the ordinal anchor declares no session_id depends_on edge -- the redundant + edge only produced discovery-mode reference-integrity orphans (the session + document is not part of a corpus dump).""" + assert "session_id" not in _flat_dep_names("session_relative_reference"), \ + "session_relative_reference should not declare a redundant session_id edge" + + def test_shape_typed_scalar_leaves_present(): """Brainstorm I names observation leaves by data-type (shape), not property.""" for dim, vtype in { From aa6ae34dea0d3fa843e7ae11b2d8f056efd28592 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 23:30:24 +0000 Subject: [PATCH 6/6] V_zeta: fold image_stack onto the ingested imageseries; port daqreader_image_epochdata_ingested Retire the standalone image document onto NDI's imaging stack (the model NDI-main ships: ndi.element.image / ndi.probe.image, frames timed through the epoch clock; 'no_time' for a clockless stack). Three roles replace the one doc: - imageseries_observation -- the discoverable spine handle (subject_id + shaped time_reference + variable/kind = modality + element_id; caption is dataseries_observation.label, added here). - daqreader_image_epochdata_ingested -- the DIGITAL, in-database pixels: a frames.bin raw binary + a queryable YXCZT header (dimension_order/size, data_type, num_frames, frametimes, clocktype). This is exactly what ndi.daq.reader.image.ingest_epochfiles writes -- once ingested the image is digital data resident in the database, no external file dependency. The class lived in NDI's ndi_common but was ABSENT from did-schema; ported into V_zeta (stable), mirroring the daqreader_mfdaq_epochdata_ingested sibling. - ndi.element.image + element_epoch -- the element the frames belong to. Changes: - image_stack, image_stack_parameters -> deprecated/ (index + topics updated). - new stable/daqreader_image_epochdata_ingested.json. - element_epoch.storage + dataseries_data.storage gain data_type + data_limits. - dataseries_data gains the element_id link its siblings (ngrid / image_zarr / dataseries_pyramid) already carry. - dataseries_observation gains an optional label (the folded image_stack caption). - SPEC S4.1 + notes document the fold; test_vzeta asserts it. Suite: 415 pass. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015zjbvyLbSLMYz1uCizYwQh --- .../{stable => deprecated}/image_stack.json | 2 +- .../image_stack_parameters.json | 2 +- schemas/V_zeta/draft/dataseries_data.json | 37 +++++- .../V_zeta/draft/dataseries_observation.json | 13 ++ schemas/V_zeta/index.json | 25 +++- .../daqreader_image_epochdata_ingested.json | 116 ++++++++++++++++++ schemas/V_zeta/stable/element_epoch.json | 28 +++++ schemas/V_zeta/topics.json | 5 +- schemas/V_zeta_SPEC.md | 25 ++++ schemas/V_zeta_notes.md | 10 ++ tests/test_vzeta.py | 22 ++++ 11 files changed, 274 insertions(+), 11 deletions(-) rename schemas/V_zeta/{stable => deprecated}/image_stack.json (98%) rename schemas/V_zeta/{stable => deprecated}/image_stack_parameters.json (99%) create mode 100644 schemas/V_zeta/stable/daqreader_image_epochdata_ingested.json diff --git a/schemas/V_zeta/stable/image_stack.json b/schemas/V_zeta/deprecated/image_stack.json similarity index 98% rename from schemas/V_zeta/stable/image_stack.json rename to schemas/V_zeta/deprecated/image_stack.json index e992d56..bfb584c 100644 --- a/schemas/V_zeta/stable/image_stack.json +++ b/schemas/V_zeta/deprecated/image_stack.json @@ -10,7 +10,7 @@ "class_name": "image_stack_parameters" } ], - "maturity_level": "stable" + "maturity_level": "deprecated" }, "depends_on": [ { diff --git a/schemas/V_zeta/stable/image_stack_parameters.json b/schemas/V_zeta/deprecated/image_stack_parameters.json similarity index 99% rename from schemas/V_zeta/stable/image_stack_parameters.json rename to schemas/V_zeta/deprecated/image_stack_parameters.json index ffbbaea..2a8acbf 100644 --- a/schemas/V_zeta/stable/image_stack_parameters.json +++ b/schemas/V_zeta/deprecated/image_stack_parameters.json @@ -7,7 +7,7 @@ "class_name": "base" } ], - "maturity_level": "stable" + "maturity_level": "deprecated" }, "depends_on": [ { diff --git a/schemas/V_zeta/draft/dataseries_data.json b/schemas/V_zeta/draft/dataseries_data.json index 7647bdc..be6626e 100644 --- a/schemas/V_zeta/draft/dataseries_data.json +++ b/schemas/V_zeta/draft/dataseries_data.json @@ -10,7 +10,14 @@ "maturity_level": "draft", "abstract": true }, - "depends_on": [], + "depends_on": [ + { + "name": "element_id", + "mustBeNonEmpty": false, + "documentation": "The element whose acquired data this payload holds (the ndi.element.image / timeseries element). Mirrors ngrid / image_zarr / dataseries_pyramid, which all carry element_id; lets a dataseries payload be tied to its element and, through it, to the imageseries/timeseries observation handle.", + "must_refer_to_document_class": "element" + } + ], "file": [ { "name": "dataseries_binary_data", @@ -324,6 +331,34 @@ "ontology": null, "documentation": "Compression/filter pipeline (e.g. blosc/zstd).", "constraints": {} + }, + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Numeric pixel/sample storage type (e.g. 'uint16', 'single', 'double'). Folded from the retired image_stack_parameters.data_type.", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "data_limits", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "2-element [min, max] range of valid stored values for data_type (e.g. [0, 65535] for uint16). Folded from image_stack_parameters.data_limits.", + "constraints": {} } ] }, diff --git a/schemas/V_zeta/draft/dataseries_observation.json b/schemas/V_zeta/draft/dataseries_observation.json index e9351bf..895717d 100644 --- a/schemas/V_zeta/draft/dataseries_observation.json +++ b/schemas/V_zeta/draft/dataseries_observation.json @@ -267,6 +267,19 @@ "constraints": {} } ] + }, + { + "name": "label", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Optional free-text caption for the series (e.g. 'fluorescently labeled bacterial patches, processed'). Folded from the retired image_stack.label.", + "constraints": {} } ] } diff --git a/schemas/V_zeta/index.json b/schemas/V_zeta/index.json index 946b921..38dc2ba 100644 --- a/schemas/V_zeta/index.json +++ b/schemas/V_zeta/index.json @@ -246,6 +246,19 @@ "path": "schemas/V_zeta/stable/daqreader_mfdaq_epochdata_ingested.json", "is_meta": false }, + { + "class_name": "daqreader_image_epochdata_ingested", + "tier": "stable", + "class_version": "1.0.0", + "maturity_level": "stable", + "superclasses": [ + "base", + "daqreader_epochdata_ingested", + "epochid" + ], + "path": "schemas/V_zeta/stable/daqreader_image_epochdata_ingested.json", + "is_meta": false + }, { "class_name": "daqreader_ndr", "tier": "stable", @@ -847,25 +860,25 @@ }, { "class_name": "image_stack", - "tier": "stable", + "tier": "deprecated", "class_version": "1.0.0", - "maturity_level": "stable", + "maturity_level": "deprecated", "superclasses": [ "base", "image_stack_parameters" ], - "path": "schemas/V_zeta/stable/image_stack.json", + "path": "schemas/V_zeta/deprecated/image_stack.json", "is_meta": false }, { "class_name": "image_stack_parameters", - "tier": "stable", + "tier": "deprecated", "class_version": "1.0.0", - "maturity_level": "stable", + "maturity_level": "deprecated", "superclasses": [ "base" ], - "path": "schemas/V_zeta/stable/image_stack_parameters.json", + "path": "schemas/V_zeta/deprecated/image_stack_parameters.json", "is_meta": false }, { diff --git a/schemas/V_zeta/stable/daqreader_image_epochdata_ingested.json b/schemas/V_zeta/stable/daqreader_image_epochdata_ingested.json new file mode 100644 index 0000000..e86fba2 --- /dev/null +++ b/schemas/V_zeta/stable/daqreader_image_epochdata_ingested.json @@ -0,0 +1,116 @@ +{ + "document_class": { + "class_name": "daqreader_image_epochdata_ingested", + "class_version": "1.0.0", + "superclasses": [ + { + "class_name": "base" + }, + { + "class_name": "daqreader_epochdata_ingested" + }, + { + "class_name": "epochid" + } + ], + "maturity_level": "stable" + }, + "depends_on": [], + "file": [ + { + "name": "frames.bin", + "documentation": "The ingested image frames as a flat raw binary (column-major, in the numeric class named by data_type). Once ingested, the pixels are digital data resident in the database -- there is no external file dependency. Empty is permitted for a header-only record." + } + ], + "fields": [ + { + "name": "dimension_order", + "type": "char", + "blank_value": "", + "default_value": "YXCZT", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Dimension order of the stored frames over {Y,X,C,Z,T} (height, width, channel, plane, time). Default 'YXCZT'.", + "constraints": { + "maxLength": 16 + } + }, + { + "name": "dimension_size", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "The [Y X C Z T] extent of the image data (height, width, channels, planes, timepoints).", + "constraints": { + "element_type": "integer" + } + }, + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Underlying numeric class of the stored pixel data (e.g. 'uint16', 'single').", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "num_frames", + "type": "integer", + "blank_value": 0, + "default_value": 0, + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": true, + "queryable": true, + "ontology": null, + "documentation": "Number of frames stored, along the ordering axes (T, and Z when present).", + "constraints": { + "min": 0, + "max": 1000000000 + } + }, + { + "name": "frametimes", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "Time of each frame in epoch-clock units, as a 1xN row (NaN for clockless epochs).", + "constraints": {} + }, + { + "name": "clocktype", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "The epoch clock type ('dev_local_time' for a movie, 'no_time' for a clockless slide-scan / z-stack).", + "constraints": { + "maxLength": 256 + } + } + ] +} diff --git a/schemas/V_zeta/stable/element_epoch.json b/schemas/V_zeta/stable/element_epoch.json index 9107a88..53c23b9 100644 --- a/schemas/V_zeta/stable/element_epoch.json +++ b/schemas/V_zeta/stable/element_epoch.json @@ -333,6 +333,34 @@ "ontology": null, "documentation": "Compression/filter pipeline.", "constraints": {} + }, + { + "name": "data_type", + "type": "char", + "blank_value": "", + "default_value": "", + "mustBeNonEmpty": false, + "mustBeScalar": true, + "mustNotHaveNaN": false, + "queryable": true, + "ontology": null, + "documentation": "Numeric pixel/sample storage type (e.g. 'uint16', 'single', 'double'). Folded from the retired image_stack_parameters.data_type.", + "constraints": { + "maxLength": 32 + } + }, + { + "name": "data_limits", + "type": "matrix", + "blank_value": [], + "default_value": [], + "mustBeNonEmpty": false, + "mustBeScalar": false, + "mustNotHaveNaN": false, + "queryable": false, + "ontology": null, + "documentation": "2-element [min, max] range of valid stored values for data_type (e.g. [0, 65535] for uint16). Folded from image_stack_parameters.data_limits.", + "constraints": {} } ] } diff --git a/schemas/V_zeta/topics.json b/schemas/V_zeta/topics.json index 7b33dbe..d7e355c 100644 --- a/schemas/V_zeta/topics.json +++ b/schemas/V_zeta/topics.json @@ -81,6 +81,7 @@ "daqmetadatareader_epochdata_ingested", "daqreader", "daqreader_epochdata_ingested", + "daqreader_image_epochdata_ingested", "daqreader_mfdaq_epochdata_ingested", "daqreader_ndr", "daqsystem", @@ -109,8 +110,6 @@ "generic_file", "image", "image_collection", - "image_stack", - "image_stack_parameters", "image_zarr", "measurement", "ngrid", @@ -167,6 +166,8 @@ "name": "deprecated", "description": "Classes deprecated in V_epsilon, retained for migration of legacy instances.", "classes": [ + "image_stack", + "image_stack_parameters", "projectvar", "subject_group", "treatment", diff --git a/schemas/V_zeta_SPEC.md b/schemas/V_zeta_SPEC.md index da1f1b0..7ccf415 100644 --- a/schemas/V_zeta_SPEC.md +++ b/schemas/V_zeta_SPEC.md @@ -204,6 +204,31 @@ class; the property is the `variable` term. channel-model decision. `expression_observation` / `spatial_expression_observation` (omics endpoints) carry over. +#### 4.1 Imaging: `image_stack` retired onto the ingested imageseries + +The legacy standalone `image_stack` / `image_stack_parameters` (a file-backed +pixel blob + geometry bundle, tied to a subject but off the spine) are **retired +to `deprecated/`** and folded onto NDI's imaging stack — the same model NDI-main +ships in code (`ndi.element.image` / `ndi.probe.image`, whose frames are timed +through the epoch clock / syncgraph, `'no_time'` for a clockless stack). Three +roles replace the one document: + +| role | class | +|---|---| +| discoverable subject-facing handle | `imageseries_observation` (spine: `subject_id` + shaped `time_reference` + `variable`/`kind` = modality + `element_id`; the caption is `dataseries_observation.label`) | +| the **digital, in-database** pixels | **`daqreader_image_epochdata_ingested`** — a `frames.bin` raw binary + a queryable YXCZT header (`dimension_order`/`size`, `data_type`, `num_frames`, `frametimes`, `clocktype`). This is exactly what `ndi.daq.reader.image.ingest_epochfiles` writes: once ingested, the image is digital data resident in the database with no external file dependency. **Newly ported into V_zeta** (it was in NDI's `ndi_common` but absent from did-schema). | +| the element the frames belong to | `ndi.element.image` (non-direct = ingested), with `element_epoch` as the epoch record | + +The geometry that lived in `image_stack_parameters` (`dimension_order`/`size`/ +`scale`/`units`) becomes the dataseries `axes[]` and the ingested header; +`data_type`/`data_limits` are added to the `element_epoch`/`dataseries_data` +`storage` descriptor; `timestamp`+`clocktype` become the epoch clock. A did_v1 +`image_stack` migrates 1→6 (`did2.convert.migrators_i.image_stack`): the handle, +the ingested frames, the element, its epoch, a minimal `daqreader`, and the +ordinal time anchor — dropping the legacy `document_id` edge (the corpus +reference-integrity orphan). Discovery-mode fallback: an un-migrated `image_stack` +still resolves 1→1 to the deprecated class. + ### 5. Manipulation tier — classes earn their place by STRUCTURE Symmetric with the observation tier: a manipulation is a class only when it adds diff --git a/schemas/V_zeta_notes.md b/schemas/V_zeta_notes.md index 7efa69a..f5adf44 100644 --- a/schemas/V_zeta_notes.md +++ b/schemas/V_zeta_notes.md @@ -104,6 +104,16 @@ confirmed with the maintainer for the two spine-shaping forks: - **Optional `element_id` on the spine** (individuated referent, §3.1) — confirmed with the maintainer for element-scoped observations that Path T's ontology `target_structure` cannot address. +- **Imaging folded onto the ingested imageseries** (§4.1) — confirmed. The + standalone `image_stack` / `image_stack_parameters` are retired to + `deprecated/`; images become `imageseries_observation` (handle) + + `daqreader_image_epochdata_ingested` (the digital, in-database `frames.bin` + + YXCZT header — newly **ported into V_zeta** from NDI's `ndi_common`, which is + what `ndi.daq.reader.image.ingest_epochfiles` writes) + `ndi.element.image` / + `element_epoch`. `data_type`/`data_limits` were added to the `storage` + descriptor and `dataseries_data` gained the `element_id` link that its + siblings (ngrid / image_zarr / dataseries_pyramid) already carry. Migrator: + `did2.convert.migrators_i.image_stack` (1→6). - **`session_relative_reference` declares no `session_id` edge.** Session identity rides on `base.session_id` (every DID document carries it), so the ordinal fallback anchor needs no `session_id` dependency. The edge was diff --git a/tests/test_vzeta.py b/tests/test_vzeta.py index dccad40..1e40d4b 100644 --- a/tests/test_vzeta.py +++ b/tests/test_vzeta.py @@ -170,6 +170,28 @@ def test_no_brainstorm_e_property_leaves(): assert gone not in RECORDS, f"{gone} should not exist in V_zeta" +def test_image_stack_folded_into_imageseries(): + """image_stack / image_stack_parameters are legacy standalone image docs. + V_zeta folds imaging onto the dataseries branch (matching NDI main's + ndi.element.image / ndi.probe.image epoch-clock model): imageseries_observation + is the discoverable spine handle, imageseries_data / element_epoch carry the + bytes+geometry. The two old classes are retired to deprecated (migration only).""" + for cls in ("image_stack", "image_stack_parameters"): + assert cls in RECORDS, f"{cls} should remain for migration" + assert RECORDS[cls][0] == "deprecated", f"{cls} must be in the deprecated tier" + assert RECORDS[cls][1]["document_class"]["maturity_level"] == "deprecated" + # the imaging home is the dataseries branch on the spine + assert "imageseries_observation" in RECORDS + assert "subject_interaction" in _chain("imageseries_observation") + assert _flat_field_types("imageseries_observation").get("kind") == "ontology_term" + # nothing folds the geometry loss: storage carries dtype/limits; series a caption + st = {s["name"] for s in + [f for f in RECORDS["dataseries_data"][1]["fields"] if f["name"] == "storage"][0]["fields"]} + assert {"data_type", "data_limits"} <= st, "dataseries_data.storage must carry dtype/limits" + assert _flat_field_types("imageseries_observation").get("label") == "char", \ + "the folded image_stack.label caption must be inherited from dataseries_observation" + + def test_no_pure_identity_manipulation_classes(): """A manipulation is a class only when it adds STRUCTURE; the pure-identity procedural_/environmental_manipulation classes fold into generic_manipulation."""