Hide keyboard shortcuts

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

1import re 

2from numpy import zeros, genfromtxt, array, triu_indices, ndarray 

3from argparse import HelpFormatter, ArgumentParser 

4from sys import exit, argv 

5from os import makedirs, listdir 

6 

7from mango.debug import debug 

8from mango.io import read_inputfile, read_data, restartfile_read, get_restartdata 

9from mango.constants import _variables, c, keys 

10from mango.managers import start_server 

11 

12 

13# def _parsingav(value): 

14# """Set the averaging of a data set to true or false.""" 

15# return (value == "av") 

16 

17 

18def col_check(check): 

19 """Check columns are available.""" 

20 diffx = set(check["x"][:, 0]).difference(c.columns_flat) 

21 diffy = set(check["y"][:, 0]).difference(c.columns_flat) 

22 diff = set(list(diffx) + list(diffy)).difference(set(['+', '-', '*', '/'])) 

23 if diff != set([]): 

24 c.Error("F Invalid column{} {}, unable to plot graph".format( 

25 "s" if len(list(diff)) > 1 else "", diff)) 

26 

27 

28class SmartFormatter(HelpFormatter): 

29 """ 

30 Smart help formatter. 

31 

32 Allows for splitting the help 

33 over multiple lines by starting help with 'R|' 

34 """ 

35 

36 def _split_lines(self, text, width): 

37 if text.startswith('R|'): 

38 return text[2:].splitlines() 

39 return HelpFormatter._split_lines(self, text, width) 

40 

41 def _format_action_invocation(self, action): 

42 if not action.option_strings: 42 ↛ 43line 42 didn't jump to line 43, because the condition on line 42 was never true

43 metavar, = self._metavar_formatter(action, action.dest)(1) 

44 return metavar 

45 

46 else: 

47 parts = [] 

48 

49 # if the Optional doesn't take a value, format is: 

50 # -s, --long 

51 if action.nargs == 0: 

52 parts.extend(action.option_strings) 

53 

54 # if the Optional takes a value, format is: 

55 # -s ARGS, --long ARGS 

56 else: 

57 default = action.dest.upper() 

58 args_string = self._format_args(action, default) 

59 

60 # parts.append('%s %s' % (option_string, args_string)) ### this is change 

61 ls = args_string.split(" ", 1) 

62 if len(ls) == 2: 

63 args_string = ls[1][:-1] if ls[0].startswith('[') else ls[1] 

64 

65 parts.extend(action.option_strings) 

66 parts[-1] += ' %s' % args_string 

67 

68 return ', '.join(parts) 

69 

70 

71def list_add_arguments(self, k): 

72 """ 

73 Parse arguments from dictionary. 

74 

75 Parameters 

76 ---------- 

77 k: OrderedDict 

78 Dictionary of keywords and defaults 

79 

80 """ 

81 for i, j in k.items(): 

82 args = j[1][0] 

83 kw = j[1][1] 

84 args = tuple(args) if isinstance(args, list) else [args] 

85 try: 

86 if 'type' not in kw and 'action' not in kw: 

87 kw['type'] = j[0][1] 

88 if 'help' in kw: 88 ↛ 90line 88 didn't jump to line 90, because the condition on line 88 was never false

89 kw['help'] = kw['help'].format(j[0][2].rsplit("/", 1)[-1] if j[0][0] == 'logs' else j[0][2]) 

90 kw['default'] = None 

91 self.add_argument(*args, **kw) 

92 

93 except TypeError: 

94 self.add_argument(*args) 

95 

96 

97def notebook_help(k=keys.words): 

98 """Print Help in Jupyter Notebook.""" 

99 from IPython.display import HTML, display 

100 st = '<table><tr><th>VariableName</th><th>Help</th></tr>' 

101 it = '<tr><td>{}</td><td>{}</td></tr>' 

102 end = '</table>' 

103 s = _help(k, st, it, _mlines_nb, end) 

104 display(HTML(s)) 

105 exit(0) 

106 

107 

108def _mlines_nb(s, it, i, j, fmt): 

109 s += it.format(i, j[1][1]['help'].format(fmt)[2:]) 

110 return s 

111 

112 

113def interactive_help(k=keys.words): 

114 """Print commandline help.""" 

115 st = 'VariableName' + 10 * ' ' + 'Help\n' + '-' * 30 + '\n' 

116 it = '{:<22s}{}\n\n' 

117 end = '' 

118 s = _help(k, st, it, _mlines_ih, end) 

119 print(s) 

120 exit(0) 

121 

122 

123def _mlines_ih(s, it, i, j, fmt): 

