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
1"""
2Magnetic motion setup.
4Set up environment and start calculation loop
5"""
6# External Dependencies
7from numpy import (array, zeros, zeros_like,
8 sin, cos, ones, maximum,
9 sqrt, errstate, where, einsum)
11from numpy.core.multiarray import c_einsum
13from copy import deepcopy
14from scipy import linalg
15from math import pi
16from contextlib import suppress
18# Internal Dependencies
19from mango.constants import c, nestedDict
20from mango.position import position
21from mango.io import write_data
22from mango.initpositions import initpos
23from mango.time import _time, end, grace
24from mango.multiproc import mp_handle
25from mango.debug import debug, profile
26from mango.managers import addpid
29def calc_wrap(calc, stat):
30 """
31 Wrap calculate to allow decoration in multiprocessing.
33 Could be used in future for any function
34 """
35 with suppress(KeyboardInterrupt):
36 return profile(calc.run, stat, file="./wprofiler.prof") if c.profile and calc.flg.parallel else calc.run(stat)
39def field(time, H0=167.0, nu=267.0e3):
40 """Calculate the phase of the external magnetic field."""
41 if nu > c.EPS:
42 H = H0 * sin(2.0 * pi * nu * time)
44 else:
45 H = H0
47 return H
50def num_iters(iters, skip):
51 """Get number of iterations including first and last iterations."""
52 return 1 + ((iters - 1) // skip)
55def sanity_checks(var, pos, mag, xyz):
56 """Sanity check input."""
57 new_nm = pos.shape[0]
59 new_size = zeros(new_nm)
61 if "no_molecules" not in var.defaults and var.no_molecules != new_nm: 61 ↛ 62line 61 didn't jump to line 62, because the condition on line 61 was never true
62 c.Error("F Number of molecules is not consistant with input file")
63 elif var.no_molecules != new_nm: 63 ↛ 64line 63 didn't jump to line 64, because the condition on line 63 was never true
64 var.no_molecules = new_nm
65 name = list(var.name)
66 name[-2] = str(var.no_molecules)
67 var.name = "".join(name)
69 if "radius_1" not in var.defaults and var.radius.shape[0] != new_nm: 69 ↛ 70line 69 didn't jump to line 70, because the condition on line 69 was never true
70 c.Error("F Number of molecule radii is not consistant with input file")
71 elif "radius_1" in var.defaults: 71 ↛ 74line 71 didn't jump to line 74, because the condition on line 71 was never false
72 var.radius = var.radius[0] + new_size
74 if "dens_1" not in var.defaults and var.dens.shape[0] != new_nm: 74 ↛ 75line 74 didn't jump to line 75, because the condition on line 74 was never true
75 c.Error("F Number of molecule densities is not consistant with input file")
76 elif "dens_1" in var.defaults: 76 ↛ 80line 76 didn't jump to line 80, because the condition on line 76 was never false
77 var.dens = var.dens[0] + new_size
78 var.ms = var.ms[0] + new_size
80 if mag is not None: 80 ↛ 81line 80 didn't jump to line 81, because the condition on line 80 was never true
81 abs_mag = linalg.norm(mag, axis=1)
82 if (abs_mag > 1 + c.EPS).any() ^ (not xyz and (abs_mag > (var.ms * var.vol) + c.EPS).any()):
83 c.Error("F The magnetisation should be less than the saturation magnetisation")
86def new_vars(var):
87 """Calculate New variables from input."""
88 var.hradius = var.radius
89 var.vol = (4.0 / 3.0) * pi * (var.radius**3) # [nm^3]
90 var.hvol = (4.0 / 3.0) * pi * (var.hradius**3) # [nm^3]
92 var.phi = c.random.normal(pi, (2 * pi), size=var.no_molecules)
93 var.theta = c.random.normal(pi / 2, pi, size=var.no_molecules)
94 var.mass = var.vol * var.dens
95 var.alpha = 6.0 * var.eta * c.GBARE / var.ms # dimensionless damping parameter
96 var.geff = c.GBARE / (1.0 + var.alpha**2) # effective gyromagnetic ratio
97 # size of the magnetic fluctuations
98 # Note that c2m is divided here by sqrt(dt), but finally multiplied by dt.
99 # The stochastic part correctly scales with sqrt(dt)
100 var.c2 = sqrt(2.0 * c.KB * var.temp * var.alpha / (var.ms * c.GBARE * var.hvol * var.dt))
101 var.c2 = where(var.c2 > c.EPS2, var.c2, 0)
103 with errstate(all='raise'):
104 try:
105 var.chi0 = (var.ms**2) * var.vol / (3.0 * c.KB * var.temp)
106 var.tauB = 3.0 * var.eta * var.vol / (c.KB * var.temp)
107 except FloatingPointError:
108 c.Error(">W ZeroDivisionError\n{} and {} have been set to infinity".format(c.ustr.chi, c.ustr.taub))
109 var.chi0 = float("inf") * ones(var.no_molecules)
110 var.tauB = float("inf") * ones(var.no_molecules)
113def get_particles(var, flg):
115 if var.location is not None: 115 ↛ 116line 115 didn't jump to line 116, because the condition on line 115 was never true
116 fpos = {}
117 fmom = {}
118 fmag = {}
120 # TODO probably could improve splitting filenames
121 # currently splits on all spaces
122 # move splitting to arguments.py etc
123 location = var.location.split()
125 for stat, loc in enumerate(location):
126 pos, mom, mag = _get_particles(var, flg, loc)
127 fpos[stat] = pos
128 fmom[stat] = mom
129 fmag[stat] = mag
131 if len(var.location.split()) == 1:
132 return pos, mom, mag, pos.shape
133 pos = fpos
134 mom = fmom
135 mag = fmag
137 return pos, mom, mag, pos[0].shape
138 else:
139 pos, mom, mag = _get_particles(var, flg, var.location)
140 return pos, mom, mag, pos.shape
143def _get_particles(var, flg, location):
144 (pos, mom, mag), xyz = initpos(var.no_molecules, var.radius * 2, location, var.boxsize)
146 sanity_checks(var, pos, mag, xyz)
148 new_vars(var)
150 if mag is None: 150 ↛ 160line 150 didn't jump to line 160, because the condition on line 150 was never false
151 mag = zeros_like(pos)
152 # # Transposed (ji not ij) due to theta and phi being row vectors
153 einsum_str = "i, ji -> ij" if var.no_molecules > 1 else "i, ji -> j"
154 mag[:] = einsum(einsum_str,
155 var.ms, array([sin(var.theta) * cos(var.phi),
156 sin(var.theta) * sin(var.phi),
157 cos(var.theta)]))
158 # mag[:, 2] = 1
160 mag = einsum("...iz,...i->...iz", mag, var.ms * var.vol / maximum(sqrt(einsum("...iz,...iz->...i", mag, mag)), c.EPS2))
162 if mom is None: 162 ↛ 164line 162 didn't jump to line 164, because the condition on line 162 was never false
163 mom = zeros_like(pos)
164 elif flg.labview:
165 mom -= einsum("...iz->...z", mom) / mom.shape[0] # unit: 1.e-12 g*cm/s
167 return pos, mom, mag
170# Main calculation
171@debug(['core'])
172def integrate(var={}, flg={}):
173 """
174 Set up of Calculation.
176 Setting up of initial positions magnetisations and momentums
177 as well as neel relaxations for each molecule
179 This is all passed to the parallelisation of the statistical separations
180 """
181 c.reseed(54321)
183 if flg.restart: 183 ↛ 184line 183 didn't jump to line 184, because the condition on line 183 was never true
184 pos = var.pos
185 mag = var.mag
186 mom = var.mom
187 del var.pos
188 del var.mom
189 del var.mag
191 movement = {"var": var, "flg": flg, "mom": mom, "mag": mag, "pos": pos}
192 else:
194 pos, mom, mag, shape = get_particles(var, flg)
196 # Particle movement variables
197 movement = {"var": var, "flg": flg, "mom": mom, "mag": mag, "pos": pos,
198 "op_noise": c.random.standard_normal(size=shape) if flg.op_thermal else None}
200 print(var.name[:-1])
202 # Time recording
203 timer = end(var.finishtime)
205 # Initial conditions
206 calc = calculate(**{"Error": c.Error, "posit": position(**movement),
207 "var": var, "flg": flg, "timer": timer})
209 if hasattr(integrate, "DBG"): 209 ↛ 210line 209 didn't jump to line 210, because the condition on line 209 was never true
210 var.print_contents()
211 flg.print_contents()
213 # Parallelisation of calculations
214 mp_handle()(calc_wrap, calc, var.stats, flg.parallel)
216 return timer, var.name
219class calculate():
220 """
221 1st parallel section.
223 This function does the boilerplate around the brunt of the calculation
224 it is run once for each statistic
226 All the data is then saved in one of three user specified forms
228 1. hdf5
229 2. pickle
230 3. plain text
232 """
234 @debug(["calc"])
235 def __init__(self, **argd):
236 """
237 Initialise constant and variables.
239 dictionary keys: var, flg, mom, mag, pos, timer, posit (initialised position class)
241 Parameters
242 ----------
243 argd: dict
244 dictionary of data
246 """
247 self.__dict__.update(argd)
249 self.var.skip_iters = num_iters(self.var.nmax, self.var.skip)
250 self.savechunk()
252 self.dictcreate = dictionary_creation(self.var, self.flg)
253 self.save = save_m(self.flg.neel, write_data(self.var, self.flg))
254 self.grtime = grace(self.var.stats).time
255 self.end = False
256 self.nsplit = 0
258 self.h_axis = array([[0.0, 0.0, 1.0]]) * ones((self.var.no_molecules, 3))
260 if self.flg.noise:
261 self.getnoise = self._returnnoise
262 else:
263 self.getnoise = self._noop
265 if self.flg.suscep or self.flg.field is False:
266 self.h_axis *= 0
267 self.getfield = self._returnnoextfield
268 else:
269 self.getfield = self._returnextfield
271 if self.flg.prog: 271 ↛ 272line 271 didn't jump to line 272, because the condition on line 271 was never true
272 self.progress = self._prog_verb
273 self.progresstime = 1 # max(600 // self.flg.nout, 1)
274 elif 3 > self.flg.nout > 1:
275 self.progress = self._prog_nverb
276 self.progresstime = max(600 // self.flg.nout, 1)
277 else:
278 self.progress = self._noop
279 self.progresstime = 300
281 if hasattr(self, 'DBG'): 281 ↛ 282line 281 didn't jump to line 282, because the condition on line 281 was never true
282 self._refresh_dict = self._refresh_dict_debug
284 @staticmethod
285 def _noop():
286 pass
288 def _prog_verb(self):
289 c.progress(f"bar {self.moldata_dict['name'][len(self.var.directory):]} {self.count / self.var.nmax} {self.stat}")
291 def _prog_nverb(self):
292 print("{} of {} statistic {}".format(self.count, self.var.nmax, self.stat))
294 def _returnnoise(self):
295 c.random.standard_normal(out=self.noise_setup)
296 self.Hext += c_einsum("ij, i -> ij", self.noise_setup[0], self.var.c2)
298 def _returnnoextfield(self):
299 self.Hext[:] = self.h_axis
301 def _returnextfield(self):
302 self.Hext[:] = field(self.time.time, H0=self.var.H_0, nu=self.var.nu) * self.h_axis
304 def progress_report(self):
305 """Progress reporter."""
306 self.count += self.var.skip
308 self.countdown = self.timer.gettimegone()
309 if (self.countdown - self.oldcount) > self.progresstime: 309 ↛ 310line 309 didn't jump to line 310, because the condition on line 309 was never true
310 self.oldcount = self.countdown
311 self.progress()
312 if self.timer.gettimeleft() <= self.grtime:
313 self.moldata_dict = self.save.stop(self.moldata_dict, self.posit.count)
314 c.Error("W Hit walltime, trying to exit cleanly")
316 def savechunk(self):
317 """Adjust savechunk."""
318 self.bksavechunk = self.var.savechunk
319 if self.var.savechunk > self.var.skip_iters:
320 # split can't be larger than no_iterations
321 self.var.savechunk = self.var.skip_iters
323 def iterationadjust(self):
324 """Adjust iterations for writing and storing."""
325 if self.flg.restart: 325 ↛ 326line 325 didn't jump to line 326, because the condition on line 325 was never true
326 self.rstep = ((self.var.extra_iter[self.stname]) * self.var.skip)
327 self.cstep = self.var.nmax - self.rstep
328 # Doesn't include post optimise initial positions step
329 # Does include post optimise initial positions step
330 self.cwritten = self.var.skip_iters - self.var.extra_iter[self.stname] + 1
331 print("Stat {} Written: {} / {}".format(self.stat, self.cwritten, self.var.skip_iters + 1))
332 if self.cwritten == self.var.skip_iters + 1:
333 self.finishdata(0, self.cstep)
334 exit(0)
335 elif self.cwritten > self.var.skip_iters + 1:
336 print("Bigger?", self.cwritten, self.var.skip_iters, num_iters(self.rstep, self.var.skip))
337 exit(1)
339 self.var.skip_iters = num_iters(self.rstep, self.var.skip)
340 nmax = self.rstep
341 else:
342 nmax = self.var.nmax
344 if self.flg.restart or isinstance(self.posit.pos, dict): 344 ↛ 345line 344 didn't jump to line 345, because the condition on line 344 was never true
345 self.posit.pos = self.posit.pos[self.stat]
346 self.posit.mag = self.posit.mag[self.stat]
347 self.posit.mom = self.posit.mom[self.stat]
349 self.savechunk()
351 # savechunk as 0 == save at the end
352 self.writes = nmax // (self.var.savechunk * self.var.skip) if self.var.savechunk != 0 else 0
354 self.state_int = max(self.writes // 10, 1)
355 self.finalmemoryloop = (nmax % (self.var.savechunk * self.var.skip)) / self.var.skip if self.var.savechunk != 0 else 0
357 self.finalskiploop = nmax % self.var.skip
358 if self.finalskiploop == 0 and self.finalmemoryloop % 1 != 0: 358 ↛ 360line 358 didn't jump to line 360, because the condition on line 358 was never true
359 # finalmemory loop not whole number and skip fits exactly into nmax
360 self.finalskiploop = self.var.skip
362 # whole number
363 self.finalmemoryloop = int(self.finalmemoryloop)
365 # last dictionary size: Number of memory loops + last skip loop
366 self.remainder = self.finalmemoryloop + 1 if self.finalskiploop > 0 else 0
368 if self.finalmemoryloop == 0 and self.finalskiploop == 0: 368 ↛ 370line 368 didn't jump to line 370, because the condition on line 368 was never true
369 # Always run final loop at least once
370 self.finalmemoryloop = self.var.savechunk
371 self.writes -= 1 if self.writes > 0 else 0
373 if hasattr(self, 'DBG'): 373 ↛ 374line 373 didn't jump to line 374, because the condition on line 373 was never true
374 print(f"Stat {self.stat}", f"Write_loop: {self.writes}",
375 f"Savechunk: {self.var.savechunk}", f"Skip: {self.var.skip}",
376 f"Final_M_loop: {self.finalmemoryloop}",
377 f"Final_S_loop: {self.finalskiploop}",
378 f"Remainder: {self.remainder}",
379 f"Total_tosave: {self.var.skip_iters}")
381 def randomnumbers(self):
382 """Set up random number starting point."""
383 if self.flg.restart: 383 ↛ 384line 383 didn't jump to line 384, because the condition on line 383 was never true
384 c.rgen.state = self.var.RandNoState[self.stname]
385 else:
386 c.reseed(54321)
387 c.jump(self.stat)
389 def dictionarys(self):
390 """Create dictionaries for data storage."""
391 self.moldata_dict_end = dictionary_creation(self.var, self.flg, self.remainder)
392 if self.bksavechunk != self.var.savechunk: 392 ↛ 393line 392 didn't jump to line 393, because the condition on line 392 was never true
393 self.dictcreate = dictionary_creation(self.var, self.flg)
394 self.moldata_dict = self.dictcreate.copy()
395 # File naming
396 self.moldata_dict['name'] += "{:g}.{}".format(self.stat + 1, self.flg.save_type)
397 self.name = self.moldata_dict['name']
399 def _refresh_dict(self, dictionary):
400 self.moldata_dict = dictionary.copy()
401 self.moldata_dict['name'] = self.name
402 self.save.remove_state(dictionary)
404 def _refresh_dict_debug(self, dictionary):
405 self.moldata_dict = deepcopy(dictionary)
406 self.moldata_dict['name'] = self.name
407 self.save.remove_state(dictionary)
409 @addpid("Error")
410 def setup(self):
411 """Set up instance for each parallel calculation."""
412 self.noise_setup = zeros((3, self.var.no_molecules, 3))
413 self.Hext = zeros((self.var.no_molecules, 3))
415 self.stname = self.save.stname = f"stat{self.stat}"
417 self.iterationadjust()
418 self.randomnumbers()
419 self.dictionarys()
421 self.flg.save_type = self.save.setup(self.name)
423 self.starttime()
424 self.firststep()
425 self.prerange()
427 # Progress report varables
428 self.oldcount = self.timer.gettimegone()
430 def prerange(self):
431 """Preallocate ranges."""
432 self.dlrange = range(self.writes)
433 self.mlrange = range(self.var.savechunk)
434 self.slrange = range(self.var.skip)
436 self.mlrangefinal = range(self.finalmemoryloop)
437 self.slrangefinal = range(self.finalskiploop)
439 def run(self, stat):
440 """
441 Run calculation.
443 Parameters
444 ----------
445 stat: int
446 statistic number
448 """
449 self.stat = stat
450 self.setup()
451 self.disksaveloop()
453 def starttime(self):
454 """Start timestep recording."""
455 self.time = _time(self.var.dt, self.var.time)
457 self.posit.time = self.time
459 def firststep(self):
460 """Set up initial conditions and calculate first step."""
461 self.posit.initialconditions()
462 if self.flg.restart is None: 462 ↛ 468line 462 didn't jump to line 468, because the condition on line 462 was never false
463 self.count = 0
464 first_step = dictionary_creation(self.var, self.flg, 1)
465 first_step["name"] = self.moldata_dict['name']
466 self.save.file(self.save.memory(first_step, self.posit.prop, self.time))
467 else:
468 self.count = self.cstep
469 self.save.restart(self.moldata_dict['name'], self.var.extra_iter, self.var.SCFcount, self.cwritten)
471 def disksaveloop(self):
472 """Save to disk loop."""
473 for dl in self.dlrange:
474 self.memorysaveloop(self.mlrange)
475 if self.save.end: 475 ↛ 476line 475 didn't jump to line 476, because the condition on line 475 was never true
476 return
477 if dl % self.state_int == 0 and dl != 0:
478 self.save.state(self.moldata_dict, self.posit.count)
479 self.save.file(self.moldata_dict, self.posit.count)
480 self._refresh_dict(self.dictcreate)
482 self.finaliteration()
484 def memorysaveloop(self, loop):
485 """
486 Save to memory loop.
488 Parameters
489 ----------
490 loop: int
491 loop size
493 """
494 for _ in loop:
495 self.skiploop(self.slrange)
497 # Collect data
498 self.moldata_dict = self.save.memory(self.moldata_dict, self.posit.prop, self.time)
500 self.progress_report()
502 def skiploop(self, loop):
503 """
504 Skip loop, no saving required.
506 Parameters
507 ----------
508 loop: int
509 loop size
511 """
512 for _ in loop:
513 # External field
514 self.getfield()
516 # System noise
517 self.getnoise()
519 # Iterate
520 self.posit.propagate(self.Hext, self.noise_setup)
522 # time update
523 self.time.time_update()
525 def finaliteration(self):
526 """
527 Last iteration loop.
529 Setup for last step saving useful things for restart
530 """
531 if self.moldata_dict_end is not None: 531 ↛ 534line 531 didn't jump to line 534, because the condition on line 531 was never false
532 self._refresh_dict(self.moldata_dict_end)
533 else:
534 self._refresh_dict(self.dictcreate)
536 self.memorysaveloop(self.mlrangefinal)
538 if self.finalskiploop > 0: 538 ↛ 543line 538 didn't jump to line 543, because the condition on line 538 was never false
539 self.count += self.finalskiploop
540 self.skiploop(self.slrangefinal)
541 self.moldata_dict = self.save.memory(self.moldata_dict, self.posit.prop, self.time)
543 self.save.end = True
544 self.save.file(self.moldata_dict, self.posit.count)
546 self.progress()
547 self.finishdata(self.posit.count, self.count)
549 def finishdata(self, SCFcount, count):
550 SCFcount += self.var.SCFcount if self.flg.restart else 0
551 print(f"\nStat {self.stat}\n",
552 f"SCF cycles: {SCFcount}\n",
553 f"Total Iterations: {self.var.nmax}\n",
554 f"Completed Iterations: {count}\n",
555 f"SCF per Iteration: {(SCFcount / count) if count > 0 else 0}")
558class save_m():
559 """
560 Storing function.
562 Stores data in memory until asked to save to file where it calls the writer
564 Parameters
565 ----------
566 neel: bool
567 Is neel relaxation required?
568 wd: instance
569 instance of writing class
571 """
573 @debug(["save"])
574 def __init__(self, neel, wd):
575 """Initialise save routine."""
576 self.wd = wd
578 self.end = False
579 self.neel = neel
580 if self.neel:
581 self.neel_save = self._neel_save
582 else:
583 self.neel_save = self._no_neel_save
584 self.written = 0
585 self.SCFcount = 0
586 self._reset_ind()
588 def _neel_save(self, data_dict, data):
589 data_dict['neel_relaxation'][self.splitcount, :] = data["neel_count"].count
590 return data_dict
592 @staticmethod
593 def _no_neel_save(data_dict, data):
594 return data_dict
596 def _reset_ind(self):
597 self.splitcount = 0
599 def _incr_splitcount(self):
600 self.splitcount += 1
601 self.written += 1
603 def setup(self, name):
604 """Set up writing class."""
605 return self.wd.setup(name)
607 def restart(self, name, extra_iter, SCFcount, written):
608 """Save extra_iters, SCFcount and current written."""
609 self.written = written
610 self.SCFcount = SCFcount
611 self.wd.write({'name': name, 'vars': {'extra_iter': extra_iter}})
613 def file(self, data_dict, SCFcount=0):
614 """
615 Save current data block to file.
617 Parameters
618 ----------
619 data_dict: dict
620 Storage dictionary
622 """
623 if self.end:
624 self.state(data_dict, SCFcount)
625 self.wd.write(data_dict)
626 self._reset_ind()
628 def state(self, data_dict, SCFcount):
629 """Save current state."""
630 data_dict['vars']['RandNoState'][self.stname] = c.rgen.state
631 data_dict['vars']['written'] = self.written
632 data_dict['vars']['SCFcount'] = self.SCFcount + SCFcount
634 def remove_state(self, data_dict):
635 """Remove current state."""
636 for val in ['RandNoState', 'written', 'SCFcount']:
637 data_dict['vars'][val] = {}
639 def stop(self, data_dict, SCFcount=0):
640 """
641 Emergency Stop saving.
643 Save current data block to file.
645 Parameters
646 ----------
647 data_dict: dict
648 Storage dictionary
650 """
651 self.end = True
652 sc = self.splitcount # save to avoid reset
654 self.file(self.cutter(data_dict, deepcopy(data_dict), None, sc), SCFcount)
656 return self.cutter(data_dict, data_dict, sc, None)
658 def cutter(self, orig, copy, start, end):
659 """Return a section of input dictionary."""
660 copy['position'] = orig['position'][start:end, :, :]
661 copy['iter_time'] = orig['iter_time'][start:end, :]
662 copy['magnetisation'] = orig['magnetisation'][start:end, :, :]
663 copy['forces'] = orig['forces'][start:end, :, :]
664 copy['momentum'] = orig['momentum'][start:end, :, :]
666 if self.neel:
667 copy['neel_relaxation'][start:end, :] = orig['neel_relaxation'][start:end, :]
669 return copy
671 def memory(self, data_dict, data, time):
672 """
673 Save to memory current iteration data.
675 Parameters
676 ----------
677 data_dict: dict
678 Storage dictionary
679 data: dict
680 data to be stored
681 time: instance
682 timestep instance
684 Returns
685 -------
686 data_dict: dict
687 Storage dictionary
689 """
690 data_dict['position'][self.splitcount, :, :] = data["pos"]
691 data_dict['iter_time'][self.splitcount, :] = time.iter, time.time
692 data_dict['magnetisation'][self.splitcount, :, :] = data["mag"]
693 data_dict['forces'][self.splitcount, :, :] = data["forces"]
694 data_dict['momentum'][self.splitcount, :, :] = data["mom"]
696 data_dict = self.neel_save(data_dict, data)
698 self._incr_splitcount()
700 return data_dict
703@debug(['core'])
704def dictionary_creation(var, flg, extra=False):
705 """
706 Creation of initial dictionary.
708 - all data is the same at this point
710 - Uses nested dictionaries for ease of storage
711 """
712 if extra is False:
713 size = var.savechunk
714 elif extra > 0:
715 size = extra
716 else:
717 return None
719 moldata_dict = _getdicts(size, var.no_molecules, flg.neel)
721 moldata_dict['mango_version'] = c.version
722 moldata_dict['name'] = var.name
724 moldata_dict['flags'] = flg.__dict__.copy()
726 moldata_dict['vars'] = var.__dict__.copy()
728 del moldata_dict['vars']['finishtime']
729 with suppress(KeyError):
730 del moldata_dict['vars']['defaults']
731 del moldata_dict['vars']['time']
732 del moldata_dict['vars']['name']
734 for val in ['RandNoState', 'extra_iter', 'SCFcount', 'written']:
735 moldata_dict['vars'][val] = {}
737 return moldata_dict
740def _getdicts(x, y, neel):
741 new_dict = nestedDict()
742 new_dict['iter_time'] = zeros((x, 2))
743 new_dict['position'] = zeros((x, y, 3))
744 new_dict['magnetisation'] = zeros_like(new_dict['position'])
745 new_dict['forces'] = zeros_like(new_dict['position'])
746 new_dict['momentum'] = zeros_like(new_dict['position'])
748 # new_dict['CoM'] = zeros((x, 3))
749 # new_dict['CoM_vel'] = zeros_like(new_dict['CoM'])
750 # new_dict['momenta']['total'] = zeros_like(new_dict['CoM'])
751 # new_dict['momenta']['total_mag'] = zeros_like(new_dict['CoM'])
752 # new_dict['momenta']['total_angular'] = zeros_like(new_dict['CoM'])
753 # new_dict['energy']['kinetic'] = zeros(x)
754 # new_dict['energy']['trans_pot'] = zeros_like(new_dict['energy']['kinetic'])
755 # new_dict['energy']['mag_pot'] = zeros_like(new_dict['energy']['kinetic'])
756 # new_dict['energy']['total'] = zeros_like(new_dict['energy']['kinetic'])
757 # new_dict['energy']['kineticm'] = zeros((x, y))
759 if neel:
760 new_dict['neel_relaxation'] = zeros((x, y))
762 return new_dict
765if __name__ == "__main__":
766 pass