Cell type vulnerability in Alzheimer's Disease (SEA-AD data - v2)¶
Notebook ID: nb-SDA-2026-04-03-gap-seaad-v2-20260402032945 · Analysis: SDA-2026-04-03-gap-seaad-v2-20260402032945 · Generated: 2026-04-17
Research question¶
What cell types are most vulnerable in Alzheimer's Disease based on SEA-AD transcriptomic data from the Allen Brain Cell Atlas? Identify mechanisms of cell-type-specific vulnerability in neurons, microglia, astrocytes, and oligodendrocytes. Focus on gene expression patterns, pathway dysregulation, and therapeutic implications.
Approach¶
This notebook is generated programmatically from real Forge tool calls and SciDEX debate data. Code cells load cached evidence bundles from data/forge_cache/seaad/*.json and query live data from scidex.db. Re-run python3 scripts/regenerate_notebooks.py --analysis SDA-2026-04-03-gap-seaad-v2-20260402032945 --force to refresh.
7 hypotheses were generated and debated. The knowledge graph has 75 edges.
Debate Summary¶
Quality score: 0.95 · Rounds: 4 · Personas: Theorist, Skeptic, Domain_Expert, Synthesizer
1. Forge tool provenance¶
import json, sys, sqlite3
from pathlib import Path
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
matplotlib.rcParams['figure.dpi'] = 110
matplotlib.rcParams['figure.facecolor'] = 'white'
REPO = Path('.').resolve()
sys.path.insert(0, str(REPO))
CACHE_SUB = 'seaad'
CACHE = REPO / 'data' / 'forge_cache' / CACHE_SUB
def load(name):
p = CACHE / f'{name}.json'
if p.exists():
return json.loads(p.read_text())
return {}
db_path = Path('/home/ubuntu/scidex/scidex.db')
try:
db = sqlite3.connect(str(db_path))
prov = pd.read_sql_query('''
SELECT skill_id, status, COUNT(*) AS n_calls,
ROUND(AVG(duration_ms),0) AS mean_ms
FROM tool_calls
WHERE created_at >= date('now','-30 days')
GROUP BY skill_id, status
ORDER BY n_calls DESC
''', db)
db.close()
prov['tool'] = prov['skill_id'].str.replace('tool_', '', regex=False)
print(f'{len(prov)} tool-call aggregates (last 30 days):')
prov[['tool','status','n_calls','mean_ms']].head(20)
except Exception as e:
print(f'Provenance unavailable: {e}')
181 tool-call aggregates (last 30 days):
2. Target gene annotations¶
ann_rows = []
for g in ['AND', 'APOE', 'COMPLEX']:
mg = load(f'mygene_{g}')
hpa = load(f'hpa_{g}')
if not mg and not hpa:
ann_rows.append({'gene': g, 'name': '—', 'protein_class': '—',
'disease_involvement': '—'})
continue
ann_rows.append({
'gene': g,
'name': (mg.get('name') or '')[:55],
'protein_class': ', '.join((hpa.get('protein_class') or [])[:2])[:55]
if isinstance(hpa.get('protein_class'), list)
else str(hpa.get('protein_class') or '—')[:55],
'disease_involvement': ', '.join((hpa.get('disease_involvement') or [])[:2])[:55]
if isinstance(hpa.get('disease_involvement'), list)
else str(hpa.get('disease_involvement') or '')[:55],
})
pd.DataFrame(ann_rows)
| gene | name | protein_class | disease_involvement | |
|---|---|---|---|---|
| 0 | AND | — | — | — |
| 1 | APOE | apolipoprotein E | Cancer-related genes, Candidate cardiovascular... | Alzheimer disease, Amyloidosis |
| 2 | COMPLEX | — | — | — |
3. GO Biological Process enrichment (Enrichr)¶
go_bp = load('enrichr_GO_Biological_Process')
if isinstance(go_bp, list) and go_bp:
go_df = pd.DataFrame(go_bp[:10])[['term','p_value','odds_ratio','genes']]
go_df['p_value'] = go_df['p_value'].apply(lambda p: f'{p:.2e}')
go_df['odds_ratio'] = go_df['odds_ratio'].round(1)
go_df['term'] = go_df['term'].str[:60]
go_df['n_hits'] = go_df['genes'].apply(len)
go_df['genes'] = go_df['genes'].apply(lambda g: ', '.join(g))
go_df[['term','n_hits','p_value','odds_ratio','genes']]
else:
print('No GO:BP enrichment data')
# Visualize top GO BP enrichment
go_bp = load('enrichr_GO_Biological_Process')
if isinstance(go_bp, list) and go_bp:
top = go_bp[:8]
terms = [t['term'][:45] for t in top][::-1]
neglogp = [-np.log10(max(t['p_value'], 1e-300)) for t in top][::-1]
fig, ax = plt.subplots(figsize=(9, 4.5))
ax.barh(terms, neglogp, color='#4fc3f7')
ax.set_xlabel('-log10(p-value)')
ax.set_title('Top GO:BP enrichment (Enrichr)')
ax.grid(axis='x', alpha=0.3)
plt.tight_layout(); plt.show()
else:
print('No GO:BP data to plot')
4. KEGG pathway enrichment¶
kegg = load('enrichr_KEGG_Pathways')
if isinstance(kegg, list) and kegg:
kegg_df = pd.DataFrame(kegg[:10])[['term','p_value','odds_ratio','genes']]
kegg_df['genes'] = kegg_df['genes'].apply(lambda g: ', '.join(g))
kegg_df['p_value'] = kegg_df['p_value'].apply(lambda p: f'{p:.2e}')
kegg_df['odds_ratio'] = kegg_df['odds_ratio'].round(1)
kegg_df
else:
print('No KEGG enrichment data')
No KEGG enrichment data
5. STRING protein interaction network¶
ppi = load('string_network')
if isinstance(ppi, list) and ppi:
ppi_df = pd.DataFrame(ppi).sort_values('score', ascending=False)
display_cols = [c for c in ['protein1','protein2','score','escore','tscore'] if c in ppi_df.columns]
print(f'{len(ppi_df)} STRING edges')
ppi_df[display_cols].head(20)
else:
print('No STRING edges returned')
11 STRING edges
# Network figure
ppi = load('string_network')
if isinstance(ppi, list) and ppi:
import math
nodes = sorted({p for e in ppi for p in (e['protein1'], e['protein2'])})
n = len(nodes)
pos = {n_: (math.cos(2*math.pi*i/n), math.sin(2*math.pi*i/n)) for i, n_ in enumerate(nodes)}
fig, ax = plt.subplots(figsize=(7, 7))
for e in ppi:
x1,y1 = pos[e['protein1']]; x2,y2 = pos[e['protein2']]
ax.plot([x1,x2],[y1,y2], color='#888', alpha=0.3+0.5*e['score'],
linewidth=0.5+2*e['score'])
for name,(x,y) in pos.items():
ax.scatter([x],[y], s=450, color='#ffd54f', edgecolors='#333', zorder=3)
ax.annotate(name, (x,y), ha='center', va='center', fontsize=8, fontweight='bold', zorder=4)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title(f'STRING PPI network ({len(ppi)} edges)')
plt.tight_layout(); plt.show()
else:
print('No STRING data to visualize')
6. Reactome pathway footprint¶
pw_rows = []
for g in ['AND', 'APOE', 'COMPLEX']:
pws = load(f'reactome_{g}')
if isinstance(pws, list):
pw_rows.append({'gene': g, 'n_pathways': len(pws),
'top_pathway': (pws[0]['name'] if pws else '—')[:70]})
else:
pw_rows.append({'gene': g, 'n_pathways': 0, 'top_pathway': '—'})
pd.DataFrame(pw_rows).sort_values('n_pathways', ascending=False)
| gene | n_pathways | top_pathway | |
|---|---|---|---|
| 1 | APOE | 8 | Nuclear signaling by ERBB4 |
| 0 | AND | 0 | — |
| 2 | COMPLEX | 0 | — |
7. Allen Brain Atlas ISH regional expression¶
ish_rows = []
for g in ['AND', 'APOE', 'COMPLEX']:
ish = load(f'allen_ish_{g}')
regions = ish.get('regions') or [] if isinstance(ish, dict) else []
ish_rows.append({
'gene': g,
'n_ish_regions': len(regions),
'top_region': (regions[0].get('structure','') if regions else '—')[:45],
'top_energy': round(regions[0].get('expression_energy',0), 2) if regions else None,
})
pd.DataFrame(ish_rows)
| gene | n_ish_regions | top_region | top_energy | |
|---|---|---|---|---|
| 0 | AND | 0 | — | — |
| 1 | APOE | 0 | — | — |
| 2 | COMPLEX | 0 | — | — |
8. Hypothesis ranking (7 hypotheses)¶
hyp_data = [('Microglial TREM2-Complement Axis Modulation', 0.726), ('Oligodendrocyte DNA Repair Enhancement Therapy', 0.665), ('Astrocyte Metabolic Reprogramming via APOE4 Correction', 0.636), ('BMP4 Pathway Inhibition for Oligodendrocyte Myelination', 0.62), ('Cross-Cell Type Synaptic Rescue via Tripartite Synapse ', 0.62), ('Neuronal Integrated Stress Response Modulation', 0.618), ('Spatial Transcriptome-Guided Precision Cell Therapy', 0.578)]
titles = [h[0] for h in hyp_data][::-1]
scores = [h[1] for h in hyp_data][::-1]
fig, ax = plt.subplots(figsize=(10, max(8, len(titles)*0.4)))
colors = ['#ef5350' if s >= 0.6 else '#ffa726' if s >= 0.5 else '#66bb6a' for s in scores]
ax.barh(range(len(titles)), scores, color=colors)
ax.set_yticks(range(len(titles))); ax.set_yticklabels(titles, fontsize=7)
ax.set_xlabel('Composite Score'); ax.set_title("Cell type vulnerability in Alzheimer's Disease (SEA-AD data - v2)")
ax.grid(axis='x', alpha=0.3)
plt.tight_layout(); plt.show()
9. Score dimension heatmap (top 10)¶
labels = ['Microglial TREM2-Complement Axis Modulat', 'Oligodendrocyte DNA Repair Enhancement T', 'Astrocyte Metabolic Reprogramming via AP', 'BMP4 Pathway Inhibition for Oligodendroc', 'Cross-Cell Type Synaptic Rescue via Trip', 'Neuronal Integrated Stress Response Modu', 'Spatial Transcriptome-Guided Precision C']
matrix = np.array([[0.75, 0.9, 0.85, 0.85, 0, 0.85, 0.8, 0.95, 0.75], [0.8, 0.7, 0.65, 0.6, 0, 0.6, 0.65, 0.75, 0.45], [0.95, 0.25, 0.85, 0.75, 0, 0.65, 0.4, 0.3, 0.3], [0.85, 0.6, 0.6, 0.65, 0, 0.45, 0.55, 0.8, 0.5], [0.9, 0.4, 0.8, 0.75, 0, 0.7, 0.6, 0.45, 0.55], [0.75, 0.55, 0.65, 0.7, 0, 0.55, 0.6, 0.65, 0.5], [0.95, 0.2, 0.7, 0.6, 0, 0.6, 0.3, 0.25, 0.35]])
dims = ['novelty_score', 'feasibility_score', 'impact_score', 'mechanistic_plausibility_score', 'clinical_relevance_score', 'data_availability_score', 'reproducibility_score', 'druggability_score', 'safety_profile_score']
if matrix.size:
fig, ax = plt.subplots(figsize=(10, 5))
im = ax.imshow(matrix, cmap='RdYlGn', aspect='auto', vmin=0, vmax=1)
ax.set_xticks(range(len(dims)))
ax.set_xticklabels([d.replace('_score','').replace('_',' ').title() for d in dims],
rotation=45, ha='right', fontsize=8)
ax.set_yticks(range(len(labels))); ax.set_yticklabels(labels, fontsize=7)
ax.set_title('Score dimensions — top hypotheses')
plt.colorbar(im, ax=ax, shrink=0.8)
plt.tight_layout(); plt.show()
else:
print('No score data available')
10. PubMed evidence per hypothesis¶
Hypothesis 1: Microglial TREM2-Complement Axis Modulation¶
Target genes: TREM2 and C3 · Composite score: 0.726
Molecular Mechanism¶
The microglial TREM2-complement axis represents a fundamental regulatory network controlling neuroinflammation and synaptic homeostasis in neurodegenerative diseases. TREM2 (Triggering Receptor Expressed on Myeloid cells 2) is a type I transmembrane glycoprotein exclusively expressed on microglia within the central nervous system, functioning as a critical immunoreceptor that orchestrates microglial activation, survival, and phagocytic responses. The extracellular immunog
hid = 'h-3616325a'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 2: Oligodendrocyte DNA Repair Enhancement Therapy¶
Target genes: PARP1 and XRCC1 · Composite score: 0.665
Molecular Mechanism and Rationale¶
The oligodendrocyte DNA repair enhancement therapy is predicated on emerging evidence that white matter pathology, particularly oligodendrocyte dysfunction, represents an early and potentially causative event in Alzheimer's disease neurodegeneration. Oligodendrocytes exhibit heightened vulnerability to oxidative stress due to their high metabolic demands for myelin production and maintenance, coupled with relatively low antioxidant capacity. This vulnerabili
hid = 'h-fa7ac9cb'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 3: Astrocyte Metabolic Reprogramming via APOE4 Correction¶
Target genes: APOE · Composite score: 0.636
Molecular Mechanism and Rationale¶
The APOE4 variant disrupts astrocyte-specific metabolic pathways through altered lipid trafficking and cholesterol homeostasis, fundamentally impairing the astrocytes' ability to support neuronal function. Unlike APOE3, the APOE4 protein exhibits domain interaction between its N-terminal and C-terminal regions due to the Arg112 and Arg158 substitutions, creating a more compact molecular structure that reduces lipid binding affinity and alters receptor intera
hid = 'h-d8f2bbc9'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 4: BMP4 Pathway Inhibition for Oligodendrocyte Myelination Support¶
Target genes: BMP4 and BMPR1A · Composite score: 0.62
Molecular Mechanism and Rationale¶
The bone morphogenetic protein 4 (BMP4) pathway represents a critical regulatory mechanism in cerebrovascular homeostasis and white matter integrity. Under physiological conditions, BMP4 signaling through its cognate receptor BMPR1A maintains appropriate oligodendrocyte differentiation and myelin production. However, chronic cerebral hypoperfusion fundamentally disrupts this delicate equilibrium through a cascade of pathological events initiated at the neuro
hid = 'h-e064f134'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 5: Cross-Cell Type Synaptic Rescue via Tripartite Synapse Restoration¶
Target genes: SYN1, SLC1A2, and CX3CR1 · Composite score: 0.62
Molecular Mechanism and Rationale¶
The Cross-Cell Type Synaptic Rescue hypothesis addresses Alzheimer's disease through coordinated restoration of tripartite synapse function, targeting the synchronized dysfunction that occurs between neurons, astrocytes, and microglia. At the neuronal level, synapsin-1 (SYN1) serves as the primary regulator of synaptic vesicle clustering and neurotransmitter release. Enhanced SYN1 expression promotes presynaptic vesicle availability and facilitates activity-
hid = 'h-019c56c1'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 6: Neuronal Integrated Stress Response Modulation¶
Target genes: EIF2AK3 (PERK) and EIF2B complex · Composite score: 0.618
Molecular Mechanism and Rationale¶
The integrated stress response (ISR) represents a critical cellular surveillance mechanism that monitors protein folding homeostasis through four upstream kinases: EIF2AK3 (PERK), PKR, GCN2, and HRI. Under proteotoxic stress conditions characteristic of neurodegenerative diseases, PERK undergoes oligomerization and autophosphorylation within the endoplasmic reticulum lumen, subsequently phosphorylating the α-subunit of eukaryotic initiation factor 2 (eIF2α)
hid = 'h-5137be61'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
Hypothesis 7: Spatial Transcriptome-Guided Precision Cell Therapy¶
Target genes: SOX10 and DLX1/2 · Composite score: 0.578
Molecular Mechanism and Rationale¶
The Spatial Transcriptome-Guided Precision Cell Therapy hypothesis leverages region-specific transcriptomic vulnerabilities by targeting SOX10-mediated oligodendrogenesis in the middle temporal gyrus and DLX1/2-regulated GABAergic interneuron development in the entorhinal cortex. SOX10, a master transcription factor for oligodendrocyte lineage commitment, regulates myelin basic protein expression and oligodendrocyte precursor cell (OPC) differentiation throu
hid = 'h-0bdc3803'
papers = load(f'pubmed_{hid}')
if isinstance(papers, list) and papers:
lit = pd.DataFrame(papers)
cols = [c for c in ['year','journal','title','pmid'] if c in lit.columns]
if cols:
lit = lit[cols]
lit['title'] = lit['title'].str[:80]
if 'journal' in lit.columns:
lit['journal'] = lit['journal'].str[:30]
lit.sort_values('year', ascending=False, inplace=True)
display_df = lit
else:
display_df = pd.DataFrame(papers[:5])
else:
display_df = pd.DataFrame([{'note':'no PubMed results'}])
display_df
| note | |
|---|---|
| 0 | no PubMed results |
11. Knowledge graph edges (75 total)¶
edge_data = [{'source': 'TREM2 dysregulation', 'relation': 'causes (disease-associate', 'target': 'microglial dysfunction', 'strength': 0.8}, {'source': 'h-3616325a', 'relation': 'targets', 'target': 'TREM2', 'strength': 0.8}, {'source': 'h-3616325a', 'relation': 'targets', 'target': 'C3', 'strength': 0.8}, {'source': 'h-3616325a', 'relation': 'implicated_in', 'target': 'neurodegeneration', 'strength': 0.8}, {'source': 'complement activation', 'relation': 'causes (excessive complem', 'target': 'synapse elimination', 'strength': 0.75}, {'source': 'DNA damage', 'relation': 'causes (DNA damage in oli', 'target': 'oligodendrocyte degeneration', 'strength': 0.75}, {'source': 'TREM2 enhancement', 'relation': 'causes (enhancing TREM2 e', 'target': 'tau pathology reduction', 'strength': 0.75}, {'source': 'APOE4', 'relation': 'causes (APOE4 disrupts li', 'target': 'astrocyte dysfunction', 'strength': 0.72}, {'source': 'oligodendrocyte degeneration', 'relation': 'causes (oligodendrocyte d', 'target': 'myelin breakdown', 'strength': 0.7}, {'source': 'APOE4', 'relation': 'causes (APOE4 mediates my', 'target': 'myelin breakdown', 'strength': 0.7}, {'source': 'PARP1 activation', 'relation': 'causes (PARP1 activation ', 'target': 'DNA repair enhancement', 'strength': 0.7}, {'source': 'tripartite synapse dysfunction', 'relation': 'causes (coordinated dysfu', 'target': 'synaptic failure', 'strength': 0.7}, {'source': 'h-d8f2bbc9', 'relation': 'targets', 'target': 'APOE', 'strength': 0.7}, {'source': 'h-d8f2bbc9', 'relation': 'implicated_in', 'target': 'neurodegeneration', 'strength': 0.7}, {'source': 'integrated stress response dys', 'relation': 'causes (dysregulated ISR ', 'target': 'protein synthesis shutdown', 'strength': 0.68}, {'source': 'chronic hypoperfusion', 'relation': 'causes (chronic hypoperfu', 'target': 'BMP4 release', 'strength': 0.65}, {'source': 'BMP4', 'relation': 'causes (pericyte-derived ', 'target': 'white matter damage', 'strength': 0.65}, {'source': 'h-019c56c1', 'relation': 'targets', 'target': 'SYN1', 'strength': 0.65}, {'source': 'h-019c56c1', 'relation': 'targets', 'target': 'SLC1A2', 'strength': 0.65}, {'source': 'h-019c56c1', 'relation': 'targets', 'target': 'CX3CR1', 'strength': 0.65}, {'source': 'h-019c56c1', 'relation': 'implicated_in', 'target': 'neurodegeneration', 'strength': 0.65}, {'source': 'h-5137be61', 'relation': 'targets', 'target': 'EIF2AK3 (PERK)', 'strength': 0.6}, {'source': 'h-5137be61', 'relation': 'targets', 'target': 'EIF2B complex', 'strength': 0.6}, {'source': 'h-5137be61', 'relation': 'implicated_in', 'target': 'neurodegeneration', 'strength': 0.6}, {'source': 'h-fa7ac9cb', 'relation': 'targets', 'target': 'PARP1', 'strength': 0.55}]
if edge_data:
pd.DataFrame(edge_data).head(25)
else:
print('No KG edge data available')
12. Caveats¶
This notebook uses real Forge tool calls cached from live APIs, but:
- Enrichment is against curated gene-set libraries, not genome-wide screens
- STRING/Reactome/HPA/MyGene reflect curated knowledge
- PubMed literature is search-relevance ranked, not systematic review
The cached evidence bundle is the minimum viable real-data analysis for this topic.