def validate_math(math): # Check that all connected variables are inside this component is_valid = True for e in math.errors.all(): e.delete() # Compare list of local variables in this component with the ones used in the mathml available_variables = [ x[0] for x in math.component.variables.values_list('name') ] referenced_variables = [ x.split("</ci>")[0] for x in math.math_ml.split("<ci>")[1:] ] missing = set(referenced_variables) - set(available_variables) for m in missing: n = "'{n}' ".format(math.name) if math.name != "" else "" err = ItemError( hints= "Maths {n}in component '{c}' references a variable '{v}' which is not inside the component." .format(n=n, c=math.component.name, v=m), spec="14.1.3", fields=["variables"]) err.save() math.errors.add(err) is_valid = False # TODO Validate elements in the cellml string # TODO Validate that units are consistent # TODO Warn if multipliers are inconsistent in the units return is_valid
def validate_equivalent_variable(component, variable): is_valid = True # Check that equivalent variables are not in the same component for ev in variable.equivalent_variables.filter(component=component): err = ItemError( hints= "Variable <i>{v1}</i> and equivalent variable <i>{v2}</i> are both in the same component " "<i>{c}</i>".format(v1=variable.name, v2=ev.name, c=component.name), spec="17.1.2", fields=['component'] # TODO not sure what this should be ) err.save() component.errors.add(err) is_valid = False # Check that the variables have a valid parent component for ev in variable.equivalent_variables.filter(component__isnull=True): err = ItemError( hints= "Variable <i>{ev}</i> is equivalent to variable <i>{v}</i> in component <i>{c}</i> but " "does not have a parent component".format( ev=ev.name, v=variable.name, c=component.name, ), spec="17.?", fields=['component'] # TODO not sure what this should be ) err.save() ev.errors.add(err) component.errors.add(err) is_valid = False return is_valid
def validate_component_locally(component): is_valid = True for e in component.errors.all(): e.delete() is_valid, hints = is_cellml_identifier(component.name) if not is_valid: err = ItemError(hints="Invalid component name <i>{n}</i>: {h}".format( n=component.name, h=hints), spec='10.1.1', fields=['name']) err.save() component.errors.add(err) # Check component's variables for duplicate names duplicates = component.variables.values('name').annotate( name_count=Count('name')).filter(name_count__gt=1) for d in duplicates: err = ItemError( hints= "Variable name <i>{n}</i> is duplicated {x} times in component <i>{m}</i>" .format(n=d['name'], x=d['name_count'], m=component.name), spec='11.1.1.1', fields=['variables']) err.save() component.errors.add( err ) # It's an error of the *component* not of the variable itself ... is_valid = False return is_valid
def validate_unit(unit): is_valid = True for e in unit.errors.all(): e.delete() unit.error_tree = None # 9.1.1 Check that the pointers are valid if not unit.child_cu: is_valid = False err = ItemError( hints="Unit in units <i>{p}</i> points to a blank unit".format( p=unit.parent_cu.name), spec='9.1.1', fields=['child_cu']) err.save() unit.parent_cu.errors.add(err) error_tree, error_count = draw_error_tree(unit) error_count += unit.errors.count() unit.error_tree = {'tree_html': error_tree, 'error_count': error_count} unit.is_valid = is_valid unit.save() return is_valid
def validate_connections(model): is_valid = True for component in model.all_components.all(): for variable in component.variables.filter( equivalent_variables__isnull=False): is_valid = validate_equivalent_variable(component, variable) cycle_list = model_cyclic_variables_found(model) loop_count = len(cycle_list) if loop_count > 0: loops = " loops" if loop_count > 1 else " loop" des = ''.join(cycle_list) err = ItemError(hints="Cyclic variables exist, " + str(loop_count) + loops + " found (Component,Variable): <br>" + des, spec="19.10.5") err.save() model.errors.add(err) is_valid = False else: # Check order uniqueness in resets total_done_list = [] for component in model.all_components.all(): for variable in component.variables.filter( equivalent_variables__isnull=False).exclude( id__in=total_done_list): local_done_list = [] reset_map = {} local_done_list, reset_map = fetch_connected_resets( variable, local_done_list, reset_map) total_done_list.extend(local_done_list) for order, resets in reset_map.items(): if len(resets) > 1: des = "Non-unique reset order of " + order + " found within equivalent variable set: " for r in resets: des += "<br> - variable <i>" + r.variable.name + "</i> in component <i>" + \ r.variable.component.name + "</i> has reset with order " + order err = ItemError(hints=des, spec='12.1.1.2') err.save() model.errors.add(err) is_valid = False return is_valid
def validate_compoundunit(cu): for e in cu.errors.all(): e.delete() # Built-in units are valid if cu.is_standard: return True cu.error_tree = None # Checking the name is_valid, hints = is_cellml_identifier(cu.name) if not is_valid: err = ItemError( hints="Invalid compound_units name <i>{n}</i>: {h}".format( n=cu.name, h=hints), spec='8.1.1', fields=['name']) err.save() cu.errors.add(err) if CompoundUnit.objects.filter(name=cu.name, is_standard=True).count() > 0: err = ItemError( hints= "The name cannot be the same as a built-in units name, <i>{}</i>". format(cu.name), spec="8.1.3", fields=['name']) err.save() cu.errors.add(err) is_valid = False # Also need to check the unit elements of this compound unit here as they can't be accessed individually for u in cu.product_of.all(): is_valid = validate_unit(u) and is_valid error_tree, error_count = draw_error_tree(cu) error_count += cu.errors.count() cu.error_tree = {'tree_html': error_tree, 'error_count': error_count} cu.is_valid = is_valid cu.save() return is_valid
def validate_cellmodel_locally(model): is_valid = True for e in model.errors.all(): e.delete() model.error_tree = None # Check model name is_valid, hints = is_cellml_identifier(model.name) if not is_valid: err = ItemError(hints="Invalid model name <i>{n}</i>: {h}".format( n=model.name, h=hints), spec='4.2.1', fields=['name']) err.save() model.errors.add(err) is_valid = False # Check model's components for duplicate names duplicates = model.all_components.values('name').annotate( name_count=Count('name')).filter(name_count__gt=1) for d in duplicates: err = ItemError( hints= "Component name <i>{n}</i> is duplicated {x} times in model <i>{m}</i>" .format(n=d['name'], x=d['name_count'], m=model.name), spec='10.1.1', ) err.save() model.errors.add( err ) # It's an error of the *model* not of the component itself ... is_valid = False # Check model units duplicates = model.compoundunits.values('name').annotate( name_count=Count('name')).filter(name_count__gt=1) for d in duplicates: err = ItemError( hints= "Units name <i>{n}</i> is duplicated {x} times in model <i>{m}</i>" .format(n=d['name'], x=d['name_count'], m=model.name), spec='8.1.2', ) err.save() model.errors.add( err ) # It's an error of the *model* not of the compoundunit itself ... is_valid = False # Check that the set of compound units used by the variables exists in the model required = model.all_components.values_list( 'name', 'variables__name', 'variables__compoundunit__name') available = model.compoundunits.values_list('name').distinct() missing = [(c, v, u) for c, v, u in required if (u, ) not in available and u is not None and ( u, ) not in CompoundUnit.objects.filter( is_standard=True).values_list('name')] for c, v, u in missing: err = ItemError( hints= "Variable <i>{v}</i> in component <i>{c}</i> has units <i>{u}</i> which do not exist in this " "model, and are not built-in.".format(c=c, u=u, v=v), spec="11.1.1.2") err.save() model.errors.add(err) is_valid = False return is_valid
def validate_reset(reset): is_valid = True for e in reset.errors.all(): e.delete() if reset.order == '' or reset.order is None: err = ItemError( hints="Reset <i>{r}</i> does not have an order set".format( r=reset.name), spec="12.1.2", fields=["order"]) err.save() reset.errors.add(err) is_valid = False if reset.test_value is None: err = ItemError( hints="Reset <i>{r}</i> does not reference a test_value".format( r=reset.name), spec="12", # TODO find correct code for resets fields=['test_value']) err.save() reset.errors.add(err) is_valid = False if reset.reset_value is None: err = ItemError( hints="Reset <i>{r}</i> does not reference a reset_value".format( r=reset.name), spec="12", # TODO find correct code for resets fields=['reset_value']) err.save() reset.errors.add(err) is_valid = False if reset.component is None: err = ItemError( hints="Reset <i>{r}</i> does not have a component".format( r=reset.name), spec="10.1.2.2", fields=['component']) err.save() reset.errors.add(err) is_valid = False if reset.variable is None: err = ItemError( hints="Reset <i>{r}</i> does not reference a variable".format( r=reset.name), spec="12.1.1", fields=['variable']) err.save() reset.errors.add(err) is_valid = False if reset.test_variable is None: err = ItemError( hints="Reset <i>{r}</i> does not reference a test_variable".format( r=reset.name), spec="12", # TODO find correct code for resets fields=['test_variable']) err.save() reset.errors.add(err) is_valid = False if reset.component is not None: if reset.variable is not None and reset.component != reset.variable.component: err = ItemError( hints= "Reset <i>{r}</i> in component <i>{c}</i> refers to a variable <i>{v}</i> which is in a " "different component, <i>{vc}</i>".format( r=reset.name, c=reset.component.name, v=reset.variable.name, vc=reset.variable.component.name), spec="12", # TODO find correct code for resets fields=['variable']) err.save() reset.errors.add(err) is_valid = False if reset.test_variable is not None and reset.component != reset.test_variable.component: err = ItemError( hints= "Reset <i>{r}</i> in component <i>{c}</i> refers to a test_variable <i>{v}</i> in a different " "component, <i>{vc}</i>".format( r=reset.name, c=reset.component.name, v=reset.test_variable.name, vc=reset.test_variable.component.name), spec="12", # TODO find correct code for resets fields=['test_variable']) err.save() reset.errors.add(err) is_valid = False error_tree, error_count = draw_error_tree(reset) error_count += reset.errors.count() reset.error_tree = {'tree_html': error_tree, 'error_count': error_count} reset.is_valid = is_valid reset.save() return is_valid
def validate_variable(variable): # Variables are all local validation - no need for a duplicate for e in variable.errors.all(): e.delete() try: initial_component_id = variable.initial_value_variable.component.id except Exception as e: initial_component_id = None try: initial_unit_id = variable.initial_value_variable.compoundunit.id except Exception as e: initial_unit_id = None # Validate name is_valid, hints = is_cellml_identifier(variable.name) if not is_valid: err = ItemError(hints="Invalid variable name <i>{n}</i>: {h}".format( n=variable.name, h=hints), spec='11.1.1.1', fields=["name"]) err.save() variable.errors.add(err) # Check that variable has units if variable.compoundunit is None: err = ItemError( hints="Variable <i>{}</i> does not have any units.".format( variable.name), spec="11.1.1.2", fields=["compoundunit"]) err.save() variable.errors.add(err) is_valid = False # Check that the units of the initialising variable are the same as for this variable elif initial_unit_id is not None: if initial_unit_id != variable.compoundunit.id: err = ItemError( hints= "Variable has units of <i>{u}</i> but is initialised by variable <i>{vi}</i> " "which has units of <i>{ui}</i>.".format( u=variable.compoundunit.name, vi=variable.initial_value_variable.name, ui=variable.initial_value_variable.compoundunit.name), spec="11?", fields=["initial_value_variable"]) err.save() variable.errors.add(err) is_valid = False # Check that the variable has access to the initialising variable if initial_component_id is not None: if initial_component_id != variable.component.id: err = ItemError( hints= "Variable <i>{v}</i> in component <i>{c}</i> is initialised by variable <i>{vi}</i> " "which is in another component <i>{ci}</i>.".format( v=variable.name, c=variable.component.name, vi=variable.initial_value_variable.name, ci=variable.initial_value_variable.component.name), spec="11.1.2.1", fields=['initial_value_variable', 'component']) err.save() variable.errors.add(err) is_valid = False # Check that there is only one method of initialisation if variable.initial_value_variable is not None and variable.initial_value_constant is not None: err = ItemError( hints= "Variable <i>{v}</i> in component <i>{c}</i> is initialised by variable <i>{vi}</i> " "as well as by the constant value <i>{ci}</i>. There can be only one." .format(v=variable.name, c=variable.component.name, vi=variable.initial_value_variable.name, ci=variable.initial_value_constant), spec="11.1.2.1", fields=['initial_value_variable', 'initial_value_constant']) err.save() variable.errors.add(err) is_valid = False # Check that directly related resets have unique orders duplicated_orders = [ x[0] for x in variable.reset_variables.values_list('order') ] unique_orders = list(set(duplicated_orders)) for x in unique_orders: duplicated_orders.remove(x) for rv in variable.reset_variables.filter(order__in=duplicated_orders): err = ItemError( hints= "Variable <i>{v}</i> in component <i>{c}</i> contains more than one reset with order of " "<i>{o}</i>.".format(v=variable.name, c=variable.component.name, o=rv.order), spec="??", # TODO find spec reference for resets fields=['reset_variables'] # TODO not sure what this should be ) err.save() variable.errors.add(err) is_valid = False error_tree, error_count = draw_error_tree(variable) error_count += variable.errors.count() variable.error_tree = {'tree_html': error_tree, 'error_count': error_count} variable.is_valid = is_valid variable.save() return is_valid