-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Jupyter Widgets
Jupyter Widgets is a system for providing interactive JavaScript controls for objects in a Jupyter kernel.
Here are some helpful resources about Jupyter widgets and where they are supported. These unofficial lists are maintained by the community at large in hopes they will be helpful. Listing here does not imply endorsement by Project Jupyter. These lists are certainly not comprehensive. Feel free to edit this page to include or update relevant information.
Beyond the basic form controls (sliders, checkboxes, text inputs, date/color pickers, etc.) and containers (tabs, horizontal/vertical boxes, grids) provided by the core ipywidgets project, there are many projects providing custom interactive widgets. Here we list a few. In addition to the projects below, you may also find custom Jupyter Widgets in the jupyter-widgets GitHub topic.
| Name | Language | Description |
|---|---|---|
| bqplot | Python | Python plotting library using d3js |
| clustergrammer2 | Python | "Dimensionality-increasing" data visualization tool and interactive WebGL Jupyter widget built for single-cell data. |
| glue-jupyter | Python | Glue front-end for multi-dimensional linked-data exploration |
| idom-jupyter | Python | A client for IDOM |
| ipycanvas | Python | An HTML Canvas Widget for displaying and interacting with 2d graphics |
| ipycytoscape | Python | Visualize node-edge graphs with Cytoscape |
| ipydagred3 | Python | drawing directed acyclic graphs using dagre-d3 |
| ipydatagrid | Python | Fast Datagrid widget |
| ipydatawidgets | Python | A set of widgets to help facilitate reuse of large datasets across widgets |
| ipydatetime | Python | Date/time pickers for ipywidgets 7 only (these widgets are included in ipywidgets 8 core widgets) |
| ipyevents | Python | Capture and interact with DOM Events in Python |
| ipyfilechooser | Python | A file browser widget yielding the path and filename of the chosen file |
| ipyflex | Python | WYSIWYG layout editor for Jupyter Widgets |
| ipygany | Python | Scientific Visualization in Jupyter |
| ipyleaflet | Python | Geographic maps using leaflet |
| ipymaterialui | Python | Jupyter Widgets based on React Material UI components |
| ipympl | Python | The Maptlotlib interactive backend |
| ipyregulartable | Python | High performance, editable, stylable datagrids |
| ipysegment | Python | manual image segmentation |
| ipysheet | Python | Jupyter handsontable integration |
| ipytone | Python | Interactive Audio in Jupyter |
| ipytree | Python | A Tree Widget using jsTree |
| ipyvolume | Python | 3D plotting in Jupyter |
| ipyvue | Python | Jupyter widgets base for Vue libraries |
| ipyvuetify | Python | Jupyter widgets based on vuetify UI components which implement Google's Material Design Spec with the Vue.js framework |
| ipywebrtc | Python | Create and record/stream a variety of media streams, such as videos, images, your own webcam, etc. |
| itkwidgets | Python | Visualize images, point sets, and meshes in 2D and 3D |
| jdaviz | Python | Astronomical data analysis visualization tools |
| jupyter_bokeh | Python | An extension for rendering Bokeh content in JupyterLab notebooks |
| jupyter-innotater | Python | Annotate data including image bounding boxes inline |
| jupyter-jsmol | Python | A JSmol viewer widget for 3d chemical structures |
| jupyter-scatter | Python | Interactive 2D scatter plot widget scaling to millions of points |
| kepler.gl | Python | Geospatial analysis tool for large-scale data sets. |
| lineup_widget | Python | Create, visualize and explore rankings of items based on a set of heterogeneous attributes using LineUp.js |
| mito | Python | A spreadsheet that generates Pandas code for every edit |
| mpl-interactions | Python | Helpful ways to interact with Matplotlib plots. |
| panel | Python | A high-level app and dashboarding solution for Python |
| psplay | Python | Interactive power spectrum code |
| pythreejs | Python | 3D library using three.js |
| pyvipr | Python | dynamic and static visualizations of systems biology models written in PySB, BNGL, and SBML |
| pywwt | Python | Python interface to the AAS WorldWide Telescope |
| qsl | Python | A quick and simple tool for labeling images, videos and time series data. |
| react-ipywidgets | Python | A way to write reusable components in a React-like way, to make Python-based UI's using the ipywidgets ecosystem (ipywidgets, ipyvolume, bqplot, threejs, leaflet, ipyvuetify, ...) |
| trident-chemwidgets | Python | Interact with molecular datasets |
| VegaFusion | Python | Serverside acceleration for the Vega visualization grammar |
| widget-periodictable | Python | Select chemical elements from the periodic table. |
| xcanvas | C++ | A Canvas Widget |
| xwidgets | C++ | The C++ counterpart for ipywidgets |
| fastplotlib | Python | A fast plotting library built using the pygfx render engine utilizing Vulkan via WGPU |
| pygfx | Python | A python render engine targeting Vulkan/Metal/DX12. |
| wgpu | Python | A Python implementation of WebGPU - the next generation GPU API. |
| jupyter_rfb | Python | Remote Frame Buffer for Jupyter |
| Name | Package to install | Core widget support | Custom widget support | Examples | Notes |
|---|---|---|---|---|---|
| JupyterLab |
jupyterlab-widgets (ipywidgets installs this automatically) |
✅ | ✅ | ||
| Jupyter Notebook |
widgetsnbextension (ipywidgets installs this automatically) |
✅ | ✅ | ||
| JupyterLite | none | ✅ | ✅ | Examples | |
| VS Code | none | ✅ | ✅ | ||
| Google Colab | none | ✅ | ✅ | Example | |
| CoCalc | none | ✅ | partial | ||
| Databricks | none | ✅ | partial | Examples | |
| JetBrains Datalore | none | ✅ | none |
| Name | Language | Package to install | Core widget support | Custom widget support | Examples | Notes |
|---|---|---|---|---|---|---|
| IPython/ipykernel | Python | ipywidgets |
✅ | ✅ | ||
| xeus-python | Python | ipywidgets |
✅ | ✅ | ||
| xeus-cling | C++ | xwidgets |
✅ | ✅ |
print("helloposiabhg")
import os, numpy as np, time, shutil, subprocess, math, glob
CONFIG = { "LX": 60.0, "LY": 60.0, "LZ": 80.0, "PORE_RADIUS": 8.0, "TEMP": 300.0, "WALL_EPSILON": 0.07, "WALL_SIGMA": 3.55, "STEPS_EQ": 50000, "STEPS_PROD": 5000000, "RESTART_FREQ": 500000, "THERMO_FREQ": 5000, "DUMP_FREQ": 100000, "BASE_SEED": 12345, "OMP_NUM_THREADS": 4, "MEMBRANE_GAP": 10.0, "MIN_CC": 1.42, "MIN_OO": 2.80, "MIN_OC": 2.80, "MIN_HX": 1.50, "CELL_SIZE": 3.0, "MAX_FAIL": 800, "TARGET_WATER": 1200, "REPLICA": 1 }
WORK_DIR = "/kaggle/working/Nanopore_5pores" LOCAL_DIR = "/kaggle/working/sim" os.makedirs(WORK_DIR, exist_ok=True) os.makedirs(LOCAL_DIR, exist_ok=True) os.environ['OMP_NUM_THREADS'] = str(CONFIG['OMP_NUM_THREADS'])
def setup_lammps(): lmp_path = "/kaggle/working/lammps-static/bin/lmp" if not os.path.exists(lmp_path): print("📥 تحميل LAMMPS Static Binary...") subprocess.run([ "wget", "-q", "-O", "/kaggle/working/lammps.tar.gz", "https://download.lammps.org/static/lammps-linux-x86_64-30Mar2026.tar.gz" ], check=True) subprocess.run([ "tar", "-xzf", "/kaggle/working/lammps.tar.gz", "-C", "/kaggle/working/" ], check=True) os.chmod(lmp_path, 0o755) result = subprocess.run([lmp_path, "-h"], capture_output=True, text=True) if "LAMMPS" in result.stdout: print("✅ LAMMPS يعمل – يمكنك إيقاف نوت الـ CPU الآن") else: print("❌ فشل LAMMPS") print(result.stderr[:300]) raise RuntimeError("LAMMPS لم يعمل") return lmp_path
class NeighborGrid2D: def init(self, Lx, Ly, cs): self.Lx, self.Ly, self.cs = Lx, Ly, cs self.nx = max(1, int(Lx/cs)) self.ny = max(1, int(Ly/cs)) self.cells = {} def _idx(self, x, y): return (int((x % self.Lx) / self.Lx * self.nx) % self.nx, int((y % self.Ly) / self.Ly * self.ny) % self.ny) def insert(self, x, y): self.cells.setdefault(self._idx(x, y), []).append((x, y)) def any_within(self, x, y, cutoff): c2 = cutoff * cutoff ix0, iy0 = self._idx(x, y) for di in (-1, 0, 1): for dj in (-1, 0, 1): for (ax, ay) in self.cells.get(((ix0+di) % self.nx, (iy0+dj) % self.ny), []): dx = x - ax; dy = y - ay dx -= self.Lx * round(dx / self.Lx) dy -= self.Ly * round(dy / self.Ly) if dxdx + dydy < c2: return True return False
class NeighborGrid3D: def init(self, Lx, Ly, Lz, cs): self.Lx, self.Ly, self.Lz, self.cs = Lx, Ly, Lz, cs self.nx = max(1, int(Lx/cs)) self.ny = max(1, int(Ly/cs)) self.nz = max(1, int(Lz/cs)) self.cells = {} def _idx(self, x, y, z): return (int((x % self.Lx) / self.Lx * self.nx) % self.nx, int((y % self.Ly) / self.Ly * self.ny) % self.ny, int(((z + self.Lz0.5) / self.Lz) * self.nz) % self.nz) def insert(self, x, y, z): self.cells.setdefault(self._idx(x, y, z), []).append((x, y, z)) def any_within(self, x, y, z, cutoff): c2 = cutoff * cutoff ix0, iy0, iz0 = self._idx(x, y, z) for di in (-1, 0, 1): for dj in (-1, 0, 1): for dk in (-1, 0, 1): for (ax, ay, az) in self.cells.get(((ix0+di) % self.nx, (iy0+dj) % self.ny, (iz0+dk) % self.nz), []): dx = x-ax; dy = y-ay; dz = z-az dx -= self.Lxround(dx/self.Lx) dy -= self.Lyround(dy/self.Ly) dz -= self.Lzround(dz/self.Lz) if dxdx+dydy+dz*dz < c2: return True return False
class Builder: def init(self, cfg): self.cfg = cfg def graphene_pore(self): a, r, hg = 2.46, self.cfg['PORE_RADIUS'], self.cfg['MEMBRANE_GAP']/2.0 centers = [np.array([15,15]), np.array([15,45]), np.array([45,15]), np.array([45,45]), np.array([30,30])] atoms, grid = [], NeighborGrid2D(self.cfg['LX'], self.cfg['LY'], self.cfg['CELL_SIZE']) nx = int(self.cfg['LX']/a)+2 ny = int(self.cfg['LY']/(anp.sqrt(3)/2))+2 for i in range(-1, nx): for j in range(-1, ny): xA = ia+(j%2)a/2 yA = ja*np.sqrt(3)/2 for (x, y) in [(xA, yA), (xA, yA+a/2)]: x %= self.cfg['LX']; y %= self.cfg['LY'] if any(np.linalg.norm([x,y]-c) < r for c in centers): continue if grid.any_within(x, y, self.cfg['MIN_CC']): continue grid.insert(x, y) atoms.append((x, y, hg, 3)) atoms.append((x, y, -hg, 3)) print(f" ✅ كربون: {len(atoms)} ذرة") return atoms
def pack_water(self, carbon, seed):
rng = np.random.RandomState(seed)
Lx, Ly, Lz = self.cfg['LX'], self.cfg['LY'], self.cfg['LZ']
hg = self.cfg['MEMBRANE_GAP']/2.0
grid = NeighborGrid3D(Lx, Ly, Lz, self.cfg['CELL_SIZE'])
for (cx, cy, cz, _) in carbon:
grid.insert(cx, cy, cz)
O, H1, H2 = [], [], []
added, fail = 0, 0
target = self.cfg['TARGET_WATER']
while fail < self.cfg['MAX_FAIL'] and added < target:
zlo, zhi = (hg+2.5, Lz/2-1.5) if rng.randint(2)==0 else (-Lz/2+1.5, -hg-2.5)
ox = rng.rand()*Lx; oy = rng.rand()*Ly; oz = rng.uniform(zlo, zhi)
if grid.any_within(ox, oy, oz, self.cfg['MIN_OC']): fail+=1; continue
d = rng.randn(3); d /= max(np.linalg.norm(d), 1e-10)
perp = np.cross(d, [0,0,1])
if np.linalg.norm(perp) < 1e-6: perp = np.cross(d, [1,0,0])
perp /= np.linalg.norm(perp)
R_OH, th = 0.9572, 109.47*math.pi/180.0
h1 = (ox+R_OH*d[0], oy+R_OH*d[1], oz+R_OH*d[2])
h2d = math.cos(th)*d+math.sin(th)*perp
h2 = (ox+R_OH*h2d[0], oy+R_OH*h2d[1], oz+R_OH*h2d[2])
if (grid.any_within(h1[0],h1[1],h1[2],self.cfg['MIN_HX']) or
grid.any_within(h2[0],h2[1],h2[2],self.cfg['MIN_HX'])): fail+=1; continue
grid.insert(ox,oy,oz); grid.insert(*h1); grid.insert(*h2)
O.append((ox,oy,oz)); H1.append(h1); H2.append(h2)
added+=1; fail=0
if added%200==0: print(f" 💧 {added}/{target}")
print(f" 🎉 {len(O)} جزيء ماء")
return O, H1, H2
class Guardian: def init(self, cfg): self.cfg = cfg def validate(self, carbon, O, H1, H2): Lx, Ly, Lz = self.cfg['LX'], self.cfg['LY'], self.cfg['LZ'] cs, hg = self.cfg['CELL_SIZE'], self.cfg['MEMBRANE_GAP']/2.0 for z in (hg, -hg): g2 = NeighborGrid2D(Lx, Ly, cs) for (cx, cy, cz, _) in carbon: if abs(cz-z) > 0.1: continue if g2.any_within(cx, cy, self.cfg['MIN_CC']): print("❌ تداخل C-C"); return False g2.insert(cx, cy) gc3 = NeighborGrid3D(Lx, Ly, Lz, cs) for (cx, cy, cz, _) in carbon: gc3.insert(cx, cy, cz) for (ox, oy, oz) in O: if gc3.any_within(ox, oy, oz, self.cfg['MIN_OC']): print("❌ تداخل O-C"); return False go = NeighborGrid3D(Lx, Ly, Lz, cs) for (ox, oy, oz) in O: if go.any_within(ox, oy, oz, self.cfg['MIN_OO']): print("❌ تداخل O-O"); return False go.insert(ox, oy, oz) print(" ✅ النظام آمن"); return True
def write_data(self, carbon, O, H1, H2, fname):
nw, nc = len(O), len(carbon)
Lx, Ly, Lz = self.cfg['LX'], self.cfg['LY'], self.cfg['LZ']
with open(fname, 'w') as f:
f.write(f"Nanopore 5pores\n{nw*3+nc} atoms\n{nw*2} bonds\n{nw} angles\n")
f.write("3 atom types\n1 bond types\n1 angle types\n\n")
f.write(f"0.0 {Lx:.6f} xlo xhi\n0.0 {Ly:.6f} ylo yhi\n")
f.write(f"{-Lz/2:.6f} {Lz/2:.6f} zlo zhi\n\nMasses\n\n1 15.9994\n2 1.00794\n3 12.01\n\nAtoms\n\n")
aid = 1
for i in range(nw):
o, h1, h2 = O[i], H1[i], H2[i]
f.write(f"{aid} {i+1} 1 -0.8476 {o[0]:.4f} {o[1]:.4f} {o[2]:.4f}\n"); aid+=1
f.write(f"{aid} {i+1} 2 0.4238 {h1[0]:.4f} {h1[1]:.4f} {h1[2]:.4f}\n"); aid+=1
f.write(f"{aid} {i+1} 2 0.4238 {h2[0]:.4f} {h2[1]:.4f} {h2[2]:.4f}\n"); aid+=1
for (cx, cy, cz, _) in carbon:
f.write(f"{aid} {nw+1} 3 0.0 {cx:.4f} {cy:.4f} {cz:.4f}\n"); aid+=1
f.write("\nBonds\n\n")
for i in range(nw):
b = i*3+1
f.write(f"{i*2+1} 1 {b} {b+1}\n{i*2+2} 1 {b} {b+2}\n")
f.write("\nAngles\n\n")
for i in range(nw):
b = i*3+1
f.write(f"{i+1} 1 {b+1} {b} {b+2}\n")
def find_latest_restart(case_dir):
files = glob.glob(os.path.join(case_dir, "restart.A")) +
glob.glob(os.path.join(case_dir, "restart.B"))
return max(files, key=os.path.getmtime) if files else None
def write_lammps_input(data_path, restart_path, cfg, case_dir): in_file = os.path.join(LOCAL_DIR, "run.in") use_restart = restart_path and os.path.exists(restart_path) with open(in_file, 'w') as f: if use_restart: f.write(f"read_restart {restart_path}\n") f.write("pair_style lj/cut/coul/long 10.0\n") f.write("kspace_style pppm 1.0e-4\n") f.write("pair_modify mix arithmetic\n") f.write("group water type 1 2\n") f.write("group carbon type 3\n") f.write("fix freeze carbon setforce 0.0 0.0 0.0\n") f.write("fix shake_pr water shake 0.0001 20 0 b 1 a 1\n") f.write(f"fix nvt_pr water nvt temp {cfg['TEMP']} {cfg['TEMP']} 500.0\n") f.write("timestep 2.0\n") else: f.write(f"""units real atom_style full boundary p p p read_data {data_path}
pair_style lj/cut/coul/long 10.0 pair_coeff 1 1 0.1553 3.166 pair_coeff 2 2 0.0 0.0 pair_coeff 3 3 {cfg['WALL_EPSILON']} {cfg['WALL_SIGMA']} pair_coeff 1 3 0.104 3.36 pair_modify mix arithmetic
bond_style harmonic bond_coeff 1 1000.0 1.0 angle_style harmonic angle_coeff 1 100.0 109.47 kspace_style pppm 1.0e-4
group water type 1 2 group carbon type 3 fix freeze carbon setforce 0.0 0.0 0.0
fix shake_eq water shake 0.0001 20 0 b 1 a 1 velocity water create {cfg['TEMP']} {cfg['BASE_SEED']} dist gaussian fix nvt_eq water nvt temp {cfg['TEMP']} {cfg['TEMP']} 500.0 timestep 1.0 thermo {cfg['THERMO_FREQ']} run {cfg['STEPS_EQ']} unfix nvt_eq unfix shake_eq
fix shake_pr water shake 0.0001 20 0 b 1 a 1 fix nvt_pr water nvt temp {cfg['TEMP']} {cfg['TEMP']} 500.0 timestep 2.0 """) f.write(f"thermo {cfg['THERMO_FREQ']}\n") f.write("thermo_style custom step temp press density etotal\n") f.write(f"dump mydump water custom {cfg['DUMP_FREQ']} {os.path.join(LOCAL_DIR,'traj.lammpstrj')} id type x y z\n") restart_A = os.path.join(case_dir, "restart.A") restart_B = os.path.join(case_dir, "restart.B") f.write(f"restart {cfg['RESTART_FREQ']} {restart_A} {restart_B}\n") f.write(f"run {cfg['STEPS_PROD']} upto\n") f.write(f"write_restart {os.path.join(case_dir,'final.restart')}\n") return in_file
cfg = CONFIG case_dir = os.path.join(WORK_DIR, f"pore5_r{cfg['REPLICA']}") os.makedirs(case_dir, exist_ok=True)
lmp = setup_lammps()
restart_to_use = find_latest_restart(case_dir) if restart_to_use: print(f"♻️ استئناف من: {restart_to_use}") inp_file = write_lammps_input(None, restart_to_use, cfg, case_dir) else: print("🆕 بناء نظام جديد...") builder = Builder(cfg) carbon = builder.graphene_pore() O, H1, H2 = builder.pack_water(carbon, cfg['BASE_SEED']) guard = Guardian(cfg) if not guard.validate(carbon, O, H1, H2): raise RuntimeError("❌ فشل فحص النظام") data_file = os.path.join(LOCAL_DIR, "data.5pores") guard.write_data(carbon, O, H1, H2, data_file) inp_file = write_lammps_input(data_file, None, cfg, case_dir)
log_path = os.path.join(LOCAL_DIR, "log.txt") print("🚀 تشغيل LAMMPS...") t0 = time.time()
with open(log_path, 'w') as log_f: proc = subprocess.Popen( [lmp, "-in", inp_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) for line in proc.stdout: print(line, end='', flush=True) log_f.write(line) proc.wait() ret = proc.returncode
dt = time.time() - t0 if ret != 0: print(f"❌ فشل LAMMPS بعد {dt:.0f} ثانية") else: print(f"✅ اكتملت في {dt/60:.1f} دقيقة") for fn in ["traj.lammpstrj", "log.txt"]: src = os.path.join(LOCAL_DIR, fn) dst = os.path.join(case_dir, fn) if os.path.exists(src): if os.path.exists(dst): os.remove(dst) shutil.move(src, dst) print(f"📁 النتائج: {case_dir}")# ============================================================
import os, numpy as np, time, shutil, subprocess, math, glob
CONFIG = { "LX": 60.0, "LY": 60.0, "LZ": 80.0, "PORE_RADIUS": 8.0, "TEMP": 300.0, "WALL_EPSILON": 0.07, "WALL_SIGMA": 3.55, "STEPS_EQ": 50000, "STEPS_PROD": 5000000, "RESTART_FREQ": 500000, "THERMO_FREQ": 5000, "DUMP_FREQ": 100000, "BASE_SEED": 12345, "OMP_NUM_THREADS": 4, "MEMBRANE_GAP": 10.0, "MIN_CC": 1.42, "MIN_OO": 2.80, "MIN_OC": 2.80, "MIN_HX": 1.50, "CELL_SIZE": 3.0, "MAX_FAIL": 800, "TARGET_WATER": 1200, "REPLICA": 1 }
WORK_DIR = "/kaggle/working/Nanopore_5pores" LOCAL_DIR = "/kaggle/working/sim" os.makedirs(WORK_DIR, exist_ok=True) os.makedirs(LOCAL_DIR, exist_ok=True) os.environ['OMP_NUM_THREADS'] = str(CONFIG['OMP_NUM_THREADS'])
def setup_lammps(): lmp_path = "/kaggle/working/lammps-static/bin/lmp" if not os.path.exists(lmp_path): print("📥 تحميل LAMMPS Static Binary...") subprocess.run([ "wget", "-q", "-O", "/kaggle/working/lammps.tar.gz", "https://download.lammps.org/static/lammps-linux-x86_64-30Mar2026.tar.gz" ], check=True) subprocess.run([ "tar", "-xzf", "/kaggle/working/lammps.tar.gz", "-C", "/kaggle/working/" ], check=True) os.chmod(lmp_path, 0o755) result = subprocess.run([lmp_path, "-h"], capture_output=True, text=True) if "LAMMPS" in result.stdout: print("✅ LAMMPS يعمل – يمكنك إيقاف نوت الـ CPU الآن") else: print("❌ فشل LAMMPS") print(result.stderr[:300]) raise RuntimeError("LAMMPS لم يعمل") return lmp_path
class NeighborGrid2D: def init(self, Lx, Ly, cs): self.Lx, self.Ly, self.cs = Lx, Ly, cs self.nx = max(1, int(Lx/cs)) self.ny = max(1, int(Ly/cs)) self.cells = {} def _idx(self, x, y): return (int((x % self.Lx) / self.Lx * self.nx) % self.nx, int((y % self.Ly) / self.Ly * self.ny) % self.ny) def insert(self, x, y): self.cells.setdefault(self._idx(x, y), []).append((x, y)) def any_within(self, x, y, cutoff): c2 = cutoff * cutoff ix0, iy0 = self._idx(x, y) for di in (-1, 0, 1): for dj in (-1, 0, 1): for (ax, ay) in self.cells.get(((ix0+di) % self.nx, (iy0+dj) % self.ny), []): dx = x - ax; dy = y - ay dx -= self.Lx * round(dx / self.Lx) dy -= self.Ly * round(dy / self.Ly) if dxdx + dydy < c2: return True return False
class NeighborGrid3D: def init(self, Lx, Ly, Lz, cs): self.Lx, self.Ly, self.Lz, self.cs = Lx, Ly, Lz, cs self.nx = max(1, int(Lx/cs)) self.ny = max(1, int(Ly/cs)) self.nz = max(1, int(Lz/cs)) self.cells = {} def _idx(self, x, y, z): return (int((x % self.Lx) / self.Lx * self.nx) % self.nx, int((y % self.Ly) / self.Ly * self.ny) % self.ny, int(((z + self.Lz0.5) / self.Lz) * self.nz) % self.nz) def insert(self, x, y, z): self.cells.setdefault(self._idx(x, y, z), []).append((x, y, z)) def any_within(self, x, y, z, cutoff): c2 = cutoff * cutoff ix0, iy0, iz0 = self._idx(x, y, z) for di in (-1, 0, 1): for dj in (-1, 0, 1): for dk in (-1, 0, 1): for (ax, ay, az) in self.cells.get(((ix0+di) % self.nx, (iy0+dj) % self.ny, (iz0+dk) % self.nz), []): dx = x-ax; dy = y-ay; dz = z-az dx -= self.Lxround(dx/self.Lx) dy -= self.Lyround(dy/self.Ly) dz -= self.Lzround(dz/self.Lz) if dxdx+dydy+dz*dz < c2: return True return False
class Builder: def init(self, cfg): self.cfg = cfg def graphene_pore(self): a, r, hg = 2.46, self.cfg['PORE_RADIUS'], self.cfg['MEMBRANE_GAP']/2.0 centers = [np.array([15,15]), np.array([15,45]), np.array([45,15]), np.array([45,45]), np.array([30,30])] atoms, grid = [], NeighborGrid2D(self.cfg['LX'], self.cfg['LY'], self.cfg['CELL_SIZE']) nx = int(self.cfg['LX']/a)+2 ny = int(self.cfg['LY']/(anp.sqrt(3)/2))+2 for i in range(-1, nx): for j in range(-1, ny): xA = ia+(j%2)a/2 yA = ja*np.sqrt(3)/2 for (x, y) in [(xA, yA), (xA, yA+a/2)]: x %= self.cfg['LX']; y %= self.cfg['LY'] if any(np.linalg.norm([x,y]-c) < r for c in centers): continue if grid.any_within(x, y, self.cfg['MIN_CC']): continue grid.insert(x, y) atoms.append((x, y, hg, 3)) atoms.append((x, y, -hg, 3)) print(f" ✅ كربون: {len(atoms)} ذرة") return atoms
def pack_water(self, carbon, seed):
rng = np.random.RandomState(seed)
Lx, Ly, Lz = self.cfg['LX'], self.cfg['LY'], self.cfg['LZ']
hg = self.cfg['MEMBRANE_GAP']/2.0
grid = NeighborGrid3D(Lx, Ly, Lz, self.cfg['CELL_SIZE'])
for (cx, cy, cz, _) in carbon:
grid.insert(cx, cy, cz)
O, H1, H2 = [], [], []
added, fail = 0, 0
target = self.cfg['TARGET_WATER']
while fail < self.cfg['MAX_FAIL'] and added < target:
zlo, zhi = (hg+2.5, Lz/2-1.5) if rng.randint(2)==0 else (-Lz/2+1.5, -hg-2.5)
ox = rng.rand()*Lx; oy = rng.rand()*Ly; oz = rng.uniform(zlo, zhi)
if grid.any_within(ox, oy, oz, self.cfg['MIN_OC']): fail+=1; continue
d = rng.randn(3); d /= max(np.linalg.norm(d), 1e-10)
perp = np.cross(d, [0,0,1])
if np.linalg.norm(perp) < 1e-6: perp = np.cross(d, [1,0,0])
perp /= np.linalg.norm(perp)
R_OH, th = 0.9572, 109.47*math.pi/180.0
h1 = (ox+R_OH*d[0], oy+R_OH*d[1], oz+R_OH*d[2])
h2d = math.cos(th)*d+math.sin(th)*perp
h2 = (ox+R_OH*h2d[0], oy+R_OH*h2d[1], oz+R_OH*h2d[2])
if (grid.any_within(h1[0],h1[1],h1[2],self.cfg['MIN_HX']) or
grid.any_within(h2[0],h2[1],h2[2],self.cfg['MIN_HX'])): fail+=1; continue
grid.insert(ox,oy,oz); grid.insert(*h1); grid.insert(*h2)
O.append((ox,oy,oz)); H1.append(h1); H2.append(h2)
added+=1; fail=0
if added%200==0: print(f" 💧 {added}/{target}")
print(f" 🎉 {len(O)} جزيء ماء")
return O, H1, H2
class Guardian: def init(self, cfg): self.cfg = cfg def validate(self, carbon, O, H1, H2): Lx, Ly, Lz = self.cfg['LX'], self.cfg['LY'], self.cfg['LZ'] cs, hg = self.cfg['CELL_SIZE'], self.cfg['MEMBRANE_GAP']/2.0 for z in (hg, -hg): g2 = NeighborGrid2D(Lx, Ly, cs) for (cx, cy, cz, _) in carbon: if abs(cz-z) > 0.1: continue if g2.any_within(cx, cy, self.cfg['MIN_CC']): print("❌ تداخل C-C"); return False g2.insert(cx, cy) gc3 = NeighborGrid3D(Lx, Ly, Lz, cs) for (cx, cy, cz, _) in carbon: gc3.insert(cx, cy, cz) for (ox, oy, oz) in O: if gc3.any_within(ox, oy, oz, self.cfg['MIN_OC']): print("❌ تداخل O-C"); return False go = NeighborGrid3D(Lx, Ly, Lz, cs) for (ox, oy, oz) in O: if go.any_within(ox, oy, oz, self.cfg['MIN_OO']): print("❌ تداخل O-O"); return False go.insert(ox, oy, oz) print(" ✅ النظام آمن"); return True
def write_data(self, carbon, O, H1, H2, fname):
nw, nc = len(O), len(carbon)
Lx, Ly, Lz = self.cfg['LX'], self.cfg['LY'], self.cfg['LZ']
with open(fname, 'w') as f:
f.write(f"Nanopore 5pores\n{nw*3+nc} atoms\n{nw*2} bonds\n{nw} angles\n")
f.write("3 atom types\n1 bond types\n1 angle types\n\n")
f.write(f"0.0 {Lx:.6f} xlo xhi\n0.0 {Ly:.6f} ylo yhi\n")
f.write(f"{-Lz/2:.6f} {Lz/2:.6f} zlo zhi\n\nMasses\n\n1 15.9994\n2 1.00794\n3 12.01\n\nAtoms\n\n")
aid = 1
for i in range(nw):
o, h1, h2 = O[i], H1[i], H2[i]
f.write(f"{aid} {i+1} 1 -0.8476 {o[0]:.4f} {o[1]:.4f} {o[2]:.4f}\n"); aid+=1
f.write(f"{aid} {i+1} 2 0.4238 {h1[0]:.4f} {h1[1]:.4f} {h1[2]:.4f}\n"); aid+=1
f.write(f"{aid} {i+1} 2 0.4238 {h2[0]:.4f} {h2[1]:.4f} {h2[2]:.4f}\n"); aid+=1
for (cx, cy, cz, _) in carbon:
f.write(f"{aid} {nw+1} 3 0.0 {cx:.4f} {cy:.4f} {cz:.4f}\n"); aid+=1
f.write("\nBonds\n\n")
for i in range(nw):
b = i*3+1
f.write(f"{i*2+1} 1 {b} {b+1}\n{i*2+2} 1 {b} {b+2}\n")
f.write("\nAngles\n\n")
for i in range(nw):
b = i*3+1
f.write(f"{i+1} 1 {b+1} {b} {b+2}\n")
def find_latest_restart(case_dir):
files = glob.glob(os.path.join(case_dir, "restart.A")) +
glob.glob(os.path.join(case_dir, "restart.B"))
return max(files, key=os.path.getmtime) if files else None
def write_lammps_input(data_path, restart_path, cfg, case_dir): in_file = os.path.join(LOCAL_DIR, "run.in") use_restart = restart_path and os.path.exists(restart_path) with open(in_file, 'w') as f: if use_restart: f.write(f"read_restart {restart_path}\n") f.write("pair_style lj/cut/coul/long 10.0\n") f.write("kspace_style pppm 1.0e-4\n") f.write("pair_modify mix arithmetic\n") f.write("group water type 1 2\n") f.write("group carbon type 3\n") f.write("fix freeze carbon setforce 0.0 0.0 0.0\n") f.write("fix shake_pr water shake 0.0001 20 0 b 1 a 1\n") f.write(f"fix nvt_pr water nvt temp {cfg['TEMP']} {cfg['TEMP']} 500.0\n") f.write("timestep 2.0\n") else: f.write(f"""units real atom_style full boundary p p p read_data {data_path}
pair_style lj/cut/coul/long 10.0 pair_coeff 1 1 0.1553 3.166 pair_coeff 2 2 0.0 0.0 pair_coeff 3 3 {cfg['WALL_EPSILON']} {cfg['WALL_SIGMA']} pair_coeff 1 3 0.104 3.36 pair_modify mix arithmetic
bond_style harmonic bond_coeff 1 1000.0 1.0 angle_style harmonic angle_coeff 1 100.0 109.47 kspace_style pppm 1.0e-4
group water type 1 2 group carbon type 3 fix freeze carbon setforce 0.0 0.0 0.0
fix shake_eq water shake 0.0001 20 0 b 1 a 1 velocity water create {cfg['TEMP']} {cfg['BASE_SEED']} dist gaussian fix nvt_eq water nvt temp {cfg['TEMP']} {cfg['TEMP']} 500.0 timestep 1.0 thermo {cfg['THERMO_FREQ']} run {cfg['STEPS_EQ']} unfix nvt_eq unfix shake_eq
fix shake_pr water shake 0.0001 20 0 b 1 a 1 fix nvt_pr water nvt temp {cfg['TEMP']} {cfg['TEMP']} 500.0 timestep 2.0 """) f.write(f"thermo {cfg['THERMO_FREQ']}\n") f.write("thermo_style custom step temp press density etotal\n") f.write(f"dump mydump water custom {cfg['DUMP_FREQ']} {os.path.join(LOCAL_DIR,'traj.lammpstrj')} id type x y z\n") restart_A = os.path.join(case_dir, "restart.A") restart_B = os.path.join(case_dir, "restart.B") f.write(f"restart {cfg['RESTART_FREQ']} {restart_A} {restart_B}\n") f.write(f"run {cfg['STEPS_PROD']} upto\n") f.write(f"write_restart {os.path.join(case_dir,'final.restart')}\n") return in_file
cfg = CONFIG case_dir = os.path.join(WORK_DIR, f"pore5_r{cfg['REPLICA']}") os.makedirs(case_dir, exist_ok=True)
lmp = setup_lammps()
restart_to_use = find_latest_restart(case_dir) if restart_to_use: print(f"♻️ استئناف من: {restart_to_use}") inp_file = write_lammps_input(None, restart_to_use, cfg, case_dir) else: print("🆕 بناء نظام جديد...") builder = Builder(cfg) carbon = builder.graphene_pore() O, H1, H2 = builder.pack_water(carbon, cfg['BASE_SEED']) guard = Guardian(cfg) if not guard.validate(carbon, O, H1, H2): raise RuntimeError("❌ فشل فحص النظام") data_file = os.path.join(LOCAL_DIR, "data.5pores") guard.write_data(carbon, O, H1, H2, data_file) inp_file = write_lammps_input(data_file, None, cfg, case_dir)
log_path = os.path.join(LOCAL_DIR, "log.txt") print("🚀 تشغيل LAMMPS...") t0 = time.time()
with open(log_path, 'w') as log_f: proc = subprocess.Popen( [lmp, "-in", inp_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) for line in proc.stdout: print(line, end='', flush=True) log_f.write(line) proc.wait() ret = proc.returncode
dt = time.time() - t0 if ret != 0: print(f"❌ فشل LAMMPS بعد {dt:.0f} ثانية") else: print(f"✅ اكتملت في {dt/60:.1f} دقيقة") for fn in ["traj.lammpstrj", "log.txt"]: src = os.path.join(LOCAL_DIR, fn) dst = os.path.join(case_dir, fn) if os.path.exists(src): if os.path.exists(dst): os.remove(dst) shutil.move(src, dst) print(f"📁 النتائج: {case_dir}")