@@ -4,39 +4,19 @@ Output the simulation state
44===========================
55
66Here, the code is modified to allow us to follow the evolution of the system
7- during the simulation. To do so, the *Output * class is modified.
8-
9- Update the MinimizeEnergy class
10- -------------------------------
11-
12- Let us start by calling two additional methods within the for loop of the
13- *MinimizeEnergy * class, within the *run() * method.
14-
15- .. label :: start_MinimizeEnergy_class
16-
17- .. code-block :: python
18-
19- def run (self ):
20- (... )
21- for self .step in range (0 , self .maximum_steps+ 1 ):
22- (... )
23- self .displacement *= 0.2 # Multiply the displacement by a factor 0.2
24- log_simulation_data(self )
25- update_dump_file(self , " dump.min.lammpstrj" )
26-
27- .. label :: end_MinimizeEnergy_class
28-
29- The two methods named *update_log_minimize() * and *update_dump_file() *, are used
30- to print the information in the terminal and in a LAMMPS-type data file, respectively.
31- These two methods will be written in the following.
7+ during the simulation. To do so, two new files will be created: one dedicated
8+ to logging information, and the other to printing the atom positions to a
9+ file, thus allowing for their visualization with software like
10+ VMD :cite: `humphrey1996vmd ` or Ovito :cite: `stukowski2009visualization `.
3211
3312Create logger
3413-------------
3514
36- Let us create functions named *log_simulation_data * to a file named *logger.py *.
15+ Let us create a function named *log_simulation_data() * to a file named *logger.py *.
3716With the logger, some output are being printed in a file, as well as in the terminal.
38- The frequency of printing is set by *thermo_period *, see :ref: `chapter3-label `.
39- All quantities are re-dimensionalized before getting outputed.
17+ The period of printing, which is a multiple of the simulation steps, will be set
18+ by a new parameter named *thermo_period * (integer). All quantities are
19+ converted into *real * units before getting outputed (see :ref: `chapter2-label `).
4020
4121.. label :: start_logger_class
4222
@@ -76,6 +56,7 @@ All quantities are re-dimensionalized before getting outputed.
7656 return logger
7757
7858 def log_simulation_data (code ):
59+ # TOFIX: ceurrently, MaxF is returned dimensionless
7960
8061 # Setup the logger with the folder name, overwriting the log if code.step is 0
8162 logger = setup_logger(code.data_folder, overwrite = (code.step == 0 ))
@@ -106,14 +87,22 @@ All quantities are re-dimensionalized before getting outputed.
10687
10788 .. label :: end_logger_class
10889
109- Create dumper
90+ For simplicify, the *logger * uses the |logging | library, which provides a
91+ flexible framework for emitting log messages from Python programs. Depending on
92+ the value of *thermo_outputs *, different informations are printed, such as
93+ *step *, *Epot *, or/and *MaxF *.
94+
95+ .. |logging | raw :: html
96+
97+ <a href="https://docs.python.org/3/library/logging.html" target="_blank">logging</a>
98+
99+ Create Dumper
110100-------------
111101
112- Let us create a function named *update_dump_file * to a file named
113- *dumper.py *. The dumper will print a *.lammpstrj file *, which contains the box
114- dimensions and atom positions at every chosen frame (set by *dumping_period *,
115- see :ref: `chapter3-label `). All quantities are dimensionalized before getting outputed, and the file follows
116- a LAMMPS dump format, and can be read by molecular dynamics softwares like VMD.
102+ Let us create a function named *update_dump_file() * in a file named
103+ *dumper.py *. The dumper will print a *.lammpstrj * file, which contains
104+ the box dimensions and atom positions at every chosen frame (set by
105+ *dumping_period *). All quantities are dimensionalized before being output.
117106
118107.. label :: start_dumper_class
119108
@@ -228,11 +217,35 @@ parameters are passed the InitializeSimulation method:
228217
229218 .. label :: end_InitializeSimulation_class
230219
220+ Update the MinimizeEnergy class
221+ -------------------------------
222+
223+ As a final step, let us call two functions *log_simulation_data * and
224+ *update_dump_file * within the *for * loop of the
225+ *MinimizeEnergy * class, within the *run() * method:
226+
227+ .. label :: start_MinimizeEnergy_class
228+
229+ .. code-block :: python
230+
231+ def run (self ):
232+ (... )
233+ for self .step in range (0 , self .maximum_steps+ 1 ):
234+ (... )
235+ self .displacement *= 0.2 # Multiply the displacement by a factor 0.2
236+ log_simulation_data(self )
237+ update_dump_file(self , " dump.min.lammpstrj" )
238+
239+ .. label :: end_MinimizeEnergy_class
240+
241+ The name *dump.min.lammpstrj * will be used when printing the dump file
242+ during energy minimization.
243+
231244Test the code
232245-------------
233246
234- One can use a test similar as the previous ones. Let us ask out code to print
235- information in the dump and the log files, and then let us assert the
247+ One can use a test similar as the previous ones. Let us ask our code to print
248+ information in the * dump * and the * log * files, and then let us assert that the
236249files were indeed created without the *Outputs/ * folder:
237250
238251.. label :: start_test_5a_class
@@ -276,8 +289,10 @@ files were indeed created without the *Outputs/* folder:
276289
277290 # Test function using pytest
278291 def test_output_files ():
279- assert os.path.exists(" Outputs/dump.min.lammpstrj" ), " Test failed: dump file was not created"
280- assert os.path.exists(" Outputs/simulation.log" ), " Test failed: log file was not created"
292+ assert os.path.exists(" Outputs/dump.min.lammpstrj" ), \
293+ " Test failed: the dump file was not created"
294+ assert os.path.exists(" Outputs/simulation.log" ), \
295+ " Test failed: the log file was not created"
281296 print (" Test passed" )
282297
283298 # If the script is run directly, execute the tests
@@ -288,8 +303,9 @@ files were indeed created without the *Outputs/* folder:
288303
289304 .. label :: end_test_5a_class
290305
291- I addition to the files getting created, information must be printed in the terminal
292- during the simulation:
306+ In addition to making sure that both files were created, let us verify
307+ that the expected information was printed to the terminal during the
308+ simulation. The content of the *simulation.log * file should resemble:
293309
294310.. code-block :: bw
295311
@@ -302,8 +318,8 @@ during the simulation:
302318
303319 The data from the *simulation.log * can be used to generate plots using softwares
304320line XmGrace, GnuPlot, or Python/Pyplot. For the later, one can use a simple data
305- reader to import the data from *Outputs/ simulation.log * into Python. Copy the
306- following lines in a file named *reader.py *:
321+ reader to import the data from *simulation.log * into Python. Copy the
322+ following lines in a new file named *reader.py *:
307323
308324.. label :: start_reader_class
309325
@@ -342,14 +358,28 @@ The *import_data* function from *reader.py* can simply be used as follows:
342358
343359.. label :: start_test_5b_class
344360
361+ .. code-block :: python
362+
345363 from reader import import_data
346364
347- file_path = "Outputs/simulation.log"
348- header, data = import_data(file_path)
365+ def test_file_not_empty ():
366+ # Import data from the file
367+ file_path = " Outputs/simulation.log"
368+ header, data = import_data(file_path)
369+ # Check if the header and data are not empty
370+ assert header, " Error, no header in simulation.log"
371+ assert data, " Error, no data in simulation.log"
372+ assert len (data) > 0 , " Data should contain at least one row"
349373
350- print(header)
351- for row in data:
352- print(row)
374+ print (header)
375+ for row in data:
376+ print (row)
377+
378+ # If the script is run directly, execute the tests
379+ if __name__ == " __main__" :
380+ import pytest
381+ # Run pytest programmatically
382+ pytest.main([" -s" , __file__ ])
353383
354384 .. label :: end_test_5b_class
355385
@@ -362,4 +392,4 @@ Which must return:
362392 [25.0, -2.12, 1.22]
363393 [50.0, -2.19, 2.85]
364394 [75.0, -2.64, 0.99]
365- [100.0, -2.64, 0.51]
395+ [100.0, -2.64, 0.51]
0 commit comments