[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M73HKPWA6D380JZNW0M5ZCV8":3,"skill-same:01M73HKPWA6D380JZNW0M5ZCV8":55},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":31,"commitSha":32,"skillDirectory":33,"forksCount":34,"repositoryHtmlUrl":35,"repositoryHomepageUrl":36,"ownerHtmlUrl":37,"ownerBlogUrl":38,"ownerDescription":39,"updatedAt":40,"install":41,"resources":54},"01M73HKPWA6D380JZNW0M5ZCV8","openpiv",null,"Performs Particle Image Velocimetry (PIV) analysis with OpenPIV. Use when extracting velocity fields from PIV image pairs, analyzing fluid dynamics or flow visualization experiments, cross-correlating interrogation windows, validating and replacing spurious PIV vectors, or computing vorticity, strain rate, and turbulence statistics from measured velocity fields.","bg-szy\u002FTOP-SKILLS","bg-szy","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F106576190?v=4","01M73A4E8KPV67SFXRY8XZGNBX","ShuZhiyong","01M73A4E96MQ294MHM74TZBVQD",6,"BSD-3-Clause","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fopenpiv\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: openpiv\ndescription: Performs Particle Image Velocimetry (PIV) analysis with OpenPIV. Use when extracting velocity fields from PIV image pairs, analyzing fluid dynamics or flow visualization experiments, cross-correlating interrogation windows, validating and replacing spurious PIV vectors, or computing vorticity, strain rate, and turbulence statistics from measured velocity fields.\nlicense: BSD-3-Clause\ncompatibility: Requires Python 3.10+ with openpiv installed (uv pip install openpiv). numpy, scipy, scikit-image, and matplotlib arrive as dependencies. No network access needed after install.\nallowed-tools: Read Write Edit Bash\nmetadata:\n  version: \"1.3\"\n  skill-author: OpenPIV Team\n  tested-against: \"openpiv 0.26.1\"\n  last-reviewed: \"2026-10-01\"\n---\n\n# OpenPIV\n\n## Overview\n\nOpenPIV (Open Particle Image Velocimetry) analyzes fluid flow from PIV image pairs. It covers\npreprocessing, cross-correlation, vector validation, outlier replacement, smoothing, and scaling to\nphysical units.\n\nTargets **openpiv 0.26.1**. Synthetic checks ran on Python 3.13, NumPy 2.5.3, SciPy 1.18.1,\nscikit-image 0.26.0, and Matplotlib 3.11.2. Rust was not installed; use `backend=\"scipy\"` for the\ntested path. See [review evidence](references\u002Fadvanced_algorithms.md#review-sources-and-verification).\n\n## When to use\n\nUse this skill when working with experimental PIV or flow-visualization image pairs: measuring 2D\nvelocity fields, tuning interrogation-window parameters, validating vectors, or deriving vorticity,\nstrain rate, and turbulence statistics. For *simulating* flow rather than measuring it, use a CFD\nskill instead.\n\n## Quick Start\n\nInstall OpenPIV:\n\n```bash\nuv pip install openpiv\n\n# Pin it when the analysis needs to be reproducible -- this is the version every\n# snippet below was checked against.\nuv pip install \"openpiv==0.26.1\"\n```\n\nRun PIV analysis on an image pair:\n\n```python\nimport numpy as np\nfrom openpiv import tools, pyprocess, validation, filters, scaling\n\nframe_a = tools.imread(\"image_a.bmp\")\nframe_b = tools.imread(\"image_b.bmp\")\n\n# Always returns (u, v, s2n); s2n is all NaN if sig2noise_method=None.\nu, v, s2n = pyprocess.extended_search_area_piv(\n    frame_a.astype(np.float32),\n    frame_b.astype(np.float32),\n    window_size=32,\n    overlap=12,\n    dt=0.02,\n    search_area_size=38,\n    correlation_method=\"linear\",   # circular also supports extended search\n    normalized_correlation=True,\n    backend=\"scipy\",\n    sig2noise_method=\"peak2peak\",\n)\n\nx, y = pyprocess.get_coordinates(\n    image_size=frame_a.shape,\n    search_area_size=38,\n    overlap=12,\n    center_on_field=False,         # matches sliding-window positions\n)\n\n# flags is a boolean array: True marks a spurious vector.\nflags = validation.sig2noise_val(s2n, threshold=1.05) | ~np.isfinite(s2n)\nflags |= ~np.isfinite(u) | ~np.isfinite(v)\nu, v = filters.replace_outliers(u, v, flags, method=\"localmean\", max_iter=3, kernel_size=2)\n\n# Scale, then convert to right-handed image-boundary coordinates.\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\ny, v = frame_a.shape[0] \u002F 96.52 - y, -v\n\ntools.save(\"vectors.txt\", x, y, u, v, flags)\n```\n\nOr use the bundled CLI, which also checks inputs and preserves masks and processing parameters:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp --image frame_b.bmp --output_dir results --verbose\n```\n\n## Core Concepts\n\n### PIV Fundamentals\n\nParticle Image Velocimetry is an optical method for measuring fluid velocity by tracking illuminated\ntracer particles between two images.\n\n**Process flow:**\n\n1. Capture an image pair (`frame_a`, `frame_b`) separated by a known time `dt`.\n2. Divide the images into interrogation windows.\n3. Cross-correlate matching windows to find peak displacement.\n4. Validate vectors (signal-to-noise, global range, local median).\n5. Replace spurious vectors with interpolated values.\n6. Scale pixel displacements to physical units.\n\n### Interrogation Window Parameters\n\n**`window_size`** — correlation window in pixels (typically 16–128). Larger windows give better\ncorrelation but coarser spatial resolution.\n\n**`overlap`** — pixels shared between adjacent windows (typically 50–75% of `window_size`). Higher\noverlap raises vector density and cost, but adjacent vectors become correlated rather than\nindependent.\n\n**`search_area_size`** — the window searched in the second frame. Must be ≥ `window_size`; a few\npixels larger accommodates larger displacements. Both `\"circular\"` and `\"linear\"` support extended\nsearch. The CLI chooses zero-padded `\"linear\"` with `normalized_correlation=True` for it; this\ndoes not recover arbitrary displacement or eliminate spurious peaks. Grid stride is\n`search_area_size - overlap`, so overlap must be smaller than the search area.\n\nRules of thumb: keep the largest displacement under about a quarter of `window_size`, and aim for\n5–10 particles per window.\n\n### Signal-to-Noise Ratio\n\n`s2n` measures how distinct the correlation peak is. `sig2noise_method` controls how it is computed —\n`\"peak2mean\"` (the function default) or `\"peak2peak\"`. **The two are on different scales**, so a\nthreshold tuned for one is meaningless for the other. Typical `peak2peak` thresholds are 1.05–1.3.\n\n```python\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n# flags is bool: True == spurious. `~flags` selects the good vectors.\n```\n\n## Common Operations\n\n### Dynamic Masking\n\nMasking lives in `openpiv.preprocess` and returns `(image, mask)`. Use floating-point copies\nto avoid unsigned subtraction artifacts. Inspect masks on both frames before analysis.\n\n```python\nfrom openpiv import preprocess\n\n# Intensity masking uses Otsu; the threshold argument is for edges.\nframe_a_masked, mask_a = preprocess.dynamic_masking(\n    frame_a.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\nframe_b_masked, mask_b = preprocess.dynamic_masking(\n    frame_b.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\n```\n\nPreserve the union `mask_a | mask_b` as excluded physical regions. The CLI samples it at\ninterrogation centers, saves it, and keeps those velocities NaN after replacement. Windows\nstraddling an object can still be biased: inspect\u002Fdilate masks for the experiment. In 0.26.1\n`method=\"edges\"` indexes with uint8 instead of bool, potentially corrupting the image or failing.\nThe CLI refuses it; use intensity masking or a verified boolean mask in a custom workflow.\n\n### Multi-Pass Processing\n\nMulti-pass (window deformation) lives in `openpiv.windef`, driven by a `PIVSettings` dataclass.\n`pyprocess` has no multi-pass entry point.\n\n```python\nimport numpy as np\nfrom openpiv import scaling, windef\n\nsettings = windef.PIVSettings(\n    windowsizes=(64, 32, 16), overlap=(32, 16, 8), num_iterations=3,\n    backend=\"scipy\", sig2noise_method=\"peak2peak\", sig2noise_threshold=1.05,\n)\n\nx, y, u, v, flags = windef.simple_multipass(\n    frame_a.astype(np.float32), frame_b.astype(np.float32), settings\n)\n\n# Output is in PIXELS PER FRAME -- convert yourself. scaling.uniform only divides\n# by scaling_factor, so apply dt separately.\ndt = 0.02\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\nu, v = u \u002F dt, v \u002F dt\n```\n\n`simple_multipass` validates, replaces outliers, fills remaining NaNs with zeros, and transforms\ncoordinates. Keep its flags: repaired\u002Fzero-filled output is not an independent measurement.\nAlways pass settings: its no-settings path has two window sizes but three iterations in 0.26.1.\n\n**Units trap:** `simple_multipass` and its alias `multigrid_windef` ignore `settings.dt` and\n`settings.scaling_factor`; convert their arrays as above. Batch `windef.piv(settings)` applies\nboth before saving — do not scale its files again. The simple wrapper does not honor all batch\npreprocessing\u002Foutput switches.\n\nFor control over individual passes, `windef.first_pass` and `windef.multipass_img_deform` are the\nlower-level building blocks.\n\n## Validation and Post-Processing\n\n### Validation Methods\n\nEvery validator returns a boolean array where **True marks a spurious vector**. Also reject\nnonfinite `u`, `v`, and `s2n`: `sig2noise_val` alone does not flag NaN.\n\n```python\n# Signal-to-noise\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n\n# Global range -- takes (min, max) TUPLES, positionally or as u_thresholds\u002Fv_thresholds.\nflags = validation.global_val(u, v, (-300, 300), (-300, 300))\n\n# Local median -- u_threshold and v_threshold are REQUIRED; size is the neighbourhood half-width.\nflags = validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0, size=1)\n\n# Combine with boolean OR (not np.maximum -- these are bool arrays).\nflags = (\n    validation.sig2noise_val(s2n, threshold=1.05)\n    | validation.global_val(u, v, (-300, 300), (-300, 300))\n    | validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0)\n)\n```\n\n**Set these thresholds in the units of `u` and `v`, not in pixels per frame.**\n`extended_search_area_piv` divides by `dt`, so with `dt=0.02` a 3 px\u002Fframe displacement arrives as\n150 px\u002Fs. The thresholds above suit that case; the `(-30, 30)` figure that PIV literature and\n`PIVSettings.min_max_u_disp` use is a px\u002Fframe limit, and applying it to px\u002Fs output rejects the\nentire field. Correlate with `dt=1` to validate displacements before conversion, or adjust\nthresholds to the actual velocity units (including both time and calibration factors).\n\n### Outlier Replacement\n\n```python\nu, v = filters.replace_outliers(\n    u, v, flags, method=\"localmean\", max_iter=3, tol=1e-3, kernel_size=2\n)\n```\n\n`method` accepts `\"localmean\"`, `\"disk\"`, or `\"distance\"`; an invalid name raises `ValueError`\nwhen filling missing cells. Use `kernel_size>=2` for `\"distance\"`: size 1 truncates all neighbor\nweights to zero in 0.26.1 and leaves holes. Replacement *fills* the flagged\npositions with interpolated values — if you then overwrite them with NaN, the replacement was\nwasted. Choose one or the other:\n\n```python\n# Keep flagged vectors out of the analysis entirely, instead of interpolating them.\nu = np.where(flags, np.nan, u)\nv = np.where(flags, np.nan, v)\n```\n\n### Smoothing\n\nSmoothing is `openpiv.smoothn.smoothn`; there is no `openpiv.smooth` module. It returns a tuple\nwhose first element is the smoothed field. NaN\u002FInf are missing observations; supply a copy because\nit can modify input. Zero-filling holes first incorrectly treats them as measured zeros.\n\n```python\nfrom openpiv.smoothn import smoothn\n\nu_smooth, *_ = smoothn(np.asarray(u, dtype=float).copy(), s=0.5)  # larger == smoother\nv_smooth, *_ = smoothn(np.asarray(v, dtype=float).copy(), s=0.5)\nu_smooth = np.asarray(u_smooth)\n```\n\n## Visualization\n\n### Vector Field Plotting\n\n`display_vector_field` reads a saved vectors file and calls `plt.show()` internally, so select a\nnon-interactive backend for batch runs.\n\n```python\nimport matplotlib\nmatplotlib.use(\"Agg\")\nimport matplotlib.pyplot as plt\nfrom openpiv import tools\n\nfig, ax = plt.subplots(figsize=(8, 8))\ntools.display_vector_field(\n    \"vectors.txt\",\n    ax=ax,\n    scaling_factor=96.52,   # same factor used in scaling.uniform, to map back onto the image\n    scale=50,\n    width=0.0035,\n    on_img=False,\n)\nimage = tools.imread(\"frame_a.bmp\")\nheight, width = image.shape\nax.imshow(image, cmap=\"gray\", origin=\"upper\", zorder=-1,\n          extent=(0, width \u002F 96.52, 0, height \u002F 96.52))\nfig.savefig(\"vector_field.png\", dpi=150, bbox_inches=\"tight\")\nplt.close(fig)\n```\n\nSet image extents explicitly: the helper's `on_img=True` infers them from the last vector and\ncan stretch overlays when windows leave unused margins. The CLI plots with the actual image bounds.\n\n### Custom Visualization\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\nmag = np.sqrt(u**2 + v**2)\nfor ax, field, title, cmap in [\n    (axes[0], mag, \"Velocity Magnitude\", \"viridis\"),\n    (axes[1], u, \"U Velocity\", \"RdBu_r\"),\n    (axes[2], v, \"V Velocity\", \"RdBu_r\"),\n]:\n    im = ax.imshow(field, cmap=cmap)\n    ax.set_title(title)\n    plt.colorbar(im, ax=ax)\n\nfig.tight_layout()\nfig.savefig(\"velocity_components.png\")\nplt.close(fig)\n```\n\n## Analysis Functions\n\n`scripts\u002Fanalyze.py` bundles these against a `params.npz` written by `runner.py`. It infers the\nphysical grid spacing from the saved coordinates, so the derivatives come out per unit length:\n\n```python\nimport sys\nsys.path.insert(0, \"skills\u002Fopenpiv\u002Fscripts\")\nfrom analyze import PIVAnalyzer\n\npiv = PIVAnalyzer(\"results\u002Fparams.npz\")\nvorticity = piv.compute_vorticity()          # dv\u002Fdx - du\u002Fdy\nexx, eyy, exy = piv.compute_strain()\nstats = piv.compute_statistics()             # excludes flagged and masked vectors\npiv.plot_vector_field(save_path=\"quiver.png\")\n```\n\nThe standalone forms, if you would rather compute them inline:\n\n### Vorticity\n\n```python\ndef compute_vorticity(u, v, dx=1.0, dy=None):\n    \"\"\"Out-of-plane vorticity dv\u002Fdx - du\u002Fdy. Pass the physical grid spacing, not 1.0.\"\"\"\n    dy = dx if dy is None else dy\n    return np.gradient(v, dx, axis=1) - np.gradient(u, dy, axis=0)\n```\n\nFor the single-pass extended-search grid, spacing is\n`(search_area_size - overlap) \u002F scaling_factor` in physical units; it reduces to\n`(window_size - overlap) \u002F scaling_factor` only when the two window sizes match.\nPrefer differences of the saved `x` and `y` coordinates, especially after multipass\nprocessing. Leaving `dx=1.0` yields vorticity per grid cell, not per unit length.\nSee [OpenPIV coordinate generation](https:\u002F\u002Fopenpiv.readthedocs.io\u002Fen\u002Fstable\u002Fsrc\u002Ftutorial1.html).\n\n**Sign convention:** the CLI writes `y = image_height \u002F scaling_factor - y` and negates `v`,\nkeeping rows in image order. Saved `y` decreases down the array. The standalone forms need\nsigned `dy` (negative here), or use `PIVAnalyzer`, which reads orientation. Positive `dy` changes\nthe y-derivative contribution and can even cancel real rotation.\n\n### Strain Rate\n\n```python\ndef compute_strain(u, v, dx=1.0, dy=None):\n    \"\"\"Return (exx, eyy, exy) of the 2D strain-rate tensor.\"\"\"\n    dy = dx if dy is None else dy\n    du_dx = np.gradient(u, dx, axis=1)\n    du_dy = np.gradient(u, dy, axis=0)\n    dv_dx = np.gradient(v, dx, axis=1)\n    dv_dy = np.gradient(v, dy, axis=0)\n    return du_dx, dv_dy, 0.5 * (du_dy + dv_dx)\n```\n\n### Turbulence Statistics\n\n```python\ndef compute_statistics(u, v):\n    \"\"\"Single-frame spatial statistics. NOT Reynolds decomposition.\"\"\"\n    u_prime = u - np.nanmean(u)\n    v_prime = v - np.nanmean(v)\n    rms_u, rms_v = np.nanstd(u_prime), np.nanstd(v_prime)\n    return {\n        \"u_mean\": np.nanmean(u),\n        \"v_mean\": np.nanmean(v),\n        \"rms_u\": rms_u,\n        \"rms_v\": rms_v,\n        \"tke\": 0.5 * (rms_u**2 + rms_v**2),\n    }\n```\n\n**Caveat:** subtracting the *spatial* mean of one frame measures spatial variance, which equals\nturbulent intensity only under justified homogeneity\u002Fergodicity assumptions. Reynolds decomposition\nneeds an ensemble: subtract its mean field from each realization. The legacy `tke` key is only\ntwo-component spatial variance energy, not full turbulent kinetic energy. The analyzer excludes\nflagged vectors by default; `compute_statistics(include_interpolated=True)` includes repaired ones.\n\n## CLI Usage\n\n```bash\n# Basic run\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image img1.bmp --image img2.bmp --output_dir results --verbose\n\n# Tuned parameters with dynamic masking\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp \\\n    --image frame_b.bmp \\\n    --output_dir results \\\n    --window_size 32 \\\n    --overlap 12 \\\n    --search_area 38 \\\n    --dt 0.02 \\\n    --scaling 96.52 \\\n    --threshold 1.05 \\\n    --mask dynamic \\\n    --mask_method intensity \\\n    --verbose\n```\n\n### CLI Options\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `--image` | required | Image file; specify exactly twice for the pair |\n| `--output_dir` | `results` | Output directory (created if absent) |\n| `--window_size` | 32 | Interrogation window size (px) |\n| `--overlap` | 12 | Search-grid overlap (px), nonnegative and less than search area |\n| `--search_area` | 38 | Search area size (px), must be ≥ `--window_size` |\n| `--dt` | 0.02 | Time between frames (s) |\n| `--scaling` | 96.52 | Scaling factor, pixels per physical unit (e.g. px\u002Fmm) |\n| `--threshold` | 1.05 | `peak2peak` signal-to-noise threshold |\n| `--mask` | `none` | `none` or `dynamic` (`openpiv.preprocess.dynamic_masking`) |\n| `--mask_method` | `intensity` | Only intensity is usable in 0.26.1; edges is refused |\n| `--backend` | `scipy` | `scipy`, `auto`, or `rust`; Rust requires its extension |\n| `--drop_invalid` | off | NaN out flagged vectors instead of keeping interpolated values |\n| `--verbose` | off | Print progress messages |\n\nVerify an install end to end against OpenPIV's own bundled image pair:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frun_example.py --output_dir \u002Ftmp\u002Fopenpiv-demo\n```\n\n## Output Files\n\n- **vectors.txt** — tab-delimited, `%.4e` formatted, with a `# x y u v flags mask` comment header\n- **params.npz** — `x`, `y`, `u`, `v`, `flags`, `mask`, `s2n`, timing\u002Fcalibration\u002Fwindow parameters,\n  requested backend, and OpenPIV version. Coordinates use physical units; velocity uses units\u002Fs.\n- **vector_field.png** — vector field drawn over the first frame\n\n```text\n# x\ty\tu\tv\tflags\tmask\n2.1757e-01\t3.5226e+00\t-6.2220e-02\t-2.7081e+00\t0.0000e+00\t0.0000e+00\n4.8695e-01\t3.5226e+00\t-3.1587e-01\t-2.9800e+00\t0.0000e+00\t0.0000e+00\n```\n\n`flags` is float, `0` for valid and `1` for flagged. `mask=1` marks an excluded object region,\nindependently of flags. Preserve both with the measured field.\n\n## Best Practices\n\n### Parameter Selection\n\n1. **Window size** — 32×32 suits most cases. 64\u002F128 for better correlation at coarser resolution;\n   16\u002F24 for finer resolution at the cost of noise.\n2. **Overlap** — 50–75% of window size.\n3. **Threshold** — raise it to reject more vectors; always re-tune after switching\n   `sig2noise_method`.\n4. **Scaling factor** — calibrate against a known reference such as a calibration grid, and keep the\n   units straight (`96.52` in OpenPIV's `test1` tutorial data is px\u002Fmm).\n\n### Image Quality\n\n- Particles visible and evenly distributed, 5–10 per interrogation window\n- No saturated or overexposed regions\n- Minimal background noise; consider background subtraction across a run\n\n### Processing Tips\n\n1. Start from the defaults, then tune against the vector field you get.\n2. Inspect the `s2n` distribution — a low median means poor correlation, not a bad threshold.\n3. Visualize early; obvious problems (uniform vectors, edge artifacts) show up immediately.\n4. Use multi-pass (`windef`) for flows with large velocity gradients or displacements.\n5. Mask reflections and solid boundaries rather than letting them generate vectors.\n\n## Resources\n\n### references\u002F\n\n- `advanced_algorithms.md` — correlation and subpixel methods, multi-pass window deformation,\n  `PIVSettings` fields, 3D and phase-separation modules\n\nLoad the reference when detailed algorithm or settings information is needed.\n","# OpenPIV\n\n## Overview\n\nOpenPIV (Open Particle Image Velocimetry) analyzes fluid flow from PIV image pairs. It covers\npreprocessing, cross-correlation, vector validation, outlier replacement, smoothing, and scaling to\nphysical units.\n\nTargets **openpiv 0.26.1**. Synthetic checks ran on Python 3.13, NumPy 2.5.3, SciPy 1.18.1,\nscikit-image 0.26.0, and Matplotlib 3.11.2. Rust was not installed; use `backend=\"scipy\"` for the\ntested path. See [review evidence](references\u002Fadvanced_algorithms.md#review-sources-and-verification).\n\n## When to use\n\nUse this skill when working with experimental PIV or flow-visualization image pairs: measuring 2D\nvelocity fields, tuning interrogation-window parameters, validating vectors, or deriving vorticity,\nstrain rate, and turbulence statistics. For *simulating* flow rather than measuring it, use a CFD\nskill instead.\n\n## Quick Start\n\nInstall OpenPIV:\n\n```bash\nuv pip install openpiv\n\n# Pin it when the analysis needs to be reproducible -- this is the version every\n# snippet below was checked against.\nuv pip install \"openpiv==0.26.1\"\n```\n\nRun PIV analysis on an image pair:\n\n```python\nimport numpy as np\nfrom openpiv import tools, pyprocess, validation, filters, scaling\n\nframe_a = tools.imread(\"image_a.bmp\")\nframe_b = tools.imread(\"image_b.bmp\")\n\n# Always returns (u, v, s2n); s2n is all NaN if sig2noise_method=None.\nu, v, s2n = pyprocess.extended_search_area_piv(\n    frame_a.astype(np.float32),\n    frame_b.astype(np.float32),\n    window_size=32,\n    overlap=12,\n    dt=0.02,\n    search_area_size=38,\n    correlation_method=\"linear\",   # circular also supports extended search\n    normalized_correlation=True,\n    backend=\"scipy\",\n    sig2noise_method=\"peak2peak\",\n)\n\nx, y = pyprocess.get_coordinates(\n    image_size=frame_a.shape,\n    search_area_size=38,\n    overlap=12,\n    center_on_field=False,         # matches sliding-window positions\n)\n\n# flags is a boolean array: True marks a spurious vector.\nflags = validation.sig2noise_val(s2n, threshold=1.05) | ~np.isfinite(s2n)\nflags |= ~np.isfinite(u) | ~np.isfinite(v)\nu, v = filters.replace_outliers(u, v, flags, method=\"localmean\", max_iter=3, kernel_size=2)\n\n# Scale, then convert to right-handed image-boundary coordinates.\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\ny, v = frame_a.shape[0] \u002F 96.52 - y, -v\n\ntools.save(\"vectors.txt\", x, y, u, v, flags)\n```\n\nOr use the bundled CLI, which also checks inputs and preserves masks and processing parameters:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp --image frame_b.bmp --output_dir results --verbose\n```\n\n## Core Concepts\n\n### PIV Fundamentals\n\nParticle Image Velocimetry is an optical method for measuring fluid velocity by tracking illuminated\ntracer particles between two images.\n\n**Process flow:**\n\n1. Capture an image pair (`frame_a`, `frame_b`) separated by a known time `dt`.\n2. Divide the images into interrogation windows.\n3. Cross-correlate matching windows to find peak displacement.\n4. Validate vectors (signal-to-noise, global range, local median).\n5. Replace spurious vectors with interpolated values.\n6. Scale pixel displacements to physical units.\n\n### Interrogation Window Parameters\n\n**`window_size`** — correlation window in pixels (typically 16–128). Larger windows give better\ncorrelation but coarser spatial resolution.\n\n**`overlap`** — pixels shared between adjacent windows (typically 50–75% of `window_size`). Higher\noverlap raises vector density and cost, but adjacent vectors become correlated rather than\nindependent.\n\n**`search_area_size`** — the window searched in the second frame. Must be ≥ `window_size`; a few\npixels larger accommodates larger displacements. Both `\"circular\"` and `\"linear\"` support extended\nsearch. The CLI chooses zero-padded `\"linear\"` with `normalized_correlation=True` for it; this\ndoes not recover arbitrary displacement or eliminate spurious peaks. Grid stride is\n`search_area_size - overlap`, so overlap must be smaller than the search area.\n\nRules of thumb: keep the largest displacement under about a quarter of `window_size`, and aim for\n5–10 particles per window.\n\n### Signal-to-Noise Ratio\n\n`s2n` measures how distinct the correlation peak is. `sig2noise_method` controls how it is computed —\n`\"peak2mean\"` (the function default) or `\"peak2peak\"`. **The two are on different scales**, so a\nthreshold tuned for one is meaningless for the other. Typical `peak2peak` thresholds are 1.05–1.3.\n\n```python\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n# flags is bool: True == spurious. `~flags` selects the good vectors.\n```\n\n## Common Operations\n\n### Dynamic Masking\n\nMasking lives in `openpiv.preprocess` and returns `(image, mask)`. Use floating-point copies\nto avoid unsigned subtraction artifacts. Inspect masks on both frames before analysis.\n\n```python\nfrom openpiv import preprocess\n\n# Intensity masking uses Otsu; the threshold argument is for edges.\nframe_a_masked, mask_a = preprocess.dynamic_masking(\n    frame_a.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\nframe_b_masked, mask_b = preprocess.dynamic_masking(\n    frame_b.astype(np.float64), method=\"intensity\", filter_size=7, threshold=0.005\n)\n```\n\nPreserve the union `mask_a | mask_b` as excluded physical regions. The CLI samples it at\ninterrogation centers, saves it, and keeps those velocities NaN after replacement. Windows\nstraddling an object can still be biased: inspect\u002Fdilate masks for the experiment. In 0.26.1\n`method=\"edges\"` indexes with uint8 instead of bool, potentially corrupting the image or failing.\nThe CLI refuses it; use intensity masking or a verified boolean mask in a custom workflow.\n\n### Multi-Pass Processing\n\nMulti-pass (window deformation) lives in `openpiv.windef`, driven by a `PIVSettings` dataclass.\n`pyprocess` has no multi-pass entry point.\n\n```python\nimport numpy as np\nfrom openpiv import scaling, windef\n\nsettings = windef.PIVSettings(\n    windowsizes=(64, 32, 16), overlap=(32, 16, 8), num_iterations=3,\n    backend=\"scipy\", sig2noise_method=\"peak2peak\", sig2noise_threshold=1.05,\n)\n\nx, y, u, v, flags = windef.simple_multipass(\n    frame_a.astype(np.float32), frame_b.astype(np.float32), settings\n)\n\n# Output is in PIXELS PER FRAME -- convert yourself. scaling.uniform only divides\n# by scaling_factor, so apply dt separately.\ndt = 0.02\nx, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52)\nu, v = u \u002F dt, v \u002F dt\n```\n\n`simple_multipass` validates, replaces outliers, fills remaining NaNs with zeros, and transforms\ncoordinates. Keep its flags: repaired\u002Fzero-filled output is not an independent measurement.\nAlways pass settings: its no-settings path has two window sizes but three iterations in 0.26.1.\n\n**Units trap:** `simple_multipass` and its alias `multigrid_windef` ignore `settings.dt` and\n`settings.scaling_factor`; convert their arrays as above. Batch `windef.piv(settings)` applies\nboth before saving — do not scale its files again. The simple wrapper does not honor all batch\npreprocessing\u002Foutput switches.\n\nFor control over individual passes, `windef.first_pass` and `windef.multipass_img_deform` are the\nlower-level building blocks.\n\n## Validation and Post-Processing\n\n### Validation Methods\n\nEvery validator returns a boolean array where **True marks a spurious vector**. Also reject\nnonfinite `u`, `v`, and `s2n`: `sig2noise_val` alone does not flag NaN.\n\n```python\n# Signal-to-noise\nflags = validation.sig2noise_val(s2n, threshold=1.05)\n\n# Global range -- takes (min, max) TUPLES, positionally or as u_thresholds\u002Fv_thresholds.\nflags = validation.global_val(u, v, (-300, 300), (-300, 300))\n\n# Local median -- u_threshold and v_threshold are REQUIRED; size is the neighbourhood half-width.\nflags = validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0, size=1)\n\n# Combine with boolean OR (not np.maximum -- these are bool arrays).\nflags = (\n    validation.sig2noise_val(s2n, threshold=1.05)\n    | validation.global_val(u, v, (-300, 300), (-300, 300))\n    | validation.local_median_val(u, v, u_threshold=30.0, v_threshold=30.0)\n)\n```\n\n**Set these thresholds in the units of `u` and `v`, not in pixels per frame.**\n`extended_search_area_piv` divides by `dt`, so with `dt=0.02` a 3 px\u002Fframe displacement arrives as\n150 px\u002Fs. The thresholds above suit that case; the `(-30, 30)` figure that PIV literature and\n`PIVSettings.min_max_u_disp` use is a px\u002Fframe limit, and applying it to px\u002Fs output rejects the\nentire field. Correlate with `dt=1` to validate displacements before conversion, or adjust\nthresholds to the actual velocity units (including both time and calibration factors).\n\n### Outlier Replacement\n\n```python\nu, v = filters.replace_outliers(\n    u, v, flags, method=\"localmean\", max_iter=3, tol=1e-3, kernel_size=2\n)\n```\n\n`method` accepts `\"localmean\"`, `\"disk\"`, or `\"distance\"`; an invalid name raises `ValueError`\nwhen filling missing cells. Use `kernel_size>=2` for `\"distance\"`: size 1 truncates all neighbor\nweights to zero in 0.26.1 and leaves holes. Replacement *fills* the flagged\npositions with interpolated values — if you then overwrite them with NaN, the replacement was\nwasted. Choose one or the other:\n\n```python\n# Keep flagged vectors out of the analysis entirely, instead of interpolating them.\nu = np.where(flags, np.nan, u)\nv = np.where(flags, np.nan, v)\n```\n\n### Smoothing\n\nSmoothing is `openpiv.smoothn.smoothn`; there is no `openpiv.smooth` module. It returns a tuple\nwhose first element is the smoothed field. NaN\u002FInf are missing observations; supply a copy because\nit can modify input. Zero-filling holes first incorrectly treats them as measured zeros.\n\n```python\nfrom openpiv.smoothn import smoothn\n\nu_smooth, *_ = smoothn(np.asarray(u, dtype=float).copy(), s=0.5)  # larger == smoother\nv_smooth, *_ = smoothn(np.asarray(v, dtype=float).copy(), s=0.5)\nu_smooth = np.asarray(u_smooth)\n```\n\n## Visualization\n\n### Vector Field Plotting\n\n`display_vector_field` reads a saved vectors file and calls `plt.show()` internally, so select a\nnon-interactive backend for batch runs.\n\n```python\nimport matplotlib\nmatplotlib.use(\"Agg\")\nimport matplotlib.pyplot as plt\nfrom openpiv import tools\n\nfig, ax = plt.subplots(figsize=(8, 8))\ntools.display_vector_field(\n    \"vectors.txt\",\n    ax=ax,\n    scaling_factor=96.52,   # same factor used in scaling.uniform, to map back onto the image\n    scale=50,\n    width=0.0035,\n    on_img=False,\n)\nimage = tools.imread(\"frame_a.bmp\")\nheight, width = image.shape\nax.imshow(image, cmap=\"gray\", origin=\"upper\", zorder=-1,\n          extent=(0, width \u002F 96.52, 0, height \u002F 96.52))\nfig.savefig(\"vector_field.png\", dpi=150, bbox_inches=\"tight\")\nplt.close(fig)\n```\n\nSet image extents explicitly: the helper's `on_img=True` infers them from the last vector and\ncan stretch overlays when windows leave unused margins. The CLI plots with the actual image bounds.\n\n### Custom Visualization\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\nmag = np.sqrt(u**2 + v**2)\nfor ax, field, title, cmap in [\n    (axes[0], mag, \"Velocity Magnitude\", \"viridis\"),\n    (axes[1], u, \"U Velocity\", \"RdBu_r\"),\n    (axes[2], v, \"V Velocity\", \"RdBu_r\"),\n]:\n    im = ax.imshow(field, cmap=cmap)\n    ax.set_title(title)\n    plt.colorbar(im, ax=ax)\n\nfig.tight_layout()\nfig.savefig(\"velocity_components.png\")\nplt.close(fig)\n```\n\n## Analysis Functions\n\n`scripts\u002Fanalyze.py` bundles these against a `params.npz` written by `runner.py`. It infers the\nphysical grid spacing from the saved coordinates, so the derivatives come out per unit length:\n\n```python\nimport sys\nsys.path.insert(0, \"skills\u002Fopenpiv\u002Fscripts\")\nfrom analyze import PIVAnalyzer\n\npiv = PIVAnalyzer(\"results\u002Fparams.npz\")\nvorticity = piv.compute_vorticity()          # dv\u002Fdx - du\u002Fdy\nexx, eyy, exy = piv.compute_strain()\nstats = piv.compute_statistics()             # excludes flagged and masked vectors\npiv.plot_vector_field(save_path=\"quiver.png\")\n```\n\nThe standalone forms, if you would rather compute them inline:\n\n### Vorticity\n\n```python\ndef compute_vorticity(u, v, dx=1.0, dy=None):\n    \"\"\"Out-of-plane vorticity dv\u002Fdx - du\u002Fdy. Pass the physical grid spacing, not 1.0.\"\"\"\n    dy = dx if dy is None else dy\n    return np.gradient(v, dx, axis=1) - np.gradient(u, dy, axis=0)\n```\n\nFor the single-pass extended-search grid, spacing is\n`(search_area_size - overlap) \u002F scaling_factor` in physical units; it reduces to\n`(window_size - overlap) \u002F scaling_factor` only when the two window sizes match.\nPrefer differences of the saved `x` and `y` coordinates, especially after multipass\nprocessing. Leaving `dx=1.0` yields vorticity per grid cell, not per unit length.\nSee [OpenPIV coordinate generation](https:\u002F\u002Fopenpiv.readthedocs.io\u002Fen\u002Fstable\u002Fsrc\u002Ftutorial1.html).\n\n**Sign convention:** the CLI writes `y = image_height \u002F scaling_factor - y` and negates `v`,\nkeeping rows in image order. Saved `y` decreases down the array. The standalone forms need\nsigned `dy` (negative here), or use `PIVAnalyzer`, which reads orientation. Positive `dy` changes\nthe y-derivative contribution and can even cancel real rotation.\n\n### Strain Rate\n\n```python\ndef compute_strain(u, v, dx=1.0, dy=None):\n    \"\"\"Return (exx, eyy, exy) of the 2D strain-rate tensor.\"\"\"\n    dy = dx if dy is None else dy\n    du_dx = np.gradient(u, dx, axis=1)\n    du_dy = np.gradient(u, dy, axis=0)\n    dv_dx = np.gradient(v, dx, axis=1)\n    dv_dy = np.gradient(v, dy, axis=0)\n    return du_dx, dv_dy, 0.5 * (du_dy + dv_dx)\n```\n\n### Turbulence Statistics\n\n```python\ndef compute_statistics(u, v):\n    \"\"\"Single-frame spatial statistics. NOT Reynolds decomposition.\"\"\"\n    u_prime = u - np.nanmean(u)\n    v_prime = v - np.nanmean(v)\n    rms_u, rms_v = np.nanstd(u_prime), np.nanstd(v_prime)\n    return {\n        \"u_mean\": np.nanmean(u),\n        \"v_mean\": np.nanmean(v),\n        \"rms_u\": rms_u,\n        \"rms_v\": rms_v,\n        \"tke\": 0.5 * (rms_u**2 + rms_v**2),\n    }\n```\n\n**Caveat:** subtracting the *spatial* mean of one frame measures spatial variance, which equals\nturbulent intensity only under justified homogeneity\u002Fergodicity assumptions. Reynolds decomposition\nneeds an ensemble: subtract its mean field from each realization. The legacy `tke` key is only\ntwo-component spatial variance energy, not full turbulent kinetic energy. The analyzer excludes\nflagged vectors by default; `compute_statistics(include_interpolated=True)` includes repaired ones.\n\n## CLI Usage\n\n```bash\n# Basic run\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image img1.bmp --image img2.bmp --output_dir results --verbose\n\n# Tuned parameters with dynamic masking\npython skills\u002Fopenpiv\u002Fscripts\u002Frunner.py \\\n    --image frame_a.bmp \\\n    --image frame_b.bmp \\\n    --output_dir results \\\n    --window_size 32 \\\n    --overlap 12 \\\n    --search_area 38 \\\n    --dt 0.02 \\\n    --scaling 96.52 \\\n    --threshold 1.05 \\\n    --mask dynamic \\\n    --mask_method intensity \\\n    --verbose\n```\n\n### CLI Options\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `--image` | required | Image file; specify exactly twice for the pair |\n| `--output_dir` | `results` | Output directory (created if absent) |\n| `--window_size` | 32 | Interrogation window size (px) |\n| `--overlap` | 12 | Search-grid overlap (px), nonnegative and less than search area |\n| `--search_area` | 38 | Search area size (px), must be ≥ `--window_size` |\n| `--dt` | 0.02 | Time between frames (s) |\n| `--scaling` | 96.52 | Scaling factor, pixels per physical unit (e.g. px\u002Fmm) |\n| `--threshold` | 1.05 | `peak2peak` signal-to-noise threshold |\n| `--mask` | `none` | `none` or `dynamic` (`openpiv.preprocess.dynamic_masking`) |\n| `--mask_method` | `intensity` | Only intensity is usable in 0.26.1; edges is refused |\n| `--backend` | `scipy` | `scipy`, `auto`, or `rust`; Rust requires its extension |\n| `--drop_invalid` | off | NaN out flagged vectors instead of keeping interpolated values |\n| `--verbose` | off | Print progress messages |\n\nVerify an install end to end against OpenPIV's own bundled image pair:\n\n```bash\npython skills\u002Fopenpiv\u002Fscripts\u002Frun_example.py --output_dir \u002Ftmp\u002Fopenpiv-demo\n```\n\n## Output Files\n\n- **vectors.txt** — tab-delimited, `%.4e` formatted, with a `# x y u v flags mask` comment header\n- **params.npz** — `x`, `y`, `u`, `v`, `flags`, `mask`, `s2n`, timing\u002Fcalibration\u002Fwindow parameters,\n  requested backend, and OpenPIV version. Coordinates use physical units; velocity uses units\u002Fs.\n- **vector_field.png** — vector field drawn over the first frame\n\n```text\n# x\ty\tu\tv\tflags\tmask\n2.1757e-01\t3.5226e+00\t-6.2220e-02\t-2.7081e+00\t0.0000e+00\t0.0000e+00\n4.8695e-01\t3.5226e+00\t-3.1587e-01\t-2.9800e+00\t0.0000e+00\t0.0000e+00\n```\n\n`flags` is float, `0` for valid and `1` for flagged. `mask=1` marks an excluded object region,\nindependently of flags. Preserve both with the measured field.\n\n## Best Practices\n\n### Parameter Selection\n\n1. **Window size** — 32×32 suits most cases. 64\u002F128 for better correlation at coarser resolution;\n   16\u002F24 for finer resolution at the cost of noise.\n2. **Overlap** — 50–75% of window size.\n3. **Threshold** — raise it to reject more vectors; always re-tune after switching\n   `sig2noise_method`.\n4. **Scaling factor** — calibrate against a known reference such as a calibration grid, and keep the\n   units straight (`96.52` in OpenPIV's `test1` tutorial data is px\u002Fmm).\n\n### Image Quality\n\n- Particles visible and evenly distributed, 5–10 per interrogation window\n- No saturated or overexposed regions\n- Minimal background noise; consider background subtraction across a run\n\n### Processing Tips\n\n1. Start from the defaults, then tune against the vector field you get.\n2. Inspect the `s2n` distribution — a low median means poor correlation, not a bad threshold.\n3. Visualize early; obvious problems (uniform vectors, edge artifacts) show up immediately.\n4. Use multi-pass (`windef`) for flows with large velocity gradients or displacements.\n5. Mask reflections and solid boundaries rather than letting them generate vectors.\n\n## Resources\n\n### references\u002F\n\n- `advanced_algorithms.md` — correlation and subpixel methods, multi-pass window deformation,\n  `PIVSettings` fields, 3D and phase-separation modules\n\nLoad the reference when detailed algorithm or settings information is needed.\n",{"name":5,"license":15,"metadata":24,"description":7,"allowed-tools":29,"compatibility":30},{"version":25,"skill-author":26,"last-reviewed":27,"tested-against":28},"1.3","OpenPIV Team","2026-10-01","openpiv 0.26.1","Read Write Edit Bash","Requires Python 3.10+ with openpiv installed (uv pip install openpiv). numpy, scipy, scikit-image, and matplotlib arrive as dependencies. No network access needed after install.","master","fd76f882a04e445e899d5cfb2732f2105ea054ee","skills\u002Fawesome-skills\u002Fopenpiv",0,"https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS","https:\u002F\u002Fbg-szy.github.io\u002FTOP-SKILLS\u002F","https:\u002F\u002Fgithub.com\u002Fbg-szy","https:\u002F\u002Fwww.ecust.edu.cn\u002F","a student of East China University of Science and Technology","2026-11-12 05:55:03",{"source":8,"skillName":5,"commands":42,"prompt":52,"zipAvailable":53},[43,46,49],{"tool":44,"command":45},"npx","npx skills add bg-szy\u002FTOP-SKILLS --skill openpiv",{"tool":47,"command":48},"bunx","bunx skills add bg-szy\u002FTOP-SKILLS --skill openpiv",{"tool":50,"command":51},"pnpm","pnpm dlx skills add bg-szy\u002FTOP-SKILLS --skill openpiv","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fopenpiv\u002FSKILL.md",true,[],[56,65,73,81,89,96],{"skillNo":57,"name":58,"nameZh":6,"description":59,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":60,"licenseFileUrl":61,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M73WM4TPHEJ57D7G2AZ0ABVT","inbox-guardian-for-gmail","Review a personal Gmail inbox with local, owner-approved spam rules. Use for audit-first quarantine, Trash, repeated-evidence sender learning, and header review. Do not use for automatic unsubscribe requests or unreviewed mailbox actions.","MIT","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Finbox-guardian-for-gmail\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Finbox-guardian-for-gmail\u002FSKILL.md",[],[],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":69,"licenseFileUrl":6,"sourceHtmlUrl":70,"categories":71,"keywords":72,"publishedAt":19},"01M73QERWCH2YEGTPC346PKGWW","chatgpt-app-builder","Guide developers through creating and updating ChatGPT apps.\nCovers the full lifecycle: brainstorming ideas against UX guidelines, bootstrapping projects, implementing tools\u002Fviews, debugging, running dev servers, deploying and connecting apps to ChatGPT.\nUse when a user wants to create or update a ChatGPT app \u002F MCP server for ChatGPT, or use the Skybridge framework.","NOASSERTION","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Fchatgpt-app-builder\u002FSKILL.md",[],[],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":60,"licenseFileUrl":77,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":19},"01M73PZFMKXPVJQCV7T0BBV6EV","brewpage-publish","Publish content to brewpage.app — text, markdown, JSON, file, or multi-file site. Asks namespace and password, returns public URL. Triggers: publish, share link, upload to brewpage, host page, brewpage, publish site, upload site, upload directory, deploy site, сделай публичную ссылку, опубликуй.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Fbrewpage-publish\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Fbrewpage-publish\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":85,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":19},"01M73KATEQ37JEDHHGKYHSZK40","zinc-database","Query the ZINC22 virtual compound library (CartBlanche API, billions of make-on-demand + purchasable molecules). Look up substances by ZINC ID, resolve a SMILES to its ZINC ID (exact match), inspect purchasability\u002Fcatalogs, and assemble compound sets for docking. Property (MW\u002FlogP) filtering is done locally with RDKit. For bioactivity use chembl-database-bioactivity; for approved drugs use drugbank-database-access.","CC-BY-4.0","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fzinc-database\u002FSKILL.md",[],[],{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":60,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":19},"01M73KAN6B77H0VZ0J0P4XX5M7","zarr-python","Stores and queries chunked N-D scientific arrays with Zarr-Python 3, including codecs, sharding, S3\u002FGCS storage, and NumPy\u002FDask\u002FXarray integration. Use for array layout, bounded I\u002FO, format migration, or scientific metadata preservation.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fzarr-python\u002FSKILL.md",[],[],{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":60,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":102,"publishedAt":19},"01M73K8904EZK0FDY5Z9A5NQ47","waypoint-bio","Supports work with Outpost Bio's open microbiome foundation models - the Waypoint checkpoints (Waypoint-6m, Waypoint-45m, Waypoint-170m), the Atlas pretraining corpus, the Compass eight-task benchmark, or the `waypoint` CLI from the `waypoint-bio` package. Covers embedding microbiome samples, fine-tuning on taxonomic abundance data, benchmarking a checkpoint on Compass, pretraining a GPT-2 model on taxonomic abundance profiles, and converting MetaPhlAn, Kraken2, QIIME 2, or MGnify abundance tables into waypoint format.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fwaypoint-bio\u002FSKILL.md",[],[]]