Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
S
SWE
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Gaurav Kukreja
SWE
Commits
018806e2
Commit
018806e2
authored
Jul 13, 2012
by
breuera
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added ASAGI and the netCDF-writer.
parent
0f9dfaf3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
180 additions
and
34 deletions
+180
-34
swe_mpi.cpp
src/examples/swe_mpi.cpp
+71
-6
swe_wavepropagation.cpp
src/examples/swe_wavepropagation.cpp
+93
-8
SWE_AsagiScenario.hpp
src/scenarios/SWE_AsagiScenario.hpp
+16
-20
No files found.
src/examples/swe_mpi.cpp
View file @
018806e2
...
@@ -23,21 +23,34 @@
...
@@ -23,21 +23,34 @@
*
*
* @section DESCRIPTION
* @section DESCRIPTION
*
*
*
Very basic setting of SWE, which uses a wave propagation solver and an artificial scenario on a single block
.
*
Setting of SWE, which uses a wave propagation solver and an artificial or ASAGI scenario on multiple blocks
.
*/
*/
#include <mpi.h>
#include <mpi.h>
#include "../tools/help.hh"
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstdlib>
#include <string>
#include <string>
#include "../tools/help.hh"
#include "../SWE_Block.hh"
#include "../SWE_Block.hh"
#ifndef CUDA
#ifndef CUDA
#include "../SWE_WavePropagationBlock.hh"
#include "../SWE_WavePropagationBlock.hh"
#else
#else
#include "../SWE_WavePropagationBlockCuda.hh"
#include "../SWE_WavePropagationBlockCuda.hh"
#endif
#endif
#ifdef WRITENETCDF
#include "../tools/NetCdfWriter.hh"
#endif
#ifdef ASAGI
#include "../scenarios/SWE_AsagiScenario.hpp"
#else
#include "../scenarios/SWE_simple_scenarios.h"
#include "../scenarios/SWE_simple_scenarios.h"
#endif
#ifdef READXML
#ifdef READXML
#include "../tools/CXMLConfig.hpp"
#include "../tools/CXMLConfig.hpp"
...
@@ -136,6 +149,7 @@ int main( int argc, char** argv ) {
...
@@ -136,6 +149,7 @@ int main( int argc, char** argv ) {
// read xml file
// read xml file
#ifdef READXML
#ifdef READXML
assert
(
false
);
//TODO: not implemented.
if
(
argc
!=
2
)
{
if
(
argc
!=
2
)
{
l_sweLogger
.
printString
(
"Aborting. Please provide a proper input file."
);
l_sweLogger
.
printString
(
"Aborting. Please provide a proper input file."
);
l_sweLogger
.
printString
(
"Example: ./SWE_gnu_debug_none_augrie config.xml"
);
l_sweLogger
.
printString
(
"Example: ./SWE_gnu_debug_none_augrie config.xml"
);
...
@@ -169,8 +183,34 @@ int main( int argc, char** argv ) {
...
@@ -169,8 +183,34 @@ int main( int argc, char** argv ) {
l_blockPositionX
=
l_mpiRank
/
l_blocksY
;
l_blockPositionX
=
l_mpiRank
/
l_blocksY
;
l_blockPositionY
=
l_mpiRank
%
l_blocksY
;
l_blockPositionY
=
l_mpiRank
%
l_blocksY
;
#ifdef ASAGI
/*
* Pixel node registration used [Cartesian grid]
* Grid file format: nf = GMT netCDF format (float) (COARDS-compliant)
* x_min: -500000 x_max: 6500000 x_inc: 500 name: x nx: 14000
* y_min: -2500000 y_max: 1500000 y_inc: 500 name: y ny: 8000
* z_min: -6.48760175705 z_max: 16.1780223846 name: z
* scale_factor: 1 add_offset: 0
* mean: 0.00217145586762 stdev: 0.245563641735 rms: 0.245573241263
*/
//simulation area
float
simulationArea
[
4
];
simulationArea
[
0
]
=
-
450000
;
simulationArea
[
1
]
=
6450000
;
simulationArea
[
2
]
=
-
2450000
;
simulationArea
[
3
]
=
1450000
;
// scenarios::Asagi scene( "/naslx/ptmp/2/di56dok/data/tohoku_gebco_ucsb3_500m_hawaii_bath.nc",
// "/naslx/ptmp/2/di56dok/data/tohoku_gebco_ucsb3_500m_hawaii_displ.nc",
// (float) 300., simulationArea);
SWE_AsagiScenario
l_scenario
(
"/work/breuera/workspace/geo_information/output/tohoku_gebco_ucsb3_500m_hawaii_bath.nc"
,
"/work/breuera/workspace/geo_information/output/tohoku_gebco_ucsb3_500m_hawaii_displ.nc"
,
(
float
)
14400.
,
simulationArea
,
true
);
#else
// create a simple artificial scenario
// create a simple artificial scenario
SWE_BathymetryDamBreakScenario
l_scenario
;
SWE_BathymetryDamBreakScenario
l_scenario
;
#endif
//! number of checkpoints for visualization (at each checkpoint in time, an output file is written).
//! number of checkpoints for visualization (at each checkpoint in time, an output file is written).
int
l_numberOfCheckPoints
=
40
;
int
l_numberOfCheckPoints
=
40
;
...
@@ -218,7 +258,7 @@ int main( int argc, char** argv ) {
...
@@ -218,7 +258,7 @@ int main( int argc, char** argv ) {
#endif
#endif
// initialize the wave propgation block
// initialize the wave propgation block
l_wavePropgationBlock
.
initScenario
(
l_scenario
);
l_wavePropgationBlock
.
initScenario
(
l_scenario
,
true
);
//! time when the simulation ends.
//! time when the simulation ends.
float
l_endSimulation
=
l_scenario
.
endSimulation
();
float
l_endSimulation
=
l_scenario
.
endSimulation
();
...
@@ -330,8 +370,27 @@ int main( int argc, char** argv ) {
...
@@ -330,8 +370,27 @@ int main( int argc, char** argv ) {
// write the output at time zero
// write the output at time zero
l_sweLogger
.
printOutputTime
(
0
);
l_sweLogger
.
printOutputTime
(
0
);
#ifdef WRITENETCDF
//boundary size of the ghost layers
int
l_boundarySize
[
4
];
l_boundarySize
[
0
]
=
l_boundarySize
[
1
]
=
l_boundarySize
[
2
]
=
l_boundarySize
[
3
]
=
1
;
//construct a NetCdfWriter
std
::
string
l_fileName
=
generateFileName
(
l_baseName
,
l_blockPositionX
,
l_blockPositionY
);
io
::
NetCdfWriter
l_netCdfWriter
(
l_fileName
,
l_nXLocal
,
l_nYLocal
);
//create the netCDF-file
l_netCdfWriter
.
createNetCdfFile
(
l_dX
,
l_dY
,
l_originX
,
l_originY
);
l_netCdfWriter
.
writeBathymetry
(
l_wavePropgationBlock
.
getBathymetry
(),
l_boundarySize
);
l_netCdfWriter
.
writeUnknowns
(
l_wavePropgationBlock
.
getWaterHeight
(),
l_wavePropgationBlock
.
getDischarge_hu
(),
l_wavePropgationBlock
.
getDischarge_hv
(),
l_boundarySize
,
(
float
)
0.
);
#else
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
0
,
l_blockPositionX
,
l_blockPositionY
),
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
0
,
l_blockPositionX
,
l_blockPositionY
),
l_nXLocal
*
l_blockPositionX
,
l_nYLocal
*
l_blockPositionY
);
l_nXLocal
*
l_blockPositionX
,
l_nYLocal
*
l_blockPositionY
);
#endif
/**
/**
...
@@ -352,7 +411,6 @@ int main( int argc, char** argv ) {
...
@@ -352,7 +411,6 @@ int main( int argc, char** argv ) {
// do time steps until next checkpoint is reached
// do time steps until next checkpoint is reached
while
(
l_t
<
l_checkPoints
[
c
]
)
{
while
(
l_t
<
l_checkPoints
[
c
]
)
{
// exchange ghost and copy layers
// exchange ghost and copy layers
l_sweLogger
.
printString
(
"Exchanging ghost and copy layers."
);
exchangeLeftRightGhostLayers
(
l_leftNeighborRank
,
l_leftInflow
,
l_leftOutflow
,
exchangeLeftRightGhostLayers
(
l_leftNeighborRank
,
l_leftInflow
,
l_leftOutflow
,
l_rightNeighborRank
,
l_rightInflow
,
l_rightOutflow
,
l_rightNeighborRank
,
l_rightInflow
,
l_rightOutflow
,
l_mpiCol
);
l_mpiCol
);
...
@@ -364,7 +422,7 @@ int main( int argc, char** argv ) {
...
@@ -364,7 +422,7 @@ int main( int argc, char** argv ) {
// reset the cpu clock
// reset the cpu clock
l_sweLogger
.
resetCpuClockToCurrentTime
();
l_sweLogger
.
resetCpuClockToCurrentTime
();
// set values in ghost cells
:
// set values in ghost cells
l_wavePropgationBlock
.
setGhostLayer
();
l_wavePropgationBlock
.
setGhostLayer
();
// compute numerical flux on each edge
// compute numerical flux on each edge
...
@@ -396,9 +454,16 @@ int main( int argc, char** argv ) {
...
@@ -396,9 +454,16 @@ int main( int argc, char** argv ) {
// print current simulation time
// print current simulation time
l_sweLogger
.
printOutputTime
(
l_t
);
l_sweLogger
.
printOutputTime
(
l_t
);
// write vtk output
// write output
#ifdef WRITENETCDF
l_netCdfWriter
.
writeUnknowns
(
l_wavePropgationBlock
.
getWaterHeight
(),
l_wavePropgationBlock
.
getDischarge_hu
(),
l_wavePropgationBlock
.
getDischarge_hv
(),
l_boundarySize
,
l_t
);
#else
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
c
,
l_blockPositionX
,
l_blockPositionY
),
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
c
,
l_blockPositionX
,
l_blockPositionY
),
l_blockPositionX
*
l_nXLocal
,
l_blockPositionY
*
l_nYLocal
);
l_blockPositionX
*
l_nXLocal
,
l_blockPositionY
*
l_nYLocal
);
#endif
}
}
/**
/**
...
...
src/examples/swe_wavepropagation.cpp
View file @
018806e2
...
@@ -23,21 +23,35 @@
...
@@ -23,21 +23,35 @@
*
*
* @section DESCRIPTION
* @section DESCRIPTION
*
*
*
Very basic setting of SWE, which uses a wave propagation solver and an artificial
scenario on a single block.
*
Basic setting of SWE, which uses a wave propagation solver and an artificial or ASAGI
scenario on a single block.
*/
*/
#include
"../tools/help.hh"
#include
<cassert>
#include <cstdlib>
#include <cstdlib>
#include <string>
#include <string>
#include "../tools/help.hh"
#include "../SWE_Block.hh"
#include "../SWE_Block.hh"
#ifndef CUDA
#ifndef CUDA
#include "../SWE_WavePropagationBlock.hh"
#include "../SWE_WavePropagationBlock.hh"
#else
#else
#include "../SWE_WavePropagationBlockCuda.hh"
#include "../SWE_WavePropagationBlockCuda.hh"
#endif
#endif
#ifdef WRITENETCDF
#include "../tools/NetCdfWriter.hh"
#endif
#ifdef ASAGI
#include "../scenarios/SWE_AsagiScenario.hpp"
#else
#include "../scenarios/SWE_simple_scenarios.h"
#include "../scenarios/SWE_simple_scenarios.h"
#include "../tools/Logger.hpp"
#endif
#ifdef READXML
#include "../tools/CXMLConfig.hpp"
#endif
#ifndef STATICLOGGER
#ifndef STATICLOGGER
#define STATICLOGGER
#define STATICLOGGER
...
@@ -53,12 +67,14 @@ int main( int argc, char** argv ) {
...
@@ -53,12 +67,14 @@ int main( int argc, char** argv ) {
* Initialization.
* Initialization.
*/
*/
// check if the necessary command line input parameters are given
// check if the necessary command line input parameters are given
#ifndef READXML
if
(
argc
!=
4
)
{
if
(
argc
!=
4
)
{
std
::
cout
<<
"Aborting ... please provide proper input parameters."
<<
std
::
endl
std
::
cout
<<
"Aborting ... please provide proper input parameters."
<<
std
::
endl
<<
"Example: ./SWE_parallel 200 300 /work/openmp_out"
<<
std
::
endl
<<
"Example: ./SWE_parallel 200 300 /work/openmp_out"
<<
std
::
endl
<<
"
\t
for a single block of size 200 * 300"
<<
std
::
endl
;
<<
"
\t
for a single block of size 200 * 300"
<<
std
::
endl
;
return
1
;
return
1
;
}
}
#endif
//! number of grid cells in x- and y-direction.
//! number of grid cells in x- and y-direction.
int
l_nX
,
l_nY
;
int
l_nX
,
l_nY
;
...
@@ -67,15 +83,58 @@ int main( int argc, char** argv ) {
...
@@ -67,15 +83,58 @@ int main( int argc, char** argv ) {
std
::
string
l_baseName
;
std
::
string
l_baseName
;
// read command line parameters
// read command line parameters
#ifndef READXML
l_nY
=
l_nX
=
atoi
(
argv
[
1
]);
l_nY
=
l_nX
=
atoi
(
argv
[
1
]);
l_nY
=
atoi
(
argv
[
2
]);
l_nY
=
atoi
(
argv
[
2
]);
l_baseName
=
std
::
string
(
argv
[
3
]);
l_baseName
=
std
::
string
(
argv
[
3
]);
#endif
//create a simple artificial scenario
// read xml file
#ifdef READXML
assert
(
false
);
//TODO: not implemented.
if
(
argc
!=
2
)
{
s_sweLogger
.
printString
(
"Aborting. Please provide a proper input file."
);
s_sweLogger
.
printString
(
"Example: ./SWE_gnu_debug_none_augrie config.xml"
);
return
1
;
}
s_sweLogger
.
printString
(
"Reading xml-file."
);
std
::
string
l_xmlFile
=
std
::
string
(
argv
[
1
]);
s_sweLogger
.
printString
(
l_xmlFile
);
CXMLConfig
l_xmlConfig
;
l_xmlConfig
.
loadConfig
(
l_xmlFile
.
c_str
());
#endif
#ifdef ASAGI
/* Information about the example bathymetry grid (tohoku_gebco_ucsb3_500m_hawaii_bath.nc):
*
* Pixel node registration used [Cartesian grid]
* Grid file format: nf = GMT netCDF format (float) (COARDS-compliant)
* x_min: -500000 x_max: 6500000 x_inc: 500 name: x nx: 14000
* y_min: -2500000 y_max: 1500000 y_inc: 500 name: y ny: 8000
* z_min: -6.48760175705 z_max: 16.1780223846 name: z
* scale_factor: 1 add_offset: 0
* mean: 0.00217145586762 stdev: 0.245563641735 rms: 0.245573241263
*/
//simulation area
float
simulationArea
[
4
];
simulationArea
[
0
]
=
-
450000
;
simulationArea
[
1
]
=
6450000
;
simulationArea
[
2
]
=
-
2450000
;
simulationArea
[
3
]
=
1450000
;
SWE_AsagiScenario
l_scenario
(
"/work/breuera/workspace/geo_information/output/tohoku_gebco_ucsb3_500m_hawaii_bath.nc"
,
"/work/breuera/workspace/geo_information/output/tohoku_gebco_ucsb3_500m_hawaii_displ.nc"
,
(
float
)
28800.
,
simulationArea
,
true
);
#else
// create a simple artificial scenario
SWE_BathymetryDamBreakScenario
l_scenario
;
SWE_BathymetryDamBreakScenario
l_scenario
;
#endif
//! number of checkpoints for visualization (at each checkpoint in time, an output file is written).
//! number of checkpoints for visualization (at each checkpoint in time, an output file is written).
int
l_numberOfCheckPoints
=
4
0
;
int
l_numberOfCheckPoints
=
2
0
;
//! size of a single cell in x- and y-direction
//! size of a single cell in x- and y-direction
float
l_dX
,
l_dY
;
float
l_dX
,
l_dY
;
...
@@ -116,8 +175,27 @@ int main( int argc, char** argv ) {
...
@@ -116,8 +175,27 @@ int main( int argc, char** argv ) {
l_checkPoints
[
cp
]
=
cp
*
(
l_endSimulation
/
l_numberOfCheckPoints
);
l_checkPoints
[
cp
]
=
cp
*
(
l_endSimulation
/
l_numberOfCheckPoints
);
}
}
// write the output at time zero
// write the output at time zero
s_sweLogger
.
printOutputTime
((
float
)
0.
);
#ifdef WRITENETCDF
//boundary size of the ghost layers
int
l_boundarySize
[
4
];
l_boundarySize
[
0
]
=
l_boundarySize
[
1
]
=
l_boundarySize
[
2
]
=
l_boundarySize
[
3
]
=
1
;
//construct a NetCdfWriter
std
::
string
l_fileName
=
l_baseName
;
io
::
NetCdfWriter
l_netCdfWriter
(
l_fileName
,
l_nX
,
l_nY
);
//create the netCDF-file
l_netCdfWriter
.
createNetCdfFile
(
l_dX
,
l_dY
,
l_originX
,
l_originY
);
l_netCdfWriter
.
writeBathymetry
(
l_wavePropgationBlock
.
getBathymetry
(),
l_boundarySize
);
l_netCdfWriter
.
writeUnknowns
(
l_wavePropgationBlock
.
getWaterHeight
(),
l_wavePropgationBlock
.
getDischarge_hu
(),
l_wavePropgationBlock
.
getDischarge_hv
(),
l_boundarySize
,
(
float
)
0.
);
#else
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
0
,
0
,
0
),
l_nX
,
l_nY
);
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
0
,
0
,
0
),
l_nX
,
l_nY
);
#endif
/**
/**
...
@@ -159,11 +237,18 @@ int main( int argc, char** argv ) {
...
@@ -159,11 +237,18 @@ int main( int argc, char** argv ) {
// update the cpu time in the logger
// update the cpu time in the logger
s_sweLogger
.
updateCpuTime
();
s_sweLogger
.
updateCpuTime
();
// print current simulation time
// print current simulation time
of the output
s_sweLogger
.
printOutputTime
(
l_t
);
s_sweLogger
.
printOutputTime
(
l_t
);
// write vtk output
// write output
#ifdef WRITENETCDF
l_netCdfWriter
.
writeUnknowns
(
l_wavePropgationBlock
.
getWaterHeight
(),
l_wavePropgationBlock
.
getDischarge_hu
(),
l_wavePropgationBlock
.
getDischarge_hv
(),
l_boundarySize
,
l_t
);
#else
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
c
,
0
,
0
),
l_nX
,
l_nY
);
l_wavePropgationBlock
.
writeVTKFileXML
(
generateFileName
(
l_baseName
,
c
,
0
,
0
),
l_nX
,
l_nY
);
#endif
}
}
/**
/**
...
@@ -173,7 +258,7 @@ int main( int argc, char** argv ) {
...
@@ -173,7 +258,7 @@ int main( int argc, char** argv ) {
s_sweLogger
.
printStatisticsMessage
();
s_sweLogger
.
printStatisticsMessage
();
// print the cpu time
// print the cpu time
s_sweLogger
.
printCpuTime
(
"CPU/GPU time"
);
s_sweLogger
.
printCpuTime
();
// print the wall clock time (includes plotting)
// print the wall clock time (includes plotting)
s_sweLogger
.
printWallClockTime
(
time
(
NULL
));
s_sweLogger
.
printWallClockTime
(
time
(
NULL
));
...
...
src/scenarios/SWE_AsagiScenario.hpp
View file @
018806e2
...
@@ -25,19 +25,15 @@
...
@@ -25,19 +25,15 @@
* Access to bathymetry and displacement files with ASAGI.
* Access to bathymetry and displacement files with ASAGI.
*/
*/
#ifndef
ASAGI
_HPP_
#ifndef
SWEASAGISCENARIO
_HPP_
#define
ASAGI
_HPP_
#define
SWEASAGISCENARIO
_HPP_
#include <cassert>
#include <cassert>
#include <string>
#include <string>
#include <asagi.h>
#include <asagi.h>
#include "SWE_Scenario.h"
#include "SWE_Scenario.h"
namespace
scenarios
{
class
SWE_AsagiScenario
:
public
SWE_Scenario
{
class
Asagi
;
}
class
scenarios
::
Asagi
:
public
SWE_Scenario
{
//private:
//private:
//! pointer to the Asagi bathymetry grid
//! pointer to the Asagi bathymetry grid
asagi
::
Grid
*
bathymetryGrid
;
asagi
::
Grid
*
bathymetryGrid
;
...
@@ -75,17 +71,17 @@ class scenarios::Asagi: public SWE_Scenario {
...
@@ -75,17 +71,17 @@ class scenarios::Asagi: public SWE_Scenario {
* @param i_displacementFile path to the netCDF-displacement file
* @param i_displacementFile path to the netCDF-displacement file
* @param i_duration time the simulation runs (in seconds)
* @param i_duration time the simulation runs (in seconds)
*/
*/
Asagi
(
const
std
::
string
i_bathymetryFile
,
SWE_AsagiScenario
(
const
std
::
string
i_bathymetryFile
,
const
std
::
string
i_displacementFile
,
const
std
::
string
i_displacementFile
,
const
float
i_duration
,
const
float
i_duration
,
const
float
i_simulationArea
[
4
],
const
float
i_simulationArea
[
4
],
const
bool
i_dynamicDisplacement
=
false
)
:
const
bool
i_dynamicDisplacement
=
false
)
:
dynamicDisplacement
(
i_dynamicDisplacement
),
dynamicDisplacement
(
i_dynamicDisplacement
),
duration
(
i_duration
)
{
duration
(
i_duration
)
{
//create the bathymetry grid
//create the bathymetry grid
bathymetryGrid
=
asagi
::
Grid
::
create
(
asagi
::
Grid
::
FLOAT
);
bathymetryGrid
=
asagi
::
Grid
::
create
(
asagi
::
Grid
::
FLOAT
);
//create the displacement grid
//create the displacement grid
displacementGrid
=
asagi
::
Grid
::
create
(
asagi
::
Grid
::
FLOAT
);
displacementGrid
=
asagi
::
Grid
::
create
(
asagi
::
Grid
::
FLOAT
);
int
l_asagiOpen
=
bathymetryGrid
->
open
(
i_bathymetryFile
.
c_str
());
int
l_asagiOpen
=
bathymetryGrid
->
open
(
i_bathymetryFile
.
c_str
());
//open the bathymetry grid
//open the bathymetry grid
...
@@ -154,7 +150,7 @@ class scenarios::Asagi: public SWE_Scenario {
...
@@ -154,7 +150,7 @@ class scenarios::Asagi: public SWE_Scenario {
}
}
virtual
~
Asagi
()
{
virtual
~
SWE_AsagiScenario
()
{
}
}
void
deleteGrids
()
{
void
deleteGrids
()
{
...
@@ -287,4 +283,4 @@ class scenarios::Asagi: public SWE_Scenario {
...
@@ -287,4 +283,4 @@ class scenarios::Asagi: public SWE_Scenario {
};
};
};
};
#endif
/*
ASAGI
_HPP_ */
#endif
/*
SWEASAGISCENARIO
_HPP_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment