IAP GITLAB
Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
C
corsika
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Issue analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Pranav Sampathkumar
corsika
Commits
5a17a776
Commit
5a17a776
authored
4 years ago
by
Maximilian Reininghaus
Committed by
Ralf Ulrich
4 years ago
Browse files
Options
Downloads
Patches
Plain Diff
refactored
parent
3ab30bbd
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
Documentation/Examples/vertical_EAS.cc
+3
-11
3 additions, 11 deletions
Documentation/Examples/vertical_EAS.cc
Processes/InteractionCounter/InteractionCounter.h
+175
-122
175 additions, 122 deletions
Processes/InteractionCounter/InteractionCounter.h
with
178 additions
and
133 deletions
Documentation/Examples/vertical_EAS.cc
+
3
−
11
View file @
5a17a776
...
@@ -222,17 +222,9 @@ int main(int argc, char** argv) {
...
@@ -222,17 +222,9 @@ int main(int argc, char** argv) {
cout
<<
"total dEdX energy (GeV): "
<<
eLoss
.
GetTotal
()
/
1
_GeV
<<
endl
cout
<<
"total dEdX energy (GeV): "
<<
eLoss
.
GetTotal
()
/
1
_GeV
<<
endl
<<
"relative difference (%): "
<<
eLoss
.
GetTotal
()
/
E0
*
100
<<
endl
;
<<
"relative difference (%): "
<<
eLoss
.
GetTotal
()
/
E0
*
100
<<
endl
;
auto
const
cms_hists
=
auto
const
hists
=
sibyllCounted
.
GetHistogram
()
+
sibyllNucCounted
.
GetHistogram
();
*
std
::
get
<
0
>
(
sibyllCounted
.
CMSHists
())
+
*
std
::
get
<
0
>
(
sibyllNucCounted
.
CMSHists
());
hists
.
saveLab
(
"inthist_lab.txt"
);
auto
const
lab_hists
=
hists
.
saveCMS
(
"inthist_cms.txt"
);
*
std
::
get
<
0
>
(
sibyllCounted
.
labHists
())
+
*
std
::
get
<
0
>
(
sibyllNucCounted
.
labHists
());
process
::
interaction_counter
::
saveHist
(
cms_hists
,
*
std
::
get
<
1
>
(
sibyllNucCounted
.
CMSHists
()),
"intcount_hist_cms.txt"
,
"center-of-mass system"
);
process
::
interaction_counter
::
saveHist
(
lab_hists
,
*
std
::
get
<
1
>
(
sibyllNucCounted
.
labHists
()),
"intcount_hist_lab.txt"
,
"lab system"
);
std
::
ofstream
finish
(
"finished"
);
std
::
ofstream
finish
(
"finished"
);
finish
<<
"run completed without error"
<<
std
::
endl
;
finish
<<
"run completed without error"
<<
std
::
endl
;
...
...
This diff is collapsed.
Click to expand it.
Processes/InteractionCounter/InteractionCounter.h
+
175
−
122
View file @
5a17a776
...
@@ -23,51 +23,43 @@
...
@@ -23,51 +23,43 @@
#include
<map>
#include
<map>
#include
<utility>
#include
<utility>
template
<
typename
TKey
,
typename
TVal
>
auto
operator
+=
(
std
::
map
<
TKey
,
TVal
>&
a
,
std
::
map
<
TKey
,
TVal
>
b
)
{
a
.
merge
(
b
);
for
(
auto
const
&
[
id
,
hist
]
:
b
)
{
a
[
id
]
+=
hist
;
}
return
a
;
}
namespace
corsika
::
process
::
interaction_counter
{
namespace
corsika
::
process
::
interaction_counter
{
/*!
using
hist_type
=
decltype
(
boost
::
histogram
::
make_histogram
(
* Wrapper around an InteractionProcess that fills histograms of the number
std
::
declval
<
boost
::
histogram
::
axis
::
integer
<
particles
::
CodeIntType
>>
(),
* of calls to DoInteraction() binned in projectile energy (both in
std
::
declval
<
boost
::
histogram
::
axis
::
regular
<
* lab and center-of-mass frame) and species
double
,
boost
::
histogram
::
axis
::
transform
::
log
>>
()));
*/
template
<
class
TCountedProcess
>
using
nucl_hist_type
=
decltype
(
boost
::
histogram
::
make_histogram
(
class
InteractionCounter
std
::
declval
<
boost
::
histogram
::
axis
::
regular
<
:
public
InteractionProcess
<
InteractionCounter
<
TCountedProcess
>>
{
double
,
boost
::
histogram
::
axis
::
transform
::
log
>>
()));
using
nuclear_hist_type
=
std
::
map
<
int32_t
,
nucl_hist_type
>
;
class
InteractionHistogram
{
static
auto
constexpr
lower_edge_cms
=
1.
,
upper_edge_cms
=
1e8
;
// GeV sqrt s
static
auto
constexpr
lower_edge_cms
=
1.
,
upper_edge_cms
=
1e8
;
// GeV sqrt s
static
auto
constexpr
lower_edge_lab
=
1.
,
upper_edge_lab
=
1e12
;
// GeV lab
static
auto
constexpr
lower_edge_lab
=
1.
,
upper_edge_lab
=
1e12
;
// GeV lab
static
auto
constexpr
num_bins_lab
=
120
,
num_bins_cms
=
80
;
static
auto
constexpr
num_bins_lab
=
120
,
num_bins_cms
=
80
;
static
auto
constexpr
numIds
=
static
auto
constexpr
numIds
=
static_cast
<
particles
::
CodeIntType
>
(
particles
::
Code
::
LastParticle
);
static_cast
<
particles
::
CodeIntType
>
(
particles
::
Code
::
LastParticle
);
using
hist_type_count_cms
=
decltype
(
boost
::
histogram
::
make_histogram
(
hist_type
interaction_histogram_cms_
;
boost
::
histogram
::
axis
::
integer
<
particles
::
CodeIntType
>
(
0
,
numIds
),
hist_type
interaction_histogram_lab_
;
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
transform
::
log
>
(
num_bins_cms
,
lower_edge_cms
,
upper_edge_cms
)));
using
hist_type_count_lab
=
decltype
(
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
axis
::
integer
<
particles
::
CodeIntType
>
(
0
,
numIds
),
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
transform
::
log
>
(
num_bins_lab
,
lower_edge_lab
,
upper_edge_lab
)));
static_assert
(
std
::
is_same_v
<
hist_type_count_cms
,
hist_type_count_lab
>
);
using
nucl_hist_type
=
decltype
(
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
transform
::
log
>
(
num_bins_lab
,
lower_edge_lab
,
upper_edge_lab
)));
TCountedProcess
&
process_
;
hist_type_count_cms
interaction_histogram_cms_
;
hist_type_count_lab
interaction_histogram_lab_
;
/*!
/*!
* These maps map PDG nucei codes to their corresponding interaction histograms
* These maps map PDG nuc
l
ei codes to their corresponding interaction histograms
*/
*/
std
::
map
<
int32_t
,
nucl_hist_type
>
nucl
I
nt
H
ist
L
ab
,
nucl
I
nt
H
ist
CMS
;
nucl
ear
_hist_type
nucl
ear_i
nt
h
ist
_l
ab
_
,
nucl
ear_i
nt
h
ist
_cms_
;
public:
public:
InteractionCounter
(
TCountedProcess
&
process
)
InteractionHistogram
()
:
process_
(
process
)
:
interaction_histogram_cms_
{
boost
::
histogram
::
make_histogram
(
,
interaction_histogram_cms_
{
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
axis
::
integer
<
short
>
(
0
,
numIds
),
boost
::
histogram
::
axis
::
integer
<
short
>
(
0
,
numIds
),
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
transform
::
log
>
(
boost
::
histogram
::
axis
::
transform
::
log
>
(
...
@@ -78,36 +70,28 @@ namespace corsika::process::interaction_counter {
...
@@ -78,36 +70,28 @@ namespace corsika::process::interaction_counter {
boost
::
histogram
::
axis
::
transform
::
log
>
(
boost
::
histogram
::
axis
::
transform
::
log
>
(
num_bins_lab
,
lower_edge_lab
,
upper_edge_lab
))}
{}
num_bins_lab
,
lower_edge_lab
,
upper_edge_lab
))}
{}
template
<
typename
TProjectile
>
void
fill
(
particles
::
Code
projectile_id
,
units
::
si
::
HEPEnergyType
lab_energy
,
auto
DoInteraction
(
TProjectile
&
projectile
)
{
units
::
si
::
HEPEnergyType
mass_target
,
int
A
=
0
,
int
Z
=
0
)
{
using
namespace
units
::
si
;
using
namespace
units
::
si
;
auto
const
massNumber
=
projectile
.
GetNode
()
->
GetModelProperties
()
.
GetNuclearComposition
()
.
GetAverageMassNumber
();
auto
const
massTarget
=
massNumber
*
ConvertSIToHEP
(
units
::
constants
::
u
);
auto
const
massProjectile
=
projectile
.
GetMass
();
auto
const
sqrtS
=
sqrt
(
massProjectile
*
massProjectile
+
massTarget
*
massTarget
+
2
*
massProjectile
*
massTarget
);
if
(
projectile
.
GetPID
()
==
corsika
::
particles
::
Code
::
Nucleus
)
{
std
::
cerr
<<
"NUCLEUS "
<<
projectile
.
GetEnergy
()
<<
" "
<<
projectile
.
GetNuclearA
()
<<
" "
<<
projectile
.
GetNuclearZ
()
<<
std
::
endl
;
int
const
A
=
projectile
.
GetNuclearA
();
int
const
Z
=
projectile
.
GetNuclearZ
();
int32_t
const
pdg
=
1'000'000'000l
+
Z
*
10'000l
+
A
*
10l
;
if
(
nuclIntHistCMS
.
count
(
pdg
)
==
0
)
{
if
(
projectile_id
==
particles
::
Code
::
Nucleus
)
{
std
::
cerr
<<
"NUCLEUS "
<<
lab_energy
<<
" "
<<
A
<<
" "
<<
Z
<<
std
::
endl
;
auto
const
sqrtS
=
sqrt
(
A
*
A
*
(
units
::
constants
::
nucleonMass
*
units
::
constants
::
nucleonMass
)
+
mass_target
*
mass_target
+
2
*
lab_energy
*
mass_target
);
nuclIntHistLab
.
emplace
(
int32_t
const
pdg
=
1'000'000'000l
+
Z
*
10'000l
+
A
*
10l
;
if
(
nuclear_inthist_cms_
.
count
(
pdg
)
==
0
)
{
nuclear_inthist_lab_
.
emplace
(
pdg
,
pdg
,
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
transform
::
log
>
(
boost
::
histogram
::
axis
::
transform
::
log
>
(
num_bins_lab
,
lower_edge_lab
,
upper_edge_lab
)));
num_bins_lab
,
lower_edge_lab
,
upper_edge_lab
)));
nucl
I
nt
H
ist
CMS
.
emplace
(
nucl
ear_i
nt
h
ist
_cms_
.
emplace
(
pdg
,
pdg
,
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
make_histogram
(
boost
::
histogram
::
axis
::
regular
<
double
,
boost
::
histogram
::
axis
::
regular
<
double
,
...
@@ -115,99 +99,168 @@ namespace corsika::process::interaction_counter {
...
@@ -115,99 +99,168 @@ namespace corsika::process::interaction_counter {
num_bins_cms
,
lower_edge_cms
,
upper_edge_cms
)));
num_bins_cms
,
lower_edge_cms
,
upper_edge_cms
)));
}
}
nucl
I
nt
H
ist
L
ab
[
pdg
](
projectile
.
GetE
nergy
()
/
1
_GeV
);
nucl
ear_i
nt
h
ist
_l
ab
_
[
pdg
](
lab_e
nergy
/
1
_GeV
);
nucl
I
nt
H
ist
CMS
[
pdg
](
sqrtS
/
1
_GeV
);
nucl
ear_i
nt
h
ist
_cms_
[
pdg
](
sqrtS
/
1
_GeV
);
}
else
{
}
else
{
auto
const
projectile_mass
=
particles
::
GetMass
(
projectile_id
);
auto
const
sqrtS
=
sqrt
(
projectile_mass
*
projectile_mass
+
mass_target
*
mass_target
+
2
*
lab_energy
*
mass_target
);
interaction_histogram_cms_
(
interaction_histogram_cms_
(
static_cast
<
corsika
::
particles
::
CodeIntType
>
(
projectile
.
GetPID
()),
static_cast
<
corsika
::
particles
::
CodeIntType
>
(
projectile_id
),
sqrtS
/
1
_GeV
);
sqrtS
/
1
_GeV
);
interaction_histogram_lab_
(
interaction_histogram_lab_
(
static_cast
<
corsika
::
particles
::
CodeIntType
>
(
projectile
.
GetPID
()
),
static_cast
<
corsika
::
particles
::
CodeIntType
>
(
projectile
_id
),
projectile
.
GetE
nergy
()
/
1
_GeV
);
lab_e
nergy
/
1
_GeV
);
}
}
}
return
process_
.
DoInteraction
(
projectile
);
auto
CMSHists
()
const
{
return
std
::
pair
<
decltype
(
interaction_histogram_cms_
)
const
&
,
decltype
(
nuclear_inthist_cms_
)
const
&>
{
interaction_histogram_cms_
,
nuclear_inthist_cms_
};
}
}
void
Init
()
{
process_
.
Init
();
}
auto
labHists
()
const
{
return
std
::
pair
<
decltype
(
interaction_histogram_lab_
)
const
&
,
decltype
(
nuclear_inthist_lab_
)
const
&>
(
interaction_histogram_lab_
,
nuclear_inthist_lab_
);
}
template
<
typename
TParticle
>
void
saveLab
(
std
::
string
const
&
filename
)
const
{
auto
GetInteractionLength
(
TParticle
const
&
particle
)
const
{
save
(
interaction_histogram_lab_
,
nuclear_inthist_lab_
,
filename
,
"lab system"
);
return
process_
.
GetInteractionLength
(
particle
);
}
}
auto
CMSHists
()
const
{
void
saveCMS
(
std
::
string
const
&
filename
)
const
{
return
std
::
make_pair
(
&
interaction_histogram_cms_
,
&
nuclIntHistCMS
);
save
(
interaction_histogram_lab_
,
nuclear_inthist_cms_
,
filename
,
"center-of-mass system"
);
}
}
auto
labHists
()
const
{
auto
&
operator
+=
(
InteractionHistogram
const
&
other
)
{
return
std
::
make_pair
(
&
interaction_histogram_lab_
,
&
nuclIntHistLab
);
interaction_histogram_lab_
+=
other
.
interaction_histogram_lab_
;
interaction_histogram_cms_
+=
other
.
interaction_histogram_cms_
;
nuclear_inthist_lab_
+=
other
.
nuclear_inthist_lab_
;
nuclear_inthist_cms_
+=
other
.
nuclear_inthist_cms_
;
return
*
this
;
}
}
};
/*! Save a histogram into a text file. The \arg comment string is written
auto
operator
+
(
InteractionHistogram
other
)
const
{
* into the header of the text file.
other
.
nuclear_inthist_lab_
+=
nuclear_inthist_lab_
;
* This method is static so that you can sum the histograms of multiple
other
.
nuclear_inthist_cms_
+=
nuclear_inthist_cms_
;
* InteractionProcesses before saving them into the same file.
*/
return
other
;
template
<
typename
T1
>
}
static
void
saveHist
(
T1
const
&
hist
,
std
::
string
const
&
filename
,
std
::
string
const
&
comment
=
""
)
{
private
:
std
::
ofstream
file
;
/*! Save a histogram into a text file. The \arg comment string is written
file
.
open
(
filename
);
* into the header of the text file.
saveHist
(
hist
,
file
,
comment
);
* This method is static so that you can sum the histograms of multiple
}
* InteractionProcesses before saving them into the same file.
*/
template
<
typename
T1
>
static
void
saveHist
(
T1
const
&
hist
,
std
::
ofstream
&
file
,
static
void
saveHist
(
hist_type
const
&
hist
,
std
::
string
const
&
filename
,
std
::
string
const
&
comment
=
""
)
{
std
::
string
const
&
comment
=
""
)
{
auto
const
&
energy_axis
=
hist
.
axis
(
1
);
std
::
ofstream
file
;
file
.
open
(
filename
);
file
<<
"# interaction count histogram ("
<<
comment
<<
")"
<<
std
::
endl
saveHist
(
hist
,
file
,
comment
);
<<
"# "
<<
energy_axis
.
size
()
<<
" bins between "
<<
energy_axis
.
bin
(
0
).
lower
()
}
<<
" and "
<<
energy_axis
.
bin
(
energy_axis
.
size
()
-
1
).
upper
()
<<
" GeV"
<<
std
::
endl
;
static
void
saveHist
(
hist_type
const
&
hist
,
std
::
ofstream
&
file
,
std
::
string
const
&
comment
=
""
)
{
for
(
particles
::
CodeIntType
p
=
0
;
auto
const
&
energy_axis
=
hist
.
axis
(
1
);
p
<
static_cast
<
particles
::
CodeIntType
>
(
particles
::
Code
::
LastParticle
);
++
p
)
{
file
<<
"# interaction count histogram ("
<<
comment
<<
")"
<<
std
::
endl
if
(
auto
pdg
=
static_cast
<
particles
::
PDGCodeType
>
(
<<
"# "
<<
energy_axis
.
size
()
<<
" bins between "
<<
energy_axis
.
bin
(
0
).
lower
()
particles
::
GetPDG
(
static_cast
<
particles
::
Code
>
(
p
)));
<<
" and "
<<
energy_axis
.
bin
(
energy_axis
.
size
()
-
1
).
upper
()
<<
" GeV"
pdg
<
1'000'000'000l
)
{
<<
std
::
endl
;
file
<<
"# "
<<
static_cast
<
particles
::
Code
>
(
p
)
<<
std
::
endl
;
file
<<
pdg
;
for
(
particles
::
CodeIntType
p
=
0
;
for
(
int
i
=
0
;
i
<
energy_axis
.
size
();
++
i
)
{
file
<<
' '
<<
hist
.
at
(
p
,
i
);
}
p
<
static_cast
<
particles
::
CodeIntType
>
(
particles
::
Code
::
LastParticle
);
++
p
)
{
if
(
auto
pdg
=
static_cast
<
particles
::
PDGCodeType
>
(
particles
::
GetPDG
(
static_cast
<
particles
::
Code
>
(
p
)));
pdg
<
1'000'000'000l
)
{
file
<<
"# "
<<
static_cast
<
particles
::
Code
>
(
p
)
<<
std
::
endl
;
file
<<
pdg
;
for
(
int
i
=
0
;
i
<
energy_axis
.
size
();
++
i
)
{
file
<<
' '
<<
hist
.
at
(
p
,
i
);
}
file
<<
std
::
endl
;
}
}
}
static
void
saveHistMap
(
nuclear_hist_type
const
&
histMap
,
std
::
ofstream
&
file
)
{
file
<<
"# nuclei"
<<
std
::
endl
;
for
(
auto
const
&
[
pdg
,
hist
]
:
histMap
)
{
auto
const
num_ebins_nucl
=
hist
.
axis
(
0
).
size
();
file
<<
pdg
<<
' '
;
for
(
int
i
=
0
;
i
<
num_ebins_nucl
;
++
i
)
{
file
<<
' '
<<
hist
.
at
(
i
);
}
file
<<
std
::
endl
;
file
<<
std
::
endl
;
}
}
}
}
}
template
<
typename
THistogramMap
>
/*!
static
void
saveHistMap
(
THistogramMap
const
&
histMap
,
std
::
ofstream
&
file
)
{
* save both the "normal" particle histograms as well as the "nuclear" histograms
file
<<
"# nuclei"
<<
std
::
endl
;
* into the same file
for
(
auto
const
&
[
pdg
,
hist
]
:
histMap
)
{
*/
auto
const
num_ebins_nucl
=
hist
.
axis
(
0
).
size
();
file
<<
pdg
<<
' '
;
static
void
save
(
hist_type
const
&
hist
,
nuclear_hist_type
const
&
histMap
,
for
(
int
i
=
0
;
i
<
num_ebins_nucl
;
++
i
)
{
file
<<
' '
<<
hist
.
at
(
i
);
}
std
::
string
const
&
filename
,
std
::
string
const
&
comment
=
""
)
{
file
<<
std
::
endl
;
std
::
ofstream
file
;
file
.
open
(
filename
);
saveHist
(
hist
,
file
,
comment
);
saveHistMap
(
histMap
,
file
);
}
}
}
}
;
/*!
/*!
* save both the "normal" particle histograms as well as the "nuclear" histograms
* Wrapper around an InteractionProcess that fills histograms of the number
* into the same file
* of calls to DoInteraction() binned in projectile energy (both in
* lab and center-of-mass frame) and species
*/
*/
template
<
class
TCountedProcess
>
class
InteractionCounter
:
public
InteractionProcess
<
InteractionCounter
<
TCountedProcess
>>
{
TCountedProcess
&
process_
;
InteractionHistogram
histogram_
;
public:
InteractionCounter
(
TCountedProcess
&
process
)
:
process_
(
process
)
{}
template
<
typename
T1
,
typename
T2
>
template
<
typename
TProjectile
>
static
void
saveHist
(
T1
const
&
hist
,
T2
const
&
histMap
,
std
::
string
const
&
filename
,
auto
DoInteraction
(
TProjectile
&
projectile
)
{
std
::
string
const
&
comment
=
""
)
{
auto
const
massNumber
=
projectile
.
GetNode
()
std
::
ofstream
file
;
->
GetModelProperties
()
file
.
open
(
filename
);
.
GetNuclearComposition
()
.
GetAverageMassNumber
();
auto
const
massTarget
=
massNumber
*
units
::
constants
::
nucleonMass
;
if
(
auto
const
projectile_id
=
projectile
.
GetPID
();
projectile_id
==
particles
::
Code
::
Nucleus
)
{
auto
const
A
=
projectile
.
GetNuclearA
();
auto
const
Z
=
projectile
.
GetNuclearZ
();
histogram_
.
fill
(
projectile_id
,
projectile
.
GetEnergy
(),
massTarget
,
A
,
Z
);
}
else
{
histogram_
.
fill
(
projectile_id
,
projectile
.
GetEnergy
(),
massTarget
);
}
return
process_
.
DoInteraction
(
projectile
);
}
void
Init
()
{
process_
.
Init
();
}
template
<
typename
TParticle
>
auto
GetInteractionLength
(
TParticle
const
&
particle
)
const
{
return
process_
.
GetInteractionLength
(
particle
);
}
auto
const
&
GetHistogram
()
const
{
return
histogram_
;
}
};
saveHist
(
hist
,
file
,
comment
);
saveHistMap
(
histMap
,
file
);
}
}
// namespace corsika::process::interaction_counter
}
// namespace corsika::process::interaction_counter
#endif
#endif
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment