-
Notifications
You must be signed in to change notification settings - Fork 6
/
solver.py
756 lines (605 loc) · 27.7 KB
/
solver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
# solver gittree menu
# note that in the main menu, we need to call add the following:
# 1) from solver import *
# 2) call solver_card() in SinglePageWithDrawerLayout
# 3) define a node in the gittree (pipeline)
# 4) define any global state variables that might be needed
# definition of ui_card
import shutil
from uicard import ui_card, ui_subcard, server
from trame.widgets import vuetify
from su2_json import *
from su2_io import save_su2mesh, save_json_cfg_file
# check if a file is opened by another process
#import psutil
import pandas as pd
from base64 import b64decode
import subprocess, io, struct, os
# real-time update, asynchronous io
import asyncio
from trame.app import get_server, asynchronous
from trame.app.file_upload import ClientFile
import vtk
from vtkmodules.vtkCommonDataModel import vtkDataObject
# import the grid from the mesh module
from mesh import *
from vtk_helper import *
# Logging function
from logger import log, update_su2_logs
# matplotlib
import matplotlib
matplotlib.use("agg")
import matplotlib.pyplot as plt
from trame.widgets import matplotlib as tramematplotlib
# line 'i' has fixed color so the color does not change if a line is deselected
mplColorList=['blue','orange','red','green','purple','brown','pink','gray','olive','cyan',
'black','gold','yellow','springgreen','thistle','beige','coral','navy','salmon','lightsteelblue']
state, ctrl = server.state, server.controller
############################################################################
# Solver models - list options #
############################################################################
# the main su2 solver process
proc_SU2 = None
# list of fields that we could check for convergence
state.convergence_fields=[]
state.convergence_fields_range=[]
# list of booleans stating which of the fields need to be
# included in the convergence criteria
state.convergence_fields_visibility=[]
# global iteration number while running a case
state.global_iter = -1
# initialize from json file
def set_json_solver():
if 'ITER' in state.jsonData:
state.iter_idx = state.jsonData['ITER']
state.dirty('iter_idx')
if 'CONV_RESIDUAL_MINVAL' in state.jsonData:
state.convergence_val = state.jsonData['CONV_RESIDUAL_MINVAL']
state.dirty('convergence_val')
if 'CONV_FIELD' in state.jsonData:
state.convergence_fields = state.jsonData['CONV_FIELD']
log("info", f"state convergence fields = = {state.convergence_fields} {type(state.convergence_fields)}")
# matplotlib
state.active_figure="mpl_plot_history"
state.graph_update=True
@state.change("active_figure", "figure_size", "countdown","monitorLinesVisibility")
def update_chart(active_figure, **kwargs):
log("info", "updating figure 1")
ctrl.update_figure(globals()[active_figure]())
#ctrl.update_figure2(globals()[active_figure]())
#matplotlib
def update_visibility(index, visibility):
log("info", f"monitorLinesVisibility = = {state.monitorLinesVisibility}")
state.monitorLinesVisibility[index] = visibility
log("info", f"monitorLinesVisibility = = {state.monitorLinesVisibility}")
state.dirty("monitorLinesVisibility")
log("info", f"Toggle {index} to {visibility}")
log("info", f"monitorLinesVisibility = = {state.monitorLinesVisibility}")
#matplotlib
def dialog_card():
log("info", f"dialog card, lines= = {state.monitorLinesNames}")
# show_dialog2 determines if the entire dialog is shown or not
with vuetify.VDialog(width=200,position='{X:10,Y:10}',transition="dialog-top-transition",v_model=("show_dialog",False)):
#with vuetify.VCard(color="light-gray"):
with vuetify.VCard():
vuetify.VCardTitle("Line visibility", classes="grey lighten-1 grey--text text--darken-3")
#with vuetify.VListGroup(value=("true",), sub_group=True):
# with vuetify.Template(v_slot_activator=True):
# vuetify.VListItemTitle("Bars")
# with vuetify.VListItemContent():
# #with vuetify.VListItem(v_for="id in monitorLinesRange", key="id"):
vuetify.VCheckbox(
# loop over list monitorLinesRange
v_for="id in monitorLinesRange",
key="id",
# checkbox changes the state of monitorLinesVisibility[id]
v_model=("monitorLinesVisibility[id]",),
# name of the checkbox
label=("`label= ${ monitorLinesNames[id] }`",),
# on each change, immediately go to update_visibility
change=(update_visibility,"[id, $event]"),
classes="mt-1 pt-1",
hide_details=True,
dense=True,
)
# close dialog window button
# right-align the button
with vuetify.VCol(classes="text-right"):
vuetify.VBtn("Close", classes="mt-5",click=update_dialog)
# real-time update every xx seconds
@asynchronous.task
async def start_countdown(result):
global proc_SU2
while state.keep_updating:
with state:
await asyncio.sleep(2.0)
log("debug", f"iteration = = {state.global_iter, type(state.global_iter)}")
wrt_freq = state.jsonData['OUTPUT_WRT_FREQ'][1]
log("debug", f"wrt_freq = = {wrt_freq, type(wrt_freq)}")
log("info", f"iteration save = = {state.global_iter % wrt_freq}")
log("debug", f"keep updating = = {state.keep_updating}")
# update the history from file
readHistory(BASE / "user" / state.case_name / state.history_filename)
# update the restart from file, do not reset the active scalar value
# do not update when we are about to write to the file
readRestart(BASE / "user" / state.case_name / state.restart_filename, False)
# we flip-flop the true-false state to keep triggering the state and read the history file
state.countdown = not state.countdown
# check that the job is still running
log("debug", f"poll = = {proc_SU2.poll()}")
if proc_SU2.poll() != None:
log("info", "job has stopped")
# stop updating the graphs
state.keep_updating = False
# set the running state to false
state.solver_running = False
state.solver_icon="mdi-play-circle"
update_su2_logs()
###############################################################
# PIPELINE CARD : Solver
###############################################################
def solver_card():
with ui_card(title="Solver", ui_name="Solver"):
log("debug", "## Solver Selection ##")
# 1 row of option lists
with vuetify.VRow(classes="pt-2"):
with vuetify.VCol(cols="8"):
vuetify.VTextField(
# What to do when something is selected
v_model=("convergence_val", -12),
# the name of the list box
label="Residual convergence value",
)
with vuetify.VCol(cols="4", classes="py-0 my-0"):
with vuetify.VBtn(classes="mx-0 py-0 mt-2 mb-0",elevation=1,variant="text",color="white", click=update_solver_dialog_card_convergence, icon="mdi-dots-vertical"):
vuetify.VIcon("mdi-dots-vertical",density="compact",color="green")
# 1 row of option lists
with vuetify.VRow(classes="pt-2"):
with vuetify.VCol(cols="10"):
vuetify.VTextField(
# What to do when something is selected
v_model=("iter_idx", 100),
# the name of the list box
label="Iterations",
)
with vuetify.VBtn("Solve",click=su2_play):
vuetify.VIcon("{{solver_icon}}",color="purple")
########################################################################################
# Checks/Corrects some json entries before starting the Solver
########################################################################################
# def checkjsonData():
# if 'RESTART_FILENAME' in state.jsonData:
# state.jsonData['RESTART_FILENAME' ] = 'restart'
# state.restart_filename = 'restart'
# if 'SOLUTION_FILENAME' in state.jsonData:
# state.jsonData['SOLUTION_FILENAME' ] = 'solution_flow'
def checkCaseName():
if state.case_name is None or state.case_name == "":
log("error", "Case name is empty, create a new case. \n Otherwise your data will not be saved!")
return False
return True
###############################################################
# Solver - state changes
###############################################################
@state.change("iter_idx")
def update_material(iter_idx, **kwargs):
#
log("debug", f"ITER value: = {state.iter_idx}")
#
# we want to call a submenu
#state.active_sub_ui = "submaterials_fluid"
#
# update config option value
try:
state.jsonData['ITER'] = int(state.iter_idx)
except ValueError:
log("error", "Invalid value for ITER")
@state.change("convergence_val")
def update_material(convergence_val, **kwargs):
#
# update config option value
try:
state.jsonData['CONV_RESIDUAL_MINVAL'] = int(state.convergence_val)
except ValueError:
log("error", "Invalid value for CONV_RESIDUAL_MINVAL in solver")
# start SU2 solver
def su2_play():
global proc_SU2
# every time we press the button we switch the state
state.solver_running = not state.solver_running
if state.solver_running:
log("info", "### SU2 solver started!")
# change the solver button icon
state.solver_icon="mdi-stop-circle"
# reset monitorLinesNames for the history plot
state.monitorLinesNames = []
# check if the case name is set
if not checkCaseName():
return
# save the cfg file
save_json_cfg_file(state.filename_json_export,state.filename_cfg_export)
# save the mesh file
global root
save_su2mesh(root,state.jsonData['MESH_FILENAME'])
# clear old su2 log and set new one
state.last_modified_su2_log_len = 0
state.su2_logs = ""
# run SU2_CFD with config.cfg
with open(BASE / "user" / state.case_name / "su2.out", "w") as outfile:
with open(BASE / "user" / state.case_name / "su2.err", "w") as errfile:
proc_SU2 = subprocess.Popen(['SU2_CFD', state.filename_cfg_export],
cwd= BASE / "user" / state.case_name,
text=True,
stdout=outfile,
stderr=errfile
)
# at this point we have started the simulation
# we can now start updating the real-time plots
state.keep_updating = True
log("debug", f"start polling, poll = = {proc_SU2.poll()}")
# Wait until process terminates
#while result.poll() is None:
# time.sleep(1.0)
log("debug", f"result = = {proc_SU2}")
log("debug", f"result poll= = {proc_SU2.poll()}")
# periodic update of the monitor and volume result
start_countdown(proc_SU2)
log("debug", f"result = = {proc_SU2}")
# save mesh
# save config
# save restart file
# call su2_cfd
else:
state.solver_icon="mdi-play-circle"
log("info", "### SU2 solver stopped!"),
# we need to terminate or kill the result process here if stop is pressed
log("debug", f"process= = {type(proc_SU2)}")
proc_SU2.terminate()
# matplotlib history
def update_convergence_fields_visibility(index, visibility):
log("debug", f"index= = {index}")
log("debug", f"visible= = {state.convergence_fields_visibility}")
state.convergence_fields_visibility[index] = visibility
log("debug", f"visible= = {state.convergence_fields_visibility}")
state.dirty("convergence_fields_visibility")
log("debug", f"Toggle {index} to {visibility}")
# matplotlib history
# select which variables to use for convergence. Currently: only residual values of the solver
def solver_dialog_card_convergence():
with vuetify.VDialog(width=300,position='{X:10,Y:10}',transition="dialog-top-transition",v_model=("show_solver_dialog_card_convergence",False)):
with vuetify.VCard():
vuetify.VCardTitle("Convergence Criteria",
classes="grey lighten-1 py-1 grey--text text--darken-3")
with vuetify.VContainer(fluid=True):
# ####################################################### #
with vuetify.VRow(classes="py-0 my-0"):
with vuetify.VCol(cols="8", classes="py-1 my-1 pr-0 mr-0"):
vuetify.VCheckbox(
# loop over list of convergence fields
v_for="id in convergence_fields_range",
key="id",
# checkbox changes the state of monitorLinesVisibility[id]
v_model=("convergence_fields_visibility[id]",),
# name of the checkbox
label=("`${ convergence_fields[id] }`",),
# on each change, immediately go to update_convergence_fields_visibility
change=(update_convergence_fields_visibility,"[id, $event]"),
classes="mt-1 pt-1",
hide_details=True,
dense=True,
)
with vuetify.VCardText():
vuetify.VBtn("close", click=update_solver_dialog_card_convergence)
###############################################################################
def update_solver_dialog_card_convergence():
log("debug", f"changing state of solver_dialog_Card_convergence to: = {state.show_solver_dialog_card_convergence}")
state.show_solver_dialog_card_convergence = not state.show_solver_dialog_card_convergence
# if we show the card, then also update the fields that we need to show
if state.show_solver_dialog_card_convergence==True:
log("debug", "updating list of fields")
# note that Euler and inc_euler can be treated as compressible / incompressible as well
log("debug", state.jsonData['SOLVER'])
log("debug", state.jsonData['INC_ENERGY_EQUATION'])
if ("INC" in str(state.jsonData['SOLVER'])):
compressible = False
else:
compressible = True
# if incompressible, we check if temperature is on
if (compressible==False):
if (state.jsonData['INC_ENERGY_EQUATION']==True):
energy=True
else:
energy=False
# INC_RANS: [PRESSURE VELOCITY-X VELOCITY-Y] [VELOCITY-Z] [TEMPERATURE]
# SA: [NU_TILDE]
# SST: [TKE, DISSIPATION]
# RANS: [DENSITY MOMENTUM-X MOMENTUM-Y] [ENERGY] [MOMENTUM-Z]
if (compressible==True):
state.convergence_fields=["RMS_DENSITY","RMS_MOMENTUM-X","RMS_MOMENTUM-Y"]
if (state.nDim==3):
state.convergence_fields.append("RMS_MOMENTUM-Z")
state.convergence_fields.append("RMS_ENERGY")
else:
state.convergence_fields=["RMS_PRESSURE","RMS_VELOCITY-X","RMS_VELOCITY-Y"]
if (state.nDim==3):
state.convergence_fields.append("RMS_VELOCITY-Z")
if (energy==True):
state.convergence_fields.append("RMS_TEMPERATURE")
state.convergence_fields_range=list(range(0,len(state.convergence_fields)))
# get the checkbox states from the jsondata
state.convergence_fields_visibility = [False for i in state.convergence_fields]
for field in state.jsonData['CONV_FIELD']:
log("debug", f"field= = {field}")
for i in range(len(state.convergence_fields)):
log("debug", f"i= = {i} {state.convergence_fields[i]}")
if (field==state.convergence_fields[i]):
log("debug", "field found")
state.convergence_fields_visibility[i] = True
log("debug", f"convergence fields: = {state.convergence_fields}")
state.dirty('convergence_fields')
state.dirty('convergence_fields_range')
else:
# the dialog is closed again: we update the state of CONV_FIELD in jsonData
state.jsonData['CONV_FIELD']=[]
for i in range(len(state.convergence_fields_visibility)):
if (state.convergence_fields_visibility[i]==True):
state.jsonData['CONV_FIELD'].append(state.convergence_fields[i])
###############################################################################
# matplotlib
def update_dialog():
state.show_dialog = not state.show_dialog
state.dirty('monitorLinesVisibility')
state.dirty('monitorLinesNames')
state.dirty('monitorLinesRange')
###############################################################################
# Read the history file
# set the names and visibility
def readHistory(filename):
log("debug", f"read_history, filename= = {filename}")
skipNrRows=[]
# read the history file
dataframe = pd.read_csv(filename,skiprows=skipNrRows)
# get rid of quotation marks in the column names
dataframe.columns = dataframe.columns.str.replace('"','')
# get rid of spaces in the column names
dataframe.columns = dataframe.columns.str.replace(' ','')
# limit the columns to the ones containing the strings rms and Res
dfrms = dataframe.filter(regex='rms|Res')
# only set the initial state the first time
if state.monitorLinesNames==[]:
state.monitorLinesNames = list(dfrms)
state.monitorLinesRange = list(range(0,len(state.monitorLinesNames)))
state.monitorLinesVisibility = [True for i in dfrms]
state.dirty('monitorLinesNames')
state.dirty('monitorLinesVisibility')
state.dirty('monitorLinesRange')
state.x = [i for i in range(len(dfrms.index))]
# number of global iterations, assuming we start from 0 and every line is an iteration.
# actually, we should look at Inner_Iter
state.global_iter = len(dfrms.index)
#log("info", f"x = = {state.x}")
state.ylist=[]
for c in range(len(dfrms.columns)):
state.ylist.append(dfrms.iloc[:,c].tolist())
dialog_card()
return [state.x,state.ylist]
###############################################################################
# read binay restart file
def Read_SU2_Restart_Binary(val_filename):
val_filename = str(val_filename)
fname = val_filename
nRestart_Vars = 5
Restart_Vars = [0] * nRestart_Vars
fields = []
# Determine sizes dynamically
int_size = struct.calcsize('i')
double_size = struct.calcsize('d')
string_size = 33 # Assuming the fixed length for variable names
try:
with open(fname, "rb") as fhw:
# Read the number of variables and points
Restart_Vars = struct.unpack('i' * nRestart_Vars, fhw.read(int_size * nRestart_Vars))
nFields = Restart_Vars[1]
nPointFile = Restart_Vars[2]
# Read variable names
for _ in range(nFields):
str_buf = fhw.read(string_size).decode('utf-8').strip('\x00')
fields.append(str_buf)
# Read restart data
Restart_Data = struct.unpack('d' * nFields * nPointFile, fhw.read(double_size * nFields * nPointFile))
# Convert the data into a pandas DataFrame
Restart_Data = [Restart_Data[i:i + nFields] for i in range(0, len(Restart_Data), nFields)]
df = pd.DataFrame(Restart_Data, columns=fields)
except:
log("info", "Unable able to read binary restart file")
df = pd.DataFrame()
return df
# # ##### upload ascii restart file #####
@state.change("restartFile")
def uploadRestart(restartFile, **kwargs):
log("debug", "Updating restart.csv file")
if restartFile is None:
state.jsonData["RESTART_SOL"] = False
log("debug", "removed file")
return
# check if the case name is set
if not checkCaseName():
state.restartFile = None
return
filename = restartFile['name']
file = ClientFile(restartFile)
base_path = Path("e:/gsoc/su2gui/user") / state.case_name
base_path.mkdir(parents=True, exist_ok=True) # Create directories if they do not exist
# for .csv
if filename.endswith(".csv"):
try:
filecontent = file.content.decode('utf-8')
except:
filecontent = file.content
f = filecontent.splitlines()
with open(BASE / "user" / state.case_name / filename,'w') as restartFile:
restartFile.write(filecontent)
state.jsonData["SOLUTION_FILENAME"] = filename
state.jsonData["RESTART_SOL"] = True
state.jsonData["READ_BINARY_RESTART"] = False
# we reset the active field because we read or upload the restart from file as a user action
readRestart(BASE / "user" / state.case_name / filename, True, initialization='.csv')
# for .dat binary restart file
elif filename.endswith(".dat"):
filecontent = b64decode(file.content)
with open(BASE / "user" / state.case_name / filename,'wb') as restartFile:
restartFile.write(filecontent)
state.jsonData["SOLUTION_FILENAME"] = filename
state.jsonData["RESTART_SOL"] = True
state.jsonData["READ_BINARY_RESTART"] = True
# we reset the active field because we read or upload the restart from file as a user action
readRestart(BASE / "user" / state.case_name / filename, True, initialization='.dat')
log("info", "Restart loaded ")
# check if a file has a handle on it
#def has_handle(fpath):
# for proc in psutil.process_iter():
# try:
# for item in proc.open_files():
# log("info", f"item= = {item}")
# if fpath == item.path:
# return True
# except Exception:
# pass
#
# return False
# read the restart file
# reset_active_field is used to show the active field
def readRestart(restartFile, reset_active_field, **kwargs):
# check and add extension if needed
restartFile = str(restartFile)
log("debug", f"read_restart, filename= = {restartFile}")
# kwargs is used to pass the initialization of the restart file
# check if function is called by restart initialization
if 'initialization' in kwargs:
if kwargs['initialization']=='.dat':
df = Read_SU2_Restart_Binary(restartFile)
else:
df = pd.read_csv(restartFile)
else:
# move the file to prevent that the file is overwritten while reading
# the file can still be overwritten while renaming, but the time window is smaller
# we also try to prevent this by not calling readRestart when we are about to write a file
# (based on current iteration number)
try:
lock_file = restartFile + ".lock"
# Copy or overwrite the lock_file with the contents of restartFile
shutil.copy2(restartFile, lock_file)
# Read the lock_file based on the state
if state.fileio_restart_binary:
df = Read_SU2_Restart_Binary(lock_file)
else:
df = pd.read_csv(lock_file)
except Exception as e:
log("info", f"Unable to read restart file. It may not be available yet or is being used by another process.\n {e}")
df = pd.DataFrame()
# check if the points and cells match, if not then we probably were writing to the file
# while reading it and we just skip this update
log("info", f"number of points read = = {len(df)}")
log("info", f"number of points expected = = {grid.GetPoints().GetNumberOfPoints()}")
if len(df) != grid.GetPoints().GetNumberOfPoints():
log("info", "Restart file is invalid, skipping update")
return
# construct the dataset_arrays
datasetArrays = []
counter=0
for key in df.keys():
name = key
log("info", f"reading restart, field name = = {name}")
# let's skip these
if (name in ['PointID','x','y']):
continue
ArrayObject = vtk.vtkFloatArray()
ArrayObject.SetName(name)
# all components are scalars, no vectors for velocity
ArrayObject.SetNumberOfComponents(1)
# how many elements do we have?
nElems = len(df[name])
ArrayObject.SetNumberOfValues(nElems)
ArrayObject.SetNumberOfTuples(nElems)
# Nijso: TODO FIXME very slow!
for i in range(nElems):
ArrayObject.SetValue(i,df[name][i])
grid.GetPointData().AddArray(ArrayObject)
datasetArray = {
"text": name,
"value": counter,
"type": vtkDataObject.FIELD_ASSOCIATION_POINTS,
}
try:
datasetArray["range"] = [df[name].min(), df[name].max()]
except TypeError as e:
log("info", f"Could not compute range for field {name}: {e}")
datasetArrays.append(datasetArray)
counter += 1
state.dataset_arrays = datasetArrays
#log("info", f"dataset = = {datasetArrays}")
#log("info", f"dataset_0 = = {datasetArrays[0]}")
#log("info", f"dataset_0 = = {datasetArrays[0].get('text'}"))
mesh_mapper.SetInputData(grid)
mesh_actor.SetMapper(mesh_mapper)
renderer.AddActor(mesh_actor)
# we should now have the scalars available. If we update the field from an active run, do not reset the
# active scalar field
if reset_active_field==True:
defaultArray = datasetArrays[0]
mesh_mapper.SelectColorArray(defaultArray.get('text'))
mesh_mapper.GetLookupTable().SetRange(defaultArray.get('range'))
mesh_mapper.SetScalarVisibility(True)
mesh_mapper.SetUseLookupTableScalarRange(True)
# Mesh: Setup default representation to surface
mesh_actor.GetProperty().SetRepresentationToSurface()
mesh_actor.GetProperty().SetPointSize(1)
#do not show the edges
mesh_actor.GetProperty().EdgeVisibilityOff()
# We have loaded a mesh, so enable the exporting of files
state.export_disabled = False
# renderer.ResetCamera()
ctrl.view_update()
###############################################################################
def figure_size():
if state.figure_size is None:
return {}
dpi = state.figure_size.get("dpi")
rect = state.figure_size.get("size")
w_inch = rect.get("width") / dpi
h_inch = rect.get("height") / dpi
if ((w_inch<=0) or (h_inch<=0)):
return {}
return {
"figsize": (w_inch, h_inch),
"dpi": dpi,
}
###############################################################################
def mpl_plot_history():
plt.close('all')
fig, ax = plt.subplots(1, 1, **figure_size(), facecolor='blue')
ax.set_facecolor('#eafff5')
fig.set_facecolor('blue')
fig.patch.set_facecolor('blue')
fig.subplots_adjust(top=0.98, bottom=0.15, left=0.05, right=0.99, hspace=0.0, wspace=0.0)
has_lines = False
try:
for idx in state.monitorLinesRange:
if state.monitorLinesVisibility[idx]:
ax.plot(state.x, state.ylist[idx], label=state.monitorLinesNames[idx], linewidth=5, markersize=20, markeredgewidth=10, color=mplColorList[idx % 20])
has_lines = True
ax.set_xlabel('iterations', labelpad=10)
ax.set_ylabel('residuals', labelpad=-15)
ax.grid(True, color="lightgray", linestyle="solid")
if has_lines:
ax.legend(framealpha=1, facecolor='white')
ax.autoscale(enable=True, axis="x")
ax.autoscale(enable=True, axis="y")
except IndexError as e:
log("error", f"IndexError : {e}. Index causing error: {idx}")
log("error", f"state.x length : {len(state.x)}")
log("error", f"state.ylist length : {len(state.ylist)}")
log("error", f"state.monitorLinesNames length : {len(state.monitorLinesNames), state.monitorLinesNames}")
log("error", f"state.monitorLinesVisibility length: {len(state.monitorLinesVisibility)}")
log("error", f"mplColorList length : {len(mplColorList)}")
return fig