Skip to content

Commit b37b534

Browse files
authored
Merge pull request #3074 from deslaughter/fastfarm_cpp_vtk
Use C++ to read VTK inflow in AWAE
2 parents a326b65 + 52beb5a commit b37b534

File tree

7 files changed

+4815
-32
lines changed

7 files changed

+4815
-32
lines changed

modules/awae/CMakeLists.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@ if (GENERATE_TYPES)
1717
generate_f90_types(src/AWAE_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/AWAE_Types.f90 -noextrap)
1818
endif()
1919

20+
add_library(awaelib_c STATIC
21+
src/vtk.cpp
22+
)
23+
target_link_libraries(awaelib_c nwtclibs)
24+
2025
add_library(awaelib STATIC
2126
src/AWAE.f90
2227
src/AWAE_IO.f90
2328
src/AWAE_Types.f90
2429
)
25-
target_link_libraries(awaelib ifwlib nwtclibs)
30+
target_link_libraries(awaelib awaelib_c ifwlib nwtclibs)
2631

27-
install(TARGETS awaelib
32+
install(TARGETS awaelib awaelib_c
2833
EXPORT "${CMAKE_PROJECT_NAME}Libraries"
2934
RUNTIME DESTINATION bin
3035
LIBRARY DESTINATION lib

modules/awae/src/AWAE.f90

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,8 @@ subroutine AWAE_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errM
16111611
! File-based ambient wind
16121612
case (1)
16131613

1614-
!$OMP PARALLEL DO DEFAULT(Shared) PRIVATE(nt, i_hl, errStat2, errMsg2) !Private(nt,tm2,tm3)
1614+
!$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(nt, i_hl, errStat2, errMsg2) &
1615+
!$OMP SHARED(p, n_high_low, n, m, errStat, errMsg, AbortErrLev)
16151616
do nt = 1,p%NumTurbines
16161617
do i_hl=0, n_high_low
16171618

modules/awae/src/AWAE_IO.f90

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ MODULE AWAE_IO
2626
use NWTC_Library
2727
use VTK
2828
use AWAE_Types
29-
29+
use iso_c_binding, only: c_char, c_int, c_double, c_float, c_null_char
3030

3131
implicit none
3232

@@ -35,6 +35,23 @@ MODULE AWAE_IO
3535

3636
public :: AWAE_IO_InitGridInfo
3737
public :: ReadLowResWindFile
38+
39+
interface
40+
subroutine ReadVTK_inflow_info(FileName, Desc, dims, origin, gridSpacing, vecLabel, values, read_values, err_stat, err_msg) BIND(C,name='ReadVTK_inflow_info')
41+
use iso_c_binding, only: c_char, c_int, c_double, c_float, c_null_char
42+
implicit none
43+
character(kind=c_char), intent(in) :: FileName(*)
44+
character(kind=c_char), intent(out) :: Desc(1024)
45+
integer(c_int), intent(out) :: dims(3)
46+
real(c_double), intent(out) :: origin(3)
47+
real(c_double), intent(out) :: gridSpacing(3)
48+
character(kind=c_char), intent(out) :: vecLabel(1024)
49+
real(c_float), intent(out) :: values(*)
50+
integer(c_int), intent(in) :: read_values
51+
integer(c_int), intent(out) :: err_stat
52+
character(kind=c_char), intent(out) :: err_msg(1024)
53+
end subroutine
54+
end interface
3855

3956
contains
4057

@@ -91,26 +108,24 @@ end subroutine WriteDisWindFiles
91108
subroutine ReadLowResWindFile(n, p, Vamb_Low, errStat, errMsg)
92109
integer(IntKi), intent(in ) :: n !< Current simulation timestep increment (zero-based)
93110
type(AWAE_ParameterType), intent(in ) :: p !< Parameters
94-
real(SiKi), intent(inout) :: Vamb_Low(:,0:,0:,0:) !< Array which will contain the low resolution grid of ambient wind velocities
111+
real(SiKi), contiguous, intent(inout) :: Vamb_Low(:,0:,0:,0:) !< Array which will contain the low resolution grid of ambient wind velocities
95112
integer(IntKi), intent( out) :: errStat !< Error status of the operation
96113
character(*), intent( out) :: errMsg !< Error message if errStat /= ErrID_None
97114

98-
integer(IntKi) :: dims(3) ! dimension of the 3D grid (nX,nY,nZ)
99-
real(ReKi) :: origin(3) ! the lower-left corner of the 3D grid (X0,Y0,Z0)
100-
real(ReKi) :: gridSpacing(3) ! spacing between grid points in each of the 3 directions (dX,dY,dZ)
101-
integer(IntKi) :: Un ! unit number of opened file
102-
character(1024) :: FileName ! Name of output file
103-
character(1024) :: desc ! Line describing the contents of the file
104-
character(1024) :: vecLabel ! descriptor of the vector data
115+
integer(IntKi) :: dims(3) ! Dimension of the 3D grid (nX,nY,nZ)
116+
real(R8Ki) :: origin(3) ! The lower-left corner of the 3D grid (X0,Y0,Z0)
117+
real(R8Ki) :: gridSpacing(3) ! Spacing between grid points in each of the 3 directions (dX,dY,dZ)
118+
character(kind=c_char) :: FileName(2048) ! Name of output file
119+
character(kind=c_char) :: desc(1024) ! Line describing the contents of the file
120+
character(kind=c_char) :: vecLabel(1024) ! descriptor of the vector data
105121

106122
errStat = ErrID_None
107123
errMsg = ""
108124

109-
FileName = trim(p%WindFilePath)//trim(PathSep)//"Low"//trim(PathSep)//"Amb.t"//trim(Num2LStr(n))//".vtk"
110-
Un = 0; ! Initialization different from -1, important to prevent file closing
111-
call ReadVTK_SP_info(FileName, desc, dims, origin, gridSpacing, vecLabel, Un, ErrStat, ErrMsg)
112-
if (ErrStat >= AbortErrLev) return
113-
call ReadVTK_SP_vectors(FileName, Un, dims, Vamb_Low, ErrStat, ErrMsg)
125+
FileName = transfer(trim(p%WindFilePath)//trim(PathSep)//"Low"//trim(PathSep)//"Amb.t"//trim(Num2LStr(n))//".vtk"//c_null_char, FileName)
126+
call ReadVTK_inflow_info(FileName, desc, dims, origin, gridSpacing, vecLabel, Vamb_Low, 1, ErrStat, ErrMsg)
127+
if (ErrStat /= ErrID_None) ErrMsg = "ReadLowResWindFile:"//trim(ErrMsg)
128+
114129
end subroutine ReadLowResWindFile
115130

116131
!----------------------------------------------------------------------------------------------------------------------------------
@@ -120,28 +135,24 @@ subroutine ReadHighResWindFile(nt, n, p, Vamb_high, errStat, errMsg)
120135
integer(IntKi), intent(in ) :: nt
121136
integer(IntKi), intent(in ) :: n !< high-res time increment
122137
type(AWAE_ParameterType), intent(in ) :: p !< Parameters
123-
real(SiKi), intent(inout) :: Vamb_high(:,0:,0:,0:) !< Array which will contain the low resolution grid of ambient wind velocities
138+
real(SiKi), contiguous, intent(inout) :: Vamb_high(:,0:,0:,0:) !< Array which will contain the low resolution grid of ambient wind velocities
124139
integer(IntKi), intent( out) :: errStat !< Error status of the operation
125140
character(*), intent( out) :: errMsg !< Error message if errStat /= ErrID_None
126141

127-
128-
integer(IntKi) :: dims(3) ! dimension of the 3D grid (nX,nY,nZ)
129-
real(ReKi) :: origin(3) ! the lower-left corner of the 3D grid (X0,Y0,Z0)
130-
real(ReKi) :: gridSpacing(3) ! spacing between grid points in each of the 3 directions (dX,dY,dZ)
131-
integer(IntKi) :: Un ! unit number of opened file
132-
character(1024) :: FileName ! Name of output file
133-
character(1024) :: desc ! Line describing the contents of the file
134-
character(1024) :: vecLabel ! descriptor of the vector data
142+
integer(IntKi) :: dims(3) ! Dimension of the 3D grid (nX,nY,nZ)
143+
real(R8Ki) :: origin(3) ! The lower-left corner of the 3D grid (X0,Y0,Z0)
144+
real(R8Ki) :: gridSpacing(3) ! Spacing between grid points in each of the 3 directions (dX,dY,dZ)
145+
character(kind=c_char) :: FileName(2048) ! Name of output file
146+
character(kind=c_char) :: desc(1024) ! Line describing the contents of the file
147+
character(kind=c_char) :: vecLabel(1024) ! descriptor of the vector data
135148

136149
errStat = ErrID_None
137150
errMsg = ""
138151

139-
FileName = trim(p%WindFilePath)//trim(PathSep)//"HighT"//trim(num2lstr(nt))//trim(PathSep)//"Amb.t"//trim(num2lstr(n))//".vtk"
140-
Un = 0; ! Initialization different from -1, important to prevent file closing
141-
call ReadVTK_SP_info( FileName, desc, dims, origin, gridSpacing, vecLabel, Un, ErrStat, ErrMsg )
142-
if (ErrStat >= AbortErrLev) return
143-
call ReadVTK_SP_vectors( FileName, Un, dims, Vamb_high, ErrStat, ErrMsg )
144-
152+
FileName = transfer(trim(p%WindFilePath)//trim(PathSep)//"HighT"//trim(num2lstr(nt))//trim(PathSep)//"Amb.t"//trim(num2lstr(n))//".vtk"//c_null_char, FileName)
153+
call ReadVTK_inflow_info(FileName, desc, dims, origin, gridSpacing, vecLabel, Vamb_high, 1, ErrStat, ErrMsg)
154+
if (ErrStat /= ErrID_None) ErrMsg = "ReadHighResWindFile:"//trim(ErrMsg)
155+
145156
end subroutine ReadHighResWindFile
146157
!----------------------------------------------------------------------------------------------------------------------------------
147158
!> Flat array of Cartesian point coordinates

modules/awae/src/vtk.cpp

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
//------------------------------------------------------------------------------
2+
// VTK inflow reading utilities for the AWAE module
3+
//------------------------------------------------------------------------------
4+
5+
#include <iostream>
6+
#include <fstream>
7+
#include <string>
8+
#include <algorithm>
9+
#include <cctype>
10+
#include <sstream>
11+
12+
#include "fast_float.h"
13+
14+
const auto MaxChars{1023};
15+
16+
void convert_string_to_uppercase(std::string &str)
17+
{
18+
std::transform(str.begin(), str.end(), str.begin(),
19+
[](unsigned char c)
20+
{ return std::toupper(c); });
21+
}
22+
23+
void copy_string_to_array(const std::string &source, char destination[MaxChars])
24+
{
25+
const auto n_chars = source.copy(destination, MaxChars);
26+
for (auto i = n_chars; i < MaxChars; ++i)
27+
{
28+
destination[i] = ' ';
29+
}
30+
}
31+
32+
const auto ErrID_None{0};
33+
const auto ErrID_Info{1};
34+
const auto ErrID_Warn{2};
35+
const auto ErrID_Severe{3};
36+
const auto ErrID_Fatal{4};
37+
38+
extern "C"
39+
{
40+
void ReadVTK_inflow_info(const char filename[], char desc[MaxChars],
41+
int dims[3], double origin[3], double spacing[3],
42+
char vec_label[MaxChars], float values[], int *read_values,
43+
int *err_stat, char err_msg[MaxChars])
44+
{
45+
// Initialize error status and message
46+
*err_stat = ErrID_Fatal;
47+
copy_string_to_array("", err_msg);
48+
49+
// Open the file
50+
std::ifstream inputFile(filename);
51+
52+
// If file wasn't opened, return error
53+
if (!inputFile.is_open())
54+
{
55+
copy_string_to_array((std::string("Error opening file: '") + filename + "'"), err_msg);
56+
return;
57+
}
58+
59+
// Read entire file into buffer
60+
std::stringstream buffer;
61+
buffer << inputFile.rdbuf();
62+
63+
std::string line;
64+
std::string label;
65+
66+
std::getline(buffer, line); // Header
67+
std::getline(buffer, line); // Description
68+
copy_string_to_array(line, desc);
69+
70+
// Format label
71+
std::getline(buffer, line);
72+
convert_string_to_uppercase(line);
73+
if (line.find("ASCII") == std::string::npos)
74+
{
75+
copy_string_to_array("Invalid vtk structured_points file: did not find ASCII label", err_msg);
76+
return;
77+
}
78+
79+
// Dataset
80+
std::getline(buffer, line);
81+
convert_string_to_uppercase(line);
82+
if (line.find("DATASET") == std::string::npos)
83+
{
84+
copy_string_to_array("Invalid vtk structured_points file: did not find DATASET label", err_msg);
85+
return;
86+
}
87+
if (line.find("STRUCTURED_POINTS") == std::string::npos)
88+
{
89+
copy_string_to_array("Invalid vtk structured_points file: did not find STRUCTURED_POINTS label", err_msg);
90+
return;
91+
}
92+
93+
// Dimensions
94+
std::getline(buffer, line);
95+
convert_string_to_uppercase(line);
96+
if (line.find("DIMENSIONS") == std::string::npos)
97+
{
98+
copy_string_to_array("Invalid vtk structured_points file: did not find DIMENSIONS label", err_msg);
99+
return;
100+
}
101+
{
102+
std::istringstream iss(line);
103+
iss >> label >> dims[0] >> dims[1] >> dims[2];
104+
}
105+
106+
// Origin
107+
std::getline(buffer, line);
108+
convert_string_to_uppercase(line);
109+
if (line.find("ORIGIN") == std::string::npos)
110+
{
111+
copy_string_to_array("Invalid vtk structured_points file: did not find ORIGIN label", err_msg);
112+
return;
113+
}
114+
{
115+
std::istringstream iss(line);
116+
iss >> label >> origin[0] >> origin[1] >> origin[2];
117+
}
118+
119+
// Spacing
120+
std::getline(buffer, line);
121+
convert_string_to_uppercase(line);
122+
if (line.find("SPACING") == std::string::npos)
123+
{
124+
copy_string_to_array("Invalid vtk structured_points file: did not find SPACING label", err_msg);
125+
return;
126+
}
127+
{
128+
std::istringstream iss(line);
129+
iss >> label >> spacing[0] >> spacing[1] >> spacing[2];
130+
}
131+
132+
// Point data
133+
std::getline(buffer, line);
134+
convert_string_to_uppercase(line);
135+
if (line.find("POINT_DATA") == std::string::npos)
136+
{
137+
copy_string_to_array("Invalid vtk structured_points file: did not find POINT_DATA label", err_msg);
138+
return;
139+
}
140+
int n_points{0};
141+
{
142+
std::istringstream iss(line);
143+
iss >> label >> n_points;
144+
}
145+
if (n_points != (dims[0] * dims[1] * dims[2]))
146+
{
147+
copy_string_to_array("Invalid vtk structured_points file: POINT_DATA does not match DIMENSIONS", err_msg);
148+
return;
149+
}
150+
151+
// vector or field data
152+
std::getline(buffer, line);
153+
convert_string_to_uppercase(line);
154+
if (line.find("VECTORS") != std::string::npos)
155+
{
156+
if (line.find("FLOAT") == std::string::npos)
157+
{
158+
copy_string_to_array("Invalid VECTORS datatype. Must be set to float.", err_msg);
159+
return;
160+
}
161+
copy_string_to_array(line.substr(9), vec_label);
162+
}
163+
else if (line.find("FIELD") != std::string::npos)
164+
{
165+
std::istringstream iss(line);
166+
int n_arrays{0};
167+
iss >> label >> label >> n_arrays;
168+
if (n_arrays != 1)
169+
{
170+
copy_string_to_array("Invalid vtk structured_points file: FIELD label must have only 1 array", err_msg);
171+
return;
172+
}
173+
174+
std::getline(buffer, line);
175+
convert_string_to_uppercase(line);
176+
if (line.find("FLOAT") == std::string::npos)
177+
{
178+
copy_string_to_array("Invalid FIELD datatype. Must be set to float.", err_msg);
179+
return;
180+
}
181+
182+
int n_components{0};
183+
{
184+
std::istringstream iss(line);
185+
iss >> label >> n_components >> n_points;
186+
}
187+
if (n_components != 3)
188+
{
189+
copy_string_to_array("Invalid FIELD components. Must be set to 3.", err_msg);
190+
return;
191+
}
192+
if (n_points != (dims[0] * dims[1] * dims[2]))
193+
{
194+
copy_string_to_array("Invalid vtk structured_points file: FIELD array does not match DIMENSIONS", err_msg);
195+
return;
196+
}
197+
}
198+
else
199+
{
200+
copy_string_to_array("Invalid vtk structured_points file: did not find VECTORS or FIELD label", err_msg);
201+
return;
202+
}
203+
204+
// If reading of values was not requested, return
205+
if (*read_values == 0)
206+
{
207+
*err_stat = ErrID_None;
208+
return;
209+
}
210+
211+
// Get the remainder of the input as a string
212+
std::string input = buffer.str().substr(buffer.tellg());
213+
214+
// Read first value
215+
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), values[0]);
216+
217+
// Read remaining values
218+
const auto n_values{n_points * 3};
219+
for (auto i = 1U; i < n_values; ++i)
220+
{
221+
answer = fast_float::from_chars(answer.ptr, input.data() + input.size(), values[i],
222+
fast_float::chars_format::skip_white_space);
223+
if (answer.ec != std::errc())
224+
{
225+
copy_string_to_array("Error parsing value", err_msg);
226+
return;
227+
}
228+
}
229+
230+
// Set no errors
231+
*err_stat = ErrID_None;
232+
}
233+
}

modules/nwtc-library/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ target_link_libraries(nwtclibs PUBLIC
164164
${LAPACK_LIBRARIES}
165165
${CMAKE_DL_LIBS}
166166
)
167+
target_include_directories(nwtclibs PUBLIC
168+
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
169+
)
167170
if (USE_DLL_INTERFACE)
168171
target_compile_definitions(nwtclibs PRIVATE USE_DLL_INTERFACE)
169172
endif (USE_DLL_INTERFACE)

0 commit comments

Comments
 (0)