diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 950f8b25c19484757eca0c1572b19972f1e71691..c2c07fe906fb108a12252bc7ea8c7422bbb201cd 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -113,6 +113,13 @@
 #define NULL              0
 #endif
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+static const int SUB_TMVP_CANDIDATE_NUM = 10;
+static const int SUB_TMVP_INDEX = 3;  // 1: 2 subtmvp; 2: 4 subtmvp
+static const int SUB_TMVP_NUM = 2 * SUB_TMVP_INDEX;
+static const int SUB_TMVP_MV_THRESHOLD = 2;
+static const int AMVP_TMVP_INDEX = 1;  // 1: 2 AMVP tmvp; 2: 4 AMVP tmvp
+#endif
 typedef enum
 {
   AFFINEMODEL_4PARAM,
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index 1ff03737a41e4769938c43cb5d78036c0e7bf947..2c0c808a4c2bf246a3dad48210b77486c46c0d81 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -492,7 +492,38 @@ void MergeCtx::convertRegularMergeCandToBi(int candIdx)
   } 
 }
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+void MergeCtx::saveMergeInfo(PredictionUnit& puTmp, PredictionUnit pu)
+{
+  puTmp.mergeIdx = pu.mergeIdx;
+#if !JVET_Z0075_IBC_HMVP_ENLARGE
+  CHECK(candIdx >= numValidMergeCand, "Merge candidate does not exist");
+#endif
+
+  puTmp.regularMergeFlag = pu.regularMergeFlag;
+  puTmp.mergeFlag = pu.mergeFlag;
+  puTmp.mmvdMergeFlag = pu.mmvdMergeFlag;
+  puTmp.interDir = pu.interDir;
+  puTmp.cu->imv = pu.cu->imv;
+  puTmp.mergeType = pu.mergeType;
+  puTmp.mv[REF_PIC_LIST_0] = pu.mv[REF_PIC_LIST_0];
+  puTmp.mv[REF_PIC_LIST_1] = pu.mv[REF_PIC_LIST_1];
+#if MULTI_PASS_DMVR
+  puTmp.bdmvrRefine = pu.bdmvrRefine;
+#endif
+  puTmp.refIdx[REF_PIC_LIST_0] = pu.refIdx[REF_PIC_LIST_0];
+  puTmp.refIdx[REF_PIC_LIST_1] = pu.refIdx[REF_PIC_LIST_1];
+
+  puTmp.bv = pu.bv;
 
+  puTmp.cu->BcwIdx = pu.cu->BcwIdx;
+  puTmp.addHypData = pu.addHypData;
+  puTmp.numMergedAddHyps = pu.numMergedAddHyps;
+
+  puTmp.mmvdEncOptMode = pu.mmvdEncOptMode;
+  puTmp.cu->LICFlag = pu.cu->LICFlag;
+}
+#endif
 void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
 {
 #if JVET_X0049_ADAPT_DMVR
@@ -584,7 +615,33 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
   }
 #endif
 }
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION                                
+bool MergeCtx::xCheckSimilarMotionSubTMVP(int mergeCandIndex, uint32_t mvdSimilarityThresh) const
+{
+  if (interDirNeighbours[mergeCandIndex] == 0)
+  {
+    return true;
+  }
+  Mv cVector;
+
+  CHECK(interDirNeighbours[mergeCandIndex] != 1 && interDirNeighbours[mergeCandIndex] != 2, "Wrong interDir.");
+
+  cVector = (interDirNeighbours[mergeCandIndex] == 1) ? mvFieldNeighbours[(mergeCandIndex << 1)].mv : mvFieldNeighbours[(mergeCandIndex << 1) + 1].mv;
+  cVector.changePrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
 
+  for (uint32_t ui = 0; ui < mergeCandIndex; ui++)
+  {
+    Mv cTempVector = (interDirNeighbours[ui] == 1) ? mvFieldNeighbours[(ui << 1)].mv : mvFieldNeighbours[(ui << 1) + 1].mv;
+    cTempVector.changePrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+    Mv mvDiff = cTempVector - cVector;
+    if (mvDiff.getAbsHor() < mvdSimilarityThresh && mvDiff.getAbsVer() < mvdSimilarityThresh)
+    {
+      return true;
+    }
+  }
+  return false;
+}
+#endif
 #if NON_ADJACENT_MRG_CAND || TM_MRG || MULTI_PASS_DMVR || JVET_W0097_GPM_MMVD_TM || (JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM) || JVET_Y0058_IBC_LIST_MODIFY
 #if JVET_Z0075_IBC_HMVP_ENLARGE
 bool MergeCtx::xCheckSimilarMotion(int mergeCandIndex, uint32_t mvdSimilarityThresh, int compareNum) const
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index 2b5c4ec0061402659a9e3d27424a2c0d044764b0..1a97a2a139227ed06a68770a229a2b038ef9cfb4 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -598,7 +598,11 @@ public:
 #endif
   bool          hasMergedCandList;
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  MotionBuf     subPuMvpMiBuf[SUB_TMVP_NUM];
+#else
   MotionBuf     subPuMvpMiBuf;
+#endif
   MotionBuf     subPuMvpExtMiBuf;
   MvField mmvdBaseMv[MMVD_BASE_MV_NUM][2];
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
@@ -615,6 +619,9 @@ public:
   bool          useAltHpelIf      [ NUM_MERGE_CANDS ];
 #else
   bool          useAltHpelIf      [ MRG_MAX_NUM_CANDS ];
+#endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void saveMergeInfo(PredictionUnit& puTmp, PredictionUnit pu);
 #endif
   void setMergeInfo( PredictionUnit& pu, int candIdx );
 #if NON_ADJACENT_MRG_CAND || TM_MRG || MULTI_PASS_DMVR || JVET_W0097_GPM_MMVD_TM || (JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM) || JVET_Y0058_IBC_LIST_MODIFY
@@ -634,6 +641,9 @@ public:
   bool xCheckSimilarIBCMotion(int mergeCandIndex, uint32_t mvdSimilarityThresh = 1) const;
 #endif
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION                                
+  bool xCheckSimilarMotionSubTMVP(int mergeCandIndex, uint32_t mvdSimilarityThresh = 1) const;
+#endif
 #if TM_MRG
   void copyRegularMergeCand( int dstCandIdx, MergeCtx& srcCtx, int srcCandIdx );
   void convertRegularMergeCandToBi(int candIdx);
@@ -665,6 +675,9 @@ public:
 
   MergeCtx     *mrgCtx;
   MergeType     mergeType[RMVF_AFFINE_MRG_MAX_CAND_LIST_SIZE];
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  int           colIdx[RMVF_AFFINE_MRG_MAX_CAND_LIST_SIZE];
+#endif
 #if JVET_AB0112_AFFINE_DMVR
   bool          xCheckSimilarMotion(int mergeCandIndex, uint32_t mvdSimilarityThresh = 1) const;
 #endif
@@ -688,6 +701,9 @@ public:
 
   MergeCtx     *mrgCtx;
   MergeType     mergeType[AFFINE_MRG_MAX_NUM_CANDS];
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  int           colIdx[AFFINE_MRG_MAX_NUM_CANDS];
+#endif
 #if JVET_AB0112_AFFINE_DMVR
   bool          xCheckSimilarMotion(int mergeCandIndex, uint32_t mvdSimilarityThresh = 1) const;
 #endif
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 3316da46f482bd699032318cd8d20b8adc5eb9fb..d2847ca2ac4f0d33ff71deb022fa0494f84545f5 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -678,7 +678,30 @@ void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC, cons
 // ====================================================================================================================
 // Public member functions
 // ====================================================================================================================
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+bool InterPrediction::xCheckIdenticalMotionSubTMVP(const PredictionUnit &pu)
+{
+  const Slice &slice = *pu.cs->slice;
+
+  if (slice.isInterB() && !pu.cs->pps->getWPBiPred())
+  {
+    if (pu.interDir == 3)
+    {
+      int refPOCL0 = slice.getRefPic(REF_PIC_LIST_0, pu.refIdx[0])->getPOC();
+      int refPOCL1 = slice.getRefPic(REF_PIC_LIST_1, pu.refIdx[1])->getPOC();
 
+      if (refPOCL0 == refPOCL1)
+      {
+        if (pu.mv[0] == pu.mv[1])
+        {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+#endif
 bool InterPrediction::xCheckIdenticalMotion( const PredictionUnit &pu )
 {
   const Slice &slice = *pu.cs->slice;
@@ -4167,150 +4190,226 @@ void InterPrediction::xWeightedAverageY(const PredictionUnit& pu, const CPelUnit
 #endif
 
 #if JVET_W0090_ARMC_TM
-void InterPrediction::xPredAffineTpl(const PredictionUnit &pu, const RefPicList &eRefPicList, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate)
+void InterPrediction::xPredAffineTpl(const PredictionUnit &pu, const RefPicList &eRefPicList, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  , AffineMergeCtx affMrgCtx, bool isBilinear
+#endif
+)
 {
   int iRefIdx = pu.refIdx[eRefPicList];
   CHECK(iRefIdx < 0, "iRefIdx incorrect.");
   const Picture* refPic = pu.cu->slice->getRefPic(eRefPicList, iRefIdx)->unscaledPic;
-  Mv mvLT = pu.mvAffi[eRefPicList][0];
-  Mv mvRT = pu.mvAffi[eRefPicList][1];
-  Mv mvLB = pu.mvAffi[eRefPicList][2];
-  // get affine sub-block width and height
-  const int width = pu.Y().width;
-  const int height = pu.Y().height;
-  int blockWidth = AFFINE_MIN_BLOCK_SIZE;
-  int blockHeight = AFFINE_MIN_BLOCK_SIZE;
-
-  CHECK(blockWidth > width, "Sub Block width  > Block width");
-  CHECK(blockHeight > height, "Sub Block height > Block height");
-
-  const int cxWidth = width;
-  const int cxHeight = height;
-  const int iBit = MAX_CU_DEPTH;
-  int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY;
-  iDMvHorX = (mvRT - mvLT).getHor() << (iBit - floorLog2(width));
-  iDMvHorY = (mvRT - mvLT).getVer() << (iBit - floorLog2(width));
-  if (pu.cu->affineType == AFFINEMODEL_6PARAM)
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
   {
-    iDMvVerX = (mvLB - mvLT).getHor() << (iBit - floorLog2(height));
-    iDMvVerY = (mvLB - mvLT).getVer() << (iBit - floorLog2(height));
+    Size puSize = pu.lumaSize();
+    int numPartLine = std::max(puSize.width >> ATMVP_SUB_BLOCK_SIZE, 1u);
+    int numPartCol = std::max(puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u);
+    int puHeight = numPartCol == 1 ? puSize.height : 1 << ATMVP_SUB_BLOCK_SIZE;
+    int puWidth = numPartLine == 1 ? puSize.width : 1 << ATMVP_SUB_BLOCK_SIZE;
+    for (int h = 0; h < puSize.height; h += puHeight)
+    {
+      for (int w = 0; w < puSize.width; w += puWidth)
+      {
+        if (w == 0 || h == 0)
+        {
+          int iMvScaleTmpHor, iMvScaleTmpVer;
+          MotionBuf mb = affMrgCtx.mrgCtx->subPuMvpMiBuf[pu.colIdx];
+          iMvScaleTmpHor = mb.buf[(w >> ATMVP_SUB_BLOCK_SIZE) + (h >> ATMVP_SUB_BLOCK_SIZE) * (affMrgCtx.mrgCtx->subPuMvpMiBuf[0].stride)].mv[eRefPicList].hor;
+          iMvScaleTmpVer = mb.buf[(w >> ATMVP_SUB_BLOCK_SIZE) + (h >> ATMVP_SUB_BLOCK_SIZE) * (affMrgCtx.mrgCtx->subPuMvpMiBuf[0].stride)].mv[eRefPicList].ver;
+          Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
+          // clip and scale
+          if (refPic->isRefScaled(pu.cs->pps) == false)
+          {
+            clipMv(tmpMv, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+            iMvScaleTmpHor = tmpMv.getHor();
+            iMvScaleTmpVer = tmpMv.getVer();
+          }
+
+          xGetSublkAMLTemplate(*pu.cu, COMPONENT_Y, *refPic, Mv(iMvScaleTmpHor, iMvScaleTmpVer), puWidth, puHeight, w, h, numTemplate, refLeftTemplate, refAboveTemplate
+#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , (pu.afMmvdFlag
+#else
+              , pu.afMmvdFlag
+#endif 
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+              && pu.cs->sps->getUseTMMMVD()
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              )
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            || (isBilinear
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+              && pu.cs->sps->getUseTMMMVD())
+#endif
+#endif
+#endif
+          );
+        }
+      }
+    }
   }
   else
   {
-    iDMvVerX = -iDMvHorY;
-    iDMvVerY = iDMvHorX;
-  }
-  int iMvScaleHor = mvLT.getHor() << iBit;
-  int iMvScaleVer = mvLT.getVer() << iBit;
+#endif
+    Mv mvLT = pu.mvAffi[eRefPicList][0];
+    Mv mvRT = pu.mvAffi[eRefPicList][1];
+    Mv mvLB = pu.mvAffi[eRefPicList][2];
+    // get affine sub-block width and height
+    const int width = pu.Y().width;
+    const int height = pu.Y().height;
+    int blockWidth = AFFINE_MIN_BLOCK_SIZE;
+    int blockHeight = AFFINE_MIN_BLOCK_SIZE;
 
-  const int shift = iBit - 4 + MV_FRACTIONAL_BITS_INTERNAL;
+    CHECK(blockWidth > width, "Sub Block width  > Block width");
+    CHECK(blockHeight > height, "Sub Block height > Block height");
+
+    const int cxWidth = width;
+    const int cxHeight = height;
+    const int iBit = MAX_CU_DEPTH;
+    int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY;
+    iDMvHorX = (mvRT - mvLT).getHor() << (iBit - floorLog2(width));
+    iDMvHorY = (mvRT - mvLT).getVer() << (iBit - floorLog2(width));
+    if (pu.cu->affineType == AFFINEMODEL_6PARAM)
+    {
+      iDMvVerX = (mvLB - mvLT).getHor() << (iBit - floorLog2(height));
+      iDMvVerY = (mvLB - mvLT).getVer() << (iBit - floorLog2(height));
+    }
+    else
+    {
+      iDMvVerX = -iDMvHorY;
+      iDMvVerY = iDMvHorX;
+    }
+    int iMvScaleHor = mvLT.getHor() << iBit;
+    int iMvScaleVer = mvLT.getVer() << iBit;
+
+    const int shift = iBit - 4 + MV_FRACTIONAL_BITS_INTERNAL;
 #if !AFFINE_RM_CONSTRAINTS_AND_OPT
-  const bool subblkMVSpreadOverLimit = isSubblockVectorSpreadOverLimit(iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY, pu.interDir);
+    const bool subblkMVSpreadOverLimit = isSubblockVectorSpreadOverLimit(iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY, pu.interDir);
 #endif
 #if AFFINE_RM_CONSTRAINTS_AND_OPT
-  if (iDMvHorX == 0 && iDMvHorY == 0)
-    blockWidth = width;
-  else
-  {
-    int maxDmv = std::max(abs(iDMvHorX), abs(iDMvHorY)) * blockWidth;
-    int TH = 1 << (iBit - 1); // Half pel
-    while (maxDmv < TH && blockWidth < width)
+    if (iDMvHorX == 0 && iDMvHorY == 0)
+      blockWidth = width;
+    else
     {
-      blockWidth <<= 1;
-      maxDmv <<= 1;
+      int maxDmv = std::max(abs(iDMvHorX), abs(iDMvHorY)) * blockWidth;
+      int TH = 1 << (iBit - 1); // Half pel
+      while (maxDmv < TH && blockWidth < width)
+      {
+        blockWidth <<= 1;
+        maxDmv <<= 1;
+      }
     }
-  }
-  if (iDMvVerX == 0 && iDMvVerY == 0)
-    blockHeight = height;
-  else
-  {
-    int maxDmv = std::max(abs(iDMvVerX), abs(iDMvVerY)) * blockHeight;
-    int TH = 1 << (iBit - 1); // Half pel
-    while (maxDmv < TH && blockHeight < height)
+    if (iDMvVerX == 0 && iDMvVerY == 0)
+      blockHeight = height;
+    else
     {
-      blockHeight <<= 1;
-      maxDmv <<= 1;
+      int maxDmv = std::max(abs(iDMvVerX), abs(iDMvVerY)) * blockHeight;
+      int TH = 1 << (iBit - 1); // Half pel
+      while (maxDmv < TH && blockHeight < height)
+      {
+        blockHeight <<= 1;
+        maxDmv <<= 1;
+      }
     }
-  }
 #endif
-  int iMvScaleTmpHor0 = iMvScaleHor + ((iDMvHorX * blockWidth + iDMvVerX * blockHeight) >> 1);
-  int iMvScaleTmpVer0 = iMvScaleVer + ((iDMvHorY * blockWidth + iDMvVerY * blockHeight) >> 1);
+    int iMvScaleTmpHor0 = iMvScaleHor + ((iDMvHorX * blockWidth + iDMvVerX * blockHeight) >> 1);
+    int iMvScaleTmpVer0 = iMvScaleVer + ((iDMvHorY * blockWidth + iDMvVerY * blockHeight) >> 1);
 
 #if JVET_Z0139_NA_AFF
-  const CodingUnit *const cuAbove = pu.cu->cs->getCU(pu.cu->blocks[COMPONENT_Y].pos().offset(0, -1), toChannelType(COMPONENT_Y));
-  const CodingUnit *const cuLeft  = pu.cu->cs->getCU(pu.cu->blocks[COMPONENT_Y].pos().offset(-1, 0), toChannelType(COMPONENT_Y));
+    const CodingUnit *const cuAbove = pu.cu->cs->getCU(pu.cu->blocks[COMPONENT_Y].pos().offset(0, -1), toChannelType(COMPONENT_Y));
+    const CodingUnit *const cuLeft = pu.cu->cs->getCU(pu.cu->blocks[COMPONENT_Y].pos().offset(-1, 0), toChannelType(COMPONENT_Y));
 
-  // get prediction block by block
-  for (int h = 0; (cuLeft && h < cxHeight) || h < 1; h += blockHeight)
-  {
-    for (int w = 0; (cuAbove && w < cxWidth) || w < 1; w += blockWidth)
+    // get prediction block by block
+    for (int h = 0; (cuLeft && h < cxHeight) || h < 1; h += blockHeight)
+    {
+      for (int w = 0; (cuAbove && w < cxWidth) || w < 1; w += blockWidth)
 #else
-  for (int h = 0; h < cxHeight; h += blockHeight)
-  {
-    for (int w = 0; w < cxWidth; w += blockWidth)
-#endif
+    for (int h = 0; h < cxHeight; h += blockHeight)
     {
-      if (w == 0 || h == 0)
+      for (int w = 0; w < cxWidth; w += blockWidth)
+#endif
       {
-        int iMvScaleTmpHor, iMvScaleTmpVer;
+        if (w == 0 || h == 0)
+        {
+          int iMvScaleTmpHor, iMvScaleTmpVer;
 
 #if !AFFINE_RM_CONSTRAINTS_AND_OPT
-        if (!subblkMVSpreadOverLimit)
+          if (!subblkMVSpreadOverLimit)
 #endif
-        {
-          iMvScaleTmpHor = iMvScaleTmpHor0 + iDMvHorX * w + iDMvVerX * h;
-          iMvScaleTmpVer = iMvScaleTmpVer0 + iDMvHorY * w + iDMvVerY * h;
-        }
+          {
+            iMvScaleTmpHor = iMvScaleTmpHor0 + iDMvHorX * w + iDMvVerX * h;
+            iMvScaleTmpVer = iMvScaleTmpVer0 + iDMvHorY * w + iDMvVerY * h;
+          }
 #if !AFFINE_RM_CONSTRAINTS_AND_OPT
-        else
-        {
-          iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (cxWidth >> 1) + iDMvVerX * (cxHeight >> 1);
-          iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (cxWidth >> 1) + iDMvVerY * (cxHeight >> 1);
-        }
+          else
+          {
+            iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (cxWidth >> 1) + iDMvVerX * (cxHeight >> 1);
+            iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (cxWidth >> 1) + iDMvVerY * (cxHeight >> 1);
+          }
 #endif
-        roundAffineMv(iMvScaleTmpHor, iMvScaleTmpVer, shift);
-        Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
-        tmpMv.clipToStorageBitDepth();
-        iMvScaleTmpHor = tmpMv.getHor();
-        iMvScaleTmpVer = tmpMv.getVer();
-
-        // clip and scale
-#if JVET_AA0146_WRAP_AROUND_FIX
-        bool wrapRef = false;
-        if ( refPic->isWrapAroundEnabled( pu.cs->pps ) )
-        {
+          roundAffineMv(iMvScaleTmpHor, iMvScaleTmpVer, shift);
           Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
-          wrapRef = wrapClipMv( tmpMv, pu.lumaPos(), pu.lumaSize(), pu.cs->sps, pu.cs->pps );
+          tmpMv.clipToStorageBitDepth();
           iMvScaleTmpHor = tmpMv.getHor();
           iMvScaleTmpVer = tmpMv.getVer();
-        }
-        else
-        {
-          wrapRef = false;
+
+          // clip and scale
+#if JVET_AA0146_WRAP_AROUND_FIX
+          bool wrapRef = false;
+          if (refPic->isWrapAroundEnabled(pu.cs->pps))
+          {
+            Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
+            wrapRef = wrapClipMv(tmpMv, pu.lumaPos(), pu.lumaSize(), pu.cs->sps, pu.cs->pps);
+            iMvScaleTmpHor = tmpMv.getHor();
+            iMvScaleTmpVer = tmpMv.getVer();
+          }
+          else
+          {
+            wrapRef = false;
 #endif
-        if (refPic->isRefScaled(pu.cs->pps) == false)
-        {
-          clipMv(tmpMv, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
-          iMvScaleTmpHor = tmpMv.getHor();
-          iMvScaleTmpVer = tmpMv.getVer();
-        }
+            if (refPic->isRefScaled(pu.cs->pps) == false)
+            {
+              clipMv(tmpMv, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+              iMvScaleTmpHor = tmpMv.getHor();
+              iMvScaleTmpVer = tmpMv.getVer();
+            }
 #if JVET_AA0146_WRAP_AROUND_FIX
-        }
+          }
 #endif
-        xGetSublkAMLTemplate(*pu.cu, COMPONENT_Y, *refPic, Mv(iMvScaleTmpHor, iMvScaleTmpVer), blockWidth, blockHeight, w, h, numTemplate, refLeftTemplate, refAboveTemplate
+          xGetSublkAMLTemplate(*pu.cu, COMPONENT_Y, *refPic, Mv(iMvScaleTmpHor, iMvScaleTmpVer), blockWidth, blockHeight, w, h, numTemplate, refLeftTemplate, refAboveTemplate
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
-                             , pu.afMmvdFlag
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , (pu.afMmvdFlag
+#else
+              , pu.afMmvdFlag
+#endif                          
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-                            && pu.cs->sps->getUseTMMMVD()
+              && pu.cs->sps->getUseTMMMVD()
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              )
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            || (isBilinear
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+              && pu.cs->sps->getUseTMMMVD()
+#endif
+              )
 #endif
 #endif
 #if JVET_AA0146_WRAP_AROUND_FIX
-                             , wrapRef
+            , wrapRef
 #endif
-                             );
+          );
+        }
       }
     }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
   }
+#endif
 }
 #endif
 
@@ -7711,11 +7810,19 @@ void  InterPrediction::sortAffineMergeCandidates(PredictionUnit pu, AffineMergeC
         //Store
         if (pu.interDir == 3)
         {
-          getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft, posList0, posList1, load0, load1);
+          getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            false, affMrgCtx,
+#endif
+            posList0, posList1, load0, load1);
         }
         else
         {
-          getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft);
+          getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , false, affMrgCtx
+#endif
+          );
         }
         if (m_bAMLTemplateAvailabe[0])
         {
@@ -7876,7 +7983,11 @@ void  InterPrediction::sortAffineMergeCandidates(PredictionUnit pu, AffineMergeC
     PelUnitBuf pcBufPredCurTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
     PelUnitBuf pcBufPredRefLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
     PelUnitBuf pcBufPredCurLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
-    getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft);
+    getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      , affMrgCtx
+#endif
+    );
     
     if (m_bAMLTemplateAvailabe[0])
     {
@@ -7920,7 +8031,82 @@ void  InterPrediction::sortAffineMergeCandidates(PredictionUnit pu, AffineMergeC
 }
 #endif
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+void InterPrediction::adjustMergeCandidatesInOneCandidateGroupSubTMVP(PredictionUnit &pu, MergeCtx& mvpMergeCandCtx, int numRetrievedMergeCand, int mrgCandIdx)
+{
+  if (mvpMergeCandCtx.numValidMergeCand <= 1)
+  {
+    return;
+  }
+
+  const int numCandInCategory = std::min(numRetrievedMergeCand, mvpMergeCandCtx.numValidMergeCand);
+
+  uint32_t rdCandList[MRG_MAX_NUM_CANDS];
+  Distortion candCostList[MRG_MAX_NUM_CANDS];
+
+  for (uint32_t j = 0; j < MRG_MAX_NUM_CANDS; j++)
+  {
+    rdCandList[j] = j;
+    candCostList[j] = MAX_UINT;
+  }
+
+  Distortion uiCost;
+
+  DistParam cDistParam;
+  cDistParam.applyWeight = false;
 
+  int nWidth = pu.lumaSize().width;
+  int nHeight = pu.lumaSize().height;
+
+  auto origMergeIdx = pu.mergeIdx;
+  for (uint32_t uiMergeCand = 0; uiMergeCand < mvpMergeCandCtx.numValidMergeCand; uiMergeCand++)
+  {
+    if (mvpMergeCandCtx.candCost[uiMergeCand] == MAX_UINT64)
+    {
+      uiCost = 0;
+
+      mvpMergeCandCtx.setMergeInfo(pu, uiMergeCand);
+
+      PelUnitBuf pcBufPredRefTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
+      PelUnitBuf pcBufPredCurTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
+      PelUnitBuf pcBufPredRefLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
+      PelUnitBuf pcBufPredCurLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
+
+      getBlkAMLRefTemplateSubTMVP(pu, pcBufPredRefTop, pcBufPredRefLeft);
+
+      if (m_bAMLTemplateAvailabe[0])
+      {
+        m_pcRdCost->setDistParam(cDistParam, pcBufPredCurTop.Y(), pcBufPredRefTop.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
+
+        uiCost += cDistParam.distFunc(cDistParam);
+      }
+
+      if (m_bAMLTemplateAvailabe[1])
+      {
+        m_pcRdCost->setDistParam(cDistParam, pcBufPredCurLeft.Y(), pcBufPredRefLeft.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
+
+        uiCost += cDistParam.distFunc(cDistParam);
+      }
+    }
+    else
+    {
+      uiCost = mvpMergeCandCtx.candCost[uiMergeCand];
+    }
+
+    updateCandList(uiMergeCand, uiCost, numCandInCategory, rdCandList, candCostList);
+  }
+  pu.mergeIdx = origMergeIdx;
+
+  updateCandInOneCandidateGroup(mvpMergeCandCtx, rdCandList, numCandInCategory);
+
+  mvpMergeCandCtx.numValidMergeCand = numCandInCategory;
+
+  for (int idx = 0; idx < numCandInCategory; idx++)
+  {
+    mvpMergeCandCtx.candCost[idx] = candCostList[idx];
+  }
+}
+#endif
 #if JVET_W0090_ARMC_TM
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
 void InterPrediction::adjustMergeCandidatesInOneCandidateGroup(PredictionUnit &pu, MergeCtx& mvpMergeCandCtx, int numRetrievedMergeCand, int mrgCandIdx)
@@ -7950,6 +8136,13 @@ void InterPrediction::adjustMergeCandidatesInOneCandidateGroup(PredictionUnit &p
   int nHeight = pu.lumaSize().height;
 
   auto origMergeIdx = pu.mergeIdx;
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  PredictionUnit puTmp;
+  CodingUnit cuTmp;
+  puTmp.cu = &cuTmp;
+  mvpMergeCandCtx.saveMergeInfo(puTmp, pu);
+#endif
+
   for (uint32_t uiMergeCand = 0; uiMergeCand < mvpMergeCandCtx.numValidMergeCand; uiMergeCand++)
   {
     if (mvpMergeCandCtx.candCost[uiMergeCand] == MAX_UINT64)
@@ -7996,6 +8189,9 @@ void InterPrediction::adjustMergeCandidatesInOneCandidateGroup(PredictionUnit &p
   {
     mvpMergeCandCtx.candCost[idx] = candCostList[idx];
   }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  mvpMergeCandCtx.saveMergeInfo(pu, puTmp);
+#endif
 }
 
 #if JVET_AB0079_TM_BCW_MRG
@@ -9065,7 +9261,226 @@ void  InterPrediction::updateCandInfo(MergeCtx& mrgCtx, uint32_t(*RdCandList)[MR
   }
 }
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+void InterPrediction::getBlkAMLRefTemplateSubTMVP(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft)
+{
+  Mv mvCurr;
+  const int lumaShift = 2 + MV_FRACTIONAL_BITS_DIFF;
+  const int horShift = (lumaShift + ::getComponentScaleX(COMPONENT_Y, pu.chromaFormat));
+  const int verShift = (lumaShift + ::getComponentScaleY(COMPONENT_Y, pu.chromaFormat));
+
+  if (xCheckIdenticalMotionSubTMVP(pu))
+  {
+    mvCurr = pu.mv[0];
+    /*const int horIntMv = (mvCurr.getHor() + ((1 << horShift) >> 1)) >> horShift;
+    const int verIntMv = (mvCurr.getVer() + ((1 << verShift) >> 1)) >> verShift;
+    Mv    subPelMv(horIntMv << horShift, verIntMv << verShift);*/
+    Mv subPelMv = mvCurr;
+    clipMv(mvCurr, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+    CHECK(pu.refIdx[0] < 0, "invalid ref idx");
+
+    if (m_bAMLTemplateAvailabe[0])
+    {
+      Mv mvTop(0, -(AML_MERGE_TEMPLATE_SIZE << verShift));
+      mvTop += subPelMv;
+
+      clipMv(mvTop, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+
+#if RPR_ENABLE
+      const Picture* picRef = pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0])->unscaledPic;
+      const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(REF_PIC_LIST_0, pu.refIdx[0]);
+#if INTER_LIC
+      xPredInterBlk(COMPONENT_Y, pu, picRef, mvTop, pcBufPredRefTop,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+      xPredInterBlk(COMPONENT_Y, pu, picRef, mvTop, pcBufPredRefTop,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true);
+#endif
+#else
+#if INTER_LIC
+      xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0]), mvTop, pcBufPredRefTop,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true,
+        mvCurr);
+#else
+      xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0]), mvTop, pcBufPredRefTop,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
+#endif
+#endif
+    }
+    if (m_bAMLTemplateAvailabe[1])
+    {
+      Mv mvLeft(-(AML_MERGE_TEMPLATE_SIZE << horShift), 0);
+      mvLeft += subPelMv;
+
+      clipMv(mvLeft, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+
+#if RPR_ENABLE
+      const Picture* picRef = pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0])->unscaledPic;
+      const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(REF_PIC_LIST_0, pu.refIdx[0]);
+#if INTER_LIC
+      xPredInterBlk(COMPONENT_Y, pu, picRef, mvLeft, pcBufPredRefLeft,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+      xPredInterBlk(COMPONENT_Y, pu, picRef, mvLeft, pcBufPredRefLeft,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true);
+#endif
+#else
+#if INTER_LIC
+      xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0]), mvLeft, pcBufPredRefLeft,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true,
+        mvCurr);
+#else
+      xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[0]), mvLeft, pcBufPredRefLeft,
+        false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
+#endif
+#endif
+    }
+  }
+  else
+  {
+    for (uint32_t refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
+    {
+      if (!(pu.interDir & (1 << refList)))
+      {
+        continue;
+      }
+      RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
+      CHECK(pu.refIdx[refList] >= pu.cu->slice->getNumRefIdx(eRefPicList), "Invalid reference index");
+
+      m_iRefListIdx = refList;
+      mvCurr = pu.mv[refList];
+      Mv subPelMv = mvCurr;
+      clipMv(mvCurr, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
 
+      if (m_bAMLTemplateAvailabe[0])
+      {
+        Mv mvTop(0, -(AML_MERGE_TEMPLATE_SIZE << verShift));
+        mvTop += subPelMv;
+
+        clipMv(mvTop, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+
+        PelUnitBuf pcMbBuf =
+          PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[refList][0], pcBufPredRefTop.Y()));
+
+        if (pu.interDir == 3)
+        {
+#if RPR_ENABLE
+          const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
+          const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvTop, pcMbBuf, true,
+            pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvTop, pcMbBuf, true,
+            pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true);
+#endif
+#else
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvTop, pcMbBuf, true,
+            pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true,
+            mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvTop, pcMbBuf, true,
+            pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
+#endif
+#endif
+        }
+        else
+        {
+#if RPR_ENABLE
+          const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
+          const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvTop, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvTop, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true);
+#endif
+#else
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvTop, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvTop, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
+#endif
+#endif
+        }
+      }
+      if (m_bAMLTemplateAvailabe[1])
+      {
+        Mv mvLeft(-(AML_MERGE_TEMPLATE_SIZE << horShift), 0);
+        mvLeft += subPelMv;
+
+        clipMv(mvLeft, pu.lumaPos(), pu.lumaSize(), *pu.cs->sps, *pu.cs->pps);
+
+        PelUnitBuf pcMbBuf =
+          PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[refList][0], pcBufPredRefLeft.Y()));
+
+        if (pu.interDir == 3)
+        {
+#if RPR_ENABLE
+          const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
+          const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
+            true, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
+            true, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true);
+#endif
+#else
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvLeft, pcMbBuf,
+            true, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvLeft, pcMbBuf,
+            true, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
+#endif
+#endif
+        }
+        else
+        {
+#if RPR_ENABLE
+          const Picture* picRef = pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList])->unscaledPic;
+          const std::pair<int, int>& scalingRatio = pu.cu->slice->getScalingRatio(eRefPicList, pu.refIdx[refList]);
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, picRef, mvLeft, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, scalingRatio, 0, 0, false, NULL, 0, true);
+#endif
+#else
+#if INTER_LIC
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvLeft, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true, true, mvCurr);
+#else
+          xPredInterBlk(COMPONENT_Y, pu, pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[refList]), mvLeft, pcMbBuf,
+            false, pu.cu->slice->clpRng(COMPONENT_Y), false, false, SCALE_1X, 0, 0, false, NULL, 0, true);
+#endif
+#endif
+        }
+      }
+    }
+    if (m_bAMLTemplateAvailabe[0])
+    {
+      CPelUnitBuf srcPred0 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[0][0], pcBufPredRefTop.Y()));
+      CPelUnitBuf srcPred1 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAboveTemplate[1][0], pcBufPredRefTop.Y()));
+      xWeightedAverageY(pu, srcPred0, srcPred1, pcBufPredRefTop, pu.cu->slice->getSPS()->getBitDepths(),
+        pu.cu->slice->clpRngs());
+    }
+    if (m_bAMLTemplateAvailabe[1])
+    {
+      CPelUnitBuf srcPred0 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[0][0], pcBufPredRefLeft.Y()));
+      CPelUnitBuf srcPred1 = CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefLeftTemplate[1][0], pcBufPredRefLeft.Y()));
+      xWeightedAverageY(pu, srcPred0, srcPred1, pcBufPredRefLeft, pu.cu->slice->getSPS()->getBitDepths(),
+        pu.cu->slice->clpRngs());
+    }
+  }
+}
+#endif
 #if JVET_W0090_ARMC_TM || JVET_Z0056_GPM_SPLIT_MODE_REORDERING
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
 void InterPrediction::getBlkAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft, int8_t posList0, int8_t posList1, bool load0, bool load1)