124 if len(j[1][1]['help'].split('\n')) > 1: 

125 string = j[1][1]['help'].split('\n') 

126 string[0] = string[0][2:] 

127 string[-1] = string[-1].format(fmt) 

128 newl = it.format(i, string[0])[:-1] 

129 for line in string[1:]: 

130 newl += it.format('', line)[:-1] 

131 s += newl + '\n' 

132 else: 

133 s += it.format(i, j[1][1]['help'].format(fmt)[2:]) 

134 return s 

135 

136 

137def _help(k, st, it, func, end): 

138 """ 

139 Format help. 

140 

141 Parameters 

142 ---------- 

143 k: dict 

144 dictionary of keywords 

145 st: str 

146 Header of help 

147 it: str 

148 table cells 

149 func: function 

150 entry formatter 

151 end: str 

152 final line of table 

153 

154 Returns 

155 ------- 

156 s: str 

157 formatted help string 

158 

159 """ 

160 s = st 

161 for i, j in k.items(): 

162 if j[0][0] == 'logs': 

163 fmt = j[0][2].rsplit("/", 1)[-1] 

164 else: 

165 fmt = j[0][2] 

166 s = func(s, it, i, j, fmt) 

167 # if len(j[1][1]['help'].split('\n')) > 1: 

168 # string = j[1][1]['help'].split('\n') 

169 # string[0] = string[0][2:] 

170 # string[-1] = string[-1].format(fmt) 

171 # newl = it.format(i, string[0])[:-1] 

172 # for line in string[1:]: 

173 # newl += it.format('', line)[:-1] 

174 # s += newl + '\n' 

175 # else: 

176 # s += it.format(i, j[1][1]['help'].format(fmt)[2:]) 

177 s += end 

178 return s 

179 

180 

181def gethelp(opts, parser): 

182 """Help output selector.""" 

183 if opts == "-h" or '-h' in argv: 

184 c._banner() 

185 if c.using_IP: 185 ↛ 186line 185 didn't jump to line 186, because the condition on line 185 was never true

186 notebook_help(keys.words) 

187 elif c.interactive: 187 ↛ 188line 187 didn't jump to line 188, because the condition on line 187 was never true

188 interactive_help(keys.words) 

189 else: 

190 parser.parse_args(['-h']) 

191 elif opts == '-ifh' or '-ifh' in argv: 

192 c._banner() 

193 interactive_help(keys.words) 

194 

195 

196def parse_in(k=keys.words): 

197 """ 

198 Argparse function. 

199 

200 Parameters 

201 ---------- 

202 k: Ordereddict 

203 dictionary of available commands 

204 

205 Returns 

206 ------- 

207 parser: instance 

208 argparse parser instance 

209 

210 """ 

211 ArgumentParser.list_add_arguments = list_add_arguments 

212 parser = ArgumentParser(prog='mango', 

213 description="Mango: magnetic nanoparticle simulator CLI Help", 

214 formatter_class=SmartFormatter) 

215 

216 parser.list_add_arguments(k) 

217 return parser 

218 

219 

220def array_vars(parsing, variables): 

221 """Set up arrays for variables.""" 

222 for key in variables: 

223 z_arr = zeros(parsing.no_molecules) 

224 if isinstance(parsing.__dict__[key], str): 224 ↛ 225line 224 didn't jump to line 225, because the condition on line 224 was never true

225 parsing.__dict__[key] = genfromtxt(parsing.__dict__[key], dtype=float) 

226 elif isinstance(parsing.__dict__[key], float): 

227 parsing.__dict__[key] += z_arr 

228 parsing.defaults += ["{}_1".format(key)] 

229 elif len(parsing.__dict__[key]) == parsing.no_molecules: 

230 parsing.__dict__[key] = array(parsing.__dict__[key], dtype=float) 

231 elif len(parsing.__dict__[key]) == 1: 

232 parsing.__dict__[key] = float(parsing.__dict__[key][0]) + z_arr 

233 parsing.defaults += ["{}_1".format(key)] 

234 else: 

235 c.Error("F {} array must be the same length as No. MNPs".format(key)) 

236 

237 return parsing 

238 

239 

240def setdefaults(parsing, default_val): 

241 """ 

242 Set default values for variables that weren't in input. 

243 

244 Parameters 

245 ---------- 

246 parsing: instance 

247 ArgumentParser instance 

248 default_val: dict 

249 Default Values 

250 

251 Returns 

252 ------- 

253 parsing: instance 

254 ArgumentParser instance 

255 

256 """ 

257 parsing.defaults = [] 

258 for key, value in default_val.items(): 

259 if key not in parsing.__dict__ or parsing.__dict__[key] is None: 

260 parsing.__dict__[key] = default_val[key] 

261 parsing.defaults += [key] 

262 return parsing 

263 

264 

265@debug(['args']) 

266def parse(argparse, opts={}): 

267 """ 

268 Parse user input. 

269 

270 Parameters 

271 ---------- 

272 argparse: bool 

273 Is argparse used? 

274 opts: dict 

275 dict of arguments if argparse isn't used 

276 

277 Returns 

278 ------- 

279 parsing: instance 

280 instance of variables 

281 

282 """ 

283 parser = parse_in(keys.words) 

284 

285 gethelp(opts, parser) 

286 

287 if argparse: 

288 parsing = parser.parse_args() 

289 parsing = read_inputfile(parsing.inputfile, parsing.restart) if parsing.inputfile else parsing 

290 else: 

291 parsing = read_inputfile(opts) 

292 

293 if parsing.restart: 293 ↛ 294line 293 didn't jump to line 294, because the condition on line 293 was never true

294 return restart_in(parsing) 

295 

296 if ('no_molecules' in parsing.__dict__ and 'boxsize' not in parsing.__dict__): 296 ↛ 297line 296 didn't jump to line 297, because the condition on line 296 was never true

297 rad = 1.1 * parsing.radius if 'radius' in parsing.__dict__ else keys.defaults["radius"] 

298 parsing.boxsize = parsing.no_molecules * rad 

299 

300 parsing = setdefaults(parsing, keys.defaults) 

301 # parsing.average = {av: False for av in c.averages} 

302 parsing.files = {file: False for file in c.files} 

303 

304 if parsing.cfile: 304 ↛ 305line 304 didn't jump to line 305, because the condition on line 304 was never true

305 if ['lf'] == parsing.cfile: 

306 c.Error("F No file type specified") 

307 parsing.lastframe = ('lf' in parsing.cfile) 

308 getfiles = set(parsing.cfile) & set(c.files) 

309 for i in getfiles: 

310 parsing.files[i] = True 

311 # parsing.average[c.averages[c.files.index(i)]] = _parsingav(parsing.cfile[parsing.cfile.index(i) - 1]) 

312 else: 

313 parsing.lastframe = None 

314 

315 if parsing.column: 

316 parsing.column, parsing.files = column_manip(parsing.column, parsing.files) 

317 

318 return splitvars(sanity(fixparam(array_vars(parsing, ['radius', 'dens'])))) 

319 

320 

321def fixparam(p): 

322 """Modify parameters for units and types.""" 

323 set_const(p.no_molecules) 

324 p.Mdens *= 1e-6 # [1e6 emu/g] 

325 p.sigma, p.limit = calcsigmalim(p.radius, p.no_molecules) 

326 p.epsilon = c.Ar_KB * (p.sigma / c.Ar_sigma)**3 if p.epsilon is None else p.epsilon 

327 p.ms = p.Mdens * p.dens # [1e6 emu/g] * [g/mol] 

328 p.nu *= 1e-12 # time [1e-12 s] -> [1e12 Hz] 

329 p.extra_iter = None 

330 p.RandNoState = {} 

331 p.nmax = int(p.nmax) 

332 p.savechunk = int(p.savechunk) 

333 p.run = int(p.run) 

334 p.time = 0.0 

335 p.field = (not p.suscep and p.H_0 != 0.0) 

336 p.stats = list(range(p.stats)) 

337 return p 

338 

339 

340def calcsigmalim(radius, np): 

341 """Calculate sigma and cutoff limit.""" 

342 dists = radius[c.tri[0]] + radius[c.tri[1]] 

343 return dists / (2**(1 / 6)), 1 / dists 

344 

345 

346def splitvars(p): 

347 """ 

348 Split parameters into variables and flags. 

349 

350 Parameters 

351 ---------- 

352 p: instance 

353 argparse instance 

354 

355 Returns 

356 ------- 

357 var, flg: instance 

358 variable and flag instances 

359 

360 """ 

361 # Store variables and flags 

362 var_list, flags_list = keys.flgorvar() 

363 

364 def store(lis, dic): 

365 nd = {} 

366 for l in lis: 

367 nd[l] = dic[l] 

368 return nd 

369 

370 # Class of variables and flags 

371 var = _variables(**store(var_list, p.__dict__)) 

372 flg = _variables(**store(flags_list, p.__dict__)) 

373 

374 # Some Variables need changing based on input 

375 flg.pp = not flg.run == 0 

376 

377 if flg.suscep == []: 377 ↛ 378line 377 didn't jump to line 378, because the condition on line 377 was never true

378 flg.suscep = True 

379 

380 if var.temp == 0: 380 ↛ 381line 380 didn't jump to line 381, because the condition on line 380 was never true

381 flg.neel = flg.suscep = False 

382 

383 return var, flg 

384 

385 

386def sanity(p): 

387 """Sanity checks.""" 

388 if p.dens.any() <= 0.0: 388 ↛ 389line 388 didn't jump to line 389, because the condition on line 388 was never true

389 c.Error("F The density of all particles must be greater than zero") 

390 

391 if p.temp < 0: 391 ↛ 392line 391 didn't jump to line 392, because the condition on line 391 was never true

392 c.Error("F Temperature must be positive") 

393 

394 if p.eta < 0: 394 ↛ 395line 394 didn't jump to line 395, because the condition on line 394 was never true

395 c.Error("F Viscosity must be positive") 

396 

397 if isinstance(p.boxsize, ndarray) and (p.boxsize.size != 1 or p.boxsize.size != 3): 397 ↛ 398line 397 didn't jump to line 398, because the condition on line 397 was never true

398 c.Error("F Boxsize must be 1 dimensional or 3 dimensional") 

399 

400 return p 

401 

402 

403def filenaming(var, flg, run=1): 

404 """ 

405 File naming. 

406 

407 Avoid overwriting files etc. 

408 

409 Parameters 

410 ---------- 

411 var, flg: instance 

412 class variable and flag instances 

413 

414 """ 

415 if flg.pp or flg.restart: 415 ↛ 416line 415 didn't jump to line 416, because the condition on line 415 was never true

416 var.directory = var.logs if var.logs.endswith("/") else var.logs + "/" 

417 else: 

418 var.directory = "{}{}n{:g}_{:g}K_{}{:g}nm/".format( 

419 var.logs, "" if var.logs.endswith("/") else "/", 

420 var.nmax, var.temp, 

421 '' if flg.suscep else '{:g}gauss_{:g}kHz_'.format(var.H_0 * 1e-6, var.nu * 1e-15), 

422 var.radius[0] * 10) 

423 # Make Log directory as needed 

424 makedirs(var.directory, exist_ok=True) 

425 

426 # avoid overwriting other log files 

427 try: 

428 files = listdir(var.directory) 

429 except FileNotFoundError: 

430 c.Error("F Log directory does not exist") 

431 

432 # Get run number for filename 

433 if not flg.pp and not flg.restart: 433 ↛ 438line 433 didn't jump to line 438, because the condition on line 433 was never false

434 while any(file.startswith('{}Run{:g}'.format("S_" if flg.suscep else "", 434 ↛ 436line 434 didn't jump to line 436, because the condition on line 434 was never true

435 run)) for file in files): 

436 run += 1 

437 

438 flg.run = flg.run if flg.pp or flg.restart else run 

439 

440 check_name = '{}Run{:g}_mol-'.format("S_" if flg.suscep else "", flg.run) 

441 

442 if flg.pp and not flg.ufile: 442 ↛ 443line 442 didn't jump to line 443, because the condition on line 442 was never true

443 from mango.pp.util import interactive_getfiles 

444 flg, check_name = interactive_getfiles(flg, check_name, files) 

445 

446 # Add final name and save location to variables 

447 var.name = "{}{}{:g}.".format(var.directory, check_name, var.no_molecules) 

448 

449 

450def verbosity(var, flg): 

451 """ 

452 Verbosity Changing. 

453 

454 Parameters 

455 ---------- 

456 var, flg: instance 

457 class variable and flag instances 

458 

459 """ 

460 c.header(flg.nout >= 2, flg.nout >= 4) 

461 

462 verb = (flg.nout >= 2) 

463 

464 flg.prog = (flg.nout >= 3 and c.tinfo['otty']) 

465 

466 c.Error("EV {} {} {} {}".format(verb, var.directory, flg.run, 1 if flg.pp else 0)) 

467 

468 # progress bar switches 

469 if flg.prog: 

470 c.progress = start_server("Prog") 

471 if not flg.pp: # (flg.column is not False or flg.suscep or flg.files['xyz']): 

472 c.progress(f"setup {var.stats}") 

473 

474 

475def set_const(no_molecules): 

476 c.tri = triu_indices(n=no_molecules, k=1) 

477 c.set_accuracy(c.EPS2) 

478 

479 

480def restart_in(parsing): 

481 """ 

482 Get data from run to be restarted. 

483 

484 Parameters 

485 ---------- 

486 parsing: instance 

487 argparse parsing instance 

488 

489 Returns 

490 ------- 

491 variables: instance 

492 class instance of all variables to be used 

493 

494 """ 

