Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Theresa Pollinger
MoSIS
Commits
7af43381
Commit
7af43381
authored
Mar 14, 2018
by
Theresa Pollinger
Browse files
automated simulation and visualization
parent
1798600b
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
interview_kernel/example_interview.ipynb
View file @
7af43381
This diff is collapsed.
Click to expand it.
interview_kernel/exaoutput.py
View file @
7af43381
import
os
from
pathlib
import
Path
import
subprocess
from
collections
import
OrderedDict
from
pylatexenc.latexencode
import
utf8tolatex
,
utf82latex
...
...
@@ -241,14 +242,23 @@ class ExaOutput:
"configList=
\"\"
\n
"
\
"configList+=
\"
{}/{}
\"
\n
"
.
format
(
self
.
probname
,
self
.
probname
))
class
ExaRunner
():
class
ExaRunner
:
"""A class to run exastencils using the files generated by an Exaoutput class, and to get the results"""
from
functools
import
lru_cache
def
__init__
(
self
,
exaout
):
self
.
exaout
=
exaout
def
run_exastencils
(
self
):
p
=
subprocess
.
run
([
"./generate_compile_and_run_list.sh"
],
cwd
=
str
(
self
.
exaout
.
exastencils_path
),
stdin
=
subprocess
.
PIPE
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
out
=
p
.
stdout
if
p
.
returncode
!=
0
:
print
(
out
)
@
lru_cache
()
def
load_data
(
self
,
data_name
=
"u"
):
def
load_data
(
self
,
data_name
=
"u"
):
#TODO name of unknowns
import
pandas
as
pd
data_path
=
self
.
exaout
.
exastencils_path
.
joinpath
(
"generated"
).
joinpath
(
self
.
exaout
.
probname
).
joinpath
(
data_name
).
with_suffix
(
".dat"
)
df
=
pd
.
read_csv
(
data_path
,
sep
=
' '
,
index_col
=
0
)
...
...
interview_kernel/interview_kernel.py
View file @
7af43381
from
sys
import
executable
from
os.path
import
join
#from pathlib import Path
from
metakernel
import
MetaKernel
from
IPython.display
import
HTML
,
Javascript
from
metakernel
import
IPythonKernel
...
...
@@ -20,6 +21,8 @@ from bokeh.models import ColumnDataSource
#from tempfile import NamedTemporaryFile
from
pde_state_machine
import
*
from
string_handling
import
build_url
,
get_recursively
# This "main class" is two things: a REPL loop, by subclassing the cmd2 Cmd class
# and a state machine as given by the pytransitions package
...
...
@@ -50,7 +53,7 @@ class Interview(MetaKernel):
def
__init__
(
self
,
**
kwargs
):
self
.
state_machine
=
PDE_States
(
self
.
poutput
,
self
.
update_prompt
,
self
.
please_prompt
)
self
.
state_machine
=
PDE_States
(
self
.
poutput
,
self
.
update_prompt
,
self
.
please_prompt
,
self
.
display_html
)
# call superclass constructor
super
(
Interview
,
self
).
__init__
(
**
kwargs
)
...
...
@@ -143,14 +146,11 @@ class Interview(MetaKernel):
if
arg
.
startswith
(
"recap"
):
self
.
state_machine
.
recap
(
arg
)
return
True
if
arg
.
startswith
(
"
html
"
):
self
.
display_
html
(
)
if
arg
.
startswith
(
"
tgview
"
):
self
.
display_
tgview
(
arg
)
return
True
if
arg
.
startswith
(
"plt"
):
self
.
display_plt
()
return
True
if
arg
.
startswith
(
"bokeh"
):
self
.
display_bokeh
()
if
arg
.
startswith
(
"undo"
):
self
.
do_undo
(
arg
)
return
True
return
False
...
...
@@ -207,7 +207,9 @@ class Interview(MetaKernel):
super
(
Interview
,
self
).
do_complete
(
code
,
cursor_pos
)
return
def
display_html
(
self
):
def
display_html
(
self
,
code
=
None
):
# highlight some of the code entered and show line numbers (just to play around)
self
.
Display
(
HTML
(
"""
<style type="text/css">
.styled-background { background-color: #ff7; }
...
...
@@ -226,85 +228,43 @@ class Interview(MetaKernel):
</script>
"""
%
(
1
,
0
,
3
,
0
)))
tgview_url
=
join
(
self
.
state_machine
.
mmtinterface
.
serverInstance
,
"graphs/tgview.html?type=thgraph&graphdata="
,
self
.
state_machine
.
mmtinterface
.
URIprefix
,
self
.
state_machine
.
mmtinterface
.
namespace
+
"?u"
)
if
code
:
self
.
Display
(
HTML
(
code
))
def
display_tgview
(
self
,
args
=
''
):
"""displays the theory graph viewer as html, cf. https://github.com/UniFormal/TGView/wiki/"""
server_url
=
str
(
self
.
state_machine
.
mmtinterface
.
serverInstance
)
args_dict
=
{
"type"
:
"thgraph"
,
}
args
=
args
.
replace
(
"tgview "
,
''
,
1
).
strip
()
if
args
==
''
:
args_dict
[
"graphdata"
]
=
self
.
state_machine
.
mmtinterface
.
URIprefix
+
\
self
.
state_machine
.
mmtinterface
.
namespace
+
"?u"
else
:
args_dict
[
"graphdata"
]
=
self
.
state_machine
.
mmtinterface
.
URIprefix
+
\
self
.
state_machine
.
mmtinterface
.
namespace
+
"?"
+
args
# if applicable, highlight the ephemeral parts https://github.com/UniFormal/TGView/issues/25
thynames
=
get_recursively
(
self
.
state_machine
.
simdata
,
"theoryname"
)
if
thynames
:
args_dict
[
"highlight"
]
=
","
.
join
(
thynames
)
othercode
=
"""
tgview_url
=
build_url
(
server_url
,
"graphs/tgview.html"
,
args_dict
=
args_dict
)
code
=
"""
<iframe
src="
https://mmt.mathhub.info/graphs/tgview.html
"
src="
{}
"
style="width: 100%; height: 510px; border: none"
>
</iframe>
"""
# a futile attempt to set the size
metadata
=
{
#'text/html': {
'width'
:
1600
,
'height'
:
1400
#}
}
self
.
Display
(
HTML
(
othercode
,
metadata
=
metadata
))
# cf. nbviewer.jupyter.org/github/bokeh/bokeh-notebooks/blob/master/tutorial/01 - Basic Plotting.ipynb
def
display_bokeh
(
self
):
from
exaoutput
import
ExaOutput
,
ExaRunner
# create a new plot with default tools, using figure
p
=
figure
(
plot_width
=
1000
,
plot_height
=
400
)
runner
=
ExaRunner
(
ExaOutput
())
data
=
runner
.
load_data
(
"u"
)
#source = ColumnDataSource(data=data)
source
=
ColumnDataSource
(
data
=
dict
(
x
=
[],
u
=
[]))
source
.
data
=
source
.
from_df
(
data
)
#[['x', 'u']])
source
.
add
(
data
.
index
,
'index'
)
# add a circle renderer with a size, color, and alpha
p
.
circle
(
x
=
'index'
,
y
=
'u'
,
size
=
2
,
line_color
=
"navy"
,
fill_color
=
"orange"
,
fill_alpha
=
0.5
,
source
=
source
)
#show(p)
"""
.
format
(
tgview_url
)
self
.
display_html
(
code
)
output_notebook
()
# cf. http://bokeh.pydata.org/en/0.10.0/docs/user_guide/embed.html
self
.
Display
(
HTML
(
file_html
(
p
,
CDN
,
"my plot"
)))
# show the results
# using JS requires jupyter widgets extension
#script, div = components(p)
#div = notebook_div(p)
#self.Display(Javascript(script + div)) # show the results
def
display_plt
(
self
):
# plt.ion()
# plot = plt.plot([3, 8, 2, 5, 1])
#self.Display(plot)
# plt.show() #TODO find out why there is no comm and interactive shell - and if it should be there
# cf. http://ipython-books.github.io/16-creating-a-simple-kernel-for-jupyter/
fig
=
plt
.
figure
()
ax
=
fig
.
add_subplot
(
111
)
ax
.
plot
([
3
,
8
,
2
,
5
,
1
])
# We create a PNG out of this plot.
png
=
_to_png
(
fig
)
# and send it along as rich content
self
.
richcontent
=
dict
()
# We prepare the response with our rich data (the plot).
self
.
richcontent
[
'source'
]
=
'kernel'
# This dictionary may contain different MIME representations of the output.
self
.
richcontent
[
'data'
]
=
{
'image/png'
:
png
#TODO error: Notebook JSON is invalid: [{'image/png': ...
},
# We can specify the image size in the metadata field.
self
.
richcontent
[
'metadata'
]
=
{
'image/png'
:
{
'width'
:
600
,
'height'
:
400
}
}
self
.
poutput
(
"image!"
)
if
__name__
==
'__main__'
:
# from ipykernel.kernelapp import IPKernelApp
...
...
interview_kernel/mmtinterface.py
View file @
7af43381
...
...
@@ -28,12 +28,8 @@ def start_mmt_server(port_number, mmtjar):
stdin
=
subprocess
.
PIPE
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
out
=
p
.
stdout
if
p
.
returncode
!=
0
and
p
.
returncode
!=
130
:
raise
MMTServerError
(
"Could not start the MMT server, return code "
+
str
(
p
.
returncode
)
+
", "
+
str
(
out
))
#outs, errs = p.communicate()
#if outs is not None:
#print("MMT server terminated before rest of program, ") # this just wont stay alive!!!
#p.terminate()
#raise MMTServerError("MMT server terminated before rest of program, ") # + p.stdout)
raise
MMTServerError
(
"Server aborted, return code "
+
str
(
p
.
returncode
)
+
", "
+
str
(
out
))
def
exit_mmt_server
(
port_number
,
mmtjar
,
timeout
=
3.0
):
completed
=
subprocess
.
run
([
"/usr/bin/java"
,
"-jar"
,
mmtjar
,
":send"
,
str
(
port_number
),
...
...
@@ -41,9 +37,10 @@ def exit_mmt_server(port_number, mmtjar, timeout=3.0):
stdin
=
subprocess
.
PIPE
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
if
completed
.
stdout
!=
None
and
"(Connection refused)"
in
str
(
completed
.
stdout
):
if
timeout
>
0.0
:
star
t_mmt_
extension
(
port_number
,
mmtjar
,
timeout
-
0.1
)
exi
t_mmt_
server
(
port_number
,
mmtjar
,
timeout
-
0.1
)
else
:
raise
MMTServerError
(
"unable to start interview extension"
)
raise
MMTServerError
(
"unable to exit mmt server"
)
def
start_mmt_extension
(
port_number
,
mmtjar
,
timeout
=
3.0
):
time
.
sleep
(
0.1
)
# hope for server to have started communication already
...
...
interview_kernel/pde_state_machine.py
View file @
7af43381
...
...
@@ -7,9 +7,14 @@ from collections import OrderedDict
import
getpass
from
string_handling
import
*
from
exaoutput
import
ExaOutput
from
exaoutput
import
ExaOutput
,
ExaRunner
from
mmtinterface
import
*
from
bokeh.io
import
output_notebook
,
show
,
export_svgs
from
bokeh.plotting
import
figure
from
bokeh.resources
import
CDN
from
bokeh.embed
import
file_html
,
components
#, notebook_div
from
bokeh.models
import
ColumnDataSource
class
InterviewError
(
Exception
):
"""Errors that occur during the course of the interview and are not due to mmt server errors"""
...
...
@@ -61,12 +66,14 @@ class CriticalSubdict():
class
PDE_States
:
"""Just a state machine using pytranisitions that walks our theory graph and creates ephemeral theories and views"""
def
__init__
(
self
,
output_function
,
after_state_change_function
,
prompt_function
):
def
__init__
(
self
,
output_function
,
after_state_change_function
,
prompt_function
,
display_html_function
=
None
):
# just act like we were getting the right replies from MMT
self
.
cheating
=
True
# callback handles
self
.
poutput
=
output_function
self
.
please_prompt
=
prompt_function
self
.
display_html
=
display_html_function
# Initialize a state machine
self
.
states
=
[
...
...
@@ -297,8 +304,10 @@ class PDE_States:
self
.
poutput
(
""
)
self
.
poutput
(
"To get explanations, enter
\"
explain <optional keyword>
\"
. "
)
self
.
poutput
(
"To see a recap of what we know so far, enter
\"
recap <optional keyword>
\"
. "
)
self
.
poutput
(
"To interact with the current theory graph, enter
\"
tgwiev <optional theory name>
\"
. "
)
self
.
poutput
(
"Otherwise, you can always try and use LaTeX-type input."
)
self
.
poutput
(
"Have a look at the currently loaded MMT theories under "
+
self
.
mmtinterface
.
serverInstance
)
self
.
poutput
(
""
)
self
.
poutput
(
"You can inspect the currently loaded MMT theories under "
+
self
.
mmtinterface
.
serverInstance
)
self
.
poutput
(
""
)
self
.
poutput
(
""
)
self
.
poutput
(
""
)
...
...
@@ -791,7 +800,8 @@ class PDE_States:
##### for state sim
def
sim_begin
(
self
):
self
.
please_prompt
(
"Would you like to try and solve the PDE using the Finite Difference Method in ExaStencils?"
,
self
.
please_prompt
(
"Would you like to try and solve the PDE using the Finite Difference Method in ExaStencils?"
"If yes, you can provide a configuration name, or we'll just use your name."
,
self
.
sim_ok_fd
)
def
sim_handle_input
(
self
,
userstring
):
...
...
@@ -801,9 +811,42 @@ class PDE_States:
def
sim_exit
(
self
):
# generate output
ExaOutput
(
self
.
simdata
)
self
.
poutput
(
"Generated ExaStencils input."
)
# TODO generate and run simulation
exaout
=
ExaOutput
(
self
.
simdata
)
print
(
"Generated ExaStencils input; running ExaStencils"
)
# generate and run simulation
runner
=
ExaRunner
(
exaout
)
runner
.
run_exastencils
()
print
(
"Ran ExaStencils; preparing visualization"
)
# output
self
.
display_result_as_bokeh
()
# cf. nbviewer.jupyter.org/github/bokeh/bokeh-notebooks/blob/master/tutorial/01 - Basic Plotting.ipynb
def
display_result_as_bokeh
(
self
):
# create a new plot with default tools, using figure
p
=
figure
(
plot_width
=
1000
,
plot_height
=
400
)
runner
=
ExaRunner
(
ExaOutput
())
data
=
runner
.
load_data
(
"u"
)
#source = ColumnDataSource(data=data)
source
=
ColumnDataSource
(
data
=
dict
(
x
=
[],
u
=
[]))
source
.
data
=
source
.
from_df
(
data
)
source
.
add
(
data
.
index
,
'index'
)
# add a circle renderer with a size, color, and alpha
p
.
circle
(
x
=
'index'
,
y
=
'u'
,
size
=
2
,
line_color
=
"navy"
,
fill_color
=
"orange"
,
fill_alpha
=
0.5
,
source
=
source
)
#show(p)
output_notebook
()
# cf. http://bokeh.pydata.org/en/0.10.0/docs/user_guide/embed.html
self
.
display_html
(
file_html
(
p
,
CDN
,
"my plot"
))
# show the results
# using JS requires jupyter widgets extension
#script, div = components(p)
#div = notebook_div(p)
#self.Display(Javascript(script + div)) # show the results
def
sim_ok_fd
(
self
):
...
...
interview_kernel/string_handling.py
View file @
7af43381
...
...
@@ -2,6 +2,7 @@
from
distutils.util
import
strtobool
import
re
from
urllib.parse
import
urlparse
,
urlencode
,
ParseResult
def
means_no
(
answer
):
try
:
...
...
@@ -12,6 +13,14 @@ def means_no(answer):
return
False
return
False
def
build_url
(
baseurl
,
path
,
args_dict
=
{},
query_dict
=
{}):
# Returns a list in the structure of urlparse.ParseResult
url
=
urlparse
(
baseurl
)
# construct new parseresult
new_url
=
ParseResult
(
url
.
scheme
,
url
.
netloc
,
path
,
urlencode
(
args_dict
),
urlencode
(
query_dict
,
doseq
=
True
),
url
.
fragment
)
return
new_url
.
geturl
()
# cf. https://stackoverflow.com/questions/14962485/finding-a-key-recursively-in-a-dictionary
def
get_recursively
(
search_dict
,
field
):
"""
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment