LmrsUtil.java
package org.opentrafficsim.road.gtu.lane.tactical.util.lmrs;
import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.UNITINTERVAL;
import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.djunits.unit.AccelerationUnit;
import org.djunits.value.vdouble.scalar.Acceleration;
import org.djunits.value.vdouble.scalar.Duration;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.djunits.value.vdouble.scalar.Time;
import org.opentrafficsim.core.gtu.GTUException;
import org.opentrafficsim.core.gtu.TurnIndicatorStatus;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDouble;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
import org.opentrafficsim.core.network.LateralDirectionality;
import org.opentrafficsim.core.network.NetworkException;
import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
import org.opentrafficsim.road.gtu.lane.perception.categories.NeighborsPerception;
import org.opentrafficsim.road.gtu.lane.perception.headway.AbstractHeadwayGTU;
import org.opentrafficsim.road.gtu.lane.plan.operational.LaneOperationalPlanBuilder.LaneChange;
import org.opentrafficsim.road.gtu.lane.plan.operational.SimpleOperationalPlan;
import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
import org.opentrafficsim.road.network.speed.SpeedLimitProspect;
import nl.tudelft.simulation.language.Throw;
/**
* <p>
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Jul 26, 2016 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
public final class LmrsUtil
{
/** Free lane change desire threshold. */
public static final ParameterTypeDouble DFREE =
new ParameterTypeDouble("dFree", "Free lane change desire threshold.", 0.365, UNITINTERVAL)
{
/** */
private static final long serialVersionUID = 20160413L;
public void check(final double value, final BehavioralCharacteristics bc) throws ParameterException
{
if (bc.contains(DSYNC))
{
Throw.when(value >= bc.getParameter(DSYNC), ParameterException.class,
"Value of dFree is above or equal to dSync.");
}
if (bc.contains(DCOOP))
{
Throw.when(value >= bc.getParameter(DCOOP), ParameterException.class,
"Value of dFree is above or equal to dCoop.");
}
}
};
/** Synchronized lane change desire threshold. */
public static final ParameterTypeDouble DSYNC =
new ParameterTypeDouble("dSync", "Synchronized lane change desire threshold.", 0.577, UNITINTERVAL)
{
/** */
private static final long serialVersionUID = 20160413L;
public void check(final double value, final BehavioralCharacteristics bc) throws ParameterException
{
if (bc.contains(DFREE))
{
Throw.when(value <= bc.getParameter(DFREE), ParameterException.class,
"Value of dSync is below or equal to dFree.");
}
if (bc.contains(DCOOP))
{
Throw.when(value >= bc.getParameter(DCOOP), ParameterException.class,
"Value of dSync is above or equal to dCoop.");
}
}
};
/** Cooperative lane change desire threshold. */
public static final ParameterTypeDouble DCOOP =
new ParameterTypeDouble("dCoop", "Cooperative lane change desire threshold.", 0.788, UNITINTERVAL)
{
/** */
private static final long serialVersionUID = 20160413L;
public void check(final double value, final BehavioralCharacteristics bc) throws ParameterException
{
if (bc.contains(DFREE))
{
Throw.when(value <= bc.getParameter(DFREE), ParameterException.class,
"Value of dCoop is below or equal to dFree.");
}
if (bc.contains(DSYNC))
{
Throw.when(value <= bc.getParameter(DSYNC), ParameterException.class,
"Value of dCoop is below or equal to dSync.");
}
}
};
/** Current left lane change desire. */
public static final ParameterTypeDouble DLEFT = new ParameterTypeDouble("dLeft", "Left lane change desire.", 0);
/** Current right lane change desire. */
public static final ParameterTypeDouble DRIGHT = new ParameterTypeDouble("dLeft", "Left lane change desire.", 0);
/**
* Do not instantiate.
*/
private LmrsUtil()
{
//
}
/**
* Determines a simple representation of an operational plan.
* @param gtu gtu
* @param startTime start time
* @param lmrsStatus LMRS status
* @param carFollowingModel car-following model
* @param laneChange lane change status
* @param perception perception
* @param mandatoryIncentives set of mandatory lane change incentives
* @param voluntaryIncentives set of voluntary lane change incentives
* @return simple operational plan
* @throws GTUException gtu exception
* @throws NetworkException network exception
* @throws ParameterException parameter exception
* @throws OperationalPlanException operational plan exception
*/
@SuppressWarnings("checkstyle:parameternumber")
public static SimpleOperationalPlan determinePlan(final LaneBasedGTU gtu, final Time startTime, final LmrsStatus lmrsStatus,
final CarFollowingModel carFollowingModel, final LaneChange laneChange, final LanePerception perception,
final LinkedHashSet<MandatoryIncentive> mandatoryIncentives,
final LinkedHashSet<VoluntaryIncentive> voluntaryIncentives)
throws GTUException, NetworkException, ParameterException, OperationalPlanException
{
// obtain objects to get info
SpeedLimitProspect slp =
perception.getPerceptionCategory(InfrastructurePerception.class).getSpeedLimitProspect(RelativeLane.CURRENT);
SpeedLimitInfo sli = slp.getSpeedLimitInfo(Length.ZERO);
BehavioralCharacteristics bc = gtu.getBehavioralCharacteristics();
// update T as response to new leader
Set<AbstractHeadwayGTU> leaders =
perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(RelativeLane.CURRENT);
for (AbstractHeadwayGTU leader : leaders)
{
if (!lmrsStatus.getLastLeaders().contains(leader))
{
// TODO updated headway based on (estimated) desire of other vehicle
// uses current headway, this results in larger deceleration than using the desire
// we require a desire where T = desire*Tmin + (1-desire)*Tmax gives a deceleration of b*desire
//
// idea: acceleration for actual T
// acceleration for Tmin
// interpolate appropriately (which is... ? )
// Duration tLead = Duration.max(bc.getParameter(ParameterTypes.TMIN),
// leader.getDistance().minus(bc.getParameter(ParameterTypes.S0)).divideBy(gtu.getSpeed()));
// if (tLead.lt(bc.getParameter(ParameterTypes.T)))
// {
// bc.setParameter(ParameterTypes.T, tLead);
// }
}
}
lmrsStatus.setLastLeaders(leaders);
// regular car-following
Speed speed = gtu.getSpeed();
Acceleration a = CarFollowingUtil.followLeaders(carFollowingModel, bc, speed, sli,
perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(RelativeLane.CURRENT));
// during a lane change, both leaders are followed
LateralDirectionality initiatedLaneChange;
if (laneChange.isChangingLane())
{
// RelativeLane tar = this.laneChangeDirectionality.isLeft() ? RelativeLane.LEFT : RelativeLane.RIGHT;
RelativeLane tar = laneChange.getTargetLane();
initiatedLaneChange = tar.getLateralDirectionality();
Acceleration aTar = CarFollowingUtil.followLeaders(carFollowingModel, bc, speed, sli,
perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(tar));
a = Acceleration.min(a, aTar);
}
else
{
// relaxation
exponentialHeadwayRelaxation(bc);
// determine lane change desire based on incentives
Desire desire = getLaneChangeDesire(bc, perception, carFollowingModel, mandatoryIncentives, voluntaryIncentives);
// gap acceptance
boolean acceptLeft = perception.getLaneStructure().getCrossSection().contains(RelativeLane.LEFT)
&& acceptGap(perception, bc, sli, carFollowingModel, desire.getLeft(), speed, LateralDirectionality.LEFT);
boolean acceptRight = perception.getLaneStructure().getCrossSection().contains(RelativeLane.RIGHT)
&& acceptGap(perception, bc, sli, carFollowingModel, desire.getRight(), speed, LateralDirectionality.RIGHT);
// lane change decision
double dFree = bc.getParameter(DFREE);
double dSync = bc.getParameter(DSYNC);
double dCoop = bc.getParameter(DCOOP);
// decide
TurnIndicatorStatus turnIndicatorStatus;
if (desire.leftIsLargerOrEqual() && desire.getLeft() >= dFree && acceptLeft)
{
// change left
initiatedLaneChange = LateralDirectionality.LEFT;
turnIndicatorStatus = TurnIndicatorStatus.LEFT;
Duration tRel = Duration.interpolate(bc.getParameter(ParameterTypes.TMAX), bc.getParameter(ParameterTypes.TMIN),
desire.getLeft());
if (tRel.lt(bc.getParameter(ParameterTypes.T)))
{
bc.setParameter(ParameterTypes.T, tRel);
}
// TODO headway of other driver...
}
else if (!desire.leftIsLargerOrEqual() && desire.getRight() >= dFree && acceptRight)
{
// change right
initiatedLaneChange = LateralDirectionality.RIGHT;
turnIndicatorStatus = TurnIndicatorStatus.RIGHT;
Duration tRel = Duration.interpolate(bc.getParameter(ParameterTypes.TMAX), bc.getParameter(ParameterTypes.TMIN),
desire.getRight());
if (tRel.lt(bc.getParameter(ParameterTypes.T)))
{
bc.setParameter(ParameterTypes.T, tRel);
}
// TODO headway of other driver...
}
else
{
initiatedLaneChange = null;
turnIndicatorStatus = TurnIndicatorStatus.NONE;
}
laneChange.setLaneChangeDuration(gtu.getBehavioralCharacteristics().getParameter(ParameterTypes.LCDUR));
// take action if we cannot change lane
Acceleration aSync;
if (initiatedLaneChange == null)
{
// synchronize
if (desire.leftIsLargerOrEqual() && desire.getLeft() >= dSync)
{
aSync = synchronize(perception, bc, sli, carFollowingModel, desire.getLeft(), speed,
LateralDirectionality.LEFT);
a = Acceleration.min(a, aSync);
}
else if (!desire.leftIsLargerOrEqual() && desire.getRight() >= dSync)
{
aSync = synchronize(perception, bc, sli, carFollowingModel, desire.getRight(), speed,
LateralDirectionality.RIGHT);
a = Acceleration.min(a, aSync);
}
// use indicators to indicate lane change need
if (desire.leftIsLargerOrEqual() && desire.getLeft() >= dCoop)
{
// switch on left indicator
turnIndicatorStatus = TurnIndicatorStatus.LEFT;
}
else if (!desire.leftIsLargerOrEqual() && desire.getRight() >= dCoop)
{
// switch on right indicator
turnIndicatorStatus = TurnIndicatorStatus.RIGHT;
}
}
gtu.setTurnIndicatorStatus(turnIndicatorStatus);
// cooperate
aSync = cooperate(perception, bc, sli, carFollowingModel, speed, LateralDirectionality.LEFT);
a = Acceleration.min(a, aSync);
aSync = cooperate(perception, bc, sli, carFollowingModel, speed, LateralDirectionality.RIGHT);
a = Acceleration.min(a, aSync);
}
return new SimpleOperationalPlan(a, initiatedLaneChange);
}
/**
* Updates the desired headway following an exponential shape approximated with fixed time step <tt>DT</tt>.
* @param bc Behavioral characteristics.
* @throws ParameterException In case of a parameter exception.
*/
private static void exponentialHeadwayRelaxation(final BehavioralCharacteristics bc) throws ParameterException
{
double ratio = bc.getParameter(ParameterTypes.DT).si / bc.getParameter(ParameterTypes.TAU).si;
bc.setParameter(ParameterTypes.T, Duration.interpolate(bc.getParameter(ParameterTypes.T),
bc.getParameter(ParameterTypes.TMAX), ratio <= 1.0 ? ratio : 1.0));
}
/**
* Determines lane change desire for the given RSU. Mandatory desire is deduced as the maximum of a set of mandatory
* incentives, while voluntary desires are added. Depending on the level of mandatory lane change desire, voluntary desire
* may be included partially. If both are positive or negative, voluntary desire is fully included. Otherwise, voluntary
* desire is less considered within the range dSync < |mandatory| < dCoop. The absolute value is used as large
* negative mandatory desire may also dominate voluntary desire.
* @param behavioralCharacteristics behavioral characteristics
* @param perception perception
* @param carFollowingModel car-following model
* @param mandatoryIncentives mandatory incentives
* @param voluntaryIncentives voluntary incentives
* @return lane change desire for gtu
* @throws ParameterException if a parameter is not defined
* @throws GTUException if there is no mandatory incentive, the model requires at least one
* @throws OperationalPlanException perception exception
*/
private static Desire getLaneChangeDesire(final BehavioralCharacteristics behavioralCharacteristics,
final LanePerception perception, final CarFollowingModel carFollowingModel,
final LinkedHashSet<MandatoryIncentive> mandatoryIncentives,
final LinkedHashSet<VoluntaryIncentive> voluntaryIncentives)
throws ParameterException, GTUException, OperationalPlanException
{
double dSync = behavioralCharacteristics.getParameter(DSYNC);
double dCoop = behavioralCharacteristics.getParameter(DCOOP);
// Mandatory desire
double dLeftMandatory = Double.NEGATIVE_INFINITY;
double dRightMandatory = Double.NEGATIVE_INFINITY;
Desire mandatoryDesire = new Desire(dLeftMandatory, dRightMandatory);
for (MandatoryIncentive incentive : mandatoryIncentives)
{
Desire d = incentive.determineDesire(behavioralCharacteristics, perception, carFollowingModel, mandatoryDesire);
dLeftMandatory = d.getLeft() > dLeftMandatory ? d.getLeft() : dLeftMandatory;
dRightMandatory = d.getRight() > dRightMandatory ? d.getRight() : dRightMandatory;
mandatoryDesire = new Desire(dLeftMandatory, dRightMandatory);
}
// Voluntary desire
double dLeftVoluntary = 0;
double dRightVoluntary = 0;
Desire voluntaryDesire = new Desire(dLeftVoluntary, dRightVoluntary);
for (VoluntaryIncentive incentive : voluntaryIncentives)
{
Desire d = incentive.determineDesire(behavioralCharacteristics, perception, carFollowingModel, mandatoryDesire,
voluntaryDesire);
dLeftVoluntary += d.getLeft();
dRightVoluntary += d.getRight();
voluntaryDesire = new Desire(dLeftVoluntary, dRightVoluntary);
}
// Total desire
double thetaLeft = 0;
if (dLeftMandatory <= dSync || dLeftMandatory * dLeftVoluntary >= 0)
{
// low mandatory desire, or same sign
thetaLeft = 1;
}
else if (dSync < dLeftMandatory && dLeftMandatory < dCoop && dLeftMandatory * dLeftVoluntary < 0)
{
// linear from 1 at dSync to 0 at dCoop
thetaLeft = (dCoop - Math.abs(dLeftMandatory)) / (dCoop - dSync);
}
double thetaRight = 0;
if (dRightMandatory <= dSync || dRightMandatory * dRightVoluntary >= 0)
{
// low mandatory desire, or same sign
thetaRight = 1;
}
else if (dSync < dRightMandatory && dRightMandatory < dCoop && dRightMandatory * dRightVoluntary < 0)
{
// linear from 1 at dSync to 0 at dCoop
thetaRight = (dCoop - Math.abs(dRightMandatory)) / (dCoop - dSync);
}
return new Desire(dLeftMandatory + thetaLeft * dLeftVoluntary, dRightMandatory + thetaRight * dRightVoluntary);
}
/**
* Determine whether a gap is acceptable.
* @param perception perception
* @param bc behavioral characteristics
* @param sli speed limit info
* @param cfm car-following model
* @param desire level of lane change desire
* @param ownSpeed own speed
* @param lat lateral direction for synchronization
* @return whether a gap is acceptable
* @throws ParameterException if a parameter is not defined
* @throws OperationalPlanException perception exception
*/
private static boolean acceptGap(final LanePerception perception, final BehavioralCharacteristics bc,
final SpeedLimitInfo sli, final CarFollowingModel cfm, final double desire, final Speed ownSpeed,
final LateralDirectionality lat) throws ParameterException, OperationalPlanException
{
Acceleration b = bc.getParameter(ParameterTypes.B);
if (perception.getPerceptionCategory(InfrastructurePerception.class).getLegalLaneChangePossibility(RelativeLane.CURRENT,
lat).si > 0 && !perception.getPerceptionCategory(NeighborsPerception.class).isGtuAlongside(lat))
{
Acceleration aFollow = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
for (AbstractHeadwayGTU follower : perception.getPerceptionCategory(NeighborsPerception.class)
.getFirstFollowers(lat))
{
Acceleration a = singleAcceleration(follower.getDistance(), follower.getSpeed(), ownSpeed, desire,
follower.getBehavioralCharacteristics(), follower.getSpeedLimitInfo(), follower.getCarFollowingModel());
aFollow = Acceleration.min(aFollow, a);
}
Acceleration aSelf = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
for (AbstractHeadwayGTU leader : perception.getPerceptionCategory(NeighborsPerception.class).getFirstLeaders(lat))
{
Acceleration a = singleAcceleration(leader.getDistance(), ownSpeed, leader.getSpeed(), desire, bc, sli, cfm);
aSelf = Acceleration.min(aSelf, a);
}
Acceleration threshold = b.multiplyBy(-desire);
return aFollow.ge(threshold) && aSelf.ge(threshold);
}
return false;
}
/**
* Determine acceleration for synchronization.
* @param perception perception
* @param bc behavioral characteristics
* @param sli speed limit info
* @param cfm car-following model
* @param desire level of lane change desire
* @param ownSpeed own speed
* @param lat lateral direction for synchronization
* @return acceleration for synchronization
* @throws ParameterException if a parameter is not defined
* @throws OperationalPlanException perception exception
*/
private static Acceleration synchronize(final LanePerception perception, final BehavioralCharacteristics bc,
final SpeedLimitInfo sli, final CarFollowingModel cfm, final double desire, final Speed ownSpeed,
final LateralDirectionality lat) throws ParameterException, OperationalPlanException
{
Acceleration b = bc.getParameter(ParameterTypes.B);
Acceleration a = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
for (AbstractHeadwayGTU leader : perception.getPerceptionCategory(NeighborsPerception.class).getFirstLeaders(lat))
{
Acceleration aSingle = singleAcceleration(leader.getDistance(), ownSpeed, leader.getSpeed(), desire, bc, sli, cfm);
a = Acceleration.min(a, aSingle);
}
return Acceleration.max(a, b.multiplyBy(-1));
}
/**
* Determine acceleration for cooperation.
* @param perception perception
* @param bc behavioral characteristics
* @param sli speed limit info
* @param cfm car-following model
* @param ownSpeed own speed
* @param lat lateral direction for cooperation
* @return acceleration for synchronization
* @throws ParameterException if a parameter is not defined
* @throws OperationalPlanException perception exception
*/
private static Acceleration cooperate(final LanePerception perception, final BehavioralCharacteristics bc,
final SpeedLimitInfo sli, final CarFollowingModel cfm, final Speed ownSpeed, final LateralDirectionality lat)
throws ParameterException, OperationalPlanException
{
if (!perception.getLaneStructure().getCrossSection().contains(new RelativeLane(lat, 1)))
{
return new Acceleration(Double.MAX_VALUE, AccelerationUnit.SI);
}
Acceleration b = bc.getParameter(ParameterTypes.B);
Acceleration a = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
for (AbstractHeadwayGTU leader : perception.getPerceptionCategory(NeighborsPerception.class).getFirstLeaders(lat))
{
if ((lat == LateralDirectionality.LEFT && leader.isRightTurnIndicatorOn())
|| (lat == LateralDirectionality.RIGHT && leader.isLeftTurnIndicatorOn()))
{
BehavioralCharacteristics bc2 = leader.getBehavioralCharacteristics();
double desire = lat == LateralDirectionality.LEFT && bc2.contains(DRIGHT) ? bc2.getParameter(DRIGHT)
: lat == LateralDirectionality.RIGHT && bc2.contains(DLEFT) ? bc2.getParameter(DLEFT) : 0;
Acceleration aSingle =
singleAcceleration(leader.getDistance(), ownSpeed, leader.getSpeed(), desire, bc, sli, cfm);
a = Acceleration.min(a, aSingle);
}
}
return Acceleration.max(a, b.multiplyBy(-1));
}
/**
* Determine acceleration from car-following.
* @param distance distance from follower to leader
* @param followerSpeed speed of follower
* @param leaderSpeed speed of leader
* @param desire level of lane change desire
* @param bc behavioral characteristics
* @param sli speed limit info
* @param cfm car-following model
* @return acceleration from car-following
* @throws ParameterException if a parameter is not defined
*/
private static Acceleration singleAcceleration(final Length distance, final Speed followerSpeed, final Speed leaderSpeed,
final double desire, final BehavioralCharacteristics bc, final SpeedLimitInfo sli, final CarFollowingModel cfm)
throws ParameterException
{
// set T
bc.setParameter(ParameterTypes.T,
Duration.interpolate(bc.getParameter(ParameterTypes.TMAX), bc.getParameter(ParameterTypes.TMIN), desire));
// calculate acceleration
SortedMap<Length, Speed> leaders = new TreeMap<>();
leaders.put(distance, leaderSpeed);
Acceleration a = cfm.followingAcceleration(bc, followerSpeed, sli, leaders);
// reset T
bc.resetParameter(ParameterTypes.T);
return a;
}
/**
* Status of LMRS.
* <p>
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* <br>
* BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Jul 27, 2016 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
public static class LmrsStatus implements Serializable
{
/** */
private static final long serialVersionUID = 20160811L;
/** Remembered leaders. */
private Set<AbstractHeadwayGTU> lastLeaders = new HashSet<>();
/**
* @return lastLeaders.
*/
public final Set<AbstractHeadwayGTU> getLastLeaders()
{
return new HashSet<>(this.lastLeaders);
}
/**
* @param lastLeaders set lastLeaders.
*/
public final void setLastLeaders(final Set<AbstractHeadwayGTU> lastLeaders)
{
this.lastLeaders.clear();
this.lastLeaders.addAll(lastLeaders);
}
/** {@inheritDoc} */
@Override
public final String toString()
{
return "LmrsStatus";
}
}
}