1
"""
2
Tests tleap tools.
3
"""
4 12
import logging
5 12
import os
6 12
import random as random
7 12
import shutil
8 12
import subprocess as sp
9

10 12
import numpy as np
11 12
import parmed as pmd
12 12
import pytest
13

14 12
from paprika.align import zalign
15 12
from paprika.dummy import add_dummy, write_dummy_frcmod, write_dummy_mol2
16 12
from paprika.tleap import ANGSTROM_CUBED_TO_LITERS, System
17 12
from paprika.utils import is_file_and_not_empty
18

19 12
logger = logging.getLogger(__name__)
20

21

22 12
@pytest.fixture
23 12
def clean_files(directory=os.path.join(os.path.dirname(__file__), "tmp")):
24
    # This happens before the test function call
25 12
    if os.path.isdir(directory):
26 0
        shutil.rmtree(directory)
27 12
    os.makedirs(directory)
28 12
    yield
29
    # This happens after the test function call
30 12
    shutil.rmtree(directory)
31

32

33 12
@pytest.mark.slow
34
def test_solvation_simple(clean_files):
35
    """ Test that we can solvate CB6-BUT using default settings. """
36 12
    waters = np.random.randint(100, 10000)
37 12
    logger.debug("Trying {} waters with default settings...".format(waters))
38 12
    sys = System()
39 12
    sys.template_file = os.path.join(
40
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
41
    )
42 12
    sys.output_path = "tmp"
43 12
    sys.target_waters = waters
44 12
    sys.output_prefix = "solvate"
45 12
    sys.build()
46 12
    grepped_waters = sp.check_output(
47
        ["grep -oh 'WAT' ./tmp/solvate.prmtop | wc -w"], shell=True
48
    )
49 12
    assert int(grepped_waters) == waters
50

51

52 12
@pytest.mark.parametrize("shape", ["octahedral", "cubic"])
53
def test_solvation_shapes(shape, clean_files):
54
    """ Test that we can solvate CB6-BUT with a truncated octahedron. """
55 12
    waters = np.random.randint(1000, 10000)
56 12
    logger.debug("Trying {} waters in a truncated octahedron...".format(waters))
57 12
    sys = System()
58 12
    sys.template_file = os.path.join(
59
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
60
    )
61 12
    sys.output_path = "tmp"
62 12
    sys.loadpdb_file = os.path.join(
63
        os.path.dirname(__file__), "../data/cb6-but/cb6-but.pdb"
64
    )
65 12
    sys.target_waters = waters
66 12
    sys.output_prefix = "solvate"
67 12
    sys.pbc_type = shape
68 12
    sys.build()
69 12
    grepped_waters = sp.check_output(
70
        ["grep -oh 'WAT' ./tmp/solvate.prmtop | wc -w"], shell=True
71
    )
72 12
    assert int(grepped_waters) == waters
73

74

75 12
@pytest.mark.slow
76
def test_solvation_spatial_size(clean_files):
77
    """ Test that we can solvate CB6-BUT with an buffer size in Angstroms. """
78 12
    random_int = np.random.randint(10, 20)
79 12
    random_size = random_int * np.random.random_sample(1) + random_int
80 12
    logger.debug("Trying buffer size of {} A...".format(random_size[0]))
81 12
    sys = System()
82 12
    sys.template_file = os.path.join(
83
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
84
    )
85 12
    sys.output_path = "tmp"
86 12
    sys.loadpdb_file = os.path.join(
87
        os.path.dirname(__file__), "../data/cb6-but/cb6-but.pdb"
88
    )
89 12
    sys.buffer_value = float(random_size[0])
90 12
    sys.output_prefix = "solvate"
91 12
    sys.pbc_type = "cubic"
92 12
    sys.build()
93 12
    grepped_waters = sp.check_output(
94
        ["grep -oh 'WAT' ./tmp/solvate.prmtop | wc -w"], shell=True
95
    )
96 12
    assert int(grepped_waters) == sys.target_waters
97

98

99 12
@pytest.mark.slow
100
def test_solvation_potassium_control(clean_files):
101
    """ Test there is no potassium by default. A negative control. """
102 12
    waters = np.random.randint(1000, 10000)
103 12
    logger.debug("Trying {} waters with potassium...".format(waters))
104 12
    sys = System()
105 12
    sys.template_file = os.path.join(
106
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
107
    )
108 12
    sys.output_path = "tmp"
109 12
    sys.loadpdb_file = os.path.join(
110
        os.path.dirname(__file__), "../data/cb6-but/cb6-but.pdb"
111
    )
112 12
    sys.target_waters = waters
113 12
    sys.output_prefix = "solvate"
114 12
    sys.counter_cation = "K+"
115 12
    sys.build()
116 12
    potassium = sp.check_output(
117
        ["grep -oh 'K+' ./tmp/solvate.prmtop | wc -w"], shell=True
118
    )
119 12
    assert int(potassium) == 0
120

121

122 12
@pytest.mark.slow
123
def test_solvation_with_additional_ions(clean_files):
124
    """ Test that we can solvate CB6-BUT with additional ions. """
125 12
    waters = np.random.randint(1000, 10000)
126 12
    cations = ["LI", "Na+", "K+", "RB", "CS"]
127 12
    anions = ["F", "Cl-", "BR", "IOD"]
128 12
    n_cations = np.random.randint(1, 10)
129 12
    n_anions = np.random.randint(1, 10)
130 12
    random_cation = random.choice(cations)
131 12
    random_anion = random.choice(anions)
132 12
    logger.debug("Trying {} waters with additional ions...".format(waters))
133 12
    sys = System()
134 12
    sys.template_file = os.path.join(
135
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
136
    )
137 12
    sys.output_path = "tmp"
138 12
    sys.loadpdb_file = os.path.join(
139
        os.path.dirname(__file__), "../data/cb6-but/cb6-but.pdb"
140
    )
141 12
    sys.target_waters = waters
142 12
    sys.output_prefix = "solvate"
143 12
    sys.neutralize = False
144 12
    sys.add_ions = [random_cation, n_cations, random_anion, n_anions]
145 12
    sys.build()
146
    # These should come in the RESIDUE_LABEL region of the prmtop and be before all the water.
147 12
    cation_number = sp.check_output(
148
        [
149
            "grep -A 99 RESIDUE_LABEL ./tmp/solvate.prmtop | "
150
            + "grep -oh '{} ' | wc -w".format(random_cation)
151
        ],
152
        shell=True,
153
    )
154 12
    anion_number = sp.check_output(
155
        [
156
            "grep -A 99 RESIDUE_LABEL ./tmp/solvate.prmtop | "
157
            + "grep -oh '{} ' | wc -w".format(random_anion)
158
        ],
159
        shell=True,
160
    )
161 12
    logger.debug("Expecting...")
162 12
    logger.debug("cation = {}\tn_cations={}".format(random_cation, n_cations))
163 12
    logger.debug("anion  = {}\t n_anions={}".format(random_anion, n_anions))
164 12
    logger.debug("Found...")
165 12
    logger.debug("             n_cations={}".format(cation_number))
166 12
    logger.debug("              n_anions={}".format(anion_number))
167

168 12
    assert int(cation_number) == n_cations and int(anion_number) == n_anions
169

170

171 12
def test_solvation_by_M_and_m(clean_files):
172
    """ Test that we can solvate CB6-BUT through molarity and molality. """
173 12
    logger.debug("Trying 10 A buffer with 150 mM NaCl...")
174 12
    sys = System()
175 12
    sys.template_file = os.path.join(
176
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
177
    )
178 12
    sys.output_path = "tmp"
179 12
    sys.loadpdb_file = os.path.join(
180
        os.path.dirname(__file__), "../data/cb6-but/cb6-but.pdb"
181
    )
182 12
    sys.buffer_value = 10.0
183 12
    sys.output_prefix = "solvate"
184 12
    sys.neutralize = False
185 12
    sys.pbc_type = "rectangular"
186 12
    sys.add_ions = ["NA", "0.150M", "CL", "0.150M", "K", "0.100m", "BR", "0.100m"]
187 12
    sys.build()
188

189
    # Molarity Check
190 12
    obs_num_na = sp.check_output(
191
        ["grep -A 99 RESIDUE_LABEL ./tmp/solvate.prmtop | " + "grep -oh 'NA ' | wc -w"],
192
        shell=True,
193
    )
194 12
    obs_num_cl = sp.check_output(
195
        ["grep -A 99 RESIDUE_LABEL ./tmp/solvate.prmtop | " + "grep -oh 'CL ' | wc -w"],
196
        shell=True,
197
    )
198

199 12
    volume = sys.get_volume()
200 12
    volume_in_liters = volume * ANGSTROM_CUBED_TO_LITERS
201 12
    calc_num_na = np.ceil((6.022 * 10 ** 23) * (0.150) * volume_in_liters)
202 12
    calc_num_cl = np.ceil((6.022 * 10 ** 23) * (0.150) * volume_in_liters)
203 12
    assert int(obs_num_na) == int(calc_num_na)
204 12
    assert int(obs_num_cl) == int(calc_num_cl)
205

206
    # Molality Check
207 12
    obs_num_k = sp.check_output(
208
        ["grep -A 99 RESIDUE_LABEL ./tmp/solvate.prmtop | " + "grep -oh 'K ' | wc -w"],
209
        shell=True,
210
    )
211 12
    obs_num_br = sp.check_output(
212
        ["grep -A 99 RESIDUE_LABEL ./tmp/solvate.prmtop | " + "grep -oh 'BR ' | wc -w"],
213
        shell=True,
214
    )
215 12
    calc_num_waters = sys.count_residues()["WAT"]
216 12
    calc_num_k = np.ceil(0.100 * calc_num_waters * 0.018)
217 12
    calc_num_br = np.ceil(0.100 * calc_num_waters * 0.018)
218 12
    assert int(obs_num_k) == int(calc_num_k)
219 12
    assert int(obs_num_br) == int(calc_num_br)
220

221

222 12
@pytest.mark.slow
223
def test_alignment_workflow(clean_files):
224
    """ Test that we can solvate CB6-BUT after alignment. """
225 12
    cb6 = pmd.load_file(
226
        os.path.join(
227
            os.path.dirname(__file__), "../data/cb6-but/cb6-but-notcentered.pdb"
228
        )
229
    )
230 12
    zalign(cb6, ":CB6", ":BUT", save=True, filename="./tmp/tmp.pdb")
231 12
    waters = np.random.randint(1000, 10000)
232 12
    sys = System()
233 12
    sys.template_file = os.path.join(
234
        os.path.dirname(__file__), "../data/cb6-but/tleap_solvate.in"
235
    )
236 12
    sys.output_path = "tmp"
237 12
    sys.loadpdb_file = "tmp.pdb"
238 12
    sys.target_waters = waters
239 12
    sys.output_prefix = "solvate"
240 12
    sys.build()
241 12
    logger.debug("Trying {} waters after alignment...".format(waters))
242 12
    grepped_waters = sp.check_output(
243
        ["grep -oh 'WAT' ./tmp/solvate.prmtop | wc -w"], shell=True
244
    )
245 12
    assert int(grepped_waters) == waters
246

247

248 12
def test_add_dummy(clean_files):
249
    """ Test that dummy atoms get added correctly """
250 12
    temporary_directory = os.path.join(os.path.dirname(__file__), "tmp")
251 12
    host_guest = pmd.load_file(
252
        os.path.join(
253
            os.path.dirname(__file__), "../data/cb6-but/cb6-but-notcentered.pdb"
254
        ),
255
        structure=True,
256
    )
257 12
    host_guest = zalign(host_guest, ":BUT@C", ":BUT@C3", save=False)
258 12
    host_guest = add_dummy(host_guest, residue_name="DM1", z=-11.000, y=2.000, x=-1.500)
259

260 12
    host_guest.write_pdb(
261
        os.path.join(temporary_directory, "cb6-but-dum.pdb"), renumber=False
262
    )
263 12
    with open(os.path.join(temporary_directory, "cb6-but-dum.pdb"), "r") as f:
264 12
        lines = f.readlines()
265 12
        test_line1 = lines[123].rstrip()
266 12
        test_line2 = lines[124].rstrip()
267 12
    ref_line1 = "TER     123      BUT     2"
268 12
    ref_line2 = (
269
        "HETATM  123 DUM  DM1     3      -1.500   2.000 -11.000  0.00  0.00          PB"
270
    )
271 12
    assert ref_line1 == test_line1
272 12
    assert ref_line2 == test_line2
273

274 12
    write_dummy_frcmod(path=temporary_directory)
275 12
    write_dummy_mol2(path=temporary_directory, filename="dm1.mol2", residue_name="DM1")
276 12
    sys = System()
277 12
    cb6_frcmod = os.path.abspath(
278
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/cb6.frcmod")
279
    )
280 12
    cb6_mol2 = os.path.abspath(
281
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/cb6.mol2")
282
    )
283 12
    but_frcmod = os.path.abspath(
284
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.frcmod")
285
    )
286 12
    but_mol2 = os.path.abspath(
287
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.mol2")
288
    )
289

290 12
    sys.template_lines = [
291
        "source leaprc.gaff",
292
        f"loadamberparams {cb6_frcmod}",
293
        f"CB6 = loadmol2 {cb6_mol2}",
294
        f"loadamberparams {but_frcmod}",
295
        f"BUT = loadmol2 {but_mol2}",
296
        "loadamberparams dummy.frcmod",
297
        "DM1 = loadmol2 dm1.mol2",
298
        "model = loadpdb cb6-but-dum.pdb",
299
    ]
300 12
    sys.output_path = temporary_directory
301 12
    sys.output_prefix = "cb6-but-dum"
302 12
    sys.pbc_type = None
303 12
    sys.neutralize = False
304 12
    sys.build()
305 12
    with open(
306
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/REF_cb6-but-dum.rst7"),
307
        "r",
308
    ) as f:
309 12
        contents = f.read()
310 12
        reference = [float(i) for i in contents.split()[2:]]
311

312 12
    with open(os.path.join(temporary_directory, "cb6-but-dum.rst7"), "r") as f:
313 12
        contents = f.read()
314 12
        new = [float(i) for i in contents.split()[2:]]
315 12
    assert np.allclose(reference, new)
316

317

318 12
def test_hydrogen_mass_repartitioning(clean_files):
319
    """ Test that hydrogen mass is repartitioned. """
320 12
    temporary_directory = os.path.join(os.path.dirname(__file__), "tmp")
321 12
    sys = System()
322 12
    but_frcmod = os.path.abspath(
323
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.frcmod")
324
    )
325 12
    but_mol2 = os.path.abspath(
326
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.mol2")
327
    )
328

329 12
    sys.template_lines = [
330
        "source leaprc.gaff",
331
        f"loadamberparams {but_frcmod}",
332
        f"BUT = loadmol2 {but_mol2}",
333
        f"model = loadmol2 {but_mol2}",
334
    ]
335 12
    sys.output_path = temporary_directory
336 12
    sys.output_prefix = "but"
337 12
    sys.pbc_type = None
338 12
    sys.neutralize = False
339 12
    sys.build()
340

341 12
    but = pmd.load_file(
342
        os.path.join(temporary_directory, sys.output_prefix + ".prmtop")
343
    )
344 12
    assert np.allclose(but["@H="].atoms[0].mass, 1.008)
345

346 12
    sys.repartition_hydrogen_mass()
347 12
    but = pmd.load_file(
348
        os.path.join(temporary_directory, sys.output_prefix + ".prmtop")
349
    )
350 12
    assert np.allclose(but["@H="].atoms[0].mass, 3.024)
351

352

353 12
def test_multiple_pdb_files(clean_files):
354
    """
355
    Test that multiple `loadpdb` lines are carried through.
356
    Reference: https://github.com/slochower/pAPRika/issues/141
357
    """
358 12
    temporary_directory = os.path.join(os.path.dirname(__file__), "tmp")
359 12
    sys = System()
360 12
    cb6_frcmod = os.path.abspath(
361
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/cb6.frcmod")
362
    )
363 12
    cb6_mol2 = os.path.abspath(
364
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/cb6.mol2")
365
    )
366 12
    but_frcmod = os.path.abspath(
367
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.frcmod")
368
    )
369 12
    but_mol2 = os.path.abspath(
370
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.mol2")
371
    )
372

373 12
    sys.template_lines = [
374
        "source leaprc.gaff",
375
        f"loadamberparams {cb6_frcmod}",
376
        f"CB6 = loadmol2 {cb6_mol2}",
377
        f"loadamberparams {but_frcmod}",
378
        f"BUT = loadmol2 {but_mol2}",
379
        "a = loadpdb cb6-but-notcentered.pdb",
380
        "b = loadpdb cb6-but-minimized.pdb",
381
        "model = combine { a b }",
382
    ]
383 12
    sys.output_path = temporary_directory
384 12
    sys.output_prefix = "multi"
385 12
    sys.pbc_type = None
386 12
    sys.neutralize = False
387 12
    sys.build()
388

389 12
    with open(f"{temporary_directory}/multi.tleap.in", "r") as f:
390 12
        lines = f.read()
391

392 12
    assert "a = loadpdb cb6-but-notcentered.pdb" in lines
393 12
    assert "b = loadpdb cb6-but-minimized.pdb" in lines
394 12
    assert "combine" in lines
395 12
    assert "savepdb model multi.pdb" in lines
396

397

398 12
def test_conversions(clean_files):
399
    """ Test that conversion methods work in Tleap module. """
400 12
    temporary_directory = os.path.join(os.path.dirname(__file__), "tmp")
401

402 12
    but_frcmod = os.path.abspath(
403
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.frcmod")
404
    )
405 12
    but_mol2 = os.path.abspath(
406
        os.path.join(os.path.dirname(__file__), "../data/cb6-but/but.mol2")
407
    )
408

409 12
    sys = System()
410 12
    sys.template_lines = [
411
        "source leaprc.gaff",
412
        f"loadamberparams {but_frcmod}",
413
        f"BUT = loadmol2 {but_mol2}",
414
        f"model = loadmol2 {but_mol2}",
415
    ]
416 12
    sys.output_path = temporary_directory
417 12
    sys.output_prefix = "but"
418 12
    sys.pbc_type = None
419 12
    sys.neutralize = False
420 12
    sys.build()
421

422 12
    from paprika.tleap import ConversionToolkit
423 12
    from paprika.utils import is_file_and_not_empty
424

425
    # Gromacs ParmEd test
426 12
    sys.convert_to_gromacs(overwrite=True)
427 12
    top_file = os.path.join(sys.output_path, sys.output_prefix + ".top")
428 12
    gro_file = os.path.join(sys.output_path, sys.output_prefix + ".gro")
429 12
    assert is_file_and_not_empty(top_file) is True
430 12
    assert is_file_and_not_empty(gro_file) is True
431

432
    # Gromacs InterMol test
433 12
    sys.convert_to_gromacs(toolkit=ConversionToolkit.InterMol)
434 12
    assert is_file_and_not_empty(top_file) is True
435 12
    assert is_file_and_not_empty(gro_file) is True
436 12
    top_file = os.path.join(sys.output_path, sys.output_prefix + "_from_amber.top")
437 12
    gro_file = os.path.join(sys.output_path, sys.output_prefix + "_from_amber.gro")
438 12
    assert is_file_and_not_empty(top_file) is True
439 12
    assert is_file_and_not_empty(gro_file) is True
440

441
    # CHARMM ParmEd test
442 12
    sys.convert_to_charmm()
443 12
    psf_file = os.path.join(sys.output_path, sys.output_prefix + ".psf")
444 12
    crd_file = os.path.join(sys.output_path, sys.output_prefix + ".crd")
445

446 12
    assert is_file_and_not_empty(psf_file) is True
447 12
    assert is_file_and_not_empty(crd_file) is True
448

449
    # CHARMM Intermol test
450 12
    sys.convert_to_charmm(toolkit=ConversionToolkit.InterMol)
451 12
    rtf_file = os.path.join(sys.output_path, sys.output_prefix + ".rtf")
