{ "cells": [ { "cell_type": "markdown", "id": "important-midwest", "metadata": {}, "source": [ "# Instrument object\n", "This section shows the majority of the features implemented for the instrument object in McStasScript." ] }, { "cell_type": "markdown", "id": "eastern-distance", "metadata": {}, "source": [ "## Initialization\n", "An instrument object is created with the [McStas_instr](../_autosummary/mcstasscript.interface.instr.McStas_instr.rst) or [McXtrace_instr](../_autosummary/mcstasscript.interface.instr.McXtrace_instr.rst) class. When an instrument object is created the only required argument is the name of the instrument which will be used for the instrument filename. There are however a number of keyword arguments that can be used to provide more information and alter the behavior.\n", "\n", "| Keyword argument | Type | Default | Description |\n", "| --- | --- | --- | --- |\n", "| author | str |\"Python Instrument Generator\" | Name that will appear as author in instrument files |\n", "| origin | str |\"ESS DMSC\" | String that will appear as origin in instrument files |\n", "| input_path | str | \".\" | Folder which is considered workspace for McStas / McXtrace |\n", "| output_path | str | instrument_name | Name of data folder written by simulation |\n", "| package_path | strĀ | | Can be set to manually specify location of McStas/McXtrace installation |\n", "| executable_path | str | | Can be set to manually specify location of mcrun/mxrun executable |\n", "| ncount | int, float | 1E6 | Sets the ncount used for simulations |\n", "| mpi | int | | Sets the number of MPI threads used for simulations |\n", "| force_compile | bool | True | Whether to force compilation before each run or not |\n", "| parameters | ParameterContainer | | Set of parameters for initialized instrument |" ] }, { "cell_type": "code", "execution_count": null, "id": "liable-newton", "metadata": {}, "outputs": [], "source": [ "import mcstasscript as ms" ] }, { "cell_type": "code", "execution_count": null, "id": "experienced-locator", "metadata": {}, "outputs": [], "source": [ "instrument = ms.McStas_instr(\"instr_name\", author=\"Mads Bertelsen\", origin=\"DMSC\")\n", "instrument_w_settings = ms.McStas_instr(\"instr_name\", ncount=3E6, output_path=\"new_folder\")" ] }, { "cell_type": "markdown", "id": "universal-saudi", "metadata": {}, "source": [ "### Using settings method\n", "The instrument object has a *setting* method which can update some settings after initialization. The current settings can always be viewed with *show_settings*.\n", "\n", "| Keyword argument | Type | Default | Description |\n", "| --- | --- | --- | --- |\n", "| output_path | str | instrument_name | Name of data folder written by simulation |\n", "| package_path | strĀ | | Can be set to manually specify location of McStas/McXtrace installation |\n", "| executable_path | str | | Can be set to manually specify location of mcrun/mxrun executable |\n", "| ncount | int, float | 1E6 | Sets the ncount used for simulations |\n", "| mpi | int | | Sets the number of MPI threads used for simulations |\n", "| seed | | | Sets the seed of the simulation |\n", "| force_compile | bool | True | Whether to force compilation before each run or not |\n", "| custom_flags | str | | String with custom flags for mcrun/mxrun command |" ] }, { "cell_type": "code", "execution_count": null, "id": "sapphire-pasta", "metadata": {}, "outputs": [], "source": [ "instrument.show_settings()\n", "instrument_w_settings.show_settings()" ] }, { "cell_type": "code", "execution_count": null, "id": "assumed-boundary", "metadata": {}, "outputs": [], "source": [ "instrument.settings(mpi=4, seed=300)\n", "instrument.show_settings()" ] }, { "cell_type": "markdown", "id": "unsigned-ideal", "metadata": {}, "source": [ "## Parameters\n", "Instrument parameters can be added with *add_parameters* which returns a parameter object." ] }, { "cell_type": "code", "execution_count": null, "id": "signed-distributor", "metadata": {}, "outputs": [], "source": [ "wavelength = instrument.add_parameter(\"wavelength\", comment=\"Wavelength in AA\")\n", "print(wavelength)\n", "wavelength.value = 5\n", "print(wavelength)" ] }, { "cell_type": "markdown", "id": "sunset-bishop", "metadata": {}, "source": [ "### Searching for components and data\n", "McStas have a few keywords for adjusting where to search for data and components. This is typically added right after the parameters, so its natural to include it here in the documentation of the instrument object.\n", "\n", "#### Dependency\n", "The DEPENDENCY keyword allows McStas to search for data and software at runtime. There is just one dependency line for an instrument." ] }, { "cell_type": "code", "execution_count": null, "id": "surprised-jurisdiction", "metadata": {}, "outputs": [], "source": [ "instrument.set_dependency(\"/dependency/example\")" ] }, { "cell_type": "markdown", "id": "photographic-norwegian", "metadata": {}, "source": [ "As the instrument won't run unless the dependency is set to a valid path, let's reset it." ] }, { "cell_type": "code", "execution_count": null, "id": "sticky-affect", "metadata": {}, "outputs": [], "source": [ "instrument.set_dependency(\"\")" ] }, { "cell_type": "markdown", "id": "applied-gallery", "metadata": {}, "source": [ "#### Search\n", "The SEARCH keyword allows McStas to search for components before McStas code generation. There can be multiple SEARCH statements in an instrument. It is possible to enable SHELL processing so a system command can be given that should return a path. McStasScript has yet to implement this features fully, so McStasScript won't find components in search paths. For now it can only be used to overwrite existing components with identical input parameters." ] }, { "cell_type": "code", "execution_count": null, "id": "dominican-tension", "metadata": {}, "outputs": [], "source": [ "instrument.add_search(\"/search/example\")\n", "instrument.add_search(\"pwd\", SHELL=True)\n", "\n", "instrument.show_search()" ] }, { "cell_type": "markdown", "id": "level-being", "metadata": {}, "source": [ "It is possible to clear all search statements from an instrument with the *clear_search* method." ] }, { "cell_type": "code", "execution_count": null, "id": "middle-conservation", "metadata": {}, "outputs": [], "source": [ "instrument.clear_search()\n", "instrument.show_search()" ] }, { "cell_type": "markdown", "id": "fourth-glasgow", "metadata": {}, "source": [ "## Initialize section\n", "One of the great advantages for the McStas / McXtrace packages is the initialize section of the instrument where calculations can be performed before the ray-tracing simulation starts. One could for example calculate appropriate angles to reach a certain Bragg peak at a given wavelength. This would involve defining some declare variables, using these in the initialize section and then assigning them as component inputs.\n", "\n", "In McStasScript many calculations can be performed directly in Python, and so typically the initialize section is used less, but it is still useful and available through McStasScript.\n", "\n", "The instrument object has the method *append_initialize* which adds a line of code to the initialize. This line is copied directly into the instrument file, so it follows C syntax. Remember the semicolon! In addition there is *add_declare_var* to specify the declared variables needed. When declare variables are defined an object is returned which can be used when referring to that variable." ] }, { "cell_type": "code", "execution_count": null, "id": "spare-button", "metadata": {}, "outputs": [], "source": [ "wavenumber = instrument.add_declare_var(\"double\", \"wavenumber\")\n", "instrument.append_initialize(\"wavenumber = 2*PI/wavelength;\")" ] }, { "cell_type": "code", "execution_count": null, "id": "twelve-tuition", "metadata": {}, "outputs": [], "source": [ "print(instrument.initialize_section)" ] }, { "cell_type": "markdown", "id": "occupational-budget", "metadata": {}, "source": [ "## Finally section\n", "The finally section works exactly as the initialize section, but is executed after the ray-tracing simulation. Add a line to it with *append_finally*." ] }, { "cell_type": "code", "execution_count": null, "id": "cultural-workplace", "metadata": {}, "outputs": [], "source": [ "instrument.append_finally('printf(\\\"Thanks for using McStasScript!\\\\n\\\");')\n", "print(instrument.finally_section)" ] }, { "cell_type": "markdown", "id": "threaded-double", "metadata": {}, "source": [ "## Help features\n", "There are a few methods built into the instrument class that helps the user, these are:\n", "\n", "- *available_components*\n", "- *component_help*\n", "\n", "### available_components\n", "The *available_components* method shows the component categories, and if called with the name of a category, will show all available components in the specified category. The categories can include the work directory if any components are located there." ] }, { "cell_type": "code", "execution_count": null, "id": "foreign-chosen", "metadata": {}, "outputs": [], "source": [ "instrument.available_components()" ] }, { "cell_type": "code", "execution_count": null, "id": "regulated-hollywood", "metadata": {}, "outputs": [], "source": [ "instrument.available_components(\"optics\")" ] }, { "cell_type": "markdown", "id": "ultimate-junction", "metadata": {}, "source": [ "### component_help\n", "The *component_help* method can show the parameters of any component the instrument object knows about, although not necessarily used in the instrument." ] }, { "cell_type": "code", "execution_count": null, "id": "dominican-dubai", "metadata": {}, "outputs": [], "source": [ "instrument.component_help(\"Guide\")" ] }, { "cell_type": "markdown", "id": "studied-victorian", "metadata": {}, "source": [ "## Adding components\n", "One adds components to the instrument using *add_component* which takes the name of the component instance for the instrument, followed by the name of the component in the library. When adding a component, a [component](../_autosummary/mcstasscript.helper.mcstas_objects.Component.rst) object is returned, and how these can be manipulated is discussed on the [component object page](component_object.ipynb). Notice that it is not allowed to add two components with the same instance name, meaning rerunning this cell would raise an exception. " ] }, { "cell_type": "code", "execution_count": null, "id": "literary-nirvana", "metadata": {}, "outputs": [], "source": [ "source = instrument.add_component(\"source\", \"Source_div\")\n", "source.set_parameters(xwidth=0.1, yheight=0.1, focus_aw=3.0, focus_ah=2.0, \n", " lambda0=wavelength, dlambda=\"0.1*wavelength\")" ] }, { "cell_type": "code", "execution_count": null, "id": "loving-raleigh", "metadata": {}, "outputs": [], "source": [ "print(source)" ] }, { "cell_type": "code", "execution_count": null, "id": "unnecessary-helen", "metadata": {}, "outputs": [], "source": [ "instrument.show_components()" ] }, { "cell_type": "markdown", "id": "outdoor-motor", "metadata": {}, "source": [ "There are a number of keyword arguments allowed when adding a component. These will mainly be discussed on the [component object page](component_object.ipynb), but a few are relevant for the instrument, because they handle in what order components are sequenced in the instrument. To illustrate this we add a slit and a guide to the instrument at reasonable positions. Notice these new components are added at the end of the instrument." ] }, { "cell_type": "code", "execution_count": null, "id": "informative-council", "metadata": {}, "outputs": [], "source": [ "slit = instrument.add_component(\"source_slit\", \"Slit\", AT=2, RELATIVE=source)\n", "slit.set_parameters(xwidth=0.015, yheight=0.015)\n", "\n", "guide = instrument.add_component(\"guide\", \"Guide\", AT=0.1, RELATIVE=slit)\n", "guide.set_parameters(w1=0.03, h1=0.03, l=10.0)" ] }, { "cell_type": "code", "execution_count": null, "id": "moral-apartment", "metadata": {}, "outputs": [], "source": [ "instrument.show_components()" ] }, { "cell_type": "markdown", "id": "least-circulation", "metadata": {}, "source": [ "The order of components is important in a McStas/McXtrace simulation as each will affect the ray state in the sequence shown with *print_components*. If one wants to add a component between the source and the slit, this can be done with the *before* or *after* keyword." ] }, { "cell_type": "code", "execution_count": null, "id": "absent-pizza", "metadata": {}, "outputs": [], "source": [ "monitor = instrument.add_component(\"PSD\", \"PSD_monitor\", after=\"source\")\n", "monitor.set_AT(1.9, RELATIVE=source)\n", "monitor.set_parameters(xwidth=0.1, yheight=0.1, filename='\"PSD.dat\"')\n", "\n", "instrument.show_components()" ] }, { "cell_type": "markdown", "id": "municipal-prior", "metadata": {}, "source": [ "The PSD monitor was inserted after the source, this could also be accomplished with the before keyword argument.\n", "```\n", "before=\"source_slit\"\n", "```\n", "It is important to note that the McStas instrument file is read sequentially, so the position of the PSD monitor can not be relative to a later component, but must only refer to earlier components. At this point in development it is not possible to reorder components in the instrument object." ] }, { "cell_type": "markdown", "id": "after-setup", "metadata": {}, "source": [ "## Moving a component\n", "It is also possible to move a component in the component sequence of the instrument. Lets add a *Lmonitor* at the end at move it to the PSD. The *move_component* command takes a name or component object to be moved, and then the same before and after keywords as *add_component*." ] }, { "cell_type": "code", "execution_count": null, "id": "loose-motivation", "metadata": {}, "outputs": [], "source": [ "Lmon = instrument.add_component(\"Lmon\", \"L_monitor\", RELATIVE=\"guide\")\n", "instrument.show_components()" ] }, { "cell_type": "code", "execution_count": null, "id": "constant-footwear", "metadata": {}, "outputs": [], "source": [ "instrument.move_component(Lmon, after=source)\n", "instrument.show_components()" ] }, { "cell_type": "markdown", "id": "enabling-business", "metadata": {}, "source": [ "It is easy to introduce a mistake in an instrument by moving a component, as components uses each other as references for position and rotation. In the above example the *Lmon* was placed relative to the *guide* component, and thus McStasScript warns that an error was introduced when the component was moved, as *guide* has not been defined at the new position of *Lmon*. The method *check_for_errors* can be called for further information, here in a try block to catch the exception." ] }, { "cell_type": "code", "execution_count": null, "id": "assured-paint", "metadata": {}, "outputs": [], "source": [ "try:\n", " instrument.check_for_errors()\n", "except Exception as e:\n", " print(str(e))" ] }, { "cell_type": "markdown", "id": "superb-source", "metadata": {}, "source": [ "## Removing a component\n", "Components can be removed with the *remove_component* method. The input can be either a component name or a component object." ] }, { "cell_type": "code", "execution_count": null, "id": "severe-luther", "metadata": {}, "outputs": [], "source": [ "instrument.remove_component(Lmon)\n", "instrument.show_components()" ] }, { "cell_type": "markdown", "id": "distinct-thousand", "metadata": {}, "source": [ "## Making a component copy\n", "It is possible to copy an existing component using the *copy_component* method. This can reduce both the amount of typing necessary, but also the risk of making a mistake. Here the guide is copied and placed a bit after the end of the first guide, with a small rotation." ] }, { "cell_type": "code", "execution_count": null, "id": "figured-electronics", "metadata": {}, "outputs": [], "source": [ "guide2 = instrument.copy_component(\"guide_2\", \"guide\")\n", "guide2.set_AT(guide.l + 0.01, RELATIVE=guide)\n", "guide2.set_ROTATED([0, 0.5, 0], RELATIVE=guide)\n", "print(guide2)" ] }, { "cell_type": "markdown", "id": "parental-theme", "metadata": {}, "source": [ "## Getting components\n", "It is always possible to retrieve the component objects corresponding to components in the instrument with the *get_component* and *get_last_component* methods." ] }, { "cell_type": "code", "execution_count": null, "id": "military-biotechnology", "metadata": {}, "outputs": [], "source": [ "my_source = instrument.get_component(\"source\")\n", "print(my_source)" ] }, { "cell_type": "code", "execution_count": null, "id": "ambient-naples", "metadata": {}, "outputs": [], "source": [ "last_component = instrument.get_last_component()\n", "print(last_component)" ] }, { "cell_type": "markdown", "id": "third-blend", "metadata": {}, "source": [ "### Instrument diagram\n", "McStasScript can generate a diagram of an instrument file to aid the user in understanding its content. Use the *show_diagram* method to display the figure. The legend shows how the different component categories are represented with different colors, and how AT and ROTATED is represented with arrows. The rest of the figure is the actual diagram of this instrument, showing the sequence of components.\n", "\n", "If in a notebook and using the %matplotlib widget backend, hovering the mouse over the left side of the boxes show further information on the individual components.\n", "\n", "The diagram will also show use of the keywords EXTEND, WHEN, JUMP and GROUP, as well as connections between Union components, though none of these are present in this diagram." ] }, { "cell_type": "code", "execution_count": null, "id": "annoying-preservation", "metadata": {}, "outputs": [], "source": [ "instrument.show_diagram()" ] }, { "cell_type": "markdown", "id": "cardiovascular-hughes", "metadata": {}, "source": [ "## Run the simulation\n", "The simulation is executed with a call to the *backengine* method, which will return the generated data. If the simulation fails, the method returns None. McStasScript does check for some common mistakes before attempting to run the McStas simulation, if any problem is found a useful error message will be shown." ] }, { "cell_type": "code", "execution_count": null, "id": "intense-chapter", "metadata": {}, "outputs": [], "source": [ "data = instrument.backengine()" ] }, { "cell_type": "code", "execution_count": null, "id": "honey-conference", "metadata": {}, "outputs": [], "source": [ "print(data)" ] }, { "cell_type": "markdown", "id": "varying-clearing", "metadata": {}, "source": [ "## Visualizing the instrument\n", "It is possible to visualize the instrument using the visualization features in McStas / McXtrace. This is done using the *show_instrument* method that show the instrument with the currently set parameters. The method takes a format keyword, of which there are two allowed:\n", "\n", "| Format | Description | |\n", "| :-- | :-- | --- |\n", "| webgl | 3D view in notebook or browser tab | (default) |\n", "| window | 2D view in window | |\n", "\n", "\n", "The default format webgl behaves differently whether in a notebook or from a script. In a notebook, the output will be shown directly in the cell as shown in the example below, but in a script it will open a new browser tab. If a new browser tab is desired even when running from a notebook, set the keyword argument *new_tab* to True.\n", "\n", "When using the 3D view in webgl, use these controls to manipulate the view:\n", "\n", "| Action | Effect on view |\n", "| :-- | :-: |\n", "| Hold left click and drag | Rotate |\n", "| Hold right click and drag | Move |\n", "| Hold mouse wheel and drag up/down | Zoom in/out |" ] }, { "cell_type": "code", "execution_count": null, "id": "headed-simulation", "metadata": {}, "outputs": [], "source": [ "instrument.show_instrument()" ] }, { "cell_type": "markdown", "id": "disciplinary-tamil", "metadata": {}, "source": [ "The window format is a 2D view which is opened in a new window, and may not always work if one use McStasScript through the cloud or a docker container. It is better suited for getting measurements and ensuring the geometry is exactly as desired." ] }, { "cell_type": "code", "execution_count": null, "id": "italic-madagascar", "metadata": { "tags": [ "hide-output" ] }, "outputs": [], "source": [ "instrument.show_instrument(format=\"window\")" ] }, { "cell_type": "markdown", "id": "supreme-stamp", "metadata": {}, "source": [ "### Showing instrument file\n", "McStasScript writes the instrument file for McStas in the process of running or visualizing the instrument. The file can be shown with the *show_instrument_file* method." ] }, { "cell_type": "code", "execution_count": null, "id": "korean-industry", "metadata": {}, "outputs": [], "source": [ "instrument.show_instrument_file(line_numbers=True)" ] }, { "cell_type": "markdown", "id": "dressed-branch", "metadata": {}, "source": [ "## Dump and load an instrument object\n", "It is possible to save an instrument object to disk and load it later." ] }, { "cell_type": "code", "execution_count": null, "id": "casual-blame", "metadata": {}, "outputs": [], "source": [ "instrument.dump(\"dump_file_name.dmp\")" ] }, { "cell_type": "markdown", "id": "distant-arthritis", "metadata": {}, "source": [ "To load an instrument object from a file, use the *from_dump* method that takes the filename." ] }, { "cell_type": "code", "execution_count": null, "id": "advance-soldier", "metadata": {}, "outputs": [], "source": [ "loaded_instrument = ms.McStas_instr.from_dump(\"dump_file_name.dmp\")" ] }, { "cell_type": "code", "execution_count": null, "id": "european-pepper", "metadata": {}, "outputs": [], "source": [ "loaded_instrument.show_components()\n", "loaded_instrument.show_settings()" ] }, { "cell_type": "code", "execution_count": null, "id": "independent-blend", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" }, "metadata": { "execution": { "timeout": 100 } } }, "nbformat": 4, "nbformat_minor": 5 }