/*
* EasyWave - A realtime tsunami simulation program with GPU support.
* Copyright (C) 2014 Andrey Babeyko, Johannes Spazier
* GFZ German Research Centre for Geosciences (http://www.gfz-potsdam.de)
*
* Parts of this program (especially the GPU extension) were developed
* within the context of the following publicly funded project:
* - TRIDEC, EU 7th Framework Programme, Grant Agreement 258723
* (http://www.tridec-online.eu)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
// Time stepping
#include
#include
#include
#include "easywave.h"
/* TODO: still not perfect */
#define Node(idx1, idx2) Node.node[idx1][idx2]
#define CNode CStructNode
#define gNode ((CStructNode*)gNode)
int ewStep( void )
{
int i,j,enlarge;
float absH,v1,v2;
int m;
CNode& Node = *gNode;
// sea floor topography (mass conservation)
#pragma omp parallel for default(shared) private(i,j,absH)
for( i=Imin; i<=Imax; i++ ) {
for( j=Jmin; j<=Jmax; j++ ) {
m = idx(j,i);
if( Node(m, iD) == 0 ) continue;
Node(m, iH) = Node(m, iH) - Node(m, iR1)*( Node(m, iM) - Node(m-NLat, iM) + Node(m, iN)*R6[j] - Node(m-1, iN)*R6[j-1] );
absH = fabs(Node(m, iH));
if( absH < Par.sshZeroThreshold ) Node(m, iH) = 0.;
if( Node(m, iH) > Node(m, iHmax) ) Node(m, iHmax) = Node(m, iH);
if( Par.sshArrivalThreshold && Node(m, iTime) < 0 && absH > Par.sshArrivalThreshold ) Node(m, iTime) = (float)Par.time;
}
}
// open bondary conditions
if( Jmin <= 2 ) {
for( i=2; i<=(NLon-1); i++ ) {
m = idx(1,i);
Node(m, iH) = sqrt( pow(Node(m, iN),2.) + 0.25*pow((Node(m, iM)+Node(m-NLat, iM)),2.) )*C1[i];
if( Node(m, iN) > 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Imin <= 2 ) {
for( j=2; j<=(NLat-1); j++ ) {
m = idx(j,1);
Node(m, iH) = sqrt( pow(Node(m, iM),2.) + 0.25*pow((Node(m, iN)+Node(m-1, iN)),2.) )*C2[j];
if( Node(m, iM) > 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Jmax >= (NLat-1) ) {
for( i=2; i<=(NLon-1); i++ ) {
m = idx(NLat,i);
Node(m, iH) = sqrt( pow(Node(m-1, iN),2.) + 0.25*pow((Node(m, iM)+Node(m-1, iM)),2.) )*C3[i];
if( Node(m-1, iN) < 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Imax >= (NLon-1) ) {
for( j=2; j<=(NLat-1); j++ ) {
m = idx(j,NLon);
Node(m, iH) = sqrt( pow(Node(m-NLat, iM),2.) + 0.25*pow((Node(m, iN)+Node(m-1, iN)),2.) )*C4[j];
if( Node(m-NLat, iM) < 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Jmin <= 2 ) {
m = idx(1,1);
Node(m, iH) = sqrt( pow(Node(m, iM),2.) + pow(Node(m, iN),2.) )*C1[1];
if( Node(m, iN) > 0 ) Node(m, iH) = - Node(m, iH);
m = idx(1,NLon);
Node(m, iH) = sqrt( pow(Node(m-NLat, iM),2.) + pow(Node(m, iN),2.) )*C1[NLon];
if( Node(m, iN) > 0 ) Node(m, iH) = - Node(m, iH);
}
if( Jmin >= (NLat-1) ) {
m = idx(NLat,1);
Node(m, iH) = sqrt( pow(Node(m, iM),2.) + pow(Node(m-1, iN),2.) )*C3[1];
if( Node(m-1, iN) < 0 ) Node(m, iH) = - Node(m, iH);
m = idx(NLat,NLon);
Node(m, iH) = sqrt( pow(Node(m-NLat, iM),2.) + pow(Node(m-1, iN),2.) )*C3[NLon];
if( Node(m-1, iN) < 0 ) Node(m, iH) = - Node(m, iH);
}
// moment conservation
#pragma omp parallel for default(shared) private(i,j)
for( i=Imin; i<=Imax; i++ ) {
for( j=Jmin; j<=Jmax; j++ ) {
m = idx(j,i);
if( (Node(m, iD)*Node(m+NLat, iD)) != 0 )
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH)-Node(m, iH));
if( (Node(m, iD)*Node(m+1, iD)) != 0 )
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH)-Node(m, iH));
}
}
// open boundaries
if( Jmin <= 2 ) {
for( i=1; i<=(NLon-1); i++ ) {
m = idx(1,i);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH) - Node(m, iH));
}
}
if( Imin <= 2 ) {
for( j=1; j<=NLat; j++ ) {
m = idx(j,1);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH) - Node(m, iH));
}
}
if( Jmax >= (NLat-1) ) {
for( i=1; i<=(NLon-1); i++ ) {
m = idx(NLat,i);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH) - Node(m, iH));
}
}
if( Imin <= 2 ) {
for( j=1; j<=(NLat-1); j++ ) {
m = idx(j,1);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH) - Node(m, iH));
}
}
if( Jmin <= 2 ) {
for( i=1; i<=NLon; i++ ) {
m = idx(1,i);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH) - Node(m, iH));
}
}
if( Imax >= (NLon-1) ) {
for( j=1; j<=(NLat-1); j++ ) {
m = idx(j,NLon);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH) - Node(m, iH));
}
}
// calculation area for the next step
if( Imin > 2 ) {
for( enlarge=0, j=Jmin; j<=Jmax; j++ ) {
if( fabs(Node(idx(j,Imin+2), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Imin--; if( Imin < 2 ) Imin = 2; }
}
if( Imax < (NLon-1) ) {
for( enlarge=0, j=Jmin; j<=Jmax; j++ ) {
if( fabs(Node(idx(j,Imax-2), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Imax++; if( Imax > (NLon-1) ) Imax = NLon-1; }
}
if( Jmin > 2 ) {
for( enlarge=0, i=Imin; i<=Imax; i++ ) {
if( fabs(Node(idx(Jmin+2,i), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Jmin--; if( Jmin < 2 ) Jmin = 2; }
}
if( Jmax < (NLat-1) ) {
for( enlarge=0, i=Imin; i<=Imax; i++ ) {
if( fabs(Node(idx(Jmax-2,i), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Jmax++; if( Jmax > (NLat-1) ) Jmax = NLat-1; }
}
return 0;
}
int ewStepCor( void )
{
int i,j,enlarge;
float absH,v1,v2;
int m;
CNode& Node = *gNode;
// sea floor topography (mass conservation)
#pragma omp parallel for default(shared) private(i,j,nod,absH)
for( i=Imin; i<=Imax; i++ ) {
for( j=Jmin; j<=Jmax; j++ ) {
m = idx(j,i);
if( Node(m, iD) == 0 ) continue;
Node(m, iH) = Node(m, iH) - Node(m, iR1)*( Node(m, iM) - Node(m-NLat, iM) + Node(m, iN)*R6[j] - Node(m-1, iN)*R6[j-1] );
absH = fabs(Node(m, iH));
if( absH < Par.sshZeroThreshold ) Node(m, iH) = 0.;
if( Node(m, iH) > Node(m, iHmax) ) Node(m, iHmax) = Node(m, iH);
if( Par.sshArrivalThreshold && Node(m, iTime) < 0 && absH > Par.sshArrivalThreshold ) Node(m, iTime) = (float)Par.time;
}
}
// open bondary conditions
if( Jmin <= 2 ) {
for( i=2; i<=(NLon-1); i++ ) {
m = idx(1,i);
Node(m, iH) = sqrt( pow(Node(m, iN),2.) + 0.25*pow((Node(m, iM)+Node(m-NLat, iM)),2.) )*C1[i];
if( Node(m, iN) > 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Imin <= 2 ) {
for( j=2; j<=(NLat-1); j++ ) {
m = idx(j,1);
Node(m, iH) = sqrt( pow(Node(m, iM),2.) + 0.25*pow((Node(m, iN)+Node(m-1, iN)),2.) )*C2[j];
if( Node(m, iM) > 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Jmax >= (NLat-1) ) {
for( i=2; i<=(NLon-1); i++ ) {
m = idx(NLat,i);
Node(m, iH) = sqrt( pow(Node(m-1, iN),2.) + 0.25*pow((Node(m, iM)+Node(m-1, iM)),2.) )*C3[i];
if( Node(m-1, iN) < 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Imax >= (NLon-1) ) {
for( j=2; j<=(NLat-1); j++ ) {
m = idx(j,NLon);
Node(m, iH) = sqrt( pow(Node(m-NLat, iM),2.) + 0.25*pow((Node(m, iN)+Node(m-1, iN)),2.) )*C4[j];
if( Node(m-NLat, iM) < 0 ) Node(m, iH) = - Node(m, iH);
}
}
if( Jmin <= 2 ) {
m = idx(1,1);
Node(m, iH) = sqrt( pow(Node(m, iM),2.) + pow(Node(m, iN),2.) )*C1[1];
if( Node(m, iN) > 0 ) Node(m, iH) = - Node(m, iH);
m = idx(1,NLon);
Node(m, iH) = sqrt( pow(Node(m-NLat, iM),2.) + pow(Node(m, iN),2.) )*C1[NLon];
if( Node(m, iN) > 0 ) Node(m, iH) = - Node(m, iH);
}
if( Jmin >= (NLat-1) ) {
m = idx(NLat,1);
Node(m, iH) = sqrt( pow(Node(m, iM),2.) + pow(Node(m-1, iN),2.) )*C3[1];
if( Node(m-1, iN) < 0 ) Node(m, iH) = - Node(m, iH);
m = idx(NLat,NLon);
Node(m, iH) = sqrt( pow(Node(m-NLat, iM),2.) + pow(Node(m-1, iN),2.) )*C3[NLon];
if( Node(m-1, iN) < 0 ) Node(m, iH) = - Node(m, iH);
}
// moment conservation
// longitudial flux update
#pragma omp parallel for default(shared) private(i,j,nod,v1,v2)
for( i=Imin; i<=Imax; i++ ) {
for( j=Jmin; j<=Jmax; j++ ) {
m = idx(j,i);
if( (Node(m, iD)*Node(m+NLat, iD)) == 0 ) continue;
v1 = Node(m+NLat, iH) - Node(m, iH);
v2 = Node(m-1, iN) + Node(m, iN) + Node(m+NLat, iN) + Node(m+NLat-1, iN);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*v1 + Node(m, iR3)*v2;
}
}
// open boundaries
if( Jmin <= 2 ) {
for( i=1; i<=(NLon-1); i++ ) {
m = idx(1,i);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH) - Node(m, iH));
}
}
if( Imin <= 2 ) {
for( j=1; j<=NLat; j++ ) {
m = idx(j,1);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH) - Node(m, iH));
}
}
if( Jmax >= (NLat-1) ) {
for( i=1; i<=(NLon-1); i++ ) {
m = idx(NLat,i);
Node(m, iM) = Node(m, iM) - Node(m, iR2)*(Node(m+NLat, iH) - Node(m, iH));
}
}
// lattitudial flux update
#pragma omp parallel for default(shared) private(i,j,nod,v1,v2)
for( i=Imin; i<=Imax; i++ ) {
for( j=Jmin; j<=Jmax; j++ ) {
m = idx(j,i);
if( (Node(m, iD)*Node(m+1, iD)) == 0 ) continue;
v1 = Node(m+1, iH) - Node(m, iH);
v2 = Node(m-NLat, iM) + Node(m, iM) + Node(m-NLat+1, iM) + Node(m+1, iM);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*v1 - Node(m, iR5)*v2;
}
}
// open boundaries
if( Imin <= 2 ) {
for( j=1; j<=(NLat-1); j++ ) {
m = idx(j,1);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH) - Node(m, iH));
}
}
if( Jmin <= 2 ) {
for( i=1; i<=NLon; i++ ) {
m = idx(1,i);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH) - Node(m, iH));
}
}
if( Imax >= (NLon-1) ) {
for( j=1; j<=(NLat-1); j++ ) {
m = idx(j,NLon);
Node(m, iN) = Node(m, iN) - Node(m, iR4)*(Node(m+1, iH) - Node(m, iH));
}
}
// calculation area for the next step
if( Imin > 2 ) {
for( enlarge=0, j=Jmin; j<=Jmax; j++ ) {
if( fabs(Node(idx(j,Imin+2), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Imin--; if( Imin < 2 ) Imin = 2; }
}
if( Imax < (NLon-1) ) {
for( enlarge=0, j=Jmin; j<=Jmax; j++ ) {
if( fabs(Node(idx(j,Imax-2), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Imax++; if( Imax > (NLon-1) ) Imax = NLon-1; }
}
if( Jmin > 2 ) {
for( enlarge=0, i=Imin; i<=Imax; i++ ) {
if( fabs(Node(idx(Jmin+2,i), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Jmin--; if( Jmin < 2 ) Jmin = 2; }
}
if( Jmax < (NLat-1) ) {
for( enlarge=0, i=Imin; i<=Imax; i++ ) {
if( fabs(Node(idx(Jmax-2,i), iH)) > Par.sshClipThreshold ) { enlarge = 1; break; }
}
if( enlarge ) { Jmax++; if( Jmax > (NLat-1) ) Jmax = NLat-1; }
}
return 0;
}