def evaluate(self, test_structures, test_energies, test_forces, test_stresses=None, include_stress=False): """ Evaluate energies, forces and stresses of structures with trained machinea learning potentials. Args: test_structures ([Structure]): List of Pymatgen Structure Objects. test_energies ([float]): List of DFT-calculated total energies of each structure in structures list. test_forces ([np.array]): List of DFT-calculated (m, 3) forces of each structure with m atoms in structures list. m can be varied with each single structure case. test_stresses (list): List of DFT-calculated (6, ) viriral stresses of each structure in structures list. include_stress (bool): Whether to include stress components. """ test_structures, test_forces, test_stresses = check_structures_forces_stresses( test_structures, test_forces, test_stresses) predict_pool = pool_from(test_structures, test_energies, test_forces, test_stresses) _, df_orig = convert_docs(predict_pool, include_stress=include_stress) _, df_predict = convert_docs(pool_from(test_structures), include_stress=include_stress) outputs = self.model.predict_objs(objs=test_structures) df_predict["y_orig"] = df_predict["n"] * outputs return df_orig, df_predict
def train(self, train_structures, train_energies, train_forces, train_stresses=None, include_stress=False, **kwargs): """ Training data with models. Args: train_structures ([Structure]): The list of Pymatgen Structure object. energies ([float]): The list of total energies of each structure in structures list. train_energies ([float]): List of total energies of each structure in structures list. train_forces ([np.array]): List of (m, 3) forces array of each structure with m atoms in structures list. m can be varied with each single structure case. train_stresses (list): List of (6, ) virial stresses of each structure in structures list. include_stress (bool): Whether to include stress components. """ train_structures, train_forces, train_stresses = check_structures_forces_stresses( train_structures, train_forces, train_stresses) train_pool = pool_from(train_structures, train_energies, train_forces, train_stresses) _, df = convert_docs(train_pool, include_stress=include_stress) ytrain = df["y_orig"] / df["n"] xtrain = self.model.describer.transform(train_structures) self.model.fit(features=xtrain, targets=ytrain, **kwargs)
def evaluate(self, test_structures, test_energies, test_forces, test_stresses=None, predict_energies=True, predict_forces=True, predict_stress=False): """ Evaluate energies, forces and stresses of structures with trained interatomic potentials. Args: test_structures ([Structure]): List of Pymatgen Structure Objects. test_energies ([float]): List of DFT-calculated total energies of each structure in structures list. test_forces ([np.array]): List of DFT-calculated (m, 3) forces of each structure with m atoms in structures list. m can be varied with each single structure case. test_stresses (list): List of DFT-calculated (6, ) viriral stresses of each structure in structures list. predict_energies (bool): Whether to predict energies of configurations. predict_forces (bool): Whether to predict forces of configurations. predict_stress (bool): Whether to predict virial stress of configurations. """ test_structures, test_forces, test_stresses = \ check_structures_forces_stresses(test_structures, test_forces, test_stresses) if not which('quip'): raise RuntimeError( "quip has not been found.\n", "Please refer to https://github.com/libAtoms/QUIP for ", "further detail.") xml_file = 'predict.xml' original_file = 'original.xyz' predict_file = 'predict.xyz' predict_pool = pool_from(test_structures, test_energies, test_forces, test_stresses) with ScratchDir('.'): _ = self.write_param(xml_file) original_file = self.write_cfgs(original_file, cfg_pool=predict_pool) _, df_orig = self.read_cfgs(original_file) exe_command = ["quip"] exe_command.append("atoms_filename={}".format(original_file)) exe_command.append("param_filename={}".format(xml_file)) if predict_energies: exe_command.append("energy=T") if predict_forces: exe_command.append("forces=T") if predict_stress: exe_command.append("virial=T") p = subprocess.Popen(exe_command, stdout=open(predict_file, 'w')) p.communicate()[0] _, df_predict = self.read_cfgs(predict_file, predict=True) return df_orig, df_predict
def train(self, train_structures, train_energies, train_forces, train_stresses=None, default_sigma=[0.0005, 0.1, 0.05, 0.01], use_energies=True, use_forces=True, use_stress=False, **kwargs): """ Training data with gaussian process regression. Args: train_structures ([Structure]): The list of Pymatgen Structure object. energies ([float]): The list of total energies of each structure in structures list. train_energies ([float]): List of total energies of each structure in structures list. train_forces ([np.array]): List of (m, 3) forces array of each structure with m atoms in structures list. m can be varied with each single structure case. train_stresses (list): List of (6, ) virial stresses of each structure in structures list. default_sigma (list): Error criteria in energies, forces, stress and hessian. Should have 4 numbers. use_energies (bool): Whether to use dft total energies for training. Default to True. use_forces (bool): Whether to use dft atomic forces for training. Default to True. use_stress (bool): Whether to use dft virial stress for training. Default to False. kwargs: l_max (int): Parameter to configure GAP. The band limit of spherical harmonics basis function. Default to 12. n_max (int): Parameter to configure GAP. The number of radial basis function. Default to 10. atom_sigma (float): Parameter to configure GAP. The width of gaussian atomic density. Default to 0.5. zeta (float): Present when covariance function type is do product. Default to 4. cutoff (float): Parameter to configure GAP. The cutoff radius. Default to 4.0. cutoff_transition_width (float): Parameter to configure GAP. The transition width of cutoff radial. Default to 0.5. delta (float): Parameter to configure Sparsification. The signal variance of noise. Default to 1. f0 (float): Parameter to configure Sparsification. The signal mean of noise. Default to 0.0. n_sparse (int): Parameter to configure Sparsification. Number of sparse points. covariance_type (str): Parameter to configure Sparsification. The type of convariance function. Default to dot_product. sparse_method (str): Method to perform clustering in sparsification. Default to 'cur_points'. sparse_jitter (float): Intrisic error of atomic/bond energy, used to regularise the sparse covariance matrix. Default to 1e-8. e0 (float): Atomic energy value to be subtracted from energies before fitting. Default to 0.0. e0_offset (float): Offset of baseline. If zero, the offset is the average atomic energy of the input data or the e0 specified manually. Default to 0.0. """ if not which('gap_fit'): raise RuntimeError( "gap_fit has not been found.\n", "Please refer to https://github.com/libAtoms/QUIP for ", "further detail.") train_structures, train_forces, train_stresses = \ check_structures_forces_stresses(train_structures, train_forces, train_stresses) gap_sorted_elements = [] for struct in train_structures: for specie in struct.species: if str(specie) not in gap_sorted_elements: gap_sorted_elements.append(str(specie)) self.elements = sorted(gap_sorted_elements, key=lambda x: Element(x)) atoms_filename = 'train.xyz' xml_filename = 'train.xml' train_pool = pool_from(train_structures, train_energies, train_forces, train_stresses) exe_command = ["gap_fit"] exe_command.append('at_file={}'.format(atoms_filename)) gap_configure_params = [ 'l_max', 'n_max', 'atom_sigma', 'zeta', 'cutoff', 'cutoff_transition_width', 'delta', 'f0', 'n_sparse', 'covariance_type', 'sparse_method' ] preprocess_params = ['sparse_jitter', 'e0', 'e0_offset'] if len(default_sigma) != 4: raise ValueError( "The default sigma is supposed to have 4 numbers.") gap_command = ['soap'] for param_name in gap_configure_params: param = kwargs.get(param_name) if kwargs.get(param_name) \ else soap_params.get(param_name) gap_command.append(param_name + '=' + '{}'.format(param)) gap_command.append('add_species=T') exe_command.append("gap=" + "{" + "{}".format(' '.join(gap_command)) + "}") for param_name in preprocess_params: param = kwargs.get(param_name) if kwargs.get(param_name) \ else soap_params.get(param_name) exe_command.append(param_name + '=' + '{}'.format(param)) default_sigma = [str(f) for f in default_sigma] exe_command.append("default_sigma={%s}" % (' '.join(default_sigma))) if use_energies: exe_command.append('energy_parameter_name=dft_energy') if use_forces: exe_command.append('force_parameter_name=dft_force') if use_stress: exe_command.append('virial_parameter_name=dft_virial') exe_command.append('gp_file={}'.format(xml_filename)) with ScratchDir('.'): self.write_cfgs(filename=atoms_filename, cfg_pool=train_pool) p = subprocess.Popen(exe_command, stdout=subprocess.PIPE) stdout = p.communicate()[0] rc = p.returncode if rc != 0: error_msg = 'gap_fit exited with return code %d' % rc msg = stdout.decode("utf-8").split('\n')[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith('ERROR') ][0] error_msg += ', '.join(msg[error_line:]) except Exception: error_msg += msg[-1] raise RuntimeError(error_msg) def get_xml(xml_file): tree = ET.parse(xml_file) root = tree.getroot() potential_label = root.tag element_param = {} for gpcoordinates in list(root.iter('gpCoordinates')): gp_descriptor = list(gpcoordinates.iter('descriptor'))[0] gp_descriptor_text = gp_descriptor.findtext('.') Z_pattern = re.compile(' Z=(.*?) ', re.S) element = str( get_el_sp(int( Z_pattern.findall(gp_descriptor_text)[0]))) param = np.loadtxt(gpcoordinates.get('sparseX_filename')) element_param[element] = param.tolist() return tree, element_param, potential_label tree, element_param, potential_label = get_xml(xml_filename) self.param['xml'] = tree self.param['element_param'] = element_param self.param['potential_label'] = potential_label return rc
def evaluate(self, test_structures, test_energies, test_forces, test_stresses=None, **kwargs): """ Evaluate energies, forces and stresses of structures with trained interatomic potentials. Args: test_structures ([Structure]): List of Pymatgen Structure Objects. test_energies ([float]): List of DFT-calculated total energies of each structure in structures list. test_forces ([np.array]): List of DFT-calculated (m, 3) forces of each structure with m atoms in structures list. m can be varied with each single structure case. test_stresses (list): List of DFT-calculated (6, ) viriral stresses of each structure in structures list. kwargs: Parameters of write_param method. """ if not which('mlp'): raise RuntimeError( "mlp has not been found.\n", "Please refer to http://gitlab.skoltech.ru/shapeev/mlip ", "for further detail.") fitted_mtp = 'fitted.mtp' original_file = 'original.cfgs' predict_file = 'predict.cfgs' test_structures, test_forces, test_stresses = \ check_structures_forces_stresses(test_structures, test_forces, test_stresses) predict_pool = pool_from(test_structures, test_energies, test_forces, test_stresses) with ScratchDir('.'): self.write_param(fitted_mtp=fitted_mtp, Abinitio=0, Driver=1, Write_cfgs=predict_file, Database_filename=original_file, **kwargs) original_file = self.write_cfg(original_file, cfg_pool=predict_pool) _, df_orig = self.read_cfgs(original_file) p = subprocess.Popen([ 'mlp', 'run', 'mlip.ini', '--filename={}'.format(original_file) ], stdout=subprocess.PIPE) stdout = p.communicate()[0] rc = p.returncode if rc != 0: error_msg = 'mlp exited with return code %d' % rc msg = stdout.decode("utf-8").split('\n')[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith('ERROR') ][0] error_msg += ', '.join(msg[error_line:]) except Exception: error_msg += msg[-1] raise RuntimeError(error_msg) if not os.path.exists(predict_file): predict_file = '_'.join([predict_file, '0']) _, df_predict = self.read_cfgs(predict_file) return df_orig, df_predict
def train(self, train_structures, train_energies, train_forces, train_stresses=None, unfitted_mtp=None, max_dist=5, radial_basis_size=8, max_iter=500, energy_weight=1, force_weight=1e-2, stress_weight=0): """ Training data with moment tensor method. Args: train_structures ([Structure]): The list of Pymatgen Structure object. energies ([float]): The list of total energies of each structure in structures list. train_energies ([float]): List of total energies of each structure in structures list. train_forces ([np.array]): List of (m, 3) forces array of each structure with m atoms in structures list. m can be varied with each single structure case. train_stresses (list): List of (6, ) virial stresses of each structure in structures list. unfitted_mtp (str): Define the initial mtp file. Default to the mtp file stored in .params directory. max_dist (float): The actual radial cutoff. radial_basis_size (int): Relevant to number of radial basis function. max_iter (int): The number of maximum iteration. energy_weight (float): The weight of energy. force_weight (float): The weight of forces. stress_weight (float): The weight of stresses. """ if not which('mlp'): raise RuntimeError( "mlp has not been found.\n", "Please refer to http://gitlab.skoltech.ru/shapeev/mlip ", "for further detail.") train_structures, train_forces, train_stresses = \ check_structures_forces_stresses(train_structures, train_forces, train_stresses) train_pool = pool_from(train_structures, train_energies, train_forces, train_stresses) elements = sorted( set( itertools.chain( *[struct.species for struct in train_structures]))) self.elements = [str(element) for element in elements] atoms_filename = 'train.cfgs' with ScratchDir('.'): atoms_filename = self.write_cfg(filename=atoms_filename, cfg_pool=train_pool) if not unfitted_mtp: raise RuntimeError("No specific parameter file provided.") MTP_file_path = os.path.join(module_dir, 'params', unfitted_mtp) shutil.copyfile(MTP_file_path, os.path.join(os.getcwd(), unfitted_mtp)) with open('min_dist', 'w') as f: p = subprocess.Popen(['mlp', 'mindist', atoms_filename], stdout=f) stdout = p.communicate()[0] with open('min_dist') as f: lines = f.readlines() min_dist = float(lines[-1].split(':')[1]) with open(unfitted_mtp) as f: template = f.read() s = template % (len( self.elements), min_dist, max_dist, radial_basis_size) with open(unfitted_mtp, 'w') as f: f.write(s) save_fitted_mtp = '.'.join([ unfitted_mtp.split('.')[0] + '_fitted', unfitted_mtp.split('.')[1] ]) p = subprocess.Popen([ 'mlp', 'train', unfitted_mtp, atoms_filename, '--max-iter={}'.format(max_iter), '--trained-pot-name={}'.format(save_fitted_mtp), '--curr-pot-name={}'.format(unfitted_mtp), '--energy-weight={}'.format(energy_weight), '--force-weight={}'.format(force_weight), '--stress-weight={}'.format(stress_weight), '--init-params=same', '--auto-min-dist' ], stdout=subprocess.PIPE) stdout = p.communicate()[0] rc = p.returncode if rc != 0: error_msg = 'MLP exited with return code %d' % rc msg = stdout.decode("utf-8").split('\n')[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith('ERROR') ][0] error_msg += ', '.join(msg[error_line:]) except Exception: error_msg += msg[-1] raise RuntimeError(error_msg) def load_config(filename): param = OrderedDict() with open(filename, 'r') as f: lines = f.readlines() param['safe'] = [line.rstrip() for line in lines[:-2]] for line in lines[-2:]: key = line.rstrip().split(' = ')[0] value = json.loads(line.rstrip().split(' = ')[1].replace( '{', '[').replace('}', ']')) param[key] = value return param self.param = load_config(save_fitted_mtp) return rc
def evaluate(self, test_structures, test_energies, test_forces, test_stresses=None): """ Evaluate energies, forces and stresses of structures with trained interatomic potentials. Args: test_structures ([Structure]): List of Pymatgen Structure Objects. test_energies ([float]): List of DFT-calculated total energies of each structure in structures list. test_forces ([np.array]): List of DFT-calculated (m, 3) forces of each structure with m atoms in structures list. m can be varied with each single structure case. test_stresses (list): List of DFT-calculated (6, ) viriral stresses of each structure in structures list. """ if not which('nnp-predict'): raise RuntimeError("NNP Predictor has not been found.") original_file = 'input.data' predict_file = 'output.data' test_structures, test_forces, test_stresses = \ check_structures_forces_stresses(test_structures, test_forces, test_stresses) predict_pool = pool_from(test_structures, test_energies, test_forces, test_stresses) with ScratchDir('.'): _, _ = self.write_param() original_file = self.write_cfgs(original_file, cfg_pool=predict_pool) _, df_orig = self.read_cfgs(original_file) input_filename = self.write_input() dfs = [] for data in predict_pool: _ = self.write_cfgs(original_file, cfg_pool=[data]) p_evaluation = subprocess.Popen( ['nnp-predict', input_filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p_evaluation.communicate() rc = p_evaluation.returncode if rc != 0: error_msg = 'n2p2 exited with return code %d' % rc msg = stderr.decode("utf-8").split('\n')[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith('ERROR') ][0] error_msg += ', '.join(msg[error_line:]) except Exception: error_msg += ', ' error_msg += msg[-1] raise RuntimeError(error_msg) _, df = self.read_cfgs(predict_file) dfs.append(df) df_predict = pd.concat(dfs, ignore_index=True) return df_orig, df_predict
def train(self, train_structures, train_energies, train_forces, train_stresses=None, **kwargs): """ Training data with moment tensor method. Args: train_structures ([Structure]): The list of Pymatgen Structure object. energies ([float]): The list of total energies of each structure in structures list. train_energies ([float]): List of total energies of each structure in structures list. train_forces ([np.array]): List of (m, 3) forces array of each structure with m atoms in structures list. m can be varied with each single structure case. train_stresses (list): List of (6, ) virial stresses of each structure in structures list. kwargs: Parameters in write_input method. """ if not which('nnp-train'): raise RuntimeError("NNP Trainer has not been found.") train_structures, train_forces, train_stresses = \ check_structures_forces_stresses(train_structures, train_forces, train_stresses) train_pool = pool_from(train_structures, train_energies, train_forces, train_stresses) atoms_filename = 'input.data' with ScratchDir('.'): _ = self.write_cfgs(filename=atoms_filename, cfg_pool=train_pool) output = 'training_output' self.write_input(**kwargs) p_scaling = subprocess.Popen(['nnp-scaling', '100'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p_scaling.communicate() rc = p_scaling.returncode if rc != 0: error_msg = 'n2p2 exited with return code %d' % rc msg = stderr.decode("utf-8").split('\n')[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith('ERROR') ][0] error_msg += ', '.join(msg[error_line:]) except Exception: error_msg += ', ' error_msg += msg[-1] raise RuntimeError(error_msg) p_train = subprocess.Popen(['nnp-train'], stdout=open(output, 'w'), stderr=subprocess.PIPE) stdout, stderr = p_train.communicate() rc = p_train.returncode if rc != 0: error_msg = 'n2p2 exited with return code %d' % rc msg = stderr.decode("utf-8").split('\n')[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith('ERROR') ][0] error_msg += ', '.join(msg[error_line:]) except Exception: error_msg += ', ' error_msg += msg[-1] raise RuntimeError(error_msg) with zopen(output) as f: error_lines = f.read() energy_rmse_pattern = re.compile( r'ENERGY\s*\S*\s*(\S*)\s*(\S*).*?\n') forces_rmse_pattern = re.compile( r'FORCES\s*\S*\s*(\S*)\s*(\S*).*?\n') errors = np.array(energy_rmse_pattern.findall(error_lines), dtype=np.float).T.tolist() self.train_energy_rmse = errors[0] self.validation_energy_rmse = errors[1] errors = np.array(forces_rmse_pattern.findall(error_lines), dtype=np.float).T.tolist() self.train_forces_rmse = errors[0] self.validation_forces_rmse = errors[1] for specie in self.elements: weights_filename = 'weights.{}.{}.out'.format( str(Element(specie).number).zfill(3), str(self.param['epochs']).zfill(6)) self.weights[specie] = [] self.bs[specie] = [] self.weight_param[specie] = [] self.load_weights(weights_filename, specie) self.load_scaler('scaling.data') return rc
def evaluate(self, test_structures, test_energies, test_forces, test_stresses=None, **kwargs): """ Evaluate energies, forces and stresses of structures with trained interatomic potentials. Args: test_structures ([Structure]): List of Pymatgen Structure Objects. test_energies ([float]): List of DFT-calculated total energies of each structure in structures list. test_forces ([np.array]): List of DFT-calculated (m, 3) forces of each structure with m atoms in structures list. m can be varied with each single structure case. test_stresses (list): List of DFT-calculated (6, ) viriral stresses of each structure in structures list. kwargs: Parameters of write_param method. """ if not which("mlp"): raise RuntimeError( "mlp has not been found.\n", "Please refer to https://mlip.skoltech.ru ", "for further detail.", ) fitted_mtp = "fitted.mtp" original_file = "original.cfgs" predict_file = "predict.cfgs" test_structures, test_forces, test_stresses = check_structures_forces_stresses( test_structures, test_forces, test_stresses) predict_pool = pool_from(test_structures, test_energies, test_forces, test_stresses) with ScratchDir("."): self.write_param( fitted_mtp=fitted_mtp, Abinitio=0, Driver=1, Write_cfgs=predict_file, Database_filename=original_file, **kwargs, ) original_file = self.write_cfg(original_file, cfg_pool=predict_pool) _, df_orig = self.read_cfgs(original_file) if self.version == "mlip-2": p = subprocess.Popen([ "mlp", "calc-efs", fitted_mtp, original_file, predict_file ], stdout=subprocess.PIPE) elif self.version == "mlip-dev": p = subprocess.Popen([ "mlp", "run", "mlip.ini", "--filename={}".format(original_file) ], stdout=subprocess.PIPE) stdout = p.communicate()[0] rc = p.returncode if rc != 0: error_msg = "mlp exited with return code %d" % rc msg = stdout.decode("utf-8").split("\n")[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith("ERROR") ][0] error_msg += ", ".join(msg[error_line:]) except Exception: error_msg += msg[-1] raise RuntimeError(error_msg) if not os.path.exists(predict_file): predict_file = "_".join([predict_file, "0"]) _, df_predict = self.read_cfgs(predict_file) return df_orig, df_predict
def train( self, train_structures, train_energies, train_forces, train_stresses, unfitted_mtp="08g.mtp", max_dist=5, radial_basis_size=8, max_iter=500, energy_weight=1, force_weight=1e-2, stress_weight=1e-3, ): """ Training data with moment tensor method. Args: train_structures ([Structure]): The list of Pymatgen Structure object. energies ([float]): The list of total energies of each structure in structures list. train_energies ([float]): List of total energies of each structure in structures list. train_forces ([np.array]): List of (m, 3) forces array of each structure with m atoms in structures list. m can be varied with each single structure case. train_stresses (list): List of (6, ) virial stresses of each structure in structures list. unfitted_mtp (str): Define the initial mtp file. Default to the mtp file stored in .params directory. max_dist (float): The actual radial cutoff. radial_basis_size (int): Relevant to number of radial basis function. max_iter (int): The number of maximum iteration. energy_weight (float): The weight of energy. force_weight (float): The weight of forces. stress_weight (float): The weight of stresses. Zero-weight can be assigned. """ if not which("mlp"): raise RuntimeError( "mlp has not been found.\n", "Please refer to https://mlip.skoltech.ru", "for further detail.", ) train_structures, train_forces, train_stresses = check_structures_forces_stresses( train_structures, train_forces, train_stresses) train_pool = pool_from(train_structures, train_energies, train_forces, train_stresses) elements = sorted( set( itertools.chain( *[struct.species for struct in train_structures]))) self.elements = [str(element) for element in elements] atoms_filename = "train.cfgs" with ScratchDir("."): atoms_filename = self.write_cfg(filename=atoms_filename, cfg_pool=train_pool) if not unfitted_mtp: raise RuntimeError("No specific parameter file provided.") MTP_file_path = os.path.join(module_dir, "params", unfitted_mtp) shutil.copyfile(MTP_file_path, os.path.join(os.getcwd(), unfitted_mtp)) with open("min_dist", "w") as f: p = subprocess.Popen(["mlp", "mindist", atoms_filename], stdout=f) stdout = p.communicate()[0] with open("min_dist") as f: lines = f.readlines() min_dist = float(lines[-1].split(":")[1]) with open(unfitted_mtp) as f: template = f.read() s = template % (len( self.elements), min_dist, max_dist, radial_basis_size) with open(unfitted_mtp, "w") as f: f.write(s) save_fitted_mtp = ".".join([ unfitted_mtp.split(".")[0] + "_fitted", unfitted_mtp.split(".")[1] ]) p = subprocess.Popen( [ "mlp", "train", unfitted_mtp, atoms_filename, "--max-iter={}".format(max_iter), "--trained-pot-name={}".format(save_fitted_mtp), "--curr-pot-name={}".format(unfitted_mtp), "--energy-weight={}".format(energy_weight), "--force-weight={}".format(force_weight), "--stress-weight={}".format(stress_weight), "--init-params=same", ], stdout=subprocess.PIPE, ) stdout = p.communicate()[0] rc = p.returncode if rc != 0: error_msg = "MLP exited with return code %d" % rc msg = stdout.decode("utf-8").split("\n")[:-1] try: error_line = [ i for i, m in enumerate(msg) if m.startswith("ERROR") ][0] error_msg += ", ".join(msg[error_line:]) except Exception: error_msg += msg[-1] raise RuntimeError(error_msg) def load_config(filename): param = OrderedDict() with open(filename, "r") as f: lines = f.readlines() param["safe"] = [line.rstrip() for line in lines[:-2]] for line in lines[-2:]: key = line.rstrip().split(" = ")[0] value = json.loads(line.rstrip().split(" = ")[1].replace( "{", "[").replace("}", "]")) param[key] = value return param self.param = load_config(save_fitted_mtp) return rc