diff --git a/docs/_toc.yml b/docs/_toc.yml index 5686cb83f..f88fc8252 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -14,8 +14,8 @@ chapters: - file: fundamentals/regularization/rotated_gradients - file: fundamentals/mesh_design - file: fundamentals/joint_inversion - - file: fundamentals/depth_of_investigation - file: fundamentals/optimization + - file: fundamentals/parallelization - file: tutorials/introduction sections: - file: tutorials/background @@ -34,10 +34,10 @@ chapters: - file: case_studies/Forrestania/python_code/unconstrained_gravity_inv_training - file: case_studies/Forrestania/python_code/unconstrained_magnetics_inv_training - file: case_studies/Forrestania/python_code/joint_grav_mag -- file: plate-simulation/index +- file: fundamentals/depth_of_investigation +- file: plate-simulation/simulation sections: - - file: plate-simulation/usage - title: Basic Usage - - file: plate-simulation/methodology - title: Methodology + - file: plate-simulation/standalone + - file: plate-simulation/sweep + - file: plate-simulation/match - file: THIRD_PARTY_SOFTWARE diff --git a/docs/conf.py b/docs/conf.py index 2f18464f2..ed45e1180 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,6 +42,7 @@ exclude_patterns = [] todo_include_todos = True + # -- Options for auto-doc ---------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc diff --git a/docs/fundamentals/depth_of_investigation.ipynb b/docs/fundamentals/depth_of_investigation.ipynb index 7f32087fc..4fe1abaa5 100644 --- a/docs/fundamentals/depth_of_investigation.ipynb +++ b/docs/fundamentals/depth_of_investigation.ipynb @@ -7,7 +7,58 @@ "source": [ "# Depth of Investigation\n", "\n", - "In geophysics, \"depth of investigation\" refers to the maximum depth below the surface from which a geophysical survey can reliably measure. It depends on factors like the survey design and physical properties of the subsurface material. Several strategies have been proposed to assess uncertainties in models recovered from inversion. {cite:t}`nabighian_1989` used a skin depth approach for electromagnetic surveys, assuming a background halfspace resistivity. {cite:t}`li_1999` implemented a cut-off value based on two inverted models obtained with slightly different assumptions. {cite:t}`christiansen_2012` proposed a mask based on the sum-square of sensitivities to estimate a volume of low confidence. In the following, we discuss the algorithm and implementation of the sensitivity cutoff strategy." + "This application allows users to compute a depth of investigation from model values. In geophysics, \"depth of investigation\" refers to the maximum depth below the surface from which a geophysical survey can reliably measure. It depends on factors like the survey design and physical properties of the subsurface material. \n", + "\n", + "![masked_model](./images/masked_model.png)\n", + "\n", + "Several strategies have been proposed to assess uncertainties in models recovered from inversion. {cite:t}`nabighian_1989` used a skin depth approach for electromagnetic surveys, assuming a background halfspace resistivity. {cite:t}`li_1999` implemented a cut-off value based on two inverted models obtained with slightly different assumptions. \n", + "\n", + "This application uses the method proposed by {cite:t}`christiansen_2012`, based on the sum-square of sensitivities to estimate a volume of low confidence." + ] + }, + { + "cell_type": "markdown", + "id": "83b4ae8f-5509-40b1-98c2-39acefba438c", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "## Interface\n", + "\n", + "The depth of investigation methods based on sensitivity cutoffs relies on the ui.json interface. \n", + "\n", + "![interface](./images/uijson.png)\n", + "\n", + "### Inputs\n", + "\n", + "- **Mesh**: The mesh used for inversion\n", + "- **Sensitivity**: Model selector for the sensitivities at a given iteration (see [Pre-requisite](pre-requisite))\n", + "- **Cut-off**: Percentage value to threshold the sentivities, relative to the **Method** used.\n", + "- **Method**: One of *percentile*, *percent* or *log percent*\n", + "\n", + "![cutoff_options](./images/cutoff_options.png)\n", + "\n", + "### Output\n", + "\n", + "After running, the application will create a masking attribute saved on the mesh.\n", + "\n", + "![mask](./images/sensitivity_mask.png)\n", + "\n", + "The mask can then be applied to any of the iterations to show only the cells that exceeded the sensitivity threshold.\n", + "\n", + "![apply_mask](./images/apply_mask.png)\n", + "\n", + "\n", + "(pre-requisite)=\n", + "### Pre-requisite\n", + "\n", + "In order to save the sensitivities during a SimPEG inversion, the 'Save sensitivities' option must be selected from the 'Optional parameters' tab of an inversion.\n", + "\n", + "![save_sensitivities](./images/save_sensitivities.png)\n", + "\n", + "This will result in a new model generated and saved into the computational mesh at each iteration.\n", + "\n", + "![sensitivity_models](./images/sensitivity_models.png)" ] }, { @@ -15,7 +66,7 @@ "id": "c13ffcec-8d95-4ee9-876f-9aa92e2c534a", "metadata": {}, "source": [ - "## Sensitivities\n", + "## Methodology\n", "\n", "The sensitivity matrix is calculated as part of the optimization problem solved by SimPEG while inverting geophysical data. The sensitivity matrix represents the degree to which each predicted datum changes with respect to a perturbation in each model cell. It is given in matrix form by\n", "\n", @@ -28,12 +79,12 @@ "The depth of investigation mask is a property of the cells of the mesh only so the rows of the sensitivity matrix (data) are sum-square normalized as follows.\n", "\n", "$$\n", - "\\mathbf{J}_{norm} = \\left[\\sum_{n=1}^{N}\\left(\\frac{\\mathbf{J}_{n:}}{w_n}\\right)^{2}\\right]^{(1/2)}\n", + "\\|\\mathbf{j}\\| = \\left[\\sum_{n=1}^{N}\\left(\\frac{\\mathbf{J}_{n:}}{w_n}\\right)^{2}\\right]^{(1/2)}\n", "$$\n", "\n", "where $w_n$ are the data uncertainties associated with the $n^{th}$ datum.\n", "\n", - "The resulting vector $J_{norm}$ can then be thought of as the degree to which the aggregate data changes due to a small perturbation in each model cell. The depth of investigation mask is then computed by thresholding those sensitivities" + "The resulting vector $\\|\\mathbf{j}\\|$ can then be thought of as the degree to which the aggregate data changes due to a small perturbation in each model cell. The depth of investigation mask is then computed by thresholding those sensitivities" ] }, { @@ -41,7 +92,7 @@ "id": "d8bb85c5-5e63-4617-ab6b-a7b6536c1d2c", "metadata": {}, "source": [ - "## Thresholding\n", + "### Thresholding\n", "\n", "The depth of investigation can be estimated by assigning a threshold on the sum-squared sensitivity vector. This can be done as a percentile, percentage, or log-percentage. In the percentile method, the mask is formed by eliminating all cells in which the sensitivity falls below the lowest $n$% of the number of data where $n$ is the chosen cutoff. In the percent method the data are transformed into a percentage of the largest value\n", "\n", @@ -51,56 +102,6 @@ "\n", "and the mask is formed by eliminating all cells in which the sensitivity falls below the lowest $n$% of the data values where $n$ is the chosen cutoff. Finally, the log-percent mask transforms the data into log-space before carrying out the percentage thresholding described above." ] - }, - { - "cell_type": "markdown", - "id": "83b4ae8f-5509-40b1-98c2-39acefba438c", - "metadata": {}, - "source": [ - "## Usage\n", - "\n", - "The depth of investigation methods based on sensitivity cutoffs described above are exposed to Geoscience ANALYST Pro Geophysics users through a ui.json interface. In order to save the sensitivities during a SimPEG inversion, the 'Save sensitivities' option must be selected from the 'Optional parameters' tab of the SimPEG inversion ui.json window.\n", - "\n", - "![save_sensitivities](./images/save_sensitivities.png)\n", - "\n", - "This will result in a new model generated and saved into the computational mesh at each iteration.\n", - "\n", - "![sensitivity_models](./images/sensitivity_models.png)\n", - "\n", - "The ui.json interface allows the user to select a mesh from the **simpeg-drivers** result and any of the generated sensitivity models, a cutoff threshold, method, and optional name for the output.\n", - "\n", - "![interface](./images/uijson.png)\n", - "\n", - "The cutoff methods are selectable in the dropdown\n", - "\n", - "![cutoff_options](./images/cutoff_options.png)\n", - "\n", - "Whatever the options, the application will create a sensitivity cutoff mask saved on the mesh\n", - "\n", - "![mask](./images/sensitivity_mask.png)\n", - "\n", - "which can then be applied to any of the iterations to show only the cells that exceeded the sensitivity threshold.\n", - "\n", - "![apply_mask](./images/apply_mask.png)\n", - "\n", - "![masked_model](./images/masked_model.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1079da0d-4ea2-4f00-b957-92199dd39cdb", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "920f0637-4028-40c7-b2c6-5976f5e90afd", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -119,7 +120,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.16" + "version": "3.10.19" } }, "nbformat": 4, diff --git a/docs/fundamentals/images/distributed_parallelization.svg b/docs/fundamentals/images/distributed_parallelization.svg new file mode 100644 index 000000000..3292e58b1 --- /dev/null +++ b/docs/fundamentals/images/distributed_parallelization.svg @@ -0,0 +1 @@ + diff --git a/docs/fundamentals/parallelization.rst b/docs/fundamentals/parallelization.rst new file mode 100644 index 000000000..fd7dd779d --- /dev/null +++ b/docs/fundamentals/parallelization.rst @@ -0,0 +1,59 @@ +.. _parallelization: + +Parallelization +=============== + +This section describes the different levels of parallelization used by the inversion routines and how to optimize resources. +For a given inversion routine, the application decomposes the problem into a series of sub-problems, or tiles, each assigned a mesh and a survey. During the inversion process, the application continuously requests predicted data and derivatives from the sub-problems. The application parallelizes these operations within each sub-problem, as well as externally so that sub-problems can be computed concurrently. + + +.. figure:: ./images/distributed_parallelization.svg + :align: center + :width: 80% + + Schematic representation of the computing elements of a tiled inversion. Each tile receives an assigned mesh and a survey (single-frequency if applicable), with array operations parallelized by dask. The dask operations always bookend the direct solver when employed. Optionally, the workload can be distributed across multiple workers to optimize performance. Each worker is responsible for a sub-set of tiles and with a limited number of threads. Only 1-dimensional arrays are passed between the main process and the workers. + + +Dask +---- + +The `dask `_ library handles most operations related to generating arrays. A mixture of ``dask.arrays`` and ``dask.delayed`` calls parallelizes the computations across multiple threads. If a direct solver is involved, the dask operations bookend the solver to avoid thread-safety issues. The application converts dask.arrays to numpy arrays before passing them to the direct solvers and before returning them to the main process. Only 1-dimensional arrays are returned to the main process, while higher-dimensional arrays and solvers remain in the distributed memory of the workers. + +Sensitivity matrices can optionally be stored on disk using the `zarr `_ library, which is optimized for parallel read/write access. In this case, the workers never hold the entire sensitivity matrix in memory, but rather read and write small chunks of the matrix as needed. This allows for efficient handling of large sensitivity matrices that may not fit in memory, at the cost of increased disk I/O. The use of zarr is optional and can be enabled by setting the ``store_sensitivity`` parameter to true in the ui.json file. + + +Direct Solvers +-------------- + +A direct solver is used for any method evaluated by partial differential equation (PDE), such as electromagnetics and electric surveys. The `Pardiso `_ and `Mumps `_ solvers parallelize operations during the factorization and backward substitution calls. Note that the current implementation of the solvers is not thread-safe and therefore cannot be shared across parallel processes. Any other levels of parallelization need to occur outside the direct solver calls or be encapsulated within a distributed process. + +The number of threads used by the solvers can be set by running the command + +.. code-block:: + + set OMP_NUM_THREADS=X + +before launching the python program. Alternatively, setting ``OMP_NUM_THREADS`` as a local environment variable will set it permanently. The default value is the number of threads available on the machine. + + +.. _parallelization_distributed: + +Dask.distributed +---------------- + +It has been found that parallel processes, both for dask.delayed and the direct solver, tend to saturate on large numbers of threads. Too many small tasks tend to overwhelm the scheduler at the cost of performance. This can be alleviated by resorting to the ``dask.distributed`` library to split the computation of tiles across multiple ``workers``. Each worker can be responsible for a subset of the tiles, and can be configured to use a limited number of threads to optimize performance. This allows for better resource utilization and improved performance, especially when dealing with large problems that require significant computational resources. The number of workers and threads (per worker) can be set with the following parameters added to the ui.json file: + +.. code-block:: + + { + ... + "n_workers": i, + "n_threads": n, + "performance_report": true + } + +Where ``n_workers`` is the number of processes to spawn, and ``n_threads`` is the number of threads to use for each process. Setting ``performance_report`` to true will generate an ``html`` performance report at the end of the inversion, which can be used to identify bottlenecks and optimize the parallelization settings. + +It is good practice to set an even number of threads per worker to optimize the load. Setting too many workers with too few threads can lead to increased overhead from inter-process communication, while setting too few workers with too many threads can lead to saturation of the direct solvers and reduced performance. For example, if the machine has 32 threads available, setting 4 workers with 8 threads each will fully use the resources. + +It is also recommended to set the number of workers as a multiple of the number of tiles, to ensure that all workers are utilized. For example, if there are 8 tiles, setting 4 workers will allow each worker to process 2 tiles concurrently. If fewer tiles than workers are available, the program will automatically split surveys into smaller chunks, while preserving the mesh, to ensure even load across the workers. This is less efficient than having a dedicated optimized mesh per tile, but will still provide performance benefits. diff --git a/docs/images/plate-simulation/basic_usage/analyst_geophysics_menu.png b/docs/images/analyst_geophysics_menu.png similarity index 100% rename from docs/images/plate-simulation/basic_usage/analyst_geophysics_menu.png rename to docs/images/analyst_geophysics_menu.png diff --git a/docs/intro.md b/docs/intro.md index 83659657f..2407d34ea 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,16 +1,45 @@ # About -This document contains training material for geophysical inversions using [SimPEG](https://simpeg.xyz/) and [Geoscience ANALYST](https://www.mirageoscience.com/mining-industry-software/geoscience-analyst/). +This document contains training material for geophysical forward modeling and inversions using [SimPEG](https://simpeg.xyz/) and [Geoscience ANALYST](https://www.mirageoscience.com/mining-industry-software/geoscience-analyst/). ```{image} ./images/ore_body.png :width: 500px ``` -# Table of content + +# Table of contents ```{tableofcontents} ``` +# Running the applications + +The main entry point to the various modules are the [*.ui.json](https://github.com/MiraGeoscience/simpeg-drivers/blob/develop/simpeg_drivers-assets/uijson) +files. The ``ui.json`` serves a dual purpose: + +(1) rendering a user-interface in Geoscience ANALYST + +(2) storing the input parameters chosen by the user for the program to run. See the [UIJson documentation](https://mirageoscience-geoh5py.readthedocs-hosted.com/en/latest/content/uijson_format/usage.html) +for more information about the ui.json interface. + +The various user-interfaces can be accessed from the Geoscience ANALYST Pro Geophysics menu. + +```{image} ./images/analyst_geophysics_menu.png +:width: 500px +``` + +The application can also be run from command line if all required fields in +the ui.json are provided. This approach is useful for advanced users who want to +automate the mesh creation process or re-run an existing mesh with different parameters. + +To run any of the applications, assuming a valid Conda environment, use the following command: + +``conda activate simpeg-drivers`` + +``python -m simpeg-drivers.driver [YOUR.ui.json]`` + +where ``[YOUR.ui.json]`` is the path to the input ui.json file on disk. + # References diff --git a/docs/images/plate-simulation/index.png b/docs/plate-simulation/images/index.png similarity index 100% rename from docs/images/plate-simulation/index.png rename to docs/plate-simulation/images/index.png diff --git a/docs/plate-simulation/images/match_landing.png b/docs/plate-simulation/images/match_landing.png new file mode 100644 index 000000000..1a52955ba Binary files /dev/null and b/docs/plate-simulation/images/match_landing.png differ diff --git a/docs/plate-simulation/images/match_template.png b/docs/plate-simulation/images/match_template.png new file mode 100644 index 000000000..a31318705 Binary files /dev/null and b/docs/plate-simulation/images/match_template.png differ diff --git a/docs/plate-simulation/images/match_uijson.png b/docs/plate-simulation/images/match_uijson.png new file mode 100644 index 000000000..24085356f Binary files /dev/null and b/docs/plate-simulation/images/match_uijson.png differ diff --git a/docs/images/plate-simulation/methodology/copy_options.png b/docs/plate-simulation/images/methodology/copy_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/copy_options.png rename to docs/plate-simulation/images/methodology/copy_options.png diff --git a/docs/images/plate-simulation/methodology/data/simpeg_group_creation.png b/docs/plate-simulation/images/methodology/data/simpeg_group_creation.png similarity index 100% rename from docs/images/plate-simulation/methodology/data/simpeg_group_creation.png rename to docs/plate-simulation/images/methodology/data/simpeg_group_creation.png diff --git a/docs/images/plate-simulation/methodology/data/simpeg_group_edit_options.png b/docs/plate-simulation/images/methodology/data/simpeg_group_edit_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/data/simpeg_group_edit_options.png rename to docs/plate-simulation/images/methodology/data/simpeg_group_edit_options.png diff --git a/docs/images/plate-simulation/methodology/data/simpeg_group_options.png b/docs/plate-simulation/images/methodology/data/simpeg_group_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/data/simpeg_group_options.png rename to docs/plate-simulation/images/methodology/data/simpeg_group_options.png diff --git a/docs/images/plate-simulation/methodology/data/simulation_options.png b/docs/plate-simulation/images/methodology/data/simulation_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/data/simulation_options.png rename to docs/plate-simulation/images/methodology/data/simulation_options.png diff --git a/docs/images/plate-simulation/methodology/make_plate_images.pub b/docs/plate-simulation/images/methodology/make_plate_images.pub similarity index 100% rename from docs/images/plate-simulation/methodology/make_plate_images.pub rename to docs/plate-simulation/images/methodology/make_plate_images.pub diff --git a/docs/images/plate-simulation/methodology/mesh/mesh_options.png b/docs/plate-simulation/images/methodology/mesh/mesh_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/mesh/mesh_options.png rename to docs/plate-simulation/images/methodology/mesh/mesh_options.png diff --git a/docs/images/plate-simulation/methodology/mesh/refinement.png b/docs/plate-simulation/images/methodology/mesh/refinement.png similarity index 100% rename from docs/images/plate-simulation/methodology/mesh/refinement.png rename to docs/plate-simulation/images/methodology/mesh/refinement.png diff --git a/docs/images/plate-simulation/methodology/model/basement_options.png b/docs/plate-simulation/images/methodology/model/basement_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/basement_options.png rename to docs/plate-simulation/images/methodology/model/basement_options.png diff --git a/docs/images/plate-simulation/methodology/model/n_plates_options.png b/docs/plate-simulation/images/methodology/model/n_plates_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/n_plates_options.png rename to docs/plate-simulation/images/methodology/model/n_plates_options.png diff --git a/docs/images/plate-simulation/methodology/model/overburden_and_basement.png b/docs/plate-simulation/images/methodology/model/overburden_and_basement.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/overburden_and_basement.png rename to docs/plate-simulation/images/methodology/model/overburden_and_basement.png diff --git a/docs/images/plate-simulation/methodology/model/overburden_options.png b/docs/plate-simulation/images/methodology/model/overburden_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/overburden_options.png rename to docs/plate-simulation/images/methodology/model/overburden_options.png diff --git a/docs/images/plate-simulation/methodology/model/plate_location.png b/docs/plate-simulation/images/methodology/model/plate_location.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_location.png rename to docs/plate-simulation/images/methodology/model/plate_location.png diff --git a/docs/images/plate-simulation/methodology/model/plate_location_options.png b/docs/plate-simulation/images/methodology/model/plate_location_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_location_options.png rename to docs/plate-simulation/images/methodology/model/plate_location_options.png diff --git a/docs/images/plate-simulation/methodology/model/plate_options.png b/docs/plate-simulation/images/methodology/model/plate_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_options.png rename to docs/plate-simulation/images/methodology/model/plate_options.png diff --git a/docs/images/plate-simulation/methodology/model/plate_orientation.png b/docs/plate-simulation/images/methodology/model/plate_orientation.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_orientation.png rename to docs/plate-simulation/images/methodology/model/plate_orientation.png diff --git a/docs/images/plate-simulation/methodology/model/plate_orientation_options.png b/docs/plate-simulation/images/methodology/model/plate_orientation_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_orientation_options.png rename to docs/plate-simulation/images/methodology/model/plate_orientation_options.png diff --git a/docs/images/plate-simulation/methodology/model/plate_resistivity_option.png b/docs/plate-simulation/images/methodology/model/plate_resistivity_option.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_resistivity_option.png rename to docs/plate-simulation/images/methodology/model/plate_resistivity_option.png diff --git a/docs/images/plate-simulation/methodology/model/plate_size.png b/docs/plate-simulation/images/methodology/model/plate_size.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_size.png rename to docs/plate-simulation/images/methodology/model/plate_size.png diff --git a/docs/images/plate-simulation/methodology/model/plate_size_options.png b/docs/plate-simulation/images/methodology/model/plate_size_options.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/plate_size_options.png rename to docs/plate-simulation/images/methodology/model/plate_size_options.png diff --git a/docs/images/plate-simulation/methodology/model/three_plates.png b/docs/plate-simulation/images/methodology/model/three_plates.png similarity index 100% rename from docs/images/plate-simulation/methodology/model/three_plates.png rename to docs/plate-simulation/images/methodology/model/three_plates.png diff --git a/docs/images/plate-simulation/methodology/results.png b/docs/plate-simulation/images/methodology/results.png similarity index 100% rename from docs/images/plate-simulation/methodology/results.png rename to docs/plate-simulation/images/methodology/results.png diff --git a/docs/images/plate-simulation/methodology/sweep_option.png b/docs/plate-simulation/images/methodology/sweep_option.png similarity index 100% rename from docs/images/plate-simulation/methodology/sweep_option.png rename to docs/plate-simulation/images/methodology/sweep_option.png diff --git a/docs/images/plate-simulation/methodology/uijson.png b/docs/plate-simulation/images/methodology/uijson.png similarity index 100% rename from docs/images/plate-simulation/methodology/uijson.png rename to docs/plate-simulation/images/methodology/uijson.png diff --git a/docs/plate-simulation/images/summary.png b/docs/plate-simulation/images/summary.png new file mode 100644 index 000000000..8517c2bdb Binary files /dev/null and b/docs/plate-simulation/images/summary.png differ diff --git a/docs/plate-simulation/images/sweep_landing.png b/docs/plate-simulation/images/sweep_landing.png new file mode 100644 index 000000000..59874636c Binary files /dev/null and b/docs/plate-simulation/images/sweep_landing.png differ diff --git a/docs/plate-simulation/images/sweep_uijson.png b/docs/plate-simulation/images/sweep_uijson.png new file mode 100644 index 000000000..6a3bff526 Binary files /dev/null and b/docs/plate-simulation/images/sweep_uijson.png differ diff --git a/docs/plate-simulation/match.rst b/docs/plate-simulation/match.rst new file mode 100644 index 000000000..c44dad3a9 --- /dev/null +++ b/docs/plate-simulation/match.rst @@ -0,0 +1,133 @@ +.. _plate_simulation_match: + +Plate Matching +============== + +The plate matching algorithm searches through a library of pre-computed plate simulations to identify the best-fit conductor geometry for observed electromagnetic data at query locations. The matching process involves spatial and temporal interpolation, data normalization, and correlation-based scoring to rank candidate simulations. + +.. figure:: /plate-simulation/images/match_landing.png + :align: center + :width: 500pt + + + +Interface +--------- + +This section describes the parameters controlling the application. + +.. figure:: /plate-simulation/images/match_uijson.png + :align: center + :width: 300pt + + *Rendered user-interface in Geoscience ANALYST.* + + +Inputs +^^^^^^ + +The algorithm operates on the following inputs: + +- **Survey**: A geophysical survey object containing the airborne TEM measurements and associated metadata +- **EM data**: Airborne time-domain electromagnetic (TEM) measurements from the survey +- **Query Points**: User-defined positions where plate parameters are to be estimated +- **Query Max Distance**: Maximum distance from the query points along the survey line segments for consideration in the matching process +- **Strike angle**: Optional angle to correct for the strike of the conductor relative to the survey line direction +- **Topography**: Object representing the earth-air interface +- **Elevation channel**: Optional channel containing elevation data for the topography locations. Mainly used for digital elevation models provided on Grid2D objects. +- **Simulation directory**: A directory of pre-computed forward simulations representing various plate geometries and conductivities + + +Methodology +----------- + +For each query location, the application identifies the closest survey line segment, extracts relevant observed data, and compares it against all simulations in the library using a multi-step matching process. To accommodate for variable position, time sampling, it is expected that the simulated library contains sufficient variability in plate parameters and survey geometries to capture the range of possible responses. + +.. figure:: /plate-simulation/images/match_template.png + :align: center + :width: 500pt + + Template for the simulated data (black) and observed data (red) used in the matching process. The radial pattern centered on the plate allows to tighten sampling around the peak response, which is critical for accurate matching. + + +The following sections describe the key steps of the matching algorithm. + + +Spatial Interpolation +^^^^^^^^^^^^^^^^^^^^^ + +The application performs spatial interpolation to align simulation data with observation points: + +1. **Local coordinate transformation**: The application identifies the survey line segment nearest to each query location. It transforms both the observed and simulated receiver locations into a local polar coordinate system (distance, azimuth, height) centered on the line segment. + +2. **Strike angle correction**: If strike angles are provided, the application rotates the coordinate system to align the plate orientation with the survey geometry. This accounts for variations in conductor strike relative to the flight line direction. + +3. **Inverse distance weighting**: The application constructs a sparse interpolation matrix using the 8 nearest simulation receivers for each observation point. The weights are computed using inverse distance weighting with a power of 2.0 and a minimum distance threshold of 0.1 to prevent singularities. + +Temporal Interpolation +^^^^^^^^^^^^^^^^^^^^^^ + +Time-domain electromagnetic data requires careful handling of the temporal sampling: + +1. **Time channel alignment**: The application identifies the overlap between simulated and observed time channels. Only time gates within the simulated range are considered for matching. + +2. **Interpolation matrix**: For each observation time within the valid range, the application constructs a sparse interpolation matrix using inverse distance weighting based on the temporal separation between channels. This allows for comparison even when simulated and observed time samplings differ. + +Data Normalization +^^^^^^^^^^^^^^^^^^ + +To enable robust comparison across different conductivity models and survey geometries, the application normalizes both observed and simulated data: + +1. **Symlog transformation**: The application applies a symmetric logarithmic transformation to handle the large dynamic range of electromagnetic decay curves. The threshold is set at the 5th percentile of absolute data values. + +2. **Median centering**: The application subtracts the median value from each time channel to remove DC offsets. + +3. **Amplitude scaling**: The application scales each data profile to unit maximum absolute value, ensuring that shape matching dominates over amplitude matching. + +Orientation Detection +^^^^^^^^^^^^^^^^^^^^^ + +Electromagnetic anomalies are strongly dependent on the direction of approach relative to the conductor dip. Since simulations are only computed in the down-dip direction, the application automatically detects and corrects for orientation reversals: + +1. **Spatial integration**: The application computes the integral of positive anomaly values on each half of the survey segment. + +2. **Asymmetry test**: If more than 50% of the time channels show stronger anomalies on the left side of the segment, the application infers an up-dip approach and reverses the spatial ordering of the data. + +Scoring and Ranking +^^^^^^^^^^^^^^^^^^^ + +For each simulation file in the library, the application computes a match score: + +1. **Cross-correlation**: For each time channel, the application computes the normalized cross-correlation between observed and simulated data. The peak correlation indicates the optimal spatial alignment. + +2. **Alignment consistency**: The application records the index of maximum correlation for each time channel and computes the median alignment position across all channels. + +3. **Residual norm**: The application computes the L2 norm of the difference between observed and amplitude-scaled simulated data across all time channels and spatial locations. This serves as the primary score metric, with lower values indicating better matches. + +4. **Ranking**: The application sorts all simulations by ascending score, with the lowest-scoring simulation representing the best match. + +Plate Parameter Extraction +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Once the best-matching simulation is identified, the application extracts the plate parameters from the simulation metadata: + +1. **Parameter retrieval**: The application reads the conductor geometry (strike length, dip length, width, dip angle, conductivity) from the ui.json metadata stored in the simulation file. + +2. **Spatial positioning**: The application positions the plate at the centroid of the matched survey segment, adjusted vertically by the overburden thickness. + +3. **Orientation correction**: The application applies strike angle corrections based on the local line azimuth and any user-specified strike angle offsets. + +4. **Plate creation**: The application creates a new ``MaxwellPlate`` object in the output workspace with the extracted geometry and stores the full model parameters in the plate metadata. + +Parallel Processing +^^^^^^^^^^^^^^^^^^^ + +The matching algorithm leverages parallel processing to accelerate the comparison of large simulation libraries: + +1. **File batching**: The application divides the simulation library into batches, with approximately 10 batches per worker process. + +2. **Distributed scoring**: Each batch is submitted to a Dask worker for independent scoring. Workers compute spatial and temporal interpolations, normalize data, and calculate correlation scores without inter-process communication. + +3. **Result aggregation**: The main process collects scores from all workers and performs the final ranking to identify the best match for each query location. + +This parallel architecture allows efficient processing of libraries containing hundreds to thousands of pre-computed simulations. diff --git a/docs/plate-simulation/methodology.rst b/docs/plate-simulation/methodology.rst deleted file mode 100644 index 87bbeeea5..000000000 --- a/docs/plate-simulation/methodology.rst +++ /dev/null @@ -1,274 +0,0 @@ -.. _plate_simulation_methodology: - -Plate Simulation: Methodology -============================= - -In order to simulate geophysical data from a physical property model, we -need three things: a computational mesh, a discretization of the model -within that mesh and a means to simulate the data. Plate simulation -relies on `discretize `_ for -octree mesh creation, and `SimPEG `_ for finite -volume based forward modeling. Plate simulation includes a module for -generating a simple two-layer model with embedded plate anomalies within -octree meshes. In this section, we will discuss all three of these -components, their interface exposed by the ui.json file, and the storage -of results. - -.. figure:: /images/plate-simulation/methodology/uijson.png - :align: center - :width: 80% - - *Merged images of both tabs of the ui.json rendered interface.* - -.. contents:: - -.. toctree:: - :maxdepth: 3 - -Octree Mesh ------------ - -In order to accurately simulate our earth model, we need a mesh -that is refined in key areas, while being coarse enough elsewhere to -efficiently simulate data. The plate simulation package includes -refinements at the earth-air interface, the transmitter and receiver -sites and on the surface of plates. - -.. figure:: /images/plate-simulation/methodology/mesh/refinement.png - :align: center - :width: 100% - - *Octree mesh refinement for earth-air interface, receiver sites, - and within the mesh.* - -The meshing can be controlled by options exposed in the ui.json. -Those options are significantly reduced compared with the octree creation from -`grid-app `_ -since we have tailored many of the parameters to suit the needs of plate simulation. - -.. figure:: /images/plate-simulation/methodology/mesh/mesh_options.png - :align: center - - *Octree mesh parameters exposed in the ui.json.* - -Geological Model ----------------- - -The plate simulation package includes a module for generating -plate(s) embedded in a two-layer Earth model within octree meshes. -There are many permutations of this simple geological scenario -leading to a complex interface. To simplify things, we have -broken the discussion into two sub-sections: background -(basement and overburden) and plates. - -Background -~~~~~~~~~~ - -All model values within plate-simulation are to be provided in -ohm-metres. The basement resistivity is actually closer to a -halfspace in the sense that it fills the model anywhere outside -of the overburden and plate. So the basement resistivity should -be chosen as an effective resistivity for the whole geological -section. This should be quite reasonable for most applications -where the differences in resistivity between layers is much smaller -than the difference between overburden and any anomalous bodies -(plates). - -.. figure:: /images/plate-simulation/methodology/model/basement_options.png - :align: center - - *Basement resistivity option.* - -The overburden is discretized by the resistivity and thickness -of the layer. The thickness is referenced to the earth-air -interface and extends into the earth by the amount specified -in the thickness parameter. - -.. figure:: /images/plate-simulation/methodology/model/overburden_options.png - :align: center - - *Overburden resistivity and thickness options.* - -.. figure:: /images/plate-simulation/methodology/model/overburden_and_basement.png - :align: center - :width: 100% - - *Model section highlighting the overburden and basement boundary.* - -Plates -~~~~~~ - -In this section we will discuss the various plate options available -through the ui.json and their impact on the resulting discretized -model. - -.. figure:: /images/plate-simulation/methodology/model/plate_options.png - :align: center - - *Plate options available in the ui.json.* - -The first set of options allows the user to specify the number of -plates and their spacing. - -.. figure:: /images/plate-simulation/methodology/model/n_plates_options.png - :align: center - - *Number of plates and spacing options.* - -For all choices of ``n>1``, the plates will be evenly spaced at the requested -spacing and will share the same resistivity, size and orientation. - -.. figure:: /images/plate-simulation/methodology/model/three_plates.png - :align: center - :width: 100% - - *Model created by choosing three plates spaced at 200m.* - -The plate resistivity is expected to be entered in ohm-metres. - -.. figure:: /images/plate-simulation/methodology/model/plate_resistivity_option.png - :align: center - - *Plate resistivity option.* - -The size of the plate is given as a 'thickness', 'strike length', and -'dip length'. - -.. figure:: /images/plate-simulation/methodology/model/plate_size_options.png - :align: center - - *Plate size options.* - -The image below shows a dipping plate with annotations showing the size -parameters for that particular plate. - -.. figure:: /images/plate-simulation/methodology/model/plate_size.png - :align: center - :width: 100% - - *A dipping plate striking northeast with annotations for its thickness, - strike length and dip length.* - -The orientation of the plate is provided in terms of a dip and dip direction. -The dip is defined as the angle between the horizontal projection of the plate -normal and the plate tangent sharing the same origin. The dip direction is -measured between the horizontal projection of the plate normal and the North -arrow. See the image below for a visual representation of these angles. - -.. figure:: /images/plate-simulation/methodology/model/plate_orientation.png - :align: center - :width: 100% - - *Plate orientation options. Plate orientation is given as a dip and dip direction. - The dip (b) is defined as the angle between the horizontal the projection of the - plate normal (n\') and the plate tangent sharing the same origin (t). The dip - direction (a) is the angle measured between the horizontal projection of the plate - normal (n\') and due north (N).* - -The location of the plate can be provided in both relative and absolute terms. -The position parameters are given as an easting, northing, and elevation. If the -relative locations checkbox is chosen, then the easting and northing will be -relative to the center of the survey and the elevation will be relative to one of -the available references. The elevation may either be referenced to the earth-air -interface or the overburden provided by the ``Depth reference`` dropdown. Either of -these choice can be relative to the minimum, maximum, or mean of the points making -up the reference surface as given by the ``Reference type`` dropdown. In all of these -cases the distance provided will act as a depth below the reference to the *top of -plate* in the *z negative down* convention. If the relative locations checkbox is not -chosen, then the easting, northing, and elevation is simply the location of the -center of the plate. - -.. figure:: /images/plate-simulation/methodology/model/plate_location_options.png - :align: center - - *Plate location options in relative mode. Notice the* ``Elevation`` *is given as - negative to ensure the top of the plate is below the selected min of the - overburden.* - -.. figure:: /images/plate-simulation/methodology/model/plate_location.png - :align: center - :width: 100% - - *Example of a relative elevation referenced 100m below the minimum of the - overburden layer.* - -Data Simulation ---------------- - -.. _simpeg_group_options: - -The simulation parameters control the forward modeling of the plate model -discretized within the octree mesh. Rather than exposing the parameters within -the plate simulation interface all over again, we simply allow the user to -select an existing forward modelling SimPEG group. It is expected that the -user will have already edited those options and provided at least a topography -and survey object as well as selected one or more components to simulate. The -user may also provide a name to the new SimPEG group that will be used to store -the results. - - -.. figure:: /images/plate-simulation/methodology/data/simpeg_group_options.png - :align: center - - *Selecting the initialized forward modelling SimPEG group and naming the - group that will store the plate simulation results.* - -The required SimPEG group can be created within Geoscience ANALYST through the -``Geophysics`` menu under ``SimPEG Python Interface`` entry. - -.. figure:: /images/plate-simulation/methodology/data/simpeg_group_creation.png - :align: center - :width: 100% - - *Creating a SimPEG group to be selected within the plate simulation interface.* - -Once created, the options can be edited by right-clicking the group and choosing -the 'Edit Options' entry. - -.. figure:: /images/plate-simulation/methodology/data/simpeg_group_edit_options.png - :align: center - - *Editing the SimPEG group options.* - -Since plate-simulation will create its own mesh and model, the mesh and -conductivity selections can be ignored. Selecting a value will not conflict -with the plate-simulation objects and will simply be ignored. In contrast, the -survey, topography and at least one component must be selected to run the simulation. - -.. figure:: /images/plate-simulation/methodology/data/simulation_options.png - :align: center - :width: 80% - - *Simulation options with annotations for required and not required components.* - -Results -------- - -The results of the simulation are stored in the SimPEG group named in the -:ref:`simpeg group option ` section. - -.. figure:: /images/plate-simulation/methodology/results.png - :align: center - - *Results group containing a survey object with all the simulated data channels - stored in property groups, and an octree mesh containing the model parameterized - in the interface.* - -To iterate on the design of experiment, simply copy the options, edit, and -run again. - -.. figure:: /images/plate-simulation/methodology/copy_options.png - :align: center - - *Copying the options to run a new simulation.* - -If the user wishes to sweep one or more of the input parameters to run a large number of -simulations, they can use the ``generate sweep file`` option to write a file used -by the `param-sweeps `_ package to do just -that. It is beyond the scope of this document to discuss the use of that package; -refer to its README for further details. - -.. figure:: /images/plate-simulation/methodology/sweep_option.png - :align: center - - *Generating a sweep file to run multiple simulations.* diff --git a/docs/plate-simulation/index.rst b/docs/plate-simulation/simulation.rst similarity index 75% rename from docs/plate-simulation/index.rst rename to docs/plate-simulation/simulation.rst index eb8b29512..9bbd6608d 100644 --- a/docs/plate-simulation/index.rst +++ b/docs/plate-simulation/simulation.rst @@ -1,12 +1,8 @@ -.. _plate_simulation_index: +.. _plate_simulation: Plate Simulation ================ -.. figure:: /images/plate-simulation/index.png - :align: center - :width: 100% - The plate-simulation application is a tool for simulating geophysical data over a simple two-layer earth model with plate(s). It relies on the `discretize `_ @@ -15,7 +11,14 @@ simulate data over the parameterized model. The mesh, model and simulation details are parameterized in a ui.json file that can be rendered in `Geoscience ANALYST Pro `_. -See: +.. figure:: /plate-simulation/images/index.png + :align: center + :width: 500pt + + +.. toctree:: + :maxdepth: 1 -- :ref:`Basic Usage ` -- :ref:`Methodology ` + standalone + sweep + match diff --git a/docs/plate-simulation/standalone.rst b/docs/plate-simulation/standalone.rst new file mode 100644 index 000000000..d2122498b --- /dev/null +++ b/docs/plate-simulation/standalone.rst @@ -0,0 +1,246 @@ +.. _plate_simulation_standalone: + +Interface +========= + +Simulating geophysical data from a physical property model requires three things: +a computational mesh, a discretization of the model within that mesh, and a means +to simulate the data. Plate simulation includes a module for generating a simple +two-layer model with embedded plate anomalies within octree meshes. This section +discusses all three of these components, their interface exposed by the ui.json file, +and the storage of results. + +.. figure:: /plate-simulation/images/methodology/uijson.png + :align: center + :width: 300pt + + *Merged images of both tabs of the ui.json rendered interface.* + + +Geological Model +---------------- + +Plate simulation includes a module for generating plates embedded in a two-layer +Earth model within octree meshes. Many permutations of this simple geological +scenario result in a complex interface. To simplify this, the discussion is +organized into two sub-sections: background (basement and overburden) and plates. +All model values within plate-simulation must be provided in SI units that varies depending on the chosen forward simulation (g/cc, SI or Ohm.m) + +Background +~~~~~~~~~~ + +The basement resistivity is actually closer to a halfspace in the sense that it +fills the model anywhere outside of the overburden and plate. Therefore, the +basement resistivity should be chosen as an effective resistivity for the whole +geological section. This approach is quite reasonable for most applications +where the differences in resistivity between layers are much smaller than the +difference between overburden and any anomalous bodies (plates). + +.. figure:: /plate-simulation/images/methodology/model/basement_options.png + :align: center + + *Basement resistivity option.* + +The overburden is discretized by the resistivity and thickness of the layer. +The thickness is referenced to the earth-air interface and extends into the +earth by the amount specified in the thickness parameter. + +.. figure:: /plate-simulation/images/methodology/model/overburden_options.png + :align: center + + *Overburden resistivity and thickness options.* + +.. figure:: /plate-simulation/images/methodology/model/overburden_and_basement.png + :align: center + :width: 500pt + + *Model section highlighting the overburden and basement boundary.* + +Plates +~~~~~~ + +This section discusses the various plate options available through the ui.json +and their impact on the resulting discretized model. + +.. figure:: /plate-simulation/images/methodology/model/plate_options.png + :align: center + + *Plate options available in the ui.json.* + +The first set of options allows the user to specify the number of plates and +their spacing. + +.. figure:: /plate-simulation/images/methodology/model/n_plates_options.png + :align: center + + *Number of plates and spacing options.* + +For all choices of ``n>1``, the plates are evenly spaced at the requested spacing +and share the same resistivity, size, and orientation. + +.. figure:: /plate-simulation/images/methodology/model/three_plates.png + :align: center + :width: 500pt + + *Model created by choosing three plates spaced at 200m.* + +The plate resistivity must be entered in SI units (g/cc, SI or Ohm.m). + +.. figure:: /plate-simulation/images/methodology/model/plate_resistivity_option.png + :align: center + + *Plate resistivity option.* + +The size of the plate is defined by three parameters: thickness, strike length, +and dip length. + +.. figure:: /plate-simulation/images/methodology/model/plate_size_options.png + :align: center + + *Plate size options.* + +The image below shows a dipping plate with annotations indicating the size +parameters for that particular plate. + +.. figure:: /plate-simulation/images/methodology/model/plate_size.png + :align: center + :width: 500pt + + *A dipping plate striking northeast with annotations for its thickness, + strike length and dip length.* + +The plate orientation is defined in terms of dip and dip direction. The dip +is the angle between the horizontal projection of the plate normal and the +plate tangent sharing the same origin. The dip direction is measured between +the horizontal projection of the plate normal and the North arrow. The image +below provides a visual representation of these angles. + +.. figure:: /plate-simulation/images/methodology/model/plate_orientation.png + :align: center + :width: 500pt + + *Plate orientation options. Plate orientation is given as a dip and dip direction. + The dip (b) is defined as the angle between the horizontal the projection of the + plate normal (n\') and the plate tangent sharing the same origin (t). The dip + direction (a) is the angle measured between the horizontal projection of the plate + normal (n\') and due north (N).* + +The plate location can be specified in both relative and absolute terms. The position +parameters are given as easting, northing, and elevation. If the relative locations +checkbox is selected, the easting and northing are relative to the center of the +survey and the elevation is relative to one of the available references. The elevation +may be referenced to either the earth-air interface or the overburden via the +``Depth reference`` dropdown. Either choice can be relative to the minimum, maximum, +or mean of the points making up the reference surface as given by the ``Reference type`` +dropdown. In all these cases, the distance provided acts as a depth below the reference +to the *top of plate* in the *z negative down* convention. If the relative locations +checkbox is not selected, the easting, northing, and elevation specify the center +location of the plate. + +.. figure:: /plate-simulation/images/methodology/model/plate_location_options.png + :align: center + + *Plate location options in relative mode. Notice the* ``Elevation`` *is given as + negative to ensure the top of the plate is below the selected min of the + overburden.* + +.. figure:: /plate-simulation/images/methodology/model/plate_location.png + :align: center + :width: 500pt + + *Example of a relative elevation referenced 100m below the minimum of the + overburden layer.* + +Data Simulation +--------------- + +.. _simpeg_group_options: + +The simulation parameters control the forward modeling of the plate model +discretized within the octree mesh. Rather than exposing parameters within +the plate simulation interface, the application allows the user to select an +existing forward modelling SimPEG group. The user must ensure that the SimPEG +group has been previously edited with appropriate options, includes at least a +topography and survey object, and has selected one or more components to simulate. +The user may also provide a name for the new SimPEG group to store the results. + +.. figure:: /plate-simulation/images/methodology/data/simpeg_group_options.png + :align: center + + *Selecting the initialized forward modelling SimPEG group and naming the + group that will store the plate simulation results.* + +Create the required SimPEG group within Geoscience ANALYST through the +``Geophysics`` menu under ``SimPEG Python Interface`` entry. + +.. figure:: /plate-simulation/images/methodology/data/simpeg_group_creation.png + :align: center + :width: 300pt + + *Creating a SimPEG group to be selected within the plate simulation interface.* + +Edit the options by right-clicking the group and selecting 'Edit Options'. + +.. figure:: /plate-simulation/images/methodology/data/simpeg_group_edit_options.png + :align: center + :witdht: 300pt + + *Editing the SimPEG group options.* + +Since plate-simulation creates its own mesh and model, the mesh and conductivity +selections can be ignored. Selecting a value does not conflict with the +plate-simulation objects and is simply ignored. In contrast, the survey, topography, +and at least one component must be selected to run the simulation. + +.. figure:: /plate-simulation/images/methodology/data/simulation_options.png + :align: center + :width: 300pt + + *Simulation options with annotations for required and not required components.* + +Octree Mesh +----------- + +To accurately simulate the earth model, the mesh must be refined in key areas +while remaining coarse enough elsewhere to efficiently simulate data. Plate +simulation includes refinements at the earth-air interface, the transmitter and +receiver sites, and on the surface of plates. + +.. figure:: /plate-simulation/images/methodology/mesh/refinement.png + :align: center + :width: 500pt + + *Octree mesh refinement for earth-air interface, receiver sites, + and within the mesh.* + +The meshing is controlled by options exposed in the ui.json. These options are +significantly reduced compared with octree creation from `grid-app `_, +as many parameters have been tailored to suit the needs of plate simulation. + +.. figure:: /plate-simulation/images/methodology/mesh/mesh_options.png + :align: center + :width: 300pt + + *Octree mesh parameters exposed in the ui.json.* + +Results +------- + +The results of the simulation are stored in the SimPEG group named in the +:ref:`simpeg group option ` section. + +.. figure:: /plate-simulation/images/methodology/results.png + :align: center + :width: 300pt + + *Results group containing a survey object with all the simulated data channels + stored in property groups, and an octree mesh containing the model parameterized + in the interface.* + +To iterate on the design of experiment, copy the options, edit them, and run again. + +.. figure:: /plate-simulation/images/methodology/copy_options.png + :align: center + :width: 300pt + + *Copying the options to run a new simulation.* diff --git a/docs/plate-simulation/sweep.rst b/docs/plate-simulation/sweep.rst new file mode 100644 index 000000000..857cc859d --- /dev/null +++ b/docs/plate-simulation/sweep.rst @@ -0,0 +1,48 @@ +.. _plate_simulation_batch: + +Batch Simulations +================= + +The Plate Sweep module provides a user interface for generating and running a batch of simulations by sweeping one or more of the input parameters. The user can select which parameters to sweep and the range of values for each parameter. + +.. figure:: /plate-simulation/images/sweep_landing.png + :align: center + :width: 500pt + +The following sections describe the user interface, inputs, and methodology of the Plate Sweep module. + + +Interface +--------- + +This section describes the parameters controlling the application. + +.. figure:: /plate-simulation/images/sweep_uijson.png + :align: center + :width: 300pt + + *Rendered user-interface in Geoscience ANALYST.* + +Inputs +^^^^^^ + +- **Plate simulation**: A Plate Simulation group that contains the input parameters for a single plate simulation, as well as the connection to a SimPEG Forward group. Parameters that are not included in the sweep will be taken from this group and used for all simulations. +- **Output directory**: A directory where the results of each simulation will be stored. Each simulation will be saved in a separate ``*.geoh5`` file named with a unique identifier. The directory is created if it does not exist, otherwise simulations are appended to it. +- **Generate summary file**: A boolean option to generate a summary file in the output directory. The summary file is a ``*.xls`` file that contains the input parameters and results of each simulation, allowing users to easily sort over the range of simulation parameters. +- **[Optional] Parameter blocks**: For every parameter of `Plate Simulation `_, users can choose a **starting**, **ending** and **number of samples** values to sweep over. The application will generate a simulation for each value in the range, while keeping all other parameters constant. If a parameter is not included in the sweep, the value set in the input Plate Simulation group will be used for all simulations. + + +Methodology +----------- + +After loading the input parameters from the Plate Simulation group, the application generates a list of parameter combinations based on the specified sweep ranges. For each combination of parameters, a unique identifier is generated using a hash system. If this unique identifier already exists in the ``Output directory``, the simulation is skipped. Otherwise a copy of the original input ``geoh5`` is created. + +The target file is then opened and the Plate Simulation group is modified with the corresponding parameters before running the simulation. The results are saved in the target ``geoh5`` file, and the process is repeated for the next combination of parameters until all combinations have been processed. + +If the `dask.distributed `_ library is enabled, the simulations are run in parallel using a local cluster. Otherwise, the simulations are run sequentially. + +Finally, if the option to generate a summary file is enabled, a routine extracts parameters from all ``*.geoh5`` files present in the ``Output director`` and tabulates them in a ``summary.xls`` file for easy reference and analysis. + +.. figure:: /plate-simulation/images/summary.png + :align: center + :width: 500pt diff --git a/docs/plate-simulation/usage.rst b/docs/plate-simulation/usage.rst deleted file mode 100644 index f940b6ca8..000000000 --- a/docs/plate-simulation/usage.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _plate_simulation_usage: - -Plate Simulation: Basic usage -============================= - -The main entry points to the various modules is the `plate_simulation.ui.json `_ -file. The ``ui.json`` has the dual purpose of (1) rendering a user-interface from -Geoscience ANALYST and (2) storing the input parameters chosen by the user for the -program to run. To learn more about the ui.json interface visit the -`UIJson documentation `_ page. - - -User-interface --------------- - -The user-interface is accessible from Geoscience ANALYST Pro Geophysics menu. - -.. figure:: /images/plate-simulation/basic_usage/analyst_geophysics_menu.png - :align: center - :width: 800 - - -From command line ------------------ - -The application can also be run from the command line if all required fields in the ui.json are provided. -This is useful for more advanced users wanting to automate the mesh creation process or re-run an existing mesh with different parameters. - -To run the application from the command line, use the following command in a Conda Prompt: - -``conda activate plate-simulation`` - -``python -m plate-simulation.driver input_file.json`` - -where ``input_file.json`` is the path to the input file on disk. diff --git a/environments/py-3.12-linux-64-dev.conda.lock.yml b/environments/py-3.12-linux-64-dev.conda.lock.yml index 458cf8d57..e5728f9e0 100644 --- a/environments/py-3.12-linux-64-dev.conda.lock.yml +++ b/environments/py-3.12-linux-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 18f7984fd4e53b1c11c474994866c72bc864ec2b5fc0c2d2ff7bbb241676ef48 +# input_hash: aafe1c8abf5f2416d4f10fa06cf2d0c04c47baf7648a31102aaf49033caf8d1a channels: - conda-forge @@ -30,10 +30,10 @@ dependencies: - brotli-python=1.2.0=py312hdb49522_1 - bzip2=1.0.8=hda65f42_9 - c-ares=1.34.6=hb03c661_0 - - ca-certificates=2026.1.4=hbd8a1cb_0 + - ca-certificates=2026.2.25=hbd8a1cb_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - - certifi=2026.1.4=pyhd8ed1ab_0 + - certifi=2026.2.25=pyhd8ed1ab_0 - cffi=2.0.0=py312h460c074_1 - charset-normalizer=3.4.4=pyhd8ed1ab_0 - click=8.3.1=pyh8f84b5b_1 @@ -54,6 +54,7 @@ dependencies: - discretize=0.12.0=np2py312h2a48985_1 - distributed=2025.3.1=pyhd8ed1ab_0 - docutils=0.18.1=py312h7900ff3_1 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - exceptiongroup=1.3.1=pyhd8ed1ab_0 - executing=2.2.1=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 @@ -82,7 +83,7 @@ dependencies: - ipython_pygments_lexers=1.1.1=pyhd8ed1ab_0 - ipywidgets=7.8.5=pyhd8ed1ab_0 - isoduration=20.11.0=pyhd8ed1ab_1 - - isort=8.0.0=pyhd8ed1ab_0 + - isort=8.0.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 @@ -105,7 +106,7 @@ dependencies: - jupytext=1.19.1=pyhbbac1ac_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py312h0a2e395_2 - - krb5=1.21.3=h659f571_0 + - krb5=1.22.2=ha1258a1_0 - lark=1.3.1=pyhd8ed1ab_0 - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45.1=default_hbd61a6d_101 @@ -116,7 +117,7 @@ dependencies: - libbrotlidec=1.2.0=hb03c661_1 - libbrotlienc=1.2.0=hb03c661_1 - libcblas=3.11.0=5_hfef963f_mkl - - libcurl=8.18.0=h4e3cde8_0 + - libcurl=8.18.0=hcf29cc6_1 - libdeflate=1.25=h17f619e_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libedit=3.1.20250104=pl5321h7949ede_0 @@ -138,7 +139,7 @@ dependencies: - libnsl=2.0.1=hb9d3cd8_1 - libpng=1.6.55=h421ea60_0 - libscotch=7.0.11=int64_hfcc3fd4_2 - - libsodium=1.0.20=h4ab18f5_0 + - libsodium=1.0.21=h280c20c_3 - libspatialindex=2.1.0=he57a185_0 - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 @@ -153,10 +154,10 @@ dependencies: - libxml2=2.15.1=h26afc86_0 - libxml2-16=2.15.1=ha9997c6_0 - libzlib=1.3.1=hb9d3cd8_2 - - llvm-openmp=21.1.8=h4922eb0_0 + - llvm-openmp=22.1.0=h4922eb0_0 - locket=1.0.0=pyhd8ed1ab_0 - markdown-it-py=4.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py312h8a5da7c_0 + - markupsafe=3.0.3=py312h8a5da7c_1 - matplotlib-base=3.10.8=py312he3d6523_0 - matplotlib-inline=0.2.1=pyhd8ed1ab_0 - mccabe=0.7.0=pyhd8ed1ab_1 @@ -182,6 +183,7 @@ dependencies: - numcodecs=0.15.1=py312hf79963d_1 - numpy=2.4.2=py312h33ff503_1 - openjpeg=2.5.4=h55fea9a_0 + - openpyxl=3.1.5=py312h7f6eeab_3 - openssl=3.6.1=h35e630c_1 - overrides=7.7.0=pyhd8ed1ab_1 - packaging=26.0=pyhcf101f3_0 @@ -283,7 +285,7 @@ dependencies: - xyzservices=2025.11.0=pyhd8ed1ab_0 - yaml=0.2.5=h280c20c_3 - zarr=2.14.2=pyhd8ed1ab_0 - - zeromq=4.3.5=h387f397_9 + - zeromq=4.3.5=h41580af_10 - zict=3.0.0=pyhd8ed1ab_1 - zipp=3.23.0=pyhcf101f3_1 - zlib=1.3.1=hb9d3cd8_2 diff --git a/environments/py-3.12-linux-64.conda.lock.yml b/environments/py-3.12-linux-64.conda.lock.yml index daa2b57af..803794387 100644 --- a/environments/py-3.12-linux-64.conda.lock.yml +++ b/environments/py-3.12-linux-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 18f7984fd4e53b1c11c474994866c72bc864ec2b5fc0c2d2ff7bbb241676ef48 +# input_hash: aafe1c8abf5f2416d4f10fa06cf2d0c04c47baf7648a31102aaf49033caf8d1a channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - brotli-python=1.2.0=py312hdb49522_1 - bzip2=1.0.8=hda65f42_9 - c-ares=1.34.6=hb03c661_0 - - ca-certificates=2026.1.4=hbd8a1cb_0 + - ca-certificates=2026.2.25=hbd8a1cb_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - click=8.3.1=pyh8f84b5b_1 @@ -28,6 +28,7 @@ dependencies: - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.12.0=np2py312h2a48985_1 - distributed=2025.3.1=pyhd8ed1ab_0 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py312h8a5da7c_0 - freetype=2.14.1=ha770c72_0 @@ -44,7 +45,7 @@ dependencies: - joblib=1.5.3=pyhd8ed1ab_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py312h0a2e395_2 - - krb5=1.21.3=h659f571_0 + - krb5=1.22.2=ha1258a1_0 - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45.1=default_hbd61a6d_101 - lerc=4.0.0=h0aef613_1 @@ -54,7 +55,7 @@ dependencies: - libbrotlidec=1.2.0=hb03c661_1 - libbrotlienc=1.2.0=hb03c661_1 - libcblas=3.11.0=5_hfef963f_mkl - - libcurl=8.18.0=h4e3cde8_0 + - libcurl=8.18.0=hcf29cc6_1 - libdeflate=1.25=h17f619e_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libedit=3.1.20250104=pl5321h7949ede_0 @@ -89,9 +90,9 @@ dependencies: - libxml2=2.15.1=h26afc86_0 - libxml2-16=2.15.1=ha9997c6_0 - libzlib=1.3.1=hb9d3cd8_2 - - llvm-openmp=21.1.8=h4922eb0_0 + - llvm-openmp=22.1.0=h4922eb0_0 - locket=1.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py312h8a5da7c_0 + - markupsafe=3.0.3=py312h8a5da7c_1 - matplotlib-base=3.10.8=py312he3d6523_0 - metis=5.1.0=hd0bcaf9_1007 - mkl=2025.3.0=h0e700b2_463 @@ -103,6 +104,7 @@ dependencies: - numcodecs=0.15.1=py312hf79963d_1 - numpy=2.4.2=py312h33ff503_1 - openjpeg=2.5.4=h55fea9a_0 + - openpyxl=3.1.5=py312h7f6eeab_3 - openssl=3.6.1=h35e630c_1 - packaging=26.0=pyhcf101f3_0 - pandas=3.0.1=py312h8ecdadd_0 diff --git a/environments/py-3.12-win-64-dev.conda.lock.yml b/environments/py-3.12-win-64-dev.conda.lock.yml index 780b9338e..296097209 100644 --- a/environments/py-3.12-win-64-dev.conda.lock.yml +++ b/environments/py-3.12-win-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: b358c98205f49ff419ad7d744e6cc55510287d85cc89d86740d7cfcc4101d89b +# input_hash: 242cc486eeea4891712e6b25f7d1c4461e1caa4743b40d8b5da026391c01085c channels: - conda-forge @@ -29,10 +29,10 @@ dependencies: - brotli-bin=1.2.0=hfd05255_1 - brotli-python=1.2.0=py312hc6d9e41_1 - bzip2=1.0.8=h0ad9c76_9 - - ca-certificates=2026.1.4=h4c7d964_0 + - ca-certificates=2026.2.25=h4c7d964_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - - certifi=2026.1.4=pyhd8ed1ab_0 + - certifi=2026.2.25=pyhd8ed1ab_0 - cffi=2.0.0=py312he06e257_1 - charset-normalizer=3.4.4=pyhd8ed1ab_0 - click=8.3.1=pyha7b4d00_1 @@ -53,6 +53,7 @@ dependencies: - discretize=0.12.0=np2py312h7c90ba1_1 - distributed=2025.3.1=pyhd8ed1ab_0 - docutils=0.18.1=py312h2e8e312_1 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - exceptiongroup=1.3.1=pyhd8ed1ab_0 - executing=2.2.1=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 @@ -81,7 +82,7 @@ dependencies: - ipython_pygments_lexers=1.1.1=pyhd8ed1ab_0 - ipywidgets=7.8.5=pyhd8ed1ab_0 - isoduration=20.11.0=pyhd8ed1ab_1 - - isort=8.0.0=pyhd8ed1ab_0 + - isort=8.0.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 @@ -103,7 +104,7 @@ dependencies: - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - jupytext=1.19.1=pyhbbac1ac_0 - kiwisolver=1.4.9=py312h78d62e6_2 - - krb5=1.21.3=hdf4eb48_0 + - krb5=1.22.2=h0ea6238_0 - lark=1.3.1=pyhd8ed1ab_0 - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 @@ -113,7 +114,7 @@ dependencies: - libbrotlidec=1.2.0=hfd05255_1 - libbrotlienc=1.2.0=hfd05255_1 - libcblas=3.11.0=5_h2a3cdd5_mkl - - libcurl=8.18.0=h43ecb02_0 + - libcurl=8.18.0=h8206538_1 - libdeflate=1.25=h51727cc_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libexpat=2.7.4=hac47afa_0 @@ -128,7 +129,7 @@ dependencies: - liblapack=3.11.0=5_hf9ab0e9_mkl - liblzma=5.8.2=hfd05255_0 - libpng=1.6.55=h7351971_0 - - libsodium=1.0.20=hc70643c_0 + - libsodium=1.0.21=h6a83c73_3 - libspatialindex=2.1.0=h518811d_0 - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 @@ -139,10 +140,10 @@ dependencies: - libxml2=2.15.1=h779ef1b_1 - libxml2-16=2.15.1=h3cfd58e_1 - libzlib=1.3.1=h2466b09_2 - - llvm-openmp=21.1.8=h4fa8253_0 + - llvm-openmp=22.1.0=h4fa8253_0 - locket=1.0.0=pyhd8ed1ab_0 - markdown-it-py=4.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py312h05f76fc_0 + - markupsafe=3.0.3=py312h05f76fc_1 - matplotlib-base=3.10.8=py312h0ebf65c_0 - matplotlib-inline=0.2.1=pyhd8ed1ab_0 - mccabe=0.7.0=pyhd8ed1ab_1 @@ -159,12 +160,13 @@ dependencies: - nbconvert-pandoc=7.16.6=h7d6f222_1 - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - - nodejs=25.6.1=he453025_0 + - nodejs=25.7.0=h80d1838_0 - notebook=7.5.4=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py312hc128f0a_1 - numpy=2.4.2=py312ha72d056_1 - openjpeg=2.5.4=h24db6dd_0 + - openpyxl=3.1.5=py312h83acffa_3 - openssl=3.6.1=hf411b9b_1 - overrides=7.7.0=pyhd8ed1ab_1 - packaging=26.0=pyhcf101f3_0 @@ -271,7 +273,7 @@ dependencies: - xyzservices=2025.11.0=pyhd8ed1ab_0 - yaml=0.2.5=h6a83c73_3 - zarr=2.14.2=pyhd8ed1ab_0 - - zeromq=4.3.5=h5bddc39_9 + - zeromq=4.3.5=h507cc87_10 - zict=3.0.0=pyhd8ed1ab_1 - zipp=3.23.0=pyhcf101f3_1 - zlib-ng=2.3.3=h0261ad2_1 diff --git a/environments/py-3.12-win-64.conda.lock.yml b/environments/py-3.12-win-64.conda.lock.yml index 8e95c507b..858c391f6 100644 --- a/environments/py-3.12-win-64.conda.lock.yml +++ b/environments/py-3.12-win-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: b358c98205f49ff419ad7d744e6cc55510287d85cc89d86740d7cfcc4101d89b +# input_hash: 242cc486eeea4891712e6b25f7d1c4461e1caa4743b40d8b5da026391c01085c channels: - conda-forge @@ -15,7 +15,7 @@ dependencies: - brotli-bin=1.2.0=hfd05255_1 - brotli-python=1.2.0=py312hc6d9e41_1 - bzip2=1.0.8=h0ad9c76_9 - - ca-certificates=2026.1.4=h4c7d964_0 + - ca-certificates=2026.2.25=h4c7d964_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - click=8.3.1=pyha7b4d00_1 @@ -28,6 +28,7 @@ dependencies: - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.12.0=np2py312h7c90ba1_1 - distributed=2025.3.1=pyhd8ed1ab_0 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py312h05f76fc_0 - freetype=2.14.1=h57928b3_0 @@ -43,7 +44,7 @@ dependencies: - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 - kiwisolver=1.4.9=py312h78d62e6_2 - - krb5=1.21.3=hdf4eb48_0 + - krb5=1.22.2=h0ea6238_0 - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.5=haf901d7_0 @@ -52,7 +53,7 @@ dependencies: - libbrotlidec=1.2.0=hfd05255_1 - libbrotlienc=1.2.0=hfd05255_1 - libcblas=3.11.0=5_h2a3cdd5_mkl - - libcurl=8.18.0=h43ecb02_0 + - libcurl=8.18.0=h8206538_1 - libdeflate=1.25=h51727cc_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libexpat=2.7.4=hac47afa_0 @@ -77,9 +78,9 @@ dependencies: - libxml2=2.15.1=h779ef1b_1 - libxml2-16=2.15.1=h3cfd58e_1 - libzlib=1.3.1=h2466b09_2 - - llvm-openmp=21.1.8=h4fa8253_0 + - llvm-openmp=22.1.0=h4fa8253_0 - locket=1.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py312h05f76fc_0 + - markupsafe=3.0.3=py312h05f76fc_1 - matplotlib-base=3.10.8=py312h0ebf65c_0 - mkl=2025.3.0=hac47afa_455 - msgpack-python=1.1.2=py312hf90b1b7_1 @@ -88,6 +89,7 @@ dependencies: - numcodecs=0.15.1=py312hc128f0a_1 - numpy=2.4.2=py312ha72d056_1 - openjpeg=2.5.4=h24db6dd_0 + - openpyxl=3.1.5=py312h83acffa_3 - openssl=3.6.1=hf411b9b_1 - packaging=26.0=pyhcf101f3_0 - pandas=3.0.1=py312h95189c4_0 diff --git a/environments/py-3.13-linux-64-dev.conda.lock.yml b/environments/py-3.13-linux-64-dev.conda.lock.yml index 98e24089c..5e6b1da04 100644 --- a/environments/py-3.13-linux-64-dev.conda.lock.yml +++ b/environments/py-3.13-linux-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 89bd18bfbcb4a4631e8ed110c1c0381f6a3362cfb8cb8a1006787cad6341cffd +# input_hash: 9c084fb4e43ef817a9ccbd7d830c295486fa3a57249edd4c6a77fb42bd4c7ff0 channels: - conda-forge @@ -30,10 +30,10 @@ dependencies: - brotli-python=1.2.0=py313hf159716_1 - bzip2=1.0.8=hda65f42_9 - c-ares=1.34.6=hb03c661_0 - - ca-certificates=2026.1.4=hbd8a1cb_0 + - ca-certificates=2026.2.25=hbd8a1cb_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - - certifi=2026.1.4=pyhd8ed1ab_0 + - certifi=2026.2.25=pyhd8ed1ab_0 - cffi=2.0.0=py313hf46b229_1 - charset-normalizer=3.4.4=pyhd8ed1ab_0 - click=8.3.1=pyh8f84b5b_1 @@ -54,6 +54,7 @@ dependencies: - discretize=0.12.0=np2py313h0f78c12_1 - distributed=2025.3.1=pyhd8ed1ab_0 - docutils=0.18.1=py313h78bf25f_1 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - exceptiongroup=1.3.1=pyhd8ed1ab_0 - executing=2.2.1=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 @@ -82,7 +83,7 @@ dependencies: - ipython_pygments_lexers=1.1.1=pyhd8ed1ab_0 - ipywidgets=7.8.5=pyhd8ed1ab_0 - isoduration=20.11.0=pyhd8ed1ab_1 - - isort=8.0.0=pyhd8ed1ab_0 + - isort=8.0.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 @@ -105,7 +106,7 @@ dependencies: - jupytext=1.19.1=pyhbbac1ac_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py313hc8edb43_2 - - krb5=1.21.3=h659f571_0 + - krb5=1.22.2=ha1258a1_0 - lark=1.3.1=pyhd8ed1ab_0 - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45.1=default_hbd61a6d_101 @@ -116,7 +117,7 @@ dependencies: - libbrotlidec=1.2.0=hb03c661_1 - libbrotlienc=1.2.0=hb03c661_1 - libcblas=3.11.0=5_hfef963f_mkl - - libcurl=8.18.0=h4e3cde8_0 + - libcurl=8.18.0=hcf29cc6_1 - libdeflate=1.25=h17f619e_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libedit=3.1.20250104=pl5321h7949ede_0 @@ -138,7 +139,7 @@ dependencies: - libnghttp2=1.67.0=had1ee68_0 - libpng=1.6.55=h421ea60_0 - libscotch=7.0.11=int64_hfcc3fd4_2 - - libsodium=1.0.20=h4ab18f5_0 + - libsodium=1.0.21=h280c20c_3 - libspatialindex=2.1.0=he57a185_0 - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 @@ -152,10 +153,10 @@ dependencies: - libxml2=2.15.1=h26afc86_0 - libxml2-16=2.15.1=ha9997c6_0 - libzlib=1.3.1=hb9d3cd8_2 - - llvm-openmp=21.1.8=h4922eb0_0 + - llvm-openmp=22.1.0=h4922eb0_0 - locket=1.0.0=pyhd8ed1ab_0 - markdown-it-py=4.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py313h3dea7bd_0 + - markupsafe=3.0.3=py313h3dea7bd_1 - matplotlib-base=3.10.8=py313h683a580_0 - matplotlib-inline=0.2.1=pyhd8ed1ab_0 - mccabe=0.7.0=pyhd8ed1ab_1 @@ -181,6 +182,7 @@ dependencies: - numcodecs=0.15.1=py313h08cd8bf_1 - numpy=2.4.2=py313hf6604e3_1 - openjpeg=2.5.4=h55fea9a_0 + - openpyxl=3.1.5=py313ha4be090_3 - openssl=3.6.1=h35e630c_1 - overrides=7.7.0=pyhd8ed1ab_1 - packaging=26.0=pyhcf101f3_0 @@ -280,7 +282,7 @@ dependencies: - xyzservices=2025.11.0=pyhd8ed1ab_0 - yaml=0.2.5=h280c20c_3 - zarr=2.14.2=pyhd8ed1ab_0 - - zeromq=4.3.5=h387f397_9 + - zeromq=4.3.5=h41580af_10 - zict=3.0.0=pyhd8ed1ab_1 - zipp=3.23.0=pyhcf101f3_1 - zlib=1.3.1=hb9d3cd8_2 diff --git a/environments/py-3.13-linux-64.conda.lock.yml b/environments/py-3.13-linux-64.conda.lock.yml index aada879ef..aa3673427 100644 --- a/environments/py-3.13-linux-64.conda.lock.yml +++ b/environments/py-3.13-linux-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 89bd18bfbcb4a4631e8ed110c1c0381f6a3362cfb8cb8a1006787cad6341cffd +# input_hash: 9c084fb4e43ef817a9ccbd7d830c295486fa3a57249edd4c6a77fb42bd4c7ff0 channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - brotli-python=1.2.0=py313hf159716_1 - bzip2=1.0.8=hda65f42_9 - c-ares=1.34.6=hb03c661_0 - - ca-certificates=2026.1.4=hbd8a1cb_0 + - ca-certificates=2026.2.25=hbd8a1cb_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - click=8.3.1=pyh8f84b5b_1 @@ -28,6 +28,7 @@ dependencies: - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.12.0=np2py313h0f78c12_1 - distributed=2025.3.1=pyhd8ed1ab_0 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py313h3dea7bd_0 - freetype=2.14.1=ha770c72_0 @@ -44,7 +45,7 @@ dependencies: - joblib=1.5.3=pyhd8ed1ab_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py313hc8edb43_2 - - krb5=1.21.3=h659f571_0 + - krb5=1.22.2=ha1258a1_0 - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45.1=default_hbd61a6d_101 - lerc=4.0.0=h0aef613_1 @@ -54,7 +55,7 @@ dependencies: - libbrotlidec=1.2.0=hb03c661_1 - libbrotlienc=1.2.0=hb03c661_1 - libcblas=3.11.0=5_hfef963f_mkl - - libcurl=8.18.0=h4e3cde8_0 + - libcurl=8.18.0=hcf29cc6_1 - libdeflate=1.25=h17f619e_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libedit=3.1.20250104=pl5321h7949ede_0 @@ -88,9 +89,9 @@ dependencies: - libxml2=2.15.1=h26afc86_0 - libxml2-16=2.15.1=ha9997c6_0 - libzlib=1.3.1=hb9d3cd8_2 - - llvm-openmp=21.1.8=h4922eb0_0 + - llvm-openmp=22.1.0=h4922eb0_0 - locket=1.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py313h3dea7bd_0 + - markupsafe=3.0.3=py313h3dea7bd_1 - matplotlib-base=3.10.8=py313h683a580_0 - metis=5.1.0=hd0bcaf9_1007 - mkl=2025.3.0=h0e700b2_463 @@ -102,6 +103,7 @@ dependencies: - numcodecs=0.15.1=py313h08cd8bf_1 - numpy=2.4.2=py313hf6604e3_1 - openjpeg=2.5.4=h55fea9a_0 + - openpyxl=3.1.5=py313ha4be090_3 - openssl=3.6.1=h35e630c_1 - packaging=26.0=pyhcf101f3_0 - pandas=3.0.1=py313hbfd7664_0 diff --git a/environments/py-3.13-win-64-dev.conda.lock.yml b/environments/py-3.13-win-64-dev.conda.lock.yml index 81c46e348..dcae0d380 100644 --- a/environments/py-3.13-win-64-dev.conda.lock.yml +++ b/environments/py-3.13-win-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 88e9d148e8962a73f08ec4acb1a027dd3c20c9518803da0467f730d3e661d9f6 +# input_hash: 634cec3ecb56deda7d45fbb3187fdfd23a39124f4735afaafd63281ac1d4e160 channels: - conda-forge @@ -29,10 +29,10 @@ dependencies: - brotli-bin=1.2.0=hfd05255_1 - brotli-python=1.2.0=py313h3ebfc14_1 - bzip2=1.0.8=h0ad9c76_9 - - ca-certificates=2026.1.4=h4c7d964_0 + - ca-certificates=2026.2.25=h4c7d964_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - - certifi=2026.1.4=pyhd8ed1ab_0 + - certifi=2026.2.25=pyhd8ed1ab_0 - cffi=2.0.0=py313h5ea7bf4_1 - charset-normalizer=3.4.4=pyhd8ed1ab_0 - click=8.3.1=pyha7b4d00_1 @@ -53,6 +53,7 @@ dependencies: - discretize=0.12.0=np2py313hedd11bf_1 - distributed=2025.3.1=pyhd8ed1ab_0 - docutils=0.18.1=py313hfa70ccb_1 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - exceptiongroup=1.3.1=pyhd8ed1ab_0 - executing=2.2.1=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 @@ -81,7 +82,7 @@ dependencies: - ipython_pygments_lexers=1.1.1=pyhd8ed1ab_0 - ipywidgets=7.8.5=pyhd8ed1ab_0 - isoduration=20.11.0=pyhd8ed1ab_1 - - isort=8.0.0=pyhd8ed1ab_0 + - isort=8.0.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 @@ -103,7 +104,7 @@ dependencies: - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - jupytext=1.19.1=pyhbbac1ac_0 - kiwisolver=1.4.9=py313h1a38498_2 - - krb5=1.21.3=hdf4eb48_0 + - krb5=1.22.2=h0ea6238_0 - lark=1.3.1=pyhd8ed1ab_0 - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 @@ -113,7 +114,7 @@ dependencies: - libbrotlidec=1.2.0=hfd05255_1 - libbrotlienc=1.2.0=hfd05255_1 - libcblas=3.11.0=5_h2a3cdd5_mkl - - libcurl=8.18.0=h43ecb02_0 + - libcurl=8.18.0=h8206538_1 - libdeflate=1.25=h51727cc_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libexpat=2.7.4=hac47afa_0 @@ -129,7 +130,7 @@ dependencies: - liblzma=5.8.2=hfd05255_0 - libmpdec=4.0.0=hfd05255_1 - libpng=1.6.55=h7351971_0 - - libsodium=1.0.20=hc70643c_0 + - libsodium=1.0.21=h6a83c73_3 - libspatialindex=2.1.0=h518811d_0 - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 @@ -140,10 +141,10 @@ dependencies: - libxml2=2.15.1=h779ef1b_1 - libxml2-16=2.15.1=h3cfd58e_1 - libzlib=1.3.1=h2466b09_2 - - llvm-openmp=21.1.8=h4fa8253_0 + - llvm-openmp=22.1.0=h4fa8253_0 - locket=1.0.0=pyhd8ed1ab_0 - markdown-it-py=4.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py313hd650c13_0 + - markupsafe=3.0.3=py313hd650c13_1 - matplotlib-base=3.10.8=py313he1ded55_0 - matplotlib-inline=0.2.1=pyhd8ed1ab_0 - mccabe=0.7.0=pyhd8ed1ab_1 @@ -160,12 +161,13 @@ dependencies: - nbconvert-pandoc=7.16.6=h7d6f222_1 - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - - nodejs=25.6.1=he453025_0 + - nodejs=25.7.0=h80d1838_0 - notebook=7.5.4=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py313hc90dcd4_1 - numpy=2.4.2=py313hce7ae62_1 - openjpeg=2.5.4=h24db6dd_0 + - openpyxl=3.1.5=py313hc624790_3 - openssl=3.6.1=hf411b9b_1 - overrides=7.7.0=pyhd8ed1ab_1 - packaging=26.0=pyhcf101f3_0 @@ -270,7 +272,7 @@ dependencies: - xyzservices=2025.11.0=pyhd8ed1ab_0 - yaml=0.2.5=h6a83c73_3 - zarr=2.14.2=pyhd8ed1ab_0 - - zeromq=4.3.5=h5bddc39_9 + - zeromq=4.3.5=h507cc87_10 - zict=3.0.0=pyhd8ed1ab_1 - zipp=3.23.0=pyhcf101f3_1 - zlib-ng=2.3.3=h0261ad2_1 diff --git a/environments/py-3.13-win-64.conda.lock.yml b/environments/py-3.13-win-64.conda.lock.yml index 4130ca9d5..a430ab249 100644 --- a/environments/py-3.13-win-64.conda.lock.yml +++ b/environments/py-3.13-win-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 88e9d148e8962a73f08ec4acb1a027dd3c20c9518803da0467f730d3e661d9f6 +# input_hash: 634cec3ecb56deda7d45fbb3187fdfd23a39124f4735afaafd63281ac1d4e160 channels: - conda-forge @@ -15,7 +15,7 @@ dependencies: - brotli-bin=1.2.0=hfd05255_1 - brotli-python=1.2.0=py313h3ebfc14_1 - bzip2=1.0.8=h0ad9c76_9 - - ca-certificates=2026.1.4=h4c7d964_0 + - ca-certificates=2026.2.25=h4c7d964_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - click=8.3.1=pyha7b4d00_1 @@ -28,6 +28,7 @@ dependencies: - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.12.0=np2py313hedd11bf_1 - distributed=2025.3.1=pyhd8ed1ab_0 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py313hd650c13_0 - freetype=2.14.1=h57928b3_0 @@ -43,7 +44,7 @@ dependencies: - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 - kiwisolver=1.4.9=py313h1a38498_2 - - krb5=1.21.3=hdf4eb48_0 + - krb5=1.22.2=h0ea6238_0 - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.5=haf901d7_0 @@ -52,7 +53,7 @@ dependencies: - libbrotlidec=1.2.0=hfd05255_1 - libbrotlienc=1.2.0=hfd05255_1 - libcblas=3.11.0=5_h2a3cdd5_mkl - - libcurl=8.18.0=h43ecb02_0 + - libcurl=8.18.0=h8206538_1 - libdeflate=1.25=h51727cc_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libexpat=2.7.4=hac47afa_0 @@ -78,9 +79,9 @@ dependencies: - libxml2=2.15.1=h779ef1b_1 - libxml2-16=2.15.1=h3cfd58e_1 - libzlib=1.3.1=h2466b09_2 - - llvm-openmp=21.1.8=h4fa8253_0 + - llvm-openmp=22.1.0=h4fa8253_0 - locket=1.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=py313hd650c13_0 + - markupsafe=3.0.3=py313hd650c13_1 - matplotlib-base=3.10.8=py313he1ded55_0 - mkl=2025.3.0=hac47afa_455 - msgpack-python=1.1.2=py313hf069bd2_1 @@ -89,6 +90,7 @@ dependencies: - numcodecs=0.15.1=py313hc90dcd4_1 - numpy=2.4.2=py313hce7ae62_1 - openjpeg=2.5.4=h24db6dd_0 + - openpyxl=3.1.5=py313hc624790_3 - openssl=3.6.1=hf411b9b_1 - packaging=26.0=pyhcf101f3_0 - pandas=3.0.1=py313h26f5e95_0 diff --git a/environments/py-3.14-linux-64-dev.conda.lock.yml b/environments/py-3.14-linux-64-dev.conda.lock.yml index 0cca742c7..64447e3be 100644 --- a/environments/py-3.14-linux-64-dev.conda.lock.yml +++ b/environments/py-3.14-linux-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: fec79b278904505e81d33ac893dfed5eeb76485fd55928cd6ec8b42277cf64fe +# input_hash: 6b8cd4100493c90834719717e9dba0c8025d7cf52a516970a8ba54b345ad21d1 channels: - conda-forge @@ -30,10 +30,10 @@ dependencies: - brotli-python=1.2.0=py314h3de4e8d_1 - bzip2=1.0.8=hda65f42_9 - c-ares=1.34.6=hb03c661_0 - - ca-certificates=2026.1.4=hbd8a1cb_0 + - ca-certificates=2026.2.25=hbd8a1cb_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - - certifi=2026.1.4=pyhd8ed1ab_0 + - certifi=2026.2.25=pyhd8ed1ab_0 - cffi=2.0.0=py314h4a8dc5f_1 - charset-normalizer=3.4.4=pyhd8ed1ab_0 - click=8.3.1=pyh8f84b5b_1 @@ -54,6 +54,7 @@ dependencies: - discretize=0.12.0=np2py314hb287c12_1 - distributed=2025.3.1=pyhd8ed1ab_0 - docutils=0.18.1=py314hdafbbf9_1 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - exceptiongroup=1.3.1=pyhd8ed1ab_0 - executing=2.2.1=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 @@ -82,7 +83,7 @@ dependencies: - ipython_pygments_lexers=1.1.1=pyhd8ed1ab_0 - ipywidgets=7.8.5=pyhd8ed1ab_0 - isoduration=20.11.0=pyhd8ed1ab_1 - - isort=8.0.0=pyhd8ed1ab_0 + - isort=8.0.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 @@ -105,7 +106,7 @@ dependencies: - jupytext=1.19.1=pyhbbac1ac_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py314h97ea11e_2 - - krb5=1.21.3=h659f571_0 + - krb5=1.22.2=ha1258a1_0 - lark=1.3.1=pyhd8ed1ab_0 - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45.1=default_hbd61a6d_101 @@ -116,7 +117,7 @@ dependencies: - libbrotlidec=1.2.0=hb03c661_1 - libbrotlienc=1.2.0=hb03c661_1 - libcblas=3.11.0=5_hfef963f_mkl - - libcurl=8.18.0=h4e3cde8_0 + - libcurl=8.18.0=hcf29cc6_1 - libdeflate=1.25=h17f619e_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libedit=3.1.20250104=pl5321h7949ede_0 @@ -138,7 +139,7 @@ dependencies: - libnghttp2=1.67.0=had1ee68_0 - libpng=1.6.55=h421ea60_0 - libscotch=7.0.11=int64_hfcc3fd4_2 - - libsodium=1.0.20=h4ab18f5_0 + - libsodium=1.0.21=h280c20c_3 - libspatialindex=2.1.0=he57a185_0 - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 @@ -152,10 +153,10 @@ dependencies: - libxml2=2.15.1=h26afc86_0 - libxml2-16=2.15.1=ha9997c6_0 - libzlib=1.3.1=hb9d3cd8_2 - - llvm-openmp=21.1.8=h4922eb0_0 + - llvm-openmp=22.1.0=h4922eb0_0 - locket=1.0.0=pyhd8ed1ab_0 - markdown-it-py=4.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=pyh7db6752_0 + - markupsafe=3.0.3=py314h67df5f8_1 - matplotlib-base=3.10.8=py314h1194b4b_0 - matplotlib-inline=0.2.1=pyhd8ed1ab_0 - mccabe=0.7.0=pyhd8ed1ab_1 @@ -181,6 +182,7 @@ dependencies: - numcodecs=0.15.1=py314ha0b5721_1 - numpy=2.4.2=py314h2b28147_1 - openjpeg=2.5.4=h55fea9a_0 + - openpyxl=3.1.5=py314hf3b76af_3 - openssl=3.6.1=h35e630c_1 - overrides=7.7.0=pyhd8ed1ab_1 - packaging=26.0=pyhcf101f3_0 @@ -281,7 +283,7 @@ dependencies: - xyzservices=2025.11.0=pyhd8ed1ab_0 - yaml=0.2.5=h280c20c_3 - zarr=2.14.2=pyhd8ed1ab_0 - - zeromq=4.3.5=h387f397_9 + - zeromq=4.3.5=h41580af_10 - zict=3.0.0=pyhd8ed1ab_1 - zipp=3.23.0=pyhcf101f3_1 - zlib=1.3.1=hb9d3cd8_2 diff --git a/environments/py-3.14-linux-64.conda.lock.yml b/environments/py-3.14-linux-64.conda.lock.yml index c64a38f2e..b74ce4e84 100644 --- a/environments/py-3.14-linux-64.conda.lock.yml +++ b/environments/py-3.14-linux-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: fec79b278904505e81d33ac893dfed5eeb76485fd55928cd6ec8b42277cf64fe +# input_hash: 6b8cd4100493c90834719717e9dba0c8025d7cf52a516970a8ba54b345ad21d1 channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - brotli-python=1.2.0=py314h3de4e8d_1 - bzip2=1.0.8=hda65f42_9 - c-ares=1.34.6=hb03c661_0 - - ca-certificates=2026.1.4=hbd8a1cb_0 + - ca-certificates=2026.2.25=hbd8a1cb_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - click=8.3.1=pyh8f84b5b_1 @@ -28,6 +28,7 @@ dependencies: - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.12.0=np2py314hb287c12_1 - distributed=2025.3.1=pyhd8ed1ab_0 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=pyh7db6752_0 - freetype=2.14.1=ha770c72_0 @@ -44,7 +45,7 @@ dependencies: - joblib=1.5.3=pyhd8ed1ab_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py314h97ea11e_2 - - krb5=1.21.3=h659f571_0 + - krb5=1.22.2=ha1258a1_0 - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45.1=default_hbd61a6d_101 - lerc=4.0.0=h0aef613_1 @@ -54,7 +55,7 @@ dependencies: - libbrotlidec=1.2.0=hb03c661_1 - libbrotlienc=1.2.0=hb03c661_1 - libcblas=3.11.0=5_hfef963f_mkl - - libcurl=8.18.0=h4e3cde8_0 + - libcurl=8.18.0=hcf29cc6_1 - libdeflate=1.25=h17f619e_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libedit=3.1.20250104=pl5321h7949ede_0 @@ -88,9 +89,9 @@ dependencies: - libxml2=2.15.1=h26afc86_0 - libxml2-16=2.15.1=ha9997c6_0 - libzlib=1.3.1=hb9d3cd8_2 - - llvm-openmp=21.1.8=h4922eb0_0 + - llvm-openmp=22.1.0=h4922eb0_0 - locket=1.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=pyh7db6752_0 + - markupsafe=3.0.3=py314h67df5f8_1 - matplotlib-base=3.10.8=py314h1194b4b_0 - metis=5.1.0=hd0bcaf9_1007 - mkl=2025.3.0=h0e700b2_463 @@ -102,6 +103,7 @@ dependencies: - numcodecs=0.15.1=py314ha0b5721_1 - numpy=2.4.2=py314h2b28147_1 - openjpeg=2.5.4=h55fea9a_0 + - openpyxl=3.1.5=py314hf3b76af_3 - openssl=3.6.1=h35e630c_1 - packaging=26.0=pyhcf101f3_0 - pandas=3.0.1=py314hb4ffadd_0 diff --git a/environments/py-3.14-win-64-dev.conda.lock.yml b/environments/py-3.14-win-64-dev.conda.lock.yml index 751a9f80a..4e02d5542 100644 --- a/environments/py-3.14-win-64-dev.conda.lock.yml +++ b/environments/py-3.14-win-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 7515184deff7a63cb5b766f656c71ba39e7ef96fc2642f588c3cd6ca6e9ab206 +# input_hash: b56575358cf9c86097af766e84815a217fa1f2932b34252343b018b28a5ce092 channels: - conda-forge @@ -29,10 +29,10 @@ dependencies: - brotli-bin=1.2.0=hfd05255_1 - brotli-python=1.2.0=py314he701e3d_1 - bzip2=1.0.8=h0ad9c76_9 - - ca-certificates=2026.1.4=h4c7d964_0 + - ca-certificates=2026.2.25=h4c7d964_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - - certifi=2026.1.4=pyhd8ed1ab_0 + - certifi=2026.2.25=pyhd8ed1ab_0 - cffi=2.0.0=py314h5a2d7ad_1 - charset-normalizer=3.4.4=pyhd8ed1ab_0 - click=8.3.1=pyha7b4d00_1 @@ -53,6 +53,7 @@ dependencies: - discretize=0.12.0=np2py314h1495373_1 - distributed=2025.3.1=pyhd8ed1ab_0 - docutils=0.18.1=py314h86ab7b2_1 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - exceptiongroup=1.3.1=pyhd8ed1ab_0 - executing=2.2.1=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 @@ -81,7 +82,7 @@ dependencies: - ipython_pygments_lexers=1.1.1=pyhd8ed1ab_0 - ipywidgets=7.8.5=pyhd8ed1ab_0 - isoduration=20.11.0=pyhd8ed1ab_1 - - isort=8.0.0=pyhd8ed1ab_0 + - isort=8.0.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 @@ -103,7 +104,7 @@ dependencies: - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - jupytext=1.19.1=pyhbbac1ac_0 - kiwisolver=1.4.9=py314hf309875_2 - - krb5=1.21.3=hdf4eb48_0 + - krb5=1.22.2=h0ea6238_0 - lark=1.3.1=pyhd8ed1ab_0 - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 @@ -113,7 +114,7 @@ dependencies: - libbrotlidec=1.2.0=hfd05255_1 - libbrotlienc=1.2.0=hfd05255_1 - libcblas=3.11.0=5_h2a3cdd5_mkl - - libcurl=8.18.0=h43ecb02_0 + - libcurl=8.18.0=h8206538_1 - libdeflate=1.25=h51727cc_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libexpat=2.7.4=hac47afa_0 @@ -129,7 +130,7 @@ dependencies: - liblzma=5.8.2=hfd05255_0 - libmpdec=4.0.0=hfd05255_1 - libpng=1.6.55=h7351971_0 - - libsodium=1.0.20=hc70643c_0 + - libsodium=1.0.21=h6a83c73_3 - libspatialindex=2.1.0=h518811d_0 - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 @@ -140,10 +141,10 @@ dependencies: - libxml2=2.15.1=h779ef1b_1 - libxml2-16=2.15.1=h3cfd58e_1 - libzlib=1.3.1=h2466b09_2 - - llvm-openmp=21.1.8=h4fa8253_0 + - llvm-openmp=22.1.0=h4fa8253_0 - locket=1.0.0=pyhd8ed1ab_0 - markdown-it-py=4.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=pyh7db6752_0 + - markupsafe=3.0.3=py314h2359020_1 - matplotlib-base=3.10.8=py314hfa45d96_0 - matplotlib-inline=0.2.1=pyhd8ed1ab_0 - mccabe=0.7.0=pyhd8ed1ab_1 @@ -160,12 +161,13 @@ dependencies: - nbconvert-pandoc=7.16.6=h7d6f222_1 - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - - nodejs=25.6.1=he453025_0 + - nodejs=25.7.0=h80d1838_0 - notebook=7.5.4=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py314hd8fd7ce_1 - numpy=2.4.2=py314h06c3c77_1 - openjpeg=2.5.4=h24db6dd_0 + - openpyxl=3.1.5=py314hccc76fc_3 - openssl=3.6.1=hf411b9b_1 - overrides=7.7.0=pyhd8ed1ab_1 - packaging=26.0=pyhcf101f3_0 @@ -271,7 +273,7 @@ dependencies: - xyzservices=2025.11.0=pyhd8ed1ab_0 - yaml=0.2.5=h6a83c73_3 - zarr=2.14.2=pyhd8ed1ab_0 - - zeromq=4.3.5=h5bddc39_9 + - zeromq=4.3.5=h507cc87_10 - zict=3.0.0=pyhd8ed1ab_1 - zipp=3.23.0=pyhcf101f3_1 - zlib-ng=2.3.3=h0261ad2_1 diff --git a/environments/py-3.14-win-64.conda.lock.yml b/environments/py-3.14-win-64.conda.lock.yml index 7933c4835..6b2faf560 100644 --- a/environments/py-3.14-win-64.conda.lock.yml +++ b/environments/py-3.14-win-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 7515184deff7a63cb5b766f656c71ba39e7ef96fc2642f588c3cd6ca6e9ab206 +# input_hash: b56575358cf9c86097af766e84815a217fa1f2932b34252343b018b28a5ce092 channels: - conda-forge @@ -15,7 +15,7 @@ dependencies: - brotli-bin=1.2.0=hfd05255_1 - brotli-python=1.2.0=py314he701e3d_1 - bzip2=1.0.8=h0ad9c76_9 - - ca-certificates=2026.1.4=h4c7d964_0 + - ca-certificates=2026.2.25=h4c7d964_0 - cached-property=1.5.2=hd8ed1ab_1 - cached_property=1.5.2=pyha770c72_1 - click=8.3.1=pyha7b4d00_1 @@ -28,6 +28,7 @@ dependencies: - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.12.0=np2py314h1495373_1 - distributed=2025.3.1=pyhd8ed1ab_0 + - et_xmlfile=2.0.0=pyhd8ed1ab_1 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=pyh7db6752_0 - freetype=2.14.1=h57928b3_0 @@ -43,7 +44,7 @@ dependencies: - jinja2=3.1.6=pyhcf101f3_1 - joblib=1.5.3=pyhd8ed1ab_0 - kiwisolver=1.4.9=py314hf309875_2 - - krb5=1.21.3=hdf4eb48_0 + - krb5=1.22.2=h0ea6238_0 - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.5=haf901d7_0 @@ -52,7 +53,7 @@ dependencies: - libbrotlidec=1.2.0=hfd05255_1 - libbrotlienc=1.2.0=hfd05255_1 - libcblas=3.11.0=5_h2a3cdd5_mkl - - libcurl=8.18.0=h43ecb02_0 + - libcurl=8.18.0=h8206538_1 - libdeflate=1.25=h51727cc_0 - libdlf=0.3.0=pyhd8ed1ab_1 - libexpat=2.7.4=hac47afa_0 @@ -78,9 +79,9 @@ dependencies: - libxml2=2.15.1=h779ef1b_1 - libxml2-16=2.15.1=h3cfd58e_1 - libzlib=1.3.1=h2466b09_2 - - llvm-openmp=21.1.8=h4fa8253_0 + - llvm-openmp=22.1.0=h4fa8253_0 - locket=1.0.0=pyhd8ed1ab_0 - - markupsafe=3.0.3=pyh7db6752_0 + - markupsafe=3.0.3=py314h2359020_1 - matplotlib-base=3.10.8=py314hfa45d96_0 - mkl=2025.3.0=hac47afa_455 - msgpack-python=1.1.2=py314h909e829_1 @@ -89,6 +90,7 @@ dependencies: - numcodecs=0.15.1=py314hd8fd7ce_1 - numpy=2.4.2=py314h06c3c77_1 - openjpeg=2.5.4=h24db6dd_0 + - openpyxl=3.1.5=py314hccc76fc_3 - openssl=3.6.1=hf411b9b_1 - packaging=26.0=pyhcf101f3_0 - pandas=3.0.1=py314hf700ef7_0 diff --git a/py-3.12.conda-lock.yml b/py-3.12.conda-lock.yml index 5ff6a6d73..ef6e02acf 100644 --- a/py-3.12.conda-lock.yml +++ b/py-3.12.conda-lock.yml @@ -15,8 +15,8 @@ version: 1 metadata: content_hash: - win-64: b358c98205f49ff419ad7d744e6cc55510287d85cc89d86740d7cfcc4101d89b - linux-64: 18f7984fd4e53b1c11c474994866c72bc864ec2b5fc0c2d2ff7bbb241676ef48 + win-64: 242cc486eeea4891712e6b25f7d1c4461e1caa4743b40d8b5da026391c01085c + linux-64: aafe1c8abf5f2416d4f10fa06cf2d0c04c47baf7648a31102aaf49033caf8d1a channels: - url: conda-forge used_env_vars: [] @@ -691,27 +691,27 @@ package: category: main optional: false - name: ca-certificates - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: linux-64 dependencies: __unix: '' - url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda hash: - md5: bddacf101bb4dd0e51811cb69c7790e2 - sha256: b5974ec9b50e3c514a382335efa81ed02b05906849827a34061c496f4defa0b2 + md5: 4492fd26db29495f0ba23f146cd5638d + sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc category: main optional: false - name: ca-certificates - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: win-64 dependencies: __win: '' - url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.1.4-h4c7d964_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda hash: - md5: 84d389c9eee640dda3d26fc5335c67d8 - sha256: 4ddcb01be03f85d3db9d881407fb13a673372f1b9fac9c836ea441893390e049 + md5: f001e6e220355b7f87403a4d0e5bf1ca + sha256: 37950019c59b99585cee5d30dbc2cc9696ed4e11f5742606a4db1621ed8f94d6 category: main optional: false - name: cached-property @@ -763,27 +763,27 @@ package: category: main optional: false - name: certifi - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.1.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda hash: - md5: eacc711330cd46939f66cd401ff9c44b - sha256: 110338066d194a715947808611b763857c15458f8b3b97197387356844af9450 + md5: 765c4d97e877cdbbb88ff33152b86125 + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 category: dev optional: true - name: certifi - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.1.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda hash: - md5: eacc711330cd46939f66cd401ff9c44b - sha256: 110338066d194a715947808611b763857c15458f8b3b97197387356844af9450 + md5: 765c4d97e877cdbbb88ff33152b86125 + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 category: dev optional: true - name: cffi @@ -1381,6 +1381,30 @@ package: sha256: 517fe814fbfe570978369bc6dd9f951739293cf90905213204f30b2c29df7946 category: dev optional: true +- name: et_xmlfile + version: 2.0.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.9' + url: https://repo.prefix.dev/conda-forge/noarch/et_xmlfile-2.0.0-pyhd8ed1ab_1.conda + hash: + md5: 71bf9646cbfabf3022c8da4b6b4da737 + sha256: 2209534fbf2f70c20661ff31f57ab6a97b82ee98812e8a2dcb2b36a0d345727c + category: main + optional: false +- name: et_xmlfile + version: 2.0.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.9' + url: https://repo.prefix.dev/conda-forge/noarch/et_xmlfile-2.0.0-pyhd8ed1ab_1.conda + hash: + md5: 71bf9646cbfabf3022c8da4b6b4da737 + sha256: 2209534fbf2f70c20661ff31f57ab6a97b82ee98812e8a2dcb2b36a0d345727c + category: main + optional: false - name: exceptiongroup version: 1.3.1 manager: conda @@ -2210,29 +2234,29 @@ package: category: dev optional: true - name: isort - version: 8.0.0 + version: 8.0.1 manager: conda platform: linux-64 dependencies: importlib-metadata: '>=4.6.0' python: '>=3.10,<4.0' - url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.1-pyhd8ed1ab_0.conda hash: - md5: 83297265e95a934c256d04177ad09293 - sha256: 7b2620c8aee9cf8c11dd70f2729cd29078a4f0e9f04acb3e24ce8ab41ecd3c27 + md5: 98cdd8615792e90da1023bc546f806d9 + sha256: cc5c2b513143ea9675ba5b3570182f7568fd1029b299ee3bc58424dcce8c5539 category: dev optional: true - name: isort - version: 8.0.0 + version: 8.0.1 manager: conda platform: win-64 dependencies: importlib-metadata: '>=4.6.0' python: '>=3.10,<4.0' - url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.1-pyhd8ed1ab_0.conda hash: - md5: 83297265e95a934c256d04177ad09293 - sha256: 7b2620c8aee9cf8c11dd70f2729cd29078a4f0e9f04acb3e24ce8ab41ecd3c27 + md5: 98cdd8615792e90da1023bc546f806d9 + sha256: cc5c2b513143ea9675ba5b3570182f7568fd1029b299ee3bc58424dcce8c5539 category: dev optional: true - name: jedi @@ -2936,34 +2960,35 @@ package: category: main optional: false - name: krb5 - version: 1.21.3 + version: 1.22.2 manager: conda platform: linux-64 dependencies: - keyutils: '>=1.6.1,<2.0a0' - libedit: '>=3.1.20191231,<4.0a0' - libgcc-ng: '>=12' - libstdcxx-ng: '>=12' - openssl: '>=3.3.1,<4.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + __glibc: '>=2.17,<3.0.a0' + keyutils: '>=1.6.3,<2.0a0' + libedit: '>=3.1.20250104,<4.0a0' + libgcc: '>=14' + libstdcxx: '>=14' + openssl: '>=3.5.5,<4.0a0' + url: https://repo.prefix.dev/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda hash: - md5: 3f43953b7d3fb3aaa1d0d0723d91e368 - sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 + md5: fb53fb07ce46a575c5d004bbc96032c2 + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 category: main optional: false - name: krb5 - version: 1.21.3 + version: 1.22.2 manager: conda platform: win-64 dependencies: - openssl: '>=3.3.1,<4.0a0' + openssl: '>=3.5.5,<4.0a0' ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda hash: - md5: 31aec030344e962fbd7dbbbbd68e60a9 - sha256: 18e8b3430d7d232dad132f574268f56b3eb1a19431d6d5de8c53c29e6c18fa81 + md5: 4432f52dc0c8eb6a7a6abc00a037d93c + sha256: eb60f1ad8b597bcf95dee11bc11fe71a8325bc1204cf51d2bb1f2120ffd77761 category: main optional: false - name: lark @@ -3229,17 +3254,17 @@ package: platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libgcc: '>=14' libnghttp2: '>=1.67.0,<2.0a0' libssh2: '>=1.11.1,<2.0a0' libzlib: '>=1.3.1,<2.0a0' - openssl: '>=3.5.4,<4.0a0' + openssl: '>=3.5.5,<4.0a0' zstd: '>=1.5.7,<1.6.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libcurl-8.18.0-h4e3cde8_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libcurl-8.18.0-hcf29cc6_1.conda hash: - md5: 0a5563efed19ca4461cf927419b6eb73 - sha256: 5454709d9fb6e9c3dd6423bc284fa7835a7823bfa8323f6e8786cdd555101fab + md5: 1707cdd636af2ff697b53186572c9f77 + sha256: c84e8dccb65ad5149c0121e4b54bdc47fa39303fd5f4979b8c44bb51b39a369b category: main optional: false - name: libcurl @@ -3247,16 +3272,16 @@ package: manager: conda platform: win-64 dependencies: - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libssh2: '>=1.11.1,<2.0a0' libzlib: '>=1.3.1,<2.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libcurl-8.18.0-h43ecb02_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/libcurl-8.18.0-h8206538_1.conda hash: - md5: 2688214a9bee5d5650cd4f5f6af5c8f2 - sha256: 86258e30845571ea13855e8a0605275905781476f3edf8ae5df90a06fcada93a + md5: b7243e3227df9a1852a05762d0efe08d + sha256: f7dfa98e615a0ddc8de80b32eb6700ea4ebf7b872a6de22a7eadc30a52edd4bf category: main optional: false - name: libdeflate @@ -3739,29 +3764,30 @@ package: category: main optional: false - name: libsodium - version: 1.0.20 + version: 1.0.21 manager: conda platform: linux-64 dependencies: - libgcc-ng: '>=12' - url: https://repo.prefix.dev/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda + __glibc: '>=2.17,<3.0.a0' + libgcc: '>=14' + url: https://repo.prefix.dev/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda hash: - md5: a587892d3c13b6621a6091be690dbca2 - sha256: 0105bd108f19ea8e6a78d2d994a6d4a8db16d19a41212070d2d1d48a63c34161 + md5: 7af961ef4aa2c1136e11dd43ded245ab + sha256: 64e5c80cbce4680a2d25179949739a6def695d72c40ca28f010711764e372d97 category: dev optional: true - name: libsodium - version: 1.0.20 + version: 1.0.21 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/libsodium-1.0.20-hc70643c_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/libsodium-1.0.21-h6a83c73_3.conda hash: - md5: 198bb594f202b205c7d18b936fa4524f - sha256: 7bcb3edccea30f711b6be9601e083ecf4f435b9407d70fc48fbcf9e5d69a0fc6 + md5: da2aa614d16a795b3007b6f4a1318a81 + sha256: d915f4fa8ebbf237c7a6e511ed458f2cfdc7c76843a924740318a15d0dd33d6d category: dev optional: true - name: libspatialindex @@ -4127,29 +4153,29 @@ package: category: main optional: false - name: llvm-openmp - version: 21.1.8 + version: 22.1.0 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - url: https://repo.prefix.dev/conda-forge/linux-64/llvm-openmp-21.1.8-h4922eb0_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/llvm-openmp-22.1.0-h4922eb0_0.conda hash: - md5: f8640b709b37dc7758ddce45ea18d000 - sha256: a5a7ad16eecbe35cac63e529ea9c261bef4ccdd68cb1db247409f04529423989 + md5: 5e7da5333653c631d27732893b934351 + sha256: 543c9f17cf6ee6d7b635823fb9009df421d510c36739534df6ae43eadaf6ff4e category: main optional: false - name: llvm-openmp - version: 21.1.8 + version: 22.1.0 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/llvm-openmp-21.1.8-h4fa8253_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/llvm-openmp-22.1.0-h4fa8253_0.conda hash: - md5: 0d8b425ac862bcf17e4b28802c9351cb - sha256: 145c4370abe870f10987efa9fc15a8383f1dab09abbc9ad4ff15a55d45658f7b + md5: e5505e0b7d6ef5c19d5c0c1884a2f494 + sha256: bb55a3736380759d338f87aac68df4fd7d845ae090b94400525f5d21a55eea31 category: main optional: false - name: locket @@ -4211,10 +4237,10 @@ package: libgcc: '>=14' python: '>=3.12,<3.13.0a0' python_abi: 3.12.* - url: https://repo.prefix.dev/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda hash: - md5: f775a43412f7f3d7ed218113ad233869 - sha256: f77f9f1a4da45cbc8792d16b41b6f169f649651a68afdc10b2da9da12b9aa42b + md5: 93a4752d42b12943a355b682ee43285b + sha256: 5f3aad1f3a685ed0b591faad335957dbdb1b73abfd6fc731a0d42718e0653b33 category: main optional: false - name: markupsafe @@ -4227,10 +4253,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/markupsafe-3.0.3-py312h05f76fc_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/markupsafe-3.0.3-py312h05f76fc_1.conda hash: - md5: 9a50d5e7b4f2bf5db9790bbe9421cdf8 - sha256: db1d772015ef052fedb3b4e7155b13446b49431a0f8c54c56ca6f82e1d4e258f + md5: a73298d225c7852f97403ca105d10a13 + sha256: b744287a780211ac4595126ef96a44309c791f155d4724021ef99092bae4aace category: main optional: false - name: matplotlib-base @@ -4797,14 +4823,14 @@ package: category: dev optional: true - name: nodejs - version: 25.6.1 + version: 25.7.0 manager: conda platform: win-64 dependencies: {} - url: https://repo.prefix.dev/conda-forge/win-64/nodejs-25.6.1-he453025_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/nodejs-25.7.0-h80d1838_0.conda hash: - md5: e85442c19d22f7aeca43742b114e9382 - sha256: 9ed24d268da60b669d451d8f2c64edbf0da1a446604e64fcf68eb64b1aff3830 + md5: 61b62d3be12c9edbe34f202d51891927 + sha256: 0ea0ddad32366396d1beda7ce93ddd3d9f705286c1a4f99f05ec0049183c1e97 category: dev optional: true - name: notebook @@ -4981,6 +5007,38 @@ package: sha256: 226c270a7e3644448954c47959c00a9bf7845f6d600c2a643db187118d028eee category: main optional: false +- name: openpyxl + version: 3.1.5 + manager: conda + platform: linux-64 + dependencies: + et_xmlfile: '' + libgcc: '>=14' + python: '>=3.12,<3.13.0a0' + python_abi: 3.12.* + url: https://repo.prefix.dev/conda-forge/linux-64/openpyxl-3.1.5-py312h7f6eeab_3.conda + hash: + md5: 04ab345ef65b88bcbb8ac3d083427bfc + sha256: 04839d313708a6b8c185bc9fcc56ccef985ed91520420c665b5e67b55fd8b5fb + category: main + optional: false +- name: openpyxl + version: 3.1.5 + manager: conda + platform: win-64 + dependencies: + et_xmlfile: '' + python: '>=3.12,<3.13.0a0' + python_abi: 3.12.* + ucrt: '>=10.0.20348.0' + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/openpyxl-3.1.5-py312h83acffa_3.conda + hash: + md5: ff342a314798173eaaf2753a22f044fa + sha256: 824eeb546a08c990eb461706280d3064c0437f67eb320018986fa439f468e43a + category: main + optional: false - name: openssl version: 3.6.1 manager: conda @@ -7890,14 +7948,14 @@ package: platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libgcc: '>=14' - libsodium: '>=1.0.20,<1.0.21.0a0' + libsodium: '>=1.0.21,<1.0.22.0a0' libstdcxx: '>=14' - url: https://repo.prefix.dev/conda-forge/linux-64/zeromq-4.3.5-h387f397_9.conda + url: https://repo.prefix.dev/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda hash: - md5: 8035e5b54c08429354d5d64027041cad - sha256: 47cfe31255b91b4a6fa0e9dbaf26baa60ac97e033402dbc8b90ba5fee5ffe184 + md5: 755b096086851e1193f3b10347415d7c + sha256: 325d370b28e2b9cc1f765c5b4cdb394c91a5d958fbd15da1a14607a28fee09f6 category: dev optional: true - name: zeromq @@ -7905,15 +7963,15 @@ package: manager: conda platform: win-64 dependencies: - krb5: '>=1.21.3,<1.22.0a0' - libsodium: '>=1.0.20,<1.0.21.0a0' + krb5: '>=1.22.2,<1.23.0a0' + libsodium: '>=1.0.21,<1.0.22.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/zeromq-4.3.5-h5bddc39_9.conda + url: https://repo.prefix.dev/conda-forge/win-64/zeromq-4.3.5-h507cc87_10.conda hash: - md5: a6c8f8ee856f7c3c1576e14b86cd8038 - sha256: 690cf749692c8ea556646d1a47b5824ad41b2f6dfd949e4cdb6c44a352fcb1aa + md5: 1ab0237036bfb14e923d6107473b0021 + sha256: b8568dfde46edf3455458912ea6ffb760e4456db8230a0cf34ecbc557d3c275f category: dev optional: true - name: zict diff --git a/py-3.13.conda-lock.yml b/py-3.13.conda-lock.yml index ba9262219..493737889 100644 --- a/py-3.13.conda-lock.yml +++ b/py-3.13.conda-lock.yml @@ -15,8 +15,8 @@ version: 1 metadata: content_hash: - win-64: 88e9d148e8962a73f08ec4acb1a027dd3c20c9518803da0467f730d3e661d9f6 - linux-64: 89bd18bfbcb4a4631e8ed110c1c0381f6a3362cfb8cb8a1006787cad6341cffd + win-64: 634cec3ecb56deda7d45fbb3187fdfd23a39124f4735afaafd63281ac1d4e160 + linux-64: 9c084fb4e43ef817a9ccbd7d830c295486fa3a57249edd4c6a77fb42bd4c7ff0 channels: - url: conda-forge used_env_vars: [] @@ -691,27 +691,27 @@ package: category: main optional: false - name: ca-certificates - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: linux-64 dependencies: __unix: '' - url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda hash: - md5: bddacf101bb4dd0e51811cb69c7790e2 - sha256: b5974ec9b50e3c514a382335efa81ed02b05906849827a34061c496f4defa0b2 + md5: 4492fd26db29495f0ba23f146cd5638d + sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc category: main optional: false - name: ca-certificates - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: win-64 dependencies: __win: '' - url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.1.4-h4c7d964_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda hash: - md5: 84d389c9eee640dda3d26fc5335c67d8 - sha256: 4ddcb01be03f85d3db9d881407fb13a673372f1b9fac9c836ea441893390e049 + md5: f001e6e220355b7f87403a4d0e5bf1ca + sha256: 37950019c59b99585cee5d30dbc2cc9696ed4e11f5742606a4db1621ed8f94d6 category: main optional: false - name: cached-property @@ -763,27 +763,27 @@ package: category: main optional: false - name: certifi - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.1.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda hash: - md5: eacc711330cd46939f66cd401ff9c44b - sha256: 110338066d194a715947808611b763857c15458f8b3b97197387356844af9450 + md5: 765c4d97e877cdbbb88ff33152b86125 + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 category: dev optional: true - name: certifi - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.1.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda hash: - md5: eacc711330cd46939f66cd401ff9c44b - sha256: 110338066d194a715947808611b763857c15458f8b3b97197387356844af9450 + md5: 765c4d97e877cdbbb88ff33152b86125 + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 category: dev optional: true - name: cffi @@ -1381,6 +1381,30 @@ package: sha256: d1d7886cd56fa84eeec860ca5761ba7d1167f0ce0e9f9093810c0f35bdeaf994 category: dev optional: true +- name: et_xmlfile + version: 2.0.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.9' + url: https://repo.prefix.dev/conda-forge/noarch/et_xmlfile-2.0.0-pyhd8ed1ab_1.conda + hash: + md5: 71bf9646cbfabf3022c8da4b6b4da737 + sha256: 2209534fbf2f70c20661ff31f57ab6a97b82ee98812e8a2dcb2b36a0d345727c + category: main + optional: false +- name: et_xmlfile + version: 2.0.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.9' + url: https://repo.prefix.dev/conda-forge/noarch/et_xmlfile-2.0.0-pyhd8ed1ab_1.conda + hash: + md5: 71bf9646cbfabf3022c8da4b6b4da737 + sha256: 2209534fbf2f70c20661ff31f57ab6a97b82ee98812e8a2dcb2b36a0d345727c + category: main + optional: false - name: exceptiongroup version: 1.3.1 manager: conda @@ -2208,29 +2232,29 @@ package: category: dev optional: true - name: isort - version: 8.0.0 + version: 8.0.1 manager: conda platform: linux-64 dependencies: importlib-metadata: '>=4.6.0' python: '>=3.10,<4.0' - url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.1-pyhd8ed1ab_0.conda hash: - md5: 83297265e95a934c256d04177ad09293 - sha256: 7b2620c8aee9cf8c11dd70f2729cd29078a4f0e9f04acb3e24ce8ab41ecd3c27 + md5: 98cdd8615792e90da1023bc546f806d9 + sha256: cc5c2b513143ea9675ba5b3570182f7568fd1029b299ee3bc58424dcce8c5539 category: dev optional: true - name: isort - version: 8.0.0 + version: 8.0.1 manager: conda platform: win-64 dependencies: importlib-metadata: '>=4.6.0' python: '>=3.10,<4.0' - url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.1-pyhd8ed1ab_0.conda hash: - md5: 83297265e95a934c256d04177ad09293 - sha256: 7b2620c8aee9cf8c11dd70f2729cd29078a4f0e9f04acb3e24ce8ab41ecd3c27 + md5: 98cdd8615792e90da1023bc546f806d9 + sha256: cc5c2b513143ea9675ba5b3570182f7568fd1029b299ee3bc58424dcce8c5539 category: dev optional: true - name: jedi @@ -2934,34 +2958,35 @@ package: category: main optional: false - name: krb5 - version: 1.21.3 + version: 1.22.2 manager: conda platform: linux-64 dependencies: - keyutils: '>=1.6.1,<2.0a0' - libedit: '>=3.1.20191231,<4.0a0' - libgcc-ng: '>=12' - libstdcxx-ng: '>=12' - openssl: '>=3.3.1,<4.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + __glibc: '>=2.17,<3.0.a0' + keyutils: '>=1.6.3,<2.0a0' + libedit: '>=3.1.20250104,<4.0a0' + libgcc: '>=14' + libstdcxx: '>=14' + openssl: '>=3.5.5,<4.0a0' + url: https://repo.prefix.dev/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda hash: - md5: 3f43953b7d3fb3aaa1d0d0723d91e368 - sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 + md5: fb53fb07ce46a575c5d004bbc96032c2 + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 category: main optional: false - name: krb5 - version: 1.21.3 + version: 1.22.2 manager: conda platform: win-64 dependencies: - openssl: '>=3.3.1,<4.0a0' + openssl: '>=3.5.5,<4.0a0' ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda hash: - md5: 31aec030344e962fbd7dbbbbd68e60a9 - sha256: 18e8b3430d7d232dad132f574268f56b3eb1a19431d6d5de8c53c29e6c18fa81 + md5: 4432f52dc0c8eb6a7a6abc00a037d93c + sha256: eb60f1ad8b597bcf95dee11bc11fe71a8325bc1204cf51d2bb1f2120ffd77761 category: main optional: false - name: lark @@ -3227,17 +3252,17 @@ package: platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libgcc: '>=14' libnghttp2: '>=1.67.0,<2.0a0' libssh2: '>=1.11.1,<2.0a0' libzlib: '>=1.3.1,<2.0a0' - openssl: '>=3.5.4,<4.0a0' + openssl: '>=3.5.5,<4.0a0' zstd: '>=1.5.7,<1.6.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libcurl-8.18.0-h4e3cde8_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libcurl-8.18.0-hcf29cc6_1.conda hash: - md5: 0a5563efed19ca4461cf927419b6eb73 - sha256: 5454709d9fb6e9c3dd6423bc284fa7835a7823bfa8323f6e8786cdd555101fab + md5: 1707cdd636af2ff697b53186572c9f77 + sha256: c84e8dccb65ad5149c0121e4b54bdc47fa39303fd5f4979b8c44bb51b39a369b category: main optional: false - name: libcurl @@ -3245,16 +3270,16 @@ package: manager: conda platform: win-64 dependencies: - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libssh2: '>=1.11.1,<2.0a0' libzlib: '>=1.3.1,<2.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libcurl-8.18.0-h43ecb02_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/libcurl-8.18.0-h8206538_1.conda hash: - md5: 2688214a9bee5d5650cd4f5f6af5c8f2 - sha256: 86258e30845571ea13855e8a0605275905781476f3edf8ae5df90a06fcada93a + md5: b7243e3227df9a1852a05762d0efe08d + sha256: f7dfa98e615a0ddc8de80b32eb6700ea4ebf7b872a6de22a7eadc30a52edd4bf category: main optional: false - name: libdeflate @@ -3751,29 +3776,30 @@ package: category: main optional: false - name: libsodium - version: 1.0.20 + version: 1.0.21 manager: conda platform: linux-64 dependencies: - libgcc-ng: '>=12' - url: https://repo.prefix.dev/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda + __glibc: '>=2.17,<3.0.a0' + libgcc: '>=14' + url: https://repo.prefix.dev/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda hash: - md5: a587892d3c13b6621a6091be690dbca2 - sha256: 0105bd108f19ea8e6a78d2d994a6d4a8db16d19a41212070d2d1d48a63c34161 + md5: 7af961ef4aa2c1136e11dd43ded245ab + sha256: 64e5c80cbce4680a2d25179949739a6def695d72c40ca28f010711764e372d97 category: dev optional: true - name: libsodium - version: 1.0.20 + version: 1.0.21 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/libsodium-1.0.20-hc70643c_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/libsodium-1.0.21-h6a83c73_3.conda hash: - md5: 198bb594f202b205c7d18b936fa4524f - sha256: 7bcb3edccea30f711b6be9601e083ecf4f435b9407d70fc48fbcf9e5d69a0fc6 + md5: da2aa614d16a795b3007b6f4a1318a81 + sha256: d915f4fa8ebbf237c7a6e511ed458f2cfdc7c76843a924740318a15d0dd33d6d category: dev optional: true - name: libspatialindex @@ -4127,29 +4153,29 @@ package: category: main optional: false - name: llvm-openmp - version: 21.1.8 + version: 22.1.0 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - url: https://repo.prefix.dev/conda-forge/linux-64/llvm-openmp-21.1.8-h4922eb0_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/llvm-openmp-22.1.0-h4922eb0_0.conda hash: - md5: f8640b709b37dc7758ddce45ea18d000 - sha256: a5a7ad16eecbe35cac63e529ea9c261bef4ccdd68cb1db247409f04529423989 + md5: 5e7da5333653c631d27732893b934351 + sha256: 543c9f17cf6ee6d7b635823fb9009df421d510c36739534df6ae43eadaf6ff4e category: main optional: false - name: llvm-openmp - version: 21.1.8 + version: 22.1.0 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/llvm-openmp-21.1.8-h4fa8253_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/llvm-openmp-22.1.0-h4fa8253_0.conda hash: - md5: 0d8b425ac862bcf17e4b28802c9351cb - sha256: 145c4370abe870f10987efa9fc15a8383f1dab09abbc9ad4ff15a55d45658f7b + md5: e5505e0b7d6ef5c19d5c0c1884a2f494 + sha256: bb55a3736380759d338f87aac68df4fd7d845ae090b94400525f5d21a55eea31 category: main optional: false - name: locket @@ -4211,10 +4237,10 @@ package: libgcc: '>=14' python: '>=3.13,<3.14.0a0' python_abi: 3.13.* - url: https://repo.prefix.dev/conda-forge/linux-64/markupsafe-3.0.3-py313h3dea7bd_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/markupsafe-3.0.3-py313h3dea7bd_1.conda hash: - md5: c14389156310b8ed3520d84f854be1ee - sha256: a530a411bdaaf0b1e4de8869dfaca46cb07407bc7dc0702a9e231b0e5ce7ca85 + md5: aeb9b9da79fd0258b3db091d1fefcd71 + sha256: 72ed7c0216541d65a17b171bf2eec4a3b81e9158d8ed48e59e1ecd3ae302d263 category: main optional: false - name: markupsafe @@ -4227,10 +4253,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/markupsafe-3.0.3-py313hd650c13_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/markupsafe-3.0.3-py313hd650c13_1.conda hash: - md5: 47eaaa4405741beb171ea6edc6eaf874 - sha256: 988d14095c1392e055fd75e24544da2db01ade73b0c2f99ddc8e2b8678ead4cc + md5: 5cc690ddf943700e0ef50a265df31f03 + sha256: 9dc626b6c00bc2dbd2494df689876ff675b93d92636ba5df8e37b99040a1f6bc category: main optional: false - name: matplotlib-base @@ -4797,14 +4823,14 @@ package: category: dev optional: true - name: nodejs - version: 25.6.1 + version: 25.7.0 manager: conda platform: win-64 dependencies: {} - url: https://repo.prefix.dev/conda-forge/win-64/nodejs-25.6.1-he453025_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/nodejs-25.7.0-h80d1838_0.conda hash: - md5: e85442c19d22f7aeca43742b114e9382 - sha256: 9ed24d268da60b669d451d8f2c64edbf0da1a446604e64fcf68eb64b1aff3830 + md5: 61b62d3be12c9edbe34f202d51891927 + sha256: 0ea0ddad32366396d1beda7ce93ddd3d9f705286c1a4f99f05ec0049183c1e97 category: dev optional: true - name: notebook @@ -4981,6 +5007,38 @@ package: sha256: 226c270a7e3644448954c47959c00a9bf7845f6d600c2a643db187118d028eee category: main optional: false +- name: openpyxl + version: 3.1.5 + manager: conda + platform: linux-64 + dependencies: + et_xmlfile: '' + libgcc: '>=14' + python: '>=3.13,<3.14.0a0' + python_abi: 3.13.* + url: https://repo.prefix.dev/conda-forge/linux-64/openpyxl-3.1.5-py313ha4be090_3.conda + hash: + md5: 993d27015ca7aa1de3f4a471a9b5309e + sha256: ee3e071cbc0be5600747631b41da17349be6fd25c982c9a9644cda3953bbf8b5 + category: main + optional: false +- name: openpyxl + version: 3.1.5 + manager: conda + platform: win-64 + dependencies: + et_xmlfile: '' + python: '>=3.13,<3.14.0a0' + python_abi: 3.13.* + ucrt: '>=10.0.20348.0' + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/openpyxl-3.1.5-py313hc624790_3.conda + hash: + md5: 57d8fccec9481a008b363bfbbef86d1f + sha256: e5e86bc7ac493fcee526434a79f51c6a24e7c71cf4e50044d0c410079bf44af8 + category: main + optional: false - name: openssl version: 3.6.1 manager: conda @@ -7831,14 +7889,14 @@ package: platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libgcc: '>=14' - libsodium: '>=1.0.20,<1.0.21.0a0' + libsodium: '>=1.0.21,<1.0.22.0a0' libstdcxx: '>=14' - url: https://repo.prefix.dev/conda-forge/linux-64/zeromq-4.3.5-h387f397_9.conda + url: https://repo.prefix.dev/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda hash: - md5: 8035e5b54c08429354d5d64027041cad - sha256: 47cfe31255b91b4a6fa0e9dbaf26baa60ac97e033402dbc8b90ba5fee5ffe184 + md5: 755b096086851e1193f3b10347415d7c + sha256: 325d370b28e2b9cc1f765c5b4cdb394c91a5d958fbd15da1a14607a28fee09f6 category: dev optional: true - name: zeromq @@ -7846,15 +7904,15 @@ package: manager: conda platform: win-64 dependencies: - krb5: '>=1.21.3,<1.22.0a0' - libsodium: '>=1.0.20,<1.0.21.0a0' + krb5: '>=1.22.2,<1.23.0a0' + libsodium: '>=1.0.21,<1.0.22.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/zeromq-4.3.5-h5bddc39_9.conda + url: https://repo.prefix.dev/conda-forge/win-64/zeromq-4.3.5-h507cc87_10.conda hash: - md5: a6c8f8ee856f7c3c1576e14b86cd8038 - sha256: 690cf749692c8ea556646d1a47b5824ad41b2f6dfd949e4cdb6c44a352fcb1aa + md5: 1ab0237036bfb14e923d6107473b0021 + sha256: b8568dfde46edf3455458912ea6ffb760e4456db8230a0cf34ecbc557d3c275f category: dev optional: true - name: zict diff --git a/py-3.14.conda-lock.yml b/py-3.14.conda-lock.yml index ebba89efd..8263d9e4a 100644 --- a/py-3.14.conda-lock.yml +++ b/py-3.14.conda-lock.yml @@ -15,8 +15,8 @@ version: 1 metadata: content_hash: - win-64: 7515184deff7a63cb5b766f656c71ba39e7ef96fc2642f588c3cd6ca6e9ab206 - linux-64: fec79b278904505e81d33ac893dfed5eeb76485fd55928cd6ec8b42277cf64fe + win-64: b56575358cf9c86097af766e84815a217fa1f2932b34252343b018b28a5ce092 + linux-64: 6b8cd4100493c90834719717e9dba0c8025d7cf52a516970a8ba54b345ad21d1 channels: - url: conda-forge used_env_vars: [] @@ -682,27 +682,27 @@ package: category: main optional: false - name: ca-certificates - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: linux-64 dependencies: __unix: '' - url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda hash: - md5: bddacf101bb4dd0e51811cb69c7790e2 - sha256: b5974ec9b50e3c514a382335efa81ed02b05906849827a34061c496f4defa0b2 + md5: 4492fd26db29495f0ba23f146cd5638d + sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc category: main optional: false - name: ca-certificates - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: win-64 dependencies: __win: '' - url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.1.4-h4c7d964_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda hash: - md5: 84d389c9eee640dda3d26fc5335c67d8 - sha256: 4ddcb01be03f85d3db9d881407fb13a673372f1b9fac9c836ea441893390e049 + md5: f001e6e220355b7f87403a4d0e5bf1ca + sha256: 37950019c59b99585cee5d30dbc2cc9696ed4e11f5742606a4db1621ed8f94d6 category: main optional: false - name: cached-property @@ -754,27 +754,27 @@ package: category: main optional: false - name: certifi - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.1.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda hash: - md5: eacc711330cd46939f66cd401ff9c44b - sha256: 110338066d194a715947808611b763857c15458f8b3b97197387356844af9450 + md5: 765c4d97e877cdbbb88ff33152b86125 + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 category: dev optional: true - name: certifi - version: 2026.1.4 + version: 2026.2.25 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.1.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda hash: - md5: eacc711330cd46939f66cd401ff9c44b - sha256: 110338066d194a715947808611b763857c15458f8b3b97197387356844af9450 + md5: 765c4d97e877cdbbb88ff33152b86125 + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 category: dev optional: true - name: cffi @@ -1372,6 +1372,30 @@ package: sha256: ca1d41146115afd54590dad17af0a8c41359c454797d44e290fb3e5bff51034e category: dev optional: true +- name: et_xmlfile + version: 2.0.0 + manager: conda + platform: linux-64 + dependencies: + python: '>=3.9' + url: https://repo.prefix.dev/conda-forge/noarch/et_xmlfile-2.0.0-pyhd8ed1ab_1.conda + hash: + md5: 71bf9646cbfabf3022c8da4b6b4da737 + sha256: 2209534fbf2f70c20661ff31f57ab6a97b82ee98812e8a2dcb2b36a0d345727c + category: main + optional: false +- name: et_xmlfile + version: 2.0.0 + manager: conda + platform: win-64 + dependencies: + python: '>=3.9' + url: https://repo.prefix.dev/conda-forge/noarch/et_xmlfile-2.0.0-pyhd8ed1ab_1.conda + hash: + md5: 71bf9646cbfabf3022c8da4b6b4da737 + sha256: 2209534fbf2f70c20661ff31f57ab6a97b82ee98812e8a2dcb2b36a0d345727c + category: main + optional: false - name: exceptiongroup version: 1.3.1 manager: conda @@ -2194,29 +2218,29 @@ package: category: dev optional: true - name: isort - version: 8.0.0 + version: 8.0.1 manager: conda platform: linux-64 dependencies: importlib-metadata: '>=4.6.0' python: '>=3.10,<4.0' - url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.1-pyhd8ed1ab_0.conda hash: - md5: 83297265e95a934c256d04177ad09293 - sha256: 7b2620c8aee9cf8c11dd70f2729cd29078a4f0e9f04acb3e24ce8ab41ecd3c27 + md5: 98cdd8615792e90da1023bc546f806d9 + sha256: cc5c2b513143ea9675ba5b3570182f7568fd1029b299ee3bc58424dcce8c5539 category: dev optional: true - name: isort - version: 8.0.0 + version: 8.0.1 manager: conda platform: win-64 dependencies: importlib-metadata: '>=4.6.0' python: '>=3.10,<4.0' - url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/isort-8.0.1-pyhd8ed1ab_0.conda hash: - md5: 83297265e95a934c256d04177ad09293 - sha256: 7b2620c8aee9cf8c11dd70f2729cd29078a4f0e9f04acb3e24ce8ab41ecd3c27 + md5: 98cdd8615792e90da1023bc546f806d9 + sha256: cc5c2b513143ea9675ba5b3570182f7568fd1029b299ee3bc58424dcce8c5539 category: dev optional: true - name: jedi @@ -2920,34 +2944,35 @@ package: category: main optional: false - name: krb5 - version: 1.21.3 + version: 1.22.2 manager: conda platform: linux-64 dependencies: - keyutils: '>=1.6.1,<2.0a0' - libedit: '>=3.1.20191231,<4.0a0' - libgcc-ng: '>=12' - libstdcxx-ng: '>=12' - openssl: '>=3.3.1,<4.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + __glibc: '>=2.17,<3.0.a0' + keyutils: '>=1.6.3,<2.0a0' + libedit: '>=3.1.20250104,<4.0a0' + libgcc: '>=14' + libstdcxx: '>=14' + openssl: '>=3.5.5,<4.0a0' + url: https://repo.prefix.dev/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda hash: - md5: 3f43953b7d3fb3aaa1d0d0723d91e368 - sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 + md5: fb53fb07ce46a575c5d004bbc96032c2 + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 category: main optional: false - name: krb5 - version: 1.21.3 + version: 1.22.2 manager: conda platform: win-64 dependencies: - openssl: '>=3.3.1,<4.0a0' + openssl: '>=3.5.5,<4.0a0' ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda hash: - md5: 31aec030344e962fbd7dbbbbd68e60a9 - sha256: 18e8b3430d7d232dad132f574268f56b3eb1a19431d6d5de8c53c29e6c18fa81 + md5: 4432f52dc0c8eb6a7a6abc00a037d93c + sha256: eb60f1ad8b597bcf95dee11bc11fe71a8325bc1204cf51d2bb1f2120ffd77761 category: main optional: false - name: lark @@ -3213,17 +3238,17 @@ package: platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libgcc: '>=14' libnghttp2: '>=1.67.0,<2.0a0' libssh2: '>=1.11.1,<2.0a0' libzlib: '>=1.3.1,<2.0a0' - openssl: '>=3.5.4,<4.0a0' + openssl: '>=3.5.5,<4.0a0' zstd: '>=1.5.7,<1.6.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libcurl-8.18.0-h4e3cde8_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libcurl-8.18.0-hcf29cc6_1.conda hash: - md5: 0a5563efed19ca4461cf927419b6eb73 - sha256: 5454709d9fb6e9c3dd6423bc284fa7835a7823bfa8323f6e8786cdd555101fab + md5: 1707cdd636af2ff697b53186572c9f77 + sha256: c84e8dccb65ad5149c0121e4b54bdc47fa39303fd5f4979b8c44bb51b39a369b category: main optional: false - name: libcurl @@ -3231,16 +3256,16 @@ package: manager: conda platform: win-64 dependencies: - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libssh2: '>=1.11.1,<2.0a0' libzlib: '>=1.3.1,<2.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libcurl-8.18.0-h43ecb02_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/libcurl-8.18.0-h8206538_1.conda hash: - md5: 2688214a9bee5d5650cd4f5f6af5c8f2 - sha256: 86258e30845571ea13855e8a0605275905781476f3edf8ae5df90a06fcada93a + md5: b7243e3227df9a1852a05762d0efe08d + sha256: f7dfa98e615a0ddc8de80b32eb6700ea4ebf7b872a6de22a7eadc30a52edd4bf category: main optional: false - name: libdeflate @@ -3737,29 +3762,30 @@ package: category: main optional: false - name: libsodium - version: 1.0.20 + version: 1.0.21 manager: conda platform: linux-64 dependencies: - libgcc-ng: '>=12' - url: https://repo.prefix.dev/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda + __glibc: '>=2.17,<3.0.a0' + libgcc: '>=14' + url: https://repo.prefix.dev/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda hash: - md5: a587892d3c13b6621a6091be690dbca2 - sha256: 0105bd108f19ea8e6a78d2d994a6d4a8db16d19a41212070d2d1d48a63c34161 + md5: 7af961ef4aa2c1136e11dd43ded245ab + sha256: 64e5c80cbce4680a2d25179949739a6def695d72c40ca28f010711764e372d97 category: dev optional: true - name: libsodium - version: 1.0.20 + version: 1.0.21 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/libsodium-1.0.20-hc70643c_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/libsodium-1.0.21-h6a83c73_3.conda hash: - md5: 198bb594f202b205c7d18b936fa4524f - sha256: 7bcb3edccea30f711b6be9601e083ecf4f435b9407d70fc48fbcf9e5d69a0fc6 + md5: da2aa614d16a795b3007b6f4a1318a81 + sha256: d915f4fa8ebbf237c7a6e511ed458f2cfdc7c76843a924740318a15d0dd33d6d category: dev optional: true - name: libspatialindex @@ -4113,29 +4139,29 @@ package: category: main optional: false - name: llvm-openmp - version: 21.1.8 + version: 22.1.0 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - url: https://repo.prefix.dev/conda-forge/linux-64/llvm-openmp-21.1.8-h4922eb0_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/llvm-openmp-22.1.0-h4922eb0_0.conda hash: - md5: f8640b709b37dc7758ddce45ea18d000 - sha256: a5a7ad16eecbe35cac63e529ea9c261bef4ccdd68cb1db247409f04529423989 + md5: 5e7da5333653c631d27732893b934351 + sha256: 543c9f17cf6ee6d7b635823fb9009df421d510c36739534df6ae43eadaf6ff4e category: main optional: false - name: llvm-openmp - version: 21.1.8 + version: 22.1.0 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/llvm-openmp-21.1.8-h4fa8253_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/llvm-openmp-22.1.0-h4fa8253_0.conda hash: - md5: 0d8b425ac862bcf17e4b28802c9351cb - sha256: 145c4370abe870f10987efa9fc15a8383f1dab09abbc9ad4ff15a55d45658f7b + md5: e5505e0b7d6ef5c19d5c0c1884a2f494 + sha256: bb55a3736380759d338f87aac68df4fd7d845ae090b94400525f5d21a55eea31 category: main optional: false - name: locket @@ -4193,11 +4219,14 @@ package: manager: conda platform: linux-64 dependencies: - python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda + __glibc: '>=2.17,<3.0.a0' + libgcc: '>=14' + python: '>=3.14,<3.15.0a0' + python_abi: 3.14.* + url: https://repo.prefix.dev/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda hash: - md5: fab1be106a50e20f10fe5228fd1d1651 - sha256: e0cbfea51a19b3055ca19428bd9233a25adca956c208abb9d00b21e7259c7e03 + md5: 9a17c4307d23318476d7fbf0fedc0cde + sha256: c279be85b59a62d5c52f5dd9a4cd43ebd08933809a8416c22c3131595607d4cf category: main optional: false - name: markupsafe @@ -4205,11 +4234,15 @@ package: manager: conda platform: win-64 dependencies: - python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda + python: '>=3.14,<3.15.0a0' + python_abi: 3.14.* + ucrt: '>=10.0.20348.0' + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/markupsafe-3.0.3-py314h2359020_1.conda hash: - md5: fab1be106a50e20f10fe5228fd1d1651 - sha256: e0cbfea51a19b3055ca19428bd9233a25adca956c208abb9d00b21e7259c7e03 + md5: 8de7b40f8b30a8fcaa423c2537fe4199 + sha256: 02805a0f3cd168dbf13afc5e4aed75cc00fe538ce143527a6471485b36f5887c category: main optional: false - name: matplotlib-base @@ -4776,14 +4809,14 @@ package: category: dev optional: true - name: nodejs - version: 25.6.1 + version: 25.7.0 manager: conda platform: win-64 dependencies: {} - url: https://repo.prefix.dev/conda-forge/win-64/nodejs-25.6.1-he453025_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/nodejs-25.7.0-h80d1838_0.conda hash: - md5: e85442c19d22f7aeca43742b114e9382 - sha256: 9ed24d268da60b669d451d8f2c64edbf0da1a446604e64fcf68eb64b1aff3830 + md5: 61b62d3be12c9edbe34f202d51891927 + sha256: 0ea0ddad32366396d1beda7ce93ddd3d9f705286c1a4f99f05ec0049183c1e97 category: dev optional: true - name: notebook @@ -4960,6 +4993,38 @@ package: sha256: 226c270a7e3644448954c47959c00a9bf7845f6d600c2a643db187118d028eee category: main optional: false +- name: openpyxl + version: 3.1.5 + manager: conda + platform: linux-64 + dependencies: + et_xmlfile: '' + libgcc: '>=14' + python: '>=3.14,<3.15.0a0' + python_abi: 3.14.* + url: https://repo.prefix.dev/conda-forge/linux-64/openpyxl-3.1.5-py314hf3b76af_3.conda + hash: + md5: bc90b1901f01e0772c74e24b6f931137 + sha256: 7a6c2355af80e8d1e9a851347dc4f5e737a21da8ebeb7f6e4b9889eb8a0186a2 + category: main + optional: false +- name: openpyxl + version: 3.1.5 + manager: conda + platform: win-64 + dependencies: + et_xmlfile: '' + python: '>=3.14,<3.15.0a0' + python_abi: 3.14.* + ucrt: '>=10.0.20348.0' + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/openpyxl-3.1.5-py314hccc76fc_3.conda + hash: + md5: 864cdb786a1bb977ed1f96eab705a6d1 + sha256: 82ad3a066acc770f0945c1ffa9b1ad1878ad9b6c3625bab940804909ce94d484 + category: main + optional: false - name: openssl version: 3.6.1 manager: conda @@ -7843,14 +7908,14 @@ package: platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - krb5: '>=1.21.3,<1.22.0a0' + krb5: '>=1.22.2,<1.23.0a0' libgcc: '>=14' - libsodium: '>=1.0.20,<1.0.21.0a0' + libsodium: '>=1.0.21,<1.0.22.0a0' libstdcxx: '>=14' - url: https://repo.prefix.dev/conda-forge/linux-64/zeromq-4.3.5-h387f397_9.conda + url: https://repo.prefix.dev/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda hash: - md5: 8035e5b54c08429354d5d64027041cad - sha256: 47cfe31255b91b4a6fa0e9dbaf26baa60ac97e033402dbc8b90ba5fee5ffe184 + md5: 755b096086851e1193f3b10347415d7c + sha256: 325d370b28e2b9cc1f765c5b4cdb394c91a5d958fbd15da1a14607a28fee09f6 category: dev optional: true - name: zeromq @@ -7858,15 +7923,15 @@ package: manager: conda platform: win-64 dependencies: - krb5: '>=1.21.3,<1.22.0a0' - libsodium: '>=1.0.20,<1.0.21.0a0' + krb5: '>=1.22.2,<1.23.0a0' + libsodium: '>=1.0.21,<1.0.22.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/zeromq-4.3.5-h5bddc39_9.conda + url: https://repo.prefix.dev/conda-forge/win-64/zeromq-4.3.5-h507cc87_10.conda hash: - md5: a6c8f8ee856f7c3c1576e14b86cd8038 - sha256: 690cf749692c8ea556646d1a47b5824ad41b2f6dfd949e4cdb6c44a352fcb1aa + md5: 1ab0237036bfb14e923d6107473b0021 + sha256: b8568dfde46edf3455458912ea6ffb760e4456db8230a0cf34ecbc557d3c275f category: dev optional: true - name: zict diff --git a/pyproject.toml b/pyproject.toml index dfdc55592..68bd28399 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,8 @@ discretize = "~0.12.0" # also in simpeg, grid-apps distributed = "~2025.3.0" # for dask[distributed] matplotlib = "~3.10.0" # from geoapps-utils numpy = "~2.4.2" +openpyxl = ">=3.1.2" +pandas = ">=3.0.*" pydantic = "~2.12.0" # also in geoh5py, curve-apps, geoapps-utils pydiso = "~0.2.0" python-mumps = "~0.0.6.0" diff --git a/simpeg_drivers-assets/uijson/plate_sweep.ui.json b/simpeg_drivers-assets/uijson/plate_sweep.ui.json index 2112815e4..5ad41533d 100644 --- a/simpeg_drivers-assets/uijson/plate_sweep.ui.json +++ b/simpeg_drivers-assets/uijson/plate_sweep.ui.json @@ -31,6 +31,14 @@ "tootip": "Directory to store simulation results, relative to the working geoh5.", "value": "./simulations" }, + "generate_summary": { + "main": true, + "group": "Base", + "label": "Generate summary file (.xlsx)", + "enabled": true, + "tootip": "Create an xlsx file summarizing the parameters of all simulations found in the 'Output directory'.", + "value": true + }, "background_start": { "main": true, "group": "Background", diff --git a/simpeg_drivers/electromagnetics/frequency_domain/options.py b/simpeg_drivers/electromagnetics/frequency_domain/options.py index 22de7e2be..5e0c672f6 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain/options.py +++ b/simpeg_drivers/electromagnetics/frequency_domain/options.py @@ -36,6 +36,13 @@ logger = getLogger(__name__) +CONVERSION = { + "Hertz (Hz)": 1e-0, + "KiloHertz (kHz)": 1e-3, + "MegaHertz (MHz)": 1e-6, + "Gigahertz (GHz)": 1e-9, +} + class BaseFDEMOptions(EMDataMixin): """ @@ -61,12 +68,7 @@ def tx_offsets(self): @property def unit_conversion(self): """Return time unit conversion factor.""" - conversion = { - "Seconds (s)": 1.0, - "Milliseconds (ms)": 1e-3, - "Microseconds (us)": 1e-6, - } - return conversion[self.data_object.unit] + return CONVERSION[self.data_object.unit] @field_validator("inversion_type", mode="before") @classmethod diff --git a/simpeg_drivers/electromagnetics/time_domain/options.py b/simpeg_drivers/electromagnetics/time_domain/options.py index c8989977e..0f3e4fbba 100644 --- a/simpeg_drivers/electromagnetics/time_domain/options.py +++ b/simpeg_drivers/electromagnetics/time_domain/options.py @@ -31,6 +31,13 @@ ) +CONVERSION = { + "Seconds (s)": 1.0, + "Milliseconds (ms)": 1e-3, + "Microseconds (us)": 1e-6, +} + + class BaseTDEMOptions(EMDataMixin): """ Base class for Time Domain Electromagnetic options. @@ -45,12 +52,7 @@ class BaseTDEMOptions(EMDataMixin): @property def unit_conversion(self): """Return time unit conversion factor.""" - conversion = { - "Seconds (s)": 1.0, - "Milliseconds (ms)": 1e-3, - "Microseconds (us)": 1e-6, - } - return conversion[self.data_object.unit] + return CONVERSION[self.data_object.unit] @property def timing_mark(self): diff --git a/simpeg_drivers/options.py b/simpeg_drivers/options.py index 207e685a3..458573acb 100644 --- a/simpeg_drivers/options.py +++ b/simpeg_drivers/options.py @@ -60,7 +60,7 @@ def deprecate_warning(value, info): Deprecated = Annotated[ Any, - Field(default=None), + Field(None), BeforeValidator(deprecate_warning), ] diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 33d3a132d..471224f84 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -34,6 +34,7 @@ from scipy.spatial import cKDTree from simpeg_drivers.driver import BaseDriver +from simpeg_drivers.electromagnetics.time_domain.options import CONVERSION from simpeg_drivers.plate_simulation.match.options import PlateMatchOptions from simpeg_drivers.plate_simulation.options import ModelOptions, PlateSimulationOptions @@ -53,7 +54,11 @@ def __init__( self._drape_heights = self._get_drape_heights() self._template = self.get_template() - self._time_mask, self._time_projection = self.time_mask_and_projection() + self._time_mask, self._time_projection = self.time_mask_and_projection( + np.asarray(self._template.channels) * CONVERSION[self._template.unit], + np.asarray(self.params.survey.channels) + * CONVERSION[self.params.survey.unit], + ) self._spatial_tree = cKDTree(self.params.survey.vertices[:, :2]) @property @@ -79,7 +84,10 @@ def get_template(self) -> AirborneTEMReceivers: return survey - def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: + @staticmethod + def time_mask_and_projection( + simulated_times, query_times + ) -> tuple[np.ndarray, csr_matrix]: """ Create a time mask and interpolation matrix from simulation to observation times. @@ -87,8 +95,6 @@ def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: :return: Time mask and time interpolation matrix. """ - simulated_times = np.asarray(self._template.channels) - query_times = np.asarray(self.params.survey.channels) # Only interpolate for times within the simulated range time_mask = (query_times >= simulated_times.min()) & ( query_times <= simulated_times.max() @@ -249,14 +255,14 @@ def spatial_interpolation( # Get the 8 nearest neighbors in the simulation to each observation point sim_tree = cKDTree(query_polar) - rad, inds = sim_tree.query(local_polar, k=8) + rad, inds = sim_tree.query(local_polar, k=16) inds = np.minimum(query_polar.shape[0] - 1, inds) return inverse_weighted_operator( rad.flatten(), inds.flatten(), (local_polar.shape[0], self._template.vertices.shape[0]), 2.0, - 1e-1, + 1e-0, ) def run(self): @@ -278,9 +284,9 @@ def run(self): indices, spatial_projection = self.spatial_mask_and_projection( query, strike_angle[ii] ) - data, flip = prepare_data(observed[:, indices]) + flip = is_up_dip(observed[:, indices]) # Loop through files and compute scores and find the best match - scores, centers = self.run_scores(spatial_projection, data) + scores, centers = self.run_scores(spatial_projection, observed[:, indices]) ranked = np.argsort(scores) best = ranked[0] logger.info( @@ -380,7 +386,7 @@ def run_scores(self, spatial_projection, data) -> tuple[np.ndarray, np.ndarray]: return scores, centers -def prepare_data(data: np.ndarray) -> tuple[np.ndarray, bool]: +def is_up_dip(data: np.ndarray) -> bool: """ Prepare data for scoring by checking for multiple channels and normalizing. @@ -398,9 +404,9 @@ def prepare_data(data: np.ndarray) -> tuple[np.ndarray, bool]: # Mostly on the left suggests the peaks are migrating up-dip and should be reversed if np.mean(left > right) > 0.5: - return data_array[:, ::-1], True + return True - return data_array, False + return False def get_data_array(property_group: PropertyGroup) -> np.ndarray: @@ -415,7 +421,9 @@ def get_data_array(property_group: PropertyGroup) -> np.ndarray: return np.vstack(table.tolist()).T -def normalized_data(data: np.ndarray, threshold=5) -> np.ndarray: +def normalized_data( + data: np.ndarray, scale: float = 1, threshold: float | None = None +) -> np.ndarray: """ Return data from a property group with symlog, zero median and unit max normalization. @@ -424,10 +432,14 @@ def normalized_data(data: np.ndarray, threshold=5) -> np.ndarray: :return: Normalized data array. """ - thresh = np.percentile(np.abs(data), threshold) - log_data = symlog(data, thresh) - centered_log = log_data - np.median(log_data) - return centered_log / np.abs(centered_log).max() + scales_data = data * scale + + if threshold is None: + threshold = np.percentile(scales_data, 5) + + log_data = symlog(scales_data, threshold) + + return log_data def fetch_survey(workspace: Workspace) -> AirborneTEMReceivers | None: @@ -453,7 +465,7 @@ def batch_files_score( :param files: Simulation file or list of simulation files to process. :param spatial_projection: Spatial interpolation matrix. :param time_projection: Time interpolation matrix. - :param observed: Observed data array. + :param observed: Normalized (symlog) observed data array. :return: List of scores for each simulation file. """ @@ -462,6 +474,9 @@ def batch_files_score( if isinstance(files, Path): files = [files] + max_late_val = np.max(np.abs(observed[-1, :])) + data = normalized_data(observed, threshold=max_late_val) + for sim_file in files: with Workspace(sim_file, mode="r") as ws: survey = fetch_survey(ws) @@ -472,24 +487,24 @@ def batch_files_score( simulated = get_data_array(survey.get_entity("Iteration_0_z")[0]) pred = time_projection @ (spatial_projection @ simulated.T).T - pred = normalized_data(pred) + scale = max_late_val / np.max(np.abs(pred[-1, :])) + pred = normalized_data(pred, scale=scale, threshold=max_late_val) + score = 0.0 indices = [] # Metric: normalized cross-correlation - for obs, pre in zip(observed, pred, strict=True): + for obs, pre in zip(data, pred, strict=True): # Scale pre on obs - vals = pre / np.abs(pre).max() * np.abs(obs).max() - # Full cross-correlation - corr = signal.correlate(obs, vals, mode="same") + corr = signal.correlate(obs, pre, mode="same") # Normalize by energy to get correlation coefficient in [-1, 1] - denom = np.linalg.norm(vals) * np.linalg.norm(obs) + denom = np.linalg.norm(pre) * np.linalg.norm(obs) if denom == 0: corr_norm = np.zeros_like(corr) else: corr_norm = corr / denom - score += np.linalg.norm(obs - vals) + score += np.linalg.norm(obs - pre) indices.append(np.argmax(corr_norm)) scores.append((score, np.median(indices))) diff --git a/simpeg_drivers/plate_simulation/sweep/driver.py b/simpeg_drivers/plate_simulation/sweep/driver.py index a07c3d70f..04e22c778 100644 --- a/simpeg_drivers/plate_simulation/sweep/driver.py +++ b/simpeg_drivers/plate_simulation/sweep/driver.py @@ -12,6 +12,7 @@ import shutil import sys +from numbers import Number from pathlib import Path from typing import Self @@ -22,10 +23,12 @@ from geoh5py.groups import SimPEGGroup, UIJsonGroup from geoh5py.shared.utils import ( dict_to_json_str, - fetch_active_workspace, + str_json_to_dict, uuid_from_values, ) from geoh5py.ui_json.utils import flatten +from h5py import File +from pandas import DataFrame from simpeg_drivers.driver import BaseDriver from simpeg_drivers.plate_simulation.driver import PlateSimulationDriver @@ -55,18 +58,18 @@ def start(cls, filepath: str | Path, mode="r", **_) -> Self: filepath = Path(filepath).resolve() uijson = PlateSweepUIJson.read(filepath) - with Workspace(uijson.geoh5, mode=mode) as workspace: - try: + try: + with Workspace(uijson.geoh5, mode=mode) as workspace: options = SweepOptions.build(uijson.to_params(workspace=workspace)) logger.info("Initializing application . . .") driver = cls(options) logger.info("Running application . . .") - driver.run() - logger.info("Results saved to %s", options.geoh5.h5file) + driver.run() + logger.info("Results saved to %s", options.geoh5.h5file) - except GeoAppsError as error: - logger.warning("\n\nApplicationError: %s\n\n", error) - sys.exit(1) + except GeoAppsError as error: + logger.warning("\n\nApplicationError: %s\n\n", error) + sys.exit(1) return driver @@ -82,7 +85,7 @@ def run(self): use_futures = self.client - if use_futures: + if use_futures and trials: blocks = np.array_split(trials, len(self.workers)) else: blocks = trials @@ -111,6 +114,13 @@ def run(self): if use_futures: self.client.gather(futures) + if self.params.generate_summary: + summary = generate_summary(self.params.workdir.iterdir()) + out_file = self.params.geoh5.h5file.parent / "summary.xlsx" + summary.to_excel(out_file, index=False) + with self.params.geoh5.open(mode="r+"): + self.out_group.add_file(out_file) + @staticmethod def run_trial( data: dict, h5file: Path, workdir: str, worker: tuple[str] | None = None @@ -163,6 +173,53 @@ def run_trial( return None +def forms_to_values(data: dict) -> dict: + """ + Convert a dictionary of forms to a dictionary of values, where the value is a number. + + :param data: Dictionary of forms. + + :return: Dictionary of key and numeric values + """ + fields = {} + for name, form in data.items(): + if isinstance(form, dict) and isinstance(form.get("value"), Number): + fields[name] = form.get("value") + + return fields + + +def generate_summary(directory: list[Path]) -> DataFrame: + """ + Generate a summary of the trials and save it to the geoh5 file. + + :param directory: List of paths to geoh5 files to summarize. + + :return: Dataframe of trial names and options. + """ + summary = [] + for simulation in directory: + if Path(simulation).resolve().suffix != ".geoh5": + continue + + with File(simulation, mode="r") as geoh5: + for group in geoh5["GEOSCIENCE"]["Groups"].values(): + if group.get("options", None): + options = str_json_to_dict(np.r_[group["options"]][0]) + + if ( + options["title"] == "Plate Simulation" + and len(group["Objects"]) > 0 + ): + options = forms_to_values(options) + output = {"file": simulation.stem} + output.update(options) + summary.append(output) + break + + return DataFrame(summary) + + def run_block( trials: list[dict], h5file: Path, diff --git a/simpeg_drivers/plate_simulation/sweep/options.py b/simpeg_drivers/plate_simulation/sweep/options.py index 52d3c2a81..dc372499c 100644 --- a/simpeg_drivers/plate_simulation/sweep/options.py +++ b/simpeg_drivers/plate_simulation/sweep/options.py @@ -63,8 +63,9 @@ class SweepOptions(Options): forward_only: bool = True inversion_type: str = "plate sweep" template: SimPEGGroup | UIJsonGroup + generate_summary: bool = True sweeps: list[ParamSweep] - workdir: str = "./simulations" + workdir: Path = Path("./simulations") @field_serializer("sweeps") def sweeps_to_params(self, sweeps): @@ -112,6 +113,9 @@ def collect_sweep(param: str) -> dict: @property def trials(self) -> list[dict]: """Returns a list of parameter combinations to run for each trial.""" + if not self.sweeps: + return [] + names = [s.name for s in self.sweeps] iterations = itertools.product(*[np.linspace(*s()) for s in self.sweeps]) options_dict = self.template_options.copy() diff --git a/simpeg_drivers/plate_simulation/sweep/uijson.py b/simpeg_drivers/plate_simulation/sweep/uijson.py index d82c9cdfe..8a74ff329 100644 --- a/simpeg_drivers/plate_simulation/sweep/uijson.py +++ b/simpeg_drivers/plate_simulation/sweep/uijson.py @@ -8,7 +8,13 @@ # ' # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from geoh5py.ui_json.forms import FloatForm, GroupForm, IntegerForm, StringForm +from geoh5py.ui_json.forms import ( + BoolForm, + FloatForm, + GroupForm, + IntegerForm, + StringForm, +) from geoh5py.ui_json.ui_json import BaseUIJson from pydantic import ConfigDict @@ -46,3 +52,4 @@ class PlateSweepUIJson(BaseUIJson): dip_direction_count: IntegerForm out_group: GroupForm | None workdir: StringForm | None + generate_summary: BoolForm diff --git a/simpeg_drivers/potential_fields/magnetic_vector/options.py b/simpeg_drivers/potential_fields/magnetic_vector/options.py index 83639a7b2..b9ed8aac9 100644 --- a/simpeg_drivers/potential_fields/magnetic_vector/options.py +++ b/simpeg_drivers/potential_fields/magnetic_vector/options.py @@ -15,12 +15,12 @@ from typing import ClassVar from geoh5py.data import FloatData -from geoh5py.ui_json.annotations import Deprecated from simpeg_drivers import assets_path from simpeg_drivers.options import ( BaseForwardOptions, BaseInversionOptions, + Deprecated, DirectiveOptions, ModelOptions, ) @@ -31,7 +31,7 @@ class VectorModelOptions(ModelOptions): Magnetic Vector Model options. """ - lower_bound: Deprecated | None = None + lower_bound: Deprecated starting_inclination: float | FloatData | None = None starting_declination: float | FloatData | None = None reference_inclination: float | FloatData | None = None diff --git a/tests/plate_simulation/runtest/sweep_test.py b/tests/plate_simulation/runtest/sweep_test.py index 08d440037..9977c378c 100644 --- a/tests/plate_simulation/runtest/sweep_test.py +++ b/tests/plate_simulation/runtest/sweep_test.py @@ -8,10 +8,10 @@ # ' # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - from geoh5py import Workspace from geoh5py.groups import SimPEGGroup from geoh5py.ui_json import InputFile +from pandas import read_excel from simpeg_drivers import assets_path from simpeg_drivers.plate_simulation.options import PlateSimulationOptions @@ -103,3 +103,7 @@ def test_sweep(tmp_path): n = len(list(workdir.glob("*.geoh5"))) assert n == 6 + + xls = read_excel(tmp_path / "summary.xlsx") + + assert len(xls) == 6 diff --git a/tests/run_tests/driver_mvi_test.py b/tests/run_tests/driver_mvi_test.py index 236c72e12..cfce3e574 100644 --- a/tests/run_tests/driver_mvi_test.py +++ b/tests/run_tests/driver_mvi_test.py @@ -149,7 +149,7 @@ def test_magnetic_vector_run( ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") if caplog: - assert "Skipping deprecated field: lower_bound" in caplog.text + assert "Deprecated field 'lower_bound' will be ignored." in caplog.text driver = MVIInversionDriver(params) assert np.all(driver.models.lower_bound == -upper_bound)