Esempio n. 1
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        comp = self.composition.composition.copy()
        rnd = random.random()
        natom_limit = self.max_comp_mult * self.composition.natom / self.composition.gcd
        condition = {
            'structure.nspecies': self.composition.nspecies,
            'structure.natom': {
                '$lte': natom_limit
            }
        }

        if self.pcdb_source is None or self.pcdb_source.entries.find(
                condition).count() <= len(self.source_blacklist):
            rnd = 0
        origin = None

        if self.pcdb_source is None or rnd < random_probability or self.composition.nspecies > 1:
            pcm_log.debug('Random Structure')
            factor = np.random.randint(self.min_comp_mult,
                                       self.max_comp_mult + 1)
            for i in comp:
                comp[i] *= factor
            structure = Structure.random_cell(comp,
                                              method='stretching',
                                              stabilization_number=5,
                                              nparal=5,
                                              periodic=True)
        else:
            pcm_log.debug('From source')
            while True:

                entry = None
                condition['properties.spacegroup'] = random.randint(1, 230)
                print('Trying', condition['properties.spacegroup'])
                for ientry in self.pcdb_source.entries.find(condition):
                    if ientry['_id'] not in self.source_blacklist:
                        entry = ientry
                        break
                if entry is not None:
                    origin = entry['_id']
                    structure = self.pcdb_source.get_structure(entry['_id'])
                    factor = covalent_radius(
                        self.composition.species[0]) / covalent_radius(
                            structure.species[0])
                    print('From source: %s Spacegroup: %d Scaling: %7.3f' %
                          (structure.formula,
                           entry['properties']['spacegroup'], factor))
                    structure.set_cell(
                        np.dot(factor * np.eye(3), structure.cell))
                    structure.symbols = structure.natom * self.composition.species
                    self.source_blacklist.append(entry['_id'])
                    break

        return self.new_entry(structure), origin
Esempio n. 2
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        entry_id = None
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        factor = np.random.randint(self.min_comp_mult, self.max_comp_mult + 1)
        comp = self.composition.composition.copy()
        #print("Initial composition: %s" % comp)
        #print(Composition(comp))
        #print(Composition(comp).symbols)
        for i in comp:
            comp[i] *= factor
        new_comp = Composition(comp)

        while True:
            rnd = random.random()
            condition = {
                'structure.nspecies': new_comp.nspecies,
                'structure.natom': new_comp.natom
            }
            if self.pcdb_source is None:
                rnd = 0
            elif len(self.sources[factor]) == 0:
                rnd = 0
            if self.pcdb_source is None or rnd < random_probability:
                pcm_log.debug('Random Structure')
                structure = Structure.random_cell(new_comp,
                                                  method='stretching',
                                                  stabilization_number=5,
                                                  nparal=5,
                                                  periodic=True)
                break
            else:
                pcm_log.debug('From source')
                entry_id = self.sources[factor][np.random.randint(
                    0, len(self.sources[factor]))]
                structure = self.pcdb_source.get_structure(entry_id)
                print("chosen structure from database =", structure)
                sym = CrystalSymmetry(structure)

                scale_factor = float(
                    np.max(covalent_radius(new_comp.species)) /
                    np.max(covalent_radius(structure.species)))
                reduce_scale = scale_factor**(1. / 3)  # WIH
                msg = 'Mult: %d natom: %d From source: %s Spacegroup: %d Scaling: %7.3f'
                print(msg % (factor, structure.natom, structure.formula,
                             sym.number(), scale_factor))
                # structure.set_cell(np.dot(scale_factor * np.eye(3), structure.cell)) # WIH
                structure.set_cell(
                    np.dot(reduce_scale * np.eye(3), structure.cell))  # WIH
                print("symbols before change = ", structure.symbols)
                structure.symbols = new_comp.symbols
                print("symbols after change = ", structure.symbols)
                self.sources[factor].remove(entry_id)
                break

        return self.new_entry(structure), entry_id