@@ -9420,10 +9835,16 @@ void  InterPrediction::adjustAffineMergeCandidates(PredictionUnit &pu, AffineMer
 #if INTER_LIC
     pu.cu->LICFlag = affMrgCtx.LICFlags[uiMergeCand];
 #endif
-
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    pu.colIdx = affMrgCtx.colIdx[uiMergeCand];
+#endif
     pu.mergeType = affMrgCtx.mergeType[uiMergeCand];
 #if JVET_Z0139_NA_AFF
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    if ((pu.mergeType == MRG_TYPE_DEFAULT_N) || (pu.mergeType == MRG_TYPE_SUBPU_ATMVP && uiMergeCand))
+#else
     if (pu.mergeType == MRG_TYPE_DEFAULT_N)
+#endif
 #else
     if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
     {
@@ -9468,7 +9889,11 @@ void  InterPrediction::adjustAffineMergeCandidates(PredictionUnit &pu, AffineMer
       {
 #endif
 
-      getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft);
+      getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , pu.cs->sps->getUseFastSubTmvp(), affMrgCtx
+#endif
+      );
 
       if (m_bAMLTemplateAvailabe[0])
       {
@@ -9602,6 +10027,9 @@ void  InterPrediction::updateAffineCandInfo(PredictionUnit &pu, AffineMergeCtx&
     affMrgCtxTmp.affineType[i] = AFFINEMODEL_4PARAM;
     affMrgCtxTmp.mergeType[i] = MRG_TYPE_DEFAULT_N;
     affMrgCtxTmp.BcwIdx[i] = BCW_DEFAULT;
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    affMrgCtxTmp.colIdx[i] = 0;
+#endif
 #if INTER_LIC
     affMrgCtxTmp.LICFlags[i] = false;
 #endif
@@ -9623,6 +10051,9 @@ void  InterPrediction::updateAffineCandInfo(PredictionUnit &pu, AffineMergeCtx&
     affMrgCtxTmp.affineType[uiMergeCand] = affMrgCtx.affineType[uiMergeCand];
     affMrgCtxTmp.mergeType[uiMergeCand] = affMrgCtx.mergeType[uiMergeCand];
     affMrgCtxTmp.BcwIdx[uiMergeCand] = affMrgCtx.BcwIdx[uiMergeCand];
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    affMrgCtxTmp.colIdx[uiMergeCand] = affMrgCtx.colIdx[uiMergeCand];
+#endif
 #if INTER_LIC                                                   
     affMrgCtxTmp.LICFlags[uiMergeCand] = affMrgCtx.LICFlags[uiMergeCand];
 #endif
@@ -9651,6 +10082,9 @@ void  InterPrediction::updateAffineCandInfo(PredictionUnit &pu, AffineMergeCtx&
     affMrgCtx.affineType[uiMergeCand] = affMrgCtxTmp.affineType[RdCandList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_AFFINE_SUB_GROUP_SIZE]];
     affMrgCtx.mergeType[uiMergeCand] = affMrgCtxTmp.mergeType[RdCandList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_AFFINE_SUB_GROUP_SIZE]];
     affMrgCtx.BcwIdx[uiMergeCand] = affMrgCtxTmp.BcwIdx[RdCandList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_AFFINE_SUB_GROUP_SIZE]];
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    affMrgCtx.colIdx[uiMergeCand] = affMrgCtxTmp.colIdx[RdCandList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_AFFINE_SUB_GROUP_SIZE]];
+#endif
 #if INTER_LIC 
     affMrgCtx.LICFlags[uiMergeCand] = affMrgCtxTmp.LICFlags[RdCandList[uiMergeCand / ADAPTIVE_AFFINE_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_AFFINE_SUB_GROUP_SIZE]];
 #endif
@@ -9723,9 +10157,17 @@ void InterPrediction::xGetSublkAMLTemplate(const CodingUnit& cu,
   }
 }
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
-void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft, int8_t posList0, int8_t posList1, bool load0, bool load1)
+void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft, 
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  bool isBilinear, AffineMergeCtx affMrgCtx,
+#endif
+  int8_t posList0, int8_t posList1, bool load0, bool load1)
 #else
-void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft)
+void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  AffineMergeCtx affMrgCtx,
+#endif
+)
 #endif
 {
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
@@ -9750,7 +10192,11 @@ void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBuf
 #if JVET_Z0067_RPR_ENABLE
       CHECK(pu.cu->slice->getRefPic(eRefPicList, pu.refIdx[eRefPicList])->isRefScaled(pu.cs->pps), "getAffAMLRefTemplate not supported with ref scaled.");
 #endif
-      xPredAffineTpl(pu, eRefPicList, numTemplate, refLeftTemplate, refAboveTemplate);
+      xPredAffineTpl(pu, eRefPicList, numTemplate, refLeftTemplate, refAboveTemplate
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , affMrgCtx, isBilinear
+#endif
+      );
 #if INTER_LIC
       if (pu.cu->LICFlag)
       {
@@ -9802,7 +10248,11 @@ void InterPrediction::getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBuf
         }
 #endif
         int  numTemplate[2]   = { 0, 0 };   // 0:Above, 1:Left
-        xPredAffineTpl(pu, eRefPicList, numTemplate, refLeftTemplate, refAboveTemplate);
+        xPredAffineTpl(pu, eRefPicList, numTemplate, refLeftTemplate, refAboveTemplate
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , affMrgCtx, isBilinear
+#endif
+        );
 #if INTER_LIC
         if (pu.cu->LICFlag)
         {
@@ -10271,6 +10721,9 @@ void  InterPrediction::adjustAffineMergeCandidatesOneGroup(PredictionUnit &pu, A
     pu.cu->BcwIdx = affMrgCtx.BcwIdx[uiMergeCand];
 #if INTER_LIC
     pu.cu->LICFlag = affMrgCtx.LICFlags[uiMergeCand];
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    pu.colIdx = affMrgCtx.colIdx[uiMergeCand];
 #endif
     pu.mergeType = affMrgCtx.mergeType[uiMergeCand];
 #if JVET_Z0139_NA_AFF
@@ -10310,8 +10763,11 @@ void  InterPrediction::adjustAffineMergeCandidatesOneGroup(PredictionUnit &pu, A
       {
 #endif
 
-        getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft);
-
+        getAffAMLRefTemplate(pu, pcBufPredRefTop, pcBufPredRefLeft
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , true, affMrgCtx
+#endif
+        );
         if (m_bAMLTemplateAvailabe[0])
         {
           m_pcRdCost->setDistParam(cDistParam, pcBufPredCurTop.Y(), pcBufPredRefTop.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
@@ -10355,6 +10811,9 @@ void  InterPrediction::updateAffineCandInfo2(PredictionUnit &pu, AffineMergeCtx&
     affMrgCtxTmp.affineType[uiMergeCand] = affMrgCtx.affineType[uiMergeCand];
     affMrgCtxTmp.mergeType[uiMergeCand] = affMrgCtx.mergeType[uiMergeCand];
     affMrgCtxTmp.BcwIdx[uiMergeCand] = affMrgCtx.BcwIdx[uiMergeCand];
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    affMrgCtxTmp.colIdx[uiMergeCand] = affMrgCtx.colIdx[uiMergeCand];
+#endif
 #if INTER_LIC                                                   
     affMrgCtxTmp.LICFlags[uiMergeCand] = affMrgCtx.LICFlags[uiMergeCand];
 #endif
@@ -13014,6 +13473,29 @@ bool InterPrediction::readTplAmvpBuffer(AMVPInfo& dst, const CodingUnit& cu, Ref
 }
 #endif
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+void InterPrediction::writeMergeBuffer(const MergeCtx& srcList0, const MergeCtx& srcList1, const CodingUnit& cu)
+{
+  m_pcMergeCtxList0 = srcList0;
+  m_pcMergeCtxList1 = srcList1;
+}
+bool InterPrediction::readMergeBuffer( MergeCtx& dstList0, MergeCtx& dstList1, const CodingUnit& cu)
+{
+  if (m_pcMergeCtxList0.numValidMergeCand > 0 || m_pcMergeCtxList1.numValidMergeCand > 0)
+  {
+    dstList0 = m_pcMergeCtxList0;
+    dstList1 = m_pcMergeCtxList1;
+    return true;
+  }
+  return false;
+}
+void InterPrediction::clearAmvpTmvpBuffer()
+{
+  m_pcMergeCtxList0 = MergeCtx();
+  m_pcMergeCtxList1 = MergeCtx();
+}
+#endif
+
 #if MULTI_PASS_DMVR
 #if JVET_X0049_ADAPT_DMVR
 bool InterPrediction::processBDMVRPU2Dir(PredictionUnit& pu, bool subPURefine[2], Mv(&finalMvDir)[2])
@@ -15997,7 +16479,12 @@ void InterPrediction::reorderRefCombList(PredictionUnit &pu, std::vector<RefList
       tmpPU.mvAffi[eRefList][2] = mvLB;
 
 #if !JVET_Z0067_RPR_ENABLE
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      AffineMergeCtx tmp;
+      getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft, tmp);
+#else
       getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft);
+#endif
 #endif
 
       uiCost = 0;
@@ -16009,7 +16496,12 @@ void InterPrediction::reorderRefCombList(PredictionUnit &pu, std::vector<RefList
       else
       {
 #if JVET_Z0067_RPR_ENABLE
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        AffineMergeCtx tmp;
+        getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft, pu.cs->sps->getUseFastSubTmvp(), tmp);
+#else
         getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft);
+#endif
 #endif
         if (m_bAMLTemplateAvailabe[0])
         {
@@ -16468,7 +16960,12 @@ void InterPrediction::reorderRefPairList(PredictionUnit &pu, std::vector<RefPicP
 
 #endif
 #if !JVET_Z0067_RPR_ENABLE
-      getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          AffineMergeCtx tmp;
+          getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft, tmp);
+#else
+          getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft);
+#endif
 #endif
 
       uiCost = 0;
@@ -16485,7 +16982,12 @@ void InterPrediction::reorderRefPairList(PredictionUnit &pu, std::vector<RefPicP
       else
       {
 #if JVET_Z0067_RPR_ENABLE
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        AffineMergeCtx tmp;
+        getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft, pu.cs->sps->getUseFastSubTmvp(), tmp);
+#else
         getAffAMLRefTemplate(tmpPU, pcBufPredRefTop, pcBufPredRefLeft);
+#endif
 #endif
         if (m_bAMLTemplateAvailabe[0])
         {
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 818e7d060af3e431db1fff81c1d5329f5996a2d2..a00ac8f6318c6f6c4383144d10b144523956672a 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -118,7 +118,10 @@ private:
   AMVPInfo m_tplAmvpInfoLIC[NUM_IMV_MODES][NUM_REF_PIC_LIST_01][MAX_NUM_REF];
 #endif
 #endif
-
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  MergeCtx m_pcMergeCtxList0;
+  MergeCtx m_pcMergeCtxList1;
+#endif
 #if JVET_AC0144_AFFINE_DMVR_REGRESSION
   const Picture* m_bmRefPic[2];
   CPelBuf   m_bmRefBuf[2];
@@ -338,7 +341,11 @@ protected:
   void xWeightedAverageY(const PredictionUnit& pu, const CPelUnitBuf& pcYuvSrc0, const CPelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const BitDepths& clipBitDepths, const ClpRngs& clpRngs);
 #endif
 #if JVET_W0090_ARMC_TM
-  void xPredAffineTpl(const PredictionUnit &pu, const RefPicList &eRefPicList, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate);
+  void xPredAffineTpl(const PredictionUnit &pu, const RefPicList &eRefPicList, int* numTemplate, Pel* refLeftTemplate, Pel* refAboveTemplate
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    , AffineMergeCtx affMrgCtx, bool isBilinear
+#endif
+  );
 #endif
 #if AFFINE_ENC_OPT
 #if JVET_Z0136_OOB
@@ -366,7 +373,11 @@ protected:
   void xSubPuBio(PredictionUnit& pu, PelUnitBuf& predBuf, const RefPicList &eRefPicList = REF_PIC_LIST_X, PelUnitBuf* yuvDstTmp = NULL);
 #endif
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  MotionInfo      m_SubPuMiBuf[SUB_TMVP_NUM][(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
+#else
   MotionInfo      m_SubPuMiBuf[(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
+#endif
 #if JVET_W0090_ARMC_TM || JVET_Z0056_GPM_SPLIT_MODE_REORDERING || JVET_Z0061_TM_OBMC || JVET_AA0061_IBC_MBVD
   Pel*   m_acYuvCurAMLTemplate[2][MAX_NUM_COMPONENT];   //0: top, 1: left
   bool   m_bAMLTemplateAvailabe[2];
@@ -607,7 +618,11 @@ public:
   void    sortAffineMergeCandidates(PredictionUnit pu, AffineMergeCtx& affMrgCtx, uint32_t * affMmvdLUT, uint32_t afMMVDIdx = -1);
 #endif
 #endif
-    
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  void    getBlkAMLRefTemplateSubTMVP(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft);
+  static bool xCheckIdenticalMotionSubTMVP(const PredictionUnit& pu);
+  void    adjustMergeCandidatesInOneCandidateGroupSubTMVP(PredictionUnit &pu, MergeCtx& smvpMergeCandCtx, int numRetrievedMergeCand, int mrgCandIdx = -1);
+#endif 
 #if JVET_W0090_ARMC_TM
   void    adjustInterMergeCandidates(PredictionUnit &pu, MergeCtx& mrgCtx, int mrgCandIdx = -1);
 #endif
@@ -662,7 +677,11 @@ public:
 #endif
                                );
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
-  void    getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft, int8_t posList0 = -1, int8_t posList1 = -1, bool loadSave0 = false, bool loadSave1 = false);
+  void    getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    bool isBilinear, AffineMergeCtx affMrgCtx,
+#endif
+    int8_t posList0 = -1, int8_t posList1 = -1, bool loadSave0 = false, bool loadSave1 = false);
 #else
   void    getAffAMLRefTemplate(PredictionUnit &pu, PelUnitBuf &pcBufPredRefTop, PelUnitBuf &pcBufPredRefLeft);
 #endif
@@ -781,6 +800,11 @@ public:
   void       clearTplAmvpBuffer ();
   void       writeTplAmvpBuffer (const AMVPInfo& src, const CodingUnit& cu, RefPicList eRefList, int refIdx);
   bool       readTplAmvpBuffer  (      AMVPInfo& dst, const CodingUnit& cu, RefPicList eRefList, int refIdx);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void       writeMergeBuffer(const MergeCtx& srcList0, const MergeCtx& srcList1, const CodingUnit& cu);
+  bool       readMergeBuffer(       MergeCtx& dstList0,       MergeCtx& dstList1, const CodingUnit& cu);
+  void       clearAmvpTmvpBuffer();
+#endif
 #endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   static Distortion getDecoderSideDerivedMvCost (const Mv& mvStart, const Mv& mvCur, int searchRangeInFullPel, int weight);
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 7b870e1cda765a639a8bd419075b01c92cb55259..4db0a4ee53f36376c29eb0765ebe717c9fa4529c 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1778,6 +1778,9 @@ private:
 #if JVET_W0090_ARMC_TM || JVET_Y0058_IBC_LIST_MODIFY || JVET_Z0075_IBC_HMVP_ENLARGE
   bool              m_AML;
 #endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  bool              m_fastSubTmvp;
+#endif
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   bool              m_armcRefinedMotion;
 #endif
@@ -2333,6 +2336,10 @@ void                    setCCALFEnabledFlag( bool b )
   void      setUseAML             ( bool b )                                        { m_AML = b; }
   bool      getUseAML             ()                                      const     { return m_AML; }
 #endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  void      setUseFastSubTmvp     ( bool b )                                        { m_fastSubTmvp = b; }
+  bool      getUseFastSubTmvp     ()                                      const     { return m_fastSubTmvp; }
+#endif
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   void      setUseArmcRefinedMotion ( bool b )                                      { m_armcRefinedMotion = b; }
   bool      getUseArmcRefinedMotion  ()                                   const     { return m_armcRefinedMotion; }
@@ -2910,6 +2917,10 @@ private:
   bool                        m_enableTMVPFlag;                                         //!< enable temporal motion vector prediction
   bool                        m_picColFromL0Flag;                                       //!< syntax element collocated_from_l0_flag
   uint32_t                    m_colRefIdx;
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  bool                        m_picColFromL0Flag2nd;                                    //!< syntax element collocated_from_l0_flag
+  uint32_t                    m_colRefIdx2nd;
+#endif
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
   uint32_t                    m_costForARMC;                                            //!< Cost for diversity criterion
 #endif
@@ -3053,6 +3064,12 @@ public:
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
   void                        setCostForARMC(uint32_t cost)                             { m_costForARMC = cost;                                                                        }
   uint32_t                    getCostForARMC()                                          { return m_costForARMC;                                                                        }
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void                        setPicColFromL0Flag2nd(bool val)                          { m_picColFromL0Flag2nd = val;                                                                 }
+  bool                        getPicColFromL0Flag2nd() const                            { return m_picColFromL0Flag2nd;                                                                }
+  void                        setColRefIdx2nd(uint32_t refIdx)                          { m_colRefIdx2nd = refIdx;                                                                     }
+  uint32_t                    getColRefIdx2nd()                                         { return m_colRefIdx2nd;                                                                       }
 #endif
   void                        setMvdL1ZeroFlag( bool b )                                { m_mvdL1ZeroFlag = b;                                                                         }
   bool                        getMvdL1ZeroFlag() const                                  { return m_mvdL1ZeroFlag;                                                                      }
@@ -3294,11 +3311,19 @@ private:
 
 
   uint32_t                   m_colRefIdx;
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  bool                       m_colFromL0Flag2nd;  // collocated picture from List0 flag
+  uint32_t                   m_colRefIdx2nd;
+#endif
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
   uint32_t                   m_costForARMC;
 #endif
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  std::vector<int>           m_implicitRefIdx[2][NUM_REF_PIC_LIST_01][NUM_REF_PIC_LIST_01][MAX_NUM_REF + 1];
+#else
   std::vector<int>           m_implicitRefIdx[NUM_REF_PIC_LIST_01][NUM_REF_PIC_LIST_01][MAX_NUM_REF + 1];
+#endif
 #endif
   double                     m_lambdas[MAX_NUM_COMPONENT];
 #if INTER_LIC
@@ -3455,11 +3480,37 @@ public:
   int                         getDepth() const                                       { return m_iDepth;                                              }
   bool                        getColFromL0Flag() const                               { return m_colFromL0Flag;                                       }
   uint32_t                    getColRefIdx() const                                   { return m_colRefIdx;                                           }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  bool                        getColFromL0Flag2nd() const                            { return m_colFromL0Flag2nd;                                    }
+  uint32_t                    getColRefIdx2nd() const                                { return m_colRefIdx2nd;                                        }
+#endif
   void                        checkColRefIdx(uint32_t curSliceSegmentIdx, const Picture* pic);
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
   uint32_t                    getCostForARMC() const                                 { return m_costForARMC;                                         }
 #endif
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void resizeImBuf(int numSlices, int col)
+  {
+    for (int refIdx = 0; refIdx < MAX_NUM_REF + 1; refIdx++)
+    {
+      m_implicitRefIdx[col][REF_PIC_LIST_0][REF_PIC_LIST_0][refIdx].resize(numSlices);
+      std::fill(m_implicitRefIdx[col][REF_PIC_LIST_0][REF_PIC_LIST_0][refIdx].begin(), m_implicitRefIdx[col][REF_PIC_LIST_0][REF_PIC_LIST_0][refIdx].end(), -1);
+
+      m_implicitRefIdx[col][REF_PIC_LIST_0][REF_PIC_LIST_1][refIdx].resize(numSlices);
+      std::fill(m_implicitRefIdx[col][REF_PIC_LIST_0][REF_PIC_LIST_1][refIdx].begin(), m_implicitRefIdx[col][REF_PIC_LIST_0][REF_PIC_LIST_1][refIdx].end(), -1);
+
+      m_implicitRefIdx[col][REF_PIC_LIST_1][REF_PIC_LIST_0][refIdx].resize(numSlices);
+      std::fill(m_implicitRefIdx[col][REF_PIC_LIST_1][REF_PIC_LIST_0][refIdx].begin(), m_implicitRefIdx[col][REF_PIC_LIST_1][REF_PIC_LIST_0][refIdx].end(), -1);
+
+      m_implicitRefIdx[col][REF_PIC_LIST_1][REF_PIC_LIST_1][refIdx].resize(numSlices);
+      std::fill(m_implicitRefIdx[col][REF_PIC_LIST_1][REF_PIC_LIST_1][refIdx].begin(), m_implicitRefIdx[col][REF_PIC_LIST_1][REF_PIC_LIST_1][refIdx].end(), -1);
+    }
+  }
+  void                        setImRefIdx(int sliceIdx, RefPicList colRefPicList, RefPicList curRefPicList, int col_refIdx, int cur_refIdx, int col) { m_implicitRefIdx[col][colRefPicList][curRefPicList][col_refIdx][sliceIdx] = cur_refIdx; }
+  int                         getImRefIdx(int sliceIdx, RefPicList colRefPicList, RefPicList curRefPicList, int col_refIdx, int col = 0) { return m_implicitRefIdx[col][colRefPicList][curRefPicList][col_refIdx][sliceIdx]; }
+  int                         getImRefIdx(int sliceIdx, RefPicList colRefPicList, RefPicList curRefPicList, int col_refIdx, int col = 0) const { return m_implicitRefIdx[col][colRefPicList][curRefPicList][col_refIdx][sliceIdx]; }
+#else
   void resizeImBuf(int numSlices)
   {
     for (int refIdx = 0; refIdx < MAX_NUM_REF + 1; refIdx++)
@@ -3480,6 +3531,7 @@ public:
   void                        setImRefIdx(int sliceIdx, RefPicList colRefPicList, RefPicList curRefPicList, int col_refIdx, int cur_refIdx) { m_implicitRefIdx[colRefPicList][curRefPicList][col_refIdx][sliceIdx] = cur_refIdx; }
   int                         getImRefIdx(int sliceIdx, RefPicList colRefPicList, RefPicList curRefPicList, int col_refIdx) { return m_implicitRefIdx[colRefPicList][curRefPicList][col_refIdx][sliceIdx]; }
   int                         getImRefIdx(int sliceIdx, RefPicList colRefPicList, RefPicList curRefPicList, int col_refIdx) const { return m_implicitRefIdx[colRefPicList][curRefPicList][col_refIdx][sliceIdx]; }
+#endif
 #endif
   bool                        getIsUsedAsLongTerm(int i, int j) const                { return m_bIsUsedAsLongTerm[i][j];                             }
   void                        setIsUsedAsLongTerm(int i, int j, bool value)          { m_bIsUsedAsLongTerm[i][j] = value;                            }
@@ -3555,7 +3607,10 @@ public:
   void                        setColFromL0Flag( bool colFromL0 )                     { m_colFromL0Flag = colFromL0;                                  }
   void                        setColRefIdx( uint32_t refIdx)                             { m_colRefIdx = refIdx;                                         }
   void                        setCheckLDC( bool b )                                  { m_bCheckLDC = b;                                              }
-
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void                        setColFromL0Flag2nd(bool colFromL0)                    { m_colFromL0Flag2nd = colFromL0;                               }
+  void                        setColRefIdx2nd(uint32_t refIdx)                       { m_colRefIdx2nd = refIdx;                                      }
+#endif
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
   void                        setCostForARMC(uint32_t cost)                          { m_costForARMC = cost;                                         }
 #endif
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index c8fdd89766535155e639cf999c0931fed79f05c3..99144a7f161f7b7bc90c9a6567773f8bbe644747 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -262,6 +262,7 @@
 #define JVET_Z0054_BLK_REF_PIC_REORDER                    1 // JVET-Z0054: Block level TM based reordering of reference pictures
 #define JVET_AA0093_REFINED_MOTION_FOR_ARMC               1 // JVET-AA0093: Refined motion for ARMC
 #define JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC          1 // JVET-AA0093: Diversity criterion for ARMC reordering
+#define JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION   1 // JVET-AC0185: Enhanced temporal motion information derivation
 #endif
 // Transform and coefficient coding
 #define TCQ_8STATES                                       1
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index d46719512cd6471042e06147132dfed2222a3d5f..0d08e36191087818d9a107ee15d67a5e62eee9e8 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -775,6 +775,9 @@ void PredictionUnit::initData()
 #endif
 #endif
   // inter data
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  colIdx = 0;
+#endif
   mergeFlag   = false;
   regularMergeFlag = false;
   mergeIdx    = MAX_UCHAR;
@@ -927,6 +930,9 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData)
 
 PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData)
 {
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  colIdx = predData.colIdx;
+#endif
   mergeFlag   = predData.mergeFlag;
   regularMergeFlag = predData.regularMergeFlag;
   mergeIdx    = predData.mergeIdx;
@@ -1070,6 +1076,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
 
   mergeFlag   = other.mergeFlag;
   regularMergeFlag = other.regularMergeFlag;
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  colIdx = other.colIdx;
+#endif
   mergeIdx    = other.mergeIdx;
 #if ENABLE_DIMD || JVET_W0123_TIMD_FUSION
   parseLumaMode = other.parseLumaMode;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index d80c7e115554f7e99868f6de2b6efe032d67c27c..574aa7cfa87c5b8214590543747ce7a4a3466263 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -503,6 +503,9 @@ struct IntraPredictionData
 
 struct InterPredictionData
 {
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  uint8_t     colIdx;
+#endif
   bool      mergeFlag;
   bool      regularMergeFlag;
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 22841fb9e14af439c955dc6735fa8bad19e23ba6..b0cee170f99d8203ddae99fc0d4dec0fc4a66bcd 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -2785,7 +2785,119 @@ uint8_t PU::getLFNSTIdx( int intraMode, int mtsMode )
   return g_lfnstLut[ intraMode ];
 }
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+void PU::addMergeHMVPCandSubTMVP(const CodingStructure &cs, MergeCtx &mrgCtx, const int &mrgCandIdx,
+  const uint32_t maxNumMergeCand, int &cnt, const bool isAvailableA1,
+  const MotionInfo miLeft, const bool isAvailableB1, const MotionInfo miAbove,
+#if !JVET_Z0075_IBC_HMVP_ENLARGE
+  , const bool ibcFlag
+  , const bool isGt4x4
+#endif
+  const PredictionUnit &pu, int col
+#if TM_MRG || (JVET_Z0084_IBC_TM && !JVET_Z0075_IBC_HMVP_ENLARGE)
+  , const uint32_t mvdSimilarityThresh
+#endif
+)
+{
+  const Slice& slice = *cs.slice;
+  MotionInfo miNeighbor;
+
+  const Picture *pColPic = slice.getRefPic(RefPicList(col == 0 ? 1 - slice.getColFromL0Flag() : 1 - slice.getColFromL0Flag2nd()), col == 0 ? slice.getColRefIdx() : slice.getColRefIdx2nd());
+#if JVET_Z0075_IBC_HMVP_ENLARGE
+#if JVET_Z0118_GDR  
+  bool isClean = cs.isClean(pu.cu->Y().bottomRight(), CHANNEL_TYPE_LUMA);
+#endif // JVET_Z0118_GDR
+
+#if JVET_Z0118_GDR  
+  auto &lut = (isClean) ? cs.motionLut.lut1 : cs.motionLut.lut0;
+#else
+  auto &lut = cs.motionLut.lut;
+#endif // JVET_Z0118_GDR
+#else
+
+#if JVET_Z0118_GDR  
+  auto &lut = ibcFlag ? (isClean ? cs.motionLut.lutIbc1 : cs.motionLut.lutIbc0) : (isClean ? cs.motionLut.lut1 : cs.motionLut.lut0);
+#else
+  auto &lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut;
+#endif // JVET_Z0118_GDR
+
+#endif // JVET_Z0075_IBC_HMVP_ENLARGE
+  int numCandInLUT = (int)lut.size();
+
+  for (int mrgIdx = 1; mrgIdx <= numCandInLUT; mrgIdx++)
+  {
+    miNeighbor = lut[numCandInLUT - mrgIdx];
+
+#if !JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0128_NON_CTC
+    bool isValidAmMode = checkIsValidMergeMvCand(pu, miNeighbor.refIdx);
+#else
+    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miNeighbor.refIdx);
+#endif
+    if (isValidAmMode &&
+#if JVET_Z0075_IBC_HMVP_ENLARGE
+    (mrgIdx > 2
+#else
+      (mrgIdx > 2 || ((mrgIdx > 1 || !isGt4x4) && ibcFlag)
+#endif
+        || ((!isAvailableA1 || (miLeft != miNeighbor)) && (!isAvailableB1 || (miAbove != miNeighbor))))
+    )
+#else
+#if JVET_Z0075_IBC_HMVP_ENLARGE
+    if (mrgIdx > 2
+#else
+    if (mrgIdx > 2 || ((mrgIdx > 1 || !isGt4x4) && ibcFlag)
+#endif
+      || ((!isAvailableA1 || (miLeft != miNeighbor)) && (!isAvailableB1 || (miAbove != miNeighbor))))
+#endif
+    {
+      int index = 0;
+      if ((miNeighbor.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miNeighbor.refIdx[0]) == pColPic)
+      {
+        index = 1;
+      }
+      else if (slice.isInterB() && (miNeighbor.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miNeighbor.refIdx[1]) == pColPic)
+      {
+        index = 2;
+      }
+      if (index > 0)
+      {
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = index;
+        miNeighbor.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+        if (index == 1)
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[index - 1], miNeighbor.refIdx[index - 1]);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
+        }
+        else
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[index - 1], miNeighbor.refIdx[index - 1]);
+        }
+
+#if NON_ADJACENT_MRG_CAND
+        if (mrgCtx.xCheckSimilarMotionSubTMVP(cnt
+#if TM_MRG
+          , mvdSimilarityThresh
+#endif
+        ))
+        {
+          continue;
+        }
+#endif
+        cnt++;
 
+        if (cnt == maxNumMergeCand)
+        {
+          break;
+        }
+      }
+    }
+    return;
+  }
+}
+#endif
 bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int &mrgCandIdx,
                           const uint32_t maxNumMergeCandMin1, int &cnt, const bool isAvailableA1,
                           const MotionInfo miLeft, const bool isAvailableB1, const MotionInfo miAbove
@@ -4110,55 +4222,25 @@ int PU::reorderInterMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx,
   }
 }
 #endif
-
-void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
-                                 int mmvdList,
-                                 const int& mrgCandIdx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+void PU::getInterMergeCandidatesSubTMVP(const PredictionUnit &pu, MergeCtx& mrgCtx,
+  int col,
+  const int& mrgCandIdx
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-                                , MergeCtx* tmvpMrgCtx
-                                , MergeCtx* namvpMrgCtx
+  , MergeCtx* namvpMrgCtx
 #endif
 )
 {
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-  if (!pu.cs->sps->getUseAML() || !pu.cs->sps->getUseTmvpNmvpReordering())
-  {
-    tmvpMrgCtx  = nullptr;
-    namvpMrgCtx = nullptr;
-  }
-#endif
   const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
-  const CodingStructure &cs  = *pu.cs;
-  const Slice &slice         = *pu.cs->slice;
+  const CodingStructure &cs = *pu.cs;
+  const Slice &slice = *pu.cs->slice;
+  const Picture *pColPic = slice.getRefPic(RefPicList(col == 0 ? 1 - slice.getColFromL0Flag() : 1 - slice.getColFromL0Flag2nd()), col == 0 ? slice.getColRefIdx() : slice.getColRefIdx2nd());
 #if TM_MRG
-  const uint32_t mvdSimilarityThresh = pu.tmMergeFlag ? PU::getTMMvdThreshold(pu) : 1;
-#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-  uint32_t additionalMRGCand = 0;
-  if (tmvpMrgCtx != NULL)
-  {
-    additionalMRGCand = tmvpMrgCtx->numValidMergeCand;
-  }
-  if (namvpMrgCtx != NULL)
-  {
-    additionalMRGCand += namvpMrgCtx->numValidMergeCand;
-  }
-  const uint32_t maxNumMergeCand =
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-                                   !pu.cs->sps->getUseAML() || !pu.cs->sps->getUseTmvpNmvpReordering() ?
-                                   (pu.tmMergeFlag ? pu.cs->sps->getMaxNumTMMergeCand() : pu.cs->sps->getMaxNumMergeCand()) :
-#endif
-                                   (pu.tmMergeFlag ? std::min((int)(TM_MRG_MAX_NUM_INIT_CANDS        + additionalMRGCand), ((int)NUM_MERGE_CANDS - (3)))
-                                                   : std::min((int)(pu.cs->sps->getMaxNumMergeCand() + additionalMRGCand), ((int)NUM_MERGE_CANDS - (3))));
-#else
+  const uint32_t mvdSimilarityThresh = SUB_TMVP_MV_THRESHOLD;
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-  const uint32_t maxNumMergeCand = pu.tmMergeFlag ? ((pu.cs->sps->getUseAML()
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-                                                  && pu.cs->sps->getUseTmvpNmvpReordering()
-#endif
-                                                    ) ? TM_MRG_MAX_NUM_INIT_CANDS : pu.cs->sps->getMaxNumTMMergeCand()) : pu.cs->sps->getMaxNumMergeCand();
+  const uint32_t maxNumMergeCand = pu.tmMergeFlag ? TM_MRG_MAX_NUM_INIT_CANDS : SUB_TMVP_CANDIDATE_NUM;
 #else
-  const uint32_t maxNumMergeCand     = pu.tmMergeFlag ? pu.cs->sps->getMaxNumTMMergeCand() : pu.cs->sps->getMaxNumMergeCand();
-#endif
+  const uint32_t maxNumMergeCand = pu.tmMergeFlag ? pu.cs->sps->getMaxNumTMMergeCand() : pu.cs->sps->getMaxNumMergeCand();
 #endif
 #else
   const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumMergeCand();
@@ -4168,15 +4250,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
 #if INTER_LIC
     mrgCtx.LICFlags[ui] = false;
-#endif
-#if JVET_AC0112_IBC_LIC
-    mrgCtx.ibcLicFlags[ui] = false;
-#endif
-#if JVET_AA0070_RRIBC
-    mrgCtx.rribcFlipTypes[ui] = 0;
 #endif
     mrgCtx.interDirNeighbours[ui] = 0;
-    mrgCtx.mvFieldNeighbours[(ui << 1)    ].refIdx = NOT_VALID;
+    mrgCtx.mvFieldNeighbours[(ui << 1)].refIdx = NOT_VALID;
     mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
     mrgCtx.useAltHpelIf[ui] = false;
 #if MULTI_HYP_PRED
@@ -4186,63 +4262,10 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     mrgCtx.candCost[ui] = MAX_UINT64;
 #endif
   }
-
-  mrgCtx.numValidMergeCand = maxNumMergeCand;
 #if JVET_Z0102_NO_ARMC_FOR_ZERO_CAND
   mrgCtx.numCandToTestEnc = maxNumMergeCand;
 #endif
   // compute the location of the current PU
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-  int amvpMergeCtxMergeDir = -1;
-  RefPicList amvpRefList = REF_PIC_LIST_X;
-  bool useAmvpMergeMode = false;
-#endif
-#if JVET_Y0128_NON_CTC
-  if (pu.amvpMergeModeFlag[0] || pu.amvpMergeModeFlag[1])
-  {
-    mrgCtx.numValidMergeCand = (mrgCandIdx + 1) > maxNumMergeCand ? maxNumMergeCand : (mrgCandIdx + 1);
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-    useAmvpMergeMode = true;
-    if (pu.amvpMergeModeFlag[0] == true)
-    {
-      amvpMergeCtxMergeDir = 1;
-      amvpRefList = REF_PIC_LIST_1;
-    }
-    else
-    {
-      amvpMergeCtxMergeDir = 2;
-      amvpRefList = REF_PIC_LIST_0;
-    }
-#endif
-  }
-#else
-  const int curPoc = slice.getPOC();
-#if !JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-  RefPicList amvpRefList = REF_PIC_LIST_X;
-#endif
-  RefPicList mergeRefList = REF_PIC_LIST_X;
-  int amvpPoc = -1;
-  if (pu.amvpMergeModeFlag[0] || pu.amvpMergeModeFlag[1])
-  {
-    mergeRefList = pu.amvpMergeModeFlag[0] ? REF_PIC_LIST_0 : REF_PIC_LIST_1;
-    amvpRefList = RefPicList(1 - mergeRefList);
-    amvpPoc = slice.getRefPOC(amvpRefList, pu.refIdx[amvpRefList]);
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-    useAmvpMergeMode = true;
-    if (pu.amvpMergeModeFlag[0] == true)
-    {
-      amvpMergeCtxMergeDir = 1;
-    }
-    else
-    {
-      amvpMergeCtxMergeDir = 2;
-    }
-#endif
-    mrgCtx.numValidMergeCand = (mrgCandIdx + 1) > maxNumMergeCand ? maxNumMergeCand : (mrgCandIdx + 1);
-  }
-#endif
-#endif
 
   int cnt = 0;
 
@@ -4264,70 +4287,48 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   {
     miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
 
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-#if JVET_Y0128_NON_CTC
-    bool isValidAmMode = checkIsValidMergeMvCand(pu, miAbove.refIdx);
-#else
-    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miAbove.refIdx);
-#endif
-    if (isValidAmMode)
-    {
-#endif
-    // get Inter Dir
-    mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
-    mrgCtx.useAltHpelIf[cnt] = miAbove.useAltHpelIf;
-    // get Mv from Above
-    mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->BcwIdx : BCW_DEFAULT;
-#if INTER_LIC
-    mrgCtx.LICFlags[cnt] = miAbove.usesLIC;
-#endif
-    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
-
-    if (slice.isInterB())
+    int index = 0;
+    if ((miAbove.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miAbove.refIdx[0]) == pColPic)
     {
-      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAbove.mv[1], miAbove.refIdx[1]);
-#if MULTI_HYP_PRED
-      mrgCtx.addHypNeighbours[cnt] = puAbove->addHypData;
-#endif
+      index = 1;
     }
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-    if (useAmvpMergeMode)
+    else if (slice.isInterB() && (miAbove.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miAbove.refIdx[1]) == pColPic)
     {
-      mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
-      mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+      index = 2;
     }
-#endif
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-    if( !mrgCtx.xCheckSimilarMotion(cnt
-#if TM_MRG
-                           , mvdSimilarityThresh
-#endif
-    ) )
-    {
-#endif
-    if (mrgCandIdx == cnt)
+    if (index > 0)
     {
-#if TM_MRG
-      if( !pu.tmMergeFlag )
-#endif
-      return;
-    }
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = index;
+      miAbove.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+      if (index == 1)
+      {
+        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[index - 1], miAbove.refIdx[index - 1]);
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
+      }
+      else
+      {
+        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAbove.mv[index - 1], miAbove.refIdx[index - 1]);
+      }
 
-    cnt++;
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-    }
+      if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
+#if TM_MRG
+        , mvdSimilarityThresh
 #endif
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-    } // if (isValidAmMode)
+      ))
 #endif
