Commit inicial
commit
2d5b06d4ad
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,542 @@
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://cdn.jsdelivr.net/npm/three@0.136/build/three.module.js",
|
||||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.136/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Encode+Sans:wdth,wght@87.5,100..900&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Encode Sans", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 4vh;
|
||||
color: #fff;
|
||||
}
|
||||
#container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
#popup {
|
||||
z-index: 1000;
|
||||
max-width: 70vw;
|
||||
max-height: 70vh;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
width: auto;
|
||||
border: solid #fff 5px;
|
||||
height: auto;
|
||||
background: #00000088;
|
||||
padding: 4vh;
|
||||
text-align: center;
|
||||
}
|
||||
#popup p + p {
|
||||
margin-top: -3vh;
|
||||
}
|
||||
#close {
|
||||
font-weight: 900;
|
||||
float: right;
|
||||
font-size: 1.5em;
|
||||
margin-top: -5vh;
|
||||
margin-right: -3.5vh;
|
||||
}
|
||||
#close:hover {
|
||||
color: #fff;
|
||||
}
|
||||
#button {
|
||||
position: absolute;
|
||||
right: 4vh;
|
||||
top: 4vh;
|
||||
padding: 4vh;
|
||||
background: darkblue;
|
||||
font-weight: 800;
|
||||
}
|
||||
#button:hover {
|
||||
background: blue;
|
||||
}
|
||||
#copyright {
|
||||
z-index: 2;
|
||||
font-size: 0.4em;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
}
|
||||
#rotate {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 1vh;
|
||||
font-size: 0.5em;
|
||||
width: 20vh;
|
||||
}
|
||||
#rotate img {
|
||||
width: 7vh;
|
||||
float: left;
|
||||
padding-right: 1vh;
|
||||
}
|
||||
#logo {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
right: 1vh;
|
||||
bottom: 1vh;
|
||||
}
|
||||
#logo img {
|
||||
width: 15vh;
|
||||
opacity: 50%;
|
||||
}
|
||||
#logo img:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script type="module">
|
||||
import * as THREE from 'three';
|
||||
import { STLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.136.0/examples/jsm/loaders/STLLoader.js';
|
||||
import { Spring } from './spring.js';
|
||||
|
||||
const isMobile = 'ontouchstart' in document.documentElement;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({antialias: true});
|
||||
//renderer.setPixelRatio( window.devicePixelRatio );
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
window.camera = camera;
|
||||
window.three = THREE;
|
||||
window.renderer = renderer;
|
||||
|
||||
/*const axesHelper = new THREE.AxesHelper( 5 );
|
||||
scene.add( axesHelper );*/
|
||||
|
||||
var width = 10;
|
||||
var height = 10;
|
||||
|
||||
function plane(width, height) {
|
||||
var geometry = new THREE.PlaneGeometry(width, height, width, height);
|
||||
geometry = geometry.toNonIndexed();
|
||||
const colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.array.length), 3);
|
||||
for(var i = 0; i < colors.count; i++) {
|
||||
var col = Math.trunc(i / 6) % width;
|
||||
var row = Math.trunc(i / 6 / width);
|
||||
if((col + row % 2) % 2)
|
||||
colors.setXYZ(i, 0x44 / 0xff, 0xaa / 0xff, 0);
|
||||
else
|
||||
colors.setXYZ(i, 0x55 / 0xff, 0xd4 / 0xff, 0);
|
||||
}
|
||||
geometry.setAttribute('color', colors);
|
||||
const material = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors});
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.position.x = width / 2;
|
||||
mesh.position.y = height / 2;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
var cb = plane(width, height);
|
||||
scene.add(cb);
|
||||
window.cb = cb;
|
||||
|
||||
var center = new THREE.Vector3(width / 2, height / 2, 0);
|
||||
var direction = new THREE.Vector3(-height / 2, -width / 2, 0);
|
||||
|
||||
window.r = 23;
|
||||
window.phi = -0.5;
|
||||
window.theta = 0.2;
|
||||
window.center = center;
|
||||
window.center.z = -0.95;
|
||||
window.center.x += 0.5;
|
||||
window.z = 15;
|
||||
camera.setFocalLength(60);
|
||||
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const pointer = new THREE.Vector2();
|
||||
|
||||
var clicked = false;
|
||||
window.point = new THREE.Vector3();
|
||||
window.pos = new THREE.Vector3();
|
||||
|
||||
function log(s) {
|
||||
document.getElementById("text").innerHTML = s;
|
||||
document.getElementById("popup").style.display = "block";
|
||||
}
|
||||
|
||||
function updatePointers(event) {
|
||||
if(isMobile) {
|
||||
var touch = event.touches[0] || event.changedTouches[0];
|
||||
var x = touch.pageX;
|
||||
var y = touch.pageY;
|
||||
}
|
||||
else {
|
||||
var x = event.clientX
|
||||
var y = event.clientY;
|
||||
}
|
||||
pointer.x = (x / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(y / window.innerHeight) * 2 + 1;
|
||||
window.point.set(( x / window.innerWidth) * 2 - 1, -(y / window.innerHeight) * 2 + 1, 0.5);
|
||||
}
|
||||
|
||||
function onClick(event) {
|
||||
clicked = true;
|
||||
updatePointers(event);
|
||||
}
|
||||
|
||||
function onMouseUp(event) {
|
||||
clicked = false;
|
||||
updatePointers(event);
|
||||
//log(clicked);
|
||||
ws.move(window.pos, true);
|
||||
}
|
||||
|
||||
function onPointerMove(event) {
|
||||
updatePointers(event);
|
||||
window.point.unproject(camera);
|
||||
window.point.sub(camera.position).normalize();
|
||||
|
||||
var distance = -camera.position.z / window.point.z;
|
||||
|
||||
window.pos.copy(camera.position).add(window.point.multiplyScalar(distance));
|
||||
if(clicked) {
|
||||
ws.move(window.pos);
|
||||
}
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.fov = 15;
|
||||
|
||||
if(camera.aspect > window.aspect)
|
||||
window.r = window.rad;
|
||||
else {
|
||||
window.r = window.rad * window.aspect / camera.aspect;
|
||||
}
|
||||
window.z = window.r / 2;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
|
||||
document.getElementById("container").style.height = window.innerHeight;
|
||||
document.getElementById("container").style.width = window.innerWidth;
|
||||
|
||||
document.getElementById("rotate").style.display = camera.aspect > 1 ? "none" : "block";
|
||||
|
||||
var theta = Math.PI / 2 - window.theta;
|
||||
var phi = window.phi - Math.PI / 2;
|
||||
var x = window.r * Math.sin(theta) * Math.cos(phi) + center.x;
|
||||
var y = window.r * Math.sin(theta) * Math.sin(phi) + center.y;
|
||||
var z = window.r * Math.cos(theta) + center.z;
|
||||
|
||||
camera.position.set(x, y, window.z);
|
||||
camera.up = new THREE.Vector3(0,0,1);
|
||||
camera.lookAt(center);
|
||||
}
|
||||
|
||||
window.aspect = 2.0;
|
||||
window.rad = 23;
|
||||
window.resize = onResize;
|
||||
|
||||
if(isMobile) {
|
||||
window.addEventListener('touchstart', onClick);
|
||||
window.addEventListener('touchend', onMouseUp);
|
||||
window.addEventListener('touchmove', onPointerMove);
|
||||
}
|
||||
else {
|
||||
window.addEventListener('mouseup', onMouseUp);
|
||||
window.addEventListener('mousedown', onClick);
|
||||
window.addEventListener('pointermove', onPointerMove);
|
||||
}
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
onResize();
|
||||
|
||||
class WindMill extends THREE.Group {
|
||||
static geometryBody = null;
|
||||
static geometryBlades = null;
|
||||
|
||||
static {
|
||||
const loader = new STLLoader();
|
||||
loader.load('./aspas_126m.stl', function(geometry) {
|
||||
WindMill.geometryBlades = geometry;
|
||||
});
|
||||
loader.load('./cuerpo_126m.stl', function(geometry) {
|
||||
WindMill.geometryBody = geometry;
|
||||
});
|
||||
}
|
||||
|
||||
static isReady() {
|
||||
return WindMill.geometryBody != null && WindMill.geometryBlades != null;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.material = new THREE.MeshBasicMaterial({color: 0xffffff});
|
||||
this.materialCircle = new THREE.MeshBasicMaterial({color: 0xaa0000});
|
||||
//this.materialCircle.transparent = true;
|
||||
//this.materialCircle.opacity = 0.5;
|
||||
|
||||
this.meshBlades = new THREE.Mesh(WindMill.geometryBlades, this.material);
|
||||
this.meshBlades.scale.set(0.0075, 0.0075, 0.0075);
|
||||
this.meshBlades.position.z = 90/126;
|
||||
|
||||
this.meshBody = new THREE.Mesh(WindMill.geometryBody, this.material);
|
||||
this.meshBody.scale.set(0.0075, 0.0075, 0.0075);
|
||||
this.meshBody.position.z = 90/126;
|
||||
|
||||
var geometry = new THREE.CircleGeometry(0.5, 20);
|
||||
this.meshCircle = new THREE.Mesh(geometry, this.materialCircle);
|
||||
this.meshCircle.position.z = 0.01;
|
||||
this.meshCircle.visible = false;
|
||||
|
||||
this.add(this.meshBlades);
|
||||
this.add(this.meshBody);
|
||||
this.add(this.meshCircle);
|
||||
|
||||
this.spring1 = new Spring(0.5, 2, 20, 6, 1, new THREE.MeshBasicMaterial({color: 0xff0000}));
|
||||
this.spring1.position.z = 90/126;
|
||||
this.spring1.rotation.z = -Math.PI/2;
|
||||
this.spring1.update();
|
||||
this.add(this.spring1);
|
||||
|
||||
this.spring2 = new Spring(0.5, 2, 20, 6, 1, new THREE.MeshBasicMaterial({color: 0xff0000}));
|
||||
this.spring2.position.z = 90/126;
|
||||
this.spring2.rotation.z = -Math.PI/2;
|
||||
this.spring2.rotation.x = Math.PI * 2 / 3;
|
||||
this.spring2.update();
|
||||
this.add(this.spring2);
|
||||
|
||||
this.spring3 = new Spring(0.5, 2, 20, 6, 1, new THREE.MeshBasicMaterial({color: 0xff0000}));
|
||||
this.spring3.position.z = 90/126;
|
||||
this.spring3.rotation.z = -Math.PI/2;
|
||||
this.spring3.rotation.x = Math.PI * 4 / 3;
|
||||
this.spring3.update();
|
||||
this.add(this.spring3);
|
||||
|
||||
this.spring1.visible = this.spring2.visible = this.spring3.visible = false;
|
||||
|
||||
this.selected = false;
|
||||
}
|
||||
|
||||
animate() {
|
||||
this.meshBlades.rotation.x += 0.1;
|
||||
this.spring1.rotation.x += 0.1;
|
||||
this.spring2.rotation.x += 0.1;
|
||||
this.spring3.rotation.x += 0.1;
|
||||
}
|
||||
|
||||
select(selected) {
|
||||
if(selected == this.selected) return;
|
||||
this.selected = selected;
|
||||
this.meshCircle.visible = selected;
|
||||
|
||||
if(selected)
|
||||
this.material.color.set(0xff0000);
|
||||
else
|
||||
this.material.color.set(0xffffff);
|
||||
}
|
||||
}
|
||||
|
||||
window.windmill = WindMill;
|
||||
window.scene = scene;
|
||||
|
||||
var wm = null;
|
||||
var wms = [];
|
||||
window.wms = wms;
|
||||
|
||||
class WindSimulation {
|
||||
constructor(width, height, mills) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.mills = mills;
|
||||
|
||||
this.wms = [];
|
||||
this.init();
|
||||
|
||||
this.wm = null;
|
||||
this.simulation = null;
|
||||
}
|
||||
|
||||
init() {
|
||||
if(!WindMill.isReady()) {
|
||||
setTimeout(() => { this.init() }, 100);
|
||||
return;
|
||||
}
|
||||
for(var i = 0; i < this.mills; i++) {
|
||||
var wm = new WindMill();
|
||||
wm.position.set(i + 0.5, i + 0.5, 0);
|
||||
wm.rotation.z = Math.PI;
|
||||
scene.add(wm);
|
||||
this.wms.push(wm);
|
||||
}
|
||||
this.wm = this.wms[0];
|
||||
}
|
||||
|
||||
move(pos, ended=false) {
|
||||
if(this.simulation) {
|
||||
scene.remove(this.simulation);
|
||||
this.simulation = null;
|
||||
}
|
||||
|
||||
var wm = this.wm;
|
||||
|
||||
if(ended) {
|
||||
if(this.wm != null) this.wm.select(false);
|
||||
this.wm = null;
|
||||
}
|
||||
|
||||
if(wm == null) return false;
|
||||
if(pos.x > this.width - 0.5 || pos.x < 0.5 || pos.y > this.height - 0.5 || pos.y < 0.5) return false;
|
||||
for(var i = 0; i < this.wms.length; i++) {
|
||||
if(this.wms[i] == wm) continue;
|
||||
if(pos.clone().sub(this.wms[i].position).length() < 1)
|
||||
return false;
|
||||
}
|
||||
wm.position.x = pos.x;
|
||||
wm.position.y = pos.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
animate() {
|
||||
requestAnimationFrame(() => { this.animate(); });
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
||||
if(!isMobile || (isMobile && clicked)) {
|
||||
const intersects = raycaster.intersectObjects(this.wms);
|
||||
var wm = null;
|
||||
for(var i = 0; i < intersects.length; i++) {
|
||||
if(intersects[i].object.geometry.constructor.name != "CylinderGeometry") {
|
||||
wm = intersects[i].object.parent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!clicked || isMobile) {
|
||||
if(this.wm != wm) {
|
||||
if(this.wm != null) this.wm.select(false);
|
||||
if(wm != null) wm.select(true);
|
||||
}
|
||||
this.wm = wm;
|
||||
}
|
||||
}
|
||||
|
||||
for(var i = 0; i < this.wms.length; i++) {
|
||||
this.wms[i].animate();
|
||||
//this.wms[i].rotation.z += 0.01;
|
||||
}
|
||||
renderer.render(scene, camera);
|
||||
|
||||
cone.rotation.y = 0.1 * Math.sin(Date.now() / 1000);
|
||||
cone.rotation.x = 0.08 * Math.sin(Date.now() / 5000);
|
||||
}
|
||||
|
||||
simulate() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/solver/", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
var json = JSON.parse(xhr.responseText);
|
||||
this.add_simulation(json.ws);
|
||||
}
|
||||
};
|
||||
var pos = [];
|
||||
for(var i = 0; i < this.wms.length; i++)
|
||||
pos.push([this.wms[i].position.y, this.wms[i].position.x]);
|
||||
console.log(pos);
|
||||
var data = JSON.stringify({"pos": pos});
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
add_simulation(ws) {
|
||||
var geometry = new THREE.PlaneGeometry(this.width, this.height, 10 * this.width, 10 * this.height);
|
||||
var colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.count * 4), 4);
|
||||
geometry.setAttribute('color', colors);
|
||||
const material = new THREE.MeshBasicMaterial({vertexColors: true, transparent: true,});
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.set(this.width / 2, this.height / 2, 90/126);
|
||||
|
||||
for(var i = 0; i < colors.count; i++) {
|
||||
var j = Math.trunc(i / 101);
|
||||
colors.setXYZW(i, 1 - ws[i % 101][100 - j] / 8, 0, 0, 1 - ws[i % 101][100 - j] / 8);
|
||||
}
|
||||
|
||||
if(this.simulation)
|
||||
scene.remove(this.simulation);
|
||||
this.simulation = mesh;
|
||||
scene.add(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
const loader = new STLLoader();
|
||||
loader.load('./casa_80.stl', function(geometry) {
|
||||
var material = new THREE.MeshBasicMaterial({color: 0xffffff});
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
var scale = 0.0005;
|
||||
mesh.scale.set(scale, scale, scale);
|
||||
mesh.rotation.z = -Math.PI / 2;
|
||||
mesh.position.x = 9.8;
|
||||
mesh.position.y = 0.2;
|
||||
scene.add(mesh);
|
||||
window.casa = mesh;
|
||||
});
|
||||
|
||||
var geometry = new THREE.CylinderGeometry(0.09, 0.03, 0.5, 10, 5, true);
|
||||
geometry = geometry.toNonIndexed();
|
||||
const colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.array.length), 3);
|
||||
geometry.setAttribute('color', colors);
|
||||
for(var i = 0; i < colors.count; i++) {
|
||||
if((Math.trunc(i / 6) + Math.trunc(i / 30) % 2) % 2)
|
||||
colors.setXYZ(i, 1, 1, 1);
|
||||
else
|
||||
colors.setXYZ(i, 1, 0.3, 0);
|
||||
}
|
||||
const material = new THREE.MeshBasicMaterial({vertexColors: true});
|
||||
var mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.z = 1;
|
||||
mesh.position.x = 9.5;
|
||||
mesh.position.y = 0.5;
|
||||
mesh.rotation.z = -Math.PI / 2;
|
||||
var cone = mesh;
|
||||
scene.add(mesh);
|
||||
|
||||
var ws = new WindSimulation(10, 10, 5);
|
||||
window.ws = ws;
|
||||
|
||||
window.scene = scene;
|
||||
ws.animate();
|
||||
|
||||
</script>
|
||||
<script>
|
||||
function hide() {
|
||||
document.getElementById("popup").style.display = "none";
|
||||
}
|
||||
</script>
|
||||
<div id="container">
|
||||
<div id="popup">
|
||||
<div id="close" onclick="hide();">✗</div>
|
||||
<div id="text">
|
||||
<img src="logooscuro.png" style="width: 30vh;" /><br />
|
||||
<p>Simulador de interacción entre turbinas.</p>
|
||||
<p>Centro de Simulación Computacional para Aplicaciones Tecnológicas - CONICET</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button" onclick="ws.simulate();">¡SIMULAR!</div>
|
||||
<div id="copyright">©2024 Centro de Simulación Computacional para Aplicaciones Tecnológicas (CSC) - CONICET</div>
|
||||
<div id="rotate"><img src="rotar_telefono.png" /><p>Rotá tu<br />dispositivo</p></div>
|
||||
<div id="logo"><a href="http://www.csc.gob.ar"><img src="logooscuro.png" /></a></div>
|
||||
</div>
|
||||
|
||||
</body>
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,22 @@
|
||||
from flask import Flask
|
||||
from flask import request
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
import xxx
|
||||
|
||||
@app.route("/", methods=['GET', 'POST'])
|
||||
def index():
|
||||
if request.method == 'POST':
|
||||
if request.data:
|
||||
params = json.loads(request.data.decode(encoding='utf-8'))
|
||||
pos = params['pos'];
|
||||
ws = xxx.run(pos);
|
||||
return {
|
||||
'pos': pos,
|
||||
'ws': ws,
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host='0.0.0.0', port='1234')
|
@ -0,0 +1,34 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
// https://discourse.threejs.org/t/solved-create-a-spring/45135/9
|
||||
class Spring extends THREE.Mesh{
|
||||
constructor(radius, turns, segmentsPerTurn, height, growth, material){
|
||||
let g = new THREE.CylinderGeometry(0.005, 0.005, 1, 16, segmentsPerTurn * turns).translate(0, 0.5, 0).rotateX(Math.PI * 0.5);
|
||||
let initPos = g.attributes.position.clone();
|
||||
super(g, material);
|
||||
this.radius = radius;
|
||||
this.turns = turns;
|
||||
this.segmentsPerTurn = segmentsPerTurn;
|
||||
this.height = height;
|
||||
this.growth = growth;
|
||||
|
||||
this.update = () => {
|
||||
let _n = new THREE.Vector3(0, 1, 0), _v3 = new THREE.Vector3(), _s = new THREE.Vector3();
|
||||
|
||||
let pos = g.attributes.position;
|
||||
for(let i = 0; i < initPos.count; i++){
|
||||
let ratio = initPos.getZ(i) * this.growth;
|
||||
let angle = this.turns * Math.PI * 2 * ratio;
|
||||
_v3.fromBufferAttribute(initPos, i).setZ(0);
|
||||
_v3.applyAxisAngle(_n, angle + Math.PI * 0.5);
|
||||
_v3.add(_s.setFromCylindricalCoords(this.radius, angle, this.height * ratio));
|
||||
pos.setXYZ(i, ... _v3);
|
||||
}
|
||||
g.computeVertexNormals();
|
||||
pos.needsUpdate = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Spring };
|
@ -0,0 +1,82 @@
|
||||
from py_wake.wind_turbines import WindTurbine
|
||||
from py_wake.wind_turbines.power_ct_functions import PowerCtTabular
|
||||
from py_wake.site._site import UniformSite
|
||||
from py_wake.wind_farm_models import PropagateDownwind
|
||||
from py_wake.deficit_models.gaussian import TurboGaussianDeficit
|
||||
from py_wake.flow_map import XYGrid
|
||||
|
||||
import numpy as np
|
||||
|
||||
D = 126 #Diametro del wT
|
||||
h = 90 #Altura del WT
|
||||
U_ref = 8
|
||||
|
||||
|
||||
initial_position = np.array([[ 1 , 1],
|
||||
[ 2. , 2],
|
||||
[ 4 , 4],
|
||||
[ 1 , 4],
|
||||
[ 2 , 4],
|
||||
[ 3 , 4],
|
||||
[ 1 , 5],
|
||||
[ 2 , 5],
|
||||
[ 5 , 5]])
|
||||
|
||||
|
||||
def py_wake_Initial_Cong(D,name,h,U_ref,initial_position=initial_position):
|
||||
|
||||
#Curvas del WT
|
||||
power_curve = np.array([
|
||||
[ 0.1, 1.000],
|
||||
[ 4.5, 267.7],
|
||||
[ 5.0, 387.6],
|
||||
[ 5.5, 534.0],
|
||||
[ 6.0, 707.4],
|
||||
[ 6.5, 910.0],
|
||||
[ 7.0, 1142.7],
|
||||
[ 7.5, 1407.5],
|
||||
[ 8.0, 1707.1],
|
||||
[ 8.5, 2047.3],
|
||||
[ 9.0, 2430.6]]) * [1, 1000]
|
||||
|
||||
|
||||
ct_curve = np.array([
|
||||
[ 0.1, 0.100],
|
||||
[ 4.5, 0.928],
|
||||
[ 5.0, 0.892],
|
||||
[ 5.5, 0.861],
|
||||
[ 6.0, 0.835],
|
||||
[ 6.5, 0.812],
|
||||
[ 7.0, 0.792],
|
||||
[ 7.5, 0.776],
|
||||
[ 8.0, 0.7702530978349217],
|
||||
[ 8.5, 0.762],
|
||||
[ 9.0, 0.763]])
|
||||
|
||||
|
||||
return WindTurbine(name=name,
|
||||
diameter=D,
|
||||
hub_height=h,
|
||||
powerCtFunction=PowerCtTabular(power_curve[:, 0],
|
||||
power_curve[:, 1],
|
||||
'w',ct_curve[:, 1],
|
||||
method='linear'))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
windTurbines = py_wake_Initial_Cong(D, 'NREL_5MW', h, U_ref)
|
||||
|
||||
def run(initial_position=initial_position, U_ref=U_ref):
|
||||
initial_position = np.array(initial_position);
|
||||
site = UniformSite(p_wd=[1],
|
||||
ws=U_ref,
|
||||
initial_position=initial_position*D)
|
||||
wt_x, wt_y = site.initial_position.T/D
|
||||
wfm = PropagateDownwind(site, windTurbines, wake_deficitModel=TurboGaussianDeficit())
|
||||
grid = XYGrid(x=np.arange(0, 10.01, 0.1)*126, y=np.arange(0, 10.01, 0.1)*126)
|
||||
xa = wfm(x=wt_x*126, y=wt_y*126, wd=0, yaw=0).flow_map(grid)
|
||||
ws = xa.WS_eff
|
||||
return ws[:,:,0,0].values[:,:,0].tolist()
|
Loading…
Reference in New Issue