Esempio n. 3
0
 def replace_failed(self):
     for entry in self.entries.find({'status.relaxation': 'failed'}):
         st = self.get_structure(entry['_id'])
         comp = st.composition
         new_structure = Structure.random_cell(comp)
         self.entries.update({'_id': entry['_id']}, {'$unset': {'status.relaxation': 1,
                                                                'status.target_forces': 1,
                                                                'properties.energy': 1,
                                                                'properties.forces': 1,
                                                                'properties.stress': 1}})
         self.update(entry['_id'], structure=new_structure)
Esempio n. 4
0
 def replace_failed(self):
     for entry in self.entries.find({'status.relaxation': 'failed'}):
         st = self.get_structure(entry['_id'])
         comp = st.composition
         new_structure = Structure.random_cell(comp)
         self.entries.update({'_id': entry['_id']}, {'$unset': {'status.relaxation': 1,
                                                                'status.target_forces': 1,
                                                                'properties.energy': 1,
                                                                'properties.forces': 1,
                                                                'properties.stress': 1}})
         self.update(entry['_id'], structure=new_structure)
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        entry_id = None
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        factor = np.random.randint(self.min_comp_mult, self.max_comp_mult + 1)
        comp = self.composition.composition.copy()
        # print("Initial composition: %s" % comp)
        # print(Composition(comp))
        # print(Composition(comp).symbols)
        for i in comp:
            comp[i] *= factor
        new_comp = Composition(comp)

        while True:
            rnd = random.random()
            condition = {'structure.nspecies': new_comp.nspecies,
                         'structure.natom': new_comp.natom}
            if self.pcdb_source is None:
                rnd = 0
            elif len(self.sources[factor]) == 0:
                rnd = 0
            if self.pcdb_source is None or rnd < random_probability:
                pcm_log.debug('Random Structure')
                structure = Structure.random_cell(new_comp, method='stretching', stabilization_number=5, nparal=5,
                                                  periodic=True)
                break
            else:
                pcm_log.debug('From source')
                entry_id = self.sources[factor][np.random.randint(0, len(self.sources[factor]))]
                structure = self.pcdb_source.get_structure(entry_id)
                print("chosen structure from database =", structure)
                sym = CrystalSymmetry(structure)

                scale_factor = float(np.max(covalent_radius(new_comp.species)) /
                                     np.max(covalent_radius(structure.species)))
                reduce_scale = scale_factor ** (1. / 3)    # WIH
                msg = 'Mult: %d natom: %d From source: %s Spacegroup: %d Scaling: %7.3f'
                print(msg % (factor, structure.natom, structure.formula, sym.number(), scale_factor))
                # structure.set_cell(np.dot(scale_factor * np.eye(3), structure.cell)) # WIH
                structure.set_cell(np.dot(reduce_scale * np.eye(3), structure.cell))  # WIH
                print("symbols before change = ", structure.symbols)
                structure.symbols = new_comp.symbols
                print("symbols after change = ", structure.symbols)
                self.sources[factor].remove(entry_id)
                break

        return self.new_entry(structure), entry_id
