[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6XF9MXYQ9MB2A375JFHEY59":3,"skill-same:01M6XF9MXYQ9MB2A375JFHEY59":89},{"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":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":47,"commitSha":48,"skillDirectory":49,"forksCount":14,"repositoryHtmlUrl":50,"repositoryHomepageUrl":6,"ownerHtmlUrl":51,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":52,"install":53,"resources":66},"01M6XF9MXYQ9MB2A375JFHEY59","microbial-dynamics",null,"Microbial population dynamics modeling and analysis. Bacterial growth curve fitting (logistic, Gompertz, Baranyi), Lotka-Volterra community dynamics, Gillespie stochastic simulation, biofilm quantification, CFU enumeration, and genome annotation. For metabolic modeling use cobrapy; for sequence analysis use biopython.","fadrienne\u002FMyGitHub","fadrienne","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F197874571?v=4","01M6X64V8VWCRSMFZ4EPS2BWXG","Francesca Adrienne","01M6X64VD5MW4F9PHDWQKS7ZAF",0,"MIT","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"microbial dynamics","dynamics","annotation","Curve Fitting","sequence","curve","for","biology","sequence analysis","quantification","enumeration","genome annotation","modeling","community","use","growth","simulation","analysis","cobrapy","biopython","2026-11-10 10:12:30",false,"---\nname: microbial-dynamics\ndescription: Microbial population dynamics modeling and analysis. Bacterial growth curve fitting (logistic, Gompertz, Baranyi), Lotka-Volterra community dynamics, Gillespie stochastic simulation, biofilm quantification, CFU enumeration, and genome annotation. For metabolic modeling use cobrapy; for sequence analysis use biopython.\ncategory: biology\nlicense: MIT license\nmetadata:\n    skill-author: InkVell Inc.\n---\n\n# Microbial Dynamics: Population Dynamics & Modeling\n\n## Overview\n\nMicrobial Dynamics provides computational tools for modeling and analyzing microbial populations. This skill covers bacterial growth curve fitting using standard models (logistic, Gompertz, Baranyi), multi-species community dynamics via Lotka-Volterra equations, stochastic population simulation using the Gillespie algorithm, biofilm quantification from crystal violet assays, colony-forming unit enumeration with statistical analysis, bacterial genome annotation via Prokka, and simplified anaerobic digestion modeling.\n\n## When to Use This Skill\n\n- Fitting bacterial growth curves from OD600 time-series data\n- Extracting growth parameters: lag phase duration, maximum growth rate (mu_max), carrying capacity (K)\n- Modeling multi-species microbial community interactions\n- Running stochastic simulations of gene expression or population dynamics\n- Processing crystal violet biofilm assay data\n- Calculating CFU\u002FmL from serial dilution plating\n- Annotating bacterial genomes and extracting gene statistics\n- Modeling biogas production from anaerobic digestion\n\n**Related Skills:** For constraint-based metabolic modeling use `cobrapy`. For sequence manipulation and BLAST use `biopython`. For statistical analysis use `statistical-analysis`.\n\n## Installation\n\n```bash\nuv pip install scipy numpy pandas matplotlib\n```\n\nFor genome annotation (optional):\n```bash\n# conda install -c bioconda prokka\n```\n\n## Quick Start\n\n```python\nfrom scipy.optimize import curve_fit\nimport numpy as np\n\n# Logistic growth model\ndef logistic(t, y0, K, r, lag):\n    return K \u002F (1 + ((K - y0) \u002F y0) * np.exp(-r * (t - lag)))\n\n# Example OD600 data\ntime = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24])\nod600 = np.array([0.02, 0.02, 0.03, 0.06, 0.15, 0.38, 0.72, 1.05, 1.25, 1.42, 1.48, 1.50, 1.51, 1.51, 1.52])\n\npopt, pcov = curve_fit(logistic, time, od600, p0=[0.02, 1.5, 0.5, 2.0], maxfev=10000)\nprint(f\"y0={popt[0]:.4f}, K={popt[1]:.3f}, r={popt[2]:.3f} h^-1, lag={popt[3]:.2f} h\")\n```\n\n## Core Capabilities\n\n### 1. Growth Curve Modeling\n\nFit OD600 data to standard microbial growth models.\n\n```python\nimport numpy as np\nfrom scipy.optimize import curve_fit\n\ndef logistic(t, y0, K, r, lag):\n    \"\"\"Logistic growth model.\"\"\"\n    return K \u002F (1 + ((K - y0) \u002F y0) * np.exp(-r * (t - lag)))\n\ndef gompertz(t, y0, K, mu_max, lag):\n    \"\"\"Modified Gompertz growth model.\"\"\"\n    return y0 + (K - y0) * np.exp(-np.exp((mu_max * np.e \u002F (K - y0)) * (lag - t) + 1))\n\ndef baranyi(t, y0, K, mu_max, lag):\n    \"\"\"Baranyi growth model.\"\"\"\n    A_t = t + (1 \u002F mu_max) * np.log(np.exp(-mu_max * t) +\n           np.exp(-mu_max * lag) - np.exp(-mu_max * (t + lag)))\n    return K - np.log(1 + (np.exp(K) - np.exp(y0)) \u002F np.exp(y0) * np.exp(-mu_max * A_t))\n\ndef fit_growth_curve(time, od600, model='logistic'):\n    \"\"\"Fit growth curve to OD data and return parameters.\"\"\"\n    models = {'logistic': logistic, 'gompertz': gompertz, 'baranyi': baranyi}\n    func = models[model]\n\n    # Initial guesses\n    y0_guess = od600[0]\n    K_guess = od600.max()\n    r_guess = 0.5\n    lag_guess = time[np.argmax(np.gradient(od600))] - 1\n\n    p0 = [y0_guess, K_guess, r_guess, max(lag_guess, 0)]\n    bounds = ([0, 0, 0, 0], [np.inf, np.inf, 10, time.max()])\n\n    popt, pcov = curve_fit(func, time, od600, p0=p0, bounds=bounds, maxfev=10000)\n    perr = np.sqrt(np.diag(pcov))\n\n    # R-squared\n    residuals = od600 - func(time, *popt)\n    ss_res = np.sum(residuals**2)\n    ss_tot = np.sum((od600 - np.mean(od600))**2)\n    r_squared = 1 - (ss_res \u002F ss_tot)\n\n    param_names = ['y0', 'K', 'mu_max', 'lag']\n    result = {name: {'value': val, 'std': err}\n              for name, val, err in zip(param_names, popt, perr)}\n    result['r_squared'] = r_squared\n    result['model'] = model\n\n    return result, popt\n\n# Compare models\nfor model_name in ['logistic', 'gompertz', 'baranyi']:\n    try:\n        result, _ = fit_growth_curve(time, od600, model=model_name)\n        print(f\"{model_name}: R²={result['r_squared']:.4f}, \"\n              f\"mu_max={result['mu_max']['value']:.3f} ± {result['mu_max']['std']:.3f} h⁻¹, \"\n              f\"lag={result['lag']['value']:.2f} h\")\n    except RuntimeError:\n        print(f\"{model_name}: fitting failed\")\n```\n\n### 2. Lotka-Volterra Community Dynamics\n\nSimulate multi-species interactions.\n\n```python\nimport numpy as np\nfrom scipy.integrate import solve_ivp\n\ndef lotka_volterra(t, N, r, K, alpha):\n    \"\"\"Generalized Lotka-Volterra for n species.\n\n    Args:\n        N: array of population sizes\n        r: array of intrinsic growth rates\n        K: array of carrying capacities\n        alpha: interaction matrix (alpha[i,j] = effect of j on i)\n    \"\"\"\n    n = len(N)\n    dNdt = np.zeros(n)\n    for i in range(n):\n        interaction = sum(alpha[i, j] * N[j] for j in range(n))\n        dNdt[i] = r[i] * N[i] * (1 - interaction \u002F K[i])\n    return dNdt\n\n# 3-species community\nr = np.array([0.5, 0.4, 0.3])      # Growth rates\nK = np.array([1000, 800, 600])       # Carrying capacities\nalpha = np.array([                    # Interaction matrix\n    [1.0, 0.5, 0.1],   # Species 1: self + competition from 2 and 3\n    [0.3, 1.0, 0.4],   # Species 2\n    [0.2, 0.6, 1.0],   # Species 3\n])\nN0 = np.array([10, 10, 10])  # Initial populations\n\nsol = solve_ivp(\n    lotka_volterra, [0, 100], N0,\n    args=(r, K, alpha),\n    t_eval=np.linspace(0, 100, 500),\n    method='RK45'\n)\n\nprint(\"Final populations:\")\nfor i in range(3):\n    print(f\"  Species {i+1}: {sol.y[i, -1]:.1f}\")\n\n# Stability analysis: check if coexistence is stable\nA = np.diag(1\u002FK) @ alpha\ntry:\n    eigenvalues = np.linalg.eigvals(A)\n    stable = all(ev.real > 0 for ev in eigenvalues)\n    print(f\"Coexistence equilibrium is {'stable' if stable else 'unstable'}\")\nexcept np.linalg.LinAlgError:\n    print(\"Stability analysis failed\")\n```\n\n### 3. Stochastic Population Simulation\n\nGillespie SSA for exact stochastic simulation.\n\n```python\nimport numpy as np\n\ndef gillespie_ssa(propensity_func, stoich_matrix, x0, t_end, max_steps=100000):\n    \"\"\"Gillespie Stochastic Simulation Algorithm.\n\n    Args:\n        propensity_func: function(x) -> array of reaction propensities\n        stoich_matrix: reactions x species stoichiometry matrix\n        x0: initial state vector\n        t_end: simulation end time\n    \"\"\"\n    t = 0\n    x = np.array(x0, dtype=float)\n    times = [t]\n    states = [x.copy()]\n\n    for step in range(max_steps):\n        props = propensity_func(x)\n        total_prop = np.sum(props)\n\n        if total_prop == 0 or t >= t_end:\n            break\n\n        # Time to next reaction\n        dt = np.random.exponential(1 \u002F total_prop)\n        t += dt\n\n        if t > t_end:\n            break\n\n        # Choose reaction\n        reaction = np.searchsorted(np.cumsum(props), np.random.uniform(0, total_prop))\n        reaction = min(reaction, len(props) - 1)\n\n        # Update state\n        x += stoich_matrix[reaction]\n        x = np.clip(x, 0, None)\n\n        times.append(t)\n        states.append(x.copy())\n\n    return np.array(times), np.array(states)\n\n# Birth-death-immigration model\ndef propensities(x):\n    N = x[0]\n    birth_rate = 0.5 * N\n    death_rate = 0.01 * N * (N - 1)  # Density-dependent death\n    immigration = 5.0\n    return np.array([birth_rate, death_rate, immigration])\n\nstoich = np.array([[1], [-1], [1]])  # Birth: +1, Death: -1, Immigration: +1\n\n# Run ensemble\nn_runs = 50\nresults = []\nfor i in range(n_runs):\n    times, states = gillespie_ssa(propensities, stoich, [10], t_end=50)\n    results.append((times, states))\n\n# Summary statistics\nfinal_pops = [states[-1, 0] for _, states in results]\nprint(f\"Mean final population: {np.mean(final_pops):.1f} ± {np.std(final_pops):.1f}\")\n```\n\n### 4. Biofilm Quantification\n\nProcess crystal violet biofilm assay data.\n\n```python\nimport numpy as np\nimport pandas as pd\n\ndef analyze_biofilm_cv(od_data, blank_od=0.05, conditions=None):\n    \"\"\"Analyze crystal violet biofilm assay.\n\n    Args:\n        od_data: dict of condition -> list of OD570 replicates\n        blank_od: blank well OD for background subtraction\n    \"\"\"\n    results = []\n    for condition, replicates in od_data.items():\n        corrected = np.array(replicates) - blank_od\n        corrected = np.clip(corrected, 0, None)\n        results.append({\n            'condition': condition,\n            'mean_od': np.mean(corrected),\n            'std_od': np.std(corrected, ddof=1),\n            'n': len(corrected),\n            'sem': np.std(corrected, ddof=1) \u002F np.sqrt(len(corrected))\n        })\n\n    df = pd.DataFrame(results)\n    # Normalize to control\n    control_mean = df.iloc[0]['mean_od']\n    df['fold_change'] = df['mean_od'] \u002F control_mean\n    return df\n\n# Example: biofilm inhibition dose-response\nod_data = {\n    'Control': [0.85, 0.92, 0.88, 0.90],\n    '1 uM': [0.80, 0.78, 0.82, 0.79],\n    '10 uM': [0.55, 0.52, 0.58, 0.50],\n    '100 uM': [0.20, 0.18, 0.22, 0.19],\n}\n\ndf = analyze_biofilm_cv(od_data)\nprint(df[['condition', 'mean_od', 'std_od', 'fold_change']])\n```\n\n### 5. CFU Enumeration\n\nCalculate colony-forming units from serial dilution plating.\n\n```python\nimport numpy as np\nfrom scipy import stats\n\ndef calculate_cfu(counts, dilution_factor, volume_plated_ml=0.1):\n    \"\"\"Calculate CFU\u002FmL from plate counts.\n\n    Args:\n        counts: list of colony counts per plate\n        dilution_factor: dilution used (e.g., 1e-6 for 10^-6)\n        volume_plated_ml: volume plated in mL\n    \"\"\"\n    counts = np.array(counts)\n    cfu_per_ml = counts \u002F (dilution_factor * volume_plated_ml)\n\n    mean_cfu = np.mean(cfu_per_ml)\n    std_cfu = np.std(cfu_per_ml, ddof=1)\n    sem = std_cfu \u002F np.sqrt(len(counts))\n\n    # 95% confidence interval\n    ci = stats.t.interval(0.95, df=len(counts)-1, loc=mean_cfu, scale=sem)\n\n    return {\n        'mean_cfu_per_ml': mean_cfu,\n        'std': std_cfu,\n        'sem': sem,\n        'ci_95': ci,\n        'n': len(counts),\n        'log10_cfu': np.log10(mean_cfu)\n    }\n\n# Example\nresult = calculate_cfu(counts=[42, 38, 45], dilution_factor=1e-6, volume_plated_ml=0.1)\nprint(f\"CFU\u002FmL: {result['mean_cfu_per_ml']:.2e}\")\nprint(f\"Log10 CFU\u002FmL: {result['log10_cfu']:.2f}\")\nprint(f\"95% CI: ({result['ci_95'][0]:.2e}, {result['ci_95'][1]:.2e})\")\n```\n\n### 6. Bacterial Genome Annotation\n\nRun Prokka and parse results.\n\n```python\nimport subprocess\nimport pandas as pd\n\ndef run_prokka(fasta_path, output_dir, prefix='genome', genus=None, species=None):\n    \"\"\"Annotate bacterial genome with Prokka.\"\"\"\n    cmd = [\n        'prokka', fasta_path,\n        '--outdir', output_dir,\n        '--prefix', prefix,\n        '--cpus', '4',\n        '--force'\n    ]\n    if genus:\n        cmd.extend(['--genus', genus])\n    if species:\n        cmd.extend(['--species', species])\n\n    result = subprocess.run(cmd, capture_output=True, text=True)\n    if result.returncode != 0:\n        raise RuntimeError(f\"Prokka failed: {result.stderr}\")\n    return f'{output_dir}\u002F{prefix}'\n\ndef parse_prokka_gff(gff_path):\n    \"\"\"Parse Prokka GFF3 output to extract gene statistics.\"\"\"\n    genes = []\n    with open(gff_path) as f:\n        for line in f:\n            if line.startswith('#') or line.startswith('>'):\n                continue\n            if '\\t' not in line:\n                continue\n            parts = line.strip().split('\\t')\n            if len(parts) \u003C 9:\n                continue\n\n            feature_type = parts[2]\n            if feature_type in ('CDS', 'tRNA', 'rRNA', 'tmRNA'):\n                attrs = dict(kv.split('=', 1) for kv in parts[8].split(';') if '=' in kv)\n                genes.append({\n                    'type': feature_type,\n                    'start': int(parts[3]),\n                    'end': int(parts[4]),\n                    'strand': parts[6],\n                    'gene': attrs.get('gene', ''),\n                    'product': attrs.get('product', ''),\n                    'length': int(parts[4]) - int(parts[3]) + 1\n                })\n\n    df = pd.DataFrame(genes)\n    print(f\"Total features: {len(df)}\")\n    print(f\"Feature types:\\n{df['type'].value_counts()}\")\n    print(f\"Mean CDS length: {df[df['type']=='CDS']['length'].mean():.0f} bp\")\n\n    # Coding density\n    total_coding = df[df['type'] == 'CDS']['length'].sum()\n    genome_size = df['end'].max()\n    coding_density = 100 * total_coding \u002F genome_size\n    print(f\"Coding density: {coding_density:.1f}%\")\n\n    return df\n```\n\n### 7. Anaerobic Digestion Modeling\n\nSimplified ADM1 for biogas prediction.\n\n```python\nimport numpy as np\nfrom scipy.integrate import solve_ivp\n\ndef adm1_simplified(t, y, params):\n    \"\"\"Simplified anaerobic digestion model.\n    State: [S_substrate, X_acidogens, X_methanogens, S_VFA, CH4]\n    \"\"\"\n    S, Xa, Xm, VFA, CH4 = y\n    k_hyd = params['k_hyd']       # Hydrolysis rate\n    mu_a = params['mu_a']         # Acidogen max growth rate\n    Ks_a = params['Ks_a']         # Acidogen half-saturation\n    mu_m = params['mu_m']         # Methanogen max growth rate\n    Ks_m = params['Ks_m']         # Methanogen half-saturation\n    Y_a = params['Y_a']           # Acidogen yield\n    Y_m = params['Y_m']           # Methanogen yield\n    kd = params['kd']             # Decay rate\n    Ki = params['Ki']             # VFA inhibition constant\n\n    # Hydrolysis\n    r_hyd = k_hyd * S\n\n    # Acidogenesis (Monod kinetics)\n    r_acid = mu_a * (S \u002F (Ks_a + S)) * Xa\n\n    # Methanogenesis (Monod with VFA inhibition)\n    inhibition = Ki \u002F (Ki + VFA)\n    r_meth = mu_m * (VFA \u002F (Ks_m + VFA)) * Xm * inhibition\n\n    dSdt = -r_hyd - r_acid \u002F Y_a\n    dXa = Y_a * r_acid - kd * Xa\n    dXm = Y_m * r_meth - kd * Xm\n    dVFA = r_acid - r_meth \u002F Y_m\n    dCH4 = r_meth\n\n    return [dSdt, dXa, dXm, dVFA, dCH4]\n\nparams = {\n    'k_hyd': 0.25, 'mu_a': 0.5, 'Ks_a': 200,\n    'mu_m': 0.2, 'Ks_m': 50, 'Y_a': 0.1,\n    'Y_m': 0.05, 'kd': 0.02, 'Ki': 3000\n}\n\ny0 = [5000, 100, 50, 100, 0]  # Initial conditions\nsol = solve_ivp(adm1_simplified, [0, 60], y0, args=(params,),\n                t_eval=np.linspace(0, 60, 300), method='RK45')\n\nprint(f\"Final substrate: {sol.y[0, -1]:.0f} mg\u002FL\")\nprint(f\"Total CH4 produced: {sol.y[4, -1]:.0f} mg\u002FL\")\n```\n\n## Typical Workflows\n\n### Workflow 1: Fit Growth Curves and Compare Conditions\n\n```python\nimport pandas as pd\nimport numpy as np\n\n# Load multi-condition OD600 data\ndata = pd.read_csv('growth_data.csv')  # columns: time, condition, od600\n\nresults = []\nfor condition, group in data.groupby('condition'):\n    time = group['time'].values\n    od = group['od600'].values\n    fit, popt = fit_growth_curve(time, od, model='gompertz')\n    fit['condition'] = condition\n    results.append(fit)\n    print(f\"{condition}: mu_max={fit['mu_max']['value']:.3f} h⁻¹, \"\n          f\"lag={fit['lag']['value']:.1f} h, K={fit['K']['value']:.3f}\")\n```\n\n### Workflow 2: Simulate 3-Species Lotka-Volterra Community\n\n```python\nimport numpy as np\nfrom scipy.integrate import solve_ivp\n\nr = np.array([0.5, 0.4, 0.3])\nK = np.array([1000, 800, 600])\nalpha = np.array([[1.0, 0.5, 0.1], [0.3, 1.0, 0.4], [0.2, 0.6, 1.0]])\nN0 = [10, 10, 10]\n\nsol = solve_ivp(lotka_volterra, [0, 200], N0, args=(r, K, alpha),\n                t_eval=np.linspace(0, 200, 1000), method='RK45')\n\nfor i in range(3):\n    print(f\"Species {i+1}: equilibrium = {sol.y[i, -1]:.0f}\")\n```\n\n### Workflow 3: Annotate Bacterial Genome and Extract Statistics\n\n```python\nprefix = run_prokka('assembly.fasta', 'prokka_output', genus='Escherichia', species='coli')\ngenes_df = parse_prokka_gff(f'{prefix}.gff')\nprint(f\"\\nCDS count: {len(genes_df[genes_df['type'] == 'CDS'])}\")\nprint(f\"tRNA count: {len(genes_df[genes_df['type'] == 'tRNA'])}\")\nprint(f\"rRNA count: {len(genes_df[genes_df['type'] == 'rRNA'])}\")\n```\n\n## Best Practices\n\n1. **Growth curve replicates** — fit each replicate individually, then report mean ± SEM of parameters; do not average curves before fitting\n2. **Model selection** — compare logistic, Gompertz, and Baranyi by AIC\u002FBIC; Baranyi is most mechanistically justified but needs more data points during lag phase\n3. **Gillespie SSA** — run sufficient ensemble size (>100 trajectories) for reliable statistics; check that propensities remain finite\n4. **CFU statistics** — count plates with 30-300 colonies only; below 30 is unreliable, above 300 is too dense\n5. **Biofilm normalization** — normalize to planktonic growth (OD600) to distinguish biofilm-specific effects from growth differences\n6. **ODE integration** — use `RK45` for non-stiff systems, `BDF` or `Radau` for stiff systems (common in multi-species models)\n\n## Troubleshooting\n\n**Problem:** Growth curve fit fails to converge\n**Solution:** Adjust initial parameter guesses closer to expected values. Increase `maxfev`. Check that data has sufficient points during lag and exponential phases.\n\n**Problem:** Lotka-Volterra simulation diverges\n**Solution:** Reduce step size or use adaptive solver. Check that interaction matrix doesn't produce negative populations — use `events` parameter in `solve_ivp` to stop at zero.\n\n**Problem:** Gillespie SSA runs too slowly\n**Solution:** For large populations (>10000), switch to tau-leaping approximation. Or use ODE mean-field approximation and add noise analytically.\n\n**Problem:** Prokka fails with \"no genes found\"\n**Solution:** Check FASTA file is properly formatted (no extra whitespace). Verify sequences are bacterial. Use `--kingdom Bacteria` flag explicitly.\n\n## Resources\n\n- [Baranyi Growth Model Paper](https:\u002F\u002Fdoi.org\u002F10.1016\u002F0168-1605(94)90157-0)\n- [Prokka Documentation](https:\u002F\u002Fgithub.com\u002Ftseemann\u002Fprokka)\n- [scipy.integrate.solve_ivp](https:\u002F\u002Fdocs.scipy.org\u002Fdoc\u002Fscipy\u002Freference\u002Fgenerated\u002Fscipy.integrate.solve_ivp.html)\n- [Gillespie Algorithm Tutorial](https:\u002F\u002Fdoi.org\u002F10.1146\u002Fannurev.physchem.58.032806.104637)\n","# Microbial Dynamics: Population Dynamics & Modeling\n\n## Overview\n\nMicrobial Dynamics provides computational tools for modeling and analyzing microbial populations. This skill covers bacterial growth curve fitting using standard models (logistic, Gompertz, Baranyi), multi-species community dynamics via Lotka-Volterra equations, stochastic population simulation using the Gillespie algorithm, biofilm quantification from crystal violet assays, colony-forming unit enumeration with statistical analysis, bacterial genome annotation via Prokka, and simplified anaerobic digestion modeling.\n\n## When to Use This Skill\n\n- Fitting bacterial growth curves from OD600 time-series data\n- Extracting growth parameters: lag phase duration, maximum growth rate (mu_max), carrying capacity (K)\n- Modeling multi-species microbial community interactions\n- Running stochastic simulations of gene expression or population dynamics\n- Processing crystal violet biofilm assay data\n- Calculating CFU\u002FmL from serial dilution plating\n- Annotating bacterial genomes and extracting gene statistics\n- Modeling biogas production from anaerobic digestion\n\n**Related Skills:** For constraint-based metabolic modeling use `cobrapy`. For sequence manipulation and BLAST use `biopython`. For statistical analysis use `statistical-analysis`.\n\n## Installation\n\n```bash\nuv pip install scipy numpy pandas matplotlib\n```\n\nFor genome annotation (optional):\n```bash\n# conda install -c bioconda prokka\n```\n\n## Quick Start\n\n```python\nfrom scipy.optimize import curve_fit\nimport numpy as np\n\n# Logistic growth model\ndef logistic(t, y0, K, r, lag):\n    return K \u002F (1 + ((K - y0) \u002F y0) * np.exp(-r * (t - lag)))\n\n# Example OD600 data\ntime = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24])\nod600 = np.array([0.02, 0.02, 0.03, 0.06, 0.15, 0.38, 0.72, 1.05, 1.25, 1.42, 1.48, 1.50, 1.51, 1.51, 1.52])\n\npopt, pcov = curve_fit(logistic, time, od600, p0=[0.02, 1.5, 0.5, 2.0], maxfev=10000)\nprint(f\"y0={popt[0]:.4f}, K={popt[1]:.3f}, r={popt[2]:.3f} h^-1, lag={popt[3]:.2f} h\")\n```\n\n## Core Capabilities\n\n### 1. Growth Curve Modeling\n\nFit OD600 data to standard microbial growth models.\n\n```python\nimport numpy as np\nfrom scipy.optimize import curve_fit\n\ndef logistic(t, y0, K, r, lag):\n    \"\"\"Logistic growth model.\"\"\"\n    return K \u002F (1 + ((K - y0) \u002F y0) * np.exp(-r * (t - lag)))\n\ndef gompertz(t, y0, K, mu_max, lag):\n    \"\"\"Modified Gompertz growth model.\"\"\"\n    return y0 + (K - y0) * np.exp(-np.exp((mu_max * np.e \u002F (K - y0)) * (lag - t) + 1))\n\ndef baranyi(t, y0, K, mu_max, lag):\n    \"\"\"Baranyi growth model.\"\"\"\n    A_t = t + (1 \u002F mu_max) * np.log(np.exp(-mu_max * t) +\n           np.exp(-mu_max * lag) - np.exp(-mu_max * (t + lag)))\n    return K - np.log(1 + (np.exp(K) - np.exp(y0)) \u002F np.exp(y0) * np.exp(-mu_max * A_t))\n\ndef fit_growth_curve(time, od600, model='logistic'):\n    \"\"\"Fit growth curve to OD data and return parameters.\"\"\"\n    models = {'logistic': logistic, 'gompertz': gompertz, 'baranyi': baranyi}\n    func = models[model]\n\n    # Initial guesses\n    y0_guess = od600[0]\n    K_guess = od600.max()\n    r_guess = 0.5\n    lag_guess = time[np.argmax(np.gradient(od600))] - 1\n\n    p0 = [y0_guess, K_guess, r_guess, max(lag_guess, 0)]\n    bounds = ([0, 0, 0, 0], [np.inf, np.inf, 10, time.max()])\n\n    popt, pcov = curve_fit(func, time, od600, p0=p0, bounds=bounds, maxfev=10000)\n    perr = np.sqrt(np.diag(pcov))\n\n    # R-squared\n    residuals = od600 - func(time, *popt)\n    ss_res = np.sum(residuals**2)\n    ss_tot = np.sum((od600 - np.mean(od600))**2)\n    r_squared = 1 - (ss_res \u002F ss_tot)\n\n    param_names = ['y0', 'K', 'mu_max', 'lag']\n    result = {name: {'value': val, 'std': err}\n              for name, val, err in zip(param_names, popt, perr)}\n    result['r_squared'] = r_squared\n    result['model'] = model\n\n    return result, popt\n\n# Compare models\nfor model_name in ['logistic', 'gompertz', 'baranyi']:\n    try:\n        result, _ = fit_growth_curve(time, od600, model=model_name)\n        print(f\"{model_name}: R²={result['r_squared']:.4f}, \"\n              f\"mu_max={result['mu_max']['value']:.3f} ± {result['mu_max']['std']:.3f} h⁻¹, \"\n              f\"lag={result['lag']['value']:.2f} h\")\n    except RuntimeError:\n        print(f\"{model_name}: fitting failed\")\n```\n\n### 2. Lotka-Volterra Community Dynamics\n\nSimulate multi-species interactions.\n\n```python\nimport numpy as np\nfrom scipy.integrate import solve_ivp\n\ndef lotka_volterra(t, N, r, K, alpha):\n    \"\"\"Generalized Lotka-Volterra for n species.\n\n    Args:\n        N: array of population sizes\n        r: array of intrinsic growth rates\n        K: array of carrying capacities\n        alpha: interaction matrix (alpha[i,j] = effect of j on i)\n    \"\"\"\n    n = len(N)\n    dNdt = np.zeros(n)\n    for i in range(n):\n        interaction = sum(alpha[i, j] * N[j] for j in range(n))\n        dNdt[i] = r[i] * N[i] * (1 - interaction \u002F K[i])\n    return dNdt\n\n# 3-species community\nr = np.array([0.5, 0.4, 0.3])      # Growth rates\nK = np.array([1000, 800, 600])       # Carrying capacities\nalpha = np.array([                    # Interaction matrix\n    [1.0, 0.5, 0.1],   # Species 1: self + competition from 2 and 3\n    [0.3, 1.0, 0.4],   # Species 2\n    [0.2, 0.6, 1.0],   # Species 3\n])\nN0 = np.array([10, 10, 10])  # Initial populations\n\nsol = solve_ivp(\n    lotka_volterra, [0, 100], N0,\n    args=(r, K, alpha),\n    t_eval=np.linspace(0, 100, 500),\n    method='RK45'\n)\n\nprint(\"Final populations:\")\nfor i in range(3):\n    print(f\"  Species {i+1}: {sol.y[i, -1]:.1f}\")\n\n# Stability analysis: check if coexistence is stable\nA = np.diag(1\u002FK) @ alpha\ntry:\n    eigenvalues = np.linalg.eigvals(A)\n    stable = all(ev.real > 0 for ev in eigenvalues)\n    print(f\"Coexistence equilibrium is {'stable' if stable else 'unstable'}\")\nexcept np.linalg.LinAlgError:\n    print(\"Stability analysis failed\")\n```\n\n### 3. Stochastic Population Simulation\n\nGillespie SSA for exact stochastic simulation.\n\n```python\nimport numpy as np\n\ndef gillespie_ssa(propensity_func, stoich_matrix, x0, t_end, max_steps=100000):\n    \"\"\"Gillespie Stochastic Simulation Algorithm.\n\n    Args:\n        propensity_func: function(x) -> array of reaction propensities\n        stoich_matrix: reactions x species stoichiometry matrix\n        x0: initial state vector\n        t_end: simulation end time\n    \"\"\"\n    t = 0\n    x = np.array(x0, dtype=float)\n    times = [t]\n    states = [x.copy()]\n\n    for step in range(max_steps):\n        props = propensity_func(x)\n        total_prop = np.sum(props)\n\n        if total_prop == 0 or t >= t_end:\n            break\n\n        # Time to next reaction\n        dt = np.random.exponential(1 \u002F total_prop)\n        t += dt\n\n        if t > t_end:\n            break\n\n        # Choose reaction\n        reaction = np.searchsorted(np.cumsum(props), np.random.uniform(0, total_prop))\n        reaction = min(reaction, len(props) - 1)\n\n        # Update state\n        x += stoich_matrix[reaction]\n        x = np.clip(x, 0, None)\n\n        times.append(t)\n        states.append(x.copy())\n\n    return np.array(times), np.array(states)\n\n# Birth-death-immigration model\ndef propensities(x):\n    N = x[0]\n    birth_rate = 0.5 * N\n    death_rate = 0.01 * N * (N - 1)  # Density-dependent death\n    immigration = 5.0\n    return np.array([birth_rate, death_rate, immigration])\n\nstoich = np.array([[1], [-1], [1]])  # Birth: +1, Death: -1, Immigration: +1\n\n# Run ensemble\nn_runs = 50\nresults = []\nfor i in range(n_runs):\n    times, states = gillespie_ssa(propensities, stoich, [10], t_end=50)\n    results.append((times, states))\n\n# Summary statistics\nfinal_pops = [states[-1, 0] for _, states in results]\nprint(f\"Mean final population: {np.mean(final_pops):.1f} ± {np.std(final_pops):.1f}\")\n```\n\n### 4. Biofilm Quantification\n\nProcess crystal violet biofilm assay data.\n\n```python\nimport numpy as np\nimport pandas as pd\n\ndef analyze_biofilm_cv(od_data, blank_od=0.05, conditions=None):\n    \"\"\"Analyze crystal violet biofilm assay.\n\n    Args:\n        od_data: dict of condition -> list of OD570 replicates\n        blank_od: blank well OD for background subtraction\n    \"\"\"\n    results = []\n    for condition, replicates in od_data.items():\n        corrected = np.array(replicates) - blank_od\n        corrected = np.clip(corrected, 0, None)\n        results.append({\n            'condition': condition,\n            'mean_od': np.mean(corrected),\n            'std_od': np.std(corrected, ddof=1),\n            'n': len(corrected),\n            'sem': np.std(corrected, ddof=1) \u002F np.sqrt(len(corrected))\n        })\n\n    df = pd.DataFrame(results)\n    # Normalize to control\n    control_mean = df.iloc[0]['mean_od']\n    df['fold_change'] = df['mean_od'] \u002F control_mean\n    return df\n\n# Example: biofilm inhibition dose-response\nod_data = {\n    'Control': [0.85, 0.92, 0.88, 0.90],\n    '1 uM': [0.80, 0.78, 0.82, 0.79],\n    '10 uM': [0.55, 0.52, 0.58, 0.50],\n    '100 uM': [0.20, 0.18, 0.22, 0.19],\n}\n\ndf = analyze_biofilm_cv(od_data)\nprint(df[['condition', 'mean_od', 'std_od', 'fold_change']])\n```\n\n### 5. CFU Enumeration\n\nCalculate colony-forming units from serial dilution plating.\n\n```python\nimport numpy as np\nfrom scipy import stats\n\ndef calculate_cfu(counts, dilution_factor, volume_plated_ml=0.1):\n    \"\"\"Calculate CFU\u002FmL from plate counts.\n\n    Args:\n        counts: list of colony counts per plate\n        dilution_factor: dilution used (e.g., 1e-6 for 10^-6)\n        volume_plated_ml: volume plated in mL\n    \"\"\"\n    counts = np.array(counts)\n    cfu_per_ml = counts \u002F (dilution_factor * volume_plated_ml)\n\n    mean_cfu = np.mean(cfu_per_ml)\n    std_cfu = np.std(cfu_per_ml, ddof=1)\n    sem = std_cfu \u002F np.sqrt(len(counts))\n\n    # 95% confidence interval\n    ci = stats.t.interval(0.95, df=len(counts)-1, loc=mean_cfu, scale=sem)\n\n    return {\n        'mean_cfu_per_ml': mean_cfu,\n        'std': std_cfu,\n        'sem': sem,\n        'ci_95': ci,\n        'n': len(counts),\n        'log10_cfu': np.log10(mean_cfu)\n    }\n\n# Example\nresult = calculate_cfu(counts=[42, 38, 45], dilution_factor=1e-6, volume_plated_ml=0.1)\nprint(f\"CFU\u002FmL: {result['mean_cfu_per_ml']:.2e}\")\nprint(f\"Log10 CFU\u002FmL: {result['log10_cfu']:.2f}\")\nprint(f\"95% CI: ({result['ci_95'][0]:.2e}, {result['ci_95'][1]:.2e})\")\n```\n\n### 6. Bacterial Genome Annotation\n\nRun Prokka and parse results.\n\n```python\nimport subprocess\nimport pandas as pd\n\ndef run_prokka(fasta_path, output_dir, prefix='genome', genus=None, species=None):\n    \"\"\"Annotate bacterial genome with Prokka.\"\"\"\n    cmd = [\n        'prokka', fasta_path,\n        '--outdir', output_dir,\n        '--prefix', prefix,\n        '--cpus', '4',\n        '--force'\n    ]\n    if genus:\n        cmd.extend(['--genus', genus])\n    if species:\n        cmd.extend(['--species', species])\n\n    result = subprocess.run(cmd, capture_output=True, text=True)\n    if result.returncode != 0:\n        raise RuntimeError(f\"Prokka failed: {result.stderr}\")\n    return f'{output_dir}\u002F{prefix}'\n\ndef parse_prokka_gff(gff_path):\n    \"\"\"Parse Prokka GFF3 output to extract gene statistics.\"\"\"\n    genes = []\n    with open(gff_path) as f:\n        for line in f:\n            if line.startswith('#') or line.startswith('>'):\n                continue\n            if '\\t' not in line:\n                continue\n            parts = line.strip().split('\\t')\n            if len(parts) \u003C 9:\n                continue\n\n            feature_type = parts[2]\n            if feature_type in ('CDS', 'tRNA', 'rRNA', 'tmRNA'):\n                attrs = dict(kv.split('=', 1) for kv in parts[8].split(';') if '=' in kv)\n                genes.append({\n                    'type': feature_type,\n                    'start': int(parts[3]),\n                    'end': int(parts[4]),\n                    'strand': parts[6],\n                    'gene': attrs.get('gene', ''),\n                    'product': attrs.get('product', ''),\n                    'length': int(parts[4]) - int(parts[3]) + 1\n                })\n\n    df = pd.DataFrame(genes)\n    print(f\"Total features: {len(df)}\")\n    print(f\"Feature types:\\n{df['type'].value_counts()}\")\n    print(f\"Mean CDS length: {df[df['type']=='CDS']['length'].mean():.0f} bp\")\n\n    # Coding density\n    total_coding = df[df['type'] == 'CDS']['length'].sum()\n    genome_size = df['end'].max()\n    coding_density = 100 * total_coding \u002F genome_size\n    print(f\"Coding density: {coding_density:.1f}%\")\n\n    return df\n```\n\n### 7. Anaerobic Digestion Modeling\n\nSimplified ADM1 for biogas prediction.\n\n```python\nimport numpy as np\nfrom scipy.integrate import solve_ivp\n\ndef adm1_simplified(t, y, params):\n    \"\"\"Simplified anaerobic digestion model.\n    State: [S_substrate, X_acidogens, X_methanogens, S_VFA, CH4]\n    \"\"\"\n    S, Xa, Xm, VFA, CH4 = y\n    k_hyd = params['k_hyd']       # Hydrolysis rate\n    mu_a = params['mu_a']         # Acidogen max growth rate\n    Ks_a = params['Ks_a']         # Acidogen half-saturation\n    mu_m = params['mu_m']         # Methanogen max growth rate\n    Ks_m = params['Ks_m']         # Methanogen half-saturation\n    Y_a = params['Y_a']           # Acidogen yield\n    Y_m = params['Y_m']           # Methanogen yield\n    kd = params['kd']             # Decay rate\n    Ki = params['Ki']             # VFA inhibition constant\n\n    # Hydrolysis\n    r_hyd = k_hyd * S\n\n    # Acidogenesis (Monod kinetics)\n    r_acid = mu_a * (S \u002F (Ks_a + S)) * Xa\n\n    # Methanogenesis (Monod with VFA inhibition)\n    inhibition = Ki \u002F (Ki + VFA)\n    r_meth = mu_m * (VFA \u002F (Ks_m + VFA)) * Xm * inhibition\n\n    dSdt = -r_hyd - r_acid \u002F Y_a\n    dXa = Y_a * r_acid - kd * Xa\n    dXm = Y_m * r_meth - kd * Xm\n    dVFA = r_acid - r_meth \u002F Y_m\n    dCH4 = r_meth\n\n    return [dSdt, dXa, dXm, dVFA, dCH4]\n\nparams = {\n    'k_hyd': 0.25, 'mu_a': 0.5, 'Ks_a': 200,\n    'mu_m': 0.2, 'Ks_m': 50, 'Y_a': 0.1,\n    'Y_m': 0.05, 'kd': 0.02, 'Ki': 3000\n}\n\ny0 = [5000, 100, 50, 100, 0]  # Initial conditions\nsol = solve_ivp(adm1_simplified, [0, 60], y0, args=(params,),\n                t_eval=np.linspace(0, 60, 300), method='RK45')\n\nprint(f\"Final substrate: {sol.y[0, -1]:.0f} mg\u002FL\")\nprint(f\"Total CH4 produced: {sol.y[4, -1]:.0f} mg\u002FL\")\n```\n\n## Typical Workflows\n\n### Workflow 1: Fit Growth Curves and Compare Conditions\n\n```python\nimport pandas as pd\nimport numpy as np\n\n# Load multi-condition OD600 data\ndata = pd.read_csv('growth_data.csv')  # columns: time, condition, od600\n\nresults = []\nfor condition, group in data.groupby('condition'):\n    time = group['time'].values\n    od = group['od600'].values\n    fit, popt = fit_growth_curve(time, od, model='gompertz')\n    fit['condition'] = condition\n    results.append(fit)\n    print(f\"{condition}: mu_max={fit['mu_max']['value']:.3f} h⁻¹, \"\n          f\"lag={fit['lag']['value']:.1f} h, K={fit['K']['value']:.3f}\")\n```\n\n### Workflow 2: Simulate 3-Species Lotka-Volterra Community\n\n```python\nimport numpy as np\nfrom scipy.integrate import solve_ivp\n\nr = np.array([0.5, 0.4, 0.3])\nK = np.array([1000, 800, 600])\nalpha = np.array([[1.0, 0.5, 0.1], [0.3, 1.0, 0.4], [0.2, 0.6, 1.0]])\nN0 = [10, 10, 10]\n\nsol = solve_ivp(lotka_volterra, [0, 200], N0, args=(r, K, alpha),\n                t_eval=np.linspace(0, 200, 1000), method='RK45')\n\nfor i in range(3):\n    print(f\"Species {i+1}: equilibrium = {sol.y[i, -1]:.0f}\")\n```\n\n### Workflow 3: Annotate Bacterial Genome and Extract Statistics\n\n```python\nprefix = run_prokka('assembly.fasta', 'prokka_output', genus='Escherichia', species='coli')\ngenes_df = parse_prokka_gff(f'{prefix}.gff')\nprint(f\"\\nCDS count: {len(genes_df[genes_df['type'] == 'CDS'])}\")\nprint(f\"tRNA count: {len(genes_df[genes_df['type'] == 'tRNA'])}\")\nprint(f\"rRNA count: {len(genes_df[genes_df['type'] == 'rRNA'])}\")\n```\n\n## Best Practices\n\n1. **Growth curve replicates** — fit each replicate individually, then report mean ± SEM of parameters; do not average curves before fitting\n2. **Model selection** — compare logistic, Gompertz, and Baranyi by AIC\u002FBIC; Baranyi is most mechanistically justified but needs more data points during lag phase\n3. **Gillespie SSA** — run sufficient ensemble size (>100 trajectories) for reliable statistics; check that propensities remain finite\n4. **CFU statistics** — count plates with 30-300 colonies only; below 30 is unreliable, above 300 is too dense\n5. **Biofilm normalization** — normalize to planktonic growth (OD600) to distinguish biofilm-specific effects from growth differences\n6. **ODE integration** — use `RK45` for non-stiff systems, `BDF` or `Radau` for stiff systems (common in multi-species models)\n\n## Troubleshooting\n\n**Problem:** Growth curve fit fails to converge\n**Solution:** Adjust initial parameter guesses closer to expected values. Increase `maxfev`. Check that data has sufficient points during lag and exponential phases.\n\n**Problem:** Lotka-Volterra simulation diverges\n**Solution:** Reduce step size or use adaptive solver. Check that interaction matrix doesn't produce negative populations — use `events` parameter in `solve_ivp` to stop at zero.\n\n**Problem:** Gillespie SSA runs too slowly\n**Solution:** For large populations (>10000), switch to tau-leaping approximation. Or use ODE mean-field approximation and add noise analytically.\n\n**Problem:** Prokka fails with \"no genes found\"\n**Solution:** Check FASTA file is properly formatted (no extra whitespace). Verify sequences are bacterial. Use `--kingdom Bacteria` flag explicitly.\n\n## Resources\n\n- [Baranyi Growth Model Paper](https:\u002F\u002Fdoi.org\u002F10.1016\u002F0168-1605(94)90157-0)\n- [Prokka Documentation](https:\u002F\u002Fgithub.com\u002Ftseemann\u002Fprokka)\n- [scipy.integrate.solve_ivp](https:\u002F\u002Fdocs.scipy.org\u002Fdoc\u002Fscipy\u002Freference\u002Fgenerated\u002Fscipy.integrate.solve_ivp.html)\n- [Gillespie Algorithm Tutorial](https:\u002F\u002Fdoi.org\u002F10.1146\u002Fannurev.physchem.58.032806.104637)\n",{"name":5,"license":44,"category":26,"metadata":45,"description":7},"MIT license",{"skill-author":46},"InkVell Inc.","main","4aa39efd1cdab0b4657ecee16c92a92011a5b10f","openscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub","https:\u002F\u002Fgithub.com\u002Ffadrienne","2026-10-28 00:43:09",{"source":8,"skillName":5,"commands":54,"prompt":64,"zipAvailable":65},[55,58,61],{"tool":56,"command":57},"npx","npx skills add fadrienne\u002FMyGitHub --skill microbial-dynamics",{"tool":59,"command":60},"bunx","bunx skills add fadrienne\u002FMyGitHub --skill microbial-dynamics",{"tool":62,"command":63},"pnpm","pnpm dlx skills add fadrienne\u002FMyGitHub --skill microbial-dynamics","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002FSKILL.md",true,[67,73,77,81,85],{"path":68,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":71,"sourceHtmlUrl":72},"scripts\u002Fbiofilm_assay.py","SCRIPT","脚本",9633,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002Fscripts\u002Fbiofilm_assay.py",{"path":74,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":75,"sourceHtmlUrl":76},"scripts\u002Fcfu_calculator.py",12970,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002Fscripts\u002Fcfu_calculator.py",{"path":78,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":79,"sourceHtmlUrl":80},"scripts\u002Fcolony_counter.py",11124,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002Fscripts\u002Fcolony_counter.py",{"path":82,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":83,"sourceHtmlUrl":84},"scripts\u002Fgrowth_curve.py",11758,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002Fscripts\u002Fgrowth_curve.py",{"path":86,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":87,"sourceHtmlUrl":88},"scripts\u002Flotka_volterra.py",11303,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmicrobial-dynamics\u002Fscripts\u002Flotka_volterra.py",[90,120,145,179,206,233],{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":101,"publishedAt":39},"01M7167B28PK20HP7R7ZED2DY0","statistical-power","Sample size calculation, power analysis, and effect size conversion for scientific studies. Use BEFORE data collection (a priori) to determine required N, or after (post-hoc) to compute achieved power. Covers parametric tests (t-test, ANOVA, chi-square, proportions, correlation, regression), simulation-based power for complex\u002Fclustered\u002Fnested designs, and power curves. Use this skill when someone asks 'how many samples do I need', 'what is my power', 'what effect size can I detect', or any variant. Pairs with \u002Fexperimental-design (choose design first, then compute power) and \u002Fstatistical-analysis (analyze data after collection).","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fstatistical-power\u002FSKILL.md",[96],{"categoryNo":97,"categoryName":98,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[102,103,104,105,106,107,108,109,110,111,112,36,113,114,115,116,117,118,35,119],"power","statistical power","effect","scipy","regression","choose","design","uv","when","Bash","collection","calculation","ANOVA","conversion","analyze","t-test","chi-square","sample",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":129,"publishedAt":39},"01M71677EBCM8EPCE9BZCK8505","statistical-analysis","Guided statistical analysis with test selection and reporting. Use when you need help choosing appropriate tests for your data, assumption checking, power analysis, and APA-formatted results. Best for academic research reporting, test selection guidance. For implementing specific models programmatically use statsmodels.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fstatistical-analysis\u002FSKILL.md",[126],{"categoryNo":127,"categoryName":128,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000008","测试与质量",[36,130,102,131,132,133,110,134,135,136,25,137,33,138,139,140,141,142,143,144],"statistical analysis","academic research","implementing","selection","you","reporting","data","tests","with","test","research","results","statsmodels","models","help",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":160,"publishedAt":39},"01M71673R93XAHFH81DBNVNG7H","scientific-writing","Core skill for the deep research and writing tool. Write scientific manuscripts in full paragraphs (never bullet points). Use two-stage process with (1) section outlines with key points using research-lookup then (2) convert to flowing prose. IMRAD structure, citations (APA\u002FAMA\u002FVancouver), figures\u002Ftables, reporting guidelines (CONSORT\u002FSTROBE\u002FPRISMA), for research papers and journal submissions.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fscientific-writing\u002FSKILL.md",[151,154,155],{"categoryNo":152,"categoryName":153,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":97,"categoryName":98,"taxonomyType":99,"taxonomyTypeDesc":100},{"categoryNo":156,"categoryName":157,"taxonomyType":158,"taxonomyTypeDesc":159},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[161,162,163,164,165,166,167,168,169,170,111,171,172,173,174,175,176,177,135,178],"writing","scientific","scientific writing","Citations","deep","deep research","never","papers","journal","false","api","prisma","structure","openrouter","Outlines","core skill","read","features",{"skillNo":180,"name":181,"nameZh":6,"description":182,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":183,"categories":184,"keywords":189,"publishedAt":39},"01M7166ZPKXBF4EBPHVTJPQBB1","scientific-visualization","Meta-skill for publication-ready figures. Use when creating journal submission figures requiring multi-panel layouts, significance annotations, error bars, colorblind-safe palettes, and specific journal formatting (Nature, Science, Cell). Orchestrates matplotlib\u002Fseaborn\u002Fplotly with publication styles. For quick exploration use seaborn or plotly directly.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fscientific-visualization\u002FSKILL.md",[185,188],{"categoryNo":186,"categoryName":187,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":97,"categoryName":98,"taxonomyType":99,"taxonomyTypeDesc":100},[190,162,191,192,193,194,195,196,197,169,110,198,199,200,201,202,203,204,25,205],"visualization","scientific visualization","error","ready","quick","exploration","meta-skill","Meta","safe","plotly","annotations","formatting","Publication","figures","panel","submission",{"skillNo":207,"name":208,"nameZh":6,"description":209,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":210,"categories":211,"keywords":218,"publishedAt":39},"01M7166VXJWQSSC3RQZP60WBGR","research-code","Debug, profile, review, and restructure Python research and analysis code. Use when analysis scripts crash, produce wrong results, run too slowly, or need a correctness review. Covers: reading tracebacks and diagnosing root causes, hypothesis-driven debugging, reviewing code for common statistical\u002Fnumerical errors, profiling data pipelines, improving reproducibility (seeds, environments, determinism), and structuring analysis scripts for sharing. Distinct from \u002Fexploratory-data-analysis (which understands data) and \u002Fstatistical-analysis (which chooses and runs tests) — this skill focuses on the code itself.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fresearch-code\u002FSKILL.md",[212,215],{"categoryNo":213,"categoryName":214,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":216,"categoryName":217,"taxonomyType":158,"taxonomyTypeDesc":159},"01JBSEEDCAT000000000000030","开发工程师",[219,220,140,221,222,223,224,109,225,110,111,36,226,227,228,229,230,231,177,232],"code","research code","which","memory","data-analysis","errors","debugging","common","review","data pipelines","run","scripts","line","write",{"skillNo":234,"name":235,"nameZh":6,"description":236,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":237,"licenseFileUrl":6,"sourceHtmlUrl":238,"categories":239,"keywords":246,"publishedAt":39},"01M7166CF5HSR7SVZYZFWTDX55","markdown-mermaid-writing","Comprehensive markdown and Mermaid diagram writing skill. Use when creating any scientific document, report, analysis, or visualization. Establishes text-based diagrams as the default documentation standard with full style guides (markdown + mermaid), 24 diagram type references, and 9 document templates.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fmarkdown-mermaid-writing\u002FSKILL.md",[240,243,244,245],{"categoryNo":241,"categoryName":242,"taxonomyType":99,"taxonomyTypeDesc":100},"01JBSEEDCAT000000000000002","文档处理",{"categoryNo":152,"categoryName":153,"taxonomyType":99,"taxonomyTypeDesc":100},{"categoryNo":97,"categoryName":98,"taxonomyType":99,"taxonomyTypeDesc":100},{"categoryNo":156,"categoryName":157,"taxonomyType":158,"taxonomyTypeDesc":159},[161,247,248,249,32,250,190,251,252,110,111,36,253,254,255,256,257,258,162,177],"markdown mermaid writing","mermaid","markdown","diagrams","project","default","team","guides","text","documentation","references","diagram"]