+      {
+        cnt++;
+      }
+    }
   }
 
   // early termination
   if (cnt == maxNumMergeCand)
   {
-#if TM_MRG
-    if (!pu.tmMergeFlag)
-#endif
+    mrgCtx.numValidMergeCand = cnt;
     return;
   }
 
@@ -4344,303 +4345,803 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   {
     miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
 
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-#if JVET_Y0128_NON_CTC
-    bool isValidAmMode = checkIsValidMergeMvCand(pu, miLeft.refIdx);
-#else
-    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miLeft.refIdx);
-#endif
-    if (isValidAmMode && (!isAvailableB1 || (miAbove != miLeft)))
-#else
-    if (!isAvailableB1 || (miAbove != miLeft))
-#endif
     {
-      // get Inter Dir
-      mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
-      mrgCtx.useAltHpelIf[cnt] = miLeft.useAltHpelIf;
-      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->BcwIdx : BCW_DEFAULT;
-#if INTER_LIC
-      mrgCtx.LICFlags[cnt] = miLeft.usesLIC;
-#endif
-      // get Mv from Left
-      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
-
-      if (slice.isInterB())
+      int index = 0;
+      if ((miLeft.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miLeft.refIdx[0]) == pColPic)
       {
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
-#if MULTI_HYP_PRED
-        mrgCtx.addHypNeighbours[cnt] = puLeft->addHypData;
-#endif
+        index = 1;
       }
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-      if (useAmvpMergeMode)
+      else if (slice.isInterB() && (miLeft.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miLeft.refIdx[1]) == pColPic)
       {
-        mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+        index = 2;
       }
-#endif
+      if (index > 0)
+      {
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = index;
+        miLeft.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+        if (index == 1)
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[index - 1], miLeft.refIdx[index - 1]);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
+        }
+        else
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[index - 1], miLeft.refIdx[index - 1]);
+        }
+
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-      if( !mrgCtx.xCheckSimilarMotion(cnt
+        if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
 #if TM_MRG
-                             , mvdSimilarityThresh
-#endif
-      ) )
-      {
+          , mvdSimilarityThresh
 #endif
-      if (mrgCandIdx == cnt)
-      {
-#if TM_MRG
-        if (!pu.tmMergeFlag)
+        ))
 #endif
-        return;
-      }
-
-      cnt++;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
+        {
+          cnt++;
+        }
       }
-#endif
     }
   }
 
   // early termination
-  if( cnt == maxNumMergeCand )
+  if (cnt == maxNumMergeCand)
   {
-#if TM_MRG
-    if (!pu.tmMergeFlag)
-#endif
+    mrgCtx.numValidMergeCand = cnt;
     return;
   }
 
   // above right
-  const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
+  const PredictionUnit *puAboveRight = cs.getPURestricted(posRT.offset(1, -1), pu, pu.chType);
 
 #if JVET_Y0065_GPM_INTRA
-  bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu ) && puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) ).isInter;
+  bool isAvailableB0 = puAboveRight && isDiffMER(pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter(*puAboveRight->cu) && puAboveRight->getMotionInfo(posRT.offset(1, -1)).isInter;
 #else
-  bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu );
+  bool isAvailableB0 = puAboveRight && isDiffMER(pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter(*puAboveRight->cu);
 #endif
 
-  if( isAvailableB0 )
+  if (isAvailableB0)
   {
-    miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
+    miAboveRight = puAboveRight->getMotionInfo(posRT.offset(1, -1));
 
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-#if JVET_Y0128_NON_CTC
-    bool isValidAmMode = checkIsValidMergeMvCand(pu, miAboveRight.refIdx);
-#else
-    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miAboveRight.refIdx);
-#endif
-    if (isValidAmMode && (!isAvailableB1 || ( miAbove != miAboveRight )))
-#else
-    if( !isAvailableB1 || ( miAbove != miAboveRight ) )
-#endif
     {
-
-      // get Inter Dir
-      mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
-      mrgCtx.useAltHpelIf[cnt] = miAboveRight.useAltHpelIf;
-      // get Mv from Above-right
-      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;
-#if INTER_LIC
-      mrgCtx.LICFlags[cnt] = miAboveRight.usesLIC;
-#endif
-      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
-
-      if( slice.isInterB() )
+      int index = 0;
+      if ((miAboveRight.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miAboveRight.refIdx[0]) == pColPic)
       {
-        mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
-#if MULTI_HYP_PRED
-        mrgCtx.addHypNeighbours[cnt] = puAboveRight->addHypData;
-#endif
+        index = 1;
       }
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-      if (useAmvpMergeMode)
+      else if (slice.isInterB() && (miAboveRight.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miAboveRight.refIdx[1]) == pColPic)
       {
-        mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+        index = 2;
       }
-#endif
+      if (index > 0)
+      {
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = index;
+        miAboveRight.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+        if (index == 1)
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveRight.mv[index - 1], miAboveRight.refIdx[index - 1]);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
+        }
+        else
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAboveRight.mv[index - 1], miAboveRight.refIdx[index - 1]);
+        }
 
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-      if( !mrgCtx.xCheckSimilarMotion(cnt
+        if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
 #if TM_MRG
-                             , mvdSimilarityThresh
-#endif
-      ) )
-      {
+          , mvdSimilarityThresh
 #endif
-      if (mrgCandIdx == cnt)
-      {
-#if TM_MRG
-        if (!pu.tmMergeFlag)
+        ))
 #endif
-        return;
-      }
-
-      cnt++;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
+        {
+          cnt++;
+        }
       }
-#endif
     }
   }
   // early termination
-  if( cnt == maxNumMergeCand )
+  if (cnt == maxNumMergeCand)
   {
-#if TM_MRG
-    if (!pu.tmMergeFlag)
-#endif
+    mrgCtx.numValidMergeCand = cnt;
     return;
   }
 
   //left bottom
-  const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
+  const PredictionUnit *puLeftBottom = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType);
 
 #if JVET_Y0065_GPM_INTRA
-  bool isAvailableA0 = puLeftBottom && isDiffMER( pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom->cu ) && puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) ).isInter;
+  bool isAvailableA0 = puLeftBottom && isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter(*puLeftBottom->cu) && puLeftBottom->getMotionInfo(posLB.offset(-1, 1)).isInter;
 #else
-  bool isAvailableA0 = puLeftBottom && isDiffMER( pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom->cu );
+  bool isAvailableA0 = puLeftBottom && isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter(*puLeftBottom->cu);
 #endif
 
-  if( isAvailableA0 )
+  if (isAvailableA0)
   {
-    miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
+    miBelowLeft = puLeftBottom->getMotionInfo(posLB.offset(-1, 1));
 
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-#if JVET_Y0128_NON_CTC
-    bool isValidAmMode = checkIsValidMergeMvCand(pu, miBelowLeft.refIdx);
-#else
-    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miBelowLeft.refIdx);
-#endif
-    if (isValidAmMode && (!isAvailableA1 || ( miBelowLeft != miLeft )))
-#else
-    if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
-#endif
     {
-      // get Inter Dir
-      mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
-      mrgCtx.useAltHpelIf[cnt] = miBelowLeft.useAltHpelIf;
-      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT;
-#if INTER_LIC
-      mrgCtx.LICFlags[cnt] = miBelowLeft.usesLIC;
-#endif
-      // get Mv from Bottom-Left
-      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
-
-      if( slice.isInterB() )
+      int index = 0;
+      if ((miBelowLeft.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miBelowLeft.refIdx[0]) == pColPic)
       {
-        mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
-#if MULTI_HYP_PRED
-        mrgCtx.addHypNeighbours[cnt] = puLeftBottom->addHypData;
-#endif
+        index = 1;
       }
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-      if (useAmvpMergeMode)
+      else if (slice.isInterB() && (miBelowLeft.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miBelowLeft.refIdx[1]) == pColPic)
       {
-        mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+        index = 2;
       }
-#endif
+      if (index > 0)
+      {
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = index;
+        miBelowLeft.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+        if (index == 1)
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miBelowLeft.mv[index - 1], miBelowLeft.refIdx[index - 1]);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
+        }
+        else
+        {
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miBelowLeft.mv[index - 1], miBelowLeft.refIdx[index - 1]);
+        }
 
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-      if( !mrgCtx.xCheckSimilarMotion(cnt
+        if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
 #if TM_MRG
-                             , mvdSimilarityThresh
-#endif
-      ) )
-      {
+          , mvdSimilarityThresh
 #endif
-      if (mrgCandIdx == cnt)
-      {
-#if TM_MRG
-        if (!pu.tmMergeFlag)
+        ))
 #endif
-        return;
-      }
-
-      cnt++;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
+        {
+          cnt++;
+        }
       }
-#endif
     }
   }
   // early termination
-  if( cnt == maxNumMergeCand )
+  if (cnt == maxNumMergeCand)
   {
-#if TM_MRG
-    if (!pu.tmMergeFlag)
-#endif
+    mrgCtx.numValidMergeCand = cnt;
     return;
   }
 
-#if TM_MRG
-  if (pu.tmMergeFlag)
-  {
-    cnt = PU::reorderInterMergeCandidates(pu, mrgCtx, cnt, mvdSimilarityThresh);
-
-    if ((mrgCandIdx >= 0 && mrgCandIdx < cnt) || cnt >= maxNumMergeCand)
-    {
-      return;
-    }
-  }
-#endif
-
   // above left
-  if ( cnt < 4 )
+  if (cnt < 4)
   {
-    const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
+    const PredictionUnit *puAboveLeft = cs.getPURestricted(posLT.offset(-1, -1), pu, pu.chType);
 
 #if JVET_Y0065_GPM_INTRA
-    bool isAvailableB2 = puAboveLeft && isDiffMER( pu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft->cu ) && puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) ).isInter;
+    bool isAvailableB2 = puAboveLeft && isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel) && CU::isInter(*puAboveLeft->cu) && puAboveLeft->getMotionInfo(posLT.offset(-1, -1)).isInter;
 #else
-    bool isAvailableB2 = puAboveLeft && isDiffMER( pu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft->cu );
+    bool isAvailableB2 = puAboveLeft && isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel) && CU::isInter(*puAboveLeft->cu);
 #endif
 
-    if( isAvailableB2 )
+    if (isAvailableB2)
     {
-      miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
+      miAboveLeft = puAboveLeft->getMotionInfo(posLT.offset(-1, -1));
 
-#if JVET_X0083_BM_AMVP_MERGE_MODE
-#if JVET_Y0128_NON_CTC
-      bool isValidAmMode = checkIsValidMergeMvCand(pu, miAboveLeft.refIdx);
-#else
-      bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miAboveLeft.refIdx);
-#endif
-      if (isValidAmMode && ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ))
-#else
-      if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
-#endif
       {
 
-        // get Inter Dir
-        mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
-        mrgCtx.useAltHpelIf[cnt] = miAboveLeft.useAltHpelIf;
-        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT;
-#if INTER_LIC
-        mrgCtx.LICFlags[cnt] = miAboveLeft.usesLIC;
-#endif
-        // get Mv from Above-Left
-        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] );
-
-        if( slice.isInterB() )
+        int index = 0;
+        if ((miAboveLeft.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miAboveLeft.refIdx[0]) == pColPic)
         {
-          mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] );
-#if MULTI_HYP_PRED
-          mrgCtx.addHypNeighbours[cnt] = puAboveLeft->addHypData;
-#endif
+          index = 1;
         }
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-        if (useAmvpMergeMode)
+        else if (slice.isInterB() && (miAboveLeft.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miAboveLeft.refIdx[1]) == pColPic)
         {
-          mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
-          mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+          index = 2;
         }
-#endif
-
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-        if( !mrgCtx.xCheckSimilarMotion(cnt
-#if TM_MRG
-                               , mvdSimilarityThresh
-#endif
+        if (index > 0)
+        {
+          // get Inter Dir
+          mrgCtx.interDirNeighbours[cnt] = index;
+          miAboveLeft.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+          if (index == 1)
+          {
+            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveLeft.mv[index - 1], miAboveLeft.refIdx[index - 1]);
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
+          }
+          else
+          {
+            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAboveLeft.mv[index - 1], miAboveLeft.refIdx[index - 1]);
+          }
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+          if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
+#if TM_MRG
+            , mvdSimilarityThresh
+#endif
+          ))
+#endif
+          {
+            cnt++;
+          }
+        }
+      }
+    }
+    // early termination
+    if (cnt == maxNumMergeCand)
+    {
+      mrgCtx.numValidMergeCand = cnt;
+      return;
+    }
+  }
+#if NON_ADJACENT_MRG_CAND
+  if (namvpMrgCtx != NULL)
+  {
+    for (uint32_t ui = 0; ui < namvpMrgCtx->numValidMergeCand && cnt < maxNumMergeCand; ++ui)
+    {
+      mrgCtx.interDirNeighbours[cnt] = namvpMrgCtx->interDirNeighbours[ui];
+      mrgCtx.mvFieldNeighbours[cnt << 1] = namvpMrgCtx->mvFieldNeighbours[ui << 1];
+      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = namvpMrgCtx->mvFieldNeighbours[(ui << 1) + 1];
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
+#if TM_MRG
+        , mvdSimilarityThresh
+#endif
+      ))
+      {
+#endif
+        mrgCtx.candCost[cnt] = namvpMrgCtx->candCost[ui];
+        cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      }
+#endif
+    }
+  }
+#endif
+
+  if (cnt != maxNumMergeCand)
+  {
+    addMergeHMVPCandSubTMVP(cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt
+      , isAvailableA1, miLeft, isAvailableB1, miAbove, pu, col
+#if TM_MRG
+      , mvdSimilarityThresh
+#endif
+    );
+  }
+  mrgCtx.numValidMergeCand = cnt;
+
+  return;
+}
+#endif
+void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
+                                 int mmvdList,
+                                 const int& mrgCandIdx
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+                                , MergeCtx* tmvpMrgCtx
+                                , MergeCtx* namvpMrgCtx
+#endif
+)
+{
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+  if (!pu.cs->sps->getUseAML() || !pu.cs->sps->getUseTmvpNmvpReordering())
+  {
+    tmvpMrgCtx  = nullptr;
+    namvpMrgCtx = nullptr;
+  }
+#endif
+  const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
+  const CodingStructure &cs  = *pu.cs;
+  const Slice &slice         = *pu.cs->slice;
+#if TM_MRG
+  const uint32_t mvdSimilarityThresh = pu.tmMergeFlag ? PU::getTMMvdThreshold(pu) : 1;
+#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+  uint32_t additionalMRGCand = 0;
+  if (tmvpMrgCtx != NULL)
+  {
+    additionalMRGCand = tmvpMrgCtx->numValidMergeCand;
+  }
+  if (namvpMrgCtx != NULL)
+  {
+    additionalMRGCand += namvpMrgCtx->numValidMergeCand;
+  }
+  const uint32_t maxNumMergeCand =
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+                                   !pu.cs->sps->getUseAML() || !pu.cs->sps->getUseTmvpNmvpReordering() ?
+                                   (pu.tmMergeFlag ? pu.cs->sps->getMaxNumTMMergeCand() : pu.cs->sps->getMaxNumMergeCand()) :
+#endif
+                                   (pu.tmMergeFlag ? std::min((int)(TM_MRG_MAX_NUM_INIT_CANDS        + additionalMRGCand), ((int)NUM_MERGE_CANDS - (3)))
+                                                   : std::min((int)(pu.cs->sps->getMaxNumMergeCand() + additionalMRGCand), ((int)NUM_MERGE_CANDS - (3))));
+#else
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+  const uint32_t maxNumMergeCand = pu.tmMergeFlag ? ((pu.cs->sps->getUseAML()
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+                                                  && pu.cs->sps->getUseTmvpNmvpReordering()
+#endif
+                                                    ) ? TM_MRG_MAX_NUM_INIT_CANDS : pu.cs->sps->getMaxNumTMMergeCand()) : pu.cs->sps->getMaxNumMergeCand();
+#else
+  const uint32_t maxNumMergeCand     = pu.tmMergeFlag ? pu.cs->sps->getMaxNumTMMergeCand() : pu.cs->sps->getMaxNumMergeCand();
+#endif
+#endif
+#else
+  const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumMergeCand();
+#endif
+  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
+  {
+    mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
+#if INTER_LIC
+    mrgCtx.LICFlags[ui] = false;
+#endif
+#if JVET_AC0112_IBC_LIC
+    mrgCtx.ibcLicFlags[ui] = false;
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[ui] = 0;
+#endif
+    mrgCtx.interDirNeighbours[ui] = 0;
+    mrgCtx.mvFieldNeighbours[(ui << 1)    ].refIdx = NOT_VALID;
+    mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
+    mrgCtx.useAltHpelIf[ui] = false;
+#if MULTI_HYP_PRED
+    mrgCtx.addHypNeighbours[ui].clear();
+#endif
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+    mrgCtx.candCost[ui] = MAX_UINT64;
+#endif
+  }
+
+  mrgCtx.numValidMergeCand = maxNumMergeCand;
+#if JVET_Z0102_NO_ARMC_FOR_ZERO_CAND
+  mrgCtx.numCandToTestEnc = maxNumMergeCand;
+#endif
+  // compute the location of the current PU
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+  int amvpMergeCtxMergeDir = -1;
+  RefPicList amvpRefList = REF_PIC_LIST_X;
+  bool useAmvpMergeMode = false;
+#endif
+#if JVET_Y0128_NON_CTC
+  if (pu.amvpMergeModeFlag[0] || pu.amvpMergeModeFlag[1])
+  {
+    mrgCtx.numValidMergeCand = (mrgCandIdx + 1) > maxNumMergeCand ? maxNumMergeCand : (mrgCandIdx + 1);
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+    useAmvpMergeMode = true;
+    if (pu.amvpMergeModeFlag[0] == true)
+    {
+      amvpMergeCtxMergeDir = 1;
+      amvpRefList = REF_PIC_LIST_1;
+    }
+    else
+    {
+      amvpMergeCtxMergeDir = 2;
+      amvpRefList = REF_PIC_LIST_0;
+    }
+#endif
+  }
+#else
+  const int curPoc = slice.getPOC();
+#if !JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+  RefPicList amvpRefList = REF_PIC_LIST_X;
+#endif
+  RefPicList mergeRefList = REF_PIC_LIST_X;
+  int amvpPoc = -1;
+  if (pu.amvpMergeModeFlag[0] || pu.amvpMergeModeFlag[1])
+  {
+    mergeRefList = pu.amvpMergeModeFlag[0] ? REF_PIC_LIST_0 : REF_PIC_LIST_1;
+    amvpRefList = RefPicList(1 - mergeRefList);
+    amvpPoc = slice.getRefPOC(amvpRefList, pu.refIdx[amvpRefList]);
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+    useAmvpMergeMode = true;
+    if (pu.amvpMergeModeFlag[0] == true)
+    {
+      amvpMergeCtxMergeDir = 1;
+    }
+    else
+    {
+      amvpMergeCtxMergeDir = 2;
+    }
+#endif
+    mrgCtx.numValidMergeCand = (mrgCandIdx + 1) > maxNumMergeCand ? maxNumMergeCand : (mrgCandIdx + 1);
+  }
+#endif
+#endif
+
+  int cnt = 0;
+
+  const Position posLT = pu.Y().topLeft();
+  const Position posRT = pu.Y().topRight();
+  const Position posLB = pu.Y().bottomLeft();
+  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
+
+  // above
+  const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
+
+#if JVET_Y0065_GPM_INTRA
+  bool isAvailableB1 = puAbove && isDiffMER(pu.lumaPos(), posRT.offset(0, -1), plevel) && pu.cu != puAbove->cu && CU::isInter(*puAbove->cu) && puAbove->getMotionInfo(posRT.offset(0, -1)).isInter;
+#else
+  bool isAvailableB1 = puAbove && isDiffMER(pu.lumaPos(), posRT.offset(0, -1), plevel) && pu.cu != puAbove->cu && CU::isInter(*puAbove->cu);
+#endif
+
+  if (isAvailableB1)
+  {
+    miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
+
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0128_NON_CTC
+    bool isValidAmMode = checkIsValidMergeMvCand(pu, miAbove.refIdx);
+#else
+    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miAbove.refIdx);
+#endif
+    if (isValidAmMode)
+    {
+#endif
+    // get Inter Dir
+    mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
+    mrgCtx.useAltHpelIf[cnt] = miAbove.useAltHpelIf;
+    // get Mv from Above
+    mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->BcwIdx : BCW_DEFAULT;
+#if INTER_LIC
+    mrgCtx.LICFlags[cnt] = miAbove.usesLIC;
+#endif
+    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
+
+    if (slice.isInterB())
+    {
+      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAbove.mv[1], miAbove.refIdx[1]);
+#if MULTI_HYP_PRED
+      mrgCtx.addHypNeighbours[cnt] = puAbove->addHypData;
+#endif
+    }
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+    if (useAmvpMergeMode)
+    {
+      mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
+      mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+    }
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+    if( !mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                           , mvdSimilarityThresh
+#endif
+    ) )
+    {
+#endif
+    if (mrgCandIdx == cnt)
+    {
+#if TM_MRG
+      if( !pu.tmMergeFlag )
+#endif
+      return;
+    }
+
+    cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+    }
+#endif
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+    } // if (isValidAmMode)
+#endif
+  }
+
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+#if TM_MRG
+    if (!pu.tmMergeFlag)
+#endif
+    return;
+  }
+
+  //left
+  const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
+
+#if JVET_Y0065_GPM_INTRA
+  const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu) && puLeft->getMotionInfo(posLB.offset(-1, 0)).isInter;
+#else
+  const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
+#endif
+
+  if (isAvailableA1)
+  {
+    miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
+
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0128_NON_CTC
+    bool isValidAmMode = checkIsValidMergeMvCand(pu, miLeft.refIdx);
+#else
+    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miLeft.refIdx);
+#endif
+    if (isValidAmMode && (!isAvailableB1 || (miAbove != miLeft)))
+#else
+    if (!isAvailableB1 || (miAbove != miLeft))
+#endif
+    {
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
+      mrgCtx.useAltHpelIf[cnt] = miLeft.useAltHpelIf;
+      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->BcwIdx : BCW_DEFAULT;
+#if INTER_LIC
+      mrgCtx.LICFlags[cnt] = miLeft.usesLIC;
+#endif
+      // get Mv from Left
+      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
+
+      if (slice.isInterB())
+      {
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
+#if MULTI_HYP_PRED
+        mrgCtx.addHypNeighbours[cnt] = puLeft->addHypData;
+#endif
+      }
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+      if (useAmvpMergeMode)
+      {
+        mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+      }
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if( !mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                             , mvdSimilarityThresh
+#endif
+      ) )
+      {
+#endif
+      if (mrgCandIdx == cnt)
+      {
+#if TM_MRG
+        if (!pu.tmMergeFlag)
+#endif
+        return;
+      }
+
+      cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      }
+#endif
+    }
+  }
+
+  // early termination
+  if( cnt == maxNumMergeCand )
+  {
+#if TM_MRG
+    if (!pu.tmMergeFlag)
+#endif
+    return;
+  }
+
+  // above right
+  const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
+
+#if JVET_Y0065_GPM_INTRA
+  bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu ) && puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) ).isInter;
+#else
+  bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu );
+#endif
+
+  if( isAvailableB0 )
+  {
+    miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
+
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0128_NON_CTC
+    bool isValidAmMode = checkIsValidMergeMvCand(pu, miAboveRight.refIdx);
+#else
+    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miAboveRight.refIdx);
+#endif
+    if (isValidAmMode && (!isAvailableB1 || ( miAbove != miAboveRight )))
+#else
+    if( !isAvailableB1 || ( miAbove != miAboveRight ) )
+#endif
+    {
+
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
+      mrgCtx.useAltHpelIf[cnt] = miAboveRight.useAltHpelIf;
+      // get Mv from Above-right
+      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;
+#if INTER_LIC
+      mrgCtx.LICFlags[cnt] = miAboveRight.usesLIC;
+#endif
+      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
+
+      if( slice.isInterB() )
+      {
+        mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
+#if MULTI_HYP_PRED
+        mrgCtx.addHypNeighbours[cnt] = puAboveRight->addHypData;
+#endif
+      }
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+      if (useAmvpMergeMode)
+      {
+        mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+      }
+#endif
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if( !mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                             , mvdSimilarityThresh
+#endif
+      ) )
+      {
+#endif
+      if (mrgCandIdx == cnt)
+      {
+#if TM_MRG
+        if (!pu.tmMergeFlag)
+#endif
+        return;
+      }
+
+      cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      }
+#endif
+    }
+  }
+  // early termination
+  if( cnt == maxNumMergeCand )
+  {
+#if TM_MRG
+    if (!pu.tmMergeFlag)
+#endif
+    return;
+  }
+
+  //left bottom
+  const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
+
+#if JVET_Y0065_GPM_INTRA
+  bool isAvailableA0 = puLeftBottom && isDiffMER( pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom->cu ) && puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) ).isInter;
+#else
+  bool isAvailableA0 = puLeftBottom && isDiffMER( pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom->cu );
+#endif
+
+  if( isAvailableA0 )
+  {
+    miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
+
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0128_NON_CTC
+    bool isValidAmMode = checkIsValidMergeMvCand(pu, miBelowLeft.refIdx);
+#else
+    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miBelowLeft.refIdx);
+#endif
+    if (isValidAmMode && (!isAvailableA1 || ( miBelowLeft != miLeft )))
+#else
+    if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
+#endif
+    {
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
+      mrgCtx.useAltHpelIf[cnt] = miBelowLeft.useAltHpelIf;
+      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT;
+#if INTER_LIC
+      mrgCtx.LICFlags[cnt] = miBelowLeft.usesLIC;
+#endif
+      // get Mv from Bottom-Left
+      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
+
+      if( slice.isInterB() )
+      {
+        mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
+#if MULTI_HYP_PRED
+        mrgCtx.addHypNeighbours[cnt] = puLeftBottom->addHypData;
+#endif
+      }
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+      if (useAmvpMergeMode)
+      {
+        mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+      }
+#endif
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if( !mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                             , mvdSimilarityThresh
+#endif
+      ) )
+      {
+#endif
+      if (mrgCandIdx == cnt)
+      {
+#if TM_MRG
+        if (!pu.tmMergeFlag)
+#endif
+        return;
+      }
+
+      cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      }
+#endif
+    }
+  }
+  // early termination
+  if( cnt == maxNumMergeCand )
+  {
+#if TM_MRG
+    if (!pu.tmMergeFlag)
+#endif
+    return;
+  }
+
+#if TM_MRG
+  if (pu.tmMergeFlag)
+  {
+    cnt = PU::reorderInterMergeCandidates(pu, mrgCtx, cnt, mvdSimilarityThresh);
+
+    if ((mrgCandIdx >= 0 && mrgCandIdx < cnt) || cnt >= maxNumMergeCand)
+    {
+      return;
+    }
+  }
+#endif
+
+  // above left
+  if ( cnt < 4 )
+  {
+    const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
+
+#if JVET_Y0065_GPM_INTRA
+    bool isAvailableB2 = puAboveLeft && isDiffMER( pu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft->cu ) && puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) ).isInter;
+#else
+    bool isAvailableB2 = puAboveLeft && isDiffMER( pu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft->cu );
+#endif
+
+    if( isAvailableB2 )
+    {
+      miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
+
+#if JVET_X0083_BM_AMVP_MERGE_MODE
+#if JVET_Y0128_NON_CTC
+      bool isValidAmMode = checkIsValidMergeMvCand(pu, miAboveLeft.refIdx);
+#else
+      bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, miAboveLeft.refIdx);
+#endif
+      if (isValidAmMode && ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ))
+#else
+      if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
+#endif
+      {
+
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
+        mrgCtx.useAltHpelIf[cnt] = miAboveLeft.useAltHpelIf;
+        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT;
+#if INTER_LIC
+        mrgCtx.LICFlags[cnt] = miAboveLeft.usesLIC;
+#endif
+        // get Mv from Above-Left
+        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] );
+
+        if( slice.isInterB() )
+        {
+          mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] );
+#if MULTI_HYP_PRED
+          mrgCtx.addHypNeighbours[cnt] = puAboveLeft->addHypData;
+#endif
+        }
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+        if (useAmvpMergeMode)
+        {
+          mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+        }
+#endif
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if( !mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                               , mvdSimilarityThresh
+#endif
         ) )
         {
 #endif
@@ -4679,7 +5180,7 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 
     Position posC0;
     Position posC1 = pu.Y().center();
-    bool C0Avail = false;
+    bool isC0Avail = false;
     bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
     const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
     if (curSubPic.getTreatedAsPicFlag())
@@ -4693,7 +5194,7 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
       if (posYInCtu + 4 < pcv.maxCUHeight)
       {
         posC0 = posRB.offset(4, 4);
-        C0Avail = true;
+        isC0Avail = true;
       }
     }
 
@@ -4701,91 +5202,120 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     int       iRefIdx     = 0;
     int       dir         = 0;
     unsigned  uiArrayAddr = cnt;
-    bool      bExistMV    = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx, false
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-      , &iRefIdx
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    int cntTmp = cnt;
+    for (int colIdx = 0; colIdx < (pu.cu->slice->isInterB() ? 2 : 1); colIdx++)
+    {
+      if (colIdx && cnt != cntTmp)
+      {
+        break;
+      }
 #endif
-    ) )
-                              || getColocatedMVP( pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx, false
+      bool      bExistMV = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx, false
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-                                , &iRefIdx
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , colIdx
+#elif JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , 0
 #endif
-                              );
-    if (bExistMV)
-    {
-      dir     |= 1;
-      mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
-    }
-
-    if (slice.isInterB())
-    {
-      bExistMV = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx, false
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
         , &iRefIdx
 #endif
-      ) )
-                   || getColocatedMVP( pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx, false
+      ))
+        || getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx, false
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-                     , &iRefIdx
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , colIdx
+#elif JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , 0
+#endif
+          , &iRefIdx
 #endif
-                   );
+        );
       if (bExistMV)
       {
-        dir     |= 2;
-        mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
+        dir |= 1;
+        mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
+      }
+
+      if (slice.isInterB())
+      {
+        bExistMV = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx, false
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , colIdx
+#elif JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , 0
+#endif
+          , &iRefIdx
+#endif
+        ))
+          || getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx, false
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , colIdx
+#elif JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , 0
+#endif
+            , &iRefIdx
+#endif
+          );
+        if (bExistMV)
+        {
+          dir |= 2;
+          mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
+        }
       }
-    }
 
 #if JVET_X0083_BM_AMVP_MERGE_MODE
-    int8_t tempRefIdx[2] = { mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].refIdx, mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].refIdx };
+      int8_t tempRefIdx[2] = { mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].refIdx, mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].refIdx };
 #if JVET_Y0128_NON_CTC
-    bool isValidAmMode = checkIsValidMergeMvCand(pu, tempRefIdx);
+      bool isValidAmMode = checkIsValidMergeMvCand(pu, tempRefIdx);
 #else
-    bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, tempRefIdx);
+      bool isValidAmMode = checkIsValidMergeMvCand(cs, pu, curPoc, amvpPoc, tempRefIdx);
 #endif
-    if (isValidAmMode && ( dir != 0 ))
+      if (isValidAmMode && (dir != 0))
 #else
-    if( dir != 0 )
+      if (dir != 0)
 #endif
-    {
-      bool addTMvp = true;
-      if( addTMvp )
       {
-        mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
-#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
-        if (useAmvpMergeMode)
+        bool addTMvp = true;
+        if (addTMvp)
         {
-          mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
-          mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
-        }
+          mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
+#if JVET_Y0129_MVD_SIGNAL_AMVP_MERGE_MODE
+          if (useAmvpMergeMode)
+          {
+            mrgCtx.interDirNeighbours[cnt] = amvpMergeCtxMergeDir;
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + amvpRefList].setMvField(Mv(), -1);
+          }
 #endif
-        mrgCtx.BcwIdx[uiArrayAddr] = BCW_DEFAULT;
+          mrgCtx.BcwIdx[uiArrayAddr] = BCW_DEFAULT;
 #if INTER_LIC
-        mrgCtx.LICFlags[uiArrayAddr] = false;
+          mrgCtx.LICFlags[uiArrayAddr] = false;
 #endif
-        mrgCtx.useAltHpelIf[uiArrayAddr] = false;
+          mrgCtx.useAltHpelIf[uiArrayAddr] = false;
 #if MULTI_HYP_PRED
-        mrgCtx.addHypNeighbours[uiArrayAddr].clear();
+          mrgCtx.addHypNeighbours[uiArrayAddr].clear();
 #endif
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-        if( !mrgCtx.xCheckSimilarMotion(cnt
+          if (!mrgCtx.xCheckSimilarMotion(cnt
 #if TM_MRG
-                               , mvdSimilarityThresh
+            , mvdSimilarityThresh
 #endif
-        ) )
-        {
+          ))
+          {
 #endif
-        if (mrgCandIdx == cnt)
-        {
-          return;
-        }
+            if (mrgCandIdx == cnt)
+            {
+              return;
+            }
 
-        cnt++;
+            cnt++;
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-        }
+          }
 #endif
+        }
       }