Esempio n. 6
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        comp = self.composition.composition.copy()
        rnd = random.random()
        natom_limit = self.max_comp_mult * self.composition.natom / self.composition.gcd
        condition = {'structure.nspecies': self.composition.nspecies,
                     'structure.natom': {'$lte': natom_limit}}

        if self.pcdb_source is None or self.pcdb_source.entries.find(condition).count() <= len(self.source_blacklist):
            rnd = 0
        origin = None

        if self.pcdb_source is None or rnd < random_probability or self.composition.nspecies > 1:
            pcm_log.debug('Random Structure')
            factor = np.random.randint(self.min_comp_mult, self.max_comp_mult + 1)
            for i in comp:
                comp[i] *= factor
            structure = Structure.random_cell(comp, method='stretching', stabilization_number=5, nparal=5,
                                              periodic=True)
        else:
            pcm_log.debug('From source')
            while True:

                entry = None
                condition['properties.spacegroup'] = random.randint(1, 230)
                print('Trying', condition['properties.spacegroup'])
                for ientry in self.pcdb_source.entries.find(condition):
                    if ientry['_id'] not in self.source_blacklist:
                        entry = ientry
                        break
                if entry is not None:
                    origin = entry['_id']
                    structure = self.pcdb_source.get_structure(entry['_id'])
                    factor = covalent_radius(self.composition.species[0]) / covalent_radius(structure.species[0])
                    print('From source: %s Spacegroup: %d Scaling: %7.3f' % (structure.formula,
                                                                             entry['properties']['spacegroup'],
                                                                             factor))
                    structure.set_cell(np.dot(factor * np.eye(3), structure.cell))
                    structure.symbols = structure.natom * self.composition.species
                    self.source_blacklist.append(entry['_id'])
                    break

        return self.new_entry(structure), origin
