| | 986 | } |
| | 987 | |
| | 988 | MolecularXtal* XtalOpt::generateNewMXtal() |
| | 989 | { |
| | 990 | // Get all optimized structures |
| | 991 | QList<Structure*> structures = m_queue->getAllOptimizedStructures(); |
| | 992 | |
| | 993 | // Check to see if there are enough optimized structure to perform |
| | 994 | // genetic operations |
| | 995 | if (structures.size() < 3) { |
| | 996 | MolecularXtal *mxtal = 0; |
| | 997 | while (!checkXtal(mxtal)) { |
| | 998 | if (mxtal) { |
| | 999 | mxtal->deleteLater(); |
| | 1000 | mxtal = NULL; |
| | 1001 | } |
| | 1002 | mxtal = generateRandomMXtal(1, 0); |
| | 1003 | } |
| | 1004 | mxtal->setParents(mxtal->getParents() + " (too few optimized structures " |
| | 1005 | "to generate offspring)"); |
| | 1006 | return mxtal; |
| | 1007 | } |
| | 1008 | |
| | 1009 | #warning Remove when operator GUI is setup // TODO |
| | 1010 | mga_p_cross = 34; |
| | 1011 | mga_cross_minimumContribution = .25; |
| | 1012 | // - Reconf |
| | 1013 | mga_p_reconf = 33; |
| | 1014 | mga_reconf_minSubMolsToReplace = 1; |
| | 1015 | mga_reconf_maxSubMolsToReplace = 3; |
| | 1016 | mga_reconf_minStrain = 0.0; |
| | 1017 | mga_reconf_maxStrain = 0.5; |
| | 1018 | // - Swirl |
| | 1019 | mga_p_swirl = 33; |
| | 1020 | mga_swirl_minSubMolsToRotate = 1; |
| | 1021 | mga_swirl_maxSubMolsToRotate = 3; |
| | 1022 | mga_swirl_minRotationDegree = 30; |
| | 1023 | mga_swirl_fracInPlane = 0.5; |
| | 1024 | mga_swirl_minStrain = 0.0; |
| | 1025 | mga_swirl_maxStrain = 0.5; |
| | 1026 | |
| | 1027 | // Sort structure list |
| | 1028 | Structure::sortByEnthalpy(&structures); |
| | 1029 | |
| | 1030 | // Trim list |
| | 1031 | // Remove all but (popSize + 1). The "+ 1" will be removed |
| | 1032 | // during probability generation. |
| | 1033 | while ( static_cast<uint>(structures.size()) > popSize + 1 ) { |
| | 1034 | structures.removeLast(); |
| | 1035 | } |
| | 1036 | |
| | 1037 | // Make list of weighted probabilities based on enthalpy values |
| | 1038 | QList<double> probs = getProbabilityList(structures); |
| | 1039 | |
| | 1040 | // Cast Structures into MXtals |
| | 1041 | QList<MolecularXtal*> mxtals; |
| | 1042 | #if QT_VERSION >= 0x040700 |
| | 1043 | mxtals.reserve(structures.size()); |
| | 1044 | #endif // QT_VERSION |
| | 1045 | for (int i = 0; i < structures.size(); ++i) { |
| | 1046 | mxtals.append(qobject_cast<MolecularXtal*>(structures.at(i))); |
| | 1047 | } |
| | 1048 | |
| | 1049 | // Initialize loop vars |
| | 1050 | double r; |
| | 1051 | unsigned int gen; |
| | 1052 | MolecularXtal *mxtal = NULL; |
| | 1053 | |
| | 1054 | // Perform operation until xtal is valid: |
| | 1055 | while (!checkXtal(mxtal)) { |
| | 1056 | // First delete any previous failed structure in xtal |
| | 1057 | if (mxtal) { |
| | 1058 | mxtal->deleteLater(); |
| | 1059 | mxtal = NULL; |
| | 1060 | } |
| | 1061 | |
| | 1062 | // Decide operator: |
| | 1063 | r = RANDDOUBLE(); |
| | 1064 | MXtalOperator op; |
| | 1065 | if (r < mga_p_cross/100.0) |
| | 1066 | op = MXOP_Crossover; |
| | 1067 | else if (r < (mga_p_cross + mga_p_reconf)/100.0) |
| | 1068 | op = MXOP_Reconf; |
| | 1069 | else // if (r < (mga_p_cross + mga_p_reconf + mga_p_swirl)/100.0 |
| | 1070 | op = MXOP_Swirl; |
| | 1071 | |
| | 1072 | // Try 1000 times to get a good structure from the selected |
| | 1073 | // operation. If not possible, send a warning to the log and |
| | 1074 | // start anew. |
| | 1075 | int attemptCount = 0; |
| | 1076 | while (attemptCount < 1000 && !checkXtal(mxtal)) { |
| | 1077 | attemptCount++; |
| | 1078 | if (mxtal) { |
| | 1079 | delete mxtal; |
| | 1080 | mxtal = NULL; |
| | 1081 | } |
| | 1082 | |
| | 1083 | // Select two potential parents |
| | 1084 | int ind1, ind2; |
| | 1085 | MolecularXtal *parent1=0, *parent2=0; |
| | 1086 | // Select structures |
| | 1087 | double r1 = RANDDOUBLE(); |
| | 1088 | double r2 = RANDDOUBLE(); |
| | 1089 | for (ind1 = 0; ind1 < probs.size(); ind1++) |
| | 1090 | if (r1 < probs.at(ind1)) break; |
| | 1091 | for (ind2 = 0; ind2 < probs.size(); ind2++) |
| | 1092 | if (r2 < probs.at(ind2)) break; |
| | 1093 | |
| | 1094 | parent1 = mxtals.at(ind1); |
| | 1095 | parent2 = mxtals.at(ind2); |
| | 1096 | |
| | 1097 | // Operation specific set up: |
| | 1098 | switch (op) { |
| | 1099 | case MXOP_Crossover: |
| | 1100 | mxtal = MXtalOptGenetic::crossover(parent1, parent2, this); |
| | 1101 | break; |
| | 1102 | case MXOP_Reconf: |
| | 1103 | mxtal = MXtalOptGenetic::reconf(parent1, this); |
| | 1104 | break; |
| | 1105 | case MXOP_Swirl: |
| | 1106 | mxtal = MXtalOptGenetic::swirl(parent1, this); |
| | 1107 | break; |
| | 1108 | default: |
| | 1109 | qWarning() << "Unknown genetic operation, enum code:" << op; |
| | 1110 | mxtal = NULL; |
| | 1111 | continue; |
| | 1112 | } |
| | 1113 | |
| | 1114 | // Assign id |
| | 1115 | int gen = mxtal->getGeneration(); |
| | 1116 | int id = 0; |
| | 1117 | for (QList<MolecularXtal*>::const_iterator it = mxtals.constBegin(), |
| | 1118 | it_end = mxtals.constEnd(); it != it_end; ++it) { |
| | 1119 | (*it)->lock()->lockForRead(); |
| | 1120 | const int curGen = (*it)->getGeneration(); |
| | 1121 | const int curId = (*it)->getIDNumber(); |
| | 1122 | (*it)->lock()->unlock(); |
| | 1123 | if (curGen == gen && |
| | 1124 | curId >= id) { |
| | 1125 | id = curId + 1; |
| | 1126 | } |
| | 1127 | } |
| | 1128 | mxtal->setIDNumber(id); |
| | 1129 | |
| | 1130 | } |
| | 1131 | if (attemptCount >= 1000) { |
| | 1132 | QString opStr; |
| | 1133 | switch (op) { |
| | 1134 | case MXOP_Crossover: opStr = "crossover"; break; |
| | 1135 | case MXOP_Reconf: opStr = "reconf"; break; |
| | 1136 | case MXOP_Swirl: opStr = "swirl"; break; |
| | 1137 | default: opStr = "(unknown)"; break; |
| | 1138 | } |
| | 1139 | warning(tr("Unable to perform operation %1 after 1000 tries. " |
| | 1140 | "Reselecting operator...").arg(opStr)); |
| | 1141 | } |
| | 1142 | } |
| | 1143 | |
| | 1144 | return mxtal; |