452 12
    prm_file = os.path.join(sys.output_path, sys.output_prefix + ".prm")
453

454 12
    assert is_file_and_not_empty(psf_file) is True
455 12
    assert is_file_and_not_empty(crd_file) is True
456 12
    assert is_file_and_not_empty(rtf_file) is True
457 12
    assert is_file_and_not_empty(prm_file) is True
458

459
    # LAMMPS test
460 12
    sys.convert_to_lammps()
461 12
    input_file = os.path.join(sys.output_path, sys.output_prefix + ".input")
462 12
    lmp_file = os.path.join(sys.output_path, sys.output_prefix + ".lmp")
463 12
    assert is_file_and_not_empty(input_file) is True
464 12
    assert is_file_and_not_empty(lmp_file) is True
465

466
    # DESMOND test
467 12
    sys.convert_to_desmond()
468 12
    cms_file = os.path.join(sys.output_path, sys.output_prefix + ".cms")
469 12
    assert is_file_and_not_empty(cms_file) is True
470

471

472 12
def test_ion_solvation(clean_files):
473
    """ Test that tleap module is solvating an ion properly."""
474 12
    temporary_directory = os.path.join(os.path.dirname(__file__), "tmp")
475

476 12
    ions = ["Na+", "Cl-"]
477 12
    for ion in ions:
478
        # Write PDB file
479 12
        with open(os.path.join(temporary_directory, "ion.pdb"), "w") as f:
480 12
            f.writelines(
481
                "CRYST1   30.000   30.000   30.000  90.00  90.00  90.00 P 1           1\n"
482
            )
483 12
            f.writelines(
484
                f"ATOM      1 {ion:3s}  {ion:3s}     1       0.000   0.000   0.000  1.00  0.00\n"
485
            )
486 12
            f.writelines("END")
487

488
        # Write MOL2 file
489 12
        with open(os.path.join(temporary_directory, "ion.mol2"), "w") as f:
490 12
            charge = 1.0 if "+" in ion else -1.0
491 12
            gaff_type = ion.split("+" if "+" in ion else "-")[0].lower()
492 12
            f.writelines("@<TRIPOS>MOLECULE\n")
493 12
            f.writelines(f"{ion}\n")
494 12
            f.writelines("1     0     1     0     0\n")
495 12
            f.writelines("SMALL\n")
496 12
            f.writelines("No Charge or Current Charge\n\n\n")
497 12
            f.writelines("@<TRIPOS>ATOM\n")
498 12
            f.writelines(
499
                f"      1 {ion:3s}          0.0000     0.0000     0.0000 {gaff_type}         1 {ion}       {charge:.6f}\n"
500
            )
501 12
            f.writelines("@<TRIPOS>BOND\n")
502 12
            f.writelines("@<TRIPOS>SUBSTRUCTURE\n")
503 12
            f.writelines(
504
                f"     1 {ion:3s}         1 TEMP              0 ****  ****    0 ROOT"
505
            )
506

507
        # Run tleap
508 12
        ion_sys = System()
509 12
        ion_sys.output_path = temporary_directory
510 12
        ion_sys.target_waters = 1000
511 12
        ion_sys.pbc_type = "cubic"
512 12
        ion_sys.neutralize = False
513 12
        ion_sys.template_lines = [
514
            "source leaprc.gaff",
515
            "source leaprc.water.tip3p",
516
            f"{ion} = loadmol2 ion.mol2",
517
            "model = loadpdb ion.pdb",
518
        ]
519 12
        ion_sys.build()
520

521
        # Make sure Amber files are generated
522 12
        assert (
523
            is_file_and_not_empty(os.path.join(temporary_directory, "build.prmtop"))
524
            is True
525
        )
526 12
        assert (
527
            is_file_and_not_empty(os.path.join(temporary_directory, "build.rst7"))
528
            is True
529
        )
530

531
        # Check number of atoms in files
532 12
        structure = pmd.load_file(
533
            os.path.join(temporary_directory, "build.prmtop"),
534
            os.path.join(temporary_directory, "build.rst7"),
535
        )
536 12
        assert len(structure.atoms) == 3001

Read our documentation on viewing source code .

Loading