Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from numpy import (all as nall, array, array_str, reshape, where, einsum, concatenate,
2 ndarray, block, arange, savetxt, atleast_1d, atleast_2d, genfromtxt)
3from re import search
4from sys import stdout, argv
5from os import get_terminal_size, path, getcwd, fstat
6from shutil import copyfile
7from datetime import datetime
8from asyncio import new_event_loop
9from contextlib import suppress
11from mango.constants import c, _variables, keys, rmemptyfile, boolconvert
12from mango.debug import debug
13from mango.managers import serverwrapper
15import mango.imports as imports
18@debug(['io'])
19def _input(func):
20 """
21 User input that wipes itself after input.
23 (For error printing)
24 """
25 out = input(func)
26 stdout.write("\x1b[A\x1b[A")
27 a = get_terminal_size()
28 stdout.write(" " * a.columns)
29 return out
32def separater(response):
33 response = atleast_2d(response)
35 cols = response.shape[-1]
37 if cols == 3:
38 response = (response, None, None)
39 elif cols == 6:
40 response = (response[..., :3], response[..., 3:6], None)
41 elif cols >= 9: 41 ↛ 44line 41 didn't jump to line 44, because the condition on line 41 was never false
42 response = (response[..., :3], response[..., 3:6], response[..., 6:9])
44 return response
47class Data():
48 append = set(["position", "magnetisation", "momentum", "iter_time", "magnetic_field",
49 "forces", "neel_relaxation"])
52class write_data(Data):
53 """Writing all calculated data to file."""
55 @debug(["write"])
56 def __init__(self, var, flg):
57 self.dump, self.save_type = imports.write(flg.save_type)
58 name = var.name
59 self.directory = name[:name.rfind("/") + 1]
60 self.restartfile = "{}{}{}".format(self.directory, name[name.rfind("Run"):name.rfind("_")], "restart")
61 self.total = var.skip_iters + 1
62 self.nmax = self.total * var.no_molecules
64 self.restarted = flg.restart
65 self.restart()
67 def setup(self, name):
68 self.loop = new_event_loop()
69 self.addtorestart(name)
70 return self.save_type
72 def write(self, *args, **kw):
73 self.loop.run_until_complete(self._write(*args, **kw))
75 @debug(['io'])
76 async def _write(self, moldata_dict):
77 """Write data to specific file type."""
78 if self.save_type == "hdf5":
79 self.dump(moldata_dict['name'], moldata_dict,
80 compression=('blosc', 9), datalength=self.nmax, append=self.append)
81 elif self.save_type == "pkl": 81 ↛ 85line 81 didn't jump to line 85, because the condition on line 81 was never false
82 with open(moldata_dict['name'], "ab") as w:
83 self.dump(moldata_dict, w, protocol=-1)
84 else:
85 no_mol = moldata_dict["position"].shape[1]
86 txt_data(moldata_dict, no_mol)
88 def restart(self):
89 if path.isfile(self.restartfile): 89 ↛ 90line 89 didn't jump to line 90, because the condition on line 89 was never true
90 copyfile(self.restartfile, self.restartfile + "R" + datetime.now().isoformat(timespec='minutes'))
91 with open(self.restartfile, 'w') as rf:
92 rf.write(f"save_type {self.save_type}\ndirectory {self.directory}\ntotal_tosave {self.total}\n")
94 def addtorestart(self, fname):
95 with open(self.restartfile, "a") as rf:
96 rf.write(f"{fname.rsplit('/')[-1]}\n")
99class read_data(Data):
100 """
101 Reads data in for post processing.
103 Improvements
104 * Only read in data required rather than all data
105 - Works for hdf5 files
106 """
108 def __init__(self, fname, rtype=None, xyzpp=False):
109 if rtype is None: 109 ↛ 110line 109 didn't jump to line 110, because the condition on line 109 was never true
110 fname, rtype = fname.rsplit('.', 1)
111 self.xyzpp = xyzpp
112 self.load, self.rtype = imports.read(rtype)
113 self._newname(fname, xyzpp)
115 def _readtype(self):
117 if self.rtype == "hdf5":
118 self._rd = self._hdf5read
119 elif self.rtype == "pkl":
120 self._rd = self._pickleread
121 elif self.xyzpp: 121 ↛ 122line 121 didn't jump to line 122, because the condition on line 121 was never true
122 self._rd = self.xyzppread
123 self.xvsloc = "{}.var".format(self.fname.split('.')[0])
124 elif self.rtype == 'xyz':
125 self._rd = self.xyzread
126 else:
127 self._rd = self.txtread
129 def _hdf5read(self, obj, *args):
130 return self.load(self.fname, obj, *args)
132 def _pickleread(self, obj, *args):
133 if obj is None: 133 ↛ 134line 133 didn't jump to line 134, because the condition on line 133 was never true
134 c.Error('F pkl files require key name')
135 lspl = [x for x in filter(None, obj.split('/'))]
136 data = []
137 with open(self.fname, 'rb') as self.v:
138 l_obj = lspl[0] if len(lspl) > 1 else obj
139 while self.v.tell() < fstat(self.v.fileno()).st_size:
140 data.append(self.load(self.v)[l_obj])
142 if len(lspl) > 1:
143 for n, reads in enumerate(data):
144 for i in lspl[1:]:
145 data[n] = data[n][i]
146 if l_obj in self.append: 146 ↛ 147line 146 didn't jump to line 147, because the condition on line 146 was never true
147 data = concatenate(data, axis=0)
148 return data[-1] if l_obj in ['vars', 'flags'] else data
150 def _newname(self, fname, xyzpp):
151 self.xyzpp = xyzpp
152 self.fname = fname if fname.endswith(self.rtype) else "{}.{}".format(fname, self.rtype)
153 self._readtype()
155 @debug(["io"])
156 def read(self, obj=None, fname=None, restart=False, lengthcheck=False, keylist=False, chunk=None, xyzpp=False):
157 """
158 Read in pickle and hdf5 outputs.
160 Parameters
161 ----------
162 obj: string
163 object to be read in
164 fname: string
165 file to be read in
166 restart: bool
167 Is read in to restart run
168 lengthcheck: bool
169 Get lenth of position data and last iteration
171 """
172 if fname is None:
173 fname = self.fname
174 if self.fname != fname:
175 self._newname(fname, xyzpp)
177 if restart:
178 if self.rtype in ["xyz", "txt"]: 178 ↛ 179line 178 didn't jump to line 179, because the condition on line 178 was never true
179 c.Error("F Restarting is not implemented for this filetype")
180 return self.getrestart(*self.lengthcheck())
181 elif lengthcheck: 181 ↛ 182line 181 didn't jump to line 182, because the condition on line 181 was never true
182 return self.lengthcheck()
183 else:
184 return self._rd(obj, chunk, keylist)
186 def getrestart(self, position, last_iter):
187 """Get restart data."""
188 restart = _variables(**self._rd('vars'))
189 restart.pos = position[last_iter, :, :]
190 restart.mag = self._rd("magnetisation")[last_iter, :, :]
191 restart.mom = self._rd("momentum")[last_iter, :, :]
193 restartflags = _variables(**self._rd('flags'))
194 return restart, restartflags, last_iter
196 def lengthcheck(self):
197 """
198 Check which row number is the last iteration.
200 Redundency check to make sure the last used row is the last row
201 """
202 position = self._rd('position')
203 l_it = nall(position == 0.0, axis=(-2, -1))
205 if not nall(l_it):
206 # l_it == False produces correct answer
207 # l_it is False does not
208 last_iter = where(l_it == False)[0][-1]
209 else:
210 last_iter = 0
212 return position, last_iter
214 def xyzppread(self, obj=None, *args):
215 """
216 Post process from xyz file.
218 Requires associated <filename>.var file with variables needed for post processing
219 also needs to include the variable columns with the xyz column variable names.
221 e.g.
222 mass 1.111
223 radius 1.23e-4
224 columns position,velocity,force
226 Only internal variable names currently supported
227 """
228 if 'xvars' not in self.__dict__.keys():
229 self.xvars = self._xyzvars()
231 if obj == 'vars':
232 return self.xvars
233 elif 'xyz' not in self.__dict__.keys():
234 _, self.xyz = self.xyzread()
235 self.xyz = separater(self.xyz)
237 try:
238 col = self.xvars['columns'].index(obj)
239 return self.xyz[col]
240 except ValueError:
241 if "velocity" in self.xvars['columns']:
242 col = self.xvars['columns'].index("velocity")
243 return self.xyz[col] * self.xvars['mass']
245 def xyzread(self, *args):
246 """Read all data from (extended) xyz file."""
247 with open(self.fname, "rb") as loc:
248 for lines in loc: 248 ↛ 252line 248 didn't jump to line 252, because the loop on line 248 didn't complete
249 if lines[:-1] not in [b"", b"#"]: 249 ↛ 248line 249 didn't jump to line 248, because the condition on line 249 was never false
250 break
252 response = atleast_2d(genfromtxt(self._skip_lines(self.fname, lines), comments="#", dtype=str))
254 molecules = response[:, 0]
256 lastaxis = response.shape[-1] - 1
258 lines = int(lines.decode("utf-8"))
260 if (response.shape[0] % lines != 0 or lastaxis % 3 != 0):
261 c.Error("F Input array shape not consistant with number of molecules specified")
263 response = response[:, 1:].astype(float).reshape((-1, lines, lastaxis), order='F')
265 return molecules, response
267 @staticmethod
268 def _skip_lines(fname, lines):
269 with open(fname, "rb") as file:
270 skip = -1
271 for lno, line in enumerate(file):
272 if line.startswith(lines):
273 skip = lno + 1
274 yield b"#" + line if line.startswith((b"i", lines)) or lno == skip else line
276 def _xyzvars(self, vnames={}):
277 with open(self.xvsloc) as xyzvars:
278 for line in xyzvars:
279 if "=" in line:
280 line = [x.strip() for x in line.split("=")]
281 val = line[1].split(' ')[0]
282 if "." in line[1].split(' ')[0]:
283 val = float(val)
284 else:
285 with suppress(ValueError):
286 val = int(val)
287 vnames[line[0].split(" ")[-1]] = val
289 vnames['columns'] = self._col_splitter(vnames['columns'])
290 for i in ['dens', 'vol']:
291 vnames[i] = atleast_1d(vnames[i])
293 return vnames
295 @staticmethod
296 def _col_splitter(columns):
297 if "," in columns:
298 return columns.split(',')
299 else:
300 return columns.split(' ')
302 def txtread(self, obj, *args):
303 """
304 Read in text file output.
306 * Not restartable
308 Parameters
309 ----------
310 obj: string
311 type of data to be read in, Variables "vars", Data "data"
313 """
314 if obj == "vars":
315 self.variables = {}
317 with open(self.fname, "r") as fp:
318 for line in fp:
319 if search(r'[#]', line) and not search(',', line):
320 values = array(line.strip().split()[:])
321 self.variables[values[1]] = float(values[3])
322 elif search(',', line):
323 break
324 # FIX from here some variables are not saved
325 return self.variables
327 elif obj == "data":
328 # FIX data shape and return values
329 data = []
330 # read file
331 with open(self.fname, "r") as fp:
332 data_temp = array([line.strip().split() for line in fp if not search(r'[#]', line)])
333 mol_sv = set(data_temp[:, 0])
334 data = array(data_temp[:, 1:], dtype=float)
335 nmax = int(self.variables["nmax"])
336 mol = int(self.variables["no_mol"])
337 stats = int(self.variables["stats"])
338 iterations = data[:nmax, :2]
339 neelr = {'mol_{}'.format(i): reshape(data[:, 2], (nmax, mol), order='F')[:, i] for i in range(mol)}
340 magnetisation = reshape(data[:, 3:6], (stats, nmax, mol, 3), order='F')
341 position = reshape(data[:, 9:12], (stats, nmax, mol, 3), order='F')
342 forces = reshape(data[:, 12:15], (stats, nmax, mol, 3), order='F')
343 momentum = reshape(data[:, 15:18], (stats, nmax, mol, 3), order='F')
344 return {"molecule names": mol_sv,
345 "iter_time": iterations,
346 "neel_relaxation": neelr,
347 "magnetisation": magnetisation,
348 "position": position,
349 "forces": forces,
350 "momentum": momentum}
353def read_inputfile(filename, restart=None, kwds=keys.words):
354 """Input File Reading."""
355 if type(filename) is str:
356 try:
357 with open(filename, "r") as f:
358 opts = {k: v.strip()
359 for k, v in [line.strip('\n').replace("\t", " ").split("[")[0].split(' ', 1)
360 for line in f if line[0] not in ['#', '\n']]}
361 except FileNotFoundError:
362 c.Error("F Input File not found")
363 else:
364 opts = filename
366 args = {}
367 for key, value in opts.items():
368 value = value.split('#')[0] if isinstance(value, str) else value
369 try:
370 if kwds[key][0][1] == int:
371 args[kwds[key][0][0]] = kwds[key][0][1](float(value))
372 elif kwds[key][0][1] == bool:
373 args[kwds[key][0][0]] = boolconvert(value) if not isinstance(value, bool) else value
374 elif kwds[key][0][1] == list and not isinstance(value, list):
375 args[kwds[key][0][0]] = value if isinstance(value, bool) else boolconvert(value) if value.lower() in ["true", "false"] else value.split()
376 else:
377 args[kwds[key][0][0]] = kwds[key][0][1](value)
378 except KeyError: 378 ↛ 380line 378 didn't jump to line 380
379 c.Error("F Input parameter '{}' doesn't exist".format(key))
380 except ValueError:
381 c.Error("F Input parameter '{}' (value: '{}') can't be read in".format(key, value))
383 args = _variables(**args)
384 args.restart = restart or (args.restart if 'restart' in opts else None)
385 args.inputfile = filename
386 return args
389@serverwrapper("Error")
390def inputregen(file=None, outfile=None, explanation=False):
391 """
392 Generate an input file based of an existing results file.
394 Parameters
395 ----------
396 file (or argv[1]): str
397 Data file location
398 outfile (or argv[2]): str
399 Input file name (optional, defaults to 'Input')
401 """
402 if '-h' in argv: 402 ↛ 403line 402 didn't jump to line 403, because the condition on line 402 was never true
403 print(inputregen.__doc__)
404 return
405 c.Error("{}{}".format("W This command is considered very very alpha\n",
406 "use for reference not as an input file"))
408 arglen = len(argv)
410 if arglen >= 2 and file is None:
411 filename = argv[1]
412 else:
413 filename = file
415 if arglen == 3 and outfile is None:
416 outfname = argv[2]
417 elif outfile is not None:
418 outfname = outfile
419 else:
420 outfname = "Input"
422 if filename in [None, False]:
423 c.Error("M Filename not provided, generating default inputfile")
424 arglist = [[i, j[0][2]] for i, j in keys.words.items()]
425 else:
427 filein = read_data(*filename.rsplit(".", 1))
428 flags = filein.read("flags")
429 var = filein.read("vars")
430 arglist = [[k, j] for i, j in var.items() for k, l in keys.words.items() if i in l[0]]
431 arglist += [[k, j] for i, j in flags.items() if i != 'run' for k, l in keys.words.items() if i in l[0]]
433 file = []
434 for i, j in arglist:
435 if str(j)[0] == '[':
436 j = str(j)[1:-1]
437 file.append("{:21s} {}\n".format(i, j))
439 if explanation: 439 ↛ 440line 439 didn't jump to line 440, because the condition on line 439 was never true
440 splitters = {0: '# Input files\n',
441 3: '\n# Properties\n',
442 10: '\n# Calculation Options\n',
443 25: '\n# Postprocessing\n',
444 36: '\n# Run Style Changes\n',
445 43: '\n# Néel Relaxation Properties\n'}
447 with open(outfname, "w") as outf:
448 for no, line in enumerate(file):
449 try:
450 exp = keys.explanation[no][2:].split('\n')
451 exp2 = exp[1].split(':')[-1].split('[')[-1][:-1]
452 exp = '{} {}'.format(exp[0].split('\n')[0].split('(')[0], '[' + exp2 if exp2[-1] == ']' else '')
453 except IndexError:
454 exp = keys.explanation[no][2:]
455 if '/' in line:
456 line = line.split('/')
457 line = '{}./{}'.format(line[0], line[-1])
458 if no in splitters.keys():
459 outf.write(splitters[no])
460 outf.write("{:33s} # {}\n".format(line[:-1], exp))
461 else:
462 with open(outfname, "w") as outf:
463 for line in file:
464 outf.write(line)
466 rmemptyfile(outfname)
469@serverwrapper("Error")
470def getvar():
471 """
472 Get variables from existing run.
474 Run with
476 mango_vars -f [Files...] -v [VARS....]
477 """
478 from argparse import ArgumentParser
479 parser = ArgumentParser(prog='MangoVars',
480 description="MangoVars reader")
481 parser.add_argument('-f', action='append', nargs='*', type=str, help='Files')
482 parser.add_argument('-v', action='append', nargs='*', type=str, help='Variables')
483 p = parser.parse_args()
485 p.f = [item for sl in p.f for item in sl]
486 p.v = [item for sl in p.v for item in sl]
488 for f in p.f:
489 print(f)
490 name, save_type = f.rsplit('.', 1)
492 reader = read_data(name, save_type)
493 variables = reader.read("vars")
494 for i in p.v:
495 if i in variables:
496 print(i, variables[i])
497 else:
498 # Get variable names
499 c.Error('{}{}'.format('>W Only internal variable names currently supported\n',
500 'Can\'t find {}'.format(i)))
503def restart_gen(file=None, reps=None, outfile=None):
504 """
505 Restart generator.
507 Run with
509 mango_restartregen [file] [reps] [outfile <optional>]
510 """
511 if '-h' in argv: 511 ↛ 512line 511 didn't jump to line 512, because the condition on line 511 was never true
512 print(restart_gen.__doc__)
513 return
514 lenarg = len(argv)
515 file = argv[1].rsplit(".", maxsplit=2) if file is None else file.rsplit(".", maxsplit=2)
516 reps = int(argv[2] if reps is None else reps)
517 outfile = (outfile if outfile is not None else
518 "Run{}restart".format(file[0].split("Run")[1].split("_")[0]) if lenarg != 4 else argv[3])
520 save_type = file[-1]
521 f_name = file[0]
522 directory_F = f_name.rsplit("/", 1)
523 directory = getcwd() if len(directory_F[0]) == 1 else "/" if len(directory_F[0]) < 1 else directory_F[0]
524 name = []
526 for i in range(reps):
527 name.append("{}.{:g}.{}".format(directory_F[1], i + 1, save_type))
529 total_tosave = read_data(name[0], save_type).read(restart=True)[0].skip_iters + 1
531 with open(outfile, "w") as rgen:
532 rgen.write("save_type {}\n".format(save_type))
533 rgen.write("directory {}\n".format(directory))
534 rgen.write("total_tosave {}\n".format(total_tosave))
535 for i in name:
536 rgen.write("{} \n".format(i))
538 rmemptyfile(outfile)
541def restartfile_read(r_file):
542 """Read restart file."""
543 with open(r_file) as rf:
544 filename = []
545 # collectLI = []
546 for line in rf:
547 line_data = line.split()
548 if line_data == []:
549 pass
550 elif line_data[0] == "save_type":
551 save_type = line_data[1]
552 elif line_data[0] == 'directory':
553 directory = line_data[1]
554 elif line_data[0] == 'total_tosave':
555 total = int(line_data[1])
556 else:
557 filename.append(line_data[0])
559 if not path.isdir(directory): 559 ↛ 563line 559 didn't jump to line 563, because the condition on line 559 was never false
560 rfile_loc = r_file.rsplit('/', 1)[0]
561 directory = rfile_loc + "/" if rfile_loc != '' else "./"
563 return [directory + file for file in filename], save_type, directory, total
566def get_restartdata(restart_data, filenames):
567 """Collect all restart data from all files."""
568 collectmag = {}
569 collectmom = {}
570 collectpos = {}
571 collectiters = {}
572 RandNoState = {}
574 for name in filenames:
575 stat = int(name.rsplit(".", 2)[-2]) - 1
576 restart, restartflags, last_iter = restart_data.read(fname=name, restart=True)
577 RandNoState = {**RandNoState, **restart.RandNoState}
578 collectmag[stat] = array(restart.mag)
579 collectmom[stat] = array(restart.mom)
580 collectpos[stat] = array(restart.pos)
581 collectiters[stat] = last_iter
583 restart.RandNoState = RandNoState
584 restart.mag = collectmag
585 restart.mom = collectmom
586 restart.pos = collectpos
588 return restart, restartflags, collectiters
591def xyz_write(xyz_mol_data, timescale, directory, run, flg, mmag, boxsize):
592 """
593 Write an extended xyz file.
595 ::
597 [n, number of atoms]
598 [timestep] [current time] [flags...]
599 mol[0] [position x y z] [momentum x y z] [magnetisation x y z] [forces x y z]
600 .
601 .
602 mol[n -1]...
604 Parameters
605 ----------
606 xyz_mol_data: np.array
607 array of data in the form [pos(xyz) mom(xyz) mag(xyz) force(xyz)] for each molecule
608 timescale: np.array
609 timescale list
610 directory: string
611 save directory
612 run: int
613 run number
614 flg: class
615 class of flags
616 flags used - pbc, mag_sw, align
617 mmag: float
618 Magnetic saturation * volume
619 boxsize: float
620 periodic boxsize
622 """
623 xyz_dshape = xyz_mol_data.shape
625 filename = "{}{}Run{}{}{}.m.xyz".format(directory, "S_" if flg.suscep else "",
626 str(run), "ALIGN" if flg.align else "",
627 'LF' if flg.lastframe else "")
629 no_mol = xyz_dshape[-2]
631 if not path.isfile(filename) or run.endswith('nofin'):
632 with open(filename, "wb") as xyz_w:
633 # Put force and velocity flags if needed
634 if flg.pbc:
635 axis = boxsize
636 else:
637 axis = False
639 commentline = bytes(" momentum={} mag={} force={} boxsize={} \n".format(True, flg.mag_sw, True, axis), 'utf-8')
641 xyz_string = 'MNP {}'.format(12 * ' % 15.7e')
642 xyz_mol_data[..., 6:9] = einsum("ijk, j -> ijk", xyz_mol_data[..., 6:9], 1 / mmag)
644 for i in [xyz_dshape[0] - 1] if flg.lastframe else range(xyz_dshape[0]):
645 xyz_w.write(bytes("{} \ni={} time={:e}[ps]".format(no_mol, i, timescale[i]), 'utf-8'))
646 xyz_w.write(commentline)
647 savetxt(xyz_w, xyz_mol_data[i, :, :], fmt=xyz_string)
648 else:
649 c.Error(">M Complete XYZ file exists, skipping")
651 rmemptyfile(filename)
654def file_write(data_array, f, timescale, directory, run, flg, mmag, boxsize):
655 """
656 Write a file of energy changes or momenta changes.
658 Parameters
659 ----------
660 data_array: np.array
661 shape of (x, y, 15) for momenta or (x, y, 4) for energy
662 f: string
663 Magnetisation "M" or Energy "E"
664 run: int
665 run number
667 """
668 def _write(f):
669 filename = "{}{}Run{}Conservation_{}{}.txt".format(directory, "S_" if flg.suscep else "", run, f,
670 'LF' if flg.lastframe else "")
672 if not path.isfile(filename) or run.endswith('nofin'):
673 itern = arange(0, timescale['F'].shape[0])
674 it_ti = block([[itern], [timescale['F']]])
675 data = block([it_ti.T, data_array])
676 savetxt(filename, data[-1][None, :] if flg.lastframe else data, fmt=format_string, header=titlestring)
677 else:
678 c.Error(">M Complete {} file exists, skipping".format("Momenta" if f == "M" else "Energy"))
680 if f == "E":
681 titlestring = "itern. time kinetic_e pot_e1 pot_e2 total_e"
682 format_string = "%.0d" + " % 15.7e" * 5
683 _write("E")
685 if f == "M":
686 titlestring = "itern. time total_m(x,y,z) mag_m(x,y,z) angular_m(x,y,z) CoM(x,y,z) CoM_vel(x,y,z)"
687 format_string = "%.0d" + " % 15.7e" * 16
688 _write("M")
690 if f == 'X':
691 xyz_write(data_array, timescale['X'], directory, run, flg, mmag, boxsize)
694def txt_data(moldata_dict, no_mol):
695 """
696 Write output as textfile.
698 Specify "txt"
700 Parameters
701 ----------
702 moldata_dict: dict
703 dictionary of data to be written
704 no_mol: int
705 Number of Moelcules
707 """
708 newfile = (not path.isfile(moldata_dict['name']))
710 stringfile = ''
711 if newfile:
712 stringfile += "# {:8s} = {:12} []\n".format("no_mol", no_mol + 1)
713 stringfile += "# {:8s} = {:12.5g} [s]\n".format('t0', moldata_dict['vars']['t0'])
714 stringfile += "# {:8s} = {:12.5g} [s]\n".format('dt', moldata_dict['vars']['dt'])
715 stringfile += "# {:8s} = {:12} []\n".format('nmax', moldata_dict['vars']['nmax'])
716 stringfile += "# {:8s} = {:12} []\n".format('skip', moldata_dict['vars']['skip'])
717 stringfile += "# {:8s} = {:12.5g} []\n".format('stats', moldata_dict['vars']['stats'])
718 stringfile += "\n"
719 stringfile += "# {:8s} = {:12.5g} [K]\n".format('temp', moldata_dict['vars']['temp'])
721 str_g = no_mol * "{:12.5g} "
722 str_e = no_mol * "{:12.5e} "
723 str_f = no_mol * "{:12.5f} "
725 stringfile += "# {:8s} = {} [cm]\n".format('radius', str_g.format(*moldata_dict['vars']['radius']))
726 stringfile += "# {:8s} = {} [g/cm^3]\n".format('dens', str_g.format(*moldata_dict['vars']['dens']))
727 stringfile += "# {:8s} = {} [emu/cm^3]\n".format('ms', str_g.format(*moldata_dict['vars']['ms']))
728 stringfile += "# {:8s} = {:12.5g} [oe]\n".format('H_0', moldata_dict['vars']['H_0'])
729 stringfile += "# {:8s} = {:12.5g} [kHz]\n".format('nu', moldata_dict['vars']['nu'])
730 stringfile += "# {:8s} = {:12.5g} [g/cm/s]\n".format('eta', moldata_dict['vars']['eta'])
731 stringfile += "# {:8s} = {} []\n".format('chi0', str_g.format(*moldata_dict['vars']['chi0']))
732 stringfile += "# {:8s} = {} [s]\n".format('tauB', str_g.format(*moldata_dict['vars']['tauB']))
733 stringfile += "\n"
734 stringfile += "# {:8s} = {} [cm^3]\n".format('volume', str_e.format(*moldata_dict['vars']['vol']))
735 stringfile += "# {:8s} = {} []\n".format('alpha', str_f.format(*moldata_dict['vars']['alpha']))
736 stringfile += "# {:8s} = {} [1/oe/s]\n".format('geff', str_f.format(*moldata_dict['vars']['geff']))
737 stringfile += "# {:8s} = {} [oe]\n".format('c2', str_f.format(*moldata_dict['vars']['c2']))
738 stringfile += "\n"
740 with suppress(KeyError):
741 stringfile += "# {:8s} = {:12.5g} [s]\n".format('tauN', moldata_dict['vars']['tauN'])
742 stringfile += "# {:8s} = {:12.2e} [erg/cm^3]\n".format('keff', moldata_dict['vars']['keff'])
743 stringfile += "# {:8s} = {:12.2e} [Hz]\n".format('nu_0', moldata_dict['vars']['nu_0'])
745 stringfile += "\n"
746 stringfile += "# {:8s} = {:12.5f} []\n".format('theta', *moldata_dict['vars']['theta'])
747 stringfile += "# {:8s} = {:12.5f} []\n".format('phi', *moldata_dict['vars']['phi'])
748 stringfile += "# {:8s} = {:12.5f} []\n".format('boxsize', moldata_dict['vars']['boxsize'])
749 stringfile += "\n"
750 stringfile += "# mol, iteration, time, neel, magnetisation (3 comp.), position, forces, momentum\n"
752 for a, j in enumerate(array(moldata_dict['iter_time'])):
753 for i in range(no_mol):
754 mol = "mol_{}".format(i)
755 k = int(moldata_dict['neel_relaxation'][mol][a]) if 'tauN' in moldata_dict['vars'].keys() else 0
756 L = array_str(moldata_dict['magnetisation'][a, i])[1:-1]
757 n = array_str(moldata_dict['position'][a, i])[1:-1]
758 o = array_str(moldata_dict['forces'][a, i])[1:-1]
759 p = array_str(moldata_dict['momentum'][a, i])[1:-1]
761 stringfile += "{} {} {} {} {} {} {}\n".format(mol, str(j)[1:-1], k, L, n, o, p)
762 stringfile += '\n'
764 with open(moldata_dict['name'], "a") as w:
765 w.write(stringfile)
767 rmemptyfile(moldata_dict['name'])