def worker_maise(db_settings, entry_id, workdir, relaxator_params):
    """
    Relax and return evaluate the energy of the structure stored with identifier 'entry_id'
     using the MAISE code

    :param db_settings: (dict) Dictionary of DB parameters needed to create a PyChemiaDB object
    :param entry_id: MongoDB identifier of one entry of the database created from db_settings
    :param workdir: (str) Working directory where input and output from MAISE is written
    :param relaxator_params: (dict) Arguments needed to control the relaxation using MAISE
                                Arguments are store as keys and they include:
                                'target_forces' : Used to defined the tolerance to consider one candidate as relaxed.
                                'source_dir': Directory with executable maise and directory INI
    :return:
    """
    max_ncalls = 6
    pcdb = get_database(db_settings)
    target_forces = relaxator_params['target_forces']
    source_dir = relaxator_params['source_dir']

    pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' % (str(entry_id), target_forces))

    if pcdb.is_locked(entry_id):
        return
    else:
        pcdb.lock(entry_id)
    structure = pcdb.get_structure(entry_id)
    status = pcdb.get_dicts(entry_id)[2]

    if 'ncalls' in status and status['ncalls'] > 0:
        ncalls = status['ncalls'] + 1
        print('ncalls = ', status['ncalls'])
    else:
        ncalls = 1
    print('Verifing initial structure...')
    while np.min(structure.distance_matrix()+(np.eye(structure.natom)*5)) < 1.9:
        print('ERROR: Bad initial guess, two atoms are to close. Creating new random structure for id: %s' %
              str(entry_id))
        write_poscar(structure, workdir + os.sep + 'Fail_initial_POSCAR')  # WIH
        structure = Structure.random_cell(structure.composition)

    write_poscar(structure, workdir + os.sep + 'POSCAR')
    if not os.path.exists(workdir + os.sep + 'setup') and ncalls == 1:     # WIH
        print('First run.')  # WIH
        #   print('Verifying that everything runs smoothly') # WIH
        print(workdir + os.sep + 'setup')
        shutil.copy2(source_dir + os.sep + 'setup_1', workdir + os.sep + 'setup')   # WIH
    elif ncalls > 1:  # WIH
        shutil.copy2(source_dir + os.sep + 'setup_2', workdir + os.sep + 'setup')   # WIH
    if not os.path.exists(workdir + os.sep + 'INI'):
        os.symlink(source_dir + os.sep + 'INI', workdir + os.sep + 'INI')
    if not os.path.exists(workdir + os.sep + 'maise'):
        os.symlink(source_dir + os.sep + 'maise', workdir + os.sep + 'maise')

    # Get the Current Working Directory
    # cwd = os.getcwd()

    # Move to the actual directory where maise will run
    os.chdir(workdir)

    wf = open('maise.stdout', 'w')
    subprocess.call(['./maise'], stdout=wf)
    wf.close()

    if os.path.isfile('OSZICAR'):
        energies = np.loadtxt('OSZICAR')
    else:
        energies = None

    forces = None
    stress = None
    stress_kb = None
    if os.path.isfile('OUTCAR'):
        rf = open('OUTCAR', 'r')
        data = rf.read()

        pos_forces = re.findall(r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', data)
        pos_forces = np.array([x.split() for x in pos_forces], dtype=float)

        if len(pos_forces) > 0 and len(pos_forces[-1]) % 7 == 0:
            pos_forces.shape = (len(pos_forces), -1, 7)
            forces = pos_forces[:, :, 3:6]
            # positions = pos_forces[:, :, :3]
        else:
            print('Forces and Positions could not be parsed : ', pos_forces.shape)
            print('pos_forces =\n%s ' % pos_forces)

        str_stress = re.findall('Total([.\d\s-]*)in', data)
        if len(str_stress) == 2:
            stress = np.array([[float(y) for y in x.split()] for x in str_stress])
        str_stress = re.findall('in kB([.\d\s-]*)energy', data)
        if len(str_stress) == 2:
            stress_kb = np.array([[float(y) for y in x.split()] for x in str_stress])

    create_new = False
    if not os.path.isfile('CONTCAR') or os.path.getsize("CONTCAR") == 0:
        create_new = True
        print('CONTCAR not found in entry: %s' % str(entry_id))
        i = 1
        while True:
            if not os.path.isfile('POSCAR-failed-%03s' % str(i)):
                os.rename('POSCAR', 'POSCAR-failed-%03s' % str(i))
                break
            else:
                i += 1
    else:
        new_structure = read_poscar('CONTCAR')
        # min_dist = np.min(new_structure.distance_matrix+np.ones((new_structure.natom,new_structure.natom)))
    min_dist = np.min(new_structure.distance_matrix()+(np.eye(new_structure.natom)*5))   # WIH
    print('Minimal distance= %8.7f' % min_dist)   # WIH

    if min_dist < 2.0:
        print('ERROR: MAISE finished with and structure with distances too close:', entry_id)  # WIH
        write_poscar(new_structure, workdir + os.sep + 'Collapsed_CONTCAR')  # WIH
        create_new = True   # WIH

    if create_new:
        new_structure = Structure.random_cell(structure.composition)
        ncalls = 0    # WIH

    if ncalls > max_ncalls:
        print('WARNING: Too many calls to MAISE and no relaxation succeeded, replacing structure: ', entry_id)    # WIH
        new_structure = Structure.random_cell(structure.composition)
        pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': 0}})
        create_new = True
    else:
        pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': ncalls}})
    pcdb.update(entry_id, structure=new_structure, properties={})

    # if not create_new and energies is not None and forces is not None and stress is not None:
    if energies is not None and forces is not None and stress is not None:

        te = energies[1]
        pcdb.entries.update({'_id': entry_id},
                            {'$set': {'status.relaxation': 'succeed',
                                      'status.target_forces': target_forces,
                                      'properties.initial_forces': generic_serializer(forces[0]),
                                      'properties.initial_stress': generic_serializer(stress[0]),
                                      'properties.initial_stress_kB': generic_serializer(stress_kb[0]),
                                      'properties.forces': generic_serializer(forces[1]),
                                      'properties.stress': generic_serializer(stress[1]),
                                      'properties.stress_kB': generic_serializer(stress_kb[1]),
                                      'properties.energy': te,
                                      'properties.energy_pa': te / new_structure.natom,
                                      'properties.energy_pf': te / new_structure.get_composition().gcd}})

    for ifile in ['POSCAR', 'CONTCAR', 'setup', 'OUTCAR', 'maise.stdout', 'list.dat']:
        if not os.path.exists(ifile):
            wf = open(ifile, 'w')
            wf.write('')
            wf.close()
        n = 1
        while True:
            if os.path.exists(ifile + ('_%03d' % n)):
                n += 1
            else:
                break
        os.rename(ifile, ifile+('_%03d' % n))

    pcm_log.info('[%s]: Unlocking the entry' % str(entry_id))
    pcdb.unlock(entry_id)
Esempio n. 8
0
def worker_maise(db_settings, entry_id, workdir, target_forces, relaxator_params):

    max_ncalls = 6
    pcdb = get_database(db_settings)
    pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' % (str(entry_id), target_forces))

    if pcdb.is_locked(entry_id):
        return
    else:
        pcdb.lock(entry_id)
    structure = pcdb.get_structure(entry_id)
    status = pcdb.get_dicts(entry_id)[2]

    if 'ncalls' in status:
        ncalls = status['ncalls'] + 1 
    else:
        ncalls = 1 

    #print('Current directory: '+os.getcwd() )
    #print('Working directory: '+workdir)
    write_poscar(structure,workdir+os.sep+'POSCAR')
    if not os.path.exists(workdir+os.sep+'setup'):
        shutil.copy2('setup', workdir)
    if not os.path.exists(workdir+os.sep+'INI'):
        os.symlink(os.getcwd()+os.sep+'INI', workdir+os.sep+'INI')
    if not os.path.exists(workdir+os.sep+'maise'):
        os.symlink(os.getcwd()+os.sep+'maise', workdir+os.sep+'maise')
    cwd=os.getcwd()
    os.chdir(workdir)
    wf=open('maise.stdout','w')
    subprocess.call(['./maise'], stdout=wf)
    wf.close()
    if os.path.isfile('OSZICAR'):
        energies=np.loadtxt('OSZICAR')
    else:
        energies=None
    if os.path.isfile('OUTCAR'):
        rf = open('OUTCAR', 'r')
        data = rf.read()
        
        pos_forces = re.findall(r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', data)
        pos_forces = np.array([x.split() for x in pos_forces], dtype=float)

        if len(pos_forces) > 0 and len(pos_forces[-1]) % 7 == 0:
            pos_forces.shape = (len(pos_forces), -1, 7)
            forces = pos_forces[:, :, 3:6]
            positions = pos_forces[:, :, :3]
        else:
            print('Forces and Positions could not be parsed : ', pos_forces.shape)
            print('pos_forces =\n%s ' % pos_forces)
            
        str_stress=re.findall('Total([\.\d\s-]*)in',data)
        if len(str_stress)==2:
            stress = np.array([[float(y) for y in x.split()] for x in str_stress])
        str_stress=re.findall('in kB([\.\d\s-]*)energy',data)
        if len(str_stress)==2:
            stress_kB = np.array([[float(y) for y in x.split()] for x in str_stress])
    else:
        forces=None
        stress=None
        stress_kB=None

    new_structure=read_poscar('CONTCAR')
    if np.min(new_structure.distance_matrix()+np.eye(new_structure.natom))<0.23:
        print('WARNING: Structure collapse 2 atoms, creating a new random structure')
        new_structure=Structure.random_cell(new_structure.composition)
    if ncalls > max_ncalls:
        print('WARNING: Too many calls to MAISE and no relaxation succeeded, replacing structure')
        new_structure=Structure.random_cell(new_structure.composition)
        pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': 0}})
    else:
        pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': ncalls}})
    pcdb.update(entry_id, structure=new_structure)

    
    if energies is not None and forces is not None and stress is not None:

        te = energies[1]
        pcdb.entries.update({'_id': entry_id},
                            {'$set': {'status.relaxation': 'succeed',
                                      'status.target_forces': target_forces,
                                      'properties.initial_forces': generic_serializer(forces[0]),
                                      'properties.initial_stress': generic_serializer(stress[0]),
                                      'properties.initial_stress_kB': generic_serializer(stress_kB[0]),
                                      'properties.forces': generic_serializer(forces[1]),
                                      'properties.stress': generic_serializer(stress[1]),
                                      'properties.stress_kB': generic_serializer(stress_kB[1]),
                                      'properties.energy': te,
                                      'properties.energy_pa': te / new_structure.natom,
                                      'properties.energy_pf': te / new_structure.get_composition().gcd}})

    for ifile in ['POSCAR', 'CONTCAR', 'setup', 'OUTCAR', 'maise.stdout', 'list.dat']:
        if not os.path.exists(ifile):
            wf = open(ifile, 'w')
            wf.write('')
            wf.close()
        n=1
        while True:
           if os.path.exists(ifile+ ('_%03d' % n)):
               n+=1
           else:
               break
        os.rename(ifile,ifile+('_%03d' % n))


    pcm_log.info('[%s]: Unlocking the entry' % str(entry_id))
    pcdb.unlock(entry_id)
Esempio n. 9
0
def worker_maise(db_settings, entry_id, workdir, relaxator_params):
    """
    Relax and return evaluate the energy of the structure stored with identifier 'entry_id'
     using the MAISE code

    :param db_settings: (dict) Dictionary of DB parameters needed to create a PyChemiaDB object
    :param entry_id: MongoDB identifier of one entry of the database created from db_settings
    :param workdir: (str) Working directory where input and output from MAISE is written
    :param relaxator_params: (dict) Arguments needed to control the relaxation using MAISE
                                Arguments are store as keys and they include:
                                'target_forces' : Used to defined the tolerance to consider one candidate as relaxed.
                                'source_dir': Directory with executable maise and directory INI
    :return:
    """
    max_ncalls = 6
    pcdb = get_database(db_settings)
    target_forces = relaxator_params['target_forces']
    source_dir = relaxator_params['source_dir']

    pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' %
                 (str(entry_id), target_forces))

    if pcdb.is_locked(entry_id):
        return
    else:
        pcdb.lock(entry_id)
    structure = pcdb.get_structure(entry_id)
    status = pcdb.get_dicts(entry_id)[2]

    if 'ncalls' in status and status['ncalls'] > 0:
        ncalls = status['ncalls'] + 1
        print('ncalls = ', status['ncalls'])
    else:
        ncalls = 1
    print('Verifing initial structure...')
    while np.min(structure.distance_matrix() +
                 (np.eye(structure.natom) * 5)) < 1.9:
        print(
            'ERROR: Bad initial guess, two atoms are to close. Creating new random structure for id: %s'
            % str(entry_id))
        write_poscar(structure,
                     workdir + os.sep + 'Fail_initial_POSCAR')  # WIH
        structure = Structure.random_cell(structure.composition)

    write_poscar(structure, workdir + os.sep + 'POSCAR')
    if not os.path.exists(workdir + os.sep + 'setup') and ncalls == 1:  # WIH
        print('First run.')  # WIH
        #   print('Verifying that everything runs smoothly') # WIH
        print(workdir + os.sep + 'setup')
        shutil.copy2(source_dir + os.sep + 'setup_1',
                     workdir + os.sep + 'setup')  # WIH
    elif ncalls > 1:  # WIH
        shutil.copy2(source_dir + os.sep + 'setup_2',
                     workdir + os.sep + 'setup')  # WIH
    if not os.path.exists(workdir + os.sep + 'INI'):
        os.symlink(source_dir + os.sep + 'INI', workdir + os.sep + 'INI')
    if not os.path.exists(workdir + os.sep + 'maise'):
        os.symlink(source_dir + os.sep + 'maise', workdir + os.sep + 'maise')

    # Get the Current Working Directory
    # cwd = os.getcwd()

    # Move to the actual directory where maise will run
    os.chdir(workdir)

    wf = open('maise.stdout', 'w')
    subprocess.call(['./maise'], stdout=wf)
    wf.close()

    if os.path.isfile('OSZICAR'):
        energies = np.loadtxt('OSZICAR')
    else:
        energies = None

    forces = None
    stress = None
    stress_kb = None
    if os.path.isfile('OUTCAR'):
        rf = open('OUTCAR', 'r')
        data = rf.read()

        pos_forces = re.findall(
            r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', data)
        pos_forces = np.array([x.split() for x in pos_forces], dtype=float)

        if len(pos_forces) > 0 and len(pos_forces[-1]) % 7 == 0:
            pos_forces.shape = (len(pos_forces), -1, 7)
            forces = pos_forces[:, :, 3:6]
            # positions = pos_forces[:, :, :3]
        else:
            print('Forces and Positions could not be parsed : ',
                  pos_forces.shape)
            print('pos_forces =\n%s ' % pos_forces)

        str_stress = re.findall('Total([.\d\s-]*)in', data)
        if len(str_stress) == 2:
            stress = np.array([[float(y) for y in x.split()]
                               for x in str_stress])
        str_stress = re.findall('in kB([.\d\s-]*)energy', data)
        if len(str_stress) == 2:
            stress_kb = np.array([[float(y) for y in x.split()]
                                  for x in str_stress])

    create_new = False
    if not os.path.isfile('CONTCAR') or os.path.getsize("CONTCAR") == 0:
        create_new = True
        print('CONTCAR not found in entry: %s' % str(entry_id))
        i = 1
        while True:
            if not os.path.isfile('POSCAR-failed-%03s' % str(i)):
                os.rename('POSCAR', 'POSCAR-failed-%03s' % str(i))
                break
            else:
                i += 1
    else:
        new_structure = read_poscar('CONTCAR')
        # min_dist = np.min(new_structure.distance_matrix+np.ones((new_structure.natom,new_structure.natom)))
    min_dist = np.min(new_structure.distance_matrix() +
                      (np.eye(new_structure.natom) * 5))  # WIH
    print('Minimal distance= %8.7f' % min_dist)  # WIH

    if min_dist < 2.0:
        print(
            'ERROR: MAISE finished with and structure with distances too close:',
            entry_id)  # WIH
        write_poscar(new_structure,
                     workdir + os.sep + 'Collapsed_CONTCAR')  # WIH
        create_new = True  # WIH

    if create_new:
        new_structure = Structure.random_cell(structure.composition)
        ncalls = 0  # WIH

    if ncalls > max_ncalls:
        print(
            'WARNING: Too many calls to MAISE and no relaxation succeeded, replacing structure: ',
            entry_id)  # WIH
        new_structure = Structure.random_cell(structure.composition)
        pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': 0}})
        create_new = True
    else:
        pcdb.entries.update({'_id': entry_id},
                            {'$set': {
                                'status.ncalls': ncalls
                            }})
    pcdb.update(entry_id, structure=new_structure, properties={})

    # if not create_new and energies is not None and forces is not None and stress is not None:
    if energies is not None and forces is not None and stress is not None:

        te = energies[1]
        pcdb.entries.update({'_id': entry_id}, {
            '$set': {
                'status.relaxation': 'succeed',
                'status.target_forces': target_forces,
                'properties.initial_forces': generic_serializer(forces[0]),
                'properties.initial_stress': generic_serializer(stress[0]),
                'properties.initial_stress_kB': generic_serializer(
                    stress_kb[0]),
                'properties.forces': generic_serializer(forces[1]),
                'properties.stress': generic_serializer(stress[1]),
                'properties.stress_kB': generic_serializer(stress_kb[1]),
                'properties.energy': te,
                'properties.energy_pa': te / new_structure.natom,
                'properties.energy_pf':
                te / new_structure.get_composition().gcd
            }
        })

    for ifile in [
            'POSCAR', 'CONTCAR', 'setup', 'OUTCAR', 'maise.stdout', 'list.dat'
    ]:
        if not os.path.exists(ifile):
            wf = open(ifile, 'w')
            wf.write('')
            wf.close()
        n = 1
        while True:
            if os.path.exists(ifile + ('_%03d' % n)):
                n += 1
            else:
                break
        os.rename(ifile, ifile + ('_%03d' % n))

    pcm_log.info('[%s]: Unlocking the entry' % str(entry_id))
    pcdb.unlock(entry_id)