def library_sizes(): result = session.query(Material.run_id, func.count(Material.id)).group_by(Material.run_id) print("\nrun-id\t\t\t\t|\tlibrary size") print("{}+{}".format("-" * 32, "-" * 32)) for row in result: print("{}\t|\t{}".format(row[0], row[1]))
def last_generation(run_id): """Finds latest generation present in database. Args: run_id (str): identification string for run. Returns: Last generation(int) to be included in database. """ return session.query(func.max(Material.generation)).filter( Material.run_id == run_id, )[0][0]
def mutate(run_id, generation, parent): """Query mutation_strength for bin and adjust as necessary. Args: run_id (str): identification string for run. generation (int): iteration in bin-mutate-simulate routine. parent (sqlalchemy.orm.query.Query): parent-material corresponding to the bin being queried. Returns: mutation_strength.strength (float): mutation strength to be used for parents in the bin being queried. If the fraction of children from previous generation which populate the SAME bin as their parent is LESS THAN 10% then the mutation strength is REDUCED BY HALF. If the fraction of these children populating the SAME bin as their parent is GREATER THAN 50% then the mutation strength is INCREASED BY 200%. """ mutation_strength_key = [run_id, generation] + parent.bin mutation_strength = session.query(MutationStrength).get( mutation_strength_key) if mutation_strength: print( "Mutation strength already calculated for this bin and generation." ) else: print("Calculating mutation strength...") mutation_strength = MutationStrength.get_prior( *mutation_strength_key).clone() mutation_strength.generation = generation try: fraction_in_parent_bin = parent.calculate_percent_children_in_bin() if fraction_in_parent_bin < 0.1: mutation_strength.strength *= 0.5 elif fraction_in_parent_bin > 0.5 and mutation_strength.strength <= 0.5: mutation_strength.strength *= 2 except ZeroDivisionError: print("No prior generation materials in this bin with children.") try: session.add(mutation_strength) session.commit() except (FlushError, sqlalchemy.exc.IntegrityError) as e: print( "Somebody beat us to saving a row with this generation. That's ok!" ) session.rollback() # it's ok b/c this calculation should always yield the exact same result! sys.stdout.flush() return mutation_strength.strength
def materials_in_generation(run_id, generation): """Count number of materials in a generation. Args: run_id (str): identification string for run. generation (int): iteration in overall bin-mutate-simulate rountine. Returns: Number(int) of materials in a particular generation that are present in the database (the final step in bin-mutate-simulate routine). """ return session.query(Material).filter( Material.run_id == run_id, Material.generation == generation).count()
def calculate_generation_index(self): """Determine material's generation-index. Args: self (class): row in material table. Returns: The generation-index is used to count the number of materials present in the database (that is to have all definition-files in the RASPA library and simulation data in the materials datatable). This attribute is used to determine when to stop adding new materials to one generation and start another. """ return session.query(Material).filter( Material.run_id == self.run_id, Material.generation == self.generation, Material.id < self.id, ).count()
def get_prior(cls, run_id, generation, gas_adsorption_bin, surface_area_bin, void_fraction_bin): """ Looks for the most recent mutation_strength row. If a row doesn't exist for this bin, the default value is used from the configuration file. Args: cls (classmethod): here MutationStrength.__init__ . run_id (str): identification string for run. gas_adsorption_bin (int): value representing a region of gas loading parameter-space. surface_area_bin (int): value representing a region of surface area parameter-space. void_fraction_bin (int): value representing a region of void fraction parameter-space. Returns: ms (float): either the mutation strength specified in the mutation stength datatable, or the default mutation strength if there is no row in the datatable corresponding to the bin. """ ms = session.query(MutationStrength) \ .filter( MutationStrength.run_id == run_id, MutationStrength.gas_adsorption_bin == gas_adsorption_bin, MutationStrength.surface_area_bin == surface_area_bin, MutationStrength.void_fraction_bin == void_fraction_bin, MutationStrength.generation <= generation) \ .order_by(MutationStrength.generation.desc()) \ .first() if ms: return ms else: return MutationStrength(run_id, generation, gas_adsorption_bin, surface_area_bin, void_fraction_bin, config['initial_mutation_strength'])
def worker_run_loop(run_id): """ Args: run_id (str): identification string for run. Writes seed generation and simulates properties, then manages overall bin-mutate-simualte routine until convergence cutt-off or maximum number of generations is reached. """ gen = last_generation(run_id) or 0 converged = False while not converged: print(('=======================================================\n' 'GENERATION {0}\n' '=======================================================\n' ).format(gen)) size_of_generation = config['children_per_generation'] while materials_in_generation(run_id, gen) < size_of_generation: if gen == 0: print("writing new seed...") material, pseudo_material = generate_pseudo_material( run_id, config['number_of_atom_types']) pseudo_material.dump() else: print( "selecting a parent / running retests on parent / mutating / simulating" ) parent_id = select_parent( run_id, max_generation=(gen - 1), generation_limit=config['children_per_generation']) parent_material = session.query(Material).get(parent_id) # run retests until we've run enough while parent_material.retest_passed is None: print("running retest...") print("Date :\t%s" % datetime.now().date().isoformat()) print("Time :\t%s" % datetime.now().time().isoformat()) parent_pseudo_material_path = os.path.join( os.path.dirname(os.path.dirname(htsohm.__file__)), run_id, 'pseudo_materials', '{0}.yaml'.format(parent_material.uuid)) with open(parent_pseudo_material_path) as parent_file: parent_pseudo_material = yaml.load(parent_file) retest(parent_material, config['retests']['number'], config['retests']['tolerance'], parent_pseudo_material) session.refresh(parent_material) if not parent_material.retest_passed: print( "parent failed retest. restarting with parent selection." ) continue mutation_strength = mutate(run_id, gen, parent_material) material, pseudo_material = mutate_pseudo_material( parent_material, parent_pseudo_material, mutation_strength, gen) pseudo_material.dump() run_all_simulations(material, pseudo_material) session.add(material) session.commit() material.generation_index = material.calculate_generation_index() if material.generation_index < config['children_per_generation']: session.add(material) else: # delete excess rows # session.delete(material) pass session.commit() sys.stdout.flush() gen += 1 converged = evaluate_convergence(run_id, gen)
def count_number_of_materials(run_id): return session.query(func.count(Material.id)).filter(Material.run_id==run_id)[0][0]
def library_sizes(): result = session.query(Material.run_id, func.count(Material.id)).group_by(Material.run_id) print("\nrun-id\t\t\t\t|\tlibrary size") print("{}+{}".format("-" * 32, "-" * 32)) for row in result: print("{}\t|\t{}".format(row[0], row[1]))
def count_number_of_materials(run_id): return session.query(func.count( Material.id)).filter(Material.run_id == run_id)[0][0]