diff --git a/doc/source/topic_guides/developers_guide.rst b/doc/source/topic_guides/developers_guide.rst index b838df0620147b8ce155c398ff7cb4517dd45d2b..7fc1b66e3ff426f64acf4c997a7de512fc51c92e 100644 --- a/doc/source/topic_guides/developers_guide.rst +++ b/doc/source/topic_guides/developers_guide.rst @@ -25,15 +25,17 @@ For developers of the project, branch management will follow How to edit, install, and test your changes locally --------------------------------------------------- -With every change made to the kmcos source code (within the kmcos directory), kmcos needs to be reinstalled for the changes to take place. -Before re-installing kmcos, to ensure the re-installation occurs correctly, it's best to delete any past kmcos installation files in your python environment. To do so, locate the site-package directory for whichever python environment you're using (typically this would be located in a directory that looks something like ~/VENV/kmcos/lib/python3/site-packages/). Within the site-packages directory, delete any subdirectories that have the name kmcos as well as any other files you see with the name kmcos (typically egg or zip files). -Next, using the terminal, navigate the kmcos source code directory that you have edited, and make sure you are in the directory where setup.py is located. Run the following commands to reinstall kmcos with changes :: +First, install kmcos, then you must locate your kmcos installation. Typically it will be in a directory similar to: ~/VENV/kmcos/lib/python3/site-packages/ +If you have difficulty finding it, use | python3 -c"import sys; print(sys.path)" | Then, inside tthe site-packages directory, if kmcos has an "egg" file, you must copy the kmcos directory out of the egg file directly into the site_packages directory. After that, delete any other kmcos egg files or directories so that there is a single kmcos directory inside of site_packages. + +OPTION 1 (recommended): Edit the source code directly inside site_packages, or edit the code elsewhere and then paste over the files in site_packages. Usually, this will be sufficient. + +OPTION 2: Edit the source code elsewhere (such as in a shared folder) and reinstall using the setup.py:: source ~/VENV/kmcos/bin/activate #this is the command to enter the python virtual environment - python3 setup.py build - python3 setup.py install + pip install . -Now that the kmcos dependencies are updated, you can start testing your latest changes. +This will reinstall kmcos. Before pushing to github, you should enter the the tests directory and run the unit tests. @@ -198,6 +200,12 @@ All kmcos models contain train main source files: ``base.f90``, a module of the same name. These modules are exposed to Python interface. +It is important to know that some of the fortran code +comes from the directory \kmcos\fortran_src\ +and some of the fortran code comes from the file +\kmcos\io.py , so io.py should be checked +as well, if needed, when looking for fortran source code. + Files for the ``local_smart`` backend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/tutorials/first_model_api.rst b/doc/source/tutorials/first_model_api.rst index 8231d3d83b4baf7a0307575d4070cb7c41e3997c..497350f942de32538865c450c9999fec0c36bc2c 100644 --- a/doc/source/tutorials/first_model_api.rst +++ b/doc/source/tutorials/first_model_api.rst @@ -228,11 +228,12 @@ directory you should see a `myfirst_kmc.xml`. You will also see a directory ending with _local_smart, this directory includes your compiled model. -You can also skip the model exporting and do it later by removing kmcos.compile(kmc_model): -you can use a separate python file later, or from the command line -can run `kmcos export myfirst_kmc.xml` in the same directory as the XML. +You can also skip the model exporting (and do it later) by commenting out kmcos.compile(kmc_model): +then you can use a separate python file later. +For some installations, you can use `kmcos export myfirst_kmc.xml` from the linux terminal +when you are in the same directory as the XML. -During troubleshooting, exporting separately can be useful to make sure +During troubleshooting, exporting separately can sometimes be useful to make sure the compiling occurs gracefully without any line containining an error. @@ -248,10 +249,10 @@ Next, let's try seeing how it looks visually with :: python3 kmc_settings.py view -... and dada! Your first running kMC model right there! -For some installations, one can type `kmcos benchmark` and `kmcos view.` +The "view" command only works on certain operating systems. +For some installations, one can alternativeley type `kmcos benchmark` and `kmcos view.` -For running the model, you should use a runfile. +For running the model, it is recommended to use a runfile. If you wonder why the CO molecules are basically just dangling there in mid-air that is because you have no background setup, yet. diff --git a/doc/source/tutorials/run_model_api.rst b/doc/source/tutorials/run_model_api.rst index 547b7554ca954e6ae1d09c76d506d7f440763066..356f24a1304d4c13ff8a31668550396090dc11e2 100644 --- a/doc/source/tutorials/run_model_api.rst +++ b/doc/source/tutorials/run_model_api.rst @@ -76,6 +76,11 @@ it also contains some additional data piggy-backed such as :: atoms.kmc_time atoms.kmc_step +If one wants to know what the next kmc step will be +and at which site, without executing the step, one can use :: + + model.get_next_kmc_step() + These quantities are often sufficient when running and simulating a catalyst surface, but of course the model could be expanded to more observables. The Fortran modules `base`, `lattice`, @@ -178,13 +183,16 @@ note that after using '_put', one must remember to call `_adjust_database()` before executing any next step or the database of available processes will not match the species, the kmc simulation will become incorrect and likely crash after some steps. +Saving and Reloading the State of the Simulation +================================= + If one wants to set the whole configuration of the lattice once can retreive it, save it, and load it with the following commands :: model.dump_config("YourConfigurationName") model.load_config("YourConfigurationName") -Those commands use the following internal commands as part of how they function :: +While it is not necessary for a regular user to know, those commands use the following internal commands as part of how they function :: #saving the configuration uses: config = model._get_configuration() @@ -192,7 +200,19 @@ Those commands use the following internal commands as part of how they function model._set_configuration(config) model._adjust_database() +However, simply saving and loading the configuration will not allow you to exactly reproduce the simulation where it left off. +To do that, you also need to save and reload the pseusdo random generator's state :: + PRNG_state = model.proclist.get_seed().tolist() #This list can be saved as a pickle or in a text file. + model.proclist.put_seed(PRNG_state) #This command takes the PRNG_state as a list and inputs into the simulation. + +By saving both the configuration and the PRNG_state, one can +start a simulation again on the same trajectory +(providing one sets the parameters such as temperature and pressure). +The snapshots module includes methods saving and loading the +configuration, PRNG_state, and parameters. +A single command to save all aspects of the simulation +and reload the simulation where it leftoff will later be added into the main code and added to the tutorials. Running models in parallel diff --git a/kmcos/__init__.py b/kmcos/__init__.py index 8fbdbe7ad32cf20cdb8794bf0c1d091548d8aba0..0d5ba47affe3618cf1bebac5214158282d92ba11 100644 --- a/kmcos/__init__.py +++ b/kmcos/__init__.py @@ -50,7 +50,7 @@ from __future__ import print_function -__version__ = "1.0.5" +__version__ = "1.0.6" VERSION = __version__ def evaluate_param_expression(param, parameters={}): @@ -480,4 +480,4 @@ def xml(argumentsString): import kmcos.cli as cli cli.main('xml'+' ' + argumentsString) -from kmcos.io import clear_model +#from kmcos.io import clear_model #this line was commented out Nov 19th 2022, it should not be here and may have been here for testing. diff --git a/kmcos/fortran_src/base.mpy b/kmcos/fortran_src/base.mpy index 2a0d671ea51b3bc046b877996ee82ac7d84f81cb..0f11ba87fde0da7f3543668b9bdebcbf15011831 100644 --- a/kmcos/fortran_src/base.mpy +++ b/kmcos/fortran_src/base.mpy @@ -1120,11 +1120,15 @@ #@ ASSERT(ran_proc.le.1,"base/determine_procsite: ran_proc has to be less or equal 1") #@ ASSERT(ran_site.ge.0,"base/determine_procsite: ran_site has to be positive") #@ ASSERT(ran_site.le.1,"base/determine_procsite: ran_site has to be less or equal 1") +#@ ! print *, "BASE/determine_procsite before avail_sites" +#@ ! print *," BASE/determine_procsite/RAN_PROC",ran_proc +#@ ! print *," BASE/determine_procsite/RAN_site",ran_site +#@ ! print *," BASE/determine_procsite/PROC",proc +#@ ! print *," BASE/determine_procsite/SITE",site #@ #@ ! ran_proc <- [0,1] so we multiply with larger value in accum_rates #@ call interval_search_real(accum_rates, ran_proc*accum_rates(nr_of_proc), proc) #@ -#@ #@ ! the result shall be between 1 and nrofsite(proc) so we have to add 1 the #@ ! scaled random number. But if the random number is closer to 1 than machine #@ ! precision, e.g. 0.999999999, we would get nrofsits(proc)+1 so we have to @@ -1132,6 +1136,11 @@ #@ site = avail_sites(proc, & #@ min(nr_of_sites(proc),int(1+ran_site*(nr_of_sites(proc)))),1) #@ +#@ ! print *, "BASE/determine_procsite after avail_sites" +#@ ! print *," BASE/determine_procsite/RAN_PROC",ran_proc +#@ ! print *," BASE/determine_procsite/RAN_site",ran_site +#@ ! print *," BASE/determine_procsite/PROC",proc +#@ ! print *," BASE/determine_procsite/SITE",site #@ #@ ASSERT(nr_of_sites(proc).gt.0,"base/determine_procsite: chosen process is invalid & #@ because it has no sites available.") diff --git a/kmcos/fortran_src/proclist_generic_subroutines.mpy b/kmcos/fortran_src/proclist_generic_subroutines.mpy index 2a212513e68c4b1d00b8f945a1d0d13fd9ee52fc..a79694674fdf1cf8b450dc5d858e92cd6f4ced18 100644 --- a/kmcos/fortran_src/proclist_generic_subroutines.mpy +++ b/kmcos/fortran_src/proclist_generic_subroutines.mpy @@ -29,7 +29,6 @@ if data.meta.debug > 0: #@ print *," PROCLIST/DO_KMC_STEP/RAN_TIME",ran_time #@ print *," PROCLIST/DO_KMC_STEP/RAN_PROC",ran_proc #@ print *," PROCLIST/DO_KMC_STEP/RAN_site",ran_site - #@ call update_accum_rate #@ call update_clocks(ran_time) #@ @@ -38,6 +37,12 @@ if data.meta.debug > 0: if data.meta.debug > 0: #@ print *,"PROCLIST/DO_KMC_STEP/PROC_NR", proc_nr #@ print *,"PROCLIST/DO_KMC_STEP/SITE", nr_site +#@ ! print *, "PROCLIST/DO_KMC_STEP" +#@ ! print *," PROCLIST/DO_KMC_STEP/RAN_TIME",ran_time +#@ ! print *," PROCLIST/DO_KMC_STEP/RAN_PROC",ran_proc +#@ ! print *," PROCLIST/DO_KMC_STEP/RAN_SITE",ran_site +#@ ! print *,"PROCLIST/DO_KMC_STEP/NR_SITE", nr_site +#@ ! print *,"PROCLIST/DO_KMC_STEP/PROC_NR", proc_nr #@ call run_proc_nr(proc_nr, nr_site) #@ enddo #@ @@ -141,9 +146,17 @@ if data.meta.debug > 0: #@ subroutine get_next_kmc_step(proc_nr, nr_site) #@ -#@ !****f* proclist/get_kmc_step +#@ !****f* proclist/get_next_kmc_step #@ ! FUNCTION #@ ! Determines next step without executing it. +#@ ! However, it changes the position in the random_number +#@ ! sequence. The python function for +#@ ! model.get_next_kmc_step() should be used +#@ ! as it makes additional function calls +#@ ! to reset the random numbers. +#@ ! Calling model.proclist.get_next_kmc_step() +#@ ! is discouraged as that will call this subroutine +#@ ! directly and will not reset the random numbers. #@ ! #@ ! ARGUMENTS #@ ! @@ -156,14 +169,18 @@ if data.meta.debug > 0: #@ call random_number(ran_proc) #@ call random_number(ran_site) if data.meta.debug > 0: - #@ print *,"PROCLIST/GET_KMC_STEP/RAN_TIME",ran_time - #@ print *,"PROCLIST/GET_KMC_STEP/RAN_PROC",ran_proc - #@ print *,"PROCLIST/GET_KMC_STEP/RAN_site",ran_site + #@ print *,"PROCLIST/GET_NEXT_KMC_STEP/RAN_TIME",ran_time + #@ print *,"PROCLIST/GET_NEXT_KMC_STEP/RAN_PROC",ran_proc + #@ print *,"PROCLIST/GET_NEXT_KMC_STEP/RAN_site",ran_site +#@ ! print *,"PROCLIST/GET_NEXT_KMC_STEP/RAN_TIME",ran_time +#@ ! print *,"PROCLIST/GET_NEXT_KMC_STEP/RAN_PROC",ran_proc +#@ ! print *,"PROCLIST/GET_NEXT_KMC_STEP/RAN_SITE",ran_site #@ call update_accum_rate -#@ call determine_procsite(ran_proc, ran_time, proc_nr, nr_site) +#@ call determine_procsite(ran_proc, ran_site, proc_nr, nr_site) #@ if data.meta.debug > 0: #@ print *,"PROCLIST/GET_KMC_STEP/PROC_NR", proc_nr +#@ ! print *,"PROCLIST/GET_NEXT_KMC_STEP/PROC_NR",proc_nr #@ end subroutine get_next_kmc_step #@ diff --git a/kmcos/io.py b/kmcos/io.py index 817d9f87b35ff20d7c478866ce814366f3356339..ce9075d7a2bf251d05b29859855d0b3e47cf0b69 100644 --- a/kmcos/io.py +++ b/kmcos/io.py @@ -39,6 +39,10 @@ from kmcos.types import cmp_coords from kmcos.utils import evaluate_template import collections +#the clear_model function is normally not called directly from here. It is normally called by the Project class of types.py, +#which gets accessed by: +#kmc_model = kmcos.create_kmc_model(model_name) +#kmc_model.clear_model() def clear_model(model_name, backend="local_smart"): #this deletes an existing model so that a directory is ready for exporting a new model. #the model name should be a string. @@ -382,6 +386,10 @@ class ProcListWriter(): # While this looks more readable on paper, I am not sure # if this make code maintainability a lot worse. So this # should probably change. + # The integer in NR_SITE, for example it could be 657, + # is appropriate to put into model.lattice.calculate_nr2lattice(657) + # when doing debugging from the python side. + # It should not be confused withe SITE_NR in other fortran subroutines. out.write('subroutine run_proc_nr(proc, nr_site)\n\n' '!****f* proclist/run_proc_nr\n' @@ -403,9 +411,10 @@ class ProcListWriter(): for process in data.process_list: out.write(' case(%s)\n' % process.name) if data.meta.debug > 0: - out.write(('print *,"PROCLIST/RUN_PROC_NR/NAME","%s"\n' - 'print *,"PROCLIST/RUN_PROC_NR/LSITE","lsite"\n' - 'print *,"PROCLIST/RUN_PROC_NR/SITE","site"\n') + #if True: + out.write(('print *,"PROCLIST/RUN_PROC_NR/NAME ","%s"\n' + 'print *,"PROCLIST/RUN_PROC_NR/LSITE",lsite\n' + 'print *,"PROCLIST/RUN_PROC_NR/NR_SITE",nr_site\n') % process.name) for action in process.action_list: if action.coord == process.executing_coord(): diff --git a/kmcos/types.py b/kmcos/types.py index d2f18251f84fedc8c7af5bbdfedc56bf989067d2..db25d5184ca70d55d742d6c21504a68da6a37b1c 100644 --- a/kmcos/types.py +++ b/kmcos/types.py @@ -97,7 +97,7 @@ class Project(object): self.output_list = OutputList() self.filename = self.model_name + ".xml" self.backend = "local_smart" #this is just the default. - self.compile_options = "" + self.compile_options = "" #typical syntax to use this is in a __build.py file like kmc_model.compile_options = '-d' #This string later gets used in kmcos __init__, typically by kmcos.compile(kmc_model). self.error_list = [] # Quick'n'dirty define access functions diff --git a/kmcos/utils/__init__.py b/kmcos/utils/__init__.py index 4f63daec34238f80bad671842f8e80816642c8dc..2104d17181dcff5baad4c45b0641efa7af64326e 100644 --- a/kmcos/utils/__init__.py +++ b/kmcos/utils/__init__.py @@ -381,7 +381,7 @@ def build(options): extra_flags = {} if options.no_optimize: - extra_flags['gfortran'] = ('-ffree-line-length-none -ffree-form' + extra_flags['gfortran'] = ('-ffree-line-length-none -ffree-form' #-ffixed-line-length-none is not used as it seems to be not needed as of Nov 20th, 2022 ' -xf95-cpp-input -Wall -fimplicit-none' ' -time -fmax-identifier-length=63 ') extra_flags['gnu95'] = extra_flags['gfortran'] @@ -389,7 +389,7 @@ def build(options): extra_flags['intelem'] = '-fpp -Wall' else: - extra_flags['gfortran'] = ('-ffree-line-length-none -ffree-form' + extra_flags['gfortran'] = ('-ffree-line-length-none -ffree-form' #-ffixed-line-length-none is not used as it seems to be not needed as of Nov 20th, 2022 ' -xf95-cpp-input -Wall -O3 -fimplicit-none' ' -time -fmax-identifier-length=63 ') extra_flags['gnu95'] = extra_flags['gfortran']