pyLoopSage 1.0.22__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyloopsage-1.1.0/MANIFEST.in +1 -0
- {pyloopsage-1.0.22/pyLoopSage.egg-info → pyloopsage-1.1.0}/PKG-INFO +36 -11
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/README.md +34 -10
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/__init__.py +1 -1
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/args_definition.py +35 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/md.py +24 -16
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/preproc.py +20 -20
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/run.py +5 -3
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/stochastic_simulation.py +95 -54
- {pyloopsage-1.0.22 → pyloopsage-1.1.0/pyLoopSage.egg-info}/PKG-INFO +36 -11
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/pyLoopSage.egg-info/SOURCES.txt +1 -1
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/pyLoopSage.egg-info/requires.txt +1 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/setup.py +2 -1
- pyloopsage-1.0.22/loopsage/knots.py +0 -193
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/LICENSE +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/em.py +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/forcefields/classic_sm_ff.xml +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/initial_structures.py +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/plots.py +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/utils.py +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/loopsage/vizualization_tools.py +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/pyLoopSage.egg-info/dependency_links.txt +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/pyLoopSage.egg-info/entry_points.txt +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/pyLoopSage.egg-info/top_level.txt +0 -0
- {pyloopsage-1.0.22 → pyloopsage-1.1.0}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
exclude loopsage/knots.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyLoopSage
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: An energy-based stochastic model of loop extrusion in chromatin.
|
|
5
5
|
Home-page: https://github.com/SFGLab/pyLoopSage
|
|
6
6
|
Author: Sebastian Korsak
|
|
@@ -31,6 +31,7 @@ Requires-Dist: statsmodels
|
|
|
31
31
|
Requires-Dist: imageio
|
|
32
32
|
Requires-Dist: imageio[ffmpeg]
|
|
33
33
|
Requires-Dist: pillow
|
|
34
|
+
Requires-Dist: pyBigWig
|
|
34
35
|
Dynamic: author
|
|
35
36
|
Dynamic: author-email
|
|
36
37
|
Dynamic: classifier
|
|
@@ -271,49 +272,73 @@ An example, illustrated with Chimera software, simulated trajectory of structure
|
|
|
271
272
|
|
|
272
273
|
### Long-table of LoopSage arguments
|
|
273
274
|
|
|
275
|
+
#### General Settings
|
|
274
276
|
| Argument Name | Description | Type | Default Value |
|
|
275
277
|
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
276
278
|
| PLATFORM | Name of the platform. Available choices: CPU, CUDA, OpenCL | str | CPU |
|
|
277
279
|
| DEVICE | Device index for CUDA or OpenCL (count from 0) | str | None |
|
|
278
|
-
| N_BEADS | Number of Simulation Beads. | int | None |
|
|
279
|
-
| BEDPE_PATH | A .bedpe file path with loops. It is required. | str | None |
|
|
280
280
|
| OUT_PATH | Output folder name. | str | ../results |
|
|
281
|
+
| SAVE_MDT | True to save metadata of the stochastic simulation. | bool | True |
|
|
282
|
+
|
|
283
|
+
#### Input Data
|
|
284
|
+
| Argument Name | Description | Type | Default Value |
|
|
285
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
286
|
+
| BEDPE_PATH | A .bedpe file path with loops. It is required. | str | None |
|
|
287
|
+
| LEF_TRACK_FILE | Path to a bw file of cohesin or condensin density. If it is provided, then simulation LEFs preferentially bind in enriched regions. | str | None |
|
|
288
|
+
| BW_FILES | List of paths to .bw files containing additional data for simulation. Enriched regions would act as barriers for cohesin. | list | None |
|
|
281
289
|
| REGION_START | Starting region coordinate. | int | None |
|
|
282
290
|
| REGION_END | Ending region coordinate. | int | None |
|
|
283
291
|
| CHROM | Chromosome that corresponds to the modeling region of interest. | str | None |
|
|
284
|
-
|
|
285
|
-
|
|
292
|
+
|
|
293
|
+
#### Stochastic Simulation Parameters
|
|
294
|
+
| Argument Name | Description | Type | Default Value |
|
|
295
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
296
|
+
| N_BEADS | Number of Simulation Beads. | int | None |
|
|
286
297
|
| N_STEPS | Number of Monte Carlo steps. | int | 40000 |
|
|
287
|
-
| N_LEF | Number of loop extrusion factors. | int | None |
|
|
288
|
-
| N_LEF2 | Number of second family loop extrusion factors. | int | 0 |
|
|
289
298
|
| MC_STEP | Monte Carlo frequency to avoid autocorrelated ensembles. | int | 200 |
|
|
290
299
|
| BURNIN | Burn-in period (steps before equilibrium). | int | 1000 |
|
|
291
300
|
| T_INIT | Initial Temperature of the Stochastic Model. | float | 2.0 |
|
|
292
301
|
| T_FINAL | Final Temperature of the Stochastic Model. | float | 1.0 |
|
|
293
302
|
| METHOD | Stochastic modeling method (Metropolis or Simulated Annealing). | str | 'Annealing' |
|
|
303
|
+
| LEF_RW | True if cohesins slide as a random walk instead of one direction. | bool | True |
|
|
304
|
+
| LEF_DRIFT | True if LEFs are pushed back when they encounter other LEFs. | bool | False |
|
|
305
|
+
| N_LEF | Number of loop extrusion factors. | int | None |
|
|
306
|
+
| N_LEF2 | Number of second family loop extrusion factors. | int | 0 |
|
|
307
|
+
|
|
308
|
+
#### Energy Coefficients
|
|
309
|
+
| Argument Name | Description | Type | Default Value |
|
|
310
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
294
311
|
| FOLDING_COEFF | Folding coefficient. | float | 1.0 |
|
|
295
312
|
| FOLDING_COEFF2 | Folding coefficient for the second family of LEFs. | float | 0.0 |
|
|
296
313
|
| CROSS_COEFF | LEF crossing coefficient. | float | 1.0 |
|
|
297
314
|
| CROSS_LOOP | True if the penalty is applied when mi<mj<ni<nj. False if it applies only when mj=ni. When false it is better to enable LEF_DRIFT as well. | bool |True |
|
|
298
315
|
| BIND_COEFF | CTCF binding coefficient. | float | 1.0 |
|
|
299
|
-
|
|
|
300
|
-
|
|
301
|
-
|
|
316
|
+
| BW_STRENGTHS | List of strengths corresponding to each .bw file. | list | None |
|
|
317
|
+
|
|
318
|
+
#### Molecular Dynamics Simulation
|
|
319
|
+
| Argument Name | Description | Type | Default Value |
|
|
320
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
302
321
|
| SIMULATION_TYPE | Either EM (energy minimizations) or MD (molecular dynamics). | str | None |
|
|
322
|
+
| INITIAL_STRUCTURE_TYPE | Choose from: rw, confined_rw, self_avoiding_rw, helix, circle, spiral, sphere. | str | rw |
|
|
303
323
|
| INTEGRATOR_STEP | Step of the integrator. | Quantity | 100 femtosecond |
|
|
304
324
|
| FORCEFIELD_PATH | Path to XML file with forcefield. | str | default_xml_path |
|
|
305
325
|
| ANGLE_FF_STRENGTH | Angle force strength. | float | 200.0 |
|
|
306
326
|
| LE_FF_LENGTH | Equilibrium distance of loop forces. | float | 0.1 |
|
|
307
327
|
| LE_FF_STRENGTH | Interaction Strength of loop forces. | float | 50000.0 |
|
|
328
|
+
| CONTINUOUS_TOP | True if the topological constraints are applied continuously during the simulation. | bool | False |
|
|
308
329
|
| EV_P | Probability that excluded volume is disabled. Enable it only in case of topoisomerase activity simulation. | float | 0.0 |
|
|
309
330
|
| EV_FF_STRENGTH | Excluded-volume strength. | float | 100.0 |
|
|
310
331
|
| EV_FF_POWER | Excluded-volume power. | float | 3.0 |
|
|
311
332
|
| FRICTION | Friction coefficient of the Langevin integrator. | float | 0.1 |
|
|
312
333
|
| TOLERANCE | Stopping condition for energy minimization. | float | 0.001 |
|
|
313
|
-
| VIZ_HEATS | True to visualize the output average heatmap. | bool | True |
|
|
314
334
|
| SIM_TEMP | Temperature of the 3D simulation (EM or MD). | Quantity | 310 kelvin |
|
|
315
335
|
| SIM_STEP | Amount of simulation steps for loop force adjustments. | int | 1000 |
|
|
316
336
|
|
|
337
|
+
#### Visualization
|
|
338
|
+
| Argument Name | Description | Type | Default Value |
|
|
339
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
340
|
+
| VIZ_HEATS | True to visualize the output average heatmap. | bool | True |
|
|
341
|
+
| SAVE_PLOTS | True to save diagnostic plots. | bool | True |
|
|
317
342
|
|
|
318
343
|
## Citation
|
|
319
344
|
Please cite the method and biological paper in case that you would like to use this model for your work,
|
|
@@ -226,49 +226,73 @@ An example, illustrated with Chimera software, simulated trajectory of structure
|
|
|
226
226
|
|
|
227
227
|
### Long-table of LoopSage arguments
|
|
228
228
|
|
|
229
|
+
#### General Settings
|
|
229
230
|
| Argument Name | Description | Type | Default Value |
|
|
230
231
|
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
231
232
|
| PLATFORM | Name of the platform. Available choices: CPU, CUDA, OpenCL | str | CPU |
|
|
232
233
|
| DEVICE | Device index for CUDA or OpenCL (count from 0) | str | None |
|
|
233
|
-
| N_BEADS | Number of Simulation Beads. | int | None |
|
|
234
|
-
| BEDPE_PATH | A .bedpe file path with loops. It is required. | str | None |
|
|
235
234
|
| OUT_PATH | Output folder name. | str | ../results |
|
|
235
|
+
| SAVE_MDT | True to save metadata of the stochastic simulation. | bool | True |
|
|
236
|
+
|
|
237
|
+
#### Input Data
|
|
238
|
+
| Argument Name | Description | Type | Default Value |
|
|
239
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
240
|
+
| BEDPE_PATH | A .bedpe file path with loops. It is required. | str | None |
|
|
241
|
+
| LEF_TRACK_FILE | Path to a bw file of cohesin or condensin density. If it is provided, then simulation LEFs preferentially bind in enriched regions. | str | None |
|
|
242
|
+
| BW_FILES | List of paths to .bw files containing additional data for simulation. Enriched regions would act as barriers for cohesin. | list | None |
|
|
236
243
|
| REGION_START | Starting region coordinate. | int | None |
|
|
237
244
|
| REGION_END | Ending region coordinate. | int | None |
|
|
238
245
|
| CHROM | Chromosome that corresponds to the modeling region of interest. | str | None |
|
|
239
|
-
|
|
240
|
-
|
|
246
|
+
|
|
247
|
+
#### Stochastic Simulation Parameters
|
|
248
|
+
| Argument Name | Description | Type | Default Value |
|
|
249
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
250
|
+
| N_BEADS | Number of Simulation Beads. | int | None |
|
|
241
251
|
| N_STEPS | Number of Monte Carlo steps. | int | 40000 |
|
|
242
|
-
| N_LEF | Number of loop extrusion factors. | int | None |
|
|
243
|
-
| N_LEF2 | Number of second family loop extrusion factors. | int | 0 |
|
|
244
252
|
| MC_STEP | Monte Carlo frequency to avoid autocorrelated ensembles. | int | 200 |
|
|
245
253
|
| BURNIN | Burn-in period (steps before equilibrium). | int | 1000 |
|
|
246
254
|
| T_INIT | Initial Temperature of the Stochastic Model. | float | 2.0 |
|
|
247
255
|
| T_FINAL | Final Temperature of the Stochastic Model. | float | 1.0 |
|
|
248
256
|
| METHOD | Stochastic modeling method (Metropolis or Simulated Annealing). | str | 'Annealing' |
|
|
257
|
+
| LEF_RW | True if cohesins slide as a random walk instead of one direction. | bool | True |
|
|
258
|
+
| LEF_DRIFT | True if LEFs are pushed back when they encounter other LEFs. | bool | False |
|
|
259
|
+
| N_LEF | Number of loop extrusion factors. | int | None |
|
|
260
|
+
| N_LEF2 | Number of second family loop extrusion factors. | int | 0 |
|
|
261
|
+
|
|
262
|
+
#### Energy Coefficients
|
|
263
|
+
| Argument Name | Description | Type | Default Value |
|
|
264
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
249
265
|
| FOLDING_COEFF | Folding coefficient. | float | 1.0 |
|
|
250
266
|
| FOLDING_COEFF2 | Folding coefficient for the second family of LEFs. | float | 0.0 |
|
|
251
267
|
| CROSS_COEFF | LEF crossing coefficient. | float | 1.0 |
|
|
252
268
|
| CROSS_LOOP | True if the penalty is applied when mi<mj<ni<nj. False if it applies only when mj=ni. When false it is better to enable LEF_DRIFT as well. | bool |True |
|
|
253
269
|
| BIND_COEFF | CTCF binding coefficient. | float | 1.0 |
|
|
254
|
-
|
|
|
255
|
-
|
|
256
|
-
|
|
270
|
+
| BW_STRENGTHS | List of strengths corresponding to each .bw file. | list | None |
|
|
271
|
+
|
|
272
|
+
#### Molecular Dynamics Simulation
|
|
273
|
+
| Argument Name | Description | Type | Default Value |
|
|
274
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
257
275
|
| SIMULATION_TYPE | Either EM (energy minimizations) or MD (molecular dynamics). | str | None |
|
|
276
|
+
| INITIAL_STRUCTURE_TYPE | Choose from: rw, confined_rw, self_avoiding_rw, helix, circle, spiral, sphere. | str | rw |
|
|
258
277
|
| INTEGRATOR_STEP | Step of the integrator. | Quantity | 100 femtosecond |
|
|
259
278
|
| FORCEFIELD_PATH | Path to XML file with forcefield. | str | default_xml_path |
|
|
260
279
|
| ANGLE_FF_STRENGTH | Angle force strength. | float | 200.0 |
|
|
261
280
|
| LE_FF_LENGTH | Equilibrium distance of loop forces. | float | 0.1 |
|
|
262
281
|
| LE_FF_STRENGTH | Interaction Strength of loop forces. | float | 50000.0 |
|
|
282
|
+
| CONTINUOUS_TOP | True if the topological constraints are applied continuously during the simulation. | bool | False |
|
|
263
283
|
| EV_P | Probability that excluded volume is disabled. Enable it only in case of topoisomerase activity simulation. | float | 0.0 |
|
|
264
284
|
| EV_FF_STRENGTH | Excluded-volume strength. | float | 100.0 |
|
|
265
285
|
| EV_FF_POWER | Excluded-volume power. | float | 3.0 |
|
|
266
286
|
| FRICTION | Friction coefficient of the Langevin integrator. | float | 0.1 |
|
|
267
287
|
| TOLERANCE | Stopping condition for energy minimization. | float | 0.001 |
|
|
268
|
-
| VIZ_HEATS | True to visualize the output average heatmap. | bool | True |
|
|
269
288
|
| SIM_TEMP | Temperature of the 3D simulation (EM or MD). | Quantity | 310 kelvin |
|
|
270
289
|
| SIM_STEP | Amount of simulation steps for loop force adjustments. | int | 1000 |
|
|
271
290
|
|
|
291
|
+
#### Visualization
|
|
292
|
+
| Argument Name | Description | Type | Default Value |
|
|
293
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
294
|
+
| VIZ_HEATS | True to visualize the output average heatmap. | bool | True |
|
|
295
|
+
| SAVE_PLOTS | True to save diagnostic plots. | bool | True |
|
|
272
296
|
|
|
273
297
|
## Citation
|
|
274
298
|
Please cite the method and biological paper in case that you would like to use this model for your work,
|
|
@@ -23,6 +23,7 @@ class Arg(object):
|
|
|
23
23
|
type: type
|
|
24
24
|
default: Union[str, float, int, bool, Quantity, None]
|
|
25
25
|
val: Union[str, float, int, bool, Quantity, None]
|
|
26
|
+
nargs: Union[str, None] = None # Optional attribute for nargs
|
|
26
27
|
|
|
27
28
|
# Define custom type to parse list from string
|
|
28
29
|
def parse_list(s):
|
|
@@ -65,6 +66,18 @@ class ListOfArgs(list):
|
|
|
65
66
|
raise ValueError(f"I Can't recognise unit {unit} in expression {val}. Example of valid quantity: 12.3 femtosecond.")
|
|
66
67
|
return Quantity(value=float(value), unit=unit)
|
|
67
68
|
|
|
69
|
+
def parse_list_of_floats(self, s: str) -> list:
|
|
70
|
+
try:
|
|
71
|
+
return [float(x.strip()) for x in s.strip('[]').split(',')]
|
|
72
|
+
except ValueError:
|
|
73
|
+
raise argparse.ArgumentTypeError("Invalid list format. Must be a comma-separated list of floats.")
|
|
74
|
+
|
|
75
|
+
def parse_list_of_strings(self, s: str) -> list:
|
|
76
|
+
try:
|
|
77
|
+
return [x.strip() for x in s.strip('[]').split(',')]
|
|
78
|
+
except ValueError:
|
|
79
|
+
raise argparse.ArgumentTypeError("Invalid list format. Must be a comma-separated list of strings.")
|
|
80
|
+
|
|
68
81
|
def to_python(self):
|
|
69
82
|
"""Casts string args to ints, floats, bool..."""
|
|
70
83
|
for i in self:
|
|
@@ -78,6 +91,22 @@ class ListOfArgs(list):
|
|
|
78
91
|
i.val = int(i.val)
|
|
79
92
|
elif i.type == float:
|
|
80
93
|
i.val = float(i.val)
|
|
94
|
+
elif i.type == list:
|
|
95
|
+
if i.name == "BW_FILES" or i.name == "STRING_LIST": # Handle lists of strings
|
|
96
|
+
if isinstance(i.val, str):
|
|
97
|
+
i.val = self.parse_list_of_strings(i.val)
|
|
98
|
+
elif not isinstance(i.val, list):
|
|
99
|
+
raise ValueError(f"Can't convert {i.val} into list of strings.")
|
|
100
|
+
elif i.name == "BW_STRENGTHS" or i.name == "FLOAT_LIST": # Handle lists of floats
|
|
101
|
+
if isinstance(i.val, str):
|
|
102
|
+
i.val = self.parse_list_of_floats(i.val)
|
|
103
|
+
elif not isinstance(i.val, list):
|
|
104
|
+
raise ValueError(f"Can't convert {i.val} into list of floats.")
|
|
105
|
+
else: # Handle lists of integers
|
|
106
|
+
if isinstance(i.val, str):
|
|
107
|
+
i.val = parse_list(i.val)
|
|
108
|
+
elif not isinstance(i.val, list):
|
|
109
|
+
raise ValueError(f"Can't convert {i.val} into list of integers.")
|
|
81
110
|
elif i.type == bool:
|
|
82
111
|
if i.val.lower() in ['true', '1', 'y', 'yes']:
|
|
83
112
|
i.val = True
|
|
@@ -138,10 +167,14 @@ args = ListOfArgs([
|
|
|
138
167
|
# Input data
|
|
139
168
|
Arg('N_BEADS', help="Number of Simulation Beads.", type=int, default='', val=''),
|
|
140
169
|
Arg('BEDPE_PATH', help="A .bedpe file path with loops. It is required.", type=str, default='', val=''),
|
|
170
|
+
Arg('LEF_TRACK_FILE', help="An optional track file for cohesin or condensin in bw format. If this file is specified LEF preferentially binds were the signal is enriched.", type=str, default='', val=''),
|
|
171
|
+
Arg('BW_FILES', help="List of bigWig file paths for feature extraction.", type=list, nargs='+', default=[], val=[]),
|
|
141
172
|
Arg('OUT_PATH', help="Output folder name.", type=str, default='../results', val='../results'),
|
|
142
173
|
Arg('REGION_START', help="Starting region coordinate.", type=int, default='', val=''),
|
|
143
174
|
Arg('REGION_END', help="Ending region coordinate.", type=int, default='', val=''),
|
|
144
175
|
Arg('CHROM', help="Chromosome that corresponds the the modelling region of interest (in case that you do not want to model the whole genome).", type=str, default='', val=''),
|
|
176
|
+
Arg('FLOAT_LIST', help="List of floating-point numbers.", type=list, nargs='+', default=[], val=[]),
|
|
177
|
+
Arg('STRING_LIST', help="List of strings.", type=list, nargs='+', default=[], val=[]),
|
|
145
178
|
|
|
146
179
|
# Stochastic Simulation parameters
|
|
147
180
|
Arg('LEF_RW', help="True in case that you would like to make cohesins slide as random walk, instead of sliding only in one direction.", type=bool, default='True', val='True'),
|
|
@@ -157,6 +190,7 @@ args = ListOfArgs([
|
|
|
157
190
|
Arg('FOLDING_COEFF', help="Folding coefficient.", type=float, default='1.0', val='1.0'),
|
|
158
191
|
Arg('FOLDING_COEFF2', help="Folding coefficient for the second family of LEFs.", type=float, default='0.0', val='0.0'),
|
|
159
192
|
Arg('CROSS_COEFF', help="LEF crossing coefficient.", type=float, default='1.0', val='1.0'),
|
|
193
|
+
Arg('BW_STRENGTHS', help="List of strengths of the energy (floats) corresponding to each BW file. This equivalent to the `r` parameter in the LoopSage paper.", type=list, nargs='+', default=[], val=[]),
|
|
160
194
|
Arg('CROSS_LOOP', help="It true if the penalty is applied for situations mi<mj<ni<nj and mi=nj, and false if it is applied only for mi=nj.", type=bool, default='True', val='True'),
|
|
161
195
|
Arg('BIND_COEFF', help="CTCF binding coefficient.", type=float, default='1.0', val='1.0'),
|
|
162
196
|
Arg('SAVE_PLOTS', help="It should be true in case that you would like to save diagnostic plots. In case that you use small MC_STEP or large N_STEPS is better to mark it as False.", type=bool, default='True', val='True'),
|
|
@@ -170,6 +204,7 @@ args = ListOfArgs([
|
|
|
170
204
|
Arg('ANGLE_FF_STRENGTH', help="Angle force strength.", type=float, default='200.0', val='200.0'),
|
|
171
205
|
Arg('LE_FF_LENGTH', help="Equillibrium distance of loop forces.", type=float, default='0.1', val='0.1'),
|
|
172
206
|
Arg('LE_FF_STRENGTH', help="Interaction Strength of loop forces.", type=float, default='50000.0', val='50000.0'),
|
|
207
|
+
Arg('CONTINUOUS_TOP', help="True if topoisomerase disables EV in a continuous region rather than a discrete set of points.", type=bool, default='False', val='False'),
|
|
173
208
|
Arg('EV_P', help="Probability that randomly excluded volume may be disabled.", type=float, default='0.0', val='0.0'),
|
|
174
209
|
Arg('EV_FF_STRENGTH', help="Excluded-volume strength.", type=float, default='100.0', val='100.0'),
|
|
175
210
|
Arg('EV_FF_POWER', help="Excluded-volume power.", type=float, default='3.0', val='3.0'),
|
|
@@ -36,18 +36,19 @@ class MD_LE:
|
|
|
36
36
|
self.ev_ff_power = ev_ff_power
|
|
37
37
|
self.tolerance = tolerance
|
|
38
38
|
|
|
39
|
-
def run_pipeline(self,run_MD=True, friction=0.1, integrator_step=10 * mm.unit.femtosecond, sim_step=100, ff_path
|
|
39
|
+
def run_pipeline(self, run_MD=True, friction=0.1, integrator_step=10 * mm.unit.femtosecond, sim_step=100, ff_path='forcefields/classic_sm_ff.xml', init_struct='rw', temperature=310, p_ev=0, plots=False, continuous_topoisomerase=False):
|
|
40
40
|
'''
|
|
41
41
|
This is the basic function that runs the molecular simulation pipeline.
|
|
42
42
|
'''
|
|
43
43
|
# Parameters
|
|
44
44
|
self.p_ev = p_ev
|
|
45
|
+
self.continuous_topoisomerase = continuous_topoisomerase
|
|
45
46
|
|
|
46
47
|
# Define initial structure
|
|
47
48
|
print('Building initial structure...')
|
|
48
|
-
points = compute_init_struct(self.N_beads,mode='rw')
|
|
49
|
-
write_mmcif(points,self.path+'/LE_init_struct.cif')
|
|
50
|
-
generate_psf(self.N_beads,self.path+'/other/LE_init_struct.psf')
|
|
49
|
+
points = compute_init_struct(self.N_beads, mode='rw')
|
|
50
|
+
write_mmcif(points, self.path+'/LE_init_struct.cif')
|
|
51
|
+
generate_psf(self.N_beads, self.path+'/other/LE_init_struct.psf')
|
|
51
52
|
print('Done brother ;D\n')
|
|
52
53
|
|
|
53
54
|
# Define System
|
|
@@ -79,32 +80,39 @@ class MD_LE:
|
|
|
79
80
|
start = time.time()
|
|
80
81
|
heats = list()
|
|
81
82
|
for i in range(self.N_steps):
|
|
82
|
-
# Define probabilities that EV would be disabled
|
|
83
|
-
if
|
|
83
|
+
# Define probabilities or regions that EV would be disabled
|
|
84
|
+
if self.continuous_topoisomerase:
|
|
85
|
+
region_length = max(1, int(self.p_ev * self.N_beads)) # Determine region length from p_ev
|
|
86
|
+
start_idx = np.random.randint(0, self.N_beads - region_length -1)
|
|
87
|
+
end_idx = start_idx + region_length
|
|
88
|
+
self.ps_ev = np.zeros(self.N_beads)
|
|
89
|
+
self.ps_ev[start_idx:end_idx] = 1
|
|
90
|
+
elif p_ev > 0:
|
|
91
|
+
self.ps_ev = np.random.rand(self.N_beads)
|
|
84
92
|
self.change_loop(i)
|
|
85
93
|
self.change_ev()
|
|
86
94
|
self.simulation.step(sim_step)
|
|
87
95
|
self.state = self.simulation.context.getState(getPositions=True)
|
|
88
96
|
PDBxFile.writeFile(pdb.topology, self.state.getPositions(), open(self.path+f'/ensemble/MDLE_{i+1}.cif', 'w'))
|
|
89
|
-
heats.append(get_heatmap(self.state.getPositions(),save=False))
|
|
97
|
+
heats.append(get_heatmap(self.state.getPositions(), save=False))
|
|
90
98
|
end = time.time()
|
|
91
99
|
elapsed = end - start
|
|
92
|
-
print(f'Everything is done! Simulation finished
|
|
100
|
+
print(f'Everything is done! Simulation finished successfully!\nMD finished in {elapsed/60:.2f} minutes.\n')
|
|
93
101
|
|
|
94
|
-
self.avg_heat = np.average(heats,axis=0)
|
|
95
|
-
self.std_heat = np.std(heats,axis=0)
|
|
102
|
+
self.avg_heat = np.average(heats, axis=0)
|
|
103
|
+
self.std_heat = np.std(heats, axis=0)
|
|
96
104
|
|
|
97
105
|
if plots:
|
|
98
|
-
np.save(self.path+f'/other/avg_heatmap.npy',self.avg_heat)
|
|
99
|
-
np.save(self.path+f'/other/std_heatmap.npy',self.std_heat)
|
|
100
|
-
self.plot_heat(self.avg_heat,f'/plots/avg_heatmap.svg')
|
|
101
|
-
self.plot_heat(self.std_heat,f'/plots/std_heatmap.svg')
|
|
106
|
+
np.save(self.path+f'/other/avg_heatmap.npy', self.avg_heat)
|
|
107
|
+
np.save(self.path+f'/other/std_heatmap.npy', self.std_heat)
|
|
108
|
+
self.plot_heat(self.avg_heat, f'/plots/avg_heatmap.svg')
|
|
109
|
+
self.plot_heat(self.std_heat, f'/plots/std_heatmap.svg')
|
|
102
110
|
return self.avg_heat
|
|
103
111
|
|
|
104
112
|
def change_ev(self):
|
|
105
|
-
ev_strength = (self.ps_ev>self.p_ev).astype(int)*np.sqrt(self.ev_ff_strength) if self.p_ev>0 else np.sqrt(self.ev_ff_strength)*np.ones(self.N_beads)
|
|
113
|
+
ev_strength = (self.ps_ev > self.p_ev).astype(int) * np.sqrt(self.ev_ff_strength) if self.p_ev > 0 else np.sqrt(self.ev_ff_strength) * np.ones(self.N_beads)
|
|
106
114
|
for n in range(self.N_beads):
|
|
107
|
-
self.ev_force.setParticleParameters(n,[ev_strength[n],0.05])
|
|
115
|
+
self.ev_force.setParticleParameters(n, [ev_strength[n], 0.05])
|
|
108
116
|
self.ev_force.updateParametersInContext(self.simulation.context)
|
|
109
117
|
|
|
110
118
|
def change_loop(self,i):
|
|
@@ -2,7 +2,7 @@ import numpy as np
|
|
|
2
2
|
import seaborn as sns
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import matplotlib.pyplot as plt
|
|
5
|
-
|
|
5
|
+
import pyBigWig
|
|
6
6
|
from matplotlib.pyplot import figure
|
|
7
7
|
|
|
8
8
|
def binding_vectors_from_bedpe(bedpe_file,N_beads,region,chrom,normalization=False,viz=False):
|
|
@@ -101,24 +101,24 @@ def get_rnap_energy(path,region,chrom,N_beads,normalization):
|
|
|
101
101
|
def distance_point_line(x0,y0,a=1,b=-1,c=0):
|
|
102
102
|
return np.abs(a*x0+b*y0+c)/np.sqrt(a**2+b**2)
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
def load_track(file,region,chrom,N_beads,viz=False,roll=False):
|
|
105
|
+
bw = pyBigWig.open(file)
|
|
106
|
+
weights = bw_to_array(bw, region, chrom, N_beads,viz,roll)
|
|
107
|
+
return weights[:N_beads]
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
109
|
+
def bw_to_array(bw, region, chrom, N_beads, viz=False, roll=False):
|
|
110
|
+
step = (region[1]-region[0])//N_beads
|
|
111
|
+
bw_array = bw.values(chrom, region[0], region[1])
|
|
112
|
+
bw_array = np.nan_to_num(bw_array)
|
|
113
|
+
bw_array_new = list()
|
|
114
|
+
for i in range(step,len(bw_array)+1,step):
|
|
115
|
+
bw_array_new.append(np.average(bw_array[(i-step):i]))
|
|
116
|
+
weights = (np.roll(np.array(bw_array_new),3)+np.roll(np.array(bw_array_new),-3))/2 if roll else bw_array_new
|
|
117
|
+
if viz:
|
|
118
|
+
figure(figsize=(15, 5))
|
|
119
|
+
plt.plot(weights)
|
|
120
|
+
plt.grid()
|
|
121
|
+
plt.title('ChIP-Seq signal',fontsize=20)
|
|
122
|
+
plt.close()
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
return weights
|
|
@@ -69,9 +69,11 @@ def main():
|
|
|
69
69
|
N_beads, N_lef, N_lef2 = args.N_BEADS, args.N_LEF, args.N_LEF2
|
|
70
70
|
N_steps, MC_step, burnin, T, T_min = args.N_STEPS, args.MC_STEP, args.BURNIN, args.T_INIT, args.T_FINAL
|
|
71
71
|
mode = args.METHOD
|
|
72
|
+
bw_paths = args.BW_FILES
|
|
72
73
|
|
|
73
74
|
# Simulation Strengths
|
|
74
75
|
f, f2, b, kappa = args.FOLDING_COEFF, args.FOLDING_COEFF2, args.BIND_COEFF, args.CROSS_COEFF
|
|
76
|
+
r = args.BW_STRENGTHS
|
|
75
77
|
|
|
76
78
|
# Definition of region
|
|
77
79
|
region, chrom = [args.REGION_START,args.REGION_END], args.CHROM
|
|
@@ -81,12 +83,12 @@ def main():
|
|
|
81
83
|
bedpe_file = args.BEDPE_PATH
|
|
82
84
|
|
|
83
85
|
# Run Simulation
|
|
84
|
-
sim = StochasticSimulation(region,chrom,bedpe_file,out_dir=output_name,N_beads=N_beads,N_lef=N_lef,N_lef2=N_lef2)
|
|
85
|
-
Es, Ms, Ns, Bs, Ks, Fs, ufs = sim.run_energy_minimization(N_steps,MC_step,burnin,T,T_min,mode=mode,viz=args.SAVE_PLOTS,save=args.SAVE_MDT,lef_rw=args.LEF_RW,f=f,f2=f2,b=b,kappa=kappa,lef_drift=args.LEF_DRIFT,cross_loop=args.CROSS_LOOP)
|
|
86
|
+
sim = StochasticSimulation(region,chrom,bedpe_file,out_dir=output_name,N_beads=N_beads,N_lef=N_lef,N_lef2=N_lef2, bw_files=bw_paths, track_file=args.LEF_TRACK_FILE)
|
|
87
|
+
Es, Ms, Ns, Bs, Ks, Fs, ufs = sim.run_energy_minimization(N_steps,MC_step,burnin,T,T_min,mode=mode,viz=args.SAVE_PLOTS,save=args.SAVE_MDT,lef_rw=args.LEF_RW,f=f,f2=f2,b=b,kappa=kappa,lef_drift=args.LEF_DRIFT,cross_loop=args.CROSS_LOOP,r=r)
|
|
86
88
|
if args.SIMULATION_TYPE=='EM':
|
|
87
89
|
sim.run_EM(args.PLATFORM,args.ANGLE_FF_STRENGTH,args.LE_FF_LENGTH,args.LE_FF_STRENGTH,args.EV_FF_STRENGTH,args.EV_FF_POWER,args.TOLERANCE,args.FRICTION,args.INTEGRATOR_STEP,args.SIM_TEMP,args.INITIAL_STRUCTURE_TYPE,args.VIZ_HEATS,args.FORCEFIELD_PATH)
|
|
88
90
|
elif args.SIMULATION_TYPE=='MD':
|
|
89
|
-
sim.run_MD(args.PLATFORM,args.ANGLE_FF_STRENGTH,args.LE_FF_LENGTH,args.LE_FF_STRENGTH,args.EV_FF_STRENGTH,args.EV_FF_POWER,args.TOLERANCE,args.FRICTION,args.INTEGRATOR_STEP,args.SIM_TEMP,args.INITIAL_STRUCTURE_TYPE,args.SIM_STEP,args.VIZ_HEATS,args.FORCEFIELD_PATH,args.EV_P)
|
|
91
|
+
sim.run_MD(args.PLATFORM,args.ANGLE_FF_STRENGTH,args.LE_FF_LENGTH,args.LE_FF_STRENGTH,args.EV_FF_STRENGTH,args.EV_FF_POWER,args.TOLERANCE,args.FRICTION,args.INTEGRATOR_STEP,args.SIM_TEMP,args.INITIAL_STRUCTURE_TYPE,args.SIM_STEP,args.VIZ_HEATS,args.FORCEFIELD_PATH,args.EV_P,args.CONTINUOUS_TOP)
|
|
90
92
|
elif args.SIMULATION_TYPE==None:
|
|
91
93
|
print('\n3D simulation did not run because it was not specified. Please specify argument SIMULATION_TYPE as EM or MD.')
|
|
92
94
|
else:
|
|
@@ -66,12 +66,23 @@ def E_fold(ms, ns, fold_norm):
|
|
|
66
66
|
return fold_norm * folding
|
|
67
67
|
|
|
68
68
|
@njit
|
|
69
|
-
def
|
|
69
|
+
def E_bw(N_bws, r, BWs, ms, ns):
|
|
70
|
+
'''
|
|
71
|
+
Calculation of the RNApII binding energy. Needs cohesins positions as input.
|
|
72
|
+
'''
|
|
73
|
+
E_bw = 0
|
|
74
|
+
for i in range(N_bws):
|
|
75
|
+
E_bw += r[i] * np.sum(BWs[i, ms] + BWs[i, ns]) / np.sum(BWs[i])
|
|
76
|
+
return E_bw
|
|
77
|
+
|
|
78
|
+
@njit
|
|
79
|
+
def get_E(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, N_lef, N_lef2, cross_loop, r=None, N_bws=0, BWs=None):
|
|
70
80
|
''''
|
|
71
81
|
The total energy.
|
|
72
82
|
'''
|
|
73
83
|
energy = E_bind(L, R, ms, ns, bind_norm) + E_cross(ms, ns, k_norm, cross_loop) + E_fold(ms, ns, fold_norm)
|
|
74
84
|
if fold_norm2!=0: energy += E_fold(ms[N_lef:N_lef+N_lef2],ns[N_lef:N_lef+N_lef2], fold_norm2)
|
|
85
|
+
if r is not None and BWs is not None: energy += E_bw(N_bws, r, BWs, ms, ns)
|
|
75
86
|
return energy
|
|
76
87
|
|
|
77
88
|
@njit
|
|
@@ -88,6 +99,13 @@ def get_dE_fold(fold_norm,ms,ns,m_new,n_new,idx):
|
|
|
88
99
|
'''
|
|
89
100
|
return fold_norm*(np.log(n_new-m_new)-np.log(ns[idx]-ms[idx]))
|
|
90
101
|
|
|
102
|
+
@njit
|
|
103
|
+
def get_dE_bw(N_bws, r, BWs, ms, ns, m_new, n_new, idx):
|
|
104
|
+
dE_bw = 0
|
|
105
|
+
for i in range(N_bws):
|
|
106
|
+
dE_bw += r[i] * (BWs[i, m_new] + BWs[i, n_new] - BWs[i, ms[idx]] - BWs[i, ns[idx]]) / np.sum(BWs[i])
|
|
107
|
+
return dE_bw
|
|
108
|
+
|
|
91
109
|
@njit
|
|
92
110
|
def get_dE_cross(ms, ns, m_new, n_new, idx, k_norm, cross_loop):
|
|
93
111
|
'''
|
|
@@ -101,7 +119,7 @@ def get_dE_cross(ms, ns, m_new, n_new, idx, k_norm, cross_loop):
|
|
|
101
119
|
return k_norm * (K2 - K1)
|
|
102
120
|
|
|
103
121
|
@njit
|
|
104
|
-
def get_dE(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, m_new, n_new, idx, N_lef, N_lef2, cross_loop):
|
|
122
|
+
def get_dE(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, m_new, n_new, idx, N_lef, N_lef2, cross_loop, r=None, N_bws=0, BWs=None):
|
|
105
123
|
'''
|
|
106
124
|
Total energy difference.
|
|
107
125
|
'''
|
|
@@ -112,14 +130,19 @@ def get_dE(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, m_new, n_new,
|
|
|
112
130
|
dE += get_dE_fold(fold_norm2,ms[N_lef:N_lef+N_lef2],ns[N_lef:N_lef+N_lef2],m_new,n_new,idx-N_lef)
|
|
113
131
|
dE += get_dE_bind(L, R, bind_norm, ms, ns, m_new, n_new, idx)
|
|
114
132
|
dE += get_dE_cross(ms, ns, m_new, n_new, idx, k_norm, cross_loop)
|
|
133
|
+
if r is not None and BWs is not None: dE += get_dE_bw(N_bws, r, BWs, ms, ns, m_new, n_new, idx)
|
|
115
134
|
return dE
|
|
116
135
|
|
|
117
136
|
@njit
|
|
118
|
-
def unbind_bind(N_beads):
|
|
137
|
+
def unbind_bind(N_beads, track=None):
|
|
119
138
|
'''
|
|
120
139
|
Rebinding Monte-Carlo step.
|
|
121
140
|
'''
|
|
122
|
-
|
|
141
|
+
if track is not None:
|
|
142
|
+
weights = track / np.sum(track)
|
|
143
|
+
m_new = np.searchsorted(np.cumsum(weights), np.random.rand())
|
|
144
|
+
else:
|
|
145
|
+
m_new = np.random.randint(0, N_beads - 3)
|
|
123
146
|
n_new = m_new + 2
|
|
124
147
|
return int(m_new), int(n_new)
|
|
125
148
|
|
|
@@ -152,58 +175,58 @@ def unfolding_metric(ms,ns,N_beads):
|
|
|
152
175
|
return unfold
|
|
153
176
|
|
|
154
177
|
@njit
|
|
155
|
-
def initialize(N_beads,N_lef):
|
|
178
|
+
def initialize(N_beads, N_lef, track=None):
|
|
156
179
|
'''
|
|
157
180
|
Random initialization of polymer DNA fiber with some cohesin positions.
|
|
158
181
|
'''
|
|
159
182
|
ms, ns = np.zeros(N_lef,dtype=np.int64), np.zeros(N_lef,dtype=np.int64)
|
|
160
183
|
for i in range(N_lef):
|
|
161
|
-
ms[i], ns[i] = unbind_bind(N_beads)
|
|
184
|
+
ms[i], ns[i] = unbind_bind(N_beads, track)
|
|
162
185
|
return ms, ns
|
|
163
186
|
|
|
164
187
|
@njit
|
|
165
|
-
def run_simulation(N_beads,N_steps,MC_step,burnin,T,T_min,fold_norm,fold_norm2,bind_norm,k_norm,N_lef,N_lef2,L,R,mode,lef_rw=True,lef_drift=True,cross_loop=True):
|
|
188
|
+
def run_simulation(N_beads, N_steps, MC_step, burnin, T, T_min, fold_norm, fold_norm2, bind_norm, k_norm, N_lef, N_lef2, L, R, mode, lef_rw=True, lef_drift=True, cross_loop=True, r=None, N_bws=0, BWs=None, track=None):
|
|
166
189
|
'''
|
|
167
190
|
Runs the Monte Carlo simulation.
|
|
168
191
|
'''
|
|
169
192
|
Ti = T
|
|
170
|
-
bi = burnin//MC_step
|
|
171
|
-
ms, ns = initialize(N_beads,N_lef+N_lef2)
|
|
172
|
-
E = get_E(L, R, bind_norm, fold_norm, fold_norm2, k_norm,
|
|
173
|
-
Es,Ks,Fs,Bs,ufs = np.zeros(N_steps//MC_step, dtype=np.float64),np.zeros(N_steps//MC_step, dtype=np.float64),np.zeros(N_steps//MC_step, dtype=np.float64),np.zeros(N_steps//MC_step, dtype=np.float64),np.zeros(N_steps//MC_step, dtype=np.float64)
|
|
174
|
-
Ms, Ns = np.zeros((N_lef+N_lef2,N_steps//MC_step), dtype=np.int64), np.zeros((N_lef+N_lef2,N_steps//MC_step), dtype=np.int64)
|
|
193
|
+
bi = burnin // MC_step
|
|
194
|
+
ms, ns = initialize(N_beads, N_lef + N_lef2, track)
|
|
195
|
+
E = get_E(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, N_lef, N_lef2, cross_loop, r, N_bws, BWs)
|
|
196
|
+
Es, Ks, Fs, Bs, ufs = np.zeros(N_steps // MC_step, dtype=np.float64), np.zeros(N_steps // MC_step, dtype=np.float64), np.zeros(N_steps // MC_step, dtype=np.float64), np.zeros(N_steps // MC_step, dtype=np.float64), np.zeros(N_steps // MC_step, dtype=np.float64)
|
|
197
|
+
Ms, Ns = np.zeros((N_lef + N_lef2, N_steps // MC_step), dtype=np.int64), np.zeros((N_lef + N_lef2, N_steps // MC_step), dtype=np.int64)
|
|
175
198
|
|
|
176
199
|
for i in range(N_steps):
|
|
177
|
-
Ti = T-(T-T_min)*(i+1)/N_steps if mode=='Annealing' else T
|
|
178
|
-
for j in range(N_lef+N_lef2):
|
|
200
|
+
Ti = T - (T - T_min) * (i + 1) / N_steps if mode == 'Annealing' else T
|
|
201
|
+
for j in range(N_lef + N_lef2):
|
|
179
202
|
# Randomly choose a move (sliding or rebinding)
|
|
180
|
-
|
|
181
|
-
if
|
|
182
|
-
m_new, n_new = unbind_bind(N_beads)
|
|
203
|
+
r_move = np.random.choice(np.array([0, 1]))
|
|
204
|
+
if r_move == 0:
|
|
205
|
+
m_new, n_new = unbind_bind(N_beads, track)
|
|
183
206
|
else:
|
|
184
|
-
m_new, n_new = slide(ms[j],ns[j],ms,ns,N_beads,lef_rw,lef_drift)
|
|
207
|
+
m_new, n_new = slide(ms[j], ns[j], ms, ns, N_beads, lef_rw, lef_drift)
|
|
185
208
|
|
|
186
209
|
# Compute energy difference
|
|
187
|
-
dE = get_dE(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, m_new, n_new, j, N_lef, N_lef2, cross_loop)
|
|
210
|
+
dE = get_dE(L, R, bind_norm, fold_norm, fold_norm2, k_norm, ms, ns, m_new, n_new, j, N_lef, N_lef2, cross_loop, r, N_bws, BWs)
|
|
188
211
|
|
|
189
|
-
if dE <= 0 or np.exp(-dE/Ti) > np.random.rand():
|
|
212
|
+
if dE <= 0 or np.exp(-dE / Ti) > np.random.rand():
|
|
190
213
|
ms[j], ns[j] = m_new, n_new
|
|
191
214
|
E += dE
|
|
192
215
|
# Compute Metrics
|
|
193
|
-
if i%MC_step==0:
|
|
194
|
-
Ms[j,i//MC_step], Ns[j,i//MC_step] = ms[j], ns[j]
|
|
216
|
+
if i % MC_step == 0:
|
|
217
|
+
Ms[j, i // MC_step], Ns[j, i // MC_step] = ms[j], ns[j]
|
|
195
218
|
|
|
196
219
|
# Compute Metrics
|
|
197
|
-
if i%MC_step==0:
|
|
198
|
-
ufs[i//MC_step] = unfolding_metric(ms,ns,N_beads)
|
|
199
|
-
Es[i//MC_step] = E
|
|
200
|
-
Ks[i//MC_step] = E_cross(ms,ns,k_norm,cross_loop)
|
|
201
|
-
Fs[i//MC_step] = E_fold(ms,ns,fold_norm)
|
|
202
|
-
Bs[i//MC_step] = E_bind(L,R,ms,ns,bind_norm)
|
|
220
|
+
if i % MC_step == 0:
|
|
221
|
+
ufs[i // MC_step] = unfolding_metric(ms, ns, N_beads)
|
|
222
|
+
Es[i // MC_step] = E
|
|
223
|
+
Ks[i // MC_step] = E_cross(ms, ns, k_norm, cross_loop)
|
|
224
|
+
Fs[i // MC_step] = E_fold(ms, ns, fold_norm)
|
|
225
|
+
Bs[i // MC_step] = E_bind(L, R, ms, ns, bind_norm)
|
|
203
226
|
return Ms, Ns, Es, Ks, Fs, Bs, ufs
|
|
204
227
|
|
|
205
228
|
class StochasticSimulation:
|
|
206
|
-
def __init__(self,region,chrom,bedpe_file,N_beads=None,N_lef=None,N_lef2=0,out_dir=None):
|
|
229
|
+
def __init__(self,region,chrom,bedpe_file,N_beads=None,N_lef=None,N_lef2=0,out_dir=None, bw_files=None, track_file=None):
|
|
207
230
|
'''
|
|
208
231
|
Definition of simulation parameters and input files.
|
|
209
232
|
|
|
@@ -218,16 +241,17 @@ class StochasticSimulation:
|
|
|
218
241
|
r (list): strength of each ChIP-Seq experinment.
|
|
219
242
|
'''
|
|
220
243
|
self.N_beads = N_beads if N_beads!=None else int(np.round((region[1]-region[0])/2000))
|
|
244
|
+
self.N_bws = len(bw_files) if bw_files else 0
|
|
221
245
|
print('Number of beads:',self.N_beads)
|
|
222
246
|
self.chrom, self.region = chrom, region
|
|
223
|
-
self.bedpe_file = bedpe_file
|
|
247
|
+
self.bedpe_file, self.bw_files, self.track_file = bedpe_file, bw_files, track_file
|
|
224
248
|
self.preprocessing()
|
|
225
249
|
self.N_lef = 2*self.N_CTCF if N_lef==None else N_lef
|
|
226
250
|
self.N_lef2 = N_lef2
|
|
227
251
|
print('Number of LEFs:',self.N_lef+self.N_lef2)
|
|
228
252
|
self.path = make_folder(out_dir)
|
|
229
253
|
|
|
230
|
-
def run_energy_minimization(self,N_steps,MC_step,burnin,T=1,T_min=0,mode='Metropolis',viz=False,save=False, f=1.0, f2=0.0, b=1.0, kappa=1.0, lef_rw=True, lef_drift=True, cross_loop=True):
|
|
254
|
+
def run_energy_minimization(self, N_steps, MC_step, burnin, T=1, T_min=0, mode='Metropolis', viz=False, save=False, f=1.0, f2=0.0, b=1.0, kappa=1.0, lef_rw=True, lef_drift=True, cross_loop=True, r=None):
|
|
231
255
|
'''
|
|
232
256
|
Implementation of the stochastic Monte Carlo simulation.
|
|
233
257
|
|
|
@@ -238,34 +262,40 @@ class StochasticSimulation:
|
|
|
238
262
|
T (float): simulation (initial) temperature.
|
|
239
263
|
mode (str): it can be either 'Metropolis' or 'Annealing'.
|
|
240
264
|
viz (bool): True in case that user wants to see plots.
|
|
265
|
+
r (list): strength of each ChIP-Seq experiment.
|
|
266
|
+
N_bws (int): number of binding weight matrices.
|
|
267
|
+
BWs (np.ndarray): binding weight matrices.
|
|
241
268
|
'''
|
|
242
269
|
# Define normalization constants
|
|
243
270
|
fold_norm, fold_norm2, bind_norm, k_norm = -self.N_beads*f/((self.N_lef+self.N_lef2)*np.log(self.N_beads/(self.N_lef+self.N_lef2))), -self.N_beads*f2/((self.N_lef+self.N_lef2)*np.log(self.N_beads/(self.N_lef+self.N_lef2))), -self.N_beads*b/(np.sum(self.L)+np.sum(self.R)), kappa*1e4
|
|
244
271
|
self.N_steps, self.MC_step = N_steps, MC_step
|
|
272
|
+
r = np.full(self.N_bws, -self.N_beads / 10) if not r and self.N_bws > 0 else (None if not r else r)
|
|
245
273
|
|
|
246
274
|
# Run simulation
|
|
247
275
|
print('\nRunning simulation (with parallelization across CPU cores)...')
|
|
248
276
|
start = time.time()
|
|
249
277
|
self.burnin = burnin
|
|
250
|
-
self.Ms, self.Ns, self.Es, self.Ks, self.Fs, self.Bs, self.ufs = run_simulation(self.N_beads,N_steps,MC_step,burnin,T,T_min,fold_norm,fold_norm2,bind_norm,k_norm,self.N_lef,self.N_lef2,self.L,self.R,mode,lef_rw,lef_drift,cross_loop)
|
|
278
|
+
self.Ms, self.Ns, self.Es, self.Ks, self.Fs, self.Bs, self.ufs = run_simulation(self.N_beads, N_steps, MC_step, burnin, T, T_min, fold_norm, fold_norm2, bind_norm, k_norm, self.N_lef, self.N_lef2, self.L, self.R, mode, lef_rw, lef_drift, cross_loop, r, self.N_bws, self.BWs, self.lef_track)
|
|
251
279
|
end = time.time()
|
|
252
280
|
elapsed = end - start
|
|
253
|
-
print(f'Computation finished
|
|
254
|
-
|
|
281
|
+
print(f'Computation finished successfully in {elapsed//3600:.0f} hours, {elapsed%3600//60:.0f} minutes and {elapsed%60:.0f} seconds.')
|
|
282
|
+
|
|
255
283
|
# Save simulation info
|
|
256
284
|
if save:
|
|
257
285
|
save_dir = os.path.join(self.path, 'other') + '/'
|
|
258
|
-
with open(save_dir + 'info.txt', "w") as
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
286
|
+
with open(save_dir + 'info.txt', "w") as file:
|
|
287
|
+
file.write(f'Number of beads {self.N_beads}.\n')
|
|
288
|
+
file.write(f'Number of cohesins {self.N_lef}. Number of cohesins in second family {self.N_lef2}. Number of CTCFs {self.N_CTCF}. \n')
|
|
289
|
+
file.write(f'Bedpe file for CTCF binding is {self.bedpe_file}.\n')
|
|
290
|
+
file.write(f'Initial temperature {T}. Minimum temperature {T_min}.\n')
|
|
291
|
+
file.write(f'Monte Carlo optimization method: {mode}.\n')
|
|
292
|
+
file.write(f'Monte Carlo steps {N_steps}. Sampling frequency {self.MC_step}. Burnin period {burnin}.\n')
|
|
293
|
+
file.write(f'Crossing energy in equilibrium is {np.average(self.Ks[burnin//MC_step:]):.2f}. Crossing coefficient kappa={kappa}.\n')
|
|
294
|
+
file.write(f'Folding energy in equilibrium is {np.average(self.Fs[burnin//MC_step:]):.2f}. Folding coefficient f={f}. Folding coefficient for the second family f2={f2}\n')
|
|
295
|
+
file.write(f'Binding energy in equilibrium is {np.average(self.Bs[burnin//MC_step:]):.2f}. Binding coefficient b={b}.\n')
|
|
296
|
+
if r is not None and self.BWs is not None:
|
|
297
|
+
file.write(f'RNApII binding energy included with {N_bws} binding weight matrices.\n')
|
|
298
|
+
file.write(f'Energy at equilibrium: {np.average(self.Es[self.burnin//MC_step:]):.2f}.\n')
|
|
269
299
|
np.save(save_dir + 'Ms.npy', self.Ms)
|
|
270
300
|
np.save(save_dir + 'Ns.npy', self.Ns)
|
|
271
301
|
np.save(save_dir + 'ufs.npy', self.ufs)
|
|
@@ -274,16 +304,27 @@ class StochasticSimulation:
|
|
|
274
304
|
np.save(save_dir + 'Fs.npy', self.Fs)
|
|
275
305
|
np.save(save_dir + 'Ks.npy', self.Ks)
|
|
276
306
|
|
|
277
|
-
# Some
|
|
278
|
-
if viz: coh_traj_plot(self.Ms,self.Ns,self.N_beads, self.path)
|
|
307
|
+
# Some visualizations
|
|
308
|
+
if viz: coh_traj_plot(self.Ms, self.Ns, self.N_beads, self.path)
|
|
279
309
|
if viz: make_timeplots(self.Es, self.Bs, self.Ks, self.Fs, burnin//MC_step, mode, self.path)
|
|
280
|
-
if viz: coh_probdist_plot(self.Ms,self.Ns,self.N_beads,self.path)
|
|
281
|
-
if viz and self.N_beads<=2000: stochastic_heatmap(self.Ms,self.Ns,MC_step,self.N_beads,self.path)
|
|
310
|
+
if viz: coh_probdist_plot(self.Ms, self.Ns, self.N_beads, self.path)
|
|
311
|
+
if viz and self.N_beads <= 2000: stochastic_heatmap(self.Ms, self.Ns, MC_step, self.N_beads, self.path)
|
|
282
312
|
|
|
283
313
|
return self.Es, self.Ms, self.Ns, self.Bs, self.Ks, self.Fs, self.ufs
|
|
284
314
|
|
|
285
315
|
def preprocessing(self):
|
|
286
316
|
self.L, self.R, self.dists = binding_vectors_from_bedpe(self.bedpe_file,self.N_beads,self.region,self.chrom,False,False)
|
|
317
|
+
if not self.bw_files:
|
|
318
|
+
self.BWs = None
|
|
319
|
+
self.N_bws = 0
|
|
320
|
+
else:
|
|
321
|
+
if isinstance(self.bw_files, str):
|
|
322
|
+
self.bw_files = [self.bw_files]
|
|
323
|
+
self.N_bws = 1
|
|
324
|
+
self.BWs = np.zeros((self.N_bws, self.N_beads))
|
|
325
|
+
for i, f in enumerate(self.bw_files):
|
|
326
|
+
self.BWs[i, :] = load_track(file=f, region=self.region, chrom=self.chrom, N_beads=self.N_beads, viz=False)
|
|
327
|
+
self.lef_track = load_track(self.track_file,self.region,self.chrom,self.N_beads,False,True) if self.track_file else None
|
|
287
328
|
self.N_CTCF = np.max([np.count_nonzero(self.L),np.count_nonzero(self.R)])
|
|
288
329
|
print('Number of CTCF:',self.N_CTCF)
|
|
289
330
|
|
|
@@ -292,9 +333,9 @@ class StochasticSimulation:
|
|
|
292
333
|
sim_heat = em.run_pipeline(plots=save_plots,friction=friction,integrator_step=integrator_step,temperature=temperature,ff_path=ff_path,init_struct=init_struct)
|
|
293
334
|
corr_exp_heat(sim_heat,self.bedpe_file,self.region,self.chrom,self.N_beads,self.path)
|
|
294
335
|
|
|
295
|
-
def run_MD(self,platform='CPU',angle_ff_strength=200,le_distance=0.1,le_ff_strength=50000.0,ev_ff_strength=100.0,ev_ff_power=3.0,tolerance=0.001,friction=0.1,integrator_step=100*mm.unit.femtosecond,temperature=310,init_struct='rw',sim_step=1000,save_plots=True,ff_path=default_xml_path,p_ev=0):
|
|
336
|
+
def run_MD(self,platform='CPU',angle_ff_strength=200,le_distance=0.1,le_ff_strength=50000.0,ev_ff_strength=100.0,ev_ff_power=3.0,tolerance=0.001,friction=0.1,integrator_step=100*mm.unit.femtosecond,temperature=310,init_struct='rw',sim_step=1000,save_plots=True,ff_path=default_xml_path,p_ev=0,continuous_topoisomerase=False):
|
|
296
337
|
md = MD_LE(self.Ms,self.Ns,self.N_beads,self.path,platform,angle_ff_strength,le_distance,le_ff_strength,ev_ff_strength,ev_ff_power,tolerance)
|
|
297
|
-
sim_heat = md.run_pipeline(plots=save_plots,sim_step=sim_step,friction=friction,integrator_step=integrator_step,temperature=temperature,ff_path=ff_path,p_ev=p_ev,init_struct=init_struct)
|
|
338
|
+
sim_heat = md.run_pipeline(plots=save_plots,sim_step=sim_step,friction=friction,integrator_step=integrator_step,temperature=temperature,ff_path=ff_path,p_ev=p_ev,init_struct=init_struct,continuous_topoisomerase=continuous_topoisomerase)
|
|
298
339
|
corr_exp_heat(sim_heat,self.bedpe_file,self.region,self.chrom,self.N_beads,self.path)
|
|
299
340
|
|
|
300
341
|
def main():
|
|
@@ -311,12 +352,12 @@ def main():
|
|
|
311
352
|
region, chrom = [15550000,16850000], 'chr6'
|
|
312
353
|
|
|
313
354
|
# Definition of data
|
|
314
|
-
output_name='
|
|
355
|
+
output_name='tmp'
|
|
315
356
|
bedpe_file = '/home/skorsak/Data/HiChIP/Maps/hg00731_smc1_maps_2.bedpe'
|
|
316
357
|
|
|
317
358
|
sim = StochasticSimulation(region,chrom,bedpe_file,out_dir=output_name,N_beads=1000,N_lef=N_lef,N_lef2=N_lef2)
|
|
318
359
|
Es, Ms, Ns, Bs, Ks, Fs, ufs = sim.run_energy_minimization(N_steps,MC_step,burnin,T,T_min,mode=mode,viz=True,save=True,f=f,f2=f2, b=b, kappa=kappa, lef_rw=lew_rw)
|
|
319
|
-
sim.
|
|
360
|
+
sim.run_MD('CUDA',continuous_topoisomerase=True, p_ev=0.01)
|
|
320
361
|
|
|
321
362
|
if __name__=='__main__':
|
|
322
|
-
main()
|
|
363
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyLoopSage
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: An energy-based stochastic model of loop extrusion in chromatin.
|
|
5
5
|
Home-page: https://github.com/SFGLab/pyLoopSage
|
|
6
6
|
Author: Sebastian Korsak
|
|
@@ -31,6 +31,7 @@ Requires-Dist: statsmodels
|
|
|
31
31
|
Requires-Dist: imageio
|
|
32
32
|
Requires-Dist: imageio[ffmpeg]
|
|
33
33
|
Requires-Dist: pillow
|
|
34
|
+
Requires-Dist: pyBigWig
|
|
34
35
|
Dynamic: author
|
|
35
36
|
Dynamic: author-email
|
|
36
37
|
Dynamic: classifier
|
|
@@ -271,49 +272,73 @@ An example, illustrated with Chimera software, simulated trajectory of structure
|
|
|
271
272
|
|
|
272
273
|
### Long-table of LoopSage arguments
|
|
273
274
|
|
|
275
|
+
#### General Settings
|
|
274
276
|
| Argument Name | Description | Type | Default Value |
|
|
275
277
|
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
276
278
|
| PLATFORM | Name of the platform. Available choices: CPU, CUDA, OpenCL | str | CPU |
|
|
277
279
|
| DEVICE | Device index for CUDA or OpenCL (count from 0) | str | None |
|
|
278
|
-
| N_BEADS | Number of Simulation Beads. | int | None |
|
|
279
|
-
| BEDPE_PATH | A .bedpe file path with loops. It is required. | str | None |
|
|
280
280
|
| OUT_PATH | Output folder name. | str | ../results |
|
|
281
|
+
| SAVE_MDT | True to save metadata of the stochastic simulation. | bool | True |
|
|
282
|
+
|
|
283
|
+
#### Input Data
|
|
284
|
+
| Argument Name | Description | Type | Default Value |
|
|
285
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
286
|
+
| BEDPE_PATH | A .bedpe file path with loops. It is required. | str | None |
|
|
287
|
+
| LEF_TRACK_FILE | Path to a bw file of cohesin or condensin density. If it is provided, then simulation LEFs preferentially bind in enriched regions. | str | None |
|
|
288
|
+
| BW_FILES | List of paths to .bw files containing additional data for simulation. Enriched regions would act as barriers for cohesin. | list | None |
|
|
281
289
|
| REGION_START | Starting region coordinate. | int | None |
|
|
282
290
|
| REGION_END | Ending region coordinate. | int | None |
|
|
283
291
|
| CHROM | Chromosome that corresponds to the modeling region of interest. | str | None |
|
|
284
|
-
|
|
285
|
-
|
|
292
|
+
|
|
293
|
+
#### Stochastic Simulation Parameters
|
|
294
|
+
| Argument Name | Description | Type | Default Value |
|
|
295
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
296
|
+
| N_BEADS | Number of Simulation Beads. | int | None |
|
|
286
297
|
| N_STEPS | Number of Monte Carlo steps. | int | 40000 |
|
|
287
|
-
| N_LEF | Number of loop extrusion factors. | int | None |
|
|
288
|
-
| N_LEF2 | Number of second family loop extrusion factors. | int | 0 |
|
|
289
298
|
| MC_STEP | Monte Carlo frequency to avoid autocorrelated ensembles. | int | 200 |
|
|
290
299
|
| BURNIN | Burn-in period (steps before equilibrium). | int | 1000 |
|
|
291
300
|
| T_INIT | Initial Temperature of the Stochastic Model. | float | 2.0 |
|
|
292
301
|
| T_FINAL | Final Temperature of the Stochastic Model. | float | 1.0 |
|
|
293
302
|
| METHOD | Stochastic modeling method (Metropolis or Simulated Annealing). | str | 'Annealing' |
|
|
303
|
+
| LEF_RW | True if cohesins slide as a random walk instead of one direction. | bool | True |
|
|
304
|
+
| LEF_DRIFT | True if LEFs are pushed back when they encounter other LEFs. | bool | False |
|
|
305
|
+
| N_LEF | Number of loop extrusion factors. | int | None |
|
|
306
|
+
| N_LEF2 | Number of second family loop extrusion factors. | int | 0 |
|
|
307
|
+
|
|
308
|
+
#### Energy Coefficients
|
|
309
|
+
| Argument Name | Description | Type | Default Value |
|
|
310
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
294
311
|
| FOLDING_COEFF | Folding coefficient. | float | 1.0 |
|
|
295
312
|
| FOLDING_COEFF2 | Folding coefficient for the second family of LEFs. | float | 0.0 |
|
|
296
313
|
| CROSS_COEFF | LEF crossing coefficient. | float | 1.0 |
|
|
297
314
|
| CROSS_LOOP | True if the penalty is applied when mi<mj<ni<nj. False if it applies only when mj=ni. When false it is better to enable LEF_DRIFT as well. | bool |True |
|
|
298
315
|
| BIND_COEFF | CTCF binding coefficient. | float | 1.0 |
|
|
299
|
-
|
|
|
300
|
-
|
|
301
|
-
|
|
316
|
+
| BW_STRENGTHS | List of strengths corresponding to each .bw file. | list | None |
|
|
317
|
+
|
|
318
|
+
#### Molecular Dynamics Simulation
|
|
319
|
+
| Argument Name | Description | Type | Default Value |
|
|
320
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
302
321
|
| SIMULATION_TYPE | Either EM (energy minimizations) or MD (molecular dynamics). | str | None |
|
|
322
|
+
| INITIAL_STRUCTURE_TYPE | Choose from: rw, confined_rw, self_avoiding_rw, helix, circle, spiral, sphere. | str | rw |
|
|
303
323
|
| INTEGRATOR_STEP | Step of the integrator. | Quantity | 100 femtosecond |
|
|
304
324
|
| FORCEFIELD_PATH | Path to XML file with forcefield. | str | default_xml_path |
|
|
305
325
|
| ANGLE_FF_STRENGTH | Angle force strength. | float | 200.0 |
|
|
306
326
|
| LE_FF_LENGTH | Equilibrium distance of loop forces. | float | 0.1 |
|
|
307
327
|
| LE_FF_STRENGTH | Interaction Strength of loop forces. | float | 50000.0 |
|
|
328
|
+
| CONTINUOUS_TOP | True if the topological constraints are applied continuously during the simulation. | bool | False |
|
|
308
329
|
| EV_P | Probability that excluded volume is disabled. Enable it only in case of topoisomerase activity simulation. | float | 0.0 |
|
|
309
330
|
| EV_FF_STRENGTH | Excluded-volume strength. | float | 100.0 |
|
|
310
331
|
| EV_FF_POWER | Excluded-volume power. | float | 3.0 |
|
|
311
332
|
| FRICTION | Friction coefficient of the Langevin integrator. | float | 0.1 |
|
|
312
333
|
| TOLERANCE | Stopping condition for energy minimization. | float | 0.001 |
|
|
313
|
-
| VIZ_HEATS | True to visualize the output average heatmap. | bool | True |
|
|
314
334
|
| SIM_TEMP | Temperature of the 3D simulation (EM or MD). | Quantity | 310 kelvin |
|
|
315
335
|
| SIM_STEP | Amount of simulation steps for loop force adjustments. | int | 1000 |
|
|
316
336
|
|
|
337
|
+
#### Visualization
|
|
338
|
+
| Argument Name | Description | Type | Default Value |
|
|
339
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------------|------------|---------------------|
|
|
340
|
+
| VIZ_HEATS | True to visualize the output average heatmap. | bool | True |
|
|
341
|
+
| SAVE_PLOTS | True to save diagnostic plots. | bool | True |
|
|
317
342
|
|
|
318
343
|
## Citation
|
|
319
344
|
Please cite the method and biological paper in case that you would like to use this model for your work,
|
|
@@ -6,7 +6,7 @@ with open('README.md', 'r', encoding='utf-8') as f:
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name='pyLoopSage', # Package name
|
|
9
|
-
version='1.0
|
|
9
|
+
version='1.1.0', # Version of the software
|
|
10
10
|
description='An energy-based stochastic model of loop extrusion in chromatin.',
|
|
11
11
|
long_description=long_description,
|
|
12
12
|
long_description_content_type='text/markdown',
|
|
@@ -39,6 +39,7 @@ setup(
|
|
|
39
39
|
'imageio',
|
|
40
40
|
'imageio[ffmpeg]',
|
|
41
41
|
'pillow',
|
|
42
|
+
'pyBigWig',
|
|
42
43
|
],
|
|
43
44
|
entry_points={
|
|
44
45
|
'console_scripts': [
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import topoly as tp
|
|
2
|
-
import numpy as np
|
|
3
|
-
import matplotlib
|
|
4
|
-
from tqdm import tqdm
|
|
5
|
-
import matplotlib
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
|
-
from mpl_toolkits.mplot3d import Axes3D
|
|
8
|
-
from mpl_toolkits.mplot3d.art3d import Line3DCollection
|
|
9
|
-
import matplotlib.colors as mcolors
|
|
10
|
-
import scipy.interpolate as si
|
|
11
|
-
from scipy.spatial.distance import pdist, squareform
|
|
12
|
-
from scipy.integrate import dblquad
|
|
13
|
-
from scipy.interpolate import splprep, splev, CubicSpline
|
|
14
|
-
from .uts import *
|
|
15
|
-
|
|
16
|
-
def trivial_knot(N=100, radius=1.0):
|
|
17
|
-
"""
|
|
18
|
-
Generate a 3D trivial (unknot) structure as a simple circle.
|
|
19
|
-
|
|
20
|
-
Parameters:
|
|
21
|
-
N (int): Number of points in the loop.
|
|
22
|
-
radius (float): Radius of the circular unknot.
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
numpy.ndarray: Nx3 array representing the 3D coordinates of the unknot.
|
|
26
|
-
"""
|
|
27
|
-
t = np.linspace(0, 2 * np.pi, N) # Parameter along the circle
|
|
28
|
-
x = radius * np.cos(t) # Circle in the xy-plane
|
|
29
|
-
y = radius * np.sin(t)
|
|
30
|
-
z = np.zeros_like(t) # No variation in z (flat circle)
|
|
31
|
-
|
|
32
|
-
return np.vstack((x, y, z)).T # Return as Nx3 matrix
|
|
33
|
-
|
|
34
|
-
def toroidal_knot(p, q, num_points=500, R=2, r=1):
|
|
35
|
-
"""
|
|
36
|
-
Generate a toroidal (p, q) knot.
|
|
37
|
-
|
|
38
|
-
Parameters:
|
|
39
|
-
p (int): Number of turns around the torus' central axis.
|
|
40
|
-
q (int): Number of turns around the torus' inner axis.
|
|
41
|
-
num_points (int): Number of points to plot.
|
|
42
|
-
R (float): Major radius of the torus (distance from center to torus tube).
|
|
43
|
-
r (float): Minor radius of the torus tube.
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
np.ndarray: Array of shape (num_points, 3) representing 3D coordinates of the knot.
|
|
47
|
-
"""
|
|
48
|
-
t = np.linspace(0, 2 * np.pi, num_points, endpoint=False)
|
|
49
|
-
|
|
50
|
-
# Parametric equations for the toroidal knot
|
|
51
|
-
x = (R + r * np.cos(q * t)) * np.cos(p * t)
|
|
52
|
-
y = (R + r * np.cos(q * t)) * np.sin(p * t)
|
|
53
|
-
z = r * np.sin(q * t)
|
|
54
|
-
V = np.column_stack((x, y, z))
|
|
55
|
-
V = np.vstack((V,[x[0],y[0],z[0]]))
|
|
56
|
-
return V
|
|
57
|
-
|
|
58
|
-
def trefoil_knot(N=200, scale=0.8, offset=(0, 0, 0), rotation=None):
|
|
59
|
-
"""Generate a 3D Trefoil Knot with transformations."""
|
|
60
|
-
t = np.linspace(0, 2 * np.pi-np.pi/36, N)
|
|
61
|
-
x = scale * (np.sin(t) + 2 * np.sin(2 * t)) + offset[0]
|
|
62
|
-
y = scale * (np.cos(t) - 2 * np.cos(2 * t)) + offset[1]
|
|
63
|
-
z = scale * (-np.sin(3 * t)) + offset[2]
|
|
64
|
-
|
|
65
|
-
V = np.vstack((x, y, z)).T
|
|
66
|
-
|
|
67
|
-
if rotation is not None:
|
|
68
|
-
V = np.dot(V, rotation) # Apply rotation matrix
|
|
69
|
-
|
|
70
|
-
return V
|
|
71
|
-
|
|
72
|
-
def cinquefoil_knot(N=300, scale=0.8, offset=(0, 0, 0), rotation=None):
|
|
73
|
-
"""Generate a 3D Cinquefoil (5_1) Knot with transformations."""
|
|
74
|
-
t = np.linspace(0, 2 * np.pi, N)
|
|
75
|
-
x = scale * (np.sin(2*t) + 2*np.sin(3*t))
|
|
76
|
-
y = scale * (np.cos(2*t) - 2*np.cos(3*t))
|
|
77
|
-
z = scale * (-np.sin(5*t))
|
|
78
|
-
|
|
79
|
-
V = np.vstack((x, y, z)).T
|
|
80
|
-
if rotation is not None:
|
|
81
|
-
V = np.dot(V, rotation) # Apply rotation
|
|
82
|
-
return V + np.array(offset) # Apply position offset
|
|
83
|
-
|
|
84
|
-
def random_rotation_matrix():
|
|
85
|
-
"""Generate a random 3D rotation matrix."""
|
|
86
|
-
theta, phi, z = np.random.uniform(0, 2*np.pi-np.pi/36, 3)
|
|
87
|
-
r = np.sqrt(z)
|
|
88
|
-
V = np.array([
|
|
89
|
-
[np.cos(theta) * np.cos(phi), -np.sin(theta), np.cos(theta) * np.sin(phi)],
|
|
90
|
-
[np.sin(theta) * np.cos(phi), np.cos(theta), np.sin(theta) * np.sin(phi)],
|
|
91
|
-
[-np.sin(phi), 0, np.cos(phi)]
|
|
92
|
-
])
|
|
93
|
-
return V
|
|
94
|
-
|
|
95
|
-
def smooth_linkage(start, end, N=50):
|
|
96
|
-
"""Generate a smooth linking curve between two knots."""
|
|
97
|
-
t = np.linspace(0, 1, N)
|
|
98
|
-
x = (1 - t) * start[0] + t * end[0]
|
|
99
|
-
y = (1 - t) * start[1] + t * end[1]
|
|
100
|
-
z = (1 - t) * start[2] + t * end[2]
|
|
101
|
-
return np.vstack((x, y, z)).T
|
|
102
|
-
|
|
103
|
-
def generate_knotted_structure(num_knots=5, N_per_knot=300):
|
|
104
|
-
"""Generate a large 3D knotted structure by linking multiple knots."""
|
|
105
|
-
knots = []
|
|
106
|
-
previous_end = None
|
|
107
|
-
|
|
108
|
-
for i in range(num_knots):
|
|
109
|
-
knot_type = np.random.choice(["trefoil", "figure_eight"])
|
|
110
|
-
offset = previous_end + np.random.uniform(-3.0, 3.0, size=3) if previous_end is not None else np.random.uniform(-5, 5, size=3)
|
|
111
|
-
scale = np.random.uniform(0.5, 1.0) # Vary knot sizes
|
|
112
|
-
rotation = random_rotation_matrix()
|
|
113
|
-
|
|
114
|
-
if knot_type == "trefoil":
|
|
115
|
-
knot = trefoil_knot(N=N_per_knot, scale=scale, offset=offset, rotation=rotation)
|
|
116
|
-
else:
|
|
117
|
-
knot = cinquefoil_knot(N=N_per_knot, scale=scale, offset=offset, rotation=rotation)
|
|
118
|
-
|
|
119
|
-
if previous_end is not None:
|
|
120
|
-
linkage = smooth_linkage(previous_end, knot[0], N=50) # Smooth connection
|
|
121
|
-
knots.append(linkage)
|
|
122
|
-
|
|
123
|
-
knots.append(knot)
|
|
124
|
-
previous_end = knot[-1]
|
|
125
|
-
|
|
126
|
-
return np.vstack(knots)
|
|
127
|
-
|
|
128
|
-
def smooth_knot_spline(V, num_interp=100, closed=True):
|
|
129
|
-
"""
|
|
130
|
-
Smoothly interpolates a 3D knot using a cubic spline.
|
|
131
|
-
|
|
132
|
-
Parameters:
|
|
133
|
-
V (numpy.ndarray): Nx3 array representing the 3D knot.
|
|
134
|
-
num_interp (int): Number of points in the interpolated knot.
|
|
135
|
-
closed (bool): Whether to enforce periodic boundary conditions for closed knots.
|
|
136
|
-
|
|
137
|
-
Returns:
|
|
138
|
-
numpy.ndarray: Smoothed Nx3 array of the interpolated knot.
|
|
139
|
-
"""
|
|
140
|
-
if V.shape[1] != 3:
|
|
141
|
-
raise ValueError("Input array V must have shape (N, 3)")
|
|
142
|
-
|
|
143
|
-
if len(V) < 4:
|
|
144
|
-
raise ValueError("At least 4 points are required for spline fitting.")
|
|
145
|
-
|
|
146
|
-
# Define the parameter t along the curve
|
|
147
|
-
t = np.linspace(0, 1, len(V))
|
|
148
|
-
|
|
149
|
-
# Interpolation points
|
|
150
|
-
t_new = np.linspace(0, 1, num_interp)
|
|
151
|
-
|
|
152
|
-
# Fit cubic splines separately for each coordinate
|
|
153
|
-
cs_x = CubicSpline(t, V[:, 0], bc_type='periodic' if closed else 'not-a-knot')
|
|
154
|
-
cs_y = CubicSpline(t, V[:, 1], bc_type='periodic' if closed else 'not-a-knot')
|
|
155
|
-
cs_z = CubicSpline(t, V[:, 2], bc_type='periodic' if closed else 'not-a-knot')
|
|
156
|
-
|
|
157
|
-
# Evaluate the splines
|
|
158
|
-
x_new = cs_x(t_new)
|
|
159
|
-
y_new = cs_y(t_new)
|
|
160
|
-
z_new = cs_z(t_new)
|
|
161
|
-
|
|
162
|
-
return np.vstack((x_new, y_new, z_new)).T
|
|
163
|
-
|
|
164
|
-
def link_number_ensemble(path,N_ens=1250,step=100):
|
|
165
|
-
nlinks = list()
|
|
166
|
-
Ms = np.load(path+'/other/Ms.npy')
|
|
167
|
-
Ns = np.load(path+'/other/Ns.npy')
|
|
168
|
-
for i in range(N_ens//step,N_ens,step):
|
|
169
|
-
V = uts.get_coordinates_cif(path+f'/ensemble/MDLE_{i+1}.cif')
|
|
170
|
-
ms, ns = Ms[:,i], Ns[:,i]
|
|
171
|
-
N_links, links = calculate_linking_number(V,ms,ns)
|
|
172
|
-
nlinks.append(N_links)
|
|
173
|
-
return nlinks
|
|
174
|
-
|
|
175
|
-
def calculate_linking_number(V,ms,ns):
|
|
176
|
-
links = list()
|
|
177
|
-
for i in tqdm(range(len(ms))):
|
|
178
|
-
for j in range(i+1,len(ms)):
|
|
179
|
-
if (ns[i]-ms[i])>5 and (ns[j]-ms[j])>5 and (((ms[i]<ns[i]) and (ns[i]<ms[j])) or ((ms[j]<ns[j]) and (ns[j]<ms[i]))):
|
|
180
|
-
loop1 = V[ms[i]:ns[i]]
|
|
181
|
-
loop1 = np.vstack((loop1,loop1[0,:]))
|
|
182
|
-
loop1 = smooth_knot_spline(loop1,2*len(loop1))
|
|
183
|
-
l1 = [list(loop1[i]) for i in range(len(loop1))]
|
|
184
|
-
loop2 = V[ms[j]:ns[j]]
|
|
185
|
-
loop2 = np.vstack((loop2,loop2[0,:]))
|
|
186
|
-
loop2 = smooth_knot_spline(loop2,2*len(loop2))
|
|
187
|
-
l2 = [list(loop2[i]) for i in range(len(loop2))]
|
|
188
|
-
links.append(tp.gln(l1,l2))
|
|
189
|
-
links = np.array(links)
|
|
190
|
-
links = links[links>0.5]
|
|
191
|
-
N_links = len(links)
|
|
192
|
-
|
|
193
|
-
return N_links, links
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|