def prepare_for_submission(self, folder): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ code = self.inputs.code # an aiida Code parameters = self.inputs.parameters # an aiida Dict input_dict = parameters.get_dict() # a python dict if 'x1' not in input_dict or 'x2' not in input_dict: raise InputValidationError( 'The input parameters node should contain both keys "x1" and "x2", ' 'but it doesn\'t.') ############################## # END OF INITIAL INPUT CHECK # ############################## input_filename = self.inputs.metadata.options.input_filename output_filename = self.inputs.metadata.options.output_filename # write all the input to a file with folder.open(input_filename, 'w') as infile: json.dump(input_dict, infile) # ============================ calcinfo ================================ calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [output_filename] calcinfo.retrieve_temporary_list = [[ 'path/hugefiles*[0-9].xml', '.', '1' ]] codeinfo = CodeInfo() codeinfo.cmdline_params = [input_filename, output_filename] codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
def prepare_for_submission(self, folder): """ The baseclass will only setup the basic calcinfo arguments but will not write **any** files which has to be implemented in the subclassed prepare_for_submission() method """ # if no custodian code is defined directly run the VASP calculation, # i.e. initialize the CodeInfo for the passed VASP code if not self.inputs.custodian.get('code', False): codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdout_name = self._default_output_file codeinfo.stderr_name = self._default_error_file # otherwise wrap in Custodian calculation and initialize CodeInfo for # the passed Custodian code (This is sufficient as AiiDA will scan all # Code-inputs to generate the required prepend / append lines) else: codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.custodian.code.uuid # define custodian-exe command line arguments codeinfo.cmdline_params = ['run', PluginDefaults.CSTDN_SPEC_FNAME] # never add the MPI command to custodian since it will call # VASP using MPI itself codeinfo.withmpi = False calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [codeinfo] # those list are set defined in the inherited classes calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.remote_symlink_list = [] # retrieve lists are defined on the base class calcinfo.retrieve_temporary_list = self.retrieve_temporary_list() calcinfo.retrieve_list = self.retrieve_permanent_list() # need to set run mode since presubmit() takes all code inputs into # account and would complain if both vasp and custodian codes are set calcinfo.codes_run_mode = CodeRunMode.SERIAL # finally write the neccessary calculation inputs to the calculation's # input folder calcinfo = self.create_calculation_inputs(folder, calcinfo) return calcinfo
def prepare_for_submission(self, tempfolder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param tempfolder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.CalcInfo` instance """ # assert that the potential and structure have the same kind elements if self.inputs.potential.allowed_element_names is not None and not set( k.symbol for k in self.inputs.structure.kinds ).issubset(self.inputs.potential.allowed_element_names): raise ValidationError( "the structure and potential are not compatible (different kind elements)" ) # Setup structure structure_txt, struct_transform = generate_lammps_structure( self.inputs.structure, self.inputs.potential.atom_style ) with open( tempfolder.get_abs_path(self.options.cell_transform_filename), "w+b" ) as handle: np.save(handle, struct_transform) if "parameters" in self.inputs: parameters = self.inputs.parameters else: parameters = Dict() # Setup input parameters input_txt = self.create_main_input_content( parameter_data=parameters, potential_data=self.inputs.potential, kind_symbols=[kind.symbol for kind in self.inputs.structure.kinds], structure_filename=self._INPUT_STRUCTURE, trajectory_filename=self.options.trajectory_suffix, system_filename=self.options.system_suffix, restart_filename=self.options.restart_filename, ) input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, "w") as infile: infile.write(input_txt) self.validate_parameters(parameters, self.inputs.potential) retrieve_list, retrieve_temporary_list = self.get_retrieve_lists() retrieve_list.extend( [self.options.output_filename, self.options.cell_transform_filename] ) # prepare extra files if needed self.prepare_extra_files(tempfolder, self.inputs.potential) # =========================== dump to file ============================= structure_filename = tempfolder.get_abs_path(self._INPUT_STRUCTURE) with open(structure_filename, "w") as infile: infile.write(structure_txt) for name, content in self.inputs.potential.get_external_files().items(): fpath = tempfolder.get_abs_path(name) with open(fpath, "w") as infile: infile.write(content) # ============================ calcinfo ================================ codeinfo = CodeInfo() codeinfo.cmdline_params = list(self._cmdline_params) codeinfo.code_uuid = self.inputs.code.uuid codeinfo.withmpi = self.metadata.options.withmpi codeinfo.stdout_name = self._stdout_name calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.retrieve_list = retrieve_list calcinfo.retrieve_temporary_list = retrieve_temporary_list calcinfo.codes_info = [codeinfo] return calcinfo
def prepare_for_submission(self, tempfolder): # Setup template with open(self.inputs.template, 'r') as tempfile: temp_contents = tempfile.read() lmp_template = Template(temp_contents) # # check variables # for variable in self.inputs.variables.values(): # if not isinstance(variable, list): # raise TypeError('Values in variables must be list') # check kinds if 'kinds' in self.inputs: kind_var = { kind: kind_index + 1 for kind_index, kind in enumerate(self.inputs.kinds) } lmp_template = Template(lmp_template.safe_substitute(**kind_var)) for i, case in enumerate(self.inputs.cases): structure = case.pop('structure') if isinstance(structure, StructureData): structure_txt, struct_transform = generate_lammps_structure( structure, kinds=self.inputs.kinds) elif isinstance(structure, SinglefileData): structure_txt = structure.get_content() else: raise TypeError( 'Input structure must be StructureData or SinglefileData') input_txt = lmp_template.safe_substitute(**case) # ========================= dump to file =========================== tempfolder.get_subfolder(i, create=True) input_filename = tempfolder.get_abs_path( f'{i}/{self._INPUT_FILE_NAME}') with open(input_filename, 'w') as infile: infile.write(input_txt) structure_filename = tempfolder.get_abs_path( f'{i}/{self._INPUT_STRUCTURE}') with open(structure_filename, 'w') as infile: infile.write(structure_txt) case_filename = tempfolder.get_abs_path(f'{i}/case.json') case.update({'structure pk': structure.pk}) with open(case_filename, 'w') as infile: json.dump(case, infile, sort_keys=True, indent=2) # ============================ calcinfo ================================ settings = self.inputs.settings.get_dict() \ if 'settings' in self.inputs else {} codeinfo = CodeInfo() codeinfo.cmdline_params = self._cmdline_params codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdout_name = self._stdout_name codeinfo.join_files = True calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.prepend_text = (f'for i in $(seq 0 {i})\n' 'do\n' 'cd "${i}" || exit') calcinfo.append_text = ('cd ..\n' 'done') calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._stdout_name calcinfo.retrieve_list = self._retrieve_list + [ self.options.output_filename ] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) calcinfo.retrieve_temporary_list = self._retrieve_temporary_list calcinfo.codes_info = [codeinfo] # =========================== local_copy_list ========================== if 'file' in self.inputs: calcinfo.local_copy_list = [] for name, obj in self.inputs.file.items(): calcinfo.local_copy_list.append( (obj.uuid, obj.filename, f'{name}.pb')) return calcinfo
def prepare_for_submission(self, tempfolder): # Setup structure if isinstance(self.inputs.structure, StructureData): structure_txt, struct_transform = generate_lammps_structure( self.inputs.structure, kinds=self.inputs.kinds) elif isinstance(self.inputs.structure, SinglefileData): structure_txt = self.inputs.structure.get_content() else: raise TypeError( 'Input structure must be StructureData or SinglefileData') with open(self.inputs.template, 'r') as tempfile: temp_contents = tempfile.read() init_temp = Template(temp_contents) input_txt = init_temp.safe_substitute(**self.inputs.variables) if 'kinds' in self.inputs: kind_temp = Template(input_txt) kind_var = { kind: kind_index + 1 for kind_index, kind in enumerate(self.inputs.kinds) } input_txt = kind_temp.safe_substitute(**kind_var) # =========================== dump to file ============================= input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: infile.write(input_txt) structure_filename = tempfolder.get_abs_path(self._INPUT_STRUCTURE) with open(structure_filename, 'w') as infile: infile.write(structure_txt) # ============================ calcinfo ================================ settings = self.inputs.settings.get_dict() \ if 'settings' in self.inputs else {} codeinfo = CodeInfo() codeinfo.cmdline_params = self._cmdline_params codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdout_name = self._stdout_name codeinfo.join_files = True calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._stdout_name calcinfo.retrieve_list = self._retrieve_list + [ self.options.output_filename ] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) calcinfo.retrieve_temporary_list = self._retrieve_temporary_list calcinfo.codes_info = [codeinfo] # =========================== local_copy_list ========================== if 'file' in self.inputs: calcinfo.local_copy_list = [] for name, obj in self.inputs.file.items(): calcinfo.local_copy_list.append( (obj.uuid, obj.filename, f'{name}.pb')) return calcinfo
def prepare_for_submission(self, folder): # create calculation info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [] calcinfo.retrieve_list = [] calcinfo.retrieve_temporary_list = [] calcinfo.prepend_text = "export GAUSS_MEMDEF=%dMB\n" % self.inputs.gauss_memdef calcinfo.local_copy_list = [] if "stencil" in self.inputs: calcinfo.local_copy_list.append( (self.inputs.stencil.uuid, self.inputs.stencil.filename, 'stencil.txt')) for key, params in self.inputs.parameters.get_dict().items(): cube_name = key + ".cube" kind_str = params["kind"] npts = params["npts"] # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.cmdline_params.append( str(self.inputs.metadata.options.resources['tot_num_mpiprocs']) ) codeinfo.cmdline_params.append(kind_str) codeinfo.cmdline_params.append(self.PARENT_FOLDER_NAME + "/" + self.DEFAULT_INPUT_FILE) codeinfo.cmdline_params.append(cube_name) if npts == -1: if 'stencil' not in self.inputs: self.report( "Warning: npts: -1 set but no stencil provided, using -2" ) codeinfo.cmdline_params.append("-2") else: codeinfo.cmdline_params.append(str(npts)) codeinfo.stdin_name = "stencil.txt" else: codeinfo.cmdline_params.append(str(npts)) codeinfo.code_uuid = self.inputs.code.uuid codeinfo.withmpi = self.inputs.metadata.options.withmpi calcinfo.codes_info.append(codeinfo) if self.inputs.retrieve_cubes.value: calcinfo.retrieve_list.append(cube_name) else: calcinfo.retrieve_temporary_list.append(cube_name) # symlink or copy to parent calculation calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self.PARENT_FOLDER_NAME) if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): """ Routine to be called when create the input files and other stuff :param folder: a aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: a dictionary with the input nodes, as they would be returned by get_inputs_dict (without the Code!) """ self.prepare_inputs() local_copy_list = [] remote_copy_list = [] remote_symlink_list = [] require_parent = False for k in self.param_dict: if str(k).lower() in ["reuse", "continuation"]: require_parent = True break parent_calc_folder = self.inputs.get('parent_calc_folder') if parent_calc_folder is None and require_parent: raise InputValidationError( "No parent calculation folder passed" " for restart calculation using reuse/continuation") ############################## # END OF INITIAL INPUT CHECK # ############################## # Generate input file self.prepare_inputs(reset=True) if self._write_headers is True: cell_nodes = [] for name, inp in self.inputs.items(): if name in self._cell_links and inp: cell_nodes.append([name, inp]) # process pseudos for name, pseudo in self.inputs.pseudos.items(): cell_nodes.append(['pseudo__{}'.format(name), pseudo]) self.cell_file.header = self._generate_header_lines(cell_nodes) param_nodes = [] for name, inp in self.inputs.items(): if name in self._param_links and inp: param_nodes.append([name, inp]) self.param_file.header = self._generate_header_lines(param_nodes) local_copy_list.extend(self.local_copy_list_to_append) seedname = self.inputs.metadata.options.seedname cell_fn = seedname + ".cell" param_fn = seedname + ".param" with folder.open(cell_fn, mode='w') as incell: incell.write(self.cell_file.get_string()) with folder.open(param_fn, mode="w") as inparam: inparam.write(self.param_file.get_string()) # IMPLEMENT OPERATIONS FOR RESTART symlink = self.inputs.metadata.options.symlink_usage parent_calc_folder = self.inputs.get('parent_calc_folder', None) if parent_calc_folder: comp_uuid = parent_calc_folder.computer.uuid remote_path = parent_calc_folder.get_remote_path() if symlink: remote_list = remote_symlink_list else: remote_list = remote_copy_list remote_list.append( (comp_uuid, remote_path, self.inputs.metadata.options.parent_folder_name)) calcinfo = CalcInfo() calcinfo.uuid = self.uuid # COPY/SYMLINK LISTS calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.remote_symlink_list = remote_symlink_list # SET UP extra CMDLINE arguments cmdline_params = self.settings_dict.pop("CMDLINE", []) # Extra parameters are added after the seed for CASTEP calcinfo.cmdline_params = [seedname] + list(cmdline_params) # CASTEP don't have any STDOUT etc when running calculations # Error is shown in the *.err file # Construct codeinfo instance codeinfo = CodeInfo() codeinfo.cmdline_params = [seedname] + list(cmdline_params) codeinfo.code_uuid = self.inputs.code.uuid calcinfo.codes_info = [codeinfo] # Retrieve by default the .castep file and the bands file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(seedname + ".castep") calcinfo.retrieve_list.append(seedname + ".bands") settings_retrieve_list = self.settings_dict.pop( "ADDITIONAL_RETRIEVE_LIST", []) calcinfo.retrieve_list.extend(settings_retrieve_list) calcinfo.retrieve_temporary_list = [] calcinfo.retrieve_temporary_list.extend( self.settings_dict.pop("ADDITIONAL_RETRIEVE_TEMPORARY_LIST", [])) calculation_mode = self.param_file.get("task", "singlepoint") # If we are doing geometryoptimisation retrieved the geom file and -out.cell file # dictionary for task specific file retrieve task_extra = self.retrieve_dict.get(calculation_mode.lower(), []) for suffix in task_extra: settings_retrieve_list.append(seedname + suffix) # Retrieve output cell file if requested if self.param_file.get("write_cell_structure"): settings_retrieve_list.append(seedname + "-out.cell") calcinfo.retrieve_list += settings_retrieve_list calcinfo.retrieve_list += self._default_retrieve_list # Remove parser options in the setting dictionary # At the moment parser options are not used here if self.settings_dict: raise InputValidationError( "The following keys have been found in " "the settings input node, but were not understood: {}".format( ",".join(list(self.settings_dict.keys())))) return calcinfo
def prepare_for_submission(self, tempfolder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param tempfolder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.CalcInfo` instance """ # assert that the potential and structure have the same kind elements if [k.symbol for k in self.inputs.structure.kinds] != self.inputs.potential.kind_elements: raise ValidationError("the structure and potential are not compatible (different kind elements)") # Setup potential potential_txt = self.inputs.potential.get_potential_file() # Setup structure structure_txt, struct_transform = generate_lammps_structure( self.inputs.structure, self.inputs.potential.atom_style) with open(tempfolder.get_abs_path(self.options.cell_transform_filename), 'w+b') as handle: np.save(handle, struct_transform) if "parameters" in self.inputs: parameters = self.inputs.parameters else: parameters = Dict() pdict = parameters.get_dict() # Check lammps version date in parameters lammps_date = convert_date_string( pdict.get("lammps_version", '11 Aug 2017')) # Setup input parameters input_txt = self._generate_input_function( parameters=parameters, potential_obj=self.inputs.potential, structure_filename=self._INPUT_STRUCTURE, trajectory_filename=self.options.trajectory_name, info_filename=self.options.info_filename, restart_filename=self.options.restart_filename, add_thermo_keywords=pdict.get("thermo_keywords", []), version_date=lammps_date) input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: infile.write(input_txt) self.validate_parameters(parameters, self.inputs.potential) # prepare extra files if needed self.prepare_extra_files(tempfolder, self.inputs.potential) # =========================== dump to file ============================= structure_filename = tempfolder.get_abs_path(self._INPUT_STRUCTURE) with open(structure_filename, 'w') as infile: infile.write(structure_txt) if potential_txt is not None: potential_filename = tempfolder.get_abs_path( self.inputs.potential.potential_filename) with open(potential_filename, 'w') as infile: infile.write(potential_txt) # ============================ calcinfo ================================ codeinfo = CodeInfo() codeinfo.cmdline_params = self._cmdline_params codeinfo.code_uuid = self.inputs.code.uuid codeinfo.withmpi = False # Set lammps openmpi environment properly codeinfo.stdout_name = self._stdout_name calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.retrieve_list = self._retrieve_list + [ self.options.output_filename, self.options.cell_transform_filename] calcinfo.retrieve_temporary_list = self._retrieve_temporary_list calcinfo.codes_info = [codeinfo] return calcinfo