-    }
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
     }
     else if (tmvpMrgCtx->numValidMergeCand > 0)
@@ -4794,9 +5324,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #if TM_MRG
       if (!pu.tmMergeFlag
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-          || !pu.cs->sps->getUseTMMrgMode()
+        || !pu.cs->sps->getUseTMMrgMode()
 #endif
-      )
+        )
 #endif
       {
         for (uint32_t ui = 0; ui < tmvpMrgCtx->numValidMergeCand && cnt < maxNumMergeCand - 1; ++ui)
@@ -4805,9 +5335,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #if INTER_LIC
           mrgCtx.LICFlags[cnt] = tmvpMrgCtx->LICFlags[ui];
 #endif
-          mrgCtx.interDirNeighbours[cnt]     = tmvpMrgCtx->interDirNeighbours[ui];
+          mrgCtx.interDirNeighbours[cnt] = tmvpMrgCtx->interDirNeighbours[ui];
           mrgCtx.mvFieldNeighbours[cnt << 1] = tmvpMrgCtx->mvFieldNeighbours[ui << 1];
-          mrgCtx.useAltHpelIf[cnt]           = tmvpMrgCtx->useAltHpelIf[ui];
+          mrgCtx.useAltHpelIf[cnt] = tmvpMrgCtx->useAltHpelIf[ui];
           if (slice.isInterB())
           {
             mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = tmvpMrgCtx->mvFieldNeighbours[(ui << 1) + 1];
@@ -4819,9 +5349,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #if NON_ADJACENT_MRG_CAND || TM_MRG
           if (!mrgCtx.xCheckSimilarMotion(cnt
 #if TM_MRG
-                                          , mvdSimilarityThresh
+            , mvdSimilarityThresh
 #endif
-                                          ))
+          ))
           {
 #endif
             mrgCtx.candCost[cnt] = tmvpMrgCtx->candCost[ui];
@@ -4843,9 +5373,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #if INTER_LIC
         mrgCtx.LICFlags[cnt] = tmvpMrgCtx->LICFlags[0];
 #endif
-        mrgCtx.interDirNeighbours[cnt]     = tmvpMrgCtx->interDirNeighbours[0];
+        mrgCtx.interDirNeighbours[cnt] = tmvpMrgCtx->interDirNeighbours[0];
         mrgCtx.mvFieldNeighbours[cnt << 1] = tmvpMrgCtx->mvFieldNeighbours[0];
-        mrgCtx.useAltHpelIf[cnt]           = tmvpMrgCtx->useAltHpelIf[0];
+        mrgCtx.useAltHpelIf[cnt] = tmvpMrgCtx->useAltHpelIf[0];
         if (slice.isInterB())
         {
           mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = tmvpMrgCtx->mvFieldNeighbours[1];
@@ -4857,9 +5387,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #if NON_ADJACENT_MRG_CAND || TM_MRG
         if (!mrgCtx.xCheckSimilarMotion(cnt
 #if TM_MRG
-                                        ,mvdSimilarityThresh
+          , mvdSimilarityThresh
 #endif
-                                        ))
+        ))
         {
 #endif
           mrgCtx.candCost[cnt] = tmvpMrgCtx->candCost[0];
@@ -4911,6 +5441,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #endif
     }
 #endif
+#endif
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  }
 #endif
   }
 
@@ -4928,7 +5461,7 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   MotionInfo miNeighbor;
   int offsetX = 0;
   int offsetY = 0;
-  const int iNACANDIDATE_NUM[4] = { 3, 5, 5, 5 };
+  const int numNACandidate[4] = { 3, 5, 5, 5 };
   const int idxMap[4][5] = { { 0, 1, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 } };
 
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
@@ -4947,9 +5480,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
 #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
 #else
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCand - 1; NASPIdx++)
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand - 1; iNASPIdx++)
 #endif
     {
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
@@ -4958,7 +5491,7 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
         continue;
       }
 #endif
-      switch (idxMap[iDistanceIndex][NASPIdx])
+      switch (idxMap[iDistanceIndex][iNASPIdx])
       {
       case 0:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height + iNADistanceVer - 1; break;
       case 1:offsetX = pu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break;
@@ -5458,11 +5991,11 @@ bool PU::addBMMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const i
 #endif
 #endif
 
-  int num_avai_candInLUT = (int)lut.size();
+  int numCandInLUT = (int)lut.size();
 
-  for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
+  for (int mrgIdx = 1; mrgIdx <= numCandInLUT; mrgIdx++)
   {
-    miNeighbor = lut[num_avai_candInLUT - mrgIdx];
+    miNeighbor = lut[numCandInLUT - mrgIdx];
 
 #if JVET_Z0075_IBC_HMVP_ENLARGE
     if ( mrgIdx > 2
@@ -6750,25 +7283,280 @@ void PU::getInterBMCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx,
         mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveRight.mv[0], miAboveRight.refIdx[0]);
         mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAboveRight.mv[1], miAboveRight.refIdx[1]);
 #if JVET_Y0089_DMVR_BCW
-        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;
+        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;
+#endif
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+        {
+#endif
+          if (mrgCandIdx == cnt)
+          {
+            mrgCtx.numValidMergeCand = cnt + 1;
+            return;
+          }
+          cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        }
+#endif
+      }
+    }
+  }
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    mrgCtx.numValidMergeCand = cnt;
+    return;
+  }
+
+  //left bottom
+  const PredictionUnit *puLeftBottom = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType);
+
+#if JVET_Y0065_GPM_INTRA
+  bool isAvailableA0 = puLeftBottom && isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter(*puLeftBottom->cu) && puLeftBottom->getMotionInfo(posLB.offset(-1, 1)).isInter;
+#else
+  bool isAvailableA0 = puLeftBottom && isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter(*puLeftBottom->cu);
+#endif
+
+  if (isAvailableA0)
+  {
+    miBelowLeft = puLeftBottom->getMotionInfo(posLB.offset(-1, 1));
+
+    if (!isAvailableA1 || (miBelowLeft != miLeft))
+    {
+      if (isBiPredFromDifferentDirEqDistPoc(pu, miBelowLeft.refIdx[0], miBelowLeft.refIdx[1])
+        )
+      {
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
+        mrgCtx.useAltHpelIf[cnt] = miBelowLeft.useAltHpelIf;
+        // get Mv from Bottom-Left
+        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miBelowLeft.mv[0], miBelowLeft.refIdx[0]);
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miBelowLeft.mv[1], miBelowLeft.refIdx[1]);
+#if JVET_Y0089_DMVR_BCW
+        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT;
+#endif
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+        {
+#endif
+          if (mrgCandIdx == cnt)
+          {
+#if TM_MRG
+            if (!pu.tmMergeFlag)
+#endif
+              return;
+          }
+          cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        }
+#endif
+      }
+    }
+  }
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    mrgCtx.numValidMergeCand = cnt;
+    return;
+  }
+
+
+  const PredictionUnit *puAboveLeft = cs.getPURestricted(posLT.offset(-1, -1), pu, pu.chType);
+
+#if JVET_Y0065_GPM_INTRA
+  bool isAvailableB2 = puAboveLeft && isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel) && CU::isInter(*puAboveLeft->cu) && puAboveLeft->getMotionInfo(posLT.offset(-1, -1)).isInter;
+#else
+  bool isAvailableB2 = puAboveLeft && isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel) && CU::isInter(*puAboveLeft->cu);
+#endif
+
+  if (isAvailableB2)
+  {
+    miAboveLeft = puAboveLeft->getMotionInfo(posLT.offset(-1, -1));
+
+    if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft)))
+    {
+      if (isBiPredFromDifferentDirEqDistPoc(pu, miAboveLeft.refIdx[0], miAboveLeft.refIdx[1])
+        )
+      {
+
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
+        mrgCtx.useAltHpelIf[cnt] = miAboveLeft.useAltHpelIf;
+        // get Mv from Above-Left
+        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveLeft.mv[0], miAboveLeft.refIdx[0]);
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAboveLeft.mv[1], miAboveLeft.refIdx[1]);
+#if JVET_Y0089_DMVR_BCW
+        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT;
+#endif
+
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+        {
+#endif
+          if (mrgCandIdx == cnt)
+          {
+            mrgCtx.numValidMergeCand = cnt + 1;
+            return;
+          }
+
+          cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        }
+#endif
+      }
+    }
+  }
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    mrgCtx.numValidMergeCand = cnt;
+    return;
+  }
+
+#if INTER_RM_SIZE_CONSTRAINTS
+  if (slice.getPicHeader()->getEnableTMVPFlag())
+#else
+  if (slice.getPicHeader()->getEnableTMVPFlag() && (pu.lumaSize().width + pu.lumaSize().height > 12))
+#endif
+  {
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+    if (mvpMrgCtx1 == NULL)
+    {
+#endif
+    //>> MTK colocated-RightBottom
+    // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
+    Position posRB = pu.Y().bottomRight().offset(-3, -3);
+    const PreCalcValues& pcv = *cs.pcv;
+
+    Position posC0;
+    Position posC1 = pu.Y().center();
+    bool isC0Avail = false;
+    bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+    const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+    if (curSubPic.getTreatedAsPicFlag())
+    {
+      boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+        (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+    }
+    if (boundaryCond)
+    {
+      int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+      if (posYInCtu + 4 < pcv.maxCUHeight)
+      {
+        posC0 = posRB.offset(4, 4);
+        isC0Avail = true;
+      }
+    }
+
+    Mv        cColMv;
+    int       iRefIdx = 0;
+    int       dir = 0;
+    unsigned  uiArrayAddr = cnt;
+    bool      bExistMV = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx, false))
+      || getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx, false);
+    if (bExistMV)
+    {
+      dir |= 1;
+      mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
+    }
+
+    if (slice.isInterB())
+    {
+      bExistMV = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx, false))
+        || getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx, false);
+      if (bExistMV)
+      {
+        dir |= 2;
+        mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
+      }
+    }
+
+    if (dir != 0)
+    {
+      bool addTMvp = isBiPredFromDifferentDirEqDistPoc(pu, mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 0].refIdx, mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].refIdx);
+      if (addTMvp)
+      {
+        mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
+        mrgCtx.useAltHpelIf[uiArrayAddr] = false;
+#if MULTI_HYP_PRED
+        mrgCtx.addHypNeighbours[uiArrayAddr].clear();
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+        {
+#endif
+          if (mrgCandIdx == cnt)
+          {
+            mrgCtx.numValidMergeCand = cnt + 1;
+            return;
+          }
+
+          cnt++;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        }
+#endif
+      }
+    }
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+    }
+#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
+    else if (mvpMrgCtx1->numValidMergeCand > 0)
+    {
+      for (int uiNumCand = 0; uiNumCand < mvpMrgCtx1->numValidMergeCand && cnt < maxNumMergeCand; uiNumCand++)
+      {
+        mrgCtx.interDirNeighbours[cnt] = mvpMrgCtx1->interDirNeighbours[uiNumCand];
+        mrgCtx.mvFieldNeighbours[cnt << 1] = mvpMrgCtx1->mvFieldNeighbours[uiNumCand << 1];
+        mrgCtx.useAltHpelIf[cnt] = mvpMrgCtx1->useAltHpelIf[uiNumCand];
+        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = mvpMrgCtx1->mvFieldNeighbours[(uiNumCand << 1) + 1];
+#if JVET_Y0089_DMVR_BCW
+        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? mvpMrgCtx1->BcwIdx[uiNumCand] : BCW_DEFAULT;
 #endif
-
 #if NON_ADJACENT_MRG_CAND || TM_MRG
         if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-        {
 #endif
+        {
+          mrgCtx.candCost[cnt] = mvpMrgCtx1->candCost[uiNumCand];
           if (mrgCandIdx == cnt)
           {
             mrgCtx.numValidMergeCand = cnt + 1;
             return;
           }
           cnt++;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
         }
+      }
+    }
+#else
+    else if (mvpMrgCtx1->numValidMergeCand > 0)
+    {
+      mrgCtx.interDirNeighbours[cnt] = mvpMrgCtx1->interDirNeighbours[0];
+      mrgCtx.mvFieldNeighbours[cnt << 1] = mvpMrgCtx1->mvFieldNeighbours[0];
+      mrgCtx.useAltHpelIf[cnt] = mvpMrgCtx1->useAltHpelIf[0];
+      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = mvpMrgCtx1->mvFieldNeighbours[1];
+#if MULTI_HYP_PRED
+      mrgCtx.addHypNeighbours[cnt] = mvpMrgCtx1->addHypNeighbours[0];
+#endif
+#if JVET_Y0089_DMVR_BCW
+      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? mvpMrgCtx1->BcwIdx[0] : BCW_DEFAULT;
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
 #endif
+      {
+        mrgCtx.candCost[cnt] = mvpMrgCtx1->candCost[0];
+        if (mrgCandIdx == cnt)
+        {
+          mrgCtx.numValidMergeCand = cnt + 1;
+          return;
+        }
+        cnt++;
       }
     }
+#endif
+#endif
   }
+
   // early termination
   if (cnt == maxNumMergeCand)
   {
@@ -6776,111 +7564,271 @@ void PU::getInterBMCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx,
     return;
   }
 
-  //left bottom
-  const PredictionUnit *puLeftBottom = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType);
-
-#if JVET_Y0065_GPM_INTRA
-  bool isAvailableA0 = puLeftBottom && isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter(*puLeftBottom->cu) && puLeftBottom->getMotionInfo(posLB.offset(-1, 1)).isInter;
+#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
+  int maxNumMergeCandMin1 = maxNumMergeCand;
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+  maxNumMergeCandMin1 -= !pu.cs->sps->getUseAML() ? 1 : 0;
+#endif
 #else
-  bool isAvailableA0 = puLeftBottom && isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter(*puLeftBottom->cu);
+  int maxNumMergeCandMin1 = maxNumMergeCand - 1;
+#endif
+#if NON_ADJACENT_MRG_CAND
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+  if (mvpMrgCtx2 == NULL)
+  {
 #endif
+  MotionInfo miNeighbor;
+  int offsetX = 0;
+  int offsetY = 0;
+  const int numNACandidate[4] = { 3, 5, 5, 5 };
+  const int idxMap[4][5] = { { 0, 1, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 } };
 
-  if (isAvailableA0)
+  for (int iDistanceIndex = 0; iDistanceIndex < NADISTANCE_LEVEL && cnt < maxNumMergeCandMin1; iDistanceIndex++)
   {
-    miBelowLeft = puLeftBottom->getMotionInfo(posLB.offset(-1, 1));
+    const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
+    const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-    if (!isAvailableA1 || (miBelowLeft != miLeft))
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCandMin1; iNASPIdx++)
     {
-      if (isBiPredFromDifferentDirEqDistPoc(pu, miBelowLeft.refIdx[0], miBelowLeft.refIdx[1])
-        )
+      switch (idxMap[iDistanceIndex][iNASPIdx])
       {
-        // get Inter Dir
-        mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
-        mrgCtx.useAltHpelIf[cnt] = miBelowLeft.useAltHpelIf;
-        // get Mv from Bottom-Left
-        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miBelowLeft.mv[0], miBelowLeft.refIdx[0]);
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miBelowLeft.mv[1], miBelowLeft.refIdx[1]);
+      case 0:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height + iNADistanceVer - 1; break;
+      case 1:offsetX = pu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break;
+      case 2:offsetX = pu.Y().width >> 1;   offsetY = -iNADistanceVer - 1;    break;
+      case 3:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height >> 1; break;
+      case 4:offsetX = -iNADistanceHor - 1; offsetY = -iNADistanceVer - 1;    break;
+      default: printf("error!"); exit(0); break;
+      }
+
+      const PredictionUnit *puNonAdjacent = cs.getPURestricted(posLT.offset(offsetX, offsetY), pu, pu.chType);
+
+#if JVET_Y0065_GPM_INTRA
+      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu) && puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY)).isInter;
+#else
+      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu);
+#endif
+
+      if (isAvailableNonAdjacent)
+      {
+        miNeighbor = puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY));
+
+
+        if (isBiPredFromDifferentDirEqDistPoc(pu, miNeighbor.refIdx[0], miNeighbor.refIdx[1])
+          )
+        {
+          // get Inter Dir
+          mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
+          // get Mv from Above-Left
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
+          mrgCtx.useAltHpelIf[cnt] = miNeighbor.useAltHpelIf;
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
 #if JVET_Y0089_DMVR_BCW
-        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT;
+          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puNonAdjacent->cu->BcwIdx : BCW_DEFAULT;
 #endif
 
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-        {
+          if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
 #endif
-          if (mrgCandIdx == cnt)
           {
-#if TM_MRG
-            if (!pu.tmMergeFlag)
-#endif
+            if (mrgCandIdx == cnt)
+            {
+              mrgCtx.numValidMergeCand = cnt + 1;
               return;
+            }
+            cnt++;
           }
-          cnt++;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
         }
-#endif
       }
     }
   }
-  // early termination
-  if (cnt == maxNumMergeCand)
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+  }
+  else
   {
-    mrgCtx.numValidMergeCand = cnt;
-    return;
+    for (int uiNumCand = 0; uiNumCand < mvpMrgCtx2->numValidMergeCand && cnt < maxNumMergeCandMin1; uiNumCand++)
+    {
+      mrgCtx.interDirNeighbours[cnt] = mvpMrgCtx2->interDirNeighbours[uiNumCand];
+      mrgCtx.mvFieldNeighbours[cnt << 1] = mvpMrgCtx2->mvFieldNeighbours[uiNumCand << 1];
+      mrgCtx.useAltHpelIf[cnt] = mvpMrgCtx2->useAltHpelIf[uiNumCand];
+      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = mvpMrgCtx2->mvFieldNeighbours[(uiNumCand << 1) + 1];
+#if JVET_Y0089_DMVR_BCW
+      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? mvpMrgCtx2->BcwIdx[uiNumCand] : BCW_DEFAULT;
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+#endif
+      {
+        mrgCtx.candCost[cnt] = mvpMrgCtx2->candCost[uiNumCand];
+        if (mrgCandIdx == cnt)
+        {
+          mrgCtx.numValidMergeCand = cnt + 1;
+          return;
+        }
+        cnt++;
+      }
+    }
   }
+#endif
+#endif
 
+  if (cnt != maxNumMergeCandMin1)
+  {
+#if !JVET_Z0075_IBC_HMVP_ENLARGE
+    bool isGt4x4 = true;
+#endif
+    bool bFound = addBMMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt
+      , isAvailableA1, miLeft, isAvailableB1, miAbove
+#if !JVET_Z0075_IBC_HMVP_ENLARGE
+      , CU::isIBC(*pu.cu)
+      , isGt4x4
+#endif
+#if TM_MRG
+      , mvThreshod
+#endif
+    );
 
-  const PredictionUnit *puAboveLeft = cs.getPURestricted(posLT.offset(-1, -1), pu, pu.chType);
+    if (bFound)
+    {
+      return;
+    }
+  }
 
-#if JVET_Y0065_GPM_INTRA
-  bool isAvailableB2 = puAboveLeft && isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel) && CU::isInter(*puAboveLeft->cu) && puAboveLeft->getMotionInfo(posLT.offset(-1, -1)).isInter;
-#else
-  bool isAvailableB2 = puAboveLeft && isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel) && CU::isInter(*puAboveLeft->cu);
+#if !JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC || (JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC)
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
+  if (!pu.cs->sps->getUseAML())
 #endif
-
-  if (isAvailableB2)
   {
-    miAboveLeft = puAboveLeft->getMotionInfo(posLT.offset(-1, -1));
-
-    if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft)))
+    if (cnt > 1 && cnt < maxNumMergeCand)
     {
-      if (isBiPredFromDifferentDirEqDistPoc(pu, miAboveLeft.refIdx[0], miAboveLeft.refIdx[1])
-        )
+      mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), NOT_VALID);
+      mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField(Mv(0, 0), NOT_VALID);
+#if INTER_LIC
+      mrgCtx.LICFlags[cnt] = false;
+#endif
+#if MULTI_HYP_PRED
+      mrgCtx.addHypNeighbours[cnt].clear();
+#endif
+      mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+      // calculate average MV for L0 and L1 seperately
+      unsigned char interDir = 0;
+      mrgCtx.useAltHpelIf[cnt] = (mrgCtx.useAltHpelIf[0] == mrgCtx.useAltHpelIf[1]) ? mrgCtx.useAltHpelIf[0] : false;
+      for (int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++)
       {
+        const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx;
+        const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx;
 
-        // get Inter Dir
-        mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
-        mrgCtx.useAltHpelIf[cnt] = miAboveLeft.useAltHpelIf;
-        // get Mv from Above-Left
-        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveLeft.mv[0], miAboveLeft.refIdx[0]);
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAboveLeft.mv[1], miAboveLeft.refIdx[1]);
-#if JVET_Y0089_DMVR_BCW
-        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT;
+        // both MVs are invalid, skip
+        if (refIdxI != refIdxJ)
+        {
+          continue;
+        }
+
+        interDir += 1 << refListId;
+        const Mv& mvI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
+        const Mv& mvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
+
+        // average two MVs
+        Mv avgMv = mvI;
+        avgMv += mvJ;
+        roundAffineMv(avgMv.hor, avgMv.ver, 1);
+
+        mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField(avgMv, refIdxI);
+      }
+
+      mrgCtx.interDirNeighbours[cnt] = interDir;
+      if (interDir == 3 && isBiPredFromDifferentDirEqDistPoc(pu, mrgCtx.mvFieldNeighbours[cnt * 2 + 0].refIdx, mrgCtx.mvFieldNeighbours[cnt * 2 + 1].refIdx))
+      {
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+#endif
+          cnt++;
+      }
+    }
+
+    // early termination
+    if (cnt == maxNumMergeCand)
+    {
+      mrgCtx.numValidMergeCand = cnt;
+      return;
+    }
+  }
+#endif
+
+  mrgCtx.numCandToTestEnc = cnt;
+
+#if JVET_Y0128_NON_CTC
+  while(cnt < maxNumMergeCand)
+#else
+  if (cnt < maxNumMergeCand)
+#endif
+  {
+    mrgCtx.interDirNeighbours[cnt] = 3;
+    mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+    mrgCtx.LICFlags[cnt] = false;
 #endif
-
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-        {
+#if MULTI_HYP_PRED
+    mrgCtx.addHypNeighbours[cnt].clear();
 #endif
-          if (mrgCandIdx == cnt)
-          {
-            mrgCtx.numValidMergeCand = cnt + 1;
-            return;
-          }
-
-          cnt++;
+    mrgCtx.useAltHpelIf[cnt] = false;
+#if JVET_Y0128_NON_CTC
+    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(0, 0), pu.cs->slice->getBMDefaultRefIdx(0));
+    mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(0, 0), pu.cs->slice->getBMDefaultRefIdx(1));
+#else
+    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(0, 0), 0);
+    mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(0, 0), 0);
+#endif
+#if !JVET_Y0128_NON_CTC
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-        }
+    if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
 #endif
+#endif
+    {
+      if (mrgCandIdx == cnt)
+      {
+        mrgCtx.numValidMergeCand = cnt + 1;
+        return;
       }
+      cnt++;
     }
   }
-  // early termination
-  if (cnt == maxNumMergeCand)
+  mrgCtx.numValidMergeCand = cnt;
+}
+#endif
+
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
+{
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+  if (!pu.cs->sps->getUseTmvpNmvpReordering())
   {
-    mrgCtx.numValidMergeCand = cnt;
+    mrgCtx.numValidMergeCand = 0;
     return;
   }
+#endif
+
+  const CodingStructure &cs = *pu.cs;
+  const Slice &slice = *pu.cs->slice;
+
+  const uint32_t mvThreshod = 1;
+  const uint32_t maxNumMergeCand = NUM_TMVP_CANDS;
+  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
+  {
+    mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
+#if INTER_LIC
+    mrgCtx.LICFlags[ui] = false;
+#endif
+    mrgCtx.interDirNeighbours[ui] = 0;
+    mrgCtx.mvFieldNeighbours[(ui << 1)].refIdx = NOT_VALID;
+    mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
+    mrgCtx.useAltHpelIf[ui] = false;
+#if MULTI_HYP_PRED
+    mrgCtx.addHypNeighbours[ui].clear();
+#endif
+    mrgCtx.candCost[ui] = MAX_UINT64;
+  }
+
+  int cnt = 0;
 
 #if INTER_RM_SIZE_CONSTRAINTS
   if (slice.getPicHeader()->getEnableTMVPFlag())
@@ -6888,182 +7836,242 @@ void PU::getInterBMCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx,
   if (slice.getPicHeader()->getEnableTMVPFlag() && (pu.lumaSize().width + pu.lumaSize().height > 12))
 #endif
   {
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-    if (mvpMrgCtx1 == NULL)
-    {
-#endif
     //>> MTK colocated-RightBottom
     // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
-    Position posRB = pu.Y().bottomRight().offset(-3, -3);
     const PreCalcValues& pcv = *cs.pcv;
-
-    Position posC0;
-    Position posC1 = pu.Y().center();
-    bool C0Avail = false;
-    bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+    bool isC0Avail;
+    bool isC1Avail;
+    bool boundaryCond;
     const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
-    if (curSubPic.getTreatedAsPicFlag())
-    {
-      boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
-        (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
-    }
-    if (boundaryCond)
-    {
-      int posYInCtu = posRB.y & pcv.maxCUHeightMask;
-      if (posYInCtu + 4 < pcv.maxCUHeight)
-      {
-        posC0 = posRB.offset(4, 4);
-        C0Avail = true;
-      }
-    }
+    Position posRB = pu.Y().bottomRight().offset(-3, -3);
+    Position posCenter = pu.Y().center();
+    Position posC0;
+    Position posC1;
 
-    Mv        cColMv;
     int       iRefIdx = 0;
-    int       dir = 0;
-    unsigned  uiArrayAddr = cnt;
-    bool      bExistMV = (C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx, false))
-      || getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx, false);
-    if (bExistMV)
-    {
-      dir |= 1;
-      mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
-    }
+    bool      bExistMV0, bExistMV1;
+    Mv        cColMv0, cColMv1;
+    int       dir;
 
-    if (slice.isInterB())
-    {
-      bExistMV = (C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx, false))
-        || getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx, false);
-      if (bExistMV)
-      {
-        dir |= 2;
-        mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
-      }
-    }
+    int offsetX0 = 0, offsetX1 = 0, offsetX2 = 0, offsetX3 = pu.Y().width >> 1;
+    int offsetY0 = 0, offsetY1 = 0, offsetY2 = 0, offsetY3 = pu.Y().height >> 1;
 
-    if (dir != 0)
+    const int numNACandidate[5] = { 2, 2, 2, 2, 2 };
+    const int idxMap[5][2] = { { 0, 1 },{ 0, 2 },{ 0, 2 },{ 0, 2 },{ 0, 2 } };
+    for (int iDistanceIndex = 0; iDistanceIndex < TMVP_DISTANCE_LEVEL && cnt < maxNumMergeCand; iDistanceIndex++)
     {
-      bool addTMvp = isBiPredFromDifferentDirEqDistPoc(pu, mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 0].refIdx, mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].refIdx);
-      if (addTMvp)
+      const int iNADistanceHor = pu.Y().width  * iDistanceIndex;
+      const int iNADistanceVer = pu.Y().height * iDistanceIndex;
+
+      for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
       {
-        mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
-        mrgCtx.useAltHpelIf[uiArrayAddr] = false;
-#if MULTI_HYP_PRED
-        mrgCtx.addHypNeighbours[uiArrayAddr].clear();
-#endif
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+        switch (idxMap[iDistanceIndex][iNASPIdx])
         {
-#endif
-          if (mrgCandIdx == cnt)
+        case 0: offsetX0 = offsetX2 = 4 + iNADistanceHor; offsetY0 = offsetY2 = 4 + iNADistanceVer; offsetX1 = iNADistanceHor; offsetY1 = iNADistanceVer; break;
+        case 1: offsetX0 = 4; offsetY0 = 0; offsetX1 = 0; offsetY1 = 4; break;
+        case 2: offsetX0 = offsetX2; offsetY0 = 4 - offsetY3; offsetX1 = 4 - offsetX3; offsetY1 = offsetY2; break;
+        default: printf("error!"); exit(0); break;
+        }
+        isC0Avail = false;
+        if (curSubPic.getTreatedAsPicFlag())
+        {
+          boundaryCond = ((posRB.x + offsetX0) <= curSubPic.getSubPicRight() && (posRB.y + offsetY0) <= curSubPic.getSubPicBottom());
+        }
+        else
+        {
+          boundaryCond = ((posRB.x + offsetX0) < pcv.lumaWidth) && ((posRB.y + offsetY0) < pcv.lumaHeight);
+        }
+        if (boundaryCond)
+        {
+          int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+          if (posYInCtu + offsetY0 < pcv.maxCUHeight)
           {
-            mrgCtx.numValidMergeCand = cnt + 1;
-            return;
+            posC0 = posRB.offset(offsetX0, offsetY0);
+            isC0Avail = true;
           }
+        }
 
-          cnt++;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
+        if (idxMap[iDistanceIndex][iNASPIdx] == 0)
+        {
+          isC1Avail = false;
+          if (curSubPic.getTreatedAsPicFlag())
+          {
+            boundaryCond = ((posCenter.x + offsetX1) <= curSubPic.getSubPicRight() && (posCenter.y + offsetY1) <= curSubPic.getSubPicBottom());
+          }
+          else
+          {
+            boundaryCond = ((posCenter.x + offsetX1) < pcv.lumaWidth) && ((posCenter.y + offsetY1) < pcv.lumaHeight);
+          }
+          if (boundaryCond)
+          {
+            int posYInCtu = posCenter.y & pcv.maxCUHeightMask;
+            if (posYInCtu + offsetY1 < pcv.maxCUHeight)
+            {
+              posC1 = posCenter.offset(offsetX1, offsetY1);
+              isC1Avail = true; 
+            }
+          }
         }
+        else
+        {
+          isC1Avail = false;
+          if (curSubPic.getTreatedAsPicFlag())
+          {
+            boundaryCond = ((posRB.x + offsetX1) <= curSubPic.getSubPicRight() && (posRB.y + offsetY1) <= curSubPic.getSubPicBottom());
+          }
+          else
+          {
+            boundaryCond = ((posRB.x + offsetX1) < pcv.lumaWidth) && ((posRB.y + offsetY1) < pcv.lumaHeight);
+          }
+          if (boundaryCond)
+          {
+            int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+            if (posYInCtu + offsetY1 < pcv.maxCUHeight)
+            {
+              posC1 = posRB.offset(offsetX1, offsetY1);
+              isC1Avail = true;
+            }
+          }
+        }
+
+        bExistMV0 = bExistMV1 = false;
+
+        // Candidate with L0 and L1
+        dir = 0;
+        bExistMV0 = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv0, iRefIdx, false
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , 0
 #endif
-      }
-    }
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-    }
-#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
-    else if (mvpMrgCtx1->numValidMergeCand > 0)
-    {
-      for (int uiNumCand = 0; uiNumCand < mvpMrgCtx1->numValidMergeCand && cnt < maxNumMergeCand; uiNumCand++)
-      {
-        mrgCtx.interDirNeighbours[cnt] = mvpMrgCtx1->interDirNeighbours[uiNumCand];
-        mrgCtx.mvFieldNeighbours[cnt << 1] = mvpMrgCtx1->mvFieldNeighbours[uiNumCand << 1];
-        mrgCtx.useAltHpelIf[cnt] = mvpMrgCtx1->useAltHpelIf[uiNumCand];
-        mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = mvpMrgCtx1->mvFieldNeighbours[(uiNumCand << 1) + 1];
-#if JVET_Y0089_DMVR_BCW
-        mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? mvpMrgCtx1->BcwIdx[uiNumCand] : BCW_DEFAULT;
-#endif
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+        ))
+          || (isC1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv0, iRefIdx, false
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , 0
 #endif
+          ));
+        if (bExistMV0)
         {
-          mrgCtx.candCost[cnt] = mvpMrgCtx1->candCost[uiNumCand];
-          if (mrgCandIdx == cnt)
+          dir |= 1;
+          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, iRefIdx);
+        }
+        else
+        {
+          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(Mv(), NOT_VALID);
+        }
+        if (slice.isInterB())
+        {
+          bExistMV1 = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv1, iRefIdx, false
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , 0
+#endif
+          ))
+            || (isC1Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv1, iRefIdx, false
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              , 0
+#endif
+            ));
+          if (bExistMV1)
           {
-            mrgCtx.numValidMergeCand = cnt + 1;
-            return;
+            dir |= 2;
+            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, iRefIdx);
           }
-          cnt++;
-        }
-      }
-    }
-#else
-    else if (mvpMrgCtx1->numValidMergeCand > 0)
-    {
-      mrgCtx.interDirNeighbours[cnt] = mvpMrgCtx1->interDirNeighbours[0];
-      mrgCtx.mvFieldNeighbours[cnt << 1] = mvpMrgCtx1->mvFieldNeighbours[0];
-      mrgCtx.useAltHpelIf[cnt] = mvpMrgCtx1->useAltHpelIf[0];
-      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = mvpMrgCtx1->mvFieldNeighbours[1];
+          else
+          {
+            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(Mv(), NOT_VALID);
+          }
+        }
+        if (dir != 0)
+        {
+          bool addTMvp = isBiPredFromDifferentDirEqDistPoc(pu, mrgCtx.mvFieldNeighbours[2 * cnt + 0].refIdx, mrgCtx.mvFieldNeighbours[2 * cnt + 1].refIdx);
+          if (addTMvp)
+          {
+            mrgCtx.interDirNeighbours[cnt] = dir;
+            mrgCtx.useAltHpelIf[cnt] = false;
 #if MULTI_HYP_PRED
-      mrgCtx.addHypNeighbours[cnt] = mvpMrgCtx1->addHypNeighbours[0];
-#endif
-#if JVET_Y0089_DMVR_BCW
-      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? mvpMrgCtx1->BcwIdx[0] : BCW_DEFAULT;
-#endif
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-      if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+            mrgCtx.addHypNeighbours[cnt].clear();
 #endif
-      {
-        mrgCtx.candCost[cnt] = mvpMrgCtx1->candCost[0];
-        if (mrgCandIdx == cnt)
-        {
-          mrgCtx.numValidMergeCand = cnt + 1;
-          return;
+            if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod
+            ))
+            {
+              cnt++;
+              if (cnt == maxNumMergeCand)
+              {
+                break;
+              }
+            }
+          }
         }
-        cnt++;
       }
     }
+}
+
+  mrgCtx.numValidMergeCand = cnt;
+}
 #endif
-#endif
-  }
 
