/// <summary> /// Returns an aray of trait possibilites and their spawn percentages. /// Bad data/data that does not obey the algorithm will cause hilarious (read: annoying) /// bugs. Make sure the user is forced to follow the rules rigidly. /// </summary> /// <param name="p_fatherTraits">Father's traits</param> /// <param name="p_motherTraits">Mother's traits</param> /// <returns></returns> private CrossList ThreePointCross(ReducedTraitModel[] p_fatherTraits, ReducedTraitModel[] p_motherTraits) { //FIX ORDER p_fatherTraits = p_fatherTraits.OrderBy(t => t.Distance).ToArray(); p_motherTraits = p_motherTraits.OrderBy(t => t.Distance).ToArray(); List<CrossTrait> returnArr = new List<CrossTrait>(); #region Trait_Prep //generate wild, het, hom for each trait & gender Trait[] wild = new Trait[3]; Trait[] hets = new Trait[3]; Trait[] homs = new Trait[3]; Trait[] father_raw = new Trait[3]; Trait[] mother_raw = new Trait[3]; for (int i = 0; i < 3; i++) { Trait dbTrt1 = db.Trait.Find(p_fatherTraits[i].Id); Trait dbTrt2 = db.Trait.Find(p_motherTraits[i].Id); wild[i] = db.Trait.FirstOrDefault(t => t.CategoryId == dbTrt1.CategoryId && t.Name.ToLower() == Constants.Wild.ToLower()); hets[i] = GetTrait((dbTrt1.Name != Constants.Wild) ? dbTrt1 : dbTrt2, true); homs[i] = GetTrait((dbTrt1.Name != Constants.Wild) ? dbTrt1 : dbTrt2, false); } #endregion #region Distance_Linked //check father trait, then mother trait to determine case List<Trait> building = new List<Trait>(); if ((!p_fatherTraits[0].IsHeterozygous && !p_fatherTraits[1].IsHeterozygous && !p_fatherTraits[2].IsHeterozygous) && (!p_motherTraits[0].IsHeterozygous && !p_motherTraits[1].IsHeterozygous && !p_motherTraits[2].IsHeterozygous)) { //father hom-hom, mother hom-hom //one output: het-het building.Add(hets[0]); building.Add(hets[1]); building.Add(hets[2]); returnArr.Add(new CrossTrait(building, 1)); return FinishCross(returnArr, 1); } else { //2 traits must be heterozygous by necessity of the algorithm //calculate recombinance rates double dist1 = (p_fatherTraits[0].Name != Constants.Wild) ? p_fatherTraits[0].Distance : p_motherTraits[0].Distance; double dist2 = (p_fatherTraits[1].Name != Constants.Wild) ? p_fatherTraits[1].Distance : p_motherTraits[1].Distance; double dist3 = (p_fatherTraits[2].Name != Constants.Wild) ? p_fatherTraits[2].Distance : p_motherTraits[2].Distance; //TODO CHANGE!! double recombined_rate_1_2 = Math.Abs(dist1 - dist2) / 100; double unrecombined_rate_1_2 = 1 - recombined_rate_1_2; double recombined_rate_2_3 = Math.Abs(dist2 - dist3) / 100; double unrecombined_rate_2_3 = 1 - recombined_rate_2_3; #region no_recombine building = new List<Trait>(); building.Add(homs[0]); building.Add(homs[1]); building.Add(homs[2]); returnArr.Add(new CrossTrait(building, (unrecombined_rate_1_2 * unrecombined_rate_2_3))); building = new List<Trait>(); building.Add(hets[0]); building.Add(hets[1]); building.Add(hets[2]); returnArr.Add(new CrossTrait(building, (unrecombined_rate_1_2 * unrecombined_rate_2_3))); #endregion #region single_recombine building = new List<Trait>(); building.Add(homs[0]); building.Add(hets[1]); building.Add(hets[2]); returnArr.Add(new CrossTrait(building, (recombined_rate_1_2 * unrecombined_rate_2_3))); building = new List<Trait>(); building.Add(hets[0]); building.Add(hets[1]); building.Add(homs[2]); returnArr.Add(new CrossTrait(building, (unrecombined_rate_1_2 * recombined_rate_2_3))); building = new List<Trait>(); building.Add(homs[0]); building.Add(homs[1]); building.Add(hets[2]); returnArr.Add(new CrossTrait(building, (unrecombined_rate_1_2 * recombined_rate_2_3))); building = new List<Trait>(); building.Add(hets[0]); building.Add(homs[1]); building.Add(homs[2]); returnArr.Add(new CrossTrait(building, (recombined_rate_1_2 * unrecombined_rate_2_3))); #endregion #region double_recombine building = new List<Trait>(); building.Add(hets[0]); building.Add(homs[1]); building.Add(hets[2]); returnArr.Add(new CrossTrait(building, (recombined_rate_1_2 * recombined_rate_2_3))); building = new List<Trait>(); building.Add(homs[0]); building.Add(hets[1]); building.Add(homs[2]); returnArr.Add(new CrossTrait(building, (recombined_rate_1_2 * recombined_rate_2_3))); #endregion return FinishCross(returnArr, 8); } #endregion /* THERE ARE 4 POSSIBLE CASES * 1: NO RECOMBINE * 2: T1T2 RECOMBINE * 3: T1T2T3 RECOMBINE * 4: T2T3 RECOMBINE */ //return new CrossList(); }
/// <summary> /// Compares two traits and determines whether they are a soft match (heterozygous recessive & wild || het dominant & hom dominant) /// </summary> /// <param name="p_trt1">A traitmod to compare</param> /// <param name="p_trt2">Another traitmod to compare</param> /// <returns>True if soft match, false otherwise</returns> private bool SoftMatchHelper(ReducedTraitModel p_trt1, ReducedTraitModel p_trt2) { Boolean t1Het = p_trt1.IsHeterozygous; Boolean t2Het = p_trt2.IsHeterozygous; Boolean t1Dom = p_trt1.IsDominant; Boolean t2Dom = p_trt2.IsDominant; return (((p_trt1.Name == p_trt2.Name) && (t1Het == t2Het)) || ((t1Het && t1Dom) && (!t2Het && t2Dom)) || ((!t1Het && t1Dom) && (t2Het && t2Dom)) || ((t1Het && !t1Dom) && (p_trt2.Name.ToLower() == Constants.Wild.ToLower())) || ((p_trt1.Name.ToLower() == Constants.Wild.ToLower()) && (t2Het && !t2Dom))); }
/// <summary> /// Returns an array of trait possibilities and their spawn percentages /// based on the provided trait pair /// </summary> /// <param name="p_fatherTrait">Father's trait</param> /// <param name="p_motherTrait">Mother's Trait</param> /// <returns>The processed list of child possibilities</returns> private CrossList BasicCross(ReducedTraitModel p_fatherTrait, ReducedTraitModel p_motherTrait) { Trait dbTrt1 = db.Trait.Find(p_fatherTrait.Id); Trait dbTrt2 = db.Trait.Find(p_motherTrait.Id); Trait trait1 = new Trait(); Trait trait2 = new Trait(); List<CrossTrait> returnArr = new List<CrossTrait>(); int count = 0; #region Sex_Linked if (dbTrt1.ChromosomeNumber == 1 || dbTrt2.ChromosomeNumber == 1) { #region Sex_Trait_Prep //take in traits after detecting that they are sex linked (on chromosome 1) //make special sex trait and perform cross //parse it in children method //?????? //profit //make trait1 heterozygous (Male XY) and trait2 homozygous (Female XX) trait1 = new Trait() { Id = dbTrt1.Id, Name = Constants.SexLinked, Father = GetTrait(dbTrt1, p_fatherTrait.IsHeterozygous), Mother = GetTrait(dbTrt2, p_motherTrait.IsHeterozygous), IsHeterozygous = true, ChromosomeNumber = 1, CategoryId = dbTrt1.CategoryId }; trait2 = new Trait() { Id = dbTrt2.Id, Name = Constants.SexLinked, Father = GetTrait(dbTrt1, p_fatherTrait.IsHeterozygous), Mother = GetTrait(dbTrt2, p_motherTrait.IsHeterozygous), IsHeterozygous = false, ChromosomeNumber = 1, CategoryId = dbTrt2.CategoryId }; //do some fancy processing and abuse CrossTrait's new Male and Female bools //we know the list contains a sex-linked trait, so find it Trait sexLinkedTrait = dbTrt1.ChromosomeNumber == 1 ? trait1 : trait2; Trait hetFatherTrait = GetTrait(sexLinkedTrait.Father, true); Trait homFatherTrait = GetTrait(sexLinkedTrait.Father, false); Trait hetMotherTrait = GetTrait(sexLinkedTrait.Mother, true); Trait homMotherTrait = GetTrait(sexLinkedTrait.Mother, false); #endregion if (sexLinkedTrait.Mother.ChromosomeNumber == 1 && sexLinkedTrait.Father.ChromosomeNumber == 1) { //we know they will be the same trait, so there are only 2 cross cases here... if (sexLinkedTrait.Mother.IsHeterozygous ?? false) { //het - hemi cross Trait wildTrait = db.Trait.First(t => t.CategoryId == sexLinkedTrait.Father.ChromosomeNumber && t.Name.ToLower() == Constants.Wild.ToLower()); returnArr.Add(new CrossTrait(homMotherTrait, .5, false, true)); //aff female returnArr.Add(new CrossTrait(hetMotherTrait, .5, false, true)); //carrier female returnArr.Add(new CrossTrait(homMotherTrait, .5, true, false)); //aff male returnArr.Add(new CrossTrait(wildTrait , .5, true, false)); //unaff male count = 4; return FinishCross(returnArr, count); } else { //hom - hemi cross returnArr.Add(new CrossTrait(homMotherTrait, 1, true, false)); //aff male returnArr.Add(new CrossTrait(homMotherTrait, 1, false, true)); //aff female count = 2; return FinishCross(returnArr, count); } } if (sexLinkedTrait.Father.ChromosomeNumber == 1) { //affected father if (!(sexLinkedTrait.Mother.IsHeterozygous ?? false)) { returnArr.Add(new CrossTrait(hetFatherTrait, 1, false, true)); //carrier females returnArr.Add(new CrossTrait(homMotherTrait, 1, true, false)); //unaff males count = 2; return FinishCross(returnArr, count); } } else { //affected mother if (sexLinkedTrait.Mother.IsHeterozygous ?? false) { //hetrec sex linked //1 son wild, 1 son aff, 1 daughter wild, 1 daughter het returnArr.Add(new CrossTrait(hetMotherTrait, .5, false, true)); //carrier female returnArr.Add(new CrossTrait(homFatherTrait, .5, false, true)); //unaff female returnArr.Add(new CrossTrait(homMotherTrait, .5, true, false)); //aff male returnArr.Add(new CrossTrait(homFatherTrait, .5, true, false)); //unaff male count = 4; return FinishCross(returnArr, count); } else { returnArr.Add(new CrossTrait(hetMotherTrait, 1, false, true)); //carrier females returnArr.Add(new CrossTrait(homMotherTrait, 1, true, false)); //aff males count = 2; return FinishCross(returnArr, count); } } } #endregion #region Non_Sex_Linked else { #region Trait_Prep trait1 = GetTrait(dbTrt1, p_fatherTrait.IsHeterozygous); trait2 = GetTrait(dbTrt2, p_motherTrait.IsHeterozygous); #endregion } //het-het if ((trait1.IsHeterozygous ?? false) && (trait2.IsHeterozygous ?? false)) { //we know theyre same trait so we return accordingly Trait wildTrait = db.Trait.First(t => t.Name.ToLower() == Constants.Wild.ToLower() && t.CategoryId == trait1.CategoryId); Trait homTrait = GetTrait(trait1, false); Trait hetTrait = GetTrait(trait1, true); returnArr.Add(new CrossTrait(homTrait, .25)); returnArr.Add(new CrossTrait(hetTrait, .5)); returnArr.Add(new CrossTrait(wildTrait, .25)); count = 3; return FinishCross(returnArr, count); } //hom-hom if (!(trait1.IsHeterozygous ?? false) && !(trait2.IsHeterozygous ?? false)) { if (trait1.Name.ToLower() == Constants.Wild.ToLower() && trait2.Name.ToLower() == Constants.Wild.ToLower()) { returnArr.Add(new CrossTrait(trait1, 1)); count = 1; return FinishCross(returnArr, count); } //rec-wild else if (!trait1.IsDominant && trait2.Name.ToLower() == Constants.Wild.ToLower()) { Trait expressed = trait1; expressed.IsHeterozygous = true; returnArr.Add(new CrossTrait(expressed, 1)); count = 1; return FinishCross(returnArr, count); } //wild-rec else if (!trait2.IsDominant && trait1.Name.ToLower() == Constants.Wild.ToLower()) { Trait expressed = trait2; expressed.IsHeterozygous = true; returnArr.Add(new CrossTrait(expressed, 1)); count = 1; return FinishCross(returnArr, count); } //dom-rec* else if (trait1.IsDominant) { Trait expressed = trait1; expressed.IsHeterozygous = true; returnArr.Add(new CrossTrait(expressed, 1)); count = 1; return FinishCross(returnArr, count); } else if (trait2.IsDominant) { Trait expressed = trait2; expressed.IsHeterozygous = true; returnArr.Add(new CrossTrait(expressed, 1)); count = 1; return FinishCross(returnArr, count); } } //hom-het if ((!(trait1.IsHeterozygous ?? false) && (trait2.IsHeterozygous ?? false)) || (!(trait2.IsHeterozygous ?? false) && (trait1.IsHeterozygous ?? false))) { Trait homTrait = (trait1.IsHeterozygous ?? false) ? trait2 : trait1; Trait hetTrait = (trait1.IsHeterozygous ?? false) ? trait1 : trait2; returnArr.Add(new CrossTrait(hetTrait, .5)); returnArr.Add(new CrossTrait(homTrait, .5)); count = 2; return FinishCross(returnArr, count); } #endregion return new CrossList(); }
/// <summary> /// helper method to create a fly from the trait strings javascript sends over /// </summary> /// <param name="p_module">Module parameter for the new fly</param> /// <param name="p_gender">Gender parameter for the new fly</param> /// <param name="p_traits">Array of TraitIDs for the new fly</param> /// <returns>A new Fly, null if it fails</returns> private Fly LogFly(int p_module, UseInstance p_instance, string p_gender, ReducedTraitModel[] p_traits) { Fly toAdd = new Fly() { Id = 0 }; try { toAdd.Gender = db.Gender.First(t => t.GenderName == p_gender); toAdd.Module = db.Module.First(t => t.Call_id == p_module); toAdd.UseInstance = p_instance; } catch (Exception e) { Exception ex = new InvalidOperationException("Something in the configuration of gender or module is wrong. This should be easily fixable through the Admin Dashboard.", e); Elmah.ErrorSignal.FromCurrentContext().Raise(ex); return null; } //foreach (ReducedTraitModel cur in p_traits) //{ // Trait newTrait = GetTrait( db.Trait.Find(cur.Id), cur.IsHeterozygous ); // toAdd.Traits.Add(newTrait); // db.Entry(newTrait).State = EntityState.Detached; //} db.Fly.Add(toAdd); try { db.SaveChanges(); } catch (Exception e) { Exception ex = new InvalidOperationException("There was an issue storing a fly (Lab/NewFly).", e); Elmah.ErrorSignal.FromCurrentContext().Raise(ex); return null; } return toAdd; }
/// <summary> /// Returns an aray of trait possibilites and their spawn percentages. /// Bad data/data that does not obey the algorithm will cause hilarious (read: annoying) /// bugs. Make sure the user is forced to follow the rules rigidly. /// </summary> /// <param name="p_fatherTraits">Father's traits</param> /// <param name="p_motherTraits">Mother's traits</param> /// <returns></returns> private CrossList TwoPointCross(ReducedTraitModel[] p_fatherTraits, ReducedTraitModel[] p_motherTraits) { List<CrossTrait> returnArr = new List<CrossTrait>(); #region Trait_Prep //generate wild, het, hom for each trait & gender Trait[] wild = new Trait[2]; Trait[] father_hets = new Trait[2]; Trait[] father_homs = new Trait[2]; Trait[] mother_hets = new Trait[2]; Trait[] mother_homs = new Trait[2]; Trait[] father_raw = new Trait[2]; Trait[] mother_raw = new Trait[2]; for (int i = 0; i < 2; i++) { Trait dbTrt1 = db.Trait.Find(p_fatherTraits[i].Id); Trait dbTrt2 = db.Trait.Find(p_motherTraits[i].Id); wild[i] = db.Trait.FirstOrDefault(t => t.CategoryId == dbTrt1.CategoryId && t.Name.ToLower() == Constants.Wild.ToLower()); //father modified father_hets[i] = GetTrait(dbTrt1, true); father_homs[i] = GetTrait(dbTrt1, false); //mother modified mother_hets[i] = GetTrait(dbTrt2, true); mother_homs[i] = GetTrait(dbTrt2, false); //raw arrays father_raw[i] = GetTrait(dbTrt1, p_fatherTraits[i].IsHeterozygous); mother_raw[i] = GetTrait(dbTrt2, p_motherTraits[i].IsHeterozygous); } #endregion #region Distance_Linked //check father trait, then mother trait to determine case List<Trait> building = new List<Trait>(); if ((!p_fatherTraits[0].IsHeterozygous && !p_fatherTraits[1].IsHeterozygous) && (!p_motherTraits[0].IsHeterozygous && !p_motherTraits[1].IsHeterozygous)) { //father hom-hom, mother hom-hom //one output: het-het building.Add((father_hets[0].Name != Constants.Wild) ? father_hets[0] : mother_hets[0]); building.Add((father_hets[1].Name != Constants.Wild) ? father_hets[1] : mother_hets[1]); returnArr.Add(new CrossTrait(building, 1)); return FinishCross(returnArr, 1); } else { //2 traits must be heterozygous by necessity of the algorithm //calculate recombinance rates double dist1 = (p_fatherTraits[0].Name != Constants.Wild) ? father_raw[0].Distance : mother_raw[0].Distance; double dist2 = (p_fatherTraits[1].Name != Constants.Wild) ? father_raw[1].Distance : mother_raw[1].Distance; double recombined_rate = Math.Abs(dist1 - dist2) / 100; double unrecombined_rate = 1 - recombined_rate; //build all four possibilities building.Add(father_raw[0]); building.Add(father_raw[1]); //unrecombined returnArr.Add(new CrossTrait(building, unrecombined_rate / 2)); building = new List<Trait>(); building.Add(mother_raw[0]); building.Add(mother_raw[1]); //unrecombined returnArr.Add(new CrossTrait(building, unrecombined_rate / 2)); building = new List<Trait>(); building.Add(mother_raw[0]); building.Add(father_raw[1]); //recombined returnArr.Add(new CrossTrait(building, recombined_rate / 2)); building = new List<Trait>(); building.Add(father_raw[0]); building.Add(mother_raw[1]); //recombined returnArr.Add(new CrossTrait(building, recombined_rate / 2)); return FinishCross(returnArr, 4); } #endregion //return new CrossList(); }