#include <bits/stdc++.h>
using namespace std;
using Tuple = tuple<int, int, int, int>;
using V1 = vector<int>;
using V2 = vector<V1>;
using V3 = vector<V2>;
using PQueue = priority_queue<Tuple, vector<Tuple>, greater<Tuple>>;

constexpr int INF = 1e+9;

template<typename T>
bool chmin(T &a, T b)
{
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

int calc_dist(int idx, V2 &A, V2 &B, int x1, int y1, int z1)
{
    if (idx == 0)
        return A[x1][y1];
    if (idx == 1)
        return A[x1][y1 - 1];
    if (idx == 2)
        return B[x1][y1];
    if (idx == 3)
        return (z1 == 0) ? 2 : 1;
    if (idx == 4)
        return 1;
    assert(false);
    return INF;
}


int main()
{
    int R, C;
    cin >> R >> C;
    V2 A(R, V1(C - 1)), B(R - 1, V1(C));
    for (auto &Ai : A) {
        for (auto &Aij : Ai)
            cin >> Aij;
    }
    for (auto &Bi : B) {
        for (auto &Bij : Bi)
            cin >> Bij;
    }
    V3 cost(R, V2(C, V1(2, INF)));
    cost[0][0][0] = 0;
    PQueue pq;
    pq.push({0, 0, 0, 0});
    int dx[5] = {0, 0, 1, -1, 0};
    int dy[5] = {1, -1, 0, 0, 0};
    while (!pq.empty()) {
        auto [cost1, x1, y1, z1] = pq.top(); pq.pop();
        if (cost[x1][y1][z1] < cost1)
            continue;
        for (int i = 0; i < 5; ++i) {
            auto x = x1 + dx[i], y = y1 + dy[i], z = (i >= 3) ? 1 : 0;
            if (x < 0 || R <= x || y < 0 || C <= y)
                continue;
            if (i == 3 && z1 == 0)
                continue;
            auto d = calc_dist(i, A, B, x1, y1, z1);
            auto cost2 = cost1 + d;
            if (chmin(cost[x][y][z], cost2))
                pq.push({cost2, x, y, z});
        }
    }
    auto &costRC = cost[R - 1][C - 1];
    cout << *min_element(costRC.begin(), costRC.end()) << endl;
}

#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
using vb = vector<bool>;
using vl = vector<long>;
using vs = vector<string>;
using vvi = vector<vector<int>>;
using vvb = vector<vector<bool>>;
using vvc = vector<vector<char>>;
using vvl = vector<vector<long>>;
using pii = pair<int, int>;
using pil = pair<int, long>;
using pll = pair<long, long>;
#define fix20 cout << fixed << setprecision(20)
#define YES cout << "Yes" << endl
#define NO cout << "No" << endl
#define rep(i,n) for(long i=0; i<(long)(n);i++)
#define REP(i,s,t) for(long i=s; i<t; i++)
#define RNG(i,s,t,u) for(long i=s; i<t; i+=u)
#define MOD 1000000007
#define all(vec) vec.begin(), vec.end()
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }

vvc d(2000+2,vector<char>(2000+2, '#'));
vector<vvl> dp(4,vvl(2000+2, vl(2000+2,-1)));
//URDL
int dx[4] = {0,1,0,-1};
int dy[4] = {-1,0,1,0};
/*void dfs(int x, int y, int dir){
  if(dp[dir][x][y] != -1) return;
  rep(i,4){
    int nx = x + dx[i];
    int ny = y + dy[i];
    if(d.at(nx).at(ny) == '#'){
      dp[i][x][y] = 0;
    }else{
      if(dp[i][nx][ny] != -1){
        dp[i][nx][ny] = dp[i][x][y] + 1;
      }else{
        dfs()
      }
    }

  }
  
  if(d.at(x).at(y) == '#'){
    dp[dir][x][y] = 0;
    return;
  }

}*/
long dfs(int x, int y, int dir){
  if(d.at(x).at(y) == '#') return 0;
  if(dp[dir][x][y] != -1) return dp[dir][x][y];
  int nx = x + dx[dir];
  int ny = y + dy[dir];
  if(d.at(nx).at(ny) == '#') return dp[dir][x][y] = 0;
  else return dp[dir][x][y] = dfs(nx,ny,dir) + 1;
}


int main(){
  long h,w;
  cin >> h >> w;
  long shiro = 0;
  rep(i,h){
    rep(j,w) {
      cin >> d.at(i+1).at(j+1);
      if(d.at(i+1).at(j+1) == '.') shiro++;
    }
  }

  vl two(5000000, 1);
  REP(i,1,5000000){
    two.at(i) = two.at(i-1)*2%MOD;
  }
  long ans = 0;
  rep(i,h){
    rep(j,w){
      if(d.at(i+1).at(j+1) == '#') continue;
      long cnt = 1;
      rep(k,4){
        cnt += dfs(i+1,j+1,k);
      }
      long tmp = two.at(shiro-cnt) * (two.at(cnt) + MOD - 1) % MOD;
      ans = ( ans + tmp ) % MOD;
    }
  }
  
  cout << ans << endl;
}