def composition_filter(self, fes): """ Valid url parameter inputs: # 1. ?composition=Fe2O3 2. ?composition=Fe-O 3. ?composition={Fe,Ni}O 4. ?composition={3d}2O3 """ request = self.request comp = request.GET.get('composition', False) if not comp: return fes if '{' and '}' in comp: c_dict_lst = parse_formula_regex(comp) f_lst = [] for cd in c_dict_lst: f = ' '.join(['%s%g' % (k, cd[k]) for k in sorted(cd.keys())]) f_lst.append(f) fes = fes.filter(composition__formula__in=f_lst) else: c_lst = comp.strip().split('-') cs = Composition.get_list(c_lst) if len(cs) == 1: c = cs[0] else: c = cs fes = fes.filter(composition=c) return fes
def evaluate(self, parse_Tree): if isinstance(parse_Tree, Tree): children = parse_Tree.children if len(children) == 1: return self.evaluate(children[0]) elif len(children) == 2: op_fn = self.evaluate(children[0]) return op_fn(self.evaluate(children[1])) elif len(children) == 3: if parse_Tree.data == "comparison": db_prop = self.evaluate(children[0]) op_fn = self.evaluate(children[1]) if db_prop == "element": return op_fn(self.db_keys[db_prop], self.evaluate(children[2]) + "_") elif db_prop == "chemical_formula": c_dict_lst = parse_formula_regex( self.evaluate(children[2])) f_lst = [] for cd in c_dict_lst: f = " ".join([ "%s%g" % (k, cd[k]) for k in sorted(cd.keys()) ]) f_lst.append(f) return op_fn(self.db_keys[db_prop], f_lst) else: if db_prop in list(self.db_keys.keys()): _child_value = self.evaluate(children[2]).replace( '"', "") return op_fn(self.db_keys[db_prop], _child_value) else: error_msg = "Unknown property is queried : " + ( db_prop) # print(error_msg) return None else: op_fn = self.evaluate(children[1]) return op_fn(self.evaluate(children[0]), self.evaluate(children[2])) else: error_msg = "Not compatible format. Tree has >3 children" # print(error_msg) return error_msg elif isinstance(parse_Tree, Token): if parse_Tree.type == "VALUE": return parse_Tree.value elif parse_Tree.type in ["NOT", "CONJUNCTION", "OPERATOR"]: return self.opers[parse_Tree.value] else: error_msg = "Not a Lark Tree or Token. Check the parser implementation" # print(error_msg) return # (error_msg)
def evaluate(self, parse_Tree): if isinstance(parse_Tree, Tree): children = parse_Tree.children if len(children) == 1: return self.evaluate(children[0]) elif len(children) == 2: op_fn = self.evaluate(children[0]) return op_fn(self.evaluate(children[1])) elif len(children) == 3: if parse_Tree.data == 'comparison': db_prop = self.evaluate(children[0]) op_fn = self.evaluate(children[1]) if db_prop == 'element': return op_fn(self.db_keys[db_prop], self.evaluate(children[2]) + '_') elif db_prop == 'chemical_formula': c_dict_lst = parse_formula_regex( self.evaluate(children[2])) f_lst = [] for cd in c_dict_lst: f = ' '.join([ '%s%g' % (k, cd[k]) for k in sorted(cd.keys()) ]) f_lst.append(f) return op_fn(self.db_keys[db_prop], f_lst) else: if db_prop in self.db_keys.keys(): _child_value = self.evaluate(children[2]).replace( '"', '') return op_fn(self.db_keys[db_prop], _child_value) else: error_msg = "Unknown property is queried : " + ( db_prop) #print(error_msg) return None else: op_fn = self.evaluate(children[1]) return op_fn(self.evaluate(children[0]), self.evaluate(children[2])) else: error_msg = "Not compatible format. Tree has >3 children" #print(error_msg) return (error_msg) elif isinstance(parse_Tree, Token): if parse_Tree.type == 'VALUE': return parse_Tree.value elif parse_Tree.type in ['NOT', 'CONJUNCTION', 'OPERATOR']: return self.opers[parse_Tree.value] else: error_msg = "Not a Lark Tree or Token. Check the parser implementation" #print(error_msg) return #(error_msg)
def composition_filter(self, entries): """ Valid url parameter inputs: 1. ?composition=Fe2O3 2. ?composition=Fe-O 3. ?composition={Fe,Ni}O 4. ?composition={3d}2O3 5. ?composition=include_(Fe,Mn)-O : (Fe OR Mn) AND O 6. ?composition=include_Cl,O-H : Cl OR O AND H 6. ?composition=include_H-{3d} : 3d elements AND H """ request = self.request comp = request.GET.get("composition", False) if not comp: return entries if not "include_" in comp: if "{" and "}" in comp: c_dict_lst = parse_formula_regex(comp) f_lst = [] for cd in c_dict_lst: f = " ".join( ["%s%g" % (k, cd[k]) for k in sorted(cd.keys())]) f_lst.append(f) entries = entries.filter(composition__formula__in=f_lst) else: c_lst = comp.strip().split("-") cs = Composition.get_list(c_lst) if len(cs) == 1: c = cs[0] else: c = cs entries = entries.filter(composition=c) else: comp_in = comp.replace("include_", "") # t = Token(comp_in) # q = t.evaluate() q = query_to_Q(comp_in) entries = entries.filter(q) # comp_ex = request.GET.get('composition_exclude', False) # if comp_ex: # cex_lst = Composition.get(comp_ex).comp.keys() # while cex_lst: # tmp_ex = cex_lst.pop() # entries = entries.exclude(composition__element_set=tmp_ex) return entries
def composition_filter(self, fes): """ Valid url parameter inputs: # 1. ?composition=Fe2O3 2. ?composition=Fe-O 3. ?composition={Fe,Ni}O 4. ?composition={3d}2O3 """ request = self.request comp = request.GET.get("composition", False) if not comp: return fes if "{" and "}" in comp: c_dict_lst = parse_formula_regex(comp) f_lst = [] for cd in c_dict_lst: f = " ".join(["%s%g" % (k, cd[k]) for k in sorted(cd.keys())]) f_lst.append(f) fes = fes.filter(composition__formula__in=f_lst) elif "-" in comp: c_lst = comp.strip().split("-") dim = len(c_lst) q_lst = [ Q(composition__element_list__contains=s + "_") for s in c_lst ] combined_q = reduce(operator.or_, q_lst) combined_q = reduce( operator.and_, [combined_q, Q(composition__ntypes__lte=dim)]) ex_q_lst = [ Q(composition__element_list__contains=e.symbol + "_") for e in Element.objects.exclude(symbol__in=c_lst) ] combined_q_not = reduce(operator.or_, ex_q_lst) fes = fes.filter(combined_q).exclude(combined_q_not) else: c = Composition.get(comp) fes = fes.filter(composition=c) return fes
def property_first_comparison(self, children): """ This function is automatically called by the Transformer when it encounters a Tree with Tree.data = property_first_comparison As of now, all the supported value comparisons in OQMD's optimade implementation are property-first comparisons. Because of that, this function is called by each filter element Format of property-first comparison: "property operator value(s)" Example: stability < 0.05 : Here, `stability` is the property, `<` is the operator, and `0.05` is the value """ _property = children[0].children[0].value try: a = self.property_dict[_property] except: self.handle_error("T1", "Cannot resolve the property name", _property) return if children[1] is None: self.handle_error( "T1", "Accompanying Operator or Value cannot be parsed", a.name) return operation_fn = children[1][0] b = children[1][1] if not (a.is_queryable and a.db_value): self.handle_error("T1", "Cannot be queried in filter", a.name) return if a.is_chem_form: c_dict_lst = parse_formula_regex(b) if len(c_dict_lst) == 1 and len(c_dict_lst[0].keys()) == 0: self.handle_error( "T1", "Chemical formula {} cannot be parsed".format(b), a.name) return b = [ " ".join(["%s%g" % (k, cd[k]) for k in sorted(cd.keys())]) for cd in c_dict_lst ] if operation_fn in self.logic_functions: if not a.is_logic_operable: self.handle_error( "T1", "Cannot be queried with operators <,>,<=,>=", a.name) return try: return operation_fn(a, b) except ParseError as err: raise err except: self.handle_error("T1", "Unknown error while converting to Django Q", a.name)