From ae9565386dc3a089ddd8aff10ca31513d717eea4 Mon Sep 17 00:00:00 2001 From: Stefan Verhoeven Date: Tue, 6 May 2025 15:41:58 +0200 Subject: [PATCH 1/4] Try out powerfit in web browser --- README.md | 20 ++++++++++++ tutorial.html | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 tutorial.html diff --git a/README.md b/README.md index 1cf74e5..fc0cf17 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,26 @@ Compile the contact-chainID.cpp file as follows g++ contact-chainID.cpp -o contact-chainID +Run in web browser +================== + +In powerfit repo make a pyodide wheel with + +``` +uvx cibuildwheel --platform pyodide +cp ../powerfit/wheelhouse/powerfit-3.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl . +``` + +Start a local server + +``` +python3 -m http.server 8000 +``` + +Then open the http://localhost:8000/tutorial.html in your web browser. +Wait for read and press the run button. +See DevTools console for print output. + Licence ======= diff --git a/tutorial.html b/tutorial.html new file mode 100644 index 0000000..624e23b --- /dev/null +++ b/tutorial.html @@ -0,0 +1,85 @@ + + + + + + + +

+ You can execute any Python code. Just enter something in the box below and + click the button. +

+ + +
+
+
Output:
+ + + + + \ No newline at end of file From 0410ba3156d380b5223a82a9f70e6b0d5ade518c Mon Sep 17 00:00:00 2001 From: Stefan Verhoeven Date: Tue, 6 May 2025 16:13:15 +0200 Subject: [PATCH 2/4] Run single core --- tutorial.html | 82 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/tutorial.html b/tutorial.html index 624e23b..3d48724 100644 --- a/tutorial.html +++ b/tutorial.html @@ -29,21 +29,78 @@ target = Volume.fromfile("ribosome-KsgA.map") print(target.shape) -from powerfit.powerfit import main -sys.argv = [ -"powerfit", -"ribosome-KsgA.map", -"13", -"KsgA.pdb", -"-a", -"20", -"-l" -] -main() +#from powerfit.powerfit import main +#sys.argv = [ "powerfit","ribosome-KsgA.map","13","KsgA.pdb","-a","20","-l"] +#main() +# main() does not work, because it tries to use multiprocessing which is not implemented in pyodide + +# TODO make single core method to simplify usage in pyodide, now it is copy of main() internals +from powerfit import ( + Volume, Structure, structure_to_shape_like, proportional_orientations, + quat_to_rotmat, determine_core_indices + ) +from powerfit.powerfitter import PowerFitter +from powerfit.analyzer import Analyzer +from powerfit.helpers import mkdir_p, write_fits_to_pdb, fisher_sigma +from powerfit.volume import extend, nearest_multiple2357, trim, resample +import numpy as np +from os.path import join + +resolution = 13 +resampling_rate = 2 +target = "ribosome-KsgA.map" +template = "KsgA.pdb" +angle = 20 +laplace = True +num = 5 +directory = '.' + +target = Volume.fromfile(target) +factor = 2 * resampling_rate * target.voxelspacing / resolution +target = resample(target, factor) +trimming_cutoff = target.array.max() / 10 +target = trim(target, trimming_cutoff) +extended_shape = [nearest_multiple2357(n) for n in target.shape] +target = extend(target, extended_shape) +structure = Structure.fromfile(template) +structure.translate(target.origin - structure.coor.mean(axis=1)) +template = structure_to_shape_like( + target, structure.coor, resolution=resolution, + weights=structure.atomnumber, shape='vol' + ) +mask = structure_to_shape_like( + target, structure.coor, resolution=resolution, shape='mask' + ) +q, w, degree = proportional_orientations(angle) +rotmat = quat_to_rotmat(q) + +class Counter: + def increment(self): + pass + +counter = Counter() + +PowerFitter._run_correlator_instance(target, template, mask, rotmat, laplace, counter=counter, jobid=1, queues=None, directory=directory) +_lcc = np.load('_lcc_part_1.npy') +_rot = np.load('_rot_part_1.npy') +mv = structure_to_shape_like( + target, structure.coor, resolution=resolution, radii=structure.rvdw, shape='mask' +).array.sum() * target.voxelspacing ** 3 +z_sigma = fisher_sigma(mv, resolution) +analyzer = Analyzer( + _lcc, rotmat, _rot, voxelspacing=target.voxelspacing, + origin=target.origin, z_sigma=z_sigma +) +Volume(_lcc, target.voxelspacing, target.origin).tofile(join(directory, 'lcc.mrc')) +analyzer.tofile(join(directory, 'solutions.out')) +n = min(num, len(analyzer.solutions)) +write_fits_to_pdb(structure, analyzer.solutions[:n], basename=join(directory, 'fit')) # Read some of the output list(Path('.').iterdir()) +print(Path('solutions.out').read_text()) +
@@ -74,7 +131,10 @@ async function evaluatePython() { let pyodide = await pyodideReadyPromise; try { + addToOutput("Running..."); + console.time() let output = await pyodide.runPythonAsync(code.value); + console.timeEnd(); addToOutput(output); } catch (err) { addToOutput(err); From e8107054647b7c399f4180e170b42e6630cde25e Mon Sep 17 00:00:00 2001 From: Stefan Verhoeven Date: Tue, 6 May 2025 16:16:10 +0200 Subject: [PATCH 3/4] print dir --- tutorial.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial.html b/tutorial.html index 3d48724..459ab4a 100644 --- a/tutorial.html +++ b/tutorial.html @@ -97,7 +97,7 @@ write_fits_to_pdb(structure, analyzer.solutions[:n], basename=join(directory, 'fit')) # Read some of the output -list(Path('.').iterdir()) +print(list(Path('.').iterdir())) print(Path('solutions.out').read_text()) From 8b04e639a61c88ac3c18a98ce83eede9a7aba268 Mon Sep 17 00:00:00 2001 From: sverhoeven Date: Wed, 7 May 2025 16:06:06 +0200 Subject: [PATCH 4/4] Rename powerfit package to powerfit_em --- README.md | 2 +- tutorial.html | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fc0cf17..41a6f53 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ In powerfit repo make a pyodide wheel with ``` uvx cibuildwheel --platform pyodide -cp ../powerfit/wheelhouse/powerfit-3.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl . +cp ../powerfit/wheelhouse/powerfit_em-3.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl . ``` Start a local server diff --git a/tutorial.html b/tutorial.html index 459ab4a..90550f0 100644 --- a/tutorial.html +++ b/tutorial.html @@ -25,24 +25,24 @@ await download_file("http://localhost:8000/ribosome-KsgA.map", "ribosome-KsgA.map") await download_file("http://localhost:8000/KsgA.pdb", "KsgA.pdb") -from powerfit import Volume +from powerfit_em import Volume target = Volume.fromfile("ribosome-KsgA.map") print(target.shape) -#from powerfit.powerfit import main +#from powerfit_em.powerfit import main #sys.argv = [ "powerfit","ribosome-KsgA.map","13","KsgA.pdb","-a","20","-l"] #main() # main() does not work, because it tries to use multiprocessing which is not implemented in pyodide # TODO make single core method to simplify usage in pyodide, now it is copy of main() internals -from powerfit import ( +from powerfit_em import ( Volume, Structure, structure_to_shape_like, proportional_orientations, quat_to_rotmat, determine_core_indices ) -from powerfit.powerfitter import PowerFitter -from powerfit.analyzer import Analyzer -from powerfit.helpers import mkdir_p, write_fits_to_pdb, fisher_sigma -from powerfit.volume import extend, nearest_multiple2357, trim, resample +from powerfit_em.powerfitter import PowerFitter +from powerfit_em.analyzer import Analyzer +from powerfit_em.helpers import mkdir_p, write_fits_to_pdb, fisher_sigma +from powerfit_em.volume import extend, nearest_multiple2357, trim, resample import numpy as np from os.path import join @@ -122,7 +122,7 @@ let pyodide = await loadPyodide(); await pyodide.loadPackage("micropip") const micropip = pyodide.pyimport("micropip"); - await micropip.install('http://localhost:8000/powerfit-3.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl'); + await micropip.install('http://localhost:8000/powerfit_em-3.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl'); output.value += "Powerfit installed\nReady!\n"; return pyodide; }