495 filenames, save_type, directory, total = restartfile_read(parsing.restart) 

496 

497 restart, restartflags, written = get_restartdata(read_data(filenames[0], save_type), filenames) 

498 

499 restart.extra_iter = {f'stat{k}': total - writ - 1 for k, writ in written.items()} 

500 

501 restart.time = 0.0 

502 restart.stats = list(written.keys()) 

503 if parsing.walltime is not None: 

504 restart.walltime = parsing.walltime 

505 

506 for i in ['logs', 'directory']: 

507 restart.__dict__[i] = directory 

508 

509 restartflags.opt = False 

510 restartflags.restart = parsing.restart 

511 

512 set_const(restart.no_molecules) 

513 

514 return restart, restartflags 

515 

516 

517def column_manip(column_var, files): 

518 """ 

519 Create a list of plots to be made. 

520 

521 TODO cleanup 

522 

523 Parameters 

524 ---------- 

525 column_var: list 

526 list parsed from user input 

527 eg. ["time kinetic[5,:,3] + avtrans_pot / - avmag_pot[:100]", "time kinetic"] 

528 files: dict 

529 files to create 

530 

531 Returns 

532 ------- 

533 plot_store: dict 

534 plots to create 

535 files: dict 

536 files to create 

537 

538 """ 

539 def search(key): 

540 """ 

541 Search for averaging of data. 

542 

543 Parameters 

544 ---------- 

545 key: str 

546 key to find 

547 

548 Returns 

549 ------- 

550 key: str 

551 found key 

552 inlist: bool 

553 is key data to be averaged? 

554 

555 """ 

556 inlist = False 

557 if key == "time": 

558 return [key, True] 

559 

560 for enum, i in enumerate(c.columns.keys()): 

561 if key in c.columns[i] or key[2:] in c.columns[i]: 

562 files[i] = True 

563 inlist = True 

564 # if not average_var[c.averages[enum]] or key[:2] == 'av': 

565 # average_var[c.averages[enum]] = _parsingav(key[:2]) 

566 # key = key[2:] if average_var[c.averages[enum]] else key 

567 

568 return [key, inlist] 

569 

570 def rearray(j): 

571 """ 

572 Rearrayify array splitting. 

573 

574 Parameters 

575 ---------- 

576 j: str 

577 array indexing like string eg 5,: 

578 

579 Returns 

580 ------- 

581 j: str 

582 proper array index eg [5,:] 

583 

584 """ 

585 for ind in range(len(j) // 2): 

586 j[(ind * 2) + 1] = "[" + j[(ind * 2) + 1] + "]" 

587 return j 

588 

589 def shapedlist(j, cols_list_arr): 

590 """Shape array so its square also marker for 'missing' array.""" 

591 arr_j = array(j + [''] if len(j) % 2 == 1 else j).reshape(-1, 2) 

592 # split elements at operations 

593 for no, k in enumerate(arr_j[:, 0]): 

594 cols_list_arr += [search(cl) for cl in filter(None, re.split('([-+/*])', k))] 

595 if arr_j[no, 1] != '': 

596 cols_list_arr[-1][1] = arr_j[no, 1] 

597 

598 cols_list_arr = [] 

599 cols_list = [] 

600 plot_no = 1 

601 plot_store = {} 

602 

603 for i, j in enumerate(column_var): 

604 # Plotting multiple graphs with multiple lines, split to new graph 

605 # if j == ",": 

606 # plot_store["plot_{}".format(plot_no)] = {"x": array(cols_list), "y": array(cols_list_arr)} 

607 # col_check(plot_store["plot_{}".format(plot_no)]) 

608 # cols_list_arr = [] 

609 # cols_list = [] 

610 # plot_no += 1 

611 # continue 

612 j = re.split(r'[\[\]]', j.replace(" ", "")) 

613 if len(j) > 1: 

614 shapedlist(rearray(j), cols_list) if i == 0 else shapedlist(rearray(j), cols_list_arr) 

615 else: 

616 for k in j: 

617 colum = re.split('([-+/*])', k) 

618 for cl in colum: 

619 if i == 0: 

620 cols_list += [search(cl)] 

621 else: 

622 cols_list_arr += [search(cl)] 

623 

624 # if j != ",": 

625 plot_store["plot_{}".format(plot_no)] = {"x": array(cols_list), "y": array(cols_list_arr)} 

626 col_check(plot_store["plot_{}".format(plot_no)]) 

627 

628 return plot_store, files 

629 

630 

631if __name__ == "__main__": 

632 pass