-  // early termination
-  if (cnt == maxNumMergeCand)
+#if NON_ADJACENT_MRG_CAND && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+void PU::getNonAdjacentBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
+{
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+  if (!pu.cs->sps->getUseTmvpNmvpReordering())
   {
-    mrgCtx.numValidMergeCand = cnt;
+    mrgCtx.numValidMergeCand = 0;
     return;
   }
-
-#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
-  int maxNumMergeCandMin1 = maxNumMergeCand;
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-  maxNumMergeCandMin1 -= !pu.cs->sps->getUseAML() ? 1 : 0;
-#endif
-#else
-  int maxNumMergeCandMin1 = maxNumMergeCand - 1;
 #endif
-#if NON_ADJACENT_MRG_CAND
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-  if (mvpMrgCtx2 == NULL)
+  const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
+  const CodingStructure &cs = *pu.cs;
+
+  const uint32_t mvThreshod = getBDMVRMvdThreshold(pu);
+
+  const uint32_t maxNumMergeCand = NUM_NON_ADJ_CANDS;
+
+  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
   {
+    mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
+#if INTER_LIC
+    mrgCtx.LICFlags[ui] = false;
+#endif
+    mrgCtx.interDirNeighbours[ui] = 0;
+    mrgCtx.mvFieldNeighbours[(ui << 1)].refIdx = NOT_VALID;
+    mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
+    mrgCtx.useAltHpelIf[ui] = false;
+#if MULTI_HYP_PRED
+    mrgCtx.addHypNeighbours[ui].clear();
 #endif
+    mrgCtx.candCost[ui] = MAX_UINT64;
+  }
+
+  int cnt = 0;
+
+  const Position posLT = pu.Y().topLeft();
+
   MotionInfo miNeighbor;
   int offsetX = 0;
   int offsetY = 0;
-  const int iNACANDIDATE_NUM[4] = { 3, 5, 5, 5 };
-  const int idxMap[4][5] = { { 0, 1, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 } };
+  int offsetX0 = 0; int offsetX1 = 0; int offsetX2 = pu.Y().width >> 1;
+  int offsetY0 = 0; int offsetY1 = 0; int offsetY2 = pu.Y().height >> 1;
 
-  for (int iDistanceIndex = 0; iDistanceIndex < NADISTANCE_LEVEL && cnt < maxNumMergeCandMin1; iDistanceIndex++)
+  const int numNACandidate[7] = { 5, 9, 9, 9, 9, 9, 9 };
+  const int idxMap[7][9] = { { 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 } };
+
+  for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
   {
     const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
     const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCandMin1; NASPIdx++)
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
     {
-      switch (idxMap[iDistanceIndex][NASPIdx])
+      switch (idxMap[iDistanceIndex][iNASPIdx])
       {
-      case 0:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height + iNADistanceVer - 1; break;
-      case 1:offsetX = pu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break;
-      case 2:offsetX = pu.Y().width >> 1;   offsetY = -iNADistanceVer - 1;    break;
-      case 3:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height >> 1; break;
-      case 4:offsetX = -iNADistanceHor - 1; offsetY = -iNADistanceVer - 1;    break;
+      case 0:offsetX = offsetX0 = -iNADistanceHor - 1;               offsetY = offsetY0 = pu.Y().height + iNADistanceVer - 1; break;
+      case 1:offsetX = offsetX1 = pu.Y().width + iNADistanceHor - 1; offsetY = offsetY1 = -iNADistanceVer - 1;                break;
+      case 2:offsetX = offsetX2;                                     offsetY = offsetY1;                                      break;
+      case 3:offsetX = offsetX0;                                     offsetY = offsetY2;                                      break;
+      case 4:offsetX = offsetX0;                                     offsetY = offsetY1;                                      break;
+      case 5:offsetX = -1;                                           offsetY = offsetY0;                                      break;
+      case 6:offsetX = offsetX1;                                     offsetY = -1;                                            break;
+      case 7:offsetX = offsetX0 >> 1;                                offsetY = offsetY0;                                      break;
+      case 8:offsetX = offsetX1;                                     offsetY = offsetY1 >> 1;                                 break;
       default: printf("error!"); exit(0); break;
       }
 
@@ -7079,192 +8087,80 @@ void PU::getInterBMCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx,
       {
         miNeighbor = puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY));
 
-
         if (isBiPredFromDifferentDirEqDistPoc(pu, miNeighbor.refIdx[0], miNeighbor.refIdx[1])
           )
         {
           // get Inter Dir
           mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
-          // get Mv from Above-Left
           mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
           mrgCtx.useAltHpelIf[cnt] = miNeighbor.useAltHpelIf;
           mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
-#if JVET_Y0089_DMVR_BCW
-          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puNonAdjacent->cu->BcwIdx : BCW_DEFAULT;
-#endif
 
-#if NON_ADJACENT_MRG_CAND || TM_MRG
           if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-#endif
           {
-            if (mrgCandIdx == cnt)
-            {
-              mrgCtx.numValidMergeCand = cnt + 1;
-              return;
-            }
             cnt++;
           }
         }
       }
     }
   }
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-  }
-  else
-  {
-    for (int uiNumCand = 0; uiNumCand < mvpMrgCtx2->numValidMergeCand && cnt < maxNumMergeCandMin1; uiNumCand++)
-    {
-      mrgCtx.interDirNeighbours[cnt] = mvpMrgCtx2->interDirNeighbours[uiNumCand];
-      mrgCtx.mvFieldNeighbours[cnt << 1] = mvpMrgCtx2->mvFieldNeighbours[uiNumCand << 1];
-      mrgCtx.useAltHpelIf[cnt] = mvpMrgCtx2->useAltHpelIf[uiNumCand];
-      mrgCtx.mvFieldNeighbours[(cnt << 1) + 1] = mvpMrgCtx2->mvFieldNeighbours[(uiNumCand << 1) + 1];
-#if JVET_Y0089_DMVR_BCW
-      mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? mvpMrgCtx2->BcwIdx[uiNumCand] : BCW_DEFAULT;
-#endif
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-      if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-#endif
-      {
-        mrgCtx.candCost[cnt] = mvpMrgCtx2->candCost[uiNumCand];
-        if (mrgCandIdx == cnt)
-        {
-          mrgCtx.numValidMergeCand = cnt + 1;
-          return;
-        }
-        cnt++;
-      }
-    }
-  }
-#endif
-#endif
-
-  if (cnt != maxNumMergeCandMin1)
-  {
-#if !JVET_Z0075_IBC_HMVP_ENLARGE
-    bool isGt4x4 = true;
-#endif
-    bool bFound = addBMMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt
-      , isAvailableA1, miLeft, isAvailableB1, miAbove
-#if !JVET_Z0075_IBC_HMVP_ENLARGE
-      , CU::isIBC(*pu.cu)
-      , isGt4x4
-#endif
-#if TM_MRG
-      , mvThreshod
-#endif
-    );
 
-    if (bFound)
-    {
-      return;
-    }
-  }
+  const int numNACandidate2[7] = { 4, 4, 4, 4, 4, 4, 4 };
+  const int idxMap2[7][5] = { { 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 } };
 
-#if !JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC || (JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC)
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
-  if (!pu.cs->sps->getUseAML())
-#endif
+  for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
   {
-    if (cnt > 1 && cnt < maxNumMergeCand)
-    {
-      mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), NOT_VALID);
-      mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField(Mv(0, 0), NOT_VALID);
-#if INTER_LIC
-      mrgCtx.LICFlags[cnt] = false;
-#endif
-#if MULTI_HYP_PRED
-      mrgCtx.addHypNeighbours[cnt].clear();
-#endif
-      mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
-      // calculate average MV for L0 and L1 seperately
-      unsigned char interDir = 0;
-      mrgCtx.useAltHpelIf[cnt] = (mrgCtx.useAltHpelIf[0] == mrgCtx.useAltHpelIf[1]) ? mrgCtx.useAltHpelIf[0] : false;
-      for (int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++)
-      {
-        const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx;
-        const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx;
-
-        // both MVs are invalid, skip
-        if (refIdxI != refIdxJ)
-        {
-          continue;
-        }
-
-        interDir += 1 << refListId;
-        const Mv& mvI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
-        const Mv& mvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
-
-        // average two MVs
-        Mv avgMv = mvI;
-        avgMv += mvJ;
-        roundAffineMv(avgMv.hor, avgMv.ver, 1);
-
-        mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField(avgMv, refIdxI);
-      }
+    const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
+    const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-      mrgCtx.interDirNeighbours[cnt] = interDir;
-      if (interDir == 3 && isBiPredFromDifferentDirEqDistPoc(pu, mrgCtx.mvFieldNeighbours[cnt * 2 + 0].refIdx, mrgCtx.mvFieldNeighbours[cnt * 2 + 1].refIdx))
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate2[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
+    {
+      switch (idxMap2[iDistanceIndex][iNASPIdx])
       {
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-        if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-#endif
-          cnt++;
+      case 0:offsetX = offsetX0 = -iNADistanceHor - 1;                                                         offsetY = offsetY2 + ((pu.Y().height + iNADistanceVer - 1 - offsetY2) >> 1); break;
+      case 1:offsetX = offsetX2 + ((pu.Y().width + iNADistanceHor - 1 - offsetX2) >> 1);                       offsetY = offsetY0 = -iNADistanceVer - 1; break;
+      case 2:offsetX = offsetX0;                                                                               offsetY = offsetY0 + ((offsetY2 - offsetY0) >> 1); break;
+      case 3:offsetX = offsetX0 + ((offsetX2 - offsetX0) >> 1);                                                offsetY = offsetY0; break;
+      default: printf("error!"); exit(0); break;
       }
-    }
-
-    // early termination
-    if (cnt == maxNumMergeCand)
-    {
-      mrgCtx.numValidMergeCand = cnt;
-      return;
-    }
-  }
-#endif
 
-  mrgCtx.numCandToTestEnc = cnt;
+      const PredictionUnit *puNonAdjacent = cs.getPURestricted(posLT.offset(offsetX, offsetY), pu, pu.chType);
 
-#if JVET_Y0128_NON_CTC
-  while(cnt < maxNumMergeCand)
-#else
-  if (cnt < maxNumMergeCand)
-#endif
-  {
-    mrgCtx.interDirNeighbours[cnt] = 3;
-    mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
-#if INTER_LIC
-    mrgCtx.LICFlags[cnt] = false;
-#endif
-#if MULTI_HYP_PRED
-    mrgCtx.addHypNeighbours[cnt].clear();
-#endif
-    mrgCtx.useAltHpelIf[cnt] = false;
-#if JVET_Y0128_NON_CTC
-    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(0, 0), pu.cs->slice->getBMDefaultRefIdx(0));
-    mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(0, 0), pu.cs->slice->getBMDefaultRefIdx(1));
+#if JVET_Y0065_GPM_INTRA
+      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu) && puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY)).isInter;
 #else
-    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(0, 0), 0);
-    mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(0, 0), 0);
-#endif
-#if !JVET_Y0128_NON_CTC
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-    if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-#endif
+      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu);
 #endif
-    {
-      if (mrgCandIdx == cnt)
+
+      if (isAvailableNonAdjacent)
       {
-        mrgCtx.numValidMergeCand = cnt + 1;
-        return;
+        miNeighbor = puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY));
+
+        if (isBiPredFromDifferentDirEqDistPoc(pu, miNeighbor.refIdx[0], miNeighbor.refIdx[1])
+          )
+        {
+          // get Inter Dir
+          mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
+          // get Mv from Above-Left
+          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
+          mrgCtx.useAltHpelIf[cnt] = miNeighbor.useAltHpelIf;
+          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
+
+          if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
+          {
+            cnt++;
+          }
+        }
       }
-      cnt++;
     }
   }
+
   mrgCtx.numValidMergeCand = cnt;
 }
 #endif
 
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
+void PU::getTmvpMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
 {
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS
   if (!pu.cs->sps->getUseTmvpNmvpReordering())
@@ -7273,12 +8169,21 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     return;
   }
 #endif
-
   const CodingStructure &cs = *pu.cs;
   const Slice &slice = *pu.cs->slice;
 
-  const uint32_t mvThreshod = 1;
+#if TM_MRG
+  const uint32_t mvdSimilarityThresh = 1;
+#endif
+#if TM_MRG && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
+  const uint32_t maxNumMergeCand =
+#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
+                                   pu.cs->sps->getUseTMMrgMode() &&
+#endif
+                                   pu.tmMergeFlag ? 1 : NUM_TMVP_CANDS;
+#else
   const uint32_t maxNumMergeCand = NUM_TMVP_CANDS;
+#endif
   for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
   {
     mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
@@ -7296,7 +8201,6 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
   }
 
   int cnt = 0;
-
 #if INTER_RM_SIZE_CONSTRAINTS
   if (slice.getPicHeader()->getEnableTMVPFlag())
 #else
@@ -7306,8 +8210,8 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     //>> MTK colocated-RightBottom
     // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
     const PreCalcValues& pcv = *cs.pcv;
-    bool C0Avail;
-    bool C1Avail;
+    bool isC0Avail;
+    bool isC1Avail;
     bool boundaryCond;
     const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
     Position posRB = pu.Y().bottomRight().offset(-3, -3);
@@ -7323,23 +8227,23 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     int offsetX0 = 0, offsetX1 = 0, offsetX2 = 0, offsetX3 = pu.Y().width >> 1;
     int offsetY0 = 0, offsetY1 = 0, offsetY2 = 0, offsetY3 = pu.Y().height >> 1;
 
-    const int iNACANDIDATE_NUM[5] = { 2, 2, 2, 2, 2 };
+    const int numNACandidate[5] = { 2, 2, 2, 2, 2 };
     const int idxMap[5][2] = { { 0, 1 },{ 0, 2 },{ 0, 2 },{ 0, 2 },{ 0, 2 } };
     for (int iDistanceIndex = 0; iDistanceIndex < TMVP_DISTANCE_LEVEL && cnt < maxNumMergeCand; iDistanceIndex++)
     {
       const int iNADistanceHor = pu.Y().width  * iDistanceIndex;
       const int iNADistanceVer = pu.Y().height * iDistanceIndex;
 
-      for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
+      for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
       {
-        switch (idxMap[iDistanceIndex][NASPIdx])
+        switch (idxMap[iDistanceIndex][iNASPIdx])
         {
         case 0: offsetX0 = offsetX2 = 4 + iNADistanceHor; offsetY0 = offsetY2 = 4 + iNADistanceVer; offsetX1 = iNADistanceHor; offsetY1 = iNADistanceVer; break;
         case 1: offsetX0 = 4; offsetY0 = 0; offsetX1 = 0; offsetY1 = 4; break;
         case 2: offsetX0 = offsetX2; offsetY0 = 4 - offsetY3; offsetX1 = 4 - offsetX3; offsetY1 = offsetY2; break;
         default: printf("error!"); exit(0); break;
         }
-        C0Avail = false;
+        isC0Avail = false;
         if (curSubPic.getTreatedAsPicFlag())
         {
           boundaryCond = ((posRB.x + offsetX0) <= curSubPic.getSubPicRight() && (posRB.y + offsetY0) <= curSubPic.getSubPicBottom());
@@ -7354,13 +8258,13 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
           if (posYInCtu + offsetY0 < pcv.maxCUHeight)
           {
             posC0 = posRB.offset(offsetX0, offsetY0);
-            C0Avail = true;
+            isC0Avail = true;
           }
         }
 
-        if (idxMap[iDistanceIndex][NASPIdx] == 0)
+        if (idxMap[iDistanceIndex][iNASPIdx] == 0)
         {
-          C1Avail = false;
+          isC1Avail = false;
           if (curSubPic.getTreatedAsPicFlag())
           {
             boundaryCond = ((posCenter.x + offsetX1) <= curSubPic.getSubPicRight() && (posCenter.y + offsetY1) <= curSubPic.getSubPicBottom());
@@ -7375,13 +8279,13 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
             if (posYInCtu + offsetY1 < pcv.maxCUHeight)
             {
               posC1 = posCenter.offset(offsetX1, offsetY1);
-              C1Avail = true;
+              isC1Avail = true;
             }
           }
         }
         else
         {
-          C1Avail = false;
+          isC1Avail = false;
           if (curSubPic.getTreatedAsPicFlag())
           {
             boundaryCond = ((posRB.x + offsetX1) <= curSubPic.getSubPicRight() && (posRB.y + offsetY1) <= curSubPic.getSubPicBottom());
@@ -7396,7 +8300,7 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
             if (posYInCtu + offsetY1 < pcv.maxCUHeight)
             {
               posC1 = posRB.offset(offsetX1, offsetY1);
-              C1Avail = true;
+              isC1Avail = true;
             }
           }
         }
@@ -7405,12 +8309,22 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
 
         // Candidate with L0 and L1
         dir = 0;
-        bExistMV0 = (C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv0, iRefIdx, false))
-          || (C1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv0, iRefIdx, false));
+        int refIdx[NUM_REF_PIC_LIST_01] = { 0, 0 };
+        bExistMV0 = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv0, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          0,
+#endif
+          &refIdx[REF_PIC_LIST_0]))
+          || (isC1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv0, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            0,
+#endif
+            &refIdx[REF_PIC_LIST_0]));
+
         if (bExistMV0)
         {
           dir |= 1;
-          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, iRefIdx);
+          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, refIdx[REF_PIC_LIST_0]);
         }
         else
         {
@@ -7418,12 +8332,21 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
         }
         if (slice.isInterB())
         {
-          bExistMV1 = (C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv1, iRefIdx, false))
-            || (C1Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv1, iRefIdx, false));
+          bExistMV1 = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv1, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            0,
+#endif
+            &refIdx[REF_PIC_LIST_1]))
+            || (isC1Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv1, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              0,
+#endif
+              &refIdx[REF_PIC_LIST_1]));
+
           if (bExistMV1)
           {
             dir |= 2;
-            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, iRefIdx);
+            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, refIdx[REF_PIC_LIST_1]);
           }
           else
           {
@@ -7432,50 +8355,350 @@ void PU::getTmvpBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
         }
         if (dir != 0)
         {
-          bool addTMvp = isBiPredFromDifferentDirEqDistPoc(pu, mrgCtx.mvFieldNeighbours[2 * cnt + 0].refIdx, mrgCtx.mvFieldNeighbours[2 * cnt + 1].refIdx);
-          if (addTMvp)
+          mrgCtx.interDirNeighbours[cnt] = dir;
+          mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+          mrgCtx.LICFlags[cnt] = false;
+#endif
+          mrgCtx.useAltHpelIf[cnt] = false;
+#if MULTI_HYP_PRED
+          mrgCtx.addHypNeighbours[cnt].clear();
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+          if (!mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+            , mvdSimilarityThresh
+#endif
+          ))
+          {
+#endif
+            cnt++;
+            if (cnt == maxNumMergeCand)
+            {
+              break;
+            }
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+          }
+#endif
+        }
+        if (!slice.getCheckLDC() && bExistMV0 && bExistMV1)
+        {
+          // Candidate without L1
+          dir = 0;
+          dir |= 1;
+          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, refIdx[REF_PIC_LIST_0]);
+          mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(Mv(), NOT_VALID);
+          if (dir != 0)
+          {
+            mrgCtx.interDirNeighbours[cnt] = dir;
+            mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+            mrgCtx.LICFlags[cnt] = false;
+#endif
+            mrgCtx.useAltHpelIf[cnt] = false;
+#if MULTI_HYP_PRED
+            mrgCtx.addHypNeighbours[cnt].clear();
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+            if (!mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+              , mvdSimilarityThresh
+#endif
+            ))
+            {
+#endif
+              cnt++;
+              if (cnt == maxNumMergeCand) break;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+            }
+#endif
+          }
+
+          // Candidate without L0
+          dir = 0;
+          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(Mv(), NOT_VALID);
+          dir |= 2;
+          mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, refIdx[REF_PIC_LIST_1]);
+          if (dir != 0)
+          {
+            mrgCtx.interDirNeighbours[cnt] = dir;
+            mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+            mrgCtx.LICFlags[cnt] = false;
+#endif
+            mrgCtx.useAltHpelIf[cnt] = false;
+#if MULTI_HYP_PRED
+            mrgCtx.addHypNeighbours[cnt].clear();
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+            if (!mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+              , mvdSimilarityThresh
+#endif
+            ))
+            {
+#endif
+              cnt++;
+              if (cnt == maxNumMergeCand)
+              {
+                break;
+              }
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+            }
+#endif
+          }
+        }
+      }
+    }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    if (pu.tmMergeFlag)
+    {
+      offsetX0 = 0, offsetX1 = 0, offsetX2 = 0, offsetX3 = pu.Y().width >> 1;
+      offsetY0 = 0, offsetY1 = 0, offsetY2 = 0, offsetY3 = pu.Y().height >> 1;
+
+      for (int iDistanceIndex = 0; iDistanceIndex < TMVP_DISTANCE_LEVEL && cnt < (maxNumMergeCand + 1); iDistanceIndex++)
+      {
+        const int iNADistanceHor = pu.Y().width  * iDistanceIndex;
+        const int iNADistanceVer = pu.Y().height * iDistanceIndex;
+
+        for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < (maxNumMergeCand + 1); iNASPIdx++)
+        {
+          switch (idxMap[iDistanceIndex][iNASPIdx])
+          {
+          case 0: offsetX0 = offsetX2 = 4 + iNADistanceHor; offsetY0 = offsetY2 = 4 + iNADistanceVer; offsetX1 = iNADistanceHor; offsetY1 = iNADistanceVer; break;
+          case 1: offsetX0 = 4; offsetY0 = 0; offsetX1 = 0; offsetY1 = 4; break;
+          case 2: offsetX0 = offsetX2; offsetY0 = 4 - offsetY3; offsetX1 = 4 - offsetX3; offsetY1 = offsetY2; break;
+          default: printf("error!"); exit(0); break;
+          }
+          isC0Avail = false;
+          if (curSubPic.getTreatedAsPicFlag())
+          {
+            boundaryCond = ((posRB.x + offsetX0) <= curSubPic.getSubPicRight() && (posRB.y + offsetY0) <= curSubPic.getSubPicBottom());
+          }
+          else
+          {
+            boundaryCond = ((posRB.x + offsetX0) < pcv.lumaWidth) && ((posRB.y + offsetY0) < pcv.lumaHeight);
+          }
+          if (boundaryCond)
+          {
+            int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+            if (posYInCtu + offsetY0 < pcv.maxCUHeight)
+            {
+              posC0 = posRB.offset(offsetX0, offsetY0);
+              isC0Avail = true;
+            }
+          }
+
+          if (idxMap[iDistanceIndex][iNASPIdx] == 0)
+          {
+            isC1Avail = false;
+            if (curSubPic.getTreatedAsPicFlag())
+            {
+              boundaryCond = ((posCenter.x + offsetX1) <= curSubPic.getSubPicRight() && (posCenter.y + offsetY1) <= curSubPic.getSubPicBottom());
+            }
+            else
+            {
+              boundaryCond = ((posCenter.x + offsetX1) < pcv.lumaWidth) && ((posCenter.y + offsetY1) < pcv.lumaHeight);
+            }
+            if (boundaryCond)
+            {
+              int posYInCtu = posCenter.y & pcv.maxCUHeightMask;
+              if (posYInCtu + offsetY1 < pcv.maxCUHeight)
+              {
+                posC1 = posCenter.offset(offsetX1, offsetY1);
+                isC1Avail = true;
+              }
+            }
+          }
+          else
+          {
+            isC1Avail = false;
+            if (curSubPic.getTreatedAsPicFlag())
+            {
+              boundaryCond = ((posRB.x + offsetX1) <= curSubPic.getSubPicRight() && (posRB.y + offsetY1) <= curSubPic.getSubPicBottom());
+            }
+            else
+            {
+              boundaryCond = ((posRB.x + offsetX1) < pcv.lumaWidth) && ((posRB.y + offsetY1) < pcv.lumaHeight);
+            }
+            if (boundaryCond)
+            {
+              int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+              if (posYInCtu + offsetY1 < pcv.maxCUHeight)
+              {
+                posC1 = posRB.offset(offsetX1, offsetY1);
+                isC1Avail = true;
+              }
+            }
+          }
+
+          bExistMV0 = bExistMV1 = false;
+
+          // Candidate with L0 and L1
+          dir = 0;
+          int refIdx[NUM_REF_PIC_LIST_01] = { 0, 0 };
+          bExistMV0 = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv0, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            1,
+#endif
+            &refIdx[REF_PIC_LIST_0]))
+            || (isC1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv0, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              1,
+#endif
+              &refIdx[REF_PIC_LIST_0]));
+
+          if (bExistMV0)
+          {
+            dir |= 1;
+            mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, refIdx[REF_PIC_LIST_0]);
+          }
+          else
+          {
+            mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(Mv(), NOT_VALID);
+          }
+          if (slice.isInterB())
+          {
+            bExistMV1 = (isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv1, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              1,
+#endif
+              &refIdx[REF_PIC_LIST_1]))
+              || (isC1Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv1, iRefIdx, false,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                1,
+#endif
+                &refIdx[REF_PIC_LIST_1]));
+
+            if (bExistMV1)
+            {
+              dir |= 2;
+              mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, refIdx[REF_PIC_LIST_1]);
+            }
+            else
+            {
+              mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(Mv(), NOT_VALID);
+            }
+          }
+          if (dir != 0)
           {
             mrgCtx.interDirNeighbours[cnt] = dir;
+            mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+            mrgCtx.LICFlags[cnt] = false;
+#endif
             mrgCtx.useAltHpelIf[cnt] = false;
 #if MULTI_HYP_PRED
             mrgCtx.addHypNeighbours[cnt].clear();
 #endif
-            if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod
-            ))
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+            if (!mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+              , mvdSimilarityThresh
+#endif
+            ))
+            {
+#endif
+              cnt++;
+              if (cnt == (maxNumMergeCand + 1))
+              {
+                break;
+              }
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+            }
+#endif
+          }
+
+          if (!slice.getCheckLDC() && bExistMV0 && bExistMV1)
+          {
+            // Candidate without L1
+            dir = 0;
+            dir |= 1;
+            mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, refIdx[REF_PIC_LIST_0]);
+            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(Mv(), NOT_VALID);
+            if (dir != 0)
+            {
+              mrgCtx.interDirNeighbours[cnt] = dir;
+              mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+              mrgCtx.LICFlags[cnt] = false;
+#endif
+              mrgCtx.useAltHpelIf[cnt] = false;
+#if MULTI_HYP_PRED
+              mrgCtx.addHypNeighbours[cnt].clear();
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+              if (!mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                , mvdSimilarityThresh
+#endif
+              ))
+              {
+#endif
+                cnt++;
+                if (cnt == (maxNumMergeCand + 1)) break;
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+              }
+#endif
+            }
+
+            // Candidate without L0
+            dir = 0;
+            mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(Mv(), NOT_VALID);
+            dir |= 2;
+            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, refIdx[REF_PIC_LIST_1]);
+            if (dir != 0)
             {
-              cnt++;
-              if (cnt == maxNumMergeCand)
+              mrgCtx.interDirNeighbours[cnt] = dir;
+              mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
+#if INTER_LIC
+              mrgCtx.LICFlags[cnt] = false;
+#endif
+              mrgCtx.useAltHpelIf[cnt] = false;
+#if MULTI_HYP_PRED
+              mrgCtx.addHypNeighbours[cnt].clear();
+#endif
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+              if (!mrgCtx.xCheckSimilarMotion(cnt
+#if TM_MRG
+                , mvdSimilarityThresh
+#endif
+              ))
               {
-                break;
+#endif
+                cnt++;
+                if (cnt == (maxNumMergeCand + 1))
+                {
+                  break;
+                }
+#if NON_ADJACENT_MRG_CAND || TM_MRG
               }
+#endif
             }
           }
         }
       }
     }
-}
+#endif
+  }
 
   mrgCtx.numValidMergeCand = cnt;
 }
 #endif
 
-#if NON_ADJACENT_MRG_CAND && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-void PU::getNonAdjacentBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM && NON_ADJACENT_MRG_CAND
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+void PU::getNonAdjacentMergeCandSubTMVP(const PredictionUnit &pu, MergeCtx& mrgCtx, int col)
 {
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-  if (!pu.cs->sps->getUseTmvpNmvpReordering())
-  {
-    mrgCtx.numValidMergeCand = 0;
-    return;
-  }
-#endif
   const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
   const CodingStructure &cs = *pu.cs;
+  const Slice &slice = *pu.cs->slice;
 
-  const uint32_t mvThreshod = getBDMVRMvdThreshold(pu);
-
+  const uint32_t mvdSimilarityThresh = SUB_TMVP_MV_THRESHOLD;
   const uint32_t maxNumMergeCand = NUM_NON_ADJ_CANDS;
 
+  const Picture *pColPic = slice.getRefPic(RefPicList(col == 0 ? 1 - slice.getColFromL0Flag() : 1 - slice.getColFromL0Flag2nd()), col == 0 ? slice.getColRefIdx() : slice.getColRefIdx2nd());
+
   for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
   {
     mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
@@ -7502,7 +8725,7 @@ void PU::getNonAdjacentBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
   int offsetX0 = 0; int offsetX1 = 0; int offsetX2 = pu.Y().width >> 1;
   int offsetY0 = 0; int offsetY1 = 0; int offsetY2 = pu.Y().height >> 1;
 
-  const int iNACANDIDATE_NUM[7] = { 5, 9, 9, 9, 9, 9, 9 };
+  const int numNACandidate[7] = { 5, 9, 9, 9, 9, 9, 9 };
   const int idxMap[7][9] = { { 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 } };
 
   for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
@@ -7510,7 +8733,7 @@ void PU::getNonAdjacentBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
     const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
+    for (int NASPIdx = 0; NASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
     {
       switch (idxMap[iDistanceIndex][NASPIdx])
       {
@@ -7528,362 +8751,114 @@ void PU::getNonAdjacentBMCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
 
       const PredictionUnit *puNonAdjacent = cs.getPURestricted(posLT.offset(offsetX, offsetY), pu, pu.chType);
 
-#if JVET_Y0065_GPM_INTRA
-      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu) && puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY)).isInter;
-#else
-      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu);
-#endif
-
-      if (isAvailableNonAdjacent)
-      {
-        miNeighbor = puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY));
-
-        if (isBiPredFromDifferentDirEqDistPoc(pu, miNeighbor.refIdx[0], miNeighbor.refIdx[1])
-          )
-        {
-          // get Inter Dir
-          mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
-          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
-          mrgCtx.useAltHpelIf[cnt] = miNeighbor.useAltHpelIf;
-          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
-
-          if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-          {
-            cnt++;
-          }
-        }
-      }
-    }
-  }
-
-  const int iNACANDIDATE_NUM2[7] = { 4, 4, 4, 4, 4, 4, 4 };
-  const int idxMap2[7][5] = { { 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 } };
-
-  for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
-  {
-    const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
-    const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
-
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM2[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
-    {
-      switch (idxMap2[iDistanceIndex][NASPIdx])
-      {
-      case 0:offsetX = offsetX0 = -iNADistanceHor - 1;                                                         offsetY = offsetY2 + ((pu.Y().height + iNADistanceVer - 1 - offsetY2) >> 1); break;
-      case 1:offsetX = offsetX2 + ((pu.Y().width + iNADistanceHor - 1 - offsetX2) >> 1);                       offsetY = offsetY0 = -iNADistanceVer - 1; break;
-      case 2:offsetX = offsetX0;                                                                               offsetY = offsetY0 + ((offsetY2 - offsetY0) >> 1); break;
-      case 3:offsetX = offsetX0 + ((offsetX2 - offsetX0) >> 1);                                                offsetY = offsetY0; break;
-      default: printf("error!"); exit(0); break;
-      }
-
-      const PredictionUnit *puNonAdjacent = cs.getPURestricted(posLT.offset(offsetX, offsetY), pu, pu.chType);
-
-#if JVET_Y0065_GPM_INTRA
-      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu) && puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY)).isInter;
-#else
       bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu);
-#endif
 
       if (isAvailableNonAdjacent)
       {
         miNeighbor = puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY));
 
-        if (isBiPredFromDifferentDirEqDistPoc(pu, miNeighbor.refIdx[0], miNeighbor.refIdx[1])
-          )
-        {
-          // get Inter Dir
-          mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
-          // get Mv from Above-Left
-          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
-          mrgCtx.useAltHpelIf[cnt] = miNeighbor.useAltHpelIf;
-          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
-
-          if (!mrgCtx.xCheckSimilarMotion(cnt, mvThreshod))
-          {
-            cnt++;
-          }
-        }
-      }
-    }
-  }
-
-  mrgCtx.numValidMergeCand = cnt;
-}
-#endif
-
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-void PU::getTmvpMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
-{
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-  if (!pu.cs->sps->getUseTmvpNmvpReordering())
-  {
-    mrgCtx.numValidMergeCand = 0;
-    return;
-  }
-#endif
-  const CodingStructure &cs = *pu.cs;
-  const Slice &slice = *pu.cs->slice;
-
-#if TM_MRG
-  const uint32_t mvdSimilarityThresh = 1;
-#endif
-#if TM_MRG && JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
-  const uint32_t maxNumMergeCand =
-#if JVET_AA0132_CONFIGURABLE_TM_TOOLS
-                                   pu.cs->sps->getUseTMMrgMode() &&
-#endif
-                                   pu.tmMergeFlag ? 1 :NUM_TMVP_CANDS;
-#else
-  const uint32_t maxNumMergeCand = NUM_TMVP_CANDS;
-#endif
-  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
-  {
-    mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
-#if INTER_LIC
-    mrgCtx.LICFlags[ui] = false;
-#endif
-    mrgCtx.interDirNeighbours[ui] = 0;
-    mrgCtx.mvFieldNeighbours[(ui << 1)].refIdx = NOT_VALID;
-    mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
-    mrgCtx.useAltHpelIf[ui] = false;
-#if MULTI_HYP_PRED
-    mrgCtx.addHypNeighbours[ui].clear();
-#endif
-    mrgCtx.candCost[ui] = MAX_UINT64;
-  }
-
-  int cnt = 0;
-
-#if INTER_RM_SIZE_CONSTRAINTS
-  if (slice.getPicHeader()->getEnableTMVPFlag())
-#else
-  if (slice.getPicHeader()->getEnableTMVPFlag() && (pu.lumaSize().width + pu.lumaSize().height > 12))
-#endif
-  {
-    //>> MTK colocated-RightBottom
-    // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
-    const PreCalcValues& pcv = *cs.pcv;
-    bool C0Avail;
-    bool C1Avail;
-    bool boundaryCond;
-    const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
-    Position posRB = pu.Y().bottomRight().offset(-3, -3);
-    Position posCenter = pu.Y().center();
-    Position posC0;
-    Position posC1;
-
-    int       iRefIdx = 0;
-    bool      bExistMV0, bExistMV1;
-    Mv        cColMv0, cColMv1;
-    int       dir;
-
-    int offsetX0 = 0, offsetX1 = 0, offsetX2 = 0, offsetX3 = pu.Y().width >> 1;
-    int offsetY0 = 0, offsetY1 = 0, offsetY2 = 0, offsetY3 = pu.Y().height >> 1;
-
-    const int iNACANDIDATE_NUM[5] = { 2, 2, 2, 2, 2 };
-    const int idxMap[5][2] = { { 0, 1 },{ 0, 2 },{ 0, 2 },{ 0, 2 },{ 0, 2 } };
-    for (int iDistanceIndex = 0; iDistanceIndex < TMVP_DISTANCE_LEVEL && cnt < maxNumMergeCand; iDistanceIndex++)
-    {
-      const int iNADistanceHor = pu.Y().width  * iDistanceIndex;
-      const int iNADistanceVer = pu.Y().height * iDistanceIndex;
-
-      for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
-      {
-        switch (idxMap[iDistanceIndex][NASPIdx])
-        {
-        case 0: offsetX0 = offsetX2 = 4 + iNADistanceHor; offsetY0 = offsetY2 = 4 + iNADistanceVer; offsetX1 = iNADistanceHor; offsetY1 = iNADistanceVer; break;
-        case 1: offsetX0 = 4; offsetY0 = 0; offsetX1 = 0; offsetY1 = 4; break;
-        case 2: offsetX0 = offsetX2; offsetY0 = 4 - offsetY3; offsetX1 = 4 - offsetX3; offsetY1 = offsetY2; break;
-        default: printf("error!"); exit(0); break;
-        }
-        C0Avail = false;
-        if (curSubPic.getTreatedAsPicFlag())
-        {
-          boundaryCond = ((posRB.x + offsetX0) <= curSubPic.getSubPicRight() && (posRB.y + offsetY0) <= curSubPic.getSubPicBottom());
-        }
-        else
-        {
-          boundaryCond = ((posRB.x + offsetX0) < pcv.lumaWidth) && ((posRB.y + offsetY0) < pcv.lumaHeight);
-        }
-        if (boundaryCond)
-        {
-          int posYInCtu = posRB.y & pcv.maxCUHeightMask;
-          if (posYInCtu + offsetY0 < pcv.maxCUHeight)
-          {
-            posC0 = posRB.offset(offsetX0, offsetY0);
-            C0Avail = true;
-          }
-        }
-
-        if (idxMap[iDistanceIndex][NASPIdx] == 0)
-        {
-          C1Avail = false;
-          if (curSubPic.getTreatedAsPicFlag())
-          {
-            boundaryCond = ((posCenter.x + offsetX1) <= curSubPic.getSubPicRight() && (posCenter.y + offsetY1) <= curSubPic.getSubPicBottom());
-          }
-          else
-          {
-            boundaryCond = ((posCenter.x + offsetX1) < pcv.lumaWidth) && ((posCenter.y + offsetY1) < pcv.lumaHeight);
-          }
-          if (boundaryCond)
-          {
-            int posYInCtu = posCenter.y & pcv.maxCUHeightMask;
-            if (posYInCtu + offsetY1 < pcv.maxCUHeight)
-            {
-              posC1 = posCenter.offset(offsetX1, offsetY1);
-              C1Avail = true;
-            }
-          }
-        }
-        else
-        {
-          C1Avail = false;
-          if (curSubPic.getTreatedAsPicFlag())
-          {
-            boundaryCond = ((posRB.x + offsetX1) <= curSubPic.getSubPicRight() && (posRB.y + offsetY1) <= curSubPic.getSubPicBottom());
-          }
-          else
-          {
-            boundaryCond = ((posRB.x + offsetX1) < pcv.lumaWidth) && ((posRB.y + offsetY1) < pcv.lumaHeight);
-          }
-          if (boundaryCond)
-          {
-            int posYInCtu = posRB.y & pcv.maxCUHeightMask;
-            if (posYInCtu + offsetY1 < pcv.maxCUHeight)
-            {
-              posC1 = posRB.offset(offsetX1, offsetY1);
-              C1Avail = true;
-            }
-          }
-        }
-
-        bExistMV0 = bExistMV1 = false;
-
-        // Candidate with L0 and L1
-        dir = 0;
-        int refIdx[NUM_REF_PIC_LIST_01] = { 0, 0 };
-        bExistMV0 = (C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv0, iRefIdx, false, &refIdx[REF_PIC_LIST_0]))
-          || (C1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv0, iRefIdx, false, &refIdx[REF_PIC_LIST_0]));
-
-        if (bExistMV0)
+        int index = 0;
+        if ((miNeighbor.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miNeighbor.refIdx[0]) == pColPic)
         {
-          dir |= 1;
-          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, refIdx[REF_PIC_LIST_0]);
+          index = 1;
         }
-        else
+        else if (slice.isInterB() && (miNeighbor.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miNeighbor.refIdx[1]) == pColPic)
         {
-          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(Mv(), NOT_VALID);
+          index = 2;
         }
-        if (slice.isInterB())
+        if (index > 0)
         {
-          bExistMV1 = (C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv1, iRefIdx, false, &refIdx[REF_PIC_LIST_1]))
-            || (C1Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv1, iRefIdx, false, &refIdx[REF_PIC_LIST_1]));
-
-          if (bExistMV1)
+          // get Inter Dir
+          mrgCtx.interDirNeighbours[cnt] = index;
+          miNeighbor.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+          if (index == 1)
           {
-            dir |= 2;
-            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, refIdx[REF_PIC_LIST_1]);
+            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[index - 1], miNeighbor.refIdx[index - 1]);
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
           }
           else
           {
-            mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(Mv(), NOT_VALID);
+            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[index - 1], miNeighbor.refIdx[index - 1]);
           }
