Skip to content

Commit

Permalink
- prepare time events
Browse files Browse the repository at this point in the history
git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@19219 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
lochel committed Feb 20, 2014
1 parent e94dab9 commit 6128548
Show file tree
Hide file tree
Showing 19 changed files with 263 additions and 248 deletions.
31 changes: 19 additions & 12 deletions Compiler/BackEnd/BackendDAE.mo
Expand Up @@ -413,11 +413,11 @@ end StateSet;
public
uniontype EventInfo
record EVENT_INFO
SampleLookup sampleLookup "stores all information regarding sample-calls" ;
list<TimeEvent> timeEvents "stores all information regarding time events" ;
list<WhenClause> whenClauseLst "list of when clauses. The WhenEquation datatype refer to this list by position" ;
list<ZeroCrossing> zeroCrossingLst "list of zero crossing coditions";
// TODO: sampleLst and relationsLst could be removed if cpp runtime is prepared to handle zero crossing conditions
list<ZeroCrossing> sampleLst "list of sample as before, used by cpp runtime";
// TODO: relationsLst could be removed if cpp runtime is prepared to handle zero-crossing conditions
list<ZeroCrossing> relationsLst "list of zero crossing function as before, used by cpp runtime";
Integer relationsNumber "stores the number of relation in all zero-crossings";
Integer numberMathEvents "stores the number of math function that trigger events e.g. floor, ceil, integer, ...";
Expand Down Expand Up @@ -477,12 +477,19 @@ uniontype ZeroCrossing
end ZeroCrossing;

public
uniontype SampleLookup
record SAMPLE_LOOKUP
Integer nSamples "total number of different sample calls" ;
list<tuple<Integer, .DAE.Exp, .DAE.Exp>> lookup "sample arguments (index, start, interval)" ;
end SAMPLE_LOOKUP;
end SampleLookup;
uniontype TimeEvent
record SIMPLE_TIME_EVENT "e.g. time > 0.5"
end SIMPLE_TIME_EVENT;

record COMPLEX_TIME_EVENT "e.g. sin(time) > 0.1"
end COMPLEX_TIME_EVENT;

record SAMPLE_TIME_EVENT "e.g. sample(1, 1)"
Integer index "unique sample index" ;
.DAE.Exp startExp;
.DAE.Exp intervalExp;
end SAMPLE_TIME_EVENT;
end TimeEvent;

//
// AdjacencyMatrixes
Expand Down Expand Up @@ -589,10 +596,10 @@ type SparseColoring = list<list< .DAE.ComponentRef>>; // coloring
public
uniontype DifferentiateInputData
record DIFFINPUTDATA
Option<Variables> independenentVars; // Independent variables
Option<Variables> dependenentVars; // Dependent variables
Option<Variables> knownVars; // known variables (e.g. parameter, constants, ...)
Option<Variables> allVars; // all variables
Option<Variables> independenentVars; // Independent variables
Option<Variables> dependenentVars; // Dependent variables
Option<Variables> knownVars; // known variables (e.g. parameter, constants, ...)
Option<Variables> allVars; // all variables
Option<list< Var>> controlVars; // variables to save control vars of for algorithm
Option<list< .DAE.ComponentRef>> diffCrefs; // all crefs to differentiate, needed for generic gradient
Option<String> matrixName; // name to create tempory vars, needed for generic gradient
Expand Down
54 changes: 26 additions & 28 deletions Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -104,15 +104,15 @@ protected
list<DAE.Element> elems, aliaseqns;
list<BackendDAE.ZeroCrossing> zero_crossings;
DAE.FunctionTree functionTree;
BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
String neqStr,nvarStr;
algorithm
System.realtimeTick(GlobalScript.RT_CLOCK_EXECSTAT_BACKEND_MODULES);
// reset dumped file sequence number
System.tmpTickResetIndex(0, Global.backendDAE_fileSequence);
Debug.execStat("Enter Backend", GlobalScript.RT_CLOCK_EXECSTAT_BACKEND_MODULES);
functionTree := Env.getFunctionTree(inCache);
(DAE.DAE(elems), functionTree, sampleLookup) := processBuiltinExpressions(lst, functionTree);
(DAE.DAE(elems), functionTree, timeEvents) := processBuiltinExpressions(lst, functionTree);
vars := BackendVariable.emptyVars();
knvars := BackendVariable.emptyVars();
extVars := BackendVariable.emptyVars();
Expand All @@ -127,7 +127,7 @@ algorithm
eqnarr := BackendEquation.listEquation(eqns);
reqnarr := BackendEquation.listEquation(reqns);
ieqnarr := BackendEquation.listEquation(ieqns);
einfo := BackendDAE.EVENT_INFO(sampleLookup, whenclauses_1, {}, {}, {}, 0, 0);
einfo := BackendDAE.EVENT_INFO(timeEvents, whenclauses_1, {}, {}, {}, 0, 0);
symjacs := {(NONE(), ({}, ({}, {})), {}), (NONE(), ({}, ({}, {})), {}), (NONE(), ({}, ({}, {})), {}), (NONE(), ({}, ({}, {})), {})};
outBackendDAE := BackendDAE.DAE(BackendDAE.EQSYSTEM(vars_1,
eqnarr,
Expand Down Expand Up @@ -439,63 +439,61 @@ protected function processBuiltinExpressions "author: lochel
input DAE.FunctionTree functionTree;
output DAE.DAElist outDAE;
output DAE.FunctionTree outTree;
output BackendDAE.SampleLookup outSampleLookup;
output list<BackendDAE.TimeEvent> outTimeEvents;
protected
HashTableExpToIndex.HashTable ht;
algorithm
ht := HashTableExpToIndex.emptyHashTable();
(outDAE, outTree, (ht, _, outSampleLookup)) := DAEUtil.traverseDAE(inDAE, functionTree, transformBuiltinExpressions, (ht, 0, BackendDAE.SAMPLE_LOOKUP(0, {})));
(outDAE, outTree, (ht, _, _, outTimeEvents)) := DAEUtil.traverseDAE(inDAE, functionTree, transformBuiltinExpressions, (ht, 0, 0, {}));
end processBuiltinExpressions;

protected function transformBuiltinExpressions "author: lochel
Helper for processBuiltinExpressions"
input tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer, BackendDAE.SampleLookup>> itpl;
output tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer, BackendDAE.SampleLookup>> otpl;
input tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, list<BackendDAE.TimeEvent>>> itpl;
output tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, list<BackendDAE.TimeEvent>>> otpl;
protected
DAE.Exp e;
tuple<HashTableExpToIndex.HashTable, Integer, BackendDAE.SampleLookup> i;
tuple<HashTableExpToIndex.HashTable, Integer, Integer, list<BackendDAE.TimeEvent>> i;
algorithm
(e, i) := itpl;
otpl := Expression.traverseExp(e, transformBuiltinExpression, i);
end transformBuiltinExpressions;

protected function transformBuiltinExpression "author: lochel
Helper for transformBuiltinExpressions"
input tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer, BackendDAE.SampleLookup>> inTuple;
output tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer, BackendDAE.SampleLookup>> outTuple;
input tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, list<BackendDAE.TimeEvent>>> inTuple;
output tuple<DAE.Exp, tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, list<BackendDAE.TimeEvent>>> outTuple;
algorithm
outTuple := matchcontinue(inTuple)
local
DAE.Exp e, start, interval;
list<DAE.Exp> es;
HashTableExpToIndex.HashTable ht;
Integer iDelay, iSample, i;
list<tuple<Integer, DAE.Exp, DAE.Exp>> samples;
BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
DAE.CallAttributes attr;

// delay [already in ht]
case ((e as DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, iDelay, sampleLookup))) equation
case ((e as DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, iDelay, iSample, timeEvents))) equation
i = BaseHashTable.get(e, ht);
then ((DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(i)::es, attr), (ht, iDelay, sampleLookup)));
then ((DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(i)::es, attr), (ht, iDelay, iSample, timeEvents)));

// delay [not yet in ht]
case ((e as DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, iDelay, sampleLookup))) equation
case ((e as DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, iDelay, iSample, timeEvents))) equation
ht = BaseHashTable.add((e, iDelay+1), ht);
then ((DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(iDelay)::es, attr), (ht, iDelay+1, sampleLookup)));
then ((DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(iDelay)::es, attr), (ht, iDelay+1, iSample, timeEvents)));

// sample [already in ht]
case ((e as DAE.CALL(Absyn.IDENT("sample"), es, attr), (ht, iDelay, sampleLookup))) equation
case ((e as DAE.CALL(Absyn.IDENT("sample"), es, attr), (ht, iDelay, iSample, timeEvents))) equation
i = BaseHashTable.get(e, ht);
then ((DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(i)::es, attr), (ht, iDelay, sampleLookup)));
then ((DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(i)::es, attr), (ht, iDelay, iSample, timeEvents)));

// sample [not yet in ht]
case ((e as DAE.CALL(Absyn.IDENT("sample"), es as {start, interval}, attr), (ht, iDelay, BackendDAE.SAMPLE_LOOKUP(iSample, samples)))) equation
case ((e as DAE.CALL(Absyn.IDENT("sample"), es as {start, interval}, attr), (ht, iDelay, iSample, timeEvents))) equation
iSample = iSample+1;
samples = listAppend(samples, {(iSample, start, interval)});
timeEvents = listAppend(timeEvents, {BackendDAE.SAMPLE_TIME_EVENT(iSample, start, interval)});
ht = BaseHashTable.add((e, iSample), ht);
sampleLookup = BackendDAE.SAMPLE_LOOKUP(iSample, samples);
then ((DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(iSample)::es, attr), (ht, iDelay, sampleLookup)));
then ((DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(iSample)::es, attr), (ht, iDelay, iSample, timeEvents)));

else inTuple;
end matchcontinue;
Expand Down Expand Up @@ -3340,7 +3338,7 @@ algorithm
list<DAE.ClassAttributes> clsAttrs;
BackendDAE.EventInfo einfo, einfo1;
BackendDAE.ExternalObjectClasses eoc;
BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
list<BackendDAE.WhenClause> whenclauses;
list<BackendDAE.Equation> eqs_lst, eqs_lst1;
list<BackendDAE.ZeroCrossing> zero_crossings;
Expand All @@ -3355,7 +3353,7 @@ algorithm
BackendDAE.ExtraInfo ei;

case (BackendDAE.DAE(systs, (BackendDAE.SHARED(knvars, exobj, av, inieqns, remeqns, constrs, clsAttrs,
cache, env, funcs, einfo as BackendDAE.EVENT_INFO(sampleLookup=sampleLookup, zeroCrossingLst=zero_crossings, relationsLst=relationsLst,
cache, env, funcs, einfo as BackendDAE.EVENT_INFO(timeEvents=timeEvents, zeroCrossingLst=zero_crossings, relationsLst=relationsLst,
sampleLst=sampleLst, whenClauseLst=whenclauses, relationsNumber=countRelations,
numberMathEvents=countMathFunctions), eoc, btp, symjacs, ei))), _)
equation
Expand All @@ -3369,7 +3367,7 @@ algorithm
eqs_lst1 = listReverse(eqs_lst1);
inieqns = BackendEquation.listEquation(eqs_lst1);
Debug.fcall(Flags.RELIDX, print, "findZeroCrossings1 sample index: " +& intString(listLength(sampleLst)) +& "\n");
einfo1 = BackendDAE.EVENT_INFO(sampleLookup, whenclauses, zero_crossings, sampleLst, relationsLst, countRelations, countMathFunctions);
einfo1 = BackendDAE.EVENT_INFO(timeEvents, whenclauses, zero_crossings, sampleLst, relationsLst, countRelations, countMathFunctions);
then
BackendDAE.DAE(systs, BackendDAE.SHARED(knvars, exobj, av, inieqns, remeqns, constrs, clsAttrs, cache, env, funcs, einfo1, eoc, btp, symjacs, ei));
end match;
Expand All @@ -3393,7 +3391,7 @@ algorithm
BackendDAE.ExternalObjectClasses eoc;
list<BackendDAE.WhenClause> whenclauses;
list<BackendDAE.Equation> eqs_lst, eqs_lst1;
BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
list<BackendDAE.ZeroCrossing> zero_crossings;
list<BackendDAE.ZeroCrossing> relations, sampleLst;
Integer countRelations;
Expand All @@ -3410,7 +3408,7 @@ algorithm

case (BackendDAE.EQSYSTEM(vars, eqns, m, mT, matching, stateSets),
(BackendDAE.SHARED(knvars, exobj, av, inieqns, remeqns, constrs, clsAttrs,
cache, env, funcs, einfo as BackendDAE.EVENT_INFO(sampleLookup=sampleLookup, zeroCrossingLst=zero_crossings,
cache, env, funcs, einfo as BackendDAE.EVENT_INFO(timeEvents=timeEvents, zeroCrossingLst=zero_crossings,
sampleLst=sampleLst, whenClauseLst=whenclauses, relationsLst=relations,
relationsNumber=countRelations, numberMathEvents=countMathFunctions),
eoc, btp, symjacs, ei), allvars))
Expand All @@ -3421,7 +3419,7 @@ algorithm
Debug.fcall(Flags.RELIDX, print, "findZeroCrossings1 number of relations : " +& intString(countRelations) +& "\n");
Debug.fcall(Flags.RELIDX, print, "findZeroCrossings1 sample index: " +& intString(listLength(sampleLst)) +& "\n");
eqns1 = BackendEquation.listEquation(eqs_lst1);
einfo1 = BackendDAE.EVENT_INFO(sampleLookup, whenclauses, zero_crossings, sampleLst, relations, countRelations, countMathFunctions);
einfo1 = BackendDAE.EVENT_INFO(timeEvents, whenclauses, zero_crossings, sampleLst, relations, countRelations, countMathFunctions);
allvars = listAppend(allvars, BackendVariable.varList(vars));
then
(BackendDAE.EQSYSTEM(vars, eqns1, m, mT, matching, stateSets), (BackendDAE.SHARED(knvars, exobj, av, inieqns, remeqns, constrs, clsAttrs, cache, env, funcs, einfo1, eoc, btp, symjacs, ei), allvars));
Expand Down
16 changes: 8 additions & 8 deletions Compiler/BackEnd/BackendDAEOptimize.mo
Expand Up @@ -462,17 +462,17 @@ protected function traverseEventInfoExps
output tuple<DAE.Exp, Type_a> outTpl;
end FuncExpType;
protected
BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
list<BackendDAE.WhenClause> whenClauseLst;
list<BackendDAE.ZeroCrossing> zeroCrossingLst,sampleLst,relationsLst;
Integer relationsNumber,numberMathEvents;
algorithm
BackendDAE.EVENT_INFO(sampleLookup,whenClauseLst,zeroCrossingLst,sampleLst,relationsLst,relationsNumber,numberMathEvents) := iEventInfo;
BackendDAE.EVENT_INFO(timeEvents,whenClauseLst,zeroCrossingLst,sampleLst,relationsLst,relationsNumber,numberMathEvents) := iEventInfo;
(whenClauseLst,outTypeA) := traverseWhenClauseExps(whenClauseLst,func,inTypeA,{});
(zeroCrossingLst,outTypeA) := traverseZeroCrossingExps(zeroCrossingLst,func,outTypeA,{});
(sampleLst,outTypeA) := traverseZeroCrossingExps(sampleLst,func,outTypeA,{});
(relationsLst,outTypeA) := traverseZeroCrossingExps(relationsLst,func,outTypeA,{});
oEventInfo := BackendDAE.EVENT_INFO(sampleLookup,whenClauseLst,zeroCrossingLst,sampleLst,relationsLst,relationsNumber,numberMathEvents);
oEventInfo := BackendDAE.EVENT_INFO(timeEvents,whenClauseLst,zeroCrossingLst,sampleLst,relationsLst,relationsNumber,numberMathEvents);
end traverseEventInfoExps;

protected function traverseWhenClauseExps
Expand Down Expand Up @@ -3570,7 +3570,7 @@ algorithm
jacRemovedEqs = BackendEquation.emptyEqns();
jacInitialEqs = BackendEquation.emptyEqns();
functions = DAEUtil.avlTreeNew();
jacEventInfo = BackendDAE.EVENT_INFO(BackendDAE.SAMPLE_LOOKUP(0, {}), {}, {}, {}, {}, 0, 0);
jacEventInfo = BackendDAE.EVENT_INFO({}, {}, {}, {}, {}, 0, 0);
jacExtObjClasses = {};

jacobian = BackendDAE.DAE({BackendDAE.EQSYSTEM(jacOrderedVars, jacOrderedEqs, NONE(), NONE(), BackendDAE.NO_MATCHING(),{})}, BackendDAE.SHARED(jacKnownVars, jacExternalObjects, jacAliasVars, jacInitialEqs, jacRemovedEqs, {}, {}, cache, env, functions, jacEventInfo, jacExtObjClasses,BackendDAE.JACOBIAN(),{},ei));
Expand Down Expand Up @@ -3615,7 +3615,7 @@ algorithm
jacOrderedEqs = BackendEquation.listEquation(derivedEquations);
jacRemovedEqs = BackendEquation.emptyEqns();
jacInitialEqs = BackendEquation.emptyEqns();
jacEventInfo = BackendDAE.EVENT_INFO(BackendDAE.SAMPLE_LOOKUP(0, {}), {}, {}, {}, {}, 0, 0);
jacEventInfo = BackendDAE.EVENT_INFO({}, {}, {}, {}, {}, 0, 0);
jacExtObjClasses = {};

jacobian = BackendDAE.DAE(BackendDAE.EQSYSTEM(jacOrderedVars, jacOrderedEqs, NONE(), NONE(), BackendDAE.NO_MATCHING(),{})::{}, BackendDAE.SHARED(jacKnownVars, jacExternalObjects, jacAliasVars, jacInitialEqs, jacRemovedEqs, {}, {}, cache, env, DAE.emptyFuncTree, jacEventInfo, jacExtObjClasses, BackendDAE.JACOBIAN(),{}, ei));
Expand Down Expand Up @@ -6239,7 +6239,7 @@ protected
BackendDAE.BackendDAEType backendDAEType;
BackendDAE.SymbolicJacobians symjacs;

BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
list<BackendDAE.WhenClause> whenClauseLst;
list<BackendDAE.ZeroCrossing> zeroCrossingLst;
list<BackendDAE.ZeroCrossing> sampleLst;
Expand Down Expand Up @@ -6271,7 +6271,7 @@ algorithm
backendDAEType=backendDAEType,
symjacs=symjacs,
info=ei) := shared;
BackendDAE.EVENT_INFO(sampleLookup=sampleLookup,
BackendDAE.EVENT_INFO(timeEvents=timeEvents,
whenClauseLst=whenClauseLst,
zeroCrossingLst=zeroCrossingLst,
sampleLst=sampleLst,
Expand All @@ -6293,7 +6293,7 @@ algorithm
eqns_ := BackendEquation.listEquation(eqns);
systs := listAppend(systs, {BackendDAE.EQSYSTEM(vars_, eqns_, NONE(), NONE(), BackendDAE.NO_MATCHING(), {})});

eventInfo := BackendDAE.EVENT_INFO(sampleLookup,
eventInfo := BackendDAE.EVENT_INFO(timeEvents,
whenClauseLst,
zeroCrossingLst,
sampleLst,
Expand Down
14 changes: 8 additions & 6 deletions Compiler/BackEnd/BackendDAEUtil.mo
Expand Up @@ -1094,18 +1094,20 @@ end calculateVarSizes;

public function numberOfZeroCrossings "author: lochel"
input BackendDAE.BackendDAE inBackendDAE;
output Integer outNumZeroCrossings "number of zerocrossings" ;
output Integer outNumTimeEvents "number of zerocrossings that are samples" ;
output Integer outNumZeroCrossings "number of ordinary zerocrossings" ;
output Integer outNumTimeEvents "number of zerocrossings that are time events" ;
output Integer outNumRelations;
output Integer outNumMathEventFunctions;
protected
list<BackendDAE.TimeEvent> timeEvents;
list<ZeroCrossing> zeroCrossingLst;
algorithm
BackendDAE.DAE(shared=BackendDAE.SHARED(eventInfo=BackendDAE.EVENT_INFO(sampleLookup=BackendDAE.SAMPLE_LOOKUP(nSamples=outNumTimeEvents),
BackendDAE.DAE(shared=BackendDAE.SHARED(eventInfo=BackendDAE.EVENT_INFO(timeEvents=timeEvents,
zeroCrossingLst=zeroCrossingLst,
relationsNumber=outNumRelations,
numberMathEvents=outNumMathEventFunctions))) := inBackendDAE;

outNumTimeEvents := listLength(timeEvents);
outNumZeroCrossings := listLength(zeroCrossingLst);
end numberOfZeroCrossings;

Expand Down Expand Up @@ -2377,13 +2379,13 @@ algorithm
ExternalObjectClasses eoc;
BackendDAE.SymbolicJacobians symjacs;
BackendDAEType btp;
BackendDAE.SampleLookup sampleLookup;
list<BackendDAE.TimeEvent> timeEvents;
BackendDAE.ExtraInfo ei;

case (_,BackendDAE.SHARED(knvars,exobj,aliasVars,inieqns,remeqns,constrs,clsAttrs,cache,env,funcs,BackendDAE.EVENT_INFO(sampleLookup,wclst,zc,smplLst,rellst,numberOfRelations,numberOfMathEventFunctions),eoc,btp,symjacs,ei))
case (_,BackendDAE.SHARED(knvars,exobj,aliasVars,inieqns,remeqns,constrs,clsAttrs,cache,env,funcs,BackendDAE.EVENT_INFO(timeEvents,wclst,zc,smplLst,rellst,numberOfRelations,numberOfMathEventFunctions),eoc,btp,symjacs,ei))
equation
wclst1 = listAppend(wclst,inWcLst);
then BackendDAE.SHARED(knvars,exobj,aliasVars,inieqns,remeqns,constrs,clsAttrs,cache,env,funcs,BackendDAE.EVENT_INFO(sampleLookup,wclst1,zc,smplLst,rellst,numberOfRelations,numberOfMathEventFunctions),eoc,btp,symjacs,ei);
then BackendDAE.SHARED(knvars,exobj,aliasVars,inieqns,remeqns,constrs,clsAttrs,cache,env,funcs,BackendDAE.EVENT_INFO(timeEvents,wclst1,zc,smplLst,rellst,numberOfRelations,numberOfMathEventFunctions),eoc,btp,symjacs,ei);

end match;
end whenClauseAddDAE;
Expand Down

0 comments on commit 6128548

Please sign in to comment.