Cálculo de potencias

main
Sebastián Santisi 1 year ago
parent 262ec12a5f
commit 10375e1faf

Binary file not shown.

@ -34,14 +34,31 @@ function help() {
'<div class="l s"><p>Desarrollado por:</p><ul><li>Dimas Barile (CSC-CONICET)</li><li>José Alberto Martínez Trespalacios (Universidad Tecnológica de Bolívar)</li><li>Sebastián Santisi (CSC-CONICET)</li></ul></div>');
}
function up() { light.shadow.camera.top += 1; light.shadow.camera.updateProjectionMatrix(); helper.update()}
/*function up() { light.shadow.camera.top += 1; light.shadow.camera.updateProjectionMatrix(); helper.update()}
function down() { light.shadow.camera.bottom -= 1; light.shadow.camera.updateProjectionMatrix(); helper.update()}
function left() { light.shadow.camera.left -= 1; light.shadow.camera.updateProjectionMatrix(); helper.update()}
function right() { light.shadow.camera.right += 1; light.shadow.camera.updateProjectionMatrix(); helper.update()}
function right() { light.shadow.camera.right += 1; light.shadow.camera.updateProjectionMatrix(); helper.update()} */
function rot(angle) {
document.getElementById("rot0").className = document.getElementById("rot225").className = document.getElementById("rot270").className = document.getElementById("rot315").className = "";
document.getElementById("rot" + angle).className = "sel";
ws.setRotation(angle);
}
document.addEventListener('mousemove', follow, false);
function follow(e) {
follower = document.getElementById("follower");
status = follower.style.display;
follower.style.display = "block";
follower.style.left = (e.clientX - follower.clientWidth) + 'px';
follower.style.top = (e.clientY - follower.clientHeight) + 'px';
follower.style.display = status;
}
</script>
</head>
<body>
<div id="container">
<div id="follower"></div>
<div id="results">Resultados</div>
<div id="popup">
<div id="close" onclick="hide();"></div>
<div id="text">
@ -50,15 +67,19 @@ function up() { light.shadow.camera.top += 1; light.shadow.camera.updateProjecti
<p>Centro de Simulación Computacional para Aplicaciones Tecnológicas - CONICET</p>
</div>
</div>
<div id="button" onclick="ws.simulate();">¡SIMULAR!</div>
<div id="help">
<div id="right">
<ul>
<li title="Viento del Este" class="sel" id="rot0" onclick="rot(0);"></li>
<li title="Viento del Sudeste" id="rot315" onclick="rot(315);"></li>
<li title="Viento del Sur" id="rot270" onclick="rot(270);"></li>
<li title="Viento del Sudoeste" id="rot225" onclick="rot(225);"></li>
</ul>
<ul>
<li onclick="ws.setRotation(0);"></li>
<li onclick="ws.setRotation(315);"></li>
<li onclick="ws.setRotation(270);"></li>
<li onclick="ws.setRotation(225);"></li>
<li onclick="help();" style="cursor: help">?</li>
<li title="Agregar aerogenerador" onclick="ws.addWindMill();">+</li>
<li title="Quitar aerogenerador" onclick="ws.removeWindMill();">-</li>
<li title="Sobre SAPE" class="sel" onclick="help();" style="cursor: help">?</li>
</ul>
<div id="button" onclick="ws.simulate();">¡SIMULAR!</div>
</div>
<div id="copyright">&copy;2024 Centro de Simulación Computacional para Aplicaciones Tecnológicas (CSC) - CONICET</div>
<div id="rotate"><img src="assets/rotar_telefono.png" /><p>Rotá tu<br />dispositivo</p></div>

@ -26,8 +26,11 @@ class WindSimulation {
this.wm = null;
this.simulation = null;
this.simulationPot = null;
this.xhr = null;
this.lastFrame = Date.now();
this.rotation = Math.PI;
this.targetRotation = Math.PI;
this.dir = 0;
@ -64,18 +67,19 @@ class WindSimulation {
for(var i = 0; i < this.mills; i++) {
var wm = new WindMill();
wm.position.set(4 + 0.5, i + 5 - Math.ceil(this.mills / 2) + 0.5, 0);
wm.rotation.z = Math.PI;
wm.rotation.z = this.targetRotation;
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;
}
move(pos, ended=false, count=2) {
if(this.simulation)
this.resetSimulation();
if(! count)
return false;
var wm = this.wm;
@ -85,11 +89,22 @@ class WindSimulation {
}
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;
if(pos.x > this.width - 0.5 || pos.x < 0.5 || pos.y > this.height - 0.5 || pos.y < 0.5) {
if(pos.x > this.width - 0.5)
pos.x = this.width - 0.5;
if(pos.x < 0.5)
pos.x = 0.5;
if(pos.y > this.height - 0.5)
pos.y = this.height - 0.5;
if(pos.y < 0.5)
pos.y = 0.5;
return this.move(pos, ended, count - 1);
}
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;
if(pos.clone().sub(this.wms[i].position).length() < 1) {
return this.move(this.wms[i].position.clone().add(pos.clone().sub(this.wms[i].position).normalize()), ended, count - 1);
}
}
wm.position.x = pos.x;
wm.position.y = pos.y;
@ -99,11 +114,14 @@ class WindSimulation {
animate() {
requestAnimationFrame(() => { this.animate(); });
var now = Date.now();
var step = (now - this.lastFrame) / 1000;
if(!Screen.isMobile || (Screen.isMobile && screen.clicked)) {
const intersects = screen.raycaster.intersectObjects(this.wms);
var wm = null;
for(var i = 0; i < intersects.length; i++) {
if(intersects[i].object.geometry.constructor.name != "CylinderGeometry") {
if(intersects[i].object.constructor.name != "Spring") {
wm = intersects[i].object.parent;
break;
}
@ -111,22 +129,32 @@ class WindSimulation {
if(!screen.clicked || Screen.isMobile) {
if(this.wm != wm) {
if(this.wm != null) this.wm.select(false);
if(wm != null) wm.select(true);
if(this.wm != null) {
this.wm.select(false);
document.getElementById("follower").style.display = "none";
}
if(wm != null) {
wm.select(true);
if(this.simulation) {
var i = this.wms.indexOf(wm);
var follower = document.getElementById("follower");
follower.innerHTML = "Aerogenerador Nº" + (i + 1) + "<br />" + (Math.round(this.simulationPot[i] * 100) / 100) + " GWh (" + Math.round(this.simulationPot[i] * 100 / 14.95) + "%)";
follower.style.display = "block";
}
}
}
this.wm = wm;
}
}
for(var i = 0; i < this.wms.length; i++)
this.wms[i].animate();
this.wms[i].animate(step);
var speed = 0.02;
var speed = 2 * step;
if(Math.abs(this.targetRotation - this.rotation) > speed) {
var step = speed * Math.sign(this.targetRotation - this.rotation);
this.rotation += step;
for(var i = 0; i < this.wms.length; i++) {
this.wms[i].animate();
this.wms[i].rotation.z += step;
}
this.flag.rotation.z += step;
@ -134,14 +162,25 @@ class WindSimulation {
this.flag.animate();
if(window.exclamation)
window.exclamation.rotation.y += 0.02;
this.lastFrame = now;
renderer.render(scene, camera);
}
resetSimulation() {
scene.remove(this.simulation);
this.simulation = null;
this.simulationPot = null;
document.getElementById("follower").style.display = "none";
document.getElementById("results").style.display = "none";
}
setRotation(dir) {
if(this.simulation) {
scene.remove(this.simulation);
this.simulation = null;
}
if(this.simulation)
this.resetSimulation();
var rotations = {};
rotations[0] = Math.PI;
@ -153,6 +192,30 @@ class WindSimulation {
this.targetRotation = rotations[dir];
}
addWindMill() {
if(this.mills >= 10) return;
this.mills++;
this.reset();
}
removeWindMill() {
if(this.mills <= 1) return;
this.mills--;
this.reset();
}
reset() {
for(var i = 0; i < this.wms.length; i++)
scene.remove(this.wms[i]);
this.wms = [];
this.rotation = this.targetRotation;
this.init_windmills();
}
simulate() {
if(this.xhr != null)
this.xhr.abort();
@ -165,7 +228,8 @@ class WindSimulation {
if(this.xhr != xhr) return;
if (xhr.readyState === 4 && xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
this.add_simulation(json.ws);
console.log(json.pot)
this.add_simulation(json.ws, json.pot);
this.xhr = null;
}
};
@ -176,7 +240,17 @@ class WindSimulation {
xhr.send(data);
}
add_simulation(ws) {
add_simulation(ws, pot) {
var sum = 0;
for(let i = 0; i < pot.length; i++) {
this.wms[i].lowPower(pot[i] < 2.75/*14.95 * 0.8*/)
sum += pot[i];
}
var results = document.getElementById("results")
results.innerHTML = (Math.round(sum * 100) / 100) + " GWh (" + Math.round(sum * 100 / 14.95 / pot.length) + "%)";
results.style.display = "block";
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);
@ -190,8 +264,9 @@ class WindSimulation {
}
if(this.simulation)
scene.remove(this.simulation);
this.resetSimulation();
this.simulation = mesh;
this.simulationPot = pot;
scene.add(mesh);
}
}
@ -200,7 +275,7 @@ var width = 10;
var height = 10;
var ws = new WindSimulation(width, height, 5);
var screen = new Screen(camera, renderer, new THREE.Vector3(width / 2 + 0.5, height / 2, -0.65));
var screen = new Screen(camera, renderer, new THREE.Vector3(width / 2 + 0.5, height / 2, -0.3));
screen.setMoveCallBack((pos, end) => { ws.move(pos, end); });
screen.onResize();
@ -232,6 +307,16 @@ window.light = light;
//scene.add( helper);
//window.helper = helper;
window.windmill = WindMill;
window.ws = ws;
window.screen = screen;
window.scene = scene;

@ -14,11 +14,11 @@ class Screen {
this.pointerScreen = new THREE.Vector2();
this.pointerWorld = new THREE.Vector3();
this.radius = 24;
this.radius = 26;
this.phi = -0.5;
this.theta = 0.45;
this.z = 15;
this.aspect = 2.13;
this.aspect = 1.94;
this.clicked = false;

@ -1,7 +1,7 @@
import * as THREE from 'three';
// https://discourse.threejs.org/t/solved-create-a-spring/45135/9
class Spring extends THREE.Mesh{
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();

@ -6,6 +6,7 @@ import { Spring } from './spring.js';
class WindMill extends THREE.Group {
static geometryBody = null;
static geometryBlades = null;
static geometryExclamation = null;
static {
const loader = new STLLoader();
@ -16,15 +17,25 @@ class WindMill extends THREE.Group {
//loader.load('assets/cuerpo_126m_50.stl', function(geometry) {
WindMill.geometryBody = geometry;
});
loader.load('assets/exclamacion_50.stl', function(geometry) {
WindMill.geometryExclamation = geometry;
var colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.array.length), 3);
for(let i = 0; i < colors.count; i++)
if(Math.abs(geometry.attributes.position.getZ(i)) < 7.4)
colors.setXYZ(i, 0xfa / 0xff, 0xd5 / 0xff, 0x0a / 0xff);
WindMill.geometryExclamation.setAttribute('color', colors);
});
}
static isReady() {
return WindMill.geometryBody != null && WindMill.geometryBlades != null;
return WindMill.geometryBody != null && WindMill.geometryBlades != null && WindMill.geometryExclamation != null;
}
constructor() {
super()
this.isLow = false;
this.material = new THREE.MeshStandardMaterial({color: 0xffffff, roughness: 0.15});
this.materialCircle = new THREE.MeshStandardMaterial({color: 0xaa0000});
//this.materialCircle.transparent = true;
@ -84,20 +95,32 @@ class WindMill extends THREE.Group {
this.spring1.visible = this.spring2.visible = this.spring3.visible = false;
var material = new THREE.MeshStandardMaterial({color: 0xfad50a, roughness: 0.15, vertexColors: true});
this.meshExclamation = new THREE.Mesh(WindMill.geometryExclamation, material);
this.meshExclamation.castShadow = true;
//this.meshExclamation.receiveShadow = true;
this.meshExclamation.scale.setScalar(0.002);
this.meshExclamation.rotateX(Math.PI / 2);
this.meshExclamation.position.z = (90 + 126 / 2 + 1) / 126;
this.add(this.meshExclamation);
this.meshExclamation.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;
animate(step) {
var inc = (this.isLow ? 0.3 : 3) * step;
this.meshBlades.rotation.x += inc;
this.spring1.rotation.x += inc;
this.spring2.rotation.x += inc;
this.spring3.rotation.x += inc;
this.meshExclamation.rotation.y += 4 * step;
}
select(selected) {
if(selected == this.selected) return;
this.selected = selected;
this.meshCircle.visible = selected;
this.meshCircle.visible = selected;
if(selected)
this.material.color.set(0xff0000);
@ -105,6 +128,13 @@ class WindMill extends THREE.Group {
this.material.color.set(0xffffff);
}
lowPower(isLow) {
if(this.isLow == isLow) return;
this.isLow = isLow;
this.meshExclamation.visible = isLow;
}
show_springs(value) {
this.spring1.visible = this.spring2.visible = this.spring3.visible = value;
}

@ -9,13 +9,19 @@ import xxx
def index():
if request.method != 'POST' or not request.data:
return abort(400);
params = json.loads(request.data.decode(encoding='utf-8'))
pos = params['pos']
direction = params['dir']
ws = xxx.run(direction, pos);
if len(pos) > 10 or direction not in (0, 225, 270, 315):
return abort(400);
ws, pot = xxx.run(direction, pos);
return {
'pos': pos,
'ws': ws,
'pot': pot,
'dir': direction,
}

@ -1,3 +1,8 @@
* {
margin: 0;
padding: 0;
}
body {
margin: 0;
font-family: "Encode Sans", sans-serif;
@ -34,7 +39,7 @@ body {
}
#popup p + p {
margin-top: -3vh;
margin-top: 1vh;
}
.l {
@ -58,9 +63,7 @@ body {
}
#button {
position: absolute;
right: 4vh;
top: 4vh;
display: inline-block;
padding: 4vh;
background: darkblue;
font-weight: 800;
@ -70,24 +73,45 @@ body {
background: blue;
}
#help {
#right {
position: absolute;
right: 4vh;
top: 16vh;
max-width: 75vw;
text-align: right;
right: 1vh;
top: 1vh;
font-weight: 800;
font-size: .8em;
}
#help li {
display: block;
float: left;
#right li {
display: inline-block;
border: solid white .5vh;
padding: .1vh 1vh;
border-radius: 1vh;
cursor: pointer;
margin-left: 1vh;
width: 2.5vh;
margin-bottom: 1vh;
width: 4vh;
height: 4vh;
text-align: center;
opacity: 0.5;
}
#right li.sel, #right li:hover {
opacity: 1;
}
#follower, #results {
border: solid white 1px;
z-index: 900;
position: absolute;
background: #00000088;
padding: 1vh;
font-size: .5em;
display: none;
}
#results {
bottom: 1vh;
left: 1vh;
}
#copyright {

@ -65,15 +65,15 @@ def py_wake_Initial_Cong(D,name,h,U_ref,initial_position=initial_position):
method='linear'))
windTurbines = py_wake_Initial_Cong(D, 'NREL_5MW', h, U_ref)
grid = XYGrid(x=np.arange(0, 10.01, 0.1)*D, y=np.arange(0, 10.01, 0.1)*D)
def run(direction=0, initial_position=initial_position, U_ref=U_ref):
initial_position = np.array(initial_position);
site = UniformSite(p_wd=[1] * 8,
p_wd = [0] * 360
#p_wd[direction * n // 360] = 1
p_wd[direction] = 1
site = UniformSite(p_wd=p_wd,
ws=U_ref,
initial_position=initial_position*D)
#ds = xr.Dataset(
@ -84,7 +84,9 @@ def run(direction=0, initial_position=initial_position, U_ref=U_ref):
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=direction, yaw=0).flow_map(grid)
xa = wfm(x=wt_x*D, y=wt_y*D, wd=direction, yaw=0).flow_map(grid)
ws = xa.WS_eff
return ws[:,:,0,0].values[:,:,0].tolist()
aep = wfm(x=wt_x*D, y=wt_y*D).aep()
return ws[:,:,0,0].values[:,:,0].tolist(), [sum(aep.values[i,:,0]) for i in aep.wt.values]

Loading…
Cancel
Save