-        }
-        if (dir != 0)
-        {
-          mrgCtx.interDirNeighbours[cnt] = dir;
-          mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
-#if INTER_LIC
-          mrgCtx.LICFlags[cnt] = false;
-#endif
-          mrgCtx.useAltHpelIf[cnt] = false;
-#if MULTI_HYP_PRED
-          mrgCtx.addHypNeighbours[cnt].clear();
-#endif
+
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-          if (!mrgCtx.xCheckSimilarMotion(cnt
+          if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
 #if TM_MRG
             , mvdSimilarityThresh
 #endif
           ))
-          {
 #endif
+          {
             cnt++;
-            if (cnt == maxNumMergeCand)
-            {
-              break;
-            }
-#if NON_ADJACENT_MRG_CAND || TM_MRG
           }
-#endif
         }
+      }
 
-        if (!slice.getCheckLDC() && bExistMV0 && bExistMV1)
+    }
+  }
+
+  const int numNACandidate2[7] = { 4, 4, 4, 4, 4, 4, 4 };
+  const int idxMap2[7][5] = { { 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 } };
+
+  for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
+  {
+    const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
+    const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
+
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate2[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
+    {
+      switch (idxMap2[iDistanceIndex][iNASPIdx])
+      {
+      case 0:offsetX = offsetX0 = -iNADistanceHor - 1;                                                         offsetY = offsetY2 + ((pu.Y().height + iNADistanceVer - 1 - offsetY2) >> 1); break;
+      case 1:offsetX = offsetX2 + ((pu.Y().width + iNADistanceHor - 1 - offsetX2) >> 1);                       offsetY = offsetY0 = -iNADistanceVer - 1; break;
+      case 2:offsetX = offsetX0;                                                                               offsetY = offsetY0 + ((offsetY2 - offsetY0) >> 1); break;
+      case 3:offsetX = offsetX0 + ((offsetX2 - offsetX0) >> 1);                                                offsetY = offsetY0; break;
+      default: printf("error!"); exit(0); break;
+      }
+
+      const PredictionUnit *puNonAdjacent = cs.getPURestricted(posLT.offset(offsetX, offsetY), pu, pu.chType);
+
+      bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), posLT.offset(offsetX, offsetY), plevel) && CU::isInter(*puNonAdjacent->cu);
+
+      if (isAvailableNonAdjacent)
+      {
+        miNeighbor = puNonAdjacent->getMotionInfo(posLT.offset(offsetX, offsetY));
+
+        int index = 0;
+        if ((miNeighbor.interDir & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, miNeighbor.refIdx[0]) == pColPic)
         {
-          // Candidate without L1
-          dir = 0;
-          dir |= 1;
-          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(cColMv0, refIdx[REF_PIC_LIST_0]);
-          mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(Mv(), NOT_VALID);
-          if (dir != 0)
+          index = 1;
+        }
+        else if (slice.isInterB() && (miNeighbor.interDir & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, miNeighbor.refIdx[1]) == pColPic)
+        {
+          index = 2;
+        }
+        if (index > 0)
+        {
+          // get Inter Dir
+          mrgCtx.interDirNeighbours[cnt] = index;
+          miNeighbor.mv[index - 1].roundToPrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+          if (index == 1)
           {
-            mrgCtx.interDirNeighbours[cnt] = dir;
-            mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
-#if INTER_LIC
-            mrgCtx.LICFlags[cnt] = false;
-#endif
-            mrgCtx.useAltHpelIf[cnt] = false;
-#if MULTI_HYP_PRED
-            mrgCtx.addHypNeighbours[cnt].clear();
-#endif
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-            if (!mrgCtx.xCheckSimilarMotion(cnt
-#if TM_MRG
-              , mvdSimilarityThresh
-#endif
-            ))
-            {
-#endif
-              cnt++;
-              if (cnt == maxNumMergeCand) break;
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-            }
-#endif
+            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[index - 1], miNeighbor.refIdx[index - 1]);
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(Mv(), NOT_VALID);
           }
-
-          // Candidate without L0
-          dir = 0;
-          mrgCtx.mvFieldNeighbours[2 * cnt].setMvField(Mv(), NOT_VALID);
-          dir |= 2;
-          mrgCtx.mvFieldNeighbours[2 * cnt + 1].setMvField(cColMv1, refIdx[REF_PIC_LIST_1]);
-          if (dir != 0)
+          else
           {
-            mrgCtx.interDirNeighbours[cnt] = dir;
-            mrgCtx.BcwIdx[cnt] = BCW_DEFAULT;
-#if INTER_LIC
-            mrgCtx.LICFlags[cnt] = false;
-#endif
-            mrgCtx.useAltHpelIf[cnt] = false;
-#if MULTI_HYP_PRED
-            mrgCtx.addHypNeighbours[cnt].clear();
-#endif
+            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(Mv(), NOT_VALID);
+            mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[index - 1], miNeighbor.refIdx[index - 1]);
+          }
+        }
 #if NON_ADJACENT_MRG_CAND || TM_MRG
-            if (!mrgCtx.xCheckSimilarMotion(cnt
+        if (!mrgCtx.xCheckSimilarMotionSubTMVP(cnt
 #if TM_MRG
-              , mvdSimilarityThresh
-#endif
-            ))
-            {
+          , mvdSimilarityThresh
 #endif
-              cnt++;
-              if (cnt == maxNumMergeCand)
-              {
-                break;
-              }
-#if NON_ADJACENT_MRG_CAND || TM_MRG
-            }
+        ))
 #endif
-          }
+        {
+          cnt++;
         }
       }
     }
@@ -7892,8 +8867,6 @@ void PU::getTmvpMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
   mrgCtx.numValidMergeCand = cnt;
 }
 #endif
-
-#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM && NON_ADJACENT_MRG_CAND
 void PU::getNonAdjacentMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
 {
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS
@@ -7951,7 +8924,7 @@ void PU::getNonAdjacentMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
   int offsetX0 = 0; int offsetX1 = 0; int offsetX2 = pu.Y().width >> 1;
   int offsetY0 = 0; int offsetY1 = 0; int offsetY2 = pu.Y().height >> 1;
 
-  const int iNACANDIDATE_NUM[7] = { 5, 9, 9, 9, 9, 9, 9 };
+  const int numNACandidate[7] = { 5, 9, 9, 9, 9, 9, 9 };
   const int idxMap[7][9] = { { 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 },{ 0, 1, 2, 3, 4, 5, 6, 7, 8 } };
 
   for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
@@ -7959,9 +8932,9 @@ void PU::getNonAdjacentMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
     const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
     {
-      switch (idxMap[iDistanceIndex][NASPIdx])
+      switch (idxMap[iDistanceIndex][iNASPIdx])
       {
       case 0:offsetX = offsetX0 = -iNADistanceHor - 1;               offsetY = offsetY0 = pu.Y().height + iNADistanceVer - 1; break;
       case 1:offsetX = offsetX1 = pu.Y().width + iNADistanceHor - 1; offsetY = offsetY1 = -iNADistanceVer - 1;                break;
@@ -8020,7 +8993,7 @@ void PU::getNonAdjacentMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     }
   }
 
-  const int iNACANDIDATE_NUM2[7] = { 4, 4, 4, 4, 4, 4, 4 };
+  const int numNACandidate2[7] = { 4, 4, 4, 4, 4, 4, 4 };
   const int idxMap2[7][5] = { { 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 },{ 0, 1, 2, 3 } };
 
   for (int iDistanceIndex = 0; iDistanceIndex < 7 && cnt < maxNumMergeCand; iDistanceIndex++)
@@ -8028,9 +9001,9 @@ void PU::getNonAdjacentMergeCand(const PredictionUnit &pu, MergeCtx& mrgCtx)
     const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
     const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-    for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM2[iDistanceIndex] && cnt < maxNumMergeCand; NASPIdx++)
+    for (int iNASPIdx = 0; iNASPIdx < numNACandidate2[iDistanceIndex] && cnt < maxNumMergeCand; iNASPIdx++)
     {
-      switch (idxMap2[iDistanceIndex][NASPIdx])
+      switch (idxMap2[iDistanceIndex][iNASPIdx])
       {
       case 0:offsetX = offsetX0 = -iNADistanceHor - 1;                                                         offsetY = offsetY2 + ((pu.Y().height + iNADistanceVer - 1 - offsetY2) >> 1); break;
       case 1:offsetX = offsetX2 + ((pu.Y().width + iNADistanceHor - 1 - offsetX2) >> 1);                       offsetY = offsetY0 = -iNADistanceVer - 1; break;
@@ -8361,6 +9334,9 @@ void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx,
 }
 bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &_pos, Mv& rcMv, const int &refIdx, bool sbFlag
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  , int col
+#endif
   , int* targetRefIdx
 #endif
 )
@@ -8374,7 +9350,11 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList
   const Slice &slice = *pu.cs->slice;
 
   // use coldir.
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  const Picture* const pColPic = slice.getRefPic(RefPicList(col == 0 ? 1 - slice.getColFromL0Flag() : 1 - slice.getColFromL0Flag2nd()), col == 0 ? slice.getColRefIdx() : slice.getColRefIdx2nd());
+#else
   const Picture* const pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx());
+#endif
 
   if( !pColPic )
   {
@@ -8390,7 +9370,13 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList
       return false;
     }
   }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  int pocCur = slice.getPOC();
+  int pocCol = pColPic->getPOC();
+  RefPicList eColRefPicList = slice.getCheckLDC() ? eRefPicList : RefPicList(pocCur > pocCol);
+#else
   RefPicList eColRefPicList = slice.getCheckLDC() ? eRefPicList : RefPicList(slice.getColFromL0Flag());
+#endif
 
   const MotionInfo& mi = pColPic->cs->getMotionInfo( pos );
 
@@ -8448,7 +9434,11 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
   if (targetRefIdx != nullptr)
   {
-    *targetRefIdx = slice.getImRefIdx(mi.sliceIdx, eColRefPicList, eRefPicList, iColRefIdx);
+    *targetRefIdx = slice.getImRefIdx(mi.sliceIdx, eColRefPicList, eRefPicList, iColRefIdx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      , col
+#endif
+    );
     if (*targetRefIdx == -1)
     {
       return false;
@@ -8888,24 +9878,227 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
 
       if( !bAdded )
       {
-        addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo );
+        addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo );
+      }
+    }
+  }
+
+  for( int i = 0; i < pInfo->numCand; i++ )
+  {
+    pInfo->mvCand[i].roundTransPrecInternal2Amvr(pu.cu->imv);
+  }
+
+  if( pInfo->numCand == 2 )
+  {
+    if( pInfo->mvCand[0] == pInfo->mvCand[1] )
+    {
+      pInfo->numCand = 1;
+    }
+  }
+
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+#if TM_AMVP
+  if (cs.picHeader->getEnableTMVPFlag() && pInfo->numCand < pInfo->maxStorageSize && (pu.lumaSize().width + pu.lumaSize().height > 8))
+#else
+  if (cs.picHeader->getEnableTMVPFlag() && pInfo->numCand < AMVP_MAX_NUM_CANDS && (pu.lumaSize().width + pu.lumaSize().height > 8))
+#endif
+  {
+    MergeCtx mrgCtxAll[2];
+    MergeCtx MrgTmvp[2];
+    MergeCtx namvpMergeCandCtx[2];
+    bool isSaved = true;
+    if (pu.cs->sps->getUseAML() && interPred != NULL)
+    {
+      int nWidth = pu.lumaSize().width;
+      int nHeight = pu.lumaSize().height;
+      bool tplAvail = interPred->xAMLGetCurBlkTemplate(pu, nWidth, nHeight);
+      if (tplAvail)
+      {
+        int poc0 = pu.cu->slice->getRefPic(RefPicList(1 - pu.cu->slice->getColFromL0Flag()), pu.cu->slice->getColRefIdx())->getPOC();
+        int poc1 = pu.cu->slice->getRefPic(RefPicList(1 - pu.cu->slice->getColFromL0Flag2nd()), pu.cu->slice->getColRefIdx2nd())->getPOC();
+        for (int col = 0; col < ((pu.cu->slice->getCheckLDC() || (poc0 == poc1)) ? 1 : 2); col++)
+        {
+          if (col == 0 || (!pu.cs->sps->getUseFastSubTmvp()))
+          {
+#if JVET_Z0054_BLK_REF_PIC_REORDER
+            if (!interPred->readMergeBuffer(mrgCtxAll[0], mrgCtxAll[1], *pu.cu))
+#else
+            if (cs.pcv->isEncoder && interPred->readMergeBuffer(mrgCtxAll[0], mrgCtxAll[1], *pu.cu))
+#endif
+            {
+              PU::getNonAdjacentMergeCandSubTMVP(pu, namvpMergeCandCtx[col], col);
+              interPred->adjustMergeCandidatesInOneCandidateGroup(pu, namvpMergeCandCtx[col], 9);
+              PU::getInterMergeCandidatesSubTMVP(pu, mrgCtxAll[col], col, -1, &namvpMergeCandCtx[col]);
+              isSaved = false;
+            }
+
+            PU::getTMVPCandOpt(pu, eRefPicList, refIdx, MrgTmvp[col], mrgCtxAll[col], col);
+            interPred->adjustMergeCandidatesInOneCandidateGroup(pu, MrgTmvp[col], AMVP_TMVP_INDEX);
+            if (MrgTmvp[col].numValidMergeCand > 0)
+            {
+              Mv mvTmp = MrgTmvp[col].mvFieldNeighbours[eRefPicList].mv;
+              mvTmp.roundTransPrecInternal2Amvr(pu.cu->imv);
+#if TM_AMVP
+              pInfo->mvCand[pInfo->numCand] = mvTmp;
+              if (!pInfo->xCheckSimilarMotion(pInfo->numCand))
+              {
+                pInfo->numCand++;
+              }
+#else
+              pInfo->mvCand[pInfo->numCand++] = cColMv;
+#endif
+            }
+          }
+          else
+          {
+            // Get Temporal Motion Predictor
+            const int refIdxCol = refIdx;
+
+            Position posRB = pu.Y().bottomRight().offset(-3, -3);
+
+            const PreCalcValues& pcv = *cs.pcv;
+
+            Position posC0;
+            bool isC0Avail = false;
+            Position posC1 = pu.Y().center();
+            Mv cColMv;
+
+            bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+            const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+            if (curSubPic.getTreatedAsPicFlag())
+            {
+              boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+                (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+            }
+            if (boundaryCond)
+            {
+              int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+              if (posYInCtu + 4 < pcv.maxCUHeight)
+              {
+                posC0 = posRB.offset(4, 4);
+                isC0Avail = true;
+              }
+            }
+            for (int colIdx = 1; colIdx < (pu.cu->slice->isInterB() ? 2 : 1); colIdx++)
+            {
+              if ((isC0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdxCol, false, colIdx)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdxCol, false, colIdx))
+              {
+                cColMv.roundTransPrecInternal2Amvr(pu.cu->imv);
+#if TM_AMVP
+                pInfo->mvCand[pInfo->numCand] = cColMv;
+                if (!pInfo->xCheckSimilarMotion(pInfo->numCand))
+                {
+                  pInfo->numCand++;
+                }
+#else
+                pInfo->mvCand[pInfo->numCand++] = cColMv;
+#endif
+              }
+            }
+          }
+        }
+      }
+      else
+      {
+        // Get Temporal Motion Predictor
+        const int refIdxCol = refIdx;
+
+        Position posRB = pu.Y().bottomRight().offset(-3, -3);
+
+        const PreCalcValues& pcv = *cs.pcv;
+
+        Position posC0;
+        bool isC0Avail = false;
+        Position posC1 = pu.Y().center();
+        Mv cColMv;
+
+        bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+        const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+        if (curSubPic.getTreatedAsPicFlag())
+        {
+          boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+            (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+        }
+        if (boundaryCond)
+        {
+          int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+          if (posYInCtu + 4 < pcv.maxCUHeight)
+          {
+            posC0 = posRB.offset(4, 4);
+            isC0Avail = true;
+          }
+        }
+        for (int colIdx = 0; colIdx < (pu.cu->slice->isInterB() ? 2 : 1); colIdx++)
+        {
+          if ((isC0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdxCol, false, colIdx)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdxCol, false, colIdx))
+          {
+            cColMv.roundTransPrecInternal2Amvr(pu.cu->imv);
+#if TM_AMVP
+            pInfo->mvCand[pInfo->numCand] = cColMv;
+            if (!pInfo->xCheckSimilarMotion(pInfo->numCand))
+            {
+              pInfo->numCand++;
+            }
+#else
+            pInfo->mvCand[pInfo->numCand++] = cColMv;
+#endif
+          }
+        }
+      }
+    }
+    else
+    {
+      // Get Temporal Motion Predictor
+      const int refIdxCol = refIdx;
+
+      Position posRB = pu.Y().bottomRight().offset(-3, -3);
+
+      const PreCalcValues& pcv = *cs.pcv;
+
+      Position posC0;
+      bool isC0Avail = false;
+      Position posC1 = pu.Y().center();
+      Mv cColMv;
+
+      bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+      const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+      if (curSubPic.getTreatedAsPicFlag())
+      {
+        boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+          (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+      }
+      if (boundaryCond)
+      {
+        int posYInCtu = posRB.y & pcv.maxCUHeightMask;
+        if (posYInCtu + 4 < pcv.maxCUHeight)
+        {
+          posC0 = posRB.offset(4, 4);
+          isC0Avail = true;
+        }
+      }
+      for (int colIdx = 0; colIdx < (pu.cu->slice->isInterB() ? 2 : 1); colIdx++)
+      {
+        if ((isC0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdxCol, false, colIdx)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdxCol, false, colIdx))
+        {
+          cColMv.roundTransPrecInternal2Amvr(pu.cu->imv);
+#if TM_AMVP
+          pInfo->mvCand[pInfo->numCand] = cColMv;
+          if (!pInfo->xCheckSimilarMotion(pInfo->numCand))
+          {
+            pInfo->numCand++;
+          }
+#else
+          pInfo->mvCand[pInfo->numCand++] = cColMv;
+#endif
+        }
       }
     }
-  }
-
-  for( int i = 0; i < pInfo->numCand; i++ )
-  {
-    pInfo->mvCand[i].roundTransPrecInternal2Amvr(pu.cu->imv);
-  }
-
-  if( pInfo->numCand == 2 )
-  {
-    if( pInfo->mvCand[0] == pInfo->mvCand[1] )
+    if (!isSaved)
     {
-      pInfo->numCand = 1;
+      interPred->writeMergeBuffer(mrgCtxAll[0], mrgCtxAll[1], *pu.cu);
     }
   }
-
+#else
 #if TM_AMVP
   if (cs.picHeader->getEnableTMVPFlag() && pInfo->numCand < pInfo->maxStorageSize && (pu.lumaSize().width + pu.lumaSize().height > 12))
 #else
@@ -8913,14 +10106,14 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
 #endif
   {
     // Get Temporal Motion Predictor
-    const int refIdx_Col = refIdx;
+    const int refIdxCol = refIdx;
 
     Position posRB = pu.Y().bottomRight().offset(-3, -3);
 
     const PreCalcValues& pcv = *cs.pcv;
 
     Position posC0;
-    bool C0Avail = false;
+    bool isC0Avail = false;
     Position posC1 = pu.Y().center();
     Mv cColMv;
 
@@ -8929,7 +10122,7 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
     if (curSubPic.getTreatedAsPicFlag())
     {
       boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
-                      (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+        (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
     }
     if (boundaryCond)
     {
@@ -8937,23 +10130,51 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
       if (posYInCtu + 4 < pcv.maxCUHeight)
       {
         posC0 = posRB.offset(4, 4);
-        C0Avail = true;
+        isC0Avail = true;
       }
     }
-    if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdx_Col, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdx_Col, false ) )
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+#if !ENABLE_INTER_TEMPLATE_MATCHING
+    int count = 0;
+#endif
+    for (int colIdx = 0; colIdx < (pu.cu->slice->isInterB() ? 2 : 1); colIdx++)
     {
-      cColMv.roundTransPrecInternal2Amvr(pu.cu->imv);
-#if TM_AMVP
-      pInfo->mvCand[pInfo->numCand] = cColMv;
-      if (!pInfo->xCheckSimilarMotion(pInfo->numCand))
+#endif
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      if (count)
       {
-        pInfo->numCand++;
+        break;
       }
+#endif
+      if ((isC0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdxCol, false
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , colIdx
+#endif
+      )) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdxCol, false
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , colIdx
+#endif
+      ))
+      {
+#if !ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        count++;
+#endif
+        cColMv.roundTransPrecInternal2Amvr(pu.cu->imv);
+#if TM_AMVP
+        pInfo->mvCand[pInfo->numCand] = cColMv;
+        if (!pInfo->xCheckSimilarMotion(pInfo->numCand))
+        {
+          pInfo->numCand++;
+        }
 #else
-      pInfo->mvCand[pInfo->numCand++] = cColMv;
+        pInfo->mvCand[pInfo->numCand++] = cColMv;
 #endif
+      }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
     }
+#endif
   }
+#endif
 
 #if TM_AMVP
   // Non-adjacent candidates
@@ -8963,7 +10184,7 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
     MotionInfo miNeighbor;
     int offsetX = 0;
     int offsetY = 0;
-    const int iNACANDIDATE_NUM[4] = { 3, 5, 5, 5 };
+    const int numNACandidate[4] = { 3, 5, 5, 5 };
     const int idxMap[4][5] = { { 0, 1, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 },{ 0, 1, 2, 3, 4 } };
 
     for (int iDistanceIndex = 0; iDistanceIndex < NADISTANCE_LEVEL && pInfo->numCand < pInfo->maxStorageSize; iDistanceIndex++)
@@ -8971,9 +10192,9 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
       const int iNADistanceHor = pu.Y().width  * (iDistanceIndex + 1);
       const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1);
 
-      for (int NASPIdx = 0; NASPIdx < iNACANDIDATE_NUM[iDistanceIndex] && pInfo->numCand < pInfo->maxStorageSize; NASPIdx++)
+      for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex] && pInfo->numCand < pInfo->maxStorageSize; iNASPIdx++)
       {
-        switch (idxMap[iDistanceIndex][NASPIdx])
+        switch (idxMap[iDistanceIndex][iNASPIdx])
         {
         case 0: offsetX = -iNADistanceHor - 1;               offsetY = pu.Y().height + iNADistanceVer - 1; break;
         case 1: offsetX = pu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1;                break;
@@ -10512,17 +11733,17 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co
           bC0Avail = true;
         }
       }
-      if ( (bC0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdxCol, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdxCol, false ) )
-      {
-        cColMv.roundAffinePrecInternal2Amvr(pu.cu->imv);
-        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv;
-        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv;
-        affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv;
+        if ((bC0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdxCol, false)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdxCol, false))
+        {
+          cColMv.roundAffinePrecInternal2Amvr(pu.cu->imv);
+          affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv;
+          affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv;
+          affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv;
 #if JVET_Z0139_HIST_AFF
-        if (checkLastAffineAMVPCandRedundancy(pu, affiAMVPInfo))
+          if (checkLastAffineAMVPCandRedundancy(pu, affiAMVPInfo))
 #endif
-          affiAMVPInfo.numCand++;
-      }
+            affiAMVPInfo.numCand++;
+        }
     }
 
 #if JVET_Z0139_NA_AFF
@@ -10909,6 +12130,9 @@ void PU::getAffineControlPointCand(const PredictionUnit &pu, MotionInfo mi[4], b
     affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 1][i].mv = cMv[1][i];
     affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 1][i].refIdx = refIdx[1];
   }
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  affMrgType.colIdx[affMrgType.numValidMergeCand] = 0;
+#endif
   affMrgType.interDirNeighbours[affMrgType.numValidMergeCand] = dir;
   affMrgType.affineType[affMrgType.numValidMergeCand] = curType;
   affMrgType.BcwIdx[affMrgType.numValidMergeCand] = (dir == 3) ? bcwIdx : BCW_DEFAULT;
@@ -11833,6 +13057,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p
 }
 
 void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION   
+  MergeCtx mrgCtxIn[2],
+#endif
 #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION && JVET_W0090_ARMC_TM
   InterPrediction* m_pcInterSearch,
 #endif
@@ -11882,6 +13109,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION
     affMrgCtx.numAffCandToTestEnc = maxNumAffineMergeCand;
     affMrgCtx.candCost[i] = MAX_UINT64;
+#endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    affMrgCtx.colIdx[i] = 0;
 #endif
   }
 
@@ -11897,88 +13127,141 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
     bool tmpLICFlag = false;
 
 #if JVET_Z0139_NA_AFF && JVET_W0090_ARMC_TM
+#if !JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
     if (cs.pcv->isEncoder || isZeroCandIdx)
+#endif
     {
+#endif    
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+      for (int i = 0; i < SUB_TMVP_NUM; i++)
+      {
+        CHECK(mrgCtx.subPuMvpMiBuf[i].area() == 0 || !mrgCtx.subPuMvpMiBuf[i].buf, "Buffer not initialized");
+        mrgCtx.subPuMvpMiBuf[i].fill(MotionInfo());
+      }
+#else
+      CHECK(mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized");
+      mrgCtx.subPuMvpMiBuf.fill(MotionInfo());
 #endif
-    CHECK( mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized" );
-    mrgCtx.subPuMvpMiBuf.fill( MotionInfo() );
+
 #if JVET_Z0139_NA_AFF && JVET_W0090_ARMC_TM
     }
 #endif
 
     int pos = 0;
+#if !(JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION && ENABLE_INTER_TEMPLATE_MATCHING)
     // Get spatial MV
     const Position posCurLB = pu.Y().bottomLeft();
     MotionInfo miLeft;
 
     //left
-    const PredictionUnit* puLeft = cs.getPURestricted( posCurLB.offset( -1, 0 ), pu, pu.chType );
+    const PredictionUnit* puLeft = cs.getPURestricted(posCurLB.offset(-1, 0), pu, pu.chType);
 #if JVET_Y0065_GPM_INTRA
-    const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posCurLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu ) && puLeft->getMotionInfo( posCurLB.offset( -1, 0 ) ).isInter;
+    const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posCurLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu) && puLeft->getMotionInfo(posCurLB.offset(-1, 0)).isInter;
 #else
-    const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posCurLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
+    const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posCurLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
 #endif
-    if ( isAvailableA1 )
+    if (isAvailableA1)
     {
 #if INTER_LIC
       affMrgCtx.mrgCtx->LICFlags[pos] = false;
 #endif
 
-      miLeft = puLeft->getMotionInfo( posCurLB.offset( -1, 0 ) );
+      miLeft = puLeft->getMotionInfo(posCurLB.offset(-1, 0));
       // get Inter Dir
       mrgCtx.interDirNeighbours[pos] = miLeft.interDir;
 
       // get Mv from Left
-      mrgCtx.mvFieldNeighbours[pos << 1].setMvField( miLeft.mv[0], miLeft.refIdx[0] );
+      mrgCtx.mvFieldNeighbours[pos << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
 
-      if ( slice.isInterB() )
+      if (slice.isInterB())
       {
-        mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miLeft.mv[1], miLeft.refIdx[1] );
+        mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
       }
       pos++;
     }
 
     mrgCtx.numValidMergeCand = pos;
+#endif
 
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    int poc0 = pu.cu->slice->getRefPic(RefPicList(1 - pu.cu->slice->getColFromL0Flag()), pu.cu->slice->getColRefIdx())->getPOC();
+    int poc1 = pu.cu->slice->getRefPic(RefPicList(1 - pu.cu->slice->getColFromL0Flag2nd()), pu.cu->slice->getColRefIdx2nd())->getPOC();
+#if ENABLE_INTER_TEMPLATE_MATCHING
+    for (int index = 0; index < SUB_TMVP_INDEX; index++)
+    {
+#endif
+      for (int colFrameIdx = 0; colFrameIdx < ((pu.cu->slice->getCheckLDC() || (poc0 == poc1)) ? 1 : 2); colFrameIdx++)
+      {
+#endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+        if (index > 0 && colFrameIdx == 1)
+        {
+          continue;
+        }
+#endif
+#if !ENABLE_INTER_TEMPLATE_MATCHING
+        if (affMrgCtx.numValidMergeCand == 1)
+        {
+          break;
+        }
+#endif
 #if JVET_Z0139_NA_AFF && JVET_W0090_ARMC_TM
-    isAvailableSubPu = getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, pos, (!isZeroCandIdx && !cs.pcv->isEncoder) ? 1: 0);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+        isAvailableSubPu = getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, 0, index, mrgCtxIn[colFrameIdx], colFrameIdx);
 #else
-    isAvailableSubPu = getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, pos, 0);
+        isAvailableSubPu = getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, pos, (!isZeroCandIdx && !cs.pcv->isEncoder) ? 1 : 0);
 #endif
-    if ( isAvailableSubPu )
-    {
-      for ( int mvNum = 0; mvNum < 3; mvNum++ )
-      {
-        affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 0].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 0].refIdx );
-        affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 1].refIdx );
-      }
-      affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = mrgCtx.interDirNeighbours[pos];
+#else
+        isAvailableSubPu = getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, pos
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , colFrameIdx
+#else
+          , 0
+#endif         
+        );
+#endif
+        if (isAvailableSubPu)
+        {
+          for (int mvNum = 0; mvNum < 3; mvNum++)
+          {
+            affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField(mrgCtx.mvFieldNeighbours[(pos << 1) + 0].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 0].refIdx);
+            affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField(mrgCtx.mvFieldNeighbours[(pos << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 1].refIdx);
+          }
+          affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = mrgCtx.interDirNeighbours[pos];
 
-      affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = AFFINE_MODEL_NUM;
-      affMrgCtx.mergeType[affMrgCtx.numValidMergeCand] = MRG_TYPE_SUBPU_ATMVP;
+          affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = AFFINE_MODEL_NUM;
+          affMrgCtx.mergeType[affMrgCtx.numValidMergeCand] = MRG_TYPE_SUBPU_ATMVP;
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          affMrgCtx.colIdx[affMrgCtx.numValidMergeCand] = (index << 1) + colFrameIdx;
+#endif
 #if AFFINE_MMVD
-      mrgCandIdx += (isAfMmvd && mrgCandIdx >= 0 ? 1 : 0);
+          mrgCandIdx += (isAfMmvd && mrgCandIdx >= 0 ? 1 : 0);
 #endif
-      if ( affMrgCtx.numValidMergeCand == mrgCandIdx )
-      {
-        affMrgCtx.numValidMergeCand++;
-        return;
-      }
+          if (affMrgCtx.numValidMergeCand == mrgCandIdx)
+          {
+            return;
+          }
 
-      affMrgCtx.numValidMergeCand++;
+          affMrgCtx.numValidMergeCand++;
 
 #if JVET_Z0139_NA_AFF && JVET_W0090_ARMC_TM
-      if (isZeroCandIdx && !cs.pcv->isEncoder)
-      {
-        return;
-      }
+          if (isZeroCandIdx && !cs.pcv->isEncoder)
+          {
+            return;
+          }
 #endif
-      // early termination
-      if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
-      {
-        return;
+          // early termination
+          if (affMrgCtx.numValidMergeCand == maxNumAffineMergeCand)
+          {
+            return;
+          }
+        }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
       }
+#if ENABLE_INTER_TEMPLATE_MATCHING
     }
+#endif
+#endif
   }
 
   if ( slice.getSPS()->getUseAffine() )
@@ -12070,6 +13353,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
       affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = puNeigh->interDir;
       affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = (EAffineModel)(puNeigh->cu->affineType);
       affMrgCtx.BcwIdx[affMrgCtx.numValidMergeCand] = puNeigh->cu->BcwIdx;
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      affMrgCtx.colIdx[affMrgCtx.numValidMergeCand] = 0;
+#endif
 #if INTER_LIC
       CHECK( puNeigh->interDir == 3 && puNeigh->cu->LICFlag, "LIC should not be enabled for affine bi-pred" );
       affMrgCtx.LICFlags[affMrgCtx.numValidMergeCand] = puNeigh->cu->LICFlag;
@@ -12115,7 +13401,18 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         affMrgCtxTemp.candCost[i] = MAX_UINT64;
       }
       affMrgCtxTemp.numValidMergeCand = 0;
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      if (pu.cs->sps->getUseFastSubTmvp())
+      {
+        affMrgCtxTemp.maxNumMergeCand = 17;
+      }
+      else
+      {
+        affMrgCtxTemp.maxNumMergeCand = 16;
+      }
+#else
       affMrgCtxTemp.maxNumMergeCand = RMVF_AFFINE_MRG_MAX_CAND_LIST_SIZE;
+#endif
 
       std::vector<RMVFInfo> mvpInfoVec[2][4];
       collectNeiMotionInfo(mvpInfoVec, pu);
@@ -12300,7 +13597,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
         const PreCalcValues& pcv = *cs.pcv;
         Position posC0;
-        bool C0Avail = false;
+        bool isC0Avail = false;
 
         bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
         const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
@@ -12315,15 +13612,18 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
           if (posYInCtu + 4 < pcv.maxCUHeight)
           {
             posC0 = posRB.offset(4, 4);
-            C0Avail = true;
+            isC0Avail = true;
           }
         }
 
         Mv        cColMv;
         int       refIdx = 0;
-        bool      bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, refIdx, false 
+        bool      bExistMV = isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, refIdx, false
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-                                                       , &refIdx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , 0
+#endif
+          , &refIdx
 #endif
         );
         if ( bExistMV )
@@ -12342,9 +13642,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
         if ( slice.isInterB() )
         {
-          bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, refIdx, false
+          bExistMV = isC0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, refIdx, false
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-                                               , &refIdx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , 0
+#endif
+            , &refIdx
 #endif
           );
           if ( bExistMV )
@@ -12585,7 +13888,18 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
     }
     const int MAX_PAIRWISE_NUM = 9;
     const int preDefinedPairs[MAX_PAIRWISE_NUM][2] = { {0, 1}, {0, 2}, {1, 2}, {0, 3}, {1, 3}, { 2, 3}, { 0, 4}, {1, 4}, { 2, 4} };
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    int iATMVPoffset = 0;
+    for (int index = 0; index < affMrgCtx.numValidMergeCand; index++)
+    {
+      if (affMrgCtx.mergeType[index] == MRG_TYPE_SUBPU_ATMVP)
+      {
+        iATMVPoffset++;
+      }
+    }
+#else
     int iATMVPoffset = affMrgCtx.mergeType[0] == MRG_TYPE_SUBPU_ATMVP ? 1 : 0;
+#endif
     int currSize = affMrgCtx.numValidMergeCand;
     for (int pairIdx = 0; pairIdx < MAX_PAIRWISE_NUM; pairIdx++)
     {
@@ -12680,6 +13994,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
       affMrgCtx.mvFieldNeighbours[(cnt << 1) + 0][mvNum].setMvField( Mv( 0, 0 ), 0 );
     }
     affMrgCtx.interDirNeighbours[cnt] = 1;
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    affMrgCtx.colIdx[cnt] = 0;
+#endif
 
     if ( slice.isInterB() )
     {
@@ -12993,6 +14310,29 @@ void PU::setAllAffineMv(PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPic
 
 void clipColPos(int& posX, int& posY, const PredictionUnit& pu)
 {
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  Position puPos = pu.lumaPos();
+  int log2CtuSize = floorLog2(pu.cs->sps->getCTUSize());
+  int ctuY = ((puPos.y >> log2CtuSize) << log2CtuSize);
+  int horMax;
+  int horMin;
+  const SubPic &curSubPic = pu.cu->slice->getPPS()->getSubPicFromPos(puPos);
+  if (curSubPic.getTreatedAsPicFlag())
+  {
+    horMax = (int)curSubPic.getSubPicRight();
+    horMin = (int)curSubPic.getSubPicLeft();
+  }
+  else
+  {
+    horMax = (int)pu.cs->pps->getPicWidthInLumaSamples() - 1;
+    horMin = 0;
+  }
+  int verMax = std::min((int)pu.cs->pps->getPicHeightInLumaSamples() - 1, ctuY + (int)pu.cs->sps->getCTUSize() - 1);
+  int verMin = std::max((int)0, ctuY);
+
+  posX = std::min(horMax, std::max(horMin, posX));
+  posY = std::min(verMax, std::max(verMin, posY));
+#else
   Position puPos = pu.lumaPos();
   int log2CtuSize = floorLog2(pu.cs->sps->getCTUSize());
   int ctuX = ((puPos.x >> log2CtuSize) << log2CtuSize);
@@ -13008,15 +14348,131 @@ void clipColPos(int& posX, int& posY, const PredictionUnit& pu)
     horMax = std::min((int)pu.cs->pps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3);
   }
   int horMin = std::max((int)0, ctuX);
-  int verMax = std::min( (int)pu.cs->pps->getPicHeightInLumaSamples() - 1, ctuY + (int)pu.cs->sps->getCTUSize() - 1 );
+  int verMax = std::min((int)pu.cs->pps->getPicHeightInLumaSamples() - 1, ctuY + (int)pu.cs->sps->getCTUSize() - 1);
   int verMin = std::max((int)0, ctuY);
 
   posX = std::min(horMax, std::max(horMin, posX));
   posY = std::min(verMax, std::max(verMin, posY));
+#endif
 }
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+void PU::getTMVPCandOpt(const PredictionUnit &pu, RefPicList refList, int refIdx, MergeCtx& mrgCtx, MergeCtx mergeCtxIn, int col)
+{
+  const uint32_t maxNumMergeCand = NUM_TMVP_CANDS;
+  for (uint32_t ui = 0; ui < pu.cs->sps->getMaxNumMergeCand(); ++ui)
+  {
+    mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
+#if INTER_LIC
+    mrgCtx.LICFlags[ui] = false;
+#endif
+    mrgCtx.interDirNeighbours[ui] = 0;
+    mrgCtx.mvFieldNeighbours[(ui << 1)].refIdx = NOT_VALID;
+    mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
+    mrgCtx.useAltHpelIf[ui] = false;
+#if MULTI_HYP_PRED
+    mrgCtx.addHypNeighbours[ui].clear();
+#endif
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+    mrgCtx.candCost[ui] = MAX_UINT64;
+#endif
+  }
+  mrgCtx.numValidMergeCand = 0;
+#if JVET_Z0102_NO_ARMC_FOR_ZERO_CAND
+  mrgCtx.numCandToTestEnc = 0;
+#endif
+
+  const Slice   &slice = *pu.cs->slice;
+  const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);
+  const unsigned mask = ~(scale - 1);
+  const Picture *pColPic = slice.getRefPic(RefPicList(col == 0 ? 1 - slice.getColFromL0Flag() : 1 - slice.getColFromL0Flag2nd()), col == 0 ? slice.getColRefIdx() : slice.getColRefIdx2nd());
+
+  Mv cTMv;
+  for (int i = 0; i < mergeCtxIn.numValidMergeCand; i++)
+  {
+    if ((mergeCtxIn.interDirNeighbours[i] & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, mergeCtxIn.mvFieldNeighbours[i << 1].refIdx) == pColPic)
+    {
+      cTMv = mergeCtxIn.mvFieldNeighbours[i << 1].mv;
+    }
+    else if (slice.isInterB() && (mergeCtxIn.interDirNeighbours[i] & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, mergeCtxIn.mvFieldNeighbours[(i << 1) + 1].refIdx) == pColPic)
+    {
+      cTMv = mergeCtxIn.mvFieldNeighbours[(i << 1) + 1].mv;
+    }
+    else
+    {
+      CHECK(true, "Wrong TMVP candidate");
+    }
+
+    ///////////////////////////////////////////////////////////////////////
+    ////////          GET Initial Temporal Vector                  ////////
+    ///////////////////////////////////////////////////////////////////////
+
+    Mv cTempVector = cTMv;
+    Mv cColMv;
+
+    // compute the location of the current PU
+    Position puPos = pu.lumaPos();
+    Size puSize = pu.lumaSize();
+    Position centerPos;
+    cTempVector = cTMv;
+
+    cTempVector.changePrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
+    int tempX = cTempVector.getHor();
+    int tempY = cTempVector.getVer();
+
+    centerPos.x = puPos.x + (puSize.width >> 1) + tempX;
+    centerPos.y = puPos.y + (puSize.height >> 1) + tempY;
+
+    clipColPos(centerPos.x, centerPos.y, pu);
+
+    centerPos = Position{ PosType(centerPos.x & mask), PosType(centerPos.y & mask) };
+
+    // derivation of center motion parameters from the collocated CU
+    const MotionInfo &mi = pColPic->cs->getMotionInfo(centerPos);
+
+    if (mi.isInter && mi.isIBCmot == false)
+    {
+      if (getColocatedMVP(pu, refList, centerPos, cColMv, refIdx, false
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+        , col
+#endif
+      ))
+      {
+        // set as default, for further motion vector field spanning
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+        mrgCtx.mvFieldNeighbours[(mrgCtx.numValidMergeCand << 1) + refList].setMvField(cColMv, refIdx);
+        mrgCtx.mvFieldNeighbours[(mrgCtx.numValidMergeCand << 1) + 1 - refList].setMvField(Mv(), NOT_VALID);
+#else
+        mrgCtx.mvFieldNeighbours[(mrgCtx.numValidMergeCand << 1) + currRefListId].setMvField(cColMv, 0);
+#endif
+        mrgCtx.interDirNeighbours[mrgCtx.numValidMergeCand] = refList + 1;
+        mrgCtx.BcwIdx[mrgCtx.numValidMergeCand] = BCW_DEFAULT;
+      }
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      if (!mrgCtx.xCheckSimilarMotion(mrgCtx.numValidMergeCand))
+      {
+#endif
+        mrgCtx.numValidMergeCand++;
+        if (mrgCtx.numValidMergeCand == maxNumMergeCand)
+        {
+          break;
+        }
+#if NON_ADJACENT_MRG_CAND || TM_MRG
+      }
+#endif
+      }
+    }
+    }
+#endif
 bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+#if ENABLE_INTER_TEMPLATE_MATCHING
+  , int subIdx, MergeCtx mergeCtxIn
+#endif
+  , int col
+#else
   , int mmvdList
+#endif
 )
 {
   const Slice   &slice = *pu.cs->slice;
@@ -13026,20 +14482,43 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
   LICFlag = false;
 #endif
 
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  const Picture *pColPic = slice.getRefPic(RefPicList(col == 0 ? 1 - slice.getColFromL0Flag() : 1 - slice.getColFromL0Flag2nd()), col == 0 ? slice.getColRefIdx() : slice.getColRefIdx2nd());
+#else
   const Picture *pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx());
+#endif
   Mv cTMv;
 
-  if ( count )
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  if (subIdx > mergeCtxIn.numValidMergeCand)
+  {
+    return false;
+  }
+  else if (subIdx < mergeCtxIn.numValidMergeCand)
+  {
+    if ((mergeCtxIn.interDirNeighbours[subIdx] & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, mergeCtxIn.mvFieldNeighbours[subIdx << 1].refIdx) == pColPic)
+    {
+      cTMv = mergeCtxIn.mvFieldNeighbours[subIdx << 1].mv;
+    }
+    else if (slice.isInterB() && (mergeCtxIn.interDirNeighbours[subIdx] & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, mergeCtxIn.mvFieldNeighbours[(subIdx << 1) + 1].refIdx) == pColPic)
+    {
+      cTMv = mergeCtxIn.mvFieldNeighbours[(subIdx << 1) + 1].mv;
+    }
+  }
+
+#else
+  if (count)
   {
-    if ( (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_0)) && slice.getRefPic( REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].refIdx ) == pColPic )
+    if ((mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].refIdx) == pColPic)
     {
       cTMv = mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].mv;
     }
-    else if ( slice.isInterB() && (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_1)) && slice.getRefPic( REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].refIdx ) == pColPic )
+    else if (slice.isInterB() && (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].refIdx) == pColPic)
     {
       cTMv = mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].mv;
     }
   }
+#endif
 
   ///////////////////////////////////////////////////////////////////////
   ////////          GET Initial Temporal Vector                  ////////
@@ -13090,7 +14569,10 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
 
       if (getColocatedMVP(pu, currRefPicList, centerPos, cColMv, refIdx, true
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
-                        , &refIdx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , col
+#endif
+        , &refIdx
 #endif
       ))
       {
@@ -13112,17 +14594,22 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
       }
     }
   }
-
   if (!found)
   {
     return false;
   }
+#if !JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
   if (mmvdList != 1)
   {
+#endif
     int xOff = (puWidth >> 1) + tempX;
     int yOff = (puHeight >> 1) + tempY;
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    MotionBuf &mb = mrgCtx.subPuMvpMiBuf[(subIdx << 1) + col];
+#else
     MotionBuf &mb = mrgCtx.subPuMvpMiBuf;
+#endif
 
     const bool isBiPred = isBipredRestriction(pu);
 
@@ -13140,8 +14627,8 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
 
         MotionInfo mi;
 
-        found       = false;
-        mi.isInter  = true;
+        found = false;
+        mi.isInter = true;
         mi.sliceIdx = slice.getIndependentSliceIdx();
         mi.isIBCmot = false;
         if (colMi.isInter && colMi.isIBCmot == false)
@@ -13151,6 +14638,9 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
             RefPicList currRefPicList = RefPicList(currRefListId);
             if (getColocatedMVP(pu, currRefPicList, colPos, cColMv, refIdx, true
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              , col
+#endif
               , &refIdx
 #endif
             ))
@@ -13160,15 +14650,15 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
 #else
               mi.refIdx[currRefListId] = 0;
 #endif
-              mi.mv[currRefListId]     = cColMv;
-              found                    = true;
+              mi.mv[currRefListId] = cColMv;
+              found = true;
             }
           }
         }
         if (!found)
         {
-          mi.mv[0]     = mrgCtx.mvFieldNeighbours[(count << 1) + 0].mv;
-          mi.mv[1]     = mrgCtx.mvFieldNeighbours[(count << 1) + 1].mv;
+          mi.mv[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].mv;
+          mi.mv[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].mv;
           mi.refIdx[0] = mrgCtx.mvFieldNeighbours[(count << 1) + 0].refIdx;
           mi.refIdx[1] = mrgCtx.mvFieldNeighbours[(count << 1) + 1].refIdx;
         }
@@ -13177,8 +14667,8 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
 
         if (isBiPred && mi.interDir == 3)
         {
-          mi.interDir  = 1;
-          mi.mv[1]     = Mv();
+          mi.interDir = 1;
+          mi.mv[1] = Mv();
           mi.refIdx[1] = NOT_VALID;
         }
 
@@ -13186,12 +14676,18 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
           .fill(mi);
       }
     }
+#if !JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
   }
+#endif
   return true;
 }
 
 #if MULTI_PASS_DMVR
-void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx, Mv* bdmvrSubPuMv0, Mv* bdmvrSubPuMv1, Mv* bdofSubPuMvOffset)
+void PU::spanMotionInfo(PredictionUnit &pu, const MergeCtx &mrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  int colIdx,
+#endif
+  Mv* bdmvrSubPuMv0, Mv* bdmvrSubPuMv1, Mv* bdofSubPuMvOffset)
 #else
 void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
 #endif
@@ -13326,11 +14822,22 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
   }
   else if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
   {
-    CHECK(mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized");
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  for (int i = 0; i < SUB_TMVP_NUM; i++)
+  {
+    CHECK(mrgCtx.subPuMvpMiBuf[i].area() == 0 || !mrgCtx.subPuMvpMiBuf[i].buf, "Buffer not initialized");
+  }
+#else
+  CHECK(mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized");
+#endif
 #if MULTI_PASS_DMVR
     MotionBuf mb = pu.getMotionBuf();
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    mb.copyFrom(mrgCtx.subPuMvpMiBuf[pu.colIdx]);
+#else
     mb.copyFrom(mrgCtx.subPuMvpMiBuf);
+#endif
 #if JVET_W0123_TIMD_FUSION
     spanIpmInfoInter(pu, mb, ib);
 #endif
@@ -13339,7 +14846,11 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
 
 #if JVET_W0123_TIMD_FUSION
 #if MULTI_PASS_DMVR
-void PU::spanMotionInfo2( PredictionUnit &pu, const MergeCtx &mrgCtx, Mv* bdmvrSubPuMv0, Mv* bdmvrSubPuMv1, Mv* bdofSubPuMvOffset)
+void PU::spanMotionInfo2(PredictionUnit &pu, const MergeCtx &mrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  int colIdx,
+#endif
+  Mv* bdmvrSubPuMv0, Mv* bdmvrSubPuMv1, Mv* bdofSubPuMvOffset)
 #else
 void PU::spanMotionInfo2( PredictionUnit &pu, const MergeCtx &mrgCtx )
 #endif
@@ -13422,11 +14933,22 @@ void PU::spanMotionInfo2( PredictionUnit &pu, const MergeCtx &mrgCtx )
   }
   else if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
   {
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      CHECK(mrgCtx.subPuMvpMiBuf[i].area() == 0 || !mrgCtx.subPuMvpMiBuf[i].buf, "Buffer not initialized");
+    }
+#else
     CHECK(mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized");
+#endif
 #if MULTI_PASS_DMVR
     MotionBuf mb = pu.getMotionBuf();
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    mb.copyFrom(mrgCtx.subPuMvpMiBuf[pu.colIdx]);
+#else
     mb.copyFrom(mrgCtx.subPuMvpMiBuf);
+#endif
   }
 }
 
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 775e1fe64c944a4eaf7abe5194abc04431f1320f..4c4183b2b46af8ab9ee6989ae065b9b825e720b8 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -242,7 +242,15 @@ namespace PU
 #endif
   );
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
-  void getTmvpMergeCand               (const PredictionUnit &pu, MergeCtx& mvpMrgCtx);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void getNonAdjacentMergeCandSubTMVP(const PredictionUnit &pu, MergeCtx& mvpMrgCtx, int col);
+  void getInterMergeCandidatesSubTMVP(const PredictionUnit &pu, MergeCtx& mrgCtx, int col, const int& mrgCandIdx = -1
+#if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
+    , MergeCtx* mvpMrgCtx1 = NULL
+#endif
+  );
+#endif
+  void getTmvpMergeCand(const PredictionUnit &pu, MergeCtx& mvpMrgCtxz);
   void getNonAdjacentMergeCand        (const PredictionUnit &pu, MergeCtx& mvpMrgCtx);
 #endif
   void getIBCMergeCandidates          (const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1);
@@ -264,6 +272,9 @@ namespace PU
   bool isDiffMER                      (const Position &pos1, const Position &pos2, const unsigned plevel);
   bool getColocatedMVP                (const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &pos, Mv& rcMv, const int &refIdx, bool sbFlag
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    , int col = 0
+#endif
     , int* targetRefIdx = nullptr
 #endif
   );
@@ -319,6 +330,19 @@ namespace PU
     , const uint32_t mvdSimilarityThresh = 1
 #endif
   );
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+  void addMergeHMVPCandSubTMVP(const CodingStructure &cs, MergeCtx& mrgCtx, const int& mrgCandIdx, const uint32_t maxNumMergeCand, int &cnt
+    , const bool isAvailableA1, const MotionInfo miLeft, const bool isAvailableB1, const MotionInfo miAbove
+#if !JVET_Z0075_IBC_HMVP_ENLARGE
+    , const bool ibcFlag
+    , const bool isGt4x4
+#endif
+    , const PredictionUnit &pu, int col
+#if TM_MRG || (JVET_Z0084_IBC_TM && !JVET_Z0075_IBC_HMVP_ENLARGE)
+    , const uint32_t mvdSimilarityThresh = 1
+#endif
+  );
+#endif
 #if JVET_X0083_BM_AMVP_MERGE_MODE
 #if JVET_Y0128_NON_CTC
   bool checkIsValidMergeMvCand        (const PredictionUnit &pu, int8_t mergeRefIdx[ NUM_REF_PIC_LIST_01 ]);
@@ -381,13 +405,21 @@ namespace PU
   );
   bool isBipredRestriction            (const PredictionUnit &pu);
 #if MULTI_PASS_DMVR
-  void spanMotionInfo                 (      PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx(), Mv* bdmvrSubPuMv0 = nullptr, Mv* bdmvrSubPuMv1 = nullptr, Mv* bdofSubPuMvOffset = nullptr );
+  void spanMotionInfo                 (      PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx(), 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    int colIdx = 0,
+#endif
+    Mv* bdmvrSubPuMv0 = nullptr, Mv* bdmvrSubPuMv1 = nullptr, Mv* bdofSubPuMvOffset = nullptr );
 #else
   void spanMotionInfo                 (      PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx() );
 #endif
 #if JVET_W0123_TIMD_FUSION
 #if MULTI_PASS_DMVR
-  void spanMotionInfo2                (      PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx(), Mv* bdmvrSubPuMv0 = nullptr, Mv* bdmvrSubPuMv1 = nullptr, Mv* bdofSubPuMvOffset = nullptr );
+  void spanMotionInfo2                (      PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx(),
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    int colIdx = 0,
+#endif
+    Mv* bdmvrSubPuMv0 = nullptr, Mv* bdmvrSubPuMv1 = nullptr, Mv* bdofSubPuMvOffset = nullptr );
 #else
   void spanMotionInfo2                (      PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx() );
 #endif
@@ -418,6 +450,9 @@ namespace PU
   int  getNonAdjAffParaDivFun(int num1, int num2);
 #endif
   void getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx, 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION   
+    MergeCtx mrgCtx[2],
+#endif
 #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION && JVET_W0090_ARMC_TM
     InterPrediction* m_pcInterSearch,
 #endif
@@ -437,7 +472,19 @@ namespace PU
 #endif
   void setAllAffineMvField            (      PredictionUnit &pu, MvField *mvField, RefPicList eRefList );
   void setAllAffineMv                 (      PredictionUnit &pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList, bool clipCPMVs = false );
-  bool getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx &mrgCtx, bool& LICFlag, const int count, int mmvdList);
+  bool getInterMergeSubPuMvpCand      (const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+#if ENABLE_INTER_TEMPLATE_MATCHING
+    , int subIdx, MergeCtx mergeCtxIn
+#endif
+    , int col = 0
+#else
+    , int mmvdList
+#endif
+  );
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  void getTMVPCandOpt(const PredictionUnit &pu, RefPicList refList, int refIdx, MergeCtx &mrgCtx, MergeCtx mergeCtx, int col = 0);
+#endif
 #if JVET_Y0128_NON_CTC
   bool isBiRefScaled(const CodingStructure& cs, const int refIdx0, const int refIdx1);
 #endif
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index d36bc9f40f2199570df4503d992e1faa999136c2..6c7a904fdfca6780c85714cad1f10d16ccc52ff0 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -1411,9 +1411,13 @@ void DecCu::xReconInter(CodingUnit &cu)
     }
 
 #if MULTI_PASS_DMVR
-    if( cu.firstPU->bdmvrRefine )
+    if (cu.firstPU->bdmvrRefine)
     {
-      PU::spanMotionInfo( *cu.firstPU, MergeCtx(), m_mvBufBDMVR[0], m_mvBufBDMVR[1], m_pcInterPred->getBdofSubPuMvOffset() );
+      PU::spanMotionInfo(*cu.firstPU, MergeCtx(),
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        cu.firstPU->colIdx,
+#endif
+        m_mvBufBDMVR[0], m_mvBufBDMVR[1], m_pcInterPred->getBdofSubPuMvOffset());
     }
 #endif
   }
@@ -1847,7 +1851,14 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         if (pu.cs->sps->getSbTMVPEnabledFlag())
         {
           Size bufSize = g_miScaling.scale(pu.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+          for (int i = 0; i < SUB_TMVP_NUM; i++)
+          {
+            mrgCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+          }
+#else
           mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
         }
 
         int   fPosBaseIdx = 
@@ -1876,7 +1887,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         mrgCtx.setMmvdMergeCandiInfo(pu, pu.mmvdMergeIdx);
 #endif
 
-        PU::spanMotionInfo(pu, mrgCtx);
+        PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+          , pu.colIdx
+#endif       
+        );
       }
       else
       {
@@ -1979,30 +1994,79 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         {
         if( pu.cu->affine )
         {
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+          MergeCtx mrgCtxAll[2];
+          for (int i = 0; i < 2; i++)
+          {
+            mrgCtxAll[i].numValidMergeCand = 0;
+          }
+          if (pu.cs->picHeader->getEnableTMVPFlag())
+          {
+            if (pu.cs->sps->getUseAML())
+            {
+              MergeCtx namvpMergeCandCtx[2];
+              int nWidth = pu.lumaSize().width;
+              int nHeight = pu.lumaSize().height;
+              bool tplAvail = m_pcInterPred->xAMLGetCurBlkTemplate(pu, nWidth, nHeight);
+              int poc0 = pu.cu->slice->getRefPic(RefPicList(1 - pu.cu->slice->getColFromL0Flag()), pu.cu->slice->getColRefIdx())->getPOC();
+              int poc1 = pu.cu->slice->getRefPic(RefPicList(1 - pu.cu->slice->getColFromL0Flag2nd()), pu.cu->slice->getColRefIdx2nd())->getPOC();
+              for (int col = 0; col < ((pu.cu->slice->getCheckLDC() || (poc0 == poc1)) ? 1 : 2); col++)
+              {
+                PU::getNonAdjacentMergeCandSubTMVP(pu, namvpMergeCandCtx[col], col);
+                if (col == 0 && tplAvail)
+                {
+                  m_pcInterPred->adjustMergeCandidatesInOneCandidateGroupSubTMVP(pu, namvpMergeCandCtx[col], 9);
+                }
+                else
+                {
+                  namvpMergeCandCtx[col].numValidMergeCand = std::min(9, namvpMergeCandCtx[col].numValidMergeCand);
+                }
+                PU::getInterMergeCandidatesSubTMVP(pu, mrgCtxAll[col], col, -1, &namvpMergeCandCtx[col]);
+                if (col == 0 && tplAvail)
+                {
+                  m_pcInterPred->adjustMergeCandidatesInOneCandidateGroupSubTMVP(pu, mrgCtxAll[col], pu.cs->sps->getMaxNumMergeCand());
+                }
+              }
+            }
+          }
+#endif
           AffineMergeCtx affineMergeCtx;
           if (pu.cs->sps->getSbTMVPEnabledFlag())
           {
-            Size bufSize = g_miScaling.scale( pu.lumaSize() );
-            mrgCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize );
+            Size bufSize = g_miScaling.scale(pu.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+            for (int i = 0; i < SUB_TMVP_NUM; i++)
+            {
+              mrgCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+            }
+#else
+            mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
             affineMergeCtx.mrgCtx = &mrgCtx;
           }
 #if AFFINE_MMVD
 #if JVET_W0090_ARMC_TM
           int affMrgIdx = pu.cs->sps->getUseAML() && (((pu.mergeIdx / ADAPTIVE_AFFINE_SUB_GROUP_SIZE + 1)*ADAPTIVE_AFFINE_SUB_GROUP_SIZE < pu.cs->sps->getMaxNumAffineMergeCand()) || (pu.mergeIdx / ADAPTIVE_AFFINE_SUB_GROUP_SIZE) == 0) ? pu.mergeIdx / ADAPTIVE_AFFINE_SUB_GROUP_SIZE * ADAPTIVE_AFFINE_SUB_GROUP_SIZE + ADAPTIVE_AFFINE_SUB_GROUP_SIZE - 1 : pu.mergeIdx;
-		  if (pu.afMmvdFlag)
-		  {
+          if (pu.afMmvdFlag)
+          {
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
-            affMrgIdx = 
+            affMrgIdx =
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_AA0093_ENHANCED_MMVD_EXTENSION
-                        !pu.cs->sps->getUseTMMMVD() ?
-                        ECM3_AF_MMVD_BASE_NUM :
+              !pu.cs->sps->getUseTMMMVD() ?
+              ECM3_AF_MMVD_BASE_NUM :
 #endif
-			            AF_MMVD_BASE_NUM;
+              AF_MMVD_BASE_NUM;
 #else
-			affMrgIdx = pu.afMmvdBaseIdx;
+            affMrgIdx = pu.afMmvdBaseIdx;
 #endif			  
-		  }
+          }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          pu.cu->imv = IMV_OFF;
+#endif
           PU::getAffineMergeCand(pu, affineMergeCtx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                               , mrgCtxAll
+#endif
 #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION
                                , m_pcInterPred
 #endif
@@ -2080,6 +2144,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
           pu.cu->BcwIdx = affineMergeCtx.BcwIdx[pu.mergeIdx];
 #if INTER_LIC
           pu.cu->LICFlag = affineMergeCtx.LICFlags[pu.mergeIdx];
+#endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          pu.colIdx = affineMergeCtx.colIdx[pu.mergeIdx];
 #endif
           pu.mergeType = affineMergeCtx.mergeType[pu.mergeIdx];
           if ( pu.mergeType == MRG_TYPE_SUBPU_ATMVP )
@@ -2125,7 +2192,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
             }
           }
 #endif
-          PU::spanMotionInfo( pu, mrgCtx );
+          PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , pu.colIdx
+#endif
+          );
         }
 #if JVET_X0141_CIIP_TIMD_TM && TM_MRG
         else if (pu.ciipFlag && pu.tmMergeFlag)
@@ -2162,7 +2233,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 
           mrgCtx.setMergeInfo(pu, storeMrgIdx);
           pu.bdmvrRefine = false;
-          PU::spanMotionInfo(pu, mrgCtx);
+          PU::spanMotionInfo(pu, mrgCtx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , pu.colIdx
+#endif
+          );
         }
 #endif
         else
@@ -2917,7 +2992,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 #if MULTI_PASS_DMVR
           if( !pu.bdmvrRefine )
           {
-            PU::spanMotionInfo( pu, mrgCtx );
+            PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              , pu.colIdx
+#endif
+            );
           }
 #else
           PU::spanMotionInfo( pu, mrgCtx );
@@ -2951,6 +3030,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
       {
 #if TM_AMVP
         m_pcInterPred->clearTplAmvpBuffer();
+#endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        m_pcInterPred->clearAmvpTmvpBuffer();
 #endif
         if (pu.cu->affine)
         {
@@ -3291,7 +3373,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 #if JVET_X0083_BM_AMVP_MERGE_MODE
         if (!pu.bdmvrRefine)
 #endif
-        PU::spanMotionInfo( pu, mrgCtx );
+          PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , pu.colIdx
+#endif
+          );
       }
     }
     if( !cu.geoFlag )
diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h
index 3b13c88f53e47d753a83cde4c4196afea2a5a5e8..021d98e9f0b7c28e7845fefd3593bcb0047da63c 100644
--- a/source/Lib/DecoderLib/DecCu.h
+++ b/source/Lib/DecoderLib/DecCu.h
@@ -99,7 +99,11 @@ private:
 
   PelStorage        m_ciipBuffer;
 
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  MotionInfo        m_SubPuMiBuf[SUB_TMVP_NUM][(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
+#else
   MotionInfo        m_SubPuMiBuf[(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
+#endif
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   bool applyBDMVR4BM[BM_MRG_MAX_NUM_INIT_CANDS];
 #endif
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index 8757ca244a52f180aa55b251aeed81aebf02d65e..0ffd2141c49f358fe7f2dac529b302a0945a4018 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -146,13 +146,23 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
   if (slice->getPicHeader()->getEnableTMVPFlag())
   {
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    for (int colFrameIdx = 0; colFrameIdx < (slice->isInterB() ? 2 : 1); colFrameIdx++)
+    {
+      const Picture* const pColPic = slice->getRefPic(RefPicList(colFrameIdx == 0 ? 1 - slice->getColFromL0Flag() : 1 - slice->getColFromL0Flag2nd()), colFrameIdx == 0 ? slice->getColRefIdx() : slice->getColRefIdx2nd());
+#else
     const Picture* const pColPic = slice->getRefPic(RefPicList(slice->isInterB() ? 1 - slice->getColFromL0Flag() : 0), slice->getColRefIdx());
+#endif 
     if (pColPic)
     {
       const int currPOC = slice->getPOC();
       const int colPOC = pColPic->getPOC();
 
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      slice->resizeImBuf(pColPic->numSlices, colFrameIdx);
+#else
       slice->resizeImBuf(pColPic->numSlices);
+#endif
       Slice *pColSlice = nullptr;
       for (int sliceIdx = 0; sliceIdx < pColPic->numSlices; sliceIdx++)
       {
@@ -202,12 +212,19 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
                   }
                 }
               } // curRefIdx
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              slice->setImRefIdx(sliceIdx, RefPicList(colRefPicListIdx), RefPicList(curRefPicListIdx), colRefIdx, targetRefIdx, colFrameIdx);
+#else
               slice->setImRefIdx(sliceIdx, RefPicList(colRefPicListIdx), RefPicList(curRefPicListIdx), colRefIdx, targetRefIdx);
+#endif
             } // curRefPicListIdx
           }
         }
       }
     }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    }
+#endif
   }
 #endif
 
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index f1ffb299495715d3568e1ffc284bc099f4deb63d..5eb2dbf5b89f9fed2b8c02d6c76e4389181fd3ac 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2238,6 +2238,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   }
 #endif
 #endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  READ_FLAG( uiCode, "sps_fast_sub_tmvp_enabled_flag");              pcSPS->setUseFastSubTmvp( uiCode != 0 );
+#endif
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
   pcSPS->setUseTmvpNmvpReordering(false);
   if (pcSPS->getUseAML())
@@ -3792,10 +3795,17 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
       {
         READ_CODE(1, uiCode, "ph_collocated_from_l0_flag");
         picHeader->setPicColFromL0Flag(uiCode);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        READ_CODE(1, uiCode, "ph_collocated_from_l0_flag_2nd");
+        picHeader->setPicColFromL0Flag2nd(uiCode);
+#endif
       }
       else
       {
         picHeader->setPicColFromL0Flag(1);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        picHeader->setPicColFromL0Flag2nd(1);
+#endif
       }
       if ((picHeader->getPicColFromL0Flag() == 1 && picHeader->getRPL(0)->getNumRefEntries() > 1) ||
         (picHeader->getPicColFromL0Flag() == 0 && picHeader->getRPL(1)->getNumRefEntries() > 1))
@@ -3807,10 +3817,25 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
       {
         picHeader->setColRefIdx(0);
       }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      if ((picHeader->getPicColFromL0Flag2nd() == 1 && picHeader->getRPL(0)->getNumRefEntries() > 1) ||
+        (picHeader->getPicColFromL0Flag2nd() == 0 && picHeader->getRPL(1)->getNumRefEntries() > 1))
+      {
+        READ_UVLC(uiCode, "ph_collocated_ref_idx_2nd");
+        picHeader->setColRefIdx2nd(uiCode);
+      }
+      else
+      {
+        picHeader->setColRefIdx2nd(0);
+      }
+#endif
     }
     else
     {
       picHeader->setPicColFromL0Flag(0);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      picHeader->setPicColFromL0Flag2nd(0);
+#endif
     }
 
 #if !JVET_R0324_REORDER
@@ -4813,15 +4838,25 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par
       if( pcSlice->getSliceType() == P_SLICE )
       {
         pcSlice->setColFromL0Flag( true );
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+        pcSlice->setColFromL0Flag2nd( true );
+#endif
       }
       else if( !pps->getRplInfoInPhFlag() && pcSlice->getSliceType() == B_SLICE )
       {
         READ_FLAG( uiCode, "collocated_from_l0_flag" );
         pcSlice->setColFromL0Flag( uiCode );
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+        READ_FLAG( uiCode, "collocated_from_l0_flag_2nd" );
+        pcSlice->setColFromL0Flag2nd( uiCode );
+#endif
       }
       else
       {
         pcSlice->setColFromL0Flag( picHeader->getPicColFromL0Flag() );
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+        pcSlice->setColFromL0Flag2nd(picHeader->getPicColFromL0Flag2nd());
+#endif
       }
 
       if (!pps->getRplInfoInPhFlag())
@@ -4837,11 +4872,26 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par
       {
         pcSlice->setColRefIdx(0);
       }
-
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+      if (pcSlice->getSliceType() != I_SLICE &&
+        ((pcSlice->getColFromL0Flag2nd() == 1 && pcSlice->getNumRefIdx(REF_PIC_LIST_0) > 1) ||
+        (pcSlice->getColFromL0Flag2nd() == 0 && pcSlice->getNumRefIdx(REF_PIC_LIST_1) > 1)))
+      {
+        READ_UVLC(uiCode, "collocated_ref_idx_2nd");
+        pcSlice->setColRefIdx2nd(uiCode);
+      }
+      else
+      {
+        pcSlice->setColRefIdx2nd(0);
+      }
+#endif
       }
       else
       {
         pcSlice->setColRefIdx(picHeader->getColRefIdx());
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+        pcSlice->setColRefIdx2nd(picHeader->getColRefIdx2nd());
+#endif
       }
     }
     if ( (pps->getUseWP() && pcSlice->getSliceType()==P_SLICE) || (pps->getWPBiPred() && pcSlice->getSliceType()==B_SLICE) )
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 1890bc029bee8330de3a2c532120cb500735b0c0..0d26828b77ff4fa2a8233119038222e0a3489bba 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1037,6 +1037,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
   if (!slice.isIntra())
   {
     m_pcInterSearch->clearTplAmvpBuffer();
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    m_pcInterSearch->clearAmvpTmvpBuffer();
+#endif
   }
 #endif
 #if INTER_LIC
@@ -3419,17 +3422,38 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
-    mergeCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize );
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      mergeCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+      mrgCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+    }
+#else
+    mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
     mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
     affineMergeCtx.mrgCtx = &mrgCtx;
 #if TM_MRG
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      tmMrgCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+#if JVET_X0141_CIIP_TIMD_TM
+      ciipTmMrgCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+#endif
+#if JVET_AB0079_TM_BCW_MRG
+      mrgCtxCiip.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+#endif
+    }
+#else
     tmMrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
 #if JVET_X0141_CIIP_TIMD_TM
     ciipTmMrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
 #endif
-#endif
 #if JVET_AB0079_TM_BCW_MRG
     mrgCtxCiip.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
+#endif
 #endif
   }
 #endif
@@ -3608,7 +3632,43 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
     PU::getInterMergeCandidates(pu, mergeCtxtmp, 0);
 #endif
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    MergeCtx mrgCtxAll[2];
+    for (int i = 0; i < 2; i++)
+    {
+      mrgCtxAll[i].numValidMergeCand = 0;
+    }
+    if (pu.cs->picHeader->getEnableTMVPFlag())
+    {
+      if (pu.cs->sps->getUseAML())
+      {
+        MergeCtx namvpMergeCandCtxSubTMVP[2];
+        int nWidth = pu.lumaSize().width;
+        int nHeight = pu.lumaSize().height;
+        bool tplAvail = m_pcInterSearch->xAMLGetCurBlkTemplate(pu, nWidth, nHeight);
+        int poc0 = slice.getRefPic(RefPicList(1 - slice.getColFromL0Flag()), slice.getColRefIdx())->getPOC();
+        int poc1 = slice.getRefPic(RefPicList(1 - slice.getColFromL0Flag2nd()), slice.getColRefIdx2nd())->getPOC();
+        for (int col = 0; col < ((pu.cu->slice->getCheckLDC() || (poc0 == poc1)) ? 1 : 2); col++)
+        {
+          PU::getNonAdjacentMergeCandSubTMVP(pu, namvpMergeCandCtxSubTMVP[col], col);
+          if (col == 0 && tplAvail)
+          {
+            m_pcInterSearch->adjustMergeCandidatesInOneCandidateGroupSubTMVP(pu, namvpMergeCandCtxSubTMVP[col], 9);
+          }
+          else
+          {
+            namvpMergeCandCtxSubTMVP[col].numValidMergeCand = std::min(9, namvpMergeCandCtxSubTMVP[col].numValidMergeCand);
+          }
+          PU::getInterMergeCandidatesSubTMVP(pu, mrgCtxAll[col], col, -1, &namvpMergeCandCtxSubTMVP[col]);
 
+          if (col == 0 && tplAvail)
+          {
+            m_pcInterSearch->adjustMergeCandidatesInOneCandidateGroupSubTMVP(pu, mrgCtxAll[col], pu.cs->sps->getMaxNumMergeCand());
+          }
+        }
+      }
+    }
+#endif
 #if JVET_X0141_CIIP_TIMD_TM && TM_MRG
     if (cu.cs->sps->getUseCiipTmMrg())
     {
@@ -3955,6 +4015,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       pu.regularMergeFlag = false;
       cu.affine = true;
       PU::getAffineMergeCand(pu, affineMergeCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION  
+        , mrgCtxAll
+#endif
 #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION && JVET_W0090_ARMC_TM
         , m_pcInterSearch
 #endif
@@ -5237,6 +5300,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         pu.interDir = affineMergeCtx.interDirNeighbours[uiMergeCand];
         cu.affineType = affineMergeCtx.affineType[uiMergeCand];
         cu.BcwIdx = affineMergeCtx.BcwIdx[uiMergeCand];
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        pu.colIdx = affineMergeCtx.colIdx[uiMergeCand];
+#endif
 #if INTER_LIC
         cu.LICFlag = affineMergeCtx.LICFlags[uiMergeCand];
 #endif
@@ -5253,7 +5319,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         {
           pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0][0].refIdx;
           pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1][0].refIdx;
-          PU::spanMotionInfo(pu, mrgCtx);
+          PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , pu.colIdx
+#endif
+          );
         }
         else
         {
@@ -5344,10 +5414,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if MULTI_PASS_DMVR
       if( !pu.bdmvrRefine )
       {
-        PU::spanMotionInfo( pu, mergeCtx );
+        PU::spanMotionInfo(pu, mergeCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , pu.colIdx
+#endif
+        );
       }
 #else
-      PU::spanMotionInfo( pu, mergeCtx );
+        PU::spanMotionInfo(pu, mergeCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          , pu.colIdx
+#endif
+        );
 #endif
 
       if( m_pcEncCfg->getMCTSEncConstraint() )
@@ -5489,18 +5567,30 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
               if ( pu.tmMergeFlag )
 #endif
               {
-                PU::spanMotionInfo( pu, mergeCtx, m_mvBufBDMVR4TM[uiMergeCand << 1], m_mvBufBDMVR4TM[( uiMergeCand << 1 ) + 1], m_pcInterSearch->getBdofSubPuMvOffset() );
+                PU::spanMotionInfo(pu, mergeCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pu.colIdx,
+#endif
+                  m_mvBufBDMVR4TM[uiMergeCand << 1], m_mvBufBDMVR4TM[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
               }
               else
 #endif
 #if JVET_X0049_ADAPT_DMVR
               if( pu.bmMergeFlag ) 
               {
-                PU::spanMotionInfo( pu, bmMrgCtx, m_mvBufBDMVR4BM[uiMergeCand << 1], m_mvBufBDMVR4BM[( uiMergeCand << 1 ) + 1], m_pcInterSearch->getBdofSubPuMvOffset() );
+                PU::spanMotionInfo(pu, bmMrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pu.colIdx,
+#endif
+                  m_mvBufBDMVR4BM[uiMergeCand << 1], m_mvBufBDMVR4BM[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
               }
               else
 #endif
-              PU::spanMotionInfo(pu, mergeCtx, m_mvBufBDMVR[uiMergeCand << 1], m_mvBufBDMVR[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
+                PU::spanMotionInfo(pu, mergeCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pu.colIdx,
+#endif
+                  m_mvBufBDMVR[uiMergeCand << 1], m_mvBufBDMVR[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
             }
 #endif
           }
@@ -5547,18 +5637,30 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if TM_MRG
               if( pu.tmMergeFlag )
               {
-                PU::spanMotionInfo( pu, mergeCtx, m_mvBufBDMVR4TM[uiMergeCand << 1], m_mvBufBDMVR4TM[( uiMergeCand << 1 ) + 1], m_mvBufEncBDOF4TM[uiMergeCand] );
+                PU::spanMotionInfo(pu, mergeCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pu.colIdx,
+#endif
+                  m_mvBufBDMVR4TM[uiMergeCand << 1], m_mvBufBDMVR4TM[(uiMergeCand << 1) + 1], m_mvBufEncBDOF4TM[uiMergeCand]);
               }
               else
 #endif
 #if JVET_X0049_ADAPT_DMVR
               if( pu.bmMergeFlag )
               {
-                PU::spanMotionInfo( pu, bmMrgCtx, m_mvBufBDMVR4BM[uiMergeCand << 1], m_mvBufBDMVR4BM[( uiMergeCand << 1 ) + 1], m_mvBufEncBDOF4BM[uiMergeCand] );
+                PU::spanMotionInfo(pu, bmMrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pu.colIdx,
+#endif
+                  m_mvBufBDMVR4BM[uiMergeCand << 1], m_mvBufBDMVR4BM[(uiMergeCand << 1) + 1], m_mvBufEncBDOF4BM[uiMergeCand]);
               }
               else
 #endif
-              PU::spanMotionInfo(pu, mergeCtx, m_mvBufBDMVR[uiMergeCand << 1], m_mvBufBDMVR[(uiMergeCand << 1) + 1], m_mvBufEncBDOF[uiMergeCand]);
+                PU::spanMotionInfo(pu, mergeCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pu.colIdx,
+#endif
+                  m_mvBufBDMVR[uiMergeCand << 1], m_mvBufBDMVR[(uiMergeCand << 1) + 1], m_mvBufEncBDOF[uiMergeCand]);
             }
 #endif
           }
@@ -5575,18 +5677,30 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if TM_MRG
           if( pu.tmMergeFlag )
           {
-            PU::spanMotionInfo( pu, mergeCtx, m_mvBufBDMVR4TM[uiMergeCand << 1], m_mvBufBDMVR4TM[( uiMergeCand << 1 ) + 1], m_pcInterSearch->getBdofSubPuMvOffset() );
+            PU::spanMotionInfo(pu, mergeCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+              pu.colIdx,
+#endif
+              m_mvBufBDMVR4TM[uiMergeCand << 1], m_mvBufBDMVR4TM[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
           }
           else
 #endif
 #if JVET_X0049_ADAPT_DMVR 
             if (pu.bmMergeFlag)
             {
-              PU::spanMotionInfo(pu, bmMrgCtx, m_mvBufBDMVR4BM[uiMergeCand << 1], m_mvBufBDMVR4BM[(uiMergeCand << 1) + 1], m_mvBufEncBDOF4BM[uiMergeCand]);
+              PU::spanMotionInfo(pu, bmMrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                pu.colIdx,
+#endif
+                m_mvBufBDMVR4BM[uiMergeCand << 1], m_mvBufBDMVR4BM[(uiMergeCand << 1) + 1], m_mvBufEncBDOF4BM[uiMergeCand]);
             }
             else
 #endif
-            PU::spanMotionInfo(pu, mergeCtx, m_mvBufBDMVR[uiMergeCand << 1], m_mvBufBDMVR[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
+              PU::spanMotionInfo(pu, mergeCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                pu.colIdx,
+#endif
+                m_mvBufBDMVR[uiMergeCand << 1], m_mvBufBDMVR[(uiMergeCand << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
         }
 #endif
       }
@@ -5693,7 +5807,14 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if TM_MRG
     for (int i = 0; i < GEO_NUM_TM_MV_CAND; i++)
     {
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+      for (int j = 0; j < SUB_TMVP_NUM; j++)
+      {
+        mergeCtx[i].subPuMvpMiBuf[j] = MotionBuf(m_SubPuMiBuf[j], bufSize);
+    }
+#else
       mergeCtx[i].subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
     }
 #else
     mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
@@ -8402,7 +8523,14 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      mergeCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+    }
+#else
     mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
   }
 
   CodingUnit &cu = tempCS->addCU(tempCS->area, pm.chType);
@@ -9321,14 +9449,20 @@ void EncCu::xCheckSATDCostAffineMerge(CodingStructure *&tempCS, CodingUnit &cu,
     pu.mv[0].setZero();
     pu.mv[1].setZero();
     cu.imv = 0;
-
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    pu.colIdx = affineMergeCtx.colIdx[uiAffMergeCand];
+#endif
     pu.mergeType = affineMergeCtx.mergeType[uiAffMergeCand];
     if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
     {
       pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 0][0].refIdx;
       pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[(uiAffMergeCand << 1) + 1][0].refIdx;
       // the SbTmvp use xSubPuMC which will need to access the motion buffer for subblock MV
-      PU::spanMotionInfo(pu, mrgCtx);
+      PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , pu.colIdx
+#endif 
+      );
     }
     else
     {
@@ -10031,7 +10165,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
         {
           pu.refIdx[0] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0][0].refIdx;
           pu.refIdx[1] = affineMergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1][0].refIdx;
-          PU::spanMotionInfo( pu, mrgCtx );
+          PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            , pu.colIdx
+#endif
+          );
         }
         else
         {
@@ -10248,7 +10386,14 @@ void EncCu::xCheckRDCostAffineMmvd2Nx2N(CodingStructure *&tempCS, CodingStructur
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
-    mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      mergeCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+    }
+#else
+    mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
     affineMergeCtx.mrgCtx = &mrgCtx;
   }
 
@@ -10560,7 +10705,14 @@ void EncCu::xCheckRDCostTMMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      mergeCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+    }
+#else
     mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
   }
 #if MULTI_PASS_DMVR
   bool applyBDMVR4TM[TM_MRG_MAX_NUM_CANDS] = { false };
@@ -10948,7 +11100,14 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      mergeCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+    }
+#else
     mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
   }
 
   {
@@ -11605,7 +11764,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       }
 #endif
 #else
-      PU::spanMotionInfo(pu, mergeCtxTm);
+      PU::spanMotionInfo(pu, mergeCtxTm
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , pu.colIdx
+#endif
+      );
 #endif
 
 #if JVET_AA0070_RRIBC
@@ -12347,7 +12510,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             {
               bool mbvdCandMisAlign = mergeCtxTmp.setIbcMbvdMergeCandiInfo(pu, mergeCand - numPreviousBv, ibcMbvdLUT[mergeCand - numPreviousBv]);
               CHECK(mbvdCandMisAlign, "MBVD candidate is invalid");
-              PU::spanMotionInfo(pu, mergeCtxTmp);
+              PU::spanMotionInfo(pu, mergeCtxTmp
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                , pu.colIdx
+#endif
+              );
             }
             else
             {
@@ -12368,7 +12535,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
                 {
 #endif
                 mergeCtxTm.setMergeInfo(pu, mergeCand);
-                PU::spanMotionInfo(pu, mergeCtxTm);
+                PU::spanMotionInfo(pu, mergeCtxTm
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  , pu.colIdx
+#endif
+                );
 #if JVET_AC0112_IBC_GPM
                 }
 #endif
@@ -12386,7 +12557,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
                 {
 #endif
                 mergeCtx.setMergeInfo(pu, mergeCand);
-                PU::spanMotionInfo(pu, mergeCtx);
+                PU::spanMotionInfo(pu, mergeCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  , pu.colIdx
+#endif
+                );
 #if JVET_AC0112_IBC_GPM
                 }
 #endif
@@ -14724,7 +14899,11 @@ void EncCu::predInterSearchAdditionalHypothesisMulti(const MEResultVec& in, MERe
     if (pu.mergeType == MRG_TYPE_SUBPU_ATMVP)
     {
       // the SbTmvp use xSubPuMC which will need to access the motion buffer for subblock MV
-      PU::spanMotionInfo(pu, mrgCtx);
+      PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , pu.colIdx
+#endif       
+      );
     }
     else if (x.cu.affine)
     {
@@ -14782,7 +14961,14 @@ void EncCu::xCheckRDCostInterMultiHyp2Nx2N(CodingStructure *&tempCS, CodingStruc
   if (sps.getSbTMVPEnabledFlag())
   {
     Size bufSize = g_miScaling.scale(tempCS->area.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION   
+    for (int i = 0; i < SUB_TMVP_NUM; i++)
+    {
+      mrgCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+    }
+#else
     mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
   }
 
   // Hadamard-based pre-search
@@ -14855,10 +15041,18 @@ void EncCu::xCheckRDCostInterMultiHyp2Nx2N(CodingStructure *&tempCS, CodingStruc
     }
     else
     {
-      PU::spanMotionInfo(pu, mrgCtx);
+      PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , pu.colIdx
+#endif
+      );
     }
 #else
-    PU::spanMotionInfo(pu, mrgCtx);
+    PU::spanMotionInfo(pu, mrgCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      , pu.colIdx
+#endif
+    );
 #endif
     cu.skip = false;
     cu.mmvdSkip = false;
@@ -14875,18 +15069,30 @@ void EncCu::xCheckRDCostInterMultiHyp2Nx2N(CodingStructure *&tempCS, CodingStruc
 #if TM_MRG
       if( pu.tmMergeFlag )
       {
-        PU::spanMotionInfo( pu, mrgCtx, m_mvBufBDMVR4TM[pu.mergeIdx << 1], m_mvBufBDMVR4TM[( pu.mergeIdx << 1 ) + 1], m_pcInterSearch->getBdofSubPuMvOffset() );
+        PU::spanMotionInfo(pu, mrgCtx,
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          pu.colIdx,
+#endif
+          m_mvBufBDMVR4TM[pu.mergeIdx << 1], m_mvBufBDMVR4TM[(pu.mergeIdx << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
       }
       else
 #endif
 #if JVET_X0049_ADAPT_DMVR
       if( pu.bmMergeFlag )
       {
-        PU::spanMotionInfo( pu, mrgCtx, m_mvBufBDMVR4BM[pu.mergeIdx << 1], m_mvBufBDMVR4BM[( pu.mergeIdx << 1 ) + 1], m_pcInterSearch->getBdofSubPuMvOffset() );
+        PU::spanMotionInfo(pu, mrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          pu.colIdx,
+#endif
+          m_mvBufBDMVR4BM[pu.mergeIdx << 1], m_mvBufBDMVR4BM[(pu.mergeIdx << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
       }
       else
 #endif
-      PU::spanMotionInfo(pu, mrgCtx, m_mvBufBDMVR[pu.mergeIdx << 1], m_mvBufBDMVR[(pu.mergeIdx << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
+        PU::spanMotionInfo(pu, mrgCtx,
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          pu.colIdx,
+#endif
+          m_mvBufBDMVR[pu.mergeIdx << 1], m_mvBufBDMVR[(pu.mergeIdx << 1) + 1], m_pcInterSearch->getBdofSubPuMvOffset());
     }
 #endif
     pu.mvRefine = false;
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 7f4663ebc7cb802c871a4ed49751f3d1a255bf9c..7227a30daa8c52b0c8a100d1dc8ef81080556fa9 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -327,7 +327,11 @@ private:
 #endif
   double                m_AFFBestSATDCost;
   double                m_mergeBestSATDCost;
-  MotionInfo            m_SubPuMiBuf      [( MAX_CU_SIZE * MAX_CU_SIZE ) >> ( MIN_CU_LOG2 << 1 )];
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  MotionInfo            m_SubPuMiBuf[SUB_TMVP_NUM][(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
+#else
+  MotionInfo            m_SubPuMiBuf[(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
+#endif
 #if MULTI_PASS_DMVR
   Mv                    m_mvBufBDMVR[(MRG_MAX_NUM_CANDS << 1)][MAX_NUM_SUBCU_DMVR];
 #if TM_MRG
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index eea8a14bc1d2ae6b295c82ba87ae0b3f512a211a..50fec0675de6fefe64419aa641c98796f1e56ab8 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -2675,88 +2675,198 @@ void EncGOP::compressGOP(int iPOCLast, int iNumPicRcvd, PicList &rcListPic, std:
       picHeader->setEnableTMVPFlag(0);
     }
 
-    if( pcSlice->getSliceType() != I_SLICE && picHeader->getEnableTMVPFlag() )
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+    int poc1stCol = -1;
+    int list1stCol = 0;
+    int list2ndCol = 0;
+#endif
+    if (pcSlice->getSliceType() != I_SLICE && picHeader->getEnableTMVPFlag())
     {
       int colRefIdxL0 = -1, colRefIdxL1 = -1;
 
       const bool isResamplingPossible = pcSlice->getSPS()->getRprEnabledFlag();
 
-      for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); refIdx++ )
+      for (int refIdx = 0; refIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0); refIdx++)
       {
-        CHECK( pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->unscaledPic == nullptr, "unscaledPic is not set for L0 reference picture" );
-
-        if( !isResamplingPossible || !pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->isRefScaled( pcSlice->getPPS() ) )
+        CHECK(pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->unscaledPic == nullptr, "unscaledPic is not set for L0 reference picture");
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        if ((!isResamplingPossible || !pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->isRefScaled(pcSlice->getPPS())) /*&& (pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->slices[0]->getSliceType() != I_SLICE)*/)
+#else
+        if (!isResamplingPossible || !pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->isRefScaled(pcSlice->getPPS()))
+#endif
         {
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          poc1stCol = pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->getPOC();
+          list1stCol = 0;
+#endif
           colRefIdxL0 = refIdx;
           break;
         }
       }
 
-      if( pcSlice->getSliceType() == B_SLICE )
+      if (pcSlice->getSliceType() == B_SLICE)
       {
-        for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); refIdx++ )
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        list2ndCol = 1;
+        if (colRefIdxL0 < 0)
         {
-          CHECK( pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->unscaledPic == nullptr, "unscaledPic is not set for L1 reference picture" );
-
-          if( !isResamplingPossible || !pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->isRefScaled( pcSlice->getPPS() ) )
+          for (int refIdx = 0; refIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1); refIdx++)
+          {
+            CHECK(pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->unscaledPic == nullptr, "unscaledPic is not set for L1 reference picture");
+            if ((!isResamplingPossible || !pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->isRefScaled(pcSlice->getPPS())) /*&& (pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->slices[0]->getSliceType() != I_SLICE)*/)
+            {
+              poc1stCol = pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->getPOC();
+              list1stCol = 1;
+              colRefIdxL0 = refIdx;
+              break;
+            }
+          }
+        }
+#endif
+        for (int refIdx = 0; refIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1); refIdx++)
+        {
+          CHECK(pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->unscaledPic == nullptr, "unscaledPic is not set for L1 reference picture");
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          int poc2ndCol = pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->getPOC();
+          if ((poc1stCol != poc2ndCol) && (!isResamplingPossible || !pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->isRefScaled(pcSlice->getPPS())) /*&& (pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->slices[0]->getSliceType() != I_SLICE)*/)
+#else
+          if (!isResamplingPossible || !pcSlice->getRefPic(REF_PIC_LIST_1, refIdx)->isRefScaled(pcSlice->getPPS()))
+#endif
           {
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+            list2ndCol = 1;
+#endif
             colRefIdxL1 = refIdx;
             break;
           }
         }
       }
-
-      if( colRefIdxL0 >= 0 && colRefIdxL1 >= 0 )
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      else
       {
-        const Picture *refPicL0 = pcSlice->getRefPic( REF_PIC_LIST_0, colRefIdxL0 );
-        if( !refPicL0->slices.size() )
+        for (int refIdx = 0; refIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0); refIdx++)
+        {
+          int poc2ndCol = pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->getPOC();
+          CHECK(pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->unscaledPic == nullptr, "unscaledPic is not set for L0 reference picture");
+          if ((poc1stCol != poc2ndCol) && (!isResamplingPossible || !pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->isRefScaled(pcSlice->getPPS())) /*&& (pcSlice->getRefPic(REF_PIC_LIST_0, refIdx)->slices[0]->getSliceType() != I_SLICE)*/)
+          {
+            colRefIdxL1 = refIdx;
+            break;
+          }
+        }
+      }
+#endif
+      if (colRefIdxL0 >= 0 && colRefIdxL1 >= 0)
+      {
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        const Picture *refPicL0 = pcSlice->getRefPic(RefPicList(list1stCol), colRefIdxL0);
+        if (!refPicL0->slices.size())
         {
           refPicL0 = refPicL0->unscaledPic;
         }
 
-        const Picture *refPicL1 = pcSlice->getRefPic( REF_PIC_LIST_1, colRefIdxL1 );
-        if( !refPicL1->slices.size() )
+        const Picture *refPicL1 = pcSlice->getRefPic(RefPicList(list2ndCol), colRefIdxL1);
+        if (!refPicL1->slices.size())
+        {
+          refPicL1 = refPicL1->unscaledPic;
+        }
+        picHeader->setPicColFromL0Flag(1 - list1stCol);
+        pcSlice->setColFromL0Flag(1 - list1stCol);
+        pcSlice->setColRefIdx(colRefIdxL0);
+        picHeader->setColRefIdx(colRefIdxL0);
+        picHeader->setPicColFromL0Flag2nd(1 - list2ndCol);
+        pcSlice->setColFromL0Flag2nd(1 - list2ndCol);
+        pcSlice->setColRefIdx2nd(colRefIdxL1);
+        picHeader->setColRefIdx2nd(colRefIdxL1);
+
+        int poc1st = refPicL0->getPOC();
+        int poc2nd = refPicL1->getPOC();
+        int pocCur = pcSlice->getPOC();
+        if ((abs(poc1st - pocCur) == abs(poc2nd - pocCur)) && (refPicL0->slices[0]->getSliceQp() < refPicL1->slices[0]->getSliceQp()))
+        {
+          picHeader->setPicColFromL0Flag2nd(1 - list1stCol);
+          pcSlice->setColFromL0Flag2nd(1 - list1stCol);
+          pcSlice->setColRefIdx2nd(colRefIdxL0);
+          picHeader->setColRefIdx2nd(colRefIdxL0);
+          picHeader->setPicColFromL0Flag(1 - list2ndCol);
+          pcSlice->setColFromL0Flag(1 - list2ndCol);
+          pcSlice->setColRefIdx(colRefIdxL1);
+          picHeader->setColRefIdx(colRefIdxL1);
+        }
+#else
+        const Picture *refPicL0 = pcSlice->getRefPic(REF_PIC_LIST_0, colRefIdxL0);
+        if (!refPicL0->slices.size())
+        {
+          refPicL0 = refPicL0->unscaledPic;
+        }
+
+        const Picture *refPicL1 = pcSlice->getRefPic(REF_PIC_LIST_1, colRefIdxL1);
+        if (!refPicL1->slices.size())
         {
           refPicL1 = refPicL1->unscaledPic;
         }
 
-        CHECK( !refPicL0->slices.size(), "Wrong L0 reference picture" );
-        CHECK( !refPicL1->slices.size(), "Wrong L1 reference picture" );
+        CHECK(!refPicL0->slices.size(), "Wrong L0 reference picture");
+        CHECK(!refPicL1->slices.size(), "Wrong L1 reference picture");
 
         const uint32_t uiColFromL0 = refPicL0->slices[0]->getSliceQp() > refPicL1->slices[0]->getSliceQp();
-        picHeader->setPicColFromL0Flag( uiColFromL0 );
-        pcSlice->setColFromL0Flag( uiColFromL0 );
-        pcSlice->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
-        picHeader->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
+        picHeader->setPicColFromL0Flag(uiColFromL0);
+        pcSlice->setColFromL0Flag(uiColFromL0);
+        pcSlice->setColRefIdx(uiColFromL0 ? colRefIdxL0 : colRefIdxL1);
+        picHeader->setColRefIdx(uiColFromL0 ? colRefIdxL0 : colRefIdxL1);
+#endif
       }
-      else if( colRefIdxL0 < 0 && colRefIdxL1 >= 0 )
+#if !JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      else if (colRefIdxL0 < 0 && colRefIdxL1 >= 0)
       {
-        picHeader->setPicColFromL0Flag( false );
-        pcSlice->setColFromL0Flag( false );
-        pcSlice->setColRefIdx( colRefIdxL1 );
-        picHeader->setColRefIdx( colRefIdxL1 );
+        picHeader->setPicColFromL0Flag(false);
+        pcSlice->setColFromL0Flag(false);
+        pcSlice->setColRefIdx(colRefIdxL1);
+        picHeader->setColRefIdx(colRefIdxL1);
       }
-      else if( colRefIdxL0 >= 0 && colRefIdxL1 < 0 )
+#endif
+      else if (colRefIdxL0 >= 0 && colRefIdxL1 < 0)
       {
-        picHeader->setPicColFromL0Flag( true );
-        pcSlice->setColFromL0Flag( true );
-        pcSlice->setColRefIdx( colRefIdxL0 );
-        picHeader->setColRefIdx( colRefIdxL0 );
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        picHeader->setPicColFromL0Flag(1 - list1stCol);
+        pcSlice->setColFromL0Flag(1 - list1stCol);
+        pcSlice->setColRefIdx(colRefIdxL0);
+        picHeader->setColRefIdx(colRefIdxL0);
+        picHeader->setPicColFromL0Flag2nd(1 - list2ndCol);
+        pcSlice->setColFromL0Flag2nd(1 - list2ndCol);
+        pcSlice->setColRefIdx2nd(0);
+        picHeader->setColRefIdx2nd(0);
+#else
+        picHeader->setPicColFromL0Flag(true);
+        pcSlice->setColFromL0Flag(true);
+        pcSlice->setColRefIdx(colRefIdxL0);
+        picHeader->setColRefIdx(colRefIdxL0);
+#endif
       }
       else
       {
-        picHeader->setEnableTMVPFlag( 0 );
+        picHeader->setEnableTMVPFlag(0);
       }
 #if JVET_Y0134_TMVP_NAMVP_CAND_REORDERING
       if (picHeader->getEnableTMVPFlag())
       {
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        for (int colFrameIdx = 0; colFrameIdx < (pcSlice->isInterB() ? 2 : 1); colFrameIdx++)
+        {
+          const Picture* const pColPic = pcSlice->getRefPic(RefPicList(colFrameIdx == 0 ? 1 - pcSlice->getColFromL0Flag() : 1 - pcSlice->getColFromL0Flag2nd()), colFrameIdx == 0 ? pcSlice->getColRefIdx() : pcSlice->getColRefIdx2nd());
+#else
         const Picture* const pColPic = pcSlice->getRefPic(RefPicList(pcSlice->isInterB() ? 1 - pcSlice->getColFromL0Flag() : 0), pcSlice->getColRefIdx());
+#endif 
         if (pColPic)
         {
           const int currPOC = pcSlice->getPOC();
           const int colPOC = pColPic->getPOC();
 
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          pcSlice->resizeImBuf(pColPic->numSlices, colFrameIdx);
+#else
           pcSlice->resizeImBuf(pColPic->numSlices);
+#endif
           Slice *pColSlice = nullptr;
           for (int sliceIdx = 0; sliceIdx < pColPic->numSlices; sliceIdx++)
           {
@@ -2810,12 +2920,19 @@ void EncGOP::compressGOP(int iPOCLast, int iNumPicRcvd, PicList &rcListPic, std:
                     }
                   } // curRefIdx
                     //printf("sliceIdx:%d, colRefPicListIdx:%d, curRefPicListIdx:%d, colRefIdx:%d, targetRefIdx:%d\n", sliceIdx, colRefPicListIdx, curRefPicListIdx, colRefIdx, targetRefIdx);
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+                  pcSlice->setImRefIdx(sliceIdx, RefPicList(colRefPicListIdx), RefPicList(curRefPicListIdx), colRefIdx, targetRefIdx, colFrameIdx);
+#else
                   pcSlice->setImRefIdx(sliceIdx, RefPicList(colRefPicListIdx), RefPicList(curRefPicListIdx), colRefIdx, targetRefIdx);
+#endif
                 } // curRefPicListIdx
               }
             }
           }
         }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        }
+#endif
       }
 #endif
     }
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 905d7651b29f0be9c0dd1be7cd080f769ee059e8..5527a960f3675b8b28b148de4e2c2e19ee7bdde8 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1534,6 +1534,9 @@ void EncLib::xInitSPS( SPS& sps )
 #if JVET_W0090_ARMC_TM
   sps.setUseAML                             ( m_AML );
 #endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  sps.setUseFastSubTmvp                     ((m_sourceWidth * m_sourceHeight) > (m_intraPeriod == -1 ? 0 : 832 * 480));
+#endif
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   sps.setUseArmcRefinedMotion               ( m_armcRefinedMotion );
 #endif
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 127109a313a617db0342c96eec6905ca1ced0d3e..fe34ffa4bc8ae06713d3bdea586fb3cc70ea15b4 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -3578,7 +3578,14 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
     if (cu.cs->sps->getSbTMVPEnabledFlag())
     {
       Size bufSize = g_miScaling.scale(pu.lumaSize());
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+      for (int i = 0; i < SUB_TMVP_NUM; i++)
+      {
+        mergeCtx.subPuMvpMiBuf[i] = MotionBuf(m_SubPuMiBuf[i], bufSize);
+      }
+#else
       mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
+#endif
     }
 
     Distortion   uiHevcCost = std::numeric_limits<Distortion>::max();
@@ -4693,7 +4700,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
     if (!pu.bdmvrRefine)
 #endif
     {
-      PU::spanMotionInfo( pu, mergeCtx );
+      PU::spanMotionInfo(pu, mergeCtx
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        , pu.colIdx
+#endif
+      );
     }
 
     m_skipPROF = false;
@@ -4725,7 +4736,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
 #if JVET_X0083_BM_AMVP_MERGE_MODE
     if (pu.bdmvrRefine)
     {
-      PU::spanMotionInfo( *cu.firstPU, MergeCtx(), mvBufEncAmBDMVR_L0, mvBufEncAmBDMVR_L1, getBdofSubPuMvOffset() );
+      PU::spanMotionInfo(*cu.firstPU, MergeCtx(),
+#if ENABLE_INTER_TEMPLATE_MATCHING && JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        pu.colIdx,
+#endif
+        mvBufEncAmBDMVR_L0, mvBufEncAmBDMVR_L1, getBdofSubPuMvOffset());
     }
 #endif
 #if INTER_LIC && (!TM_AMVP || (JVET_AA0132_CONFIGURABLE_TM_TOOLS && TM_AMVP))
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 2561d7a85a641e98247b6a0fbe4df6b977b0db95..a5805daa57ad2301ae9bc52e950e6e8ebbc3f817 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1371,6 +1371,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
 #endif
   WRITE_FLAG( pcSPS->getUseAML() ? 1 : 0,                                             "sps_aml_enabled_flag" );
 #endif
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION 
+  WRITE_FLAG( pcSPS->getUseFastSubTmvp() ? 1 : 0,                                     "sps_fast_sub_tmvp_enabled_flag");
+#endif
 #if JVET_AA0132_CONFIGURABLE_TM_TOOLS && JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM
   if (pcSPS->getUseAML())
   {
@@ -2440,12 +2443,22 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader, bool writeRbspTrailingB
         if (picHeader->getRPL(1)->getNumRefEntries() > 0)
         {
           WRITE_CODE(picHeader->getPicColFromL0Flag(), 1, "ph_collocated_from_l0_flag");
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          WRITE_CODE(picHeader->getPicColFromL0Flag2nd(), 1, "ph_collocated_from_l0_flag_2nd");
+#endif
         }
         if ((picHeader->getPicColFromL0Flag() && picHeader->getRPL(0)->getNumRefEntries() > 1) ||
           (!picHeader->getPicColFromL0Flag() && picHeader->getRPL(1)->getNumRefEntries() > 1))
         {
           WRITE_UVLC(picHeader->getColRefIdx(), "ph_collocated_ref_idx");
         }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+        if ((picHeader->getPicColFromL0Flag2nd() && picHeader->getRPL(0)->getNumRefEntries() > 1) ||
+          (!picHeader->getPicColFromL0Flag2nd() && picHeader->getRPL(1)->getNumRefEntries() > 1))
+        {
+          WRITE_UVLC(picHeader->getColRefIdx2nd(), "ph_collocated_ref_idx_2nd");
+        }
+#endif
       }
     }
     else
@@ -3000,6 +3013,9 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         if (pcSlice->getSliceType() == B_SLICE)
         {
           WRITE_FLAG(pcSlice->getColFromL0Flag(), "collocated_from_l0_flag");
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+          WRITE_FLAG(pcSlice->getColFromL0Flag2nd(), "collocated_from_l0_flag_2nd");
+#endif
         }
       }
 
@@ -3009,6 +3025,14 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
       {
         WRITE_UVLC( pcSlice->getColRefIdx(), "collocated_ref_idx" );
       }
+#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
+      if (pcSlice->getSliceType() != I_SLICE &&
+        ((pcSlice->getColFromL0Flag2nd() == 1 && pcSlice->getNumRefIdx(REF_PIC_LIST_0) > 1) ||
+        (pcSlice->getColFromL0Flag2nd() == 0 && pcSlice->getNumRefIdx(REF_PIC_LIST_1) > 1)))
+      {
+        WRITE_UVLC(pcSlice->getColRefIdx2nd(), "collocated_ref_idx_2nd");
+      }
+#endif
     }
 
     if( ( pcSlice->getPPS()->getUseWP() && pcSlice->getSliceType() == P_SLICE ) || ( pcSlice->getPPS()->getWPBiPred() && pcSlice->getSliceType() == B_SLICE ) )