use of cbit.vcell.mathmodel.MathModelMetaData in project vcell by virtualcell.
the class ServerDocumentManager method saveMathModel.
/**
* Insert the method's description here.
* Creation date: (10/28/00 12:08:30 AM)
*/
public String saveMathModel(QueryHashtable dbc, User user, String mathModelXML, String newName, String[] independentSims) throws DataAccessException, java.sql.SQLException, java.beans.PropertyVetoException, cbit.vcell.xml.XmlParseException {
//
// this invokes "update" on the database layer
//
MathModel mathModel = XmlHelper.XMLToMathModel(new XMLSource(mathModelXML));
forceDeepDirtyIfForeign(user, mathModel);
boolean isSaveAsNew = true;
//
if (newName != null) {
try {
mathModel.setName(newName);
} catch (java.beans.PropertyVetoException e) {
e.printStackTrace(System.out);
throw new DataAccessException("couldn't set new name for MathModel: " + e.getMessage());
}
} else {
isSaveAsNew = false;
}
Version oldVersion = mathModel.getVersion();
MathModel origMathModel = null;
if (oldVersion != null) {
try {
String origMathModelXML = getMathModelXML(dbc, user, oldVersion.getVersionKey(), false);
origMathModel = XmlHelper.XMLToMathModel(new XMLSource(origMathModelXML));
} catch (ObjectNotFoundException nfe) {
if (isSaveAsNew) {
User foceClearVersionUser = new User("foceClearVersionUser", new KeyValue("0"));
forceDeepDirtyIfForeign(foceClearVersionUser, mathModel);
} else {
throw new DataAccessException("Stored model has been changed or removed, please use 'Save As..'");
}
}
}
boolean bSomethingChanged = false;
//
// UPDATE AND SUBSTITUTE FROM BOTTOM UP
//
// Image->Geometry
// Geometry->MathDescription
// MathDescription->Simulation,MathModel
// Simulation->MathModel
//
Simulation[] simArray = mathModel.getSimulations();
//
// if this mathModel has an image:
// save if necessary (only once) and store saved instance in hashTable
//
Hashtable<Versionable, Versionable> memoryToDatabaseHash = new Hashtable<Versionable, Versionable>();
{
VCImage memoryImage = mathModel.getMathDescription().getGeometry().getGeometrySpec().getImage();
if (memoryImage != null) {
// defaults to unchanged
memoryToDatabaseHash.put(memoryImage, memoryImage);
if (memoryImage.getKey() != null && memoryImage.getVersion().getName().equals(memoryImage.getName())) {
//
// if image had previously been saved, not been forced 'dirty', and name not changed
// compare with original image to see if "update" is required.
//
VCImage databaseImage = null;
if (origMathModel != null) {
VCImage origImage = origMathModel.getMathDescription().getGeometry().getGeometrySpec().getImage();
if (origImage != null && origImage.getKey().equals(memoryImage.getKey())) {
databaseImage = origImage;
}
}
if (databaseImage == null) {
//
// saved image not found in origMathModel (too bad), get from database.
//
databaseImage = dbServer.getDBTopLevel().getVCImage(dbc, user, memoryImage.getKey(), false);
}
if (databaseImage != null && !databaseImage.compareEqual(memoryImage)) {
KeyValue updatedImageKey = dbServer.getDBTopLevel().updateVersionable(user, memoryImage, false, true);
VCImage updatedImage = dbServer.getDBTopLevel().getVCImage(dbc, user, updatedImageKey, false);
memoryToDatabaseHash.put(memoryImage, updatedImage);
bSomethingChanged = true;
}
} else {
//
// Image hasn't been saved, has been renamed, or has been forced 'dirty'
// insert it with a unique name
//
int count = 0;
fixNullImageName(memoryImage);
while (dbServer.getDBTopLevel().isNameUsed(user, VersionableType.VCImage, memoryImage.getName(), true)) {
try {
memoryImage.setName(TokenMangler.getNextRandomToken(memoryImage.getName()));
} catch (java.beans.PropertyVetoException e) {
e.printStackTrace(System.out);
}
if (count++ > 5) {
throw new DataAccessException("failed to find unique image name '" + memoryImage.getName() + "' is last name tried");
}
}
KeyValue updatedImageKey = dbServer.getDBTopLevel().insertVersionable(user, memoryImage, memoryImage.getName(), false, true);
VCImage updatedImage = dbServer.getDBTopLevel().getVCImage(dbc, user, updatedImageKey, false);
memoryToDatabaseHash.put(memoryImage, updatedImage);
bSomethingChanged = true;
}
}
}
//
// for the Geometry:
// substitute saved Image into Geometry and
// save Geometry if necessary (only once) and store saved instance in hashtable.
//
{
Geometry memoryGeometry = mathModel.getMathDescription().getGeometry();
// defaults to unchanged
memoryToDatabaseHash.put(memoryGeometry, memoryGeometry);
boolean bMustSaveGeometry = false;
VCImage geometryImage = memoryGeometry.getGeometrySpec().getImage();
if (geometryImage != null && memoryToDatabaseHash.get(geometryImage) != geometryImage) {
//
// image had changed and was saved, load saved image into geometry and force a save of this geometry.
//
memoryGeometry.getGeometrySpec().setImage((VCImage) memoryToDatabaseHash.get(geometryImage));
geometryImage = (VCImage) memoryToDatabaseHash.get(geometryImage);
bMustSaveGeometry = true;
}
if (memoryGeometry.getKey() != null && memoryGeometry.getVersion().getName().equals(memoryGeometry.getName())) {
if (!bMustSaveGeometry) {
//
// if geometry had previously been saved, not been forced 'dirty', and name not changed
// compare with original geometry to see if "update" is required.
//
Geometry databaseGeometry = null;
if (origMathModel != null) {
Geometry origGeometry = origMathModel.getMathDescription().getGeometry();
if (origGeometry.getKey().equals(memoryGeometry.getKey())) {
databaseGeometry = origGeometry;
}
}
if (databaseGeometry == null) {
//
// saved geometry not found in origMathModel (too bad), get from database.
//
databaseGeometry = dbServer.getDBTopLevel().getGeometry(dbc, user, memoryGeometry.getKey(), false);
}
if (databaseGeometry != null && !databaseGeometry.compareEqual(memoryGeometry)) {
bMustSaveGeometry = true;
}
}
if (bMustSaveGeometry) {
KeyValue updatedImageKey = (geometryImage != null) ? (geometryImage.getKey()) : (null);
KeyValue updatedGeometryKey = dbServer.getDBTopLevel().updateVersionable(dbc, user, memoryGeometry, updatedImageKey, false, true);
Geometry updatedGeometry = dbServer.getDBTopLevel().getGeometry(dbc, user, updatedGeometryKey, false);
memoryToDatabaseHash.put(memoryGeometry, updatedGeometry);
bSomethingChanged = true;
}
} else {
//
// Geometry hasn't been saved, has been renamed, or has been forced 'dirty'
// insert it with a unique name
//
int count = 0;
while (dbServer.getDBTopLevel().isNameUsed(user, VersionableType.Geometry, memoryGeometry.getName(), true)) {
try {
memoryGeometry.setName(TokenMangler.getNextRandomToken(memoryGeometry.getName()));
} catch (java.beans.PropertyVetoException e) {
e.printStackTrace(System.out);
}
if (count++ > 5) {
throw new DataAccessException("failed to find unique geometry name '" + memoryGeometry.getName() + "' is last name tried");
}
}
KeyValue updatedImageKey = (geometryImage != null) ? (geometryImage.getKey()) : (null);
KeyValue updatedGeometryKey = dbServer.getDBTopLevel().insertVersionable(dbc, user, memoryGeometry, updatedImageKey, memoryGeometry.getName(), false, true);
Geometry updatedGeometry = dbServer.getDBTopLevel().getGeometry(dbc, user, updatedGeometryKey, false);
memoryToDatabaseHash.put(memoryGeometry, updatedGeometry);
bSomethingChanged = true;
}
}
//
// for the MathDescription:
// substitute saved geometry into MathDescription
// save MathDescription if necessary (only once) and store saved instance in hashtable.
//
MathCompareResults mathCompareResults = null;
{
MathDescription memoryMathDescription = mathModel.getMathDescription();
// defaults to unchanged
memoryToDatabaseHash.put(memoryMathDescription, memoryMathDescription);
boolean bMustSaveMathDescription = false;
Geometry scGeometry = memoryMathDescription.getGeometry();
if (scGeometry != null && memoryToDatabaseHash.get(scGeometry) != scGeometry) {
//
// geometry had changed and was saved, load saved geometry into SimulationContext (and it's MathDescription) and force a save of this SimulationContext.
//
memoryMathDescription.setGeometry((Geometry) memoryToDatabaseHash.get(scGeometry));
bMustSaveMathDescription = true;
}
MathDescription databaseMathDescription = null;
if (memoryMathDescription.getKey() != null) {
//
if (origMathModel != null) {
MathDescription origMathDescription = origMathModel.getMathDescription();
if (origMathDescription.getKey().equals(memoryMathDescription.getKey())) {
databaseMathDescription = origMathDescription;
}
}
if (databaseMathDescription == null) {
//
// saved mathDescription not found in origMathModel (too bad), get from database.
//
databaseMathDescription = dbServer.getDBTopLevel().getMathDescription(dbc, user, memoryMathDescription.getKey());
}
if (databaseMathDescription != null) {
if (!memoryMathDescription.compareEqual(databaseMathDescription)) {
bMustSaveMathDescription = true;
}
}
} else {
bMustSaveMathDescription = true;
}
if (bMustSaveMathDescription) {
//
if (databaseMathDescription != null) {
try {
mathCompareResults = MathDescription.testEquivalency(SimulationSymbolTable.createMathSymbolTableFactory(), memoryMathDescription, databaseMathDescription);
} catch (Exception e) {
e.printStackTrace(System.out);
mathCompareResults = new MathCompareResults(Decision.MathDifferent_FAILURE_UNKNOWN, "Exception: '" + e.getMessage() + "'");
System.out.println("FAILED TO COMPARE THE FOLLOWING MATH DESCRIPTIONS");
try {
System.out.println("MemoryMathDescription:\n" + ((memoryMathDescription != null) ? (memoryMathDescription.getVCML_database()) : ("null")));
System.out.println("DatabaseMathDescription:\n" + ((databaseMathDescription != null) ? (databaseMathDescription.getVCML_database()) : ("null")));
} catch (Exception e2) {
System.out.println("couldn't print math descriptions");
}
}
} else {
mathCompareResults = new MathCompareResults(Decision.MathDifferent_NOT_SAVED);
}
KeyValue updatedGeometryKey = memoryMathDescription.getGeometry().getKey();
KeyValue updatedMathDescriptionKey = null;
if (memoryMathDescription.getVersion() != null && memoryMathDescription.getVersion().getName().equals(memoryMathDescription.getName())) {
updatedMathDescriptionKey = dbServer.getDBTopLevel().updateVersionable(user, memoryMathDescription, updatedGeometryKey, false, true);
} else {
updatedMathDescriptionKey = dbServer.getDBTopLevel().insertVersionable(user, memoryMathDescription, updatedGeometryKey, memoryMathDescription.getName(), false, true);
}
MathDescription updatedMathDescription = dbServer.getDBTopLevel().getMathDescription(dbc, user, updatedMathDescriptionKey);
memoryToDatabaseHash.put(memoryMathDescription, updatedMathDescription);
bSomethingChanged = true;
} else {
mathCompareResults = new MathCompareResults(Decision.MathEquivalent_SAME_MATHDESC_AS_IN_DB);
}
}
//
for (int i = 0; simArray != null && i < simArray.length; i++) {
Simulation memorySimulation = simArray[i];
if (!memoryToDatabaseHash.containsKey(memorySimulation)) {
//
// didn't evaluate this Simulation yet.
//
// defaults to unchanged
memoryToDatabaseHash.put(memorySimulation, memorySimulation);
boolean bMustSaveSimulation = false;
MathDescription simMathDescription = memorySimulation.getMathDescription();
if (simMathDescription != null && memoryToDatabaseHash.get(simMathDescription) != simMathDescription) {
if (memoryToDatabaseHash.get(simMathDescription) != null) {
// make sure mathDescription hasn't already propagated (newer math won't be in hashtable)
//
// mathDescription had changed and was saved, load saved mathDescription into SimulationContext (and force a save)
//
memorySimulation.setMathDescription((MathDescription) memoryToDatabaseHash.get(simMathDescription));
bMustSaveSimulation = true;
}
}
Simulation databaseSimulation = null;
//
if (memorySimulation.getKey() != null) {
if (origMathModel != null) {
for (int j = 0; j < origMathModel.getNumSimulations(); j++) {
if (origMathModel.getSimulations(j).getKey().equals(memorySimulation.getKey())) {
databaseSimulation = origMathModel.getSimulations(j);
break;
}
}
}
if (databaseSimulation == null) {
//
// saved simulation not found in origBioModel (too bad), get from database.
//
databaseSimulation = dbServer.getDBTopLevel().getSimulation(dbc, user, memorySimulation.getKey());
}
if (databaseSimulation != null && !databaseSimulation.compareEqual(memorySimulation)) {
bMustSaveSimulation = true;
}
if (!memorySimulation.getVersion().getName().equals(memorySimulation.getName())) {
// name was changed.
bMustSaveSimulation = true;
}
} else {
// never been saved.
bMustSaveSimulation = true;
}
if (bMustSaveSimulation) {
KeyValue updatedMathDescriptionKey = memorySimulation.getMathDescription().getKey();
KeyValue updatedSimulationKey = null;
boolean bSimMathematicallyEquivalent = false;
if (databaseSimulation != null) {
//
// if to be forced "independent", then set equivalent to false
//
boolean bForceIndependent = false;
for (int j = 0; independentSims != null && j < independentSims.length; j++) {
if (independentSims[j].equals(memorySimulation.getName())) {
bForceIndependent = true;
}
}
// check for math equivalency
try {
bSimMathematicallyEquivalent = !bForceIndependent && Simulation.testEquivalency(memorySimulation, databaseSimulation, mathCompareResults);
} catch (Exception e) {
e.printStackTrace(System.out);
throw new DataAccessException(e.getMessage());
}
//
if (bSimMathematicallyEquivalent) {
VCSimulationIdentifier vcSimulationIdentifier = databaseSimulation.getSimulationInfo().getAuthoritativeVCSimulationIdentifier();
SimulationStatusPersistent simStatus = dbServer.getSimulationStatus(vcSimulationIdentifier.getSimulationKey());
if (simStatus == null || !simStatus.getHasData()) {
bSimMathematicallyEquivalent = false;
}
}
}
if (memorySimulation.getKey() != null && memorySimulation.getVersion().getName().equals(memorySimulation.getName())) {
// name not changed, update simulation (but pass in database Simulation to check for parent-equivalence)
updatedSimulationKey = dbServer.getDBTopLevel().updateVersionable(user, memorySimulation, updatedMathDescriptionKey, false, bSimMathematicallyEquivalent, true);
} else {
// name changed, insert simulation (but pass in database Simulation to check for parent-equivalence)
updatedSimulationKey = dbServer.getDBTopLevel().insertVersionable(user, memorySimulation, updatedMathDescriptionKey, memorySimulation.getName(), false, bSimMathematicallyEquivalent, true);
}
Simulation updatedSimulation = dbServer.getDBTopLevel().getSimulation(dbc, user, updatedSimulationKey);
memoryToDatabaseHash.put(memorySimulation, updatedSimulation);
bSomethingChanged = true;
}
}
}
if (bSomethingChanged || origMathModel == null || !mathModel.compareEqual(origMathModel)) {
//
// create new MathModelMetaData and save to server
//
KeyValue mathDescriptionKey = ((MathDescription) memoryToDatabaseHash.get(mathModel.getMathDescription())).getKey();
KeyValue[] simKeys = new KeyValue[mathModel.getNumSimulations()];
for (int i = 0; i < mathModel.getNumSimulations(); i++) {
simKeys[i] = ((Simulation) memoryToDatabaseHash.get(mathModel.getSimulations(i))).getKey();
}
MathModelMetaData mathModelMetaData = null;
if (oldVersion == null) {
mathModelMetaData = new MathModelMetaData(mathDescriptionKey, simKeys, mathModel.getName(), mathModel.getDescription(), mathModel.getOutputFunctionContext().getOutputFunctionsList());
} else {
mathModelMetaData = new MathModelMetaData(oldVersion, mathDescriptionKey, simKeys, mathModel.getOutputFunctionContext().getOutputFunctionsList());
if (!mathModel.getDescription().equals(oldVersion.getAnnot())) {
try {
mathModelMetaData.setDescription(mathModel.getDescription());
} catch (java.beans.PropertyVetoException e) {
e.printStackTrace(System.out);
}
}
}
MathModelMetaData updatedMathModelMetaData = null;
if (mathModel.getVersion() == null || !mathModel.getVersion().getName().equals(mathModel.getName())) {
KeyValue updatedMathModelKey = dbServer.getDBTopLevel().insertVersionable(user, mathModelMetaData, null, /*hack*/
mathModel.getName(), false, true);
updatedMathModelMetaData = dbServer.getDBTopLevel().getMathModelMetaData(dbc, user, updatedMathModelKey);
} else {
KeyValue updatedMathModelKey = dbServer.getDBTopLevel().updateVersionable(user, mathModelMetaData, null, /*hack*/
false, true);
updatedMathModelMetaData = dbServer.getDBTopLevel().getMathModelMetaData(dbc, user, updatedMathModelKey);
}
//
// (THIS IS THE REALLY SCARY PART...NOT GETTING A FRESH VIEW OF EVERYTING FROM THE DATABASE FOR CREATING THE XML)
//
// mathModelXML = getMathModelXML(user,updatedMathModelMetaData.getVersion().getVersionKey());
MathModel updatedMathModel = new MathModel(updatedMathModelMetaData.getVersion());
updatedMathModel.setMathDescription((MathDescription) memoryToDatabaseHash.get(mathModel.getMathDescription()));
for (int i = 0; i < mathModel.getNumSimulations(); i++) {
updatedMathModel.addSimulation((Simulation) memoryToDatabaseHash.get(mathModel.getSimulations(i)));
}
updatedMathModel.getOutputFunctionContext().setOutputFunctions(mathModel.getOutputFunctionContext().getOutputFunctionsList());
mathModelXML = cbit.vcell.xml.XmlHelper.mathModelToXML(updatedMathModel);
dbServer.insertVersionableChildSummary(user, VersionableType.MathModelMetaData, updatedMathModel.getVersion().getVersionKey(), updatedMathModel.createMathModelChildSummary().toDatabaseSerialization());
dbServer.insertVersionableXML(user, VersionableType.MathModelMetaData, updatedMathModel.getVersion().getVersionKey(), mathModelXML);
return mathModelXML;
} else {
return mathModelXML;
}
}
use of cbit.vcell.mathmodel.MathModelMetaData in project vcell by virtualcell.
the class ServerDocumentManager method getMathModelUnresolved.
/**
* Insert the method's description here.
* Creation date: (11/14/00 4:02:44 PM)
* @return cbit.vcell.biomodel.BioModel
* @param bioModelInfo cbit.vcell.biomodel.BioModelInfo
*/
//
// this returns a MathModel that has duplicate instances of the same objects
//
public MathModel getMathModelUnresolved(QueryHashtable dbc, User user, KeyValue mathModelKey) throws DataAccessException, java.sql.SQLException {
//
// get meta data associated with MathModel
//
MathModelMetaData mathModelMetaData = dbServer.getMathModelMetaData(user, mathModelKey);
//
// get list of appropriate child components
//
KeyValue mathDescriptionKey = mathModelMetaData.getMathKey();
KeyValue[] simKeys = getKeyArrayFromEnumeration(mathModelMetaData.getSimulationKeys());
MathDescription mathDescription = dbServer.getDBTopLevel().getMathDescription(dbc, user, mathDescriptionKey);
Simulation[] simArray = new Simulation[simKeys.length];
for (int i = 0; i < simKeys.length; i++) {
Simulation sim = dbServer.getDBTopLevel().getSimulation(dbc, user, simKeys[i]);
//
try {
simArray[i] = (Simulation) BeanUtils.cloneSerializable(sim);
} catch (Throwable e) {
throw new RuntimeException("exception cloning Simulation: " + e.getMessage());
}
if (!simArray[i].getMathDescription().getKey().compareEqual(mathDescriptionKey)) {
// throw new DataAccessException("simulation("+simKeys[i]+").mathDescription = "+simArray[i].getMathDescription().getKey()+", MathModel.mathDescription = "+mathDescriptionKey);
System.out.println("ClientDocumentManager.getMathModel(), simulation(" + simKeys[i] + ").mathDescription = " + simArray[i].getMathDescription().getKey() + ", MathModel.mathDescription = " + mathDescriptionKey);
}
}
//
// create new MathModel according to loaded MathModelMetaData
//
MathModel newMathModel = new MathModel(mathModelMetaData.getVersion());
try {
newMathModel.setMathDescription(mathDescription);
newMathModel.setSimulations(simArray);
ArrayList<AnnotatedFunction> outputFunctions = mathModelMetaData.getOutputFunctions();
if (outputFunctions != null) {
newMathModel.getOutputFunctionContext().setOutputFunctions(outputFunctions);
}
} catch (java.beans.PropertyVetoException e) {
throw new DataAccessException("PropertyVetoException caught " + e.getMessage());
}
//
try {
newMathModel = (MathModel) BeanUtils.cloneSerializable(newMathModel);
} catch (Exception e) {
e.printStackTrace(System.out);
throw new DataAccessException("MathModel clone failed: " + e.getMessage());
}
newMathModel.refreshDependencies();
//
return newMathModel;
}
use of cbit.vcell.mathmodel.MathModelMetaData in project vcell by virtualcell.
the class MathModelDbDriver method getMathModelMetaData.
/**
* getModel method comment.
*/
private MathModelMetaData getMathModelMetaData(Connection con, User user, KeyValue mathModelKey) throws SQLException, DataAccessException, ObjectNotFoundException {
if (user == null || mathModelKey == null) {
throw new IllegalArgumentException("Improper parameters for getMathModelMetaData");
}
if (lg.isTraceEnabled())
lg.trace("MathModelDbDriver.getMathModelMetaData(user=" + user + ", id=" + mathModelKey + ")");
//
// to construct a MathModelMetaData as an immutable object, lets collect all keys first
// (even before authentication). If the user doesn't authenticate, then throw away the
// child keys (from link tables).
//
//
// get Simulation Keys for mathModelKey
//
KeyValue[] simKeys = getSimulationEntriesFromMathModel(con, mathModelKey);
//
// get MathModelMetaData object for mathModelKey
//
String sql;
Field[] f = { new cbit.sql.StarField(mathModelTable), userTable.userid };
Table[] t = { mathModelTable, userTable };
String condition = mathModelTable.id.getQualifiedColName() + " = " + mathModelKey + " AND " + userTable.id.getQualifiedColName() + " = " + mathModelTable.ownerRef.getQualifiedColName();
sql = DatabasePolicySQL.enforceOwnershipSelect(user, f, t, (OuterJoin) null, condition, null, dbSyntax, true);
Statement stmt = con.createStatement();
MathModelMetaData mathModelMetaData = null;
try {
ResultSet rset = stmt.executeQuery(sql);
if (rset.next()) {
mathModelMetaData = mathModelTable.getMathModelMetaData(rset, con, simKeys, dbSyntax);
} else {
throw new ObjectNotFoundException("MathModel id=" + mathModelKey + " not found for user '" + user + "'");
}
} finally {
// Release resources include resultset
stmt.close();
}
return mathModelMetaData;
}
use of cbit.vcell.mathmodel.MathModelMetaData in project vcell by virtualcell.
the class MathModelTable method getMathModelMetaData.
/**
* This method was created in VisualAge.
* @return cbit.vcell.math.MathDescription
* @param user cbit.vcell.server.User
* @param rset java.sql.ResultSet
*/
public MathModelMetaData getMathModelMetaData(ResultSet rset, MathModelDbDriver mathModelDbDriver, Connection con, DatabaseSyntax dbSyntax) throws SQLException, DataAccessException {
//
// Get Version
//
java.math.BigDecimal groupid = rset.getBigDecimal(VersionTable.privacy_ColumnName);
Version version = getVersion(rset, DbDriver.getGroupAccessFromGroupID(con, groupid));
KeyValue mathModelKey = version.getVersionKey();
KeyValue mathRef = new KeyValue(rset.getBigDecimal(table.mathRef.toString()));
//
// get Simulation Keys for bioModelKey
//
KeyValue[] simKeys = mathModelDbDriver.getSimulationEntriesFromMathModel(con, mathModelKey);
// MathModelMetaData mathModelMetaData = new MathModelMetaData(version,mathRef,simKeys);
MathModelMetaData mathModelMetaData = populateOutputFunctions(con, mathRef, version, simKeys, dbSyntax);
return mathModelMetaData;
}
Aggregations