/* * Removes an entry from a unit-to-identifier map. * * Arguments: * map Pointer to the unit-to-identifier map. * unit The unit. May be freed upon return. * encoding The encoding to be removed. * Returns: * UT_SUCCESS Success. */ static ut_status utimRemove( UnitToIdMap* const map, const ut_unit* unit, ut_encoding encoding) { ut_status status; UnitAndId targetEntry; UnitAndId** treeEntry; assert(map != NULL); assert(unit != NULL); targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, selectTree(map, encoding), compareUnits); if (treeEntry == NULL || *treeEntry == NULL) { status = UT_SUCCESS; } else { UnitAndId* uai = *treeEntry; (void)tdelete(uai, selectTree(map, encoding), compareUnits); uaiFree(uai); } return status; }
/* * Adds an entry to a unit-to-identifier map. * * Arguments: * map Pointer to unit-to-identifier map. * unit The unit. May be freed upon return. * id The identifier. May be freed upon return. * encoding The ostensible encoding of "id". * Returns: * UT_BAD_ARG "id" is inconsistent with "encoding". * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a different identifier. * UT_SUCCESS Success. */ static ut_status utimAdd( UnitToIdMap* const map, const ut_unit* unit, const char* const id, ut_encoding encoding) { ut_status status; assert(map != NULL); assert(unit != NULL); assert(id != NULL); if (adjustEncoding(&encoding, id)) { status = UT_BAD_ARG; ut_set_status(status); ut_handle_error_message("Identifier not in given encoding"); } else { UnitAndId* targetEntry = uaiNew(unit, id); if (targetEntry != NULL) { void** rootp = selectTree(map, encoding); UnitAndId** treeEntry = tsearch(targetEntry, rootp, compareUnits); if (treeEntry == NULL) { status = UT_OS; ut_set_status(status); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't add search-tree entry"); uaiFree(targetEntry); } else { if (strcmp((*treeEntry)->id, id) != 0) { status = UT_EXISTS; ut_set_status(status); ut_handle_error_message("Unit already maps to \"%s\"", (*treeEntry)->id); } else { status = UT_SUCCESS; } if (targetEntry != *treeEntry) uaiFree(targetEntry); } } /* "targetEntry" allocated */ } /* valid arguments */ return status; }
/* * Frees a unit-to-identifier map. All entries in all encodings are freed. * * Arguments: * map Pointer to the map to be freed. */ static void utimFree( UnitToIdMap* map) { if (map != NULL) { ut_encoding encodings[] = {UT_ASCII, UT_LATIN1, UT_UTF8}; int i; for (i = 0; i < sizeof(encodings)/sizeof(encodings[0]); ++i) { void** rootp = selectTree(map, encodings[i]); while (*rootp != NULL) { UnitAndId* uai = **(UnitAndId***)rootp; (void)tdelete(uai, rootp, compareUnits); uaiFree(uai); } } free(map); } }
// Autocreate patterns bool Model::createPatterns() { // Determine the pattern (molecule) layout of the model Messenger::enter("Model::createPatterns"); int n, atomid, nsel2, nmols, idi, idj, idoff, count; bool same; QString empirical; Clipboard patclip; Pattern* p; RefListItem<Bond,int>* rb; Atom* i, *selectSource; ClipAtom* clipi; RefListItem<Atom,int>* isel; // Check current pattern first... if (arePatternsValid()) { Messenger::exit("Model::createPatterns"); return true; } // Delete all old nodes first. Messenger::print("Autodetecting patterns for model '%s'..", qPrintable(name_)); patterns_.clear(); // If there are no atoms in the molecule, exit here. if (atoms_.nItems() == 0) { Messenger::print("No patterns defined for model '%s' - no atoms present.", qPrintable(name_)); patternsPoint_ = log(Log::Structure); Messenger::exit("Model::createPatterns"); return true; } // To autodetect, we start off at the first atom in the model, tree-select this atom and copy the selection to the clipboard. Use the clipboard to check subsequent selections, and if its the same just increase the nmols counter by one. If it's different, assume its the start of a new type of molecule and reset the counters. atomid = 0; nmols = 0; i = atoms_.first(); while (atomid != atoms_.nItems()) { selectNone(true); // Select molecule starting at atom 'i' and calculate fingerprint selectTree(i, true); selectSource = i; // We insist that the molecule consists of consecutively ordered atoms, otherwise we can't proceed, so count the number of selected // atoms in those that we now skip (if != nselected then we must force a 1*N pattern) nsel2 = 0; atomid += marked_.nItems(); //selectionGetEmpirical(emp); for (n=0; n<marked_.nItems(); n++) { if (i->isSelected(true)) nsel2 ++; i = i->next; } if (nsel2 != marked_.nItems()) { Messenger::error("Pattern creation failed because of bad atom ordering or the presence of additional bonds."); Messenger::error("Problem occurred in pattern %i whilst selecting from atom %i.", patterns_.nItems()+1, selectSource->id()+1); // Remove any patterns added so far patterns_.clear(); nmols = 0; Messenger::exit("Model::createPatterns"); return false; } // If this is the first pass (molecule), copy the selection. If not, compare it if (nmols == 0) { patclip.copyMarked(this); empirical = selectionEmpirical(true); nmols = 1; } else { // Compare clipboard contents with current selection same = true; // Check number of atoms first.... if (marked_.nItems() != patclip.nAtoms()) same = false; else { // Atoms clipi = patclip.atoms(); for (isel = marked_.first(); isel != NULL; isel = isel->next) { count++; // Element check if (clipi->atom().element() != isel->item->element()) { same = false; break; } // Fixed position if (clipi->atom().isPositionFixed() != isel->item->isPositionFixed()) { same = false; break; } // Fixed forcefield type check if (clipi->atom().hasFixedType() != isel->item->hasFixedType()) { same = false; break; } else if (clipi->atom().hasFixedType()) { // Both have fixed type - make sure types are the same if (clipi->atom().type() != isel->item->type()) { same = false; break; } } clipi = clipi->next; } // Bonding between atoms (but only if atoms themselves check out)... if (same) { idoff = selection(true)->item->id(); count = 0; for (isel = marked_.first(); isel != NULL; isel = isel->next) { // Convert IDs so they start at zero (i.e. subtract ID of current atom 'i') idi = isel->item->id() - idoff; for (rb = isel->item->bonds(); rb != NULL; rb = rb->next) { idj = rb->item->partner(isel->item)->id() - idoff; if (idi < idj) continue; ++count; if (!patclip.hasBond(idi,idj)) { same = false; break; } } if (!same) break; } // Check for difference between number of bonds between marked atoms and clipboard atoms if (count != patclip.nBonds()) same = false; } } // If we get to here with same == true then we increase nmols. Otherwise, we create a new pattern. if (same) ++nmols; else { // Not the same as the last stored pattern, so store old data and start a new one Messenger::print(Messenger::Verbose, "New pattern found: %s", qPrintable(empirical)); p = addPattern(qPrintable(empirical), nmols, patclip.nAtoms()); patclip.copyMarked(this); empirical = selectionEmpirical(true); nmols = 1; } } } // Store last pattern data if (nmols != 0) { Messenger::print(Messenger::Verbose, "New pattern found: %s", qPrintable(empirical)); p = addPattern(qPrintable(empirical), nmols, patclip.nAtoms()); } // Describe the atoms / rings in the patterns describeAtoms(); // Patterns depend only on the properties / relation of the atoms, and not the positions.. patternsPoint_ = log(Log::Structure); Messenger::exit("Model::createPatterns"); return true; }