MaXrd: A crystallography package developed for research support

Stian Ramsness presents MaXrd, a Mathematica package for crystallography work. It handles CIF file imports, symmetry queries, crystal visualization, and diffraction simulations using data from International Tables for Crystallography. Version 1.00 launched in 2018.
Chapters
All right, I think that's a good place to start. Hello, everyone. Welcome to my talk titled Max rd, a crystallography package developed for research support. I'm Stian Ramsness. I have a background in mathematics and physics and this has been a project that I have been working on during my master's and PhD studies. I wanted to talk about this journey today with you. I have divided into two parts. Part one is a technical development part. I will give you a brief background and we will look at some, well, the technical aspects of it, because it sort of evolved as a pet project, I would say. And I think a lot of people like me like to work in Mathematica and develop stuff there. So I thought that it would be a good idea to show how we do it, the way we have set up things and the way we work with Mathematica. Talk a bit about the development life cycle. And then this other part, I will talk about how it has been applied in, in our research. And. Well, this will mainly be about how you would use the package, while part one is what it looks like. So this is within the topics of material science. But I don't think you. I would say that it's required for this, for this talk to make sense. Of course, it's a bonus. It will. It would probably be more interesting for you if you like physics. But I think this could also be targeted towards those who like just working with the Wolfram language. And maybe you develop your own package and maybe you find that the things we have done is something close to what you are doing. So I would say that as long as you're familiar with Mathematica or the Wolfram language, you would benefit from this talk. And also you could check out in the Wolfram community this link. I can post it in the chat. A couple of months ago, I posted a notebook there that was going through what you can do with the package. And a lot of part two in this talk will be extractions from this notebook. So feel free to download it now and have a look at it while you. While I go through it in this talk. And maybe there's some more text there if you want to check out more details. Okay, so just a brief introduction to the background. I first saw Mathematica or got introduced to Mathematica in my second semester at the university. It was in our physics laboratory course that we were doing physics experiments and recording numerical data and we used Mathematic to analyze the results. Afterwards. I think I fell in love with mathematics pretty quickly. This was also the first time I was programming, so I really liked it, had a very great experience. And the course lecturer who later became my supervisor, Gunnar Tolkien, this is a guy who has been using Mathematica since the first version of it. And he said he also had the Mathematica on those huge floppy disks that, yeah, that belong in a different era now. So you could say he was pretty huge fan of Mathematica and had a lot of experience in it. And I think most much of his enthusiasm was carried over to me and his close colleague Helge Bevik Larsen. They formed a small research team in. They focused on dynamical diffraction theory. So they had a lot of code scripts or snippets or Mathematica notebooks that they had used in the research for a long time. And I got to to work with this code during my master thesis. Then I had a look at it for the first time and the state it was in was that it was, you could say that it had a lot of work done to it, but it was very in a very inconvenient shape to use outside those that knew the notebooks in and out. There were a lot of global definitions and a lot of helper functions that you have to define just to get going and stuff like that. So it was during my master's and my PhD later that I had the opportunity to develop on this code base and make it into an actual package. And you can see here that we had our first, the launch of version 1.00 in 2018. So it has been a project that has been around or sort of been very close companion in my studies. And this is what it stands for, MAX RD Mathematica X Ray Diffraction package, if you were curious about that. Okay, so just some notes on motivation for using Mathematica. So one point that you could kind of say belongs in here is that our little research team had invested some time developing, developing these scripts that they used in their dynamical diffraction theory parts. But regardless of that, I would say that the best thing about Mathematica is the documentation Center. This is by far my favorite documentation design in programming that I've seen. I just really like it. And I think when we made the package we were inspired by this principle and also the principle of sort of keeping everything in one place that you didn't need to go outside Mathematica to do the things you wanted to do. And you know, frankly I rarely go outside the Documentation center to figure out what I need to do. It's not like other languages where you go on Stack Exchange to find out what you're doing wrong or how you can fix sort of the things you're doing. Yeah, and a very close companion, a very close competitor to Mathematica is the Jupyter notebooks. And I've worked a lot of. I worked with them too, but I still just find it very much more engaging to work with Mathematica notebooks. I think it's. You get to work more quickly and it's. It's a very good way to explore new things and ideas and just work with it in general. And this final point here, symbolic exact calculations that could be useful to scientists. So in our context, it was natural to. Or it has been natural to work with symbolic computations when we deal with the symmetry groups, which is of. For mathematical group in nature. So it makes sense to have it there. All right, so I wanted to jump into the file structure first, just to get an overview of what it looks like. So if you go to the root directory of the package, it's all available on GitHub, by the way, I don't know if we've seen the link yet. Okay, you can see that about 30% is in the documentation. That's because we have a lot of figures and graphics that make up a lot of space. But inside the kernel directory you have some data assets that take a decent amount. You can see these two folders, Atomic Scattering Factor and Cross Sections. These are tabulated data from external sources that are required if you want to do some physics calculations. But in principle, if you just want to work with the mathematical aspect of the package, you can delete these if you don't need the functionality that they will call to. But something you shouldn't delete is that's very primitive to the package is this basegroups M and pointgroups M. I will come soon to what they are. Just look at the init file here. You can see that it really just contains one call to the definitions file. That's this one in the root again. And this is the one that contains all the definitions except some special symbols. And the way it works. And this I think is. This part is something that's. Maybe it's a bit peculiar to way we do things is that we have all the usage messages in one file. And this is the way the package discovers all the functions that are that belong to this Maxwell package. And the actual definitions are enclosed in this private context. So if we load the package and look at the names inside it, it will have all the functions and also these special symbols that are prefixed by the dollar symbol. And I think the reason we did this was because some things that we define, require or expect to work with global constants or variables like the lowercase abc and lowercase alpha, beta, gamma. And we can have it this way while still not cluttering the namespace. So that's the reason why we did this, I think. Here's another view. To view what the package is, you could say that there is some fundamental Wolfram language code that in a sense define the API to the package. And then you have these two special files that I told you never to delete if you want to use the package called the point groups and space groups. So in these files we have stored a lot of symmetry data. These are actually data from books, a book series called the International Tables for Crystallography. And my professor, Gennado Gilsten and his colleague Helge Berwick Lawson, they had already done a lot of work implementing what was in the books into actual files that could be read by Mathematica. So a lot of work was done there already, although I expanded it during my PhD. And to the right here on the top, you. And then the second one and then also the third one. These are files that come from outside Mathematica. These are the tabulated values that you need in physics calculations. But we wanted to follow this principle of just making everything as simple as possible for the end user. So you don't need to worry about this. We have some default values to our functions, so you don't need to think about it if you don't care. But at the same time you have these options that allow you to specify multiple sources if you need to do so. And this last file in the cyan colored one crystal data, this is a bit more fun because this will normally be extended by. By you. You bring. You would. If you want to use the package, you would normally bring in your own crystal data that you want to, to work with. So this typically would. You would get some data from your experiments and put it into Mathematica via this package. All right, so the point groups and space groups, I'll just briefly mention what they are if you're not familiar with them. So just to put it very simply, a point group is a symmetry group. So let's just look at the keys. It's really a large association and there are 32 of these and these are their names. And a point group, you can think of a point and a symmetry around it. That leaves the point, everything around the point Intact after some symmetry operation. So for point groups is just one dimensional. You can do reflections or rotations about that point in a way that leaves everything around it looking the same. Then that's the definition of a point group to do. To have everything around looking the same. And if you do things a little more advanced and go to three dimensions instead of one. So in addition to reflections and rotations, you allow translation. Everything gets a bit more complicated. You have, let's see, you have 230 of those. And the reason why people have done this, to tabulate all the symmetry information from this is because it's very tightly connected to crystals. So a crystal is defined by a unit cell. A unit cell is something you can think of, a portion, a volume of the material, an arbitrary volume that you can just copy and. Or duplicate and copy. Paste, paste, paste, just around all the whole material and everything looks the same. So it's in three dimensions where everything looks the same. You can define it by a space group. So that's why it's so closely connected to crystals. Because if you have a crystal like common table salt, sodium chloride, you know, it's just really two atom species, one sodium atom and one chlorine atom that arrange themselves over and over again in the same pattern, then it will be represented, you could say, by one of these base groups. So you have from very low symmetry here up to. Well, you go through monoclinic and tetragonal and orthorhombic and hexagonal, all the way up to cubic systems. So very high symmetry there. So that's just a brief explanation of why we put this into. Into the package. Because you sort of need them if you want to work with crystals on the symmetry. Yeah, I don't think I will spend too much time more talking about how things are stored. I will just summarize that to say that we have the. It's been a huge success to just store everything in associations. It's very fast. And if you go up here, you can see that it takes about 12 megabytes in memory. So it's absolutely worth it to just have it this way. Okay, so the next step about how we have developed things is to put everything in one huge definitions notebook. So maybe it seems weird, but it has been working for us. I should mention that we're just a small group of three people, and I'm the main developer. So maybe it works everyone in our case and not for somebody else, so many others. And this sort of acts as the code base. And then if we. Whenever we Want to add more functionality? We put in the definition of a function in there. And what's special about this notebook is that we put on this autogenerate package flag and you have a lot of initialization cells for the actual functionality definitions. And what that means is that whenever you save the notebook file, it generates a M file for you. So you have all the definitions in one file afterwards. And then we have this special hack of getting out the usage messages from the documentation pages. So what you would first do is to make your documentation pages and then get the usage from that afterwards. Okay, here we have a dive into how the definitions notebook look like. Let me just close that first. So you see I have four sections. One for initialization of the package, a finalization afterwards which is just end package, some hack to get the auto completion going. And then you have the actual definitions. So very standard way of getting the package started. You load the usage messages and all the files that I've been talking about before and they are associated with these special global variables within the package. So we have followed the sort of convention with the core language to have a dollar symbol represent something that is a global variable in the context. So those, that's those sort of special symbols. And then each function has its own heading and in the same. And something that's common for all of these chunks is that you have some common blocks to put in messages if it's applicable and options again if it's applicable. And all the functions should have a syntax information just to make things clearer. And then we encapsulate the actual definitions with the private context. I don't remember how I did it, but for some reason we were able to have the definitions outside of scope, even though it was not supposed to. So I think we started with this to not clutter the namespace. So this particular function is one of the older functions. You can see that it's written using very short symbols. We have gone away from that now. So in the later functions you would see more longer named symbols. And I think that's good. So you sort of self document what's going on in the function and you don't need that many comments. So it's been a project that has been evolving over time. So I've been learning on a way how to do things better. Another thing we have done is to have this thing called input check. I think it's. I would say it closely resembles extensions in other languages or maybe guard statements. You would regard the input. So that's a hugely overloaded function. And you would have these labels to sort of for each branch of what you're going to check. This is just the way we've done things. I think it's very clear when you read it, that's the pros and the concept that it looks very ugly behind the scenes because you have this large function definition and it's doing all sorts of things, but at least it works well for us. Okay, just going to close this and show you a bit more newer functions to do. Something I want to mention there. So this function called crystalplot, it's a bit advanced and it's a bit newer. I'm just going to take the zoom down to 50% so we get better overview here. Something we did here is to combine options from graphics 3D. This actually just returns a graphics 3D object. So we wanted to have all the options that were in this available for users. And at the same time we have some custom options that are just internal to whatever this function was doing. And at the same time we wanted to set some default values for the options that were available in graphics 3D. And I think this was the best way we could do it. So have a look at this if you're in a similar situation. I think it worked pretty well. One thing more I wanted to mention that we eventually found worked pretty well was to divide or factorize out smaller functions that were doing their own tasks. So if we go through here and you can see these blue things, it's functions that are not defined. Right. So they don't clutter the namespace. These are actually defined below here. So they do their own tasks. And yeah, it's just this modularization principle, right. To keep everything separated if they do different tasks. And I think this was the best way we came up with to do it in Mathematica. So you don't see them elsewhere, they just appear blue here in this notebook. Okay, that's what I wanted to say here. And yeah, this auto completion, that's kind of fun. This was some years ago, so I don't know how it's implemented in the latest sort of packlet tools now, but on a Stack Exchange page we found this way to enable auto completion. It's very handy for this package because in the point groups and space groups you have all these names that we saw before. Remember the 32 point groups, the names of the 230 space groups. So it's a very nice option to have this because these are of course actually just specific lists of strings that should be one of those. Right. So A lot of functions will accept or would expect either the name of a crystal or the name of a point group or space group as one of its input arguments. So I think it, it got a lot better when we were able to have this because then you can have long names on your crystals and you'll get the auto completion helping you so you don't have to have very short ambiguous names for your crystals. Okay then, about the usage messages again. So when we were done writing a particular document documentation page for a function, it would be looking something like this. For example, in this particular case with the import crystal data, we have four different signatures of how you can use the function. So we write this first using the documentation tools. Before we used to use Eclipse with the official Wolfram Workbench plugin. But I think it was in Mathematica version 13 that it got really simple to work with your own packages because then they came as an extension inside Mathematica instead, so you didn't have to work with Eclipse. But anyway, once you have made this documentation page, we use this create usage function. It's defined in here. It's a bit ugly, but it works well now. And what it does is just to extract the portion that's in these blue places here. Let's see what it looks like. If you get the output file, you can see here are the function names and then you get this very primitive raw box cell data format. But it looks like this when you query for the functions. So it looks almost identical to the official usage messages. Okay. Yeah. I also have written here some that we have a to do list whenever we wanted to add new functionality or. Or making a new release. Yeah, One important part was not to work with inside the definitions notebook. Always make a copy or a branch to work to test things. And when you're writing new functions, a big thing or a very useful thing to have is a unit test notebook. You can make this in Mathematica and it's a good idea to maintain it because you don't get compiler help from a compiler whenever you break things or change things. Right. So it's a good idea to have. I've not been as thorough as I should. I've not been updating it as much. But by all means you should have it in your project. Yeah. Here are some of the steps I mentioned, if you're interested. You can read through it afterwards. Just a yeah to do list really. But the way we build it is with this packlet tools. Now it's very simple, as I said, and it's quite fast. You just. It's done with within two minutes and installation is also very easy now. So if you want to make a package I think now is a very good time. It's very easy to do so and you can do it all inside the Mathematica. Okay so yeah, just a summary of what we learned. The biggest takeaways, some pros and cons and this first one is a neutral because we hadn't had any problems by having this huge master notebook definition notebook. I guess it's also a bit subjective. If you don't like having it this way then and don't do it. But we at least didn't have any problems with it. A bit cautious about having this input check function. This is the sort of guard statement that can do a lot of things and we decided to make it because there were a lot of functions that had to do the same checks over and over again. So we just wanted to factorize it. But over time we have maybe 10, 20 different input checks for different purposes. So that could maybe been done in a more elegant way. Something that worked really well was just to load these point groups and space group files directly into memory and having them as associations, nested associations so they sort of resemble a JSON structure. And it's absolutely worth it. It doesn't take a lot of space both on disk and in memory and it's very fast. Yeah the helper functions like we saw in crystalplot is a no brainer to do. Yeah spend a lot of time of making good documentation pages. I think that has paid off very much both from the developers side because then it's very fast to see get up to speed with something that you have. Maybe it's been a long time since you worked last time. You see how things works. It's very quick to get usage examples and also for the end user or external users of course it's like I mentioned before, it's one of my favorite things about Mathematica is the documentation system. So use it and spend a lot of time with it. It's absolutely worth it to have large documentations with all kind of explaining everything, explaining very detailed much details about options and all the stuff like that. And one thing that I don't think I mentioned was to use this if you want to do a part of something to use this explicit part syntax so you can do escape then two brackets and escape again. Right. Instead of just having two brackets like you normally would because it's much more clear to read and you don't get confused by. When you have two brackets just that just means closing a function. So. So I would use those more and I actually started to use those more in the Later. Yeah, later times. Just a notion what we could have done differently. So this has been growing over time. So maybe at some point we should divide it into subcontext or sub packages. One thing I wish I'd done more is to make more tutorials or I think they're called tech notes now because then you can explain especially if the topic is advanced and it's a quite advanced function, then it's a good way to have a small article really explaining in more detail in steps what's going on behind the scenes, why the options are the way they are. And just get some more advanced examples really of how things work. And I think this could also be more. Then it's also easier for developers to get up to pace with what a function really does. Yeah, automate the whole build process is something we could have done if we thought that it would be more useful. It's not been a high priority. Something that we should have done differently is to have a better handling of when you store large crystals. This will make more sense. I think once we have been through the second part and the same with this last part, I will come back to that. Then I will start on actually showing what the package is. So what you can use it for. Something to mention is that we have had two publications on the package. The first article was when we had sort of the core concepts in place and this very basic API that would let you utilize the symmetry information that was stored alongside it. The second article came a few years later when we had developed a more sort of made it made a package more applicable to research and we had made tools that would let you let you visualize the crystals and manipulate them and make models. Yeah. Okay. So if you want to get started, you can go to the GitHub page. You can just search Max Rd. You would probably find it at the top and you can copy there's a code there just to install it directly from the web and you just load it like you would do with any other package. It doesn't return anything when you load it. But I also like to check the version just to see if everything is working correctly or. Yeah. Okay, so let's return to this points groups and space groups. First of all, you can, if you are very interested in this topic, you can see that there are actually some space group information already in Mathematica in the sort of Standard library. If you go. If you search for element data, you can see that it has some information about, for example, carbon. Here you can see the lattice constants. Those were the ABCs that we. We touched on briefly before. And it has some information about these cryptic names. Right. But it doesn't seem to have anything other than this right now that I could find. So what our package brings is actually you could think of it as a digitalization of whatever is in those. The book series International Tables for Crystallography. So here is 1. Extraction for Space Group P6122. This figure illustrates what kind of symmetry operations operate on the unit cell. It can get quite advanced really quickly. So don't worry if it's confusing. The point is that you have, for example, here a section about the symmetry operations. So these are actually just operations in a very mathematical sense. There are 12 of them for this. And you can look them up in this association like so we can see that there are 12. But this API that I've been speaking about makes it simpler to just get this kind of information as when you want. So we have this function called get symmetry information. And here I'm just picking the third part, just a random sample. And here you can see we have stored it as the transformation function. So if we apply this directly to a tuple coordinate tuple, you get the version, the new coordinates when the symmetry operation works on that coordinate. So it makes. It's very. I think it's clear, easy to use, straight out of the box, sort of. We have some options on most functions. So for example here, if you wanted to just have the lists in this list format, you don't care about this transformation function, you could set this to false. Okay, the next thing I wanted to say if you. Yeah. From this extraction is that there are something that's called special coordinates within the unit cell. And so, for example, if you see this line here with these six coordinates grouped together, they belong to one special position. And you can look up this. If you have a special coordinate in your crystals, you can look this up. So here we would just look. We're looking up this coordinate here and you get the other six back. And this worked with symbols. So we don't need to use variable names. You can just. We can use strings too, or other symbols. So we don't need to clutter the namespace. But we can still have the operations work. Something that's also used make. Makes use of symmetry operations are the symmetry equivalent reflections functions. Yeah, so this works with Miller indices. If that's something you don't know about. You don't have to care about it now, but if you do, then yeah, we have functionality for it for working with that. And import crystal data lets us extend the crystal repository inside the package. There are some demo files that come along with the package. To get you started here we're going to import one of those and call it foo. If you look at the keys of this crystal data. Oops, I have something called there we have a reset function that lets you reset back to the default demo crystals. So let me import foo again and then look at the keys. So you now see it's in there somewhere. Okay, here I was just going to look at the what the kind of data stored with the crystal. So depending on what's in the C file, the crystallographic information file, these are very standard if you do scientific work with crystals you get things like the chemical formula, formula units, the required information about the unit cell and the space group. And in this case there were 11 atoms inside this foo crystal. But let's see, I'm just going to zoom back to 50%. Yeah. Just to mention that there are actually the standard import function supports importing C files but then you get these rules format and for one thing the information that are stored in these files can be a bit ambiguous. So our function will actually it parses the strings inside the files and it's more robust way to get the data in. And of course if you're going to use the package, the other functionalities in the package then using the import crystal data function will get it everything in the in the format that it's expected by the other functions. So it's very easy to use afterwards. Okay, now I just wanted to have a case example with sink just very plainly a hexagonal structure. So in the crystal data it will just contain one element. It has a somewhat special position about 1/3, 2/3 and 1/4 with crystal crystallographic coordinates. Yeah, so let's just see what we can get with this little information. So let's zoom back to 100%. So with this little information you can get the density, mass density pretty quickly. You can calculate the formula units if it's not accompanied in file and we can have a look at what it would look like. So here we have a plot of the, what's called the so called asymmetric unit of the crystal. This is just a single atom that was stored alongside it and the black frame around it is the unit cell. So let's see how the Symmetry operations work. So for this particular space group, there are 24 of them. So that's relatively high symmetry we can look at. If we were to look in the international tables for the space group and this coordinate, we would find this extraction that we see here just in a mathematical format. And here we recognize this coordinate. So this is a special position. Right. So, yeah, we don't have to worry about it. It has to do something with how this atom will be duplicated or copy around inside the unit cell. I just got a question here. If the packing is. Will be added to the Wolfram language packlet repository. I think I put it up some years ago, but if this is. I think if this is the new repository, then maybe I have to put it back in there. And there's also something more here that I think is a bit fun. Things get a bit more complicated when you have things in special positions or you're going to look at which reflections will be sort of visible in the experiments or not. And I think the conditions, syntax or construction in mathematics is very suitable for this kind of conditions. Yeah, they're called conditions and their reflection conditions. So they fit very well. And it's a very natural way to have to organize these conditions in there. But that's a little side note. Yes. So now if you're going to look at whatever. Atoms would be generated by the symmetry operations in sync for this special position, we get this back. So it finds that it belongs to this special position called C2. It has multiplicity 2 because it will be doubled. And if we were to plot the unit cell, you would actually find that it has two atoms. So yeah, if you don't get any. If that didn't make sense to you, I will just say that a lot of things you don't have to worry about, it will handle it automatically. Here we have another example with gallium arsenide, which has two atom species. In a bit more complicated example, here's another function I wanted to introduce. Expand crystal. This one was actually used behind the scenes when we used this structure size option. And what it does is to extend the asymmetric unit of your crystal into whatever structure size you want. By default, it's one by one by one, so just a single unit cell. But you can make larger sizes too. So this will make more sense if you're going to make a model, because you would maybe start with a small supercell of 3 by 3 by 3 unit cells. And yeah, as a starting point in your modeling. Okay, yes, this is the plot of this unit cell, gallium arsenide. And it's not what we're looking here is not actually a true unicell in its proper sense. Because if you remember before when I talked about unit cells, it's something that should be able to just duplicate next to itself all over the material and still look the same. So if you try to copy and paste this block, this unit cell and put it next to the other cells, you will see that these on the corners, these atoms would overlap and crash into each other. So if you're going to build an actual model, you would probably need to take away this boundary. So if you look at this now and if you imagine just copying this, um, and pasting it just next to it, you can see that you get the same structure repeating, but none of the atoms are crashing into each other. Right. Because this one will be copied to this place or this place when it's over there. So in some cases it's very nice to just plot it like this if you're just going to visualize it. But when you're building actual models, it can be important to have this boundary off. And there are more options here. You can choose different atom radius, you can turn on some opacity like this so you can see better the internal atoms. And yeah, there are a lot of more options. And then in addition, you can have all the options of the graphics 3D built in function. Right. Yeah. Let's see. This is just another example here. We have just instead of using the atom radius of whatever the atom species, what's connected to the atom species, we just set one fixed radius and also put on bonds to make it more. Yeah, better looking in some cases. So these are actually just graphic 3D objects where these are spheres and these bonds are cylinders. And a lot of this space group information that I've talked about so far is applied underneath the hood here. Let's see. Yeah, this is a, a function called brag angle. It was one of those early, very fundamental functions that came early on in the package. It is connected to physics and it's something that's fairly, it's a fairly simple calculation. But you need a lot of things to get going. You need to know a lot of things about the experiment. And you can see there here that it has a lot of options in the way you use it. You can either have the crystal label with or without the wavelength, or you can use a metric directly. Here's an extract from the documentation page. So you can see here is some reference to a formula. The Mathematical formula on which it's based on. Let's just see here. Here it is again. Bragg's law. So if you want to know this angle, you need to know the wavelength. This is typically something you attain from the experiment, something you would know from them. And this so called interplanar spacing, this itself is connected. You need to specify the Miller indices, these HKL values, but you also need the metric of reciprocal space, which is connected to the metric of direct space, this G, which again is related by the lattice parameters, the ABC and the angles. Alpha, beta, gamma. And another thing that can complicate things is that some people are used to working with wavelength values. Other people prefer to work with energy. But in Mathematica you have this quantity function that I like a lot. So to avoid confusion, you can have units on, in most of the functions that calculate some physical quantity. And in this Sprague angle, for example, you can either provide a energy parameter or a wavelength parameter and it will figure out to the conversions that necessary. And since our team has been primarily working with wavelength units, if you just give a numerical input like this, it would assume it to be in Angstrom. So in a wavelength unit. Yeah, okay. There's something called systematic absence. I touched upon it briefly before when I was, when I was giving an example of this special position with sync. It's just another complication that needs to be handled. But you can read more about it in the Wolfram community notebook if you're interested. And yeah, interdependencies are just handled automatically whenever possible. So you would provide as little information as you need to the function. I don't know if I had the function called example. Yeah, you can see one here. You just need the crystal you're working with and a wavelength, unless it's accompanied with the experimental data and the HKL values, those are just three parameters. And then you get a result back with units by default. So here there are angles and yeah, it was just an example. So things are very simple to use, but can be quite complicated in the background. And often we would need to generate a suitable list of these reflections. Right. So these HKL values are just arbitrary. But when you're working with a given crystal, you often don't want to just punch in these numbers manually. So often when we're starting on a new notebook, we're exploring something with our data. We want to create a list of suitable reflections and we wanted to have it checked. So we don't have a lot of duplicates in terms of symmetry equivalents. So we would merge these. We would not want to have this systematically extinct reflections. And depending on the wavelength that's connected to the actual experiment, we want to filter out those that you wouldn't observe in the actual experiment. So we have. I'm just going to import this again. This is the one I called foo before. So here you can see in this experiment there's a wavelength associated with it. So here it's very simple to use. Now we can just say reflection list for this crystal. So you see, we get about almost 2,000 reflections that are suitable for this crystal. So maybe when we did experiment, this was on the synchrotron in, in Grenoble, France. So this was. It's a very high energy wavelength. Actually, if we would do this in a sort of conventional X ray setup, this is more likely wavelength, the copper k alpha edge wavelength. And then we would have around 240 suitable reflections instead. All right, let's see here. Yeah, just a note on something that has been. Applied or a way of applying the package is to plot this kind of. To make this kind of plots and you. We need to rework into two systems, right? We have one crystallographic system that makes it more convenient with regards to the symmetry. For example, here is some ice. They have this hexagonal symmetry. But if we want to work within in the real world data, we would want to convert or like plotting these in this partition system. We would need to transfer it back to cartesian coordinates. Here are some examples of how to do it. This is a matrix that lets you do it. The transformation. This is built in. It was one of the ones with A, B, C and alpha, beta, gamma globally defined before. Yeah, These are just some details, ways to do the conversion. So like here we have a convenience function that lets you get the cartesian coordinates very quickly. Okay, so here we have some examples of functions that use the tabulated data, but they're not that exciting to look at. To get scattering cross sections, you have the minimal inputs here, just the crystal and the wavelength, this mu and the attenuation or absorption coefficient can be calculated. So here, for example, copper and the specified wavelength, you can get this mutual. So a lot of these basic functionalities can be belongs maybe in a physics laboratory where students are learning about space groups and point groups and crystals for the first time, or need to get these kind of basic values out. But I don't think I will spend that much more time on that. You can look at it yourself if you're interested. Okay, so now this next sort of subtopic is the modeling functionality. So the way we have evolved our package, it has been inspired by this inclusion compound that we have been studying. So some terms from inclusion compounds, if you're not familiar with that, it's a chemical compound that consists of two phases, a guest face or a guest unit that is embedded into a host unit. So we have used the term entity to sort of generalize this guest or host unit. By entity we mean in practice, anything that is in the crystal data. This could be the asymmetric unit like we saw with the sink. It could be a molecule, an arbitrary unit cell that we have used to extend or expand crystal function with like the 3x3x3 unit cell, a crystal that you just import, or a simple chemical element. If you want to start building from the lowest level possible. And we have a special entity called the void. If you want to just build your crystal on top of nothing. If you want to start with an empty structure and to make the models more sort of realistic, we have the put on functionality that lets you do random perturbations or to let the embedding happen according to specific rules. So we look at that. Yeah. So in this example of how to build simple models, we're going to do three basic things. We're going to start with embedding some atoms into an empty cell. Then I will take the resulting entity and put it into another crystal. And this third example part, we will take this entity from number two and make it a bit more advanced. Okay, so you start the embedding with this function called embed structure. You have a guest and the host crystal. These are the two entities. And you need to specify the target positions, of course, where you want to put it into. So I will make this, it's a good place to use this way of embedding into the void. So here we have just three random atoms, iron, nickel and cobalt, stacked on top of each other. So this were the guest faces, this is the host face, just on nothing. And we put it on just in the origin, half units up and then one unit on top there. So it looks like this nice dango stack. Okay, you can see it is now stored in the crystaldata symbol or association, just like any other crystal would. When you do things like this, it automatically gets the lowest possible space group symmetry. So it just has translation symmetry, nothing else, Nothing fancy. But this is because we want to have it this way. We want to have more control of when we just embed it in. We're just putting stuff in. We're not actually applying symmetry operations here. You would normally apply symmetry operations on the host that you worked in before. And then the things you're going to put in, you're just going to put it in there. It's nothing fancy. So here is an example of the host. This is part two. Now we're going to put it into ice. So this is the ice again. I'm just have expanded it to a 3 by 2 by 1 supercell. I've called it custom ice structure. And then I plot it and it looks like this. So we want to put this stack that we made above here into these cavities here. And you can sort of see that it's symmetric about this unit cell and that the positions for these cavities are sort of 1 2/3 along the A axis and 1/3 along the B axis. Right. Then you get into middle here. So that's why we have here put the coordinates 2/3 along the red one, 13 along the green one and then just zero, just. And yeah, don't have to move up or down. And then we can see that it has four symmetry equivalent positions. I call this insert positions. So now we're going to put the dango stack called custom entity in the customize structure on these coordinates and called it customize. Right. So it's very simple and by default it finds the other equivalent positions for these cavities. If you didn't want that for some reason, you can switch it off with this option. If you're just doing some very specific insertions and then to make it more realistic, you have some options. So what we have done so far is just to use the entities, a list of entities. But what you can also do is to impose some conditions on where an entity should be put in to restrict the placement, for example by the C coordinate or by the X coordinate. Or you could have a probability distribution. So you can have maybe an 80% chance of getting entity one in place and a 10% chance of getting entity two in another place and so on to make it more random. And the perturbation options are below here. You can either distort it by some value or you can rotate it by some value. You can see more details in there. Let me just show you here what we can do. So for clarity, I chose to put this match host size to false so that we just looking at these four units that we're going to embed and we can see on the conditions here that if the coordinates are 1/3 on x and 1/2 on c, then Push it one unit up. So that's the one we see here. And the other one is pushed down one unit, that's this one. And the other ones that didn't fall into either of those are just put in a normal fashion. Let's see what we did here. Yeah, this is just the way to expand it to the whole crystal. If you want this pattern then we just do some tricks with the fractional part. So there's. I think it's a good, when you work with Mathematica that you have many options to do things. You just need to explore it a bit in your own notebook to understand it. Let's see. Yeah, here are some rotation options. So in this first part you can have a random selection between either that one or that one. So there's a 50% chance of it rotating not at all or 180 degrees about the first rotation axis, which by default is this red A axis. So you see two of them are rotated or flipped 180 degrees and then a range of between minus 15 and 15 degrees about this green one, the secondary axis. Of course you can set the rotation axis also if you want to do something more complicated. Here we have the result of a distort functions. Now distort crystal function or distort structure by a vector function. In this case a sine. Sine like function. So very exaggerated here. But you can. Yeah, impose some perturbations in this way too. And you can also do this as an option in embedding so that the sine function or whatever vector function you have follows or the embedding positions follow this vector function. So you would embed it in a more natural place. Here's another example of distorting it by a triangular wave. Yeah. So if you're interested, do check out the options. Okay. So in the next step of our modeling we figured we needed to go one higher level up in the modeling world. And instead of just looking at unit cells or supercells that needed that were customized, maybe you should look at domains inside the structure. So a domain would be consist of several of these unit cells typically. So we made a function for creating these. Here we can see how it evolves. It's just the Monte Carlo method. So we started with these domains, one color for each domain. So they're identified by some integer and then represented by color. And then you just have this sort of fight. And in this case it converged or completed, reached a complete dominance by one type after 20 cycles. So maybe there were just. This is a very small example of 7 by 7 cells. Maybe if we do 20 by 20 times 1, you can have more exciting results. So this is just something that lets you build a randomized model. And also here, yeah, you can do it in 3D. So here it ended up in these two domains after 20 cycles. Yeah. So what you would do with this is. Well, we can look at what do you get the random domain here, it's just A list of 2 sub lists, 1 that says the size and one that contains all the identifiers of the cells in the domains. So in this case there are three, you see three colors that survived. So let's see if we want to embed three entities into these three colors, then it's pretty straightforward. To do this we just need to have a map between the identifier and the crystal entity you want to embed. So here we have just three simple atoms. Again, we have the mapping here. Then we use a function called synthesize structure which supports this kind of mapping. So you just need the domain, you need to call it something and you need the mapping. So here we can see this. Maybe I should create it again. Yeah, so this can be translated into this. Let's see to do the mapping again, This. So normally you would have something more complicated than just a single atom in each site, but this is just a great way to illustrate that it works the way it's expect the way we would expect it. Yes. And then a final thing about the rotations, I mean about the domains, is that you can also impose a bit more perturbations here by rotating it so you can rotate it. You have some options to choose the anchoring position, so you can rotate about the host, for example, then you have the anchor down there, you can rotate one domain around about that place or maybe about the centroids. So if you want to rotate about the green domain, you could do that too, or just each individual cell. So for the blue one it's there and for the red ones it's there. So I have all sort of options. Another thing you can do with domains is too, this was inspired by one article we saw about the similar compound. Where we see. Where we saw that the domains are structured in this kind of sectoral region or spiral structure. So we wanted to be able to make models with this kind of layout. And yeah, this is one way to do it. You can add, in this case we have 1, 2, 3 specified sector regions. And then there's always one default region for the ones that are not covered by whatever you specify. Yeah. So Maybe that's something that you want to try out with your crystal. But I think this one was the one we had most success with to make a mosaic structure. So a mosaic is just. You can think of all domains as having or you're still consisting of a lot of many lot of domains that are rotated about each other by a small amount. And in our case, this was the most promising model. Of course it doesn't look like this. It was first of all in 3D and the rotations are exaggerated here just to see what's going on. But yeah, feel free to. So this was just a small extension of how we construct domains. You can see this as an example in the documentation. Okay. So reciprocal space is another part of the modeling. This is, I guess it's more interested if you work with diffraction. But the idea is that you can simulate how the patterns of the crystal would look like if you would do some experiments. So you can have a look at that. These are just very basic geometrical outputs. A real life experiment would look something like this. And you can simulate this with the functionality you have in the max rd and you can get the patterns out and you can get from the real experiments and you can overlay them so that you can check with reflections that you specify and see that you have them in your experimental data. So this one was a particular useful function for us. Of course it. You can say that it was a bit specialized to our use needs, but it's still generalized enough to work with other crystals too, I think. Yeah. So this is a geometric, it's just the spheres and they're scaled in radius according to their structure factor or intensity. Yeah. So if you like this, look in the documentation, see some examples. You don't need any external tools for this. If you want to make a more realistic package than realistic image, then you should. You can connect max RD to external programs, but you need to read the documentation for that and see. See how to do it. Yeah. Here are some actual models or the way we made actual models in our research. You can see we started with something from our experimental setup. We just did some cleaning to just get the parts we wanted to build here, in this case the host. So we put out, cleared out all the host, the guest units and put them in ourselves afterwards in a certain perturbation pattern. So yeah, so these are some snippets from actual steps in building models. So here we have put them in this spiraling fashion, for example, and we tried a lot of variations that are almost similar, but still make up different models to test things. Okay, so if any of that was a bit too fast, then I should go and have a look at yourself, the things that you were most interested in. Here are some links to the articles and web pages and some books for further reading. But I think that's all we had time for. If you have any questions, then you can post them now. And thank you for your attention.
More from Guy

Cheryl Strauss Einhorn | The Human Edge: Smarter Decisions in the Age of AI | Talks at Google

Rachel Glennerster | Innovation and the Center for Global Development | Talks at Google

Rebecca Winthrop | Rethinking the Purpose of Education in the Age of AI | Talks at Google

Dr. Robert Wachter | A Giant Leap: How AI Is Transforming Healthcare... | Talks at Google






