I have been making these mathematica 3D objects that involve a molecule with some sort of surface displayed above them. This is done fairly easily by:
Molecule=Graphics3D[{{x,y,z},...},Sphere[1, .24]...,Cylinder[{1, 2}, .15]]
PES=ListPlot3D[{{x,y,z},...}]
Show[Molecule,PES]
A python script was pretty easy to whip this up for molecules; for me its better then the wolfram chemistry database because it is in better units (angstroms) and can be oriented easier. It works great, the objects manipulate smoothly. Now I wanted to do something that would have a very nice end product. Following the work of an online demonstration I started with the initialization code:
Molecule[coord_, conf_, col_, rad_, bondstyle_] :=
Module[{intconf, atomplot, tuples, bonds, bondplot},
intconf =
ReplacePart[conf,
Flatten@Table[# -> ii & /@ (Flatten@
Position[conf, DeleteDuplicates[conf][[ii]]]), {ii, 1,
Length@DeleteDuplicates[conf]}]];
atomplot = {col[[intconf[[#]]]],
Sphere[coord[[#]], rad[[intconf[[#]]]]]} & /@
Range[Length[intconf]];
tuples =
Select[Subsets[
Range[Length[
coord]], {2}], ((conf[[#[[1]]]] =!= "H" ||
conf[[#[[2]]]] =!= "H") &&
Norm[coord[[#[[1]]]] - coord[[#[[2]]]]] <=
bondstyle[[1]]) &];
bonds = coord[[#]] & /@ tuples;
bondplot =
Table[{col[[intconf[[tuples[[#, ii]]]]]],
Tube[{bonds[[#, ii]], .5*Total[bonds[[#]]]},
bondstyle[[2]]]} & /@ Range[Length[bonds]], {ii, 1, 2}];
{atomplot, bondplot}];
coord["Acrolein"] := {{-1.4373, -1.1224, 0.4127}, {0.1565,
0.3728, -0.3457}, {-1.1456, -0.2881, -0.399}, {1.0519, 0.0649,
0.6058}, {0.4003,
1.1146, -1.0773}, {-1.8435, -0.0263, -1.1667}, {0.8173, -0.6754,
1.3418}, {2.0003, 0.5599, 0.6283}};
conf["Acrolein"] := {"O", "C", "C", "C", "H", "H", "H", "H"};
I decided to use this since I can use Map to manipulate the position and scale of the object. Its really just a way to replace my python script. Surfaces were again easy to create with the Map just used to duplicate quadrants:
AcrWater=Import["xyzlist.csv"
surface["Acrolein", "Water"] =
ListPlot3D[Union[AcrWater, Map[#*{1, -1, 1} &, AcrWater]],
Mesh -> 3, ColorFunction -> "Rainbow", PlotStyle -> Opacity[0.9]];
This next part was just done in my experiments to make the graphics smoother:
graphic["Acrolein", "Water"] =
Show[
Graphics3D[{Specularity[White, 100],
Molecule[coord["Acrolein"], conf["Acrolein"],
ColorData["Atoms", #] & /@
DeleteDuplicates[
conf["Acrolein"]], {.4, .4, .4, .4}, {1.5, .193}]}],
surface["Acrolein", "Water"],
ImageSize -> {600, 600}, Background -> White, ViewPoint -> Top,
Axes -> True, Lighting -> "Neutral"];
Finally the manipulate argument:
Manipulate[
graphic[substance,
solvent], {{substance, "Acrolein", "Molecule"}, {"Acrolein"}},
{{solvent, "1C", "Solvent"}, {"Water"}}]
All of this works great together! The only problem is that manipulating the final product is incredibly slow even on a new, well equipped machine with the antialiasing all the way down. There in total will be about 30 different combinations and only implementing a single one shows significant degradation in the overall feel of the demonstration; adding more is even worse. This seems strange when it is done the previous way there is no noticeable lag even with much larger systems. My question is where is the major slowdown in this. It was my understanding that the vector objects were first evaluated then simply displayed by the manipulate command. If there is not an easy workaround is there another way to do this that can avoid the slowdown problem.
Edit: Thank you for the tips so far dynamic and tracked symbols certainly made marked improvements. Here is a chunk of working code that will mimic what I am trying to do. This is a single example with with only 25 points for the surface (real surfaces will have 1000-2000). I am not entirely sure how to do it but a better way to recreate the surface using the proper notation of the data is [x,y,sin[x+y]] where and x and y run from 0-3 in steps of .1. Instead of Dynamic I also tried the Refresh command to no avail.:
Molecule[coord_, conf_, col_, rad_, bondstyle_] :=
Module[{intconf, atomplot, tuples, bonds, bondplot},
intconf =
ReplacePart[conf,
Flatten@Table[# -> ii & /@ (Flatten@
Position[conf, DeleteDuplicates[conf][[ii]]]), {ii, 1,
Length@DeleteDuplicates[conf]}]];
atomplot = {col[[intconf[[#]]]],
Sphere[coord[[#]], rad[[intconf[[#]]]]]} & /@
Range[Length[intconf]];
tuples =
Select[Subsets[
Range[Length[
coord]], {2}], ((conf[[#[[1]]]] =!= "H" ||
conf[[#[[2]]]] =!= "H") &&
Norm[coord[[#[[1]]]] - coord[[#[[2]]]]] <=
bondstyle[[1]]) &];
bonds = coord[[#]] & /@ tuples;
bondplot =
Table[{col[[intconf[[tuples[[#, ii]]]]]],
Tube[{bonds[[#, ii]], .5*Total[bonds[[#]]]},
bondstyle[[2]]]} & /@ Range[Length[bonds]], {ii, 1, 2}];
{atomplot, bondplot}];
coord["Acrolein"] := {{-1.4373, -1.1224, 0.4127}, {0.1565,
0.3728, -0.3457}, {-1.1456, -0.2881, -0.399}, {1.0519, 0.0649,
0.6058}, {0.4003,
1.1146, -1.0773}, {-1.8435, -0.0263, -1.1667}, {0.8173, -0.6754,
1.3418}, {2.0003, 0.5599, 0.6283}};
conf["Acrolein"] := {"O", "C", "C", "C", "H", "H", "H", "H"};
AcrWater :=
Table[Sin[j + i] + 2, {i, 0, 2 Pi, Pi/4}, {j, 0, 2 Pi, Pi/4}]
surface["Acrolein", "Water"] :=
ListPlot3D[AcrWater, Mesh -> 3, ColorFunction -> "Rainbow",
PlotStyle -> Opacity[0.9]];
graphic["Acrolein", "Water"] :=
Dynamic[Show[
Graphics3D[{Specularity[White, 100],
Molecule[coord["Acrolein"], conf["Acrolein"],
ColorData["Atoms", #] & /@
DeleteDuplicates[
conf["Acrolein"]], {.4, .4, .4, .4}, {1.5, .193}]}],
surface["Acrolein", "Water"], ImageSize -> {600, 600},
Background -> White, ViewPoint -> Top, Axes -> True,
Lighting -> "Neutral"], None];
Manipulate[
graphic[substance,
solvent], {{substance, "Acrolein",
"Molecule"}, {"Acrolein"}}, {{solvent, "Water",
"Solvent"}, {"Water"}}, TrackedSymbols :> {substance, solvent}]
Manipulate
evaluates at each change of the slider, when it doesn't necessarily have to. Throwing in aDynamic
somewhere to what really needs to be updated will fix things. You might get some ideas from Vitaliy's answer here. Especially, note this: "Note, Dynamic is necessary to make it NOT lag and redraw all 3D graphics every time you change something inside Manipulate. Dynamic isolates tracked variables